计算数组中的像素

时间:2012-09-14 13:55:29

标签: python arrays image matrix

我正在使用二进制PBM格式。当我读它时,我有一个带整数的数组,其中整数是字节的序数。数组中的每个整数转换为0和1整数的列表作为二进制表示,然后我反转此列表。像素网格从0:0开始,因此第一个像素的位置为[0:0]。

如果x> = 8,我需要获得像素颜色。如果x< 8,一切都很棒。获取像素颜色的代码。

  def getpixel(self, x, y):
    '''PNMReader.getpixel(x, y) -> int

    Get pixel at coordinates [x:y] and return it as integer.'''
    if not isinstance(x, int) or not isinstance(y, int):
      raise(TypeError('both x and y must be integers'))
    if x < -1 or y < -1:
      raise(ValueError('both x and y are interpreted as in slice notation'))
    if x > (self.width-1):
      raise(ValueError('x cannot be equal or greater than width'))
    if y > (self.height-1):
      raise(ValueError('x cannot be equal or greater than height'))
    width, height = self.width, self.height
    x = (x, width-1)[x == -1]
    y = [y, height-1][y == -1]
    p = (y *height) +x
    width, height = self.width, self.height
    pixels = self._array_
    q = (8, width)[width -8 < 0]
    if x >= q:
      while x % q:
        y += 1
        x -= 1
    from pprint import pprint
    color = bitarray(pixels[y])[::-1][:q][x]
    print(color)
你可以在这里看到的

bitarray是我定义的函数,用于获取整数的列作为列表; self._array_是一个整数序列(它只是从PBM读取的字节的序数)。

如果x> = 8,我需要修复此函数以获取像素颜色。在这种情况下,我无法理解如何计算x和y的偏移量。

只接受快速解决的答案。我不希望将所有位加入为1维数组,因为如果图像很大(例如,它可能是3000x5000像素),它可能会太慢。

我知道我可以使用imagemagickfreeimage等模块,但我只能使用标准库(没有其他模块)。我需要没有绑定或非默认模块的纯Python解决方案。

1 个答案:

答案 0 :(得分:2)

如果self._array_是一个整数数组,每个整数表示原始图像中的一个字节的光栅图像数据,那么您可以使用普通的位操作技术提取所需的位。这是一个详细的解释(根据评论中的要求):

  1. 我们需要每行的宽度(以字节为单位)。这是以像素为单位的宽度除以8,除了PBM格式为每行填充最多7个虚拟像素以使每行成为精确的字节数。所以我们需要将宽度除以8并将向上,这可以使用整数算法来完成,如下所示:

    row_width = (width + 7) // 8
    
  2. 然后我们需要找到包含我们想要的像素的字节。 PBM栅格数据按行主要顺序排列,因此(x, y)处的像素位于此字节中:

    pixel_byte = self._array_[y * row_width + x // 8]
    
  3. 您可以使用操作b从右侧i提取位号(i >> b) & 1(从右侧编号,最低有效位编号为0)(右移b位并掩盖最低位)。但PBM在big-endian order中列出其像素,第一个像素位于字节中的最高位。所以我们想要的位是位号7 - x % 8

    (pixel_byte >> (7 - x % 8)) & 1
    
  4. 这应该可以解决您的直接问题。但它看起来好像你的代码对于你想要做的事情非常复杂。一些评论:

    1. 调用isinstance并自己提出TypeError是毫无意义的,因为当你尝试对参数进行整数运算时,无论如何都会发生这种情况。

    2. x > (self.width-1)最好写成x >= self.width

    3. Python的切片表示法允许任何负整数,而不仅仅是-1。例如:

      >>> range(10)[-7:-4]
      [3, 4, 5]
      
    4. 您计算了一个数字p,但您没有使用它。

    5. 您导入函数pprint,然后不要调用它。

    6. 我会写这样的东西:

      import re
      
      class Pbm(object):
          """
          Load a Binary Portable Bitmap (PBM) files and provide access to
          its pixels.  See <http://netpbm.sourceforge.net/doc/pbm.html>
          """
          _pbm_re = re.compile(r'''
             (P4)                     # 1. Magic number
             (?:\s+|\#.*\n)*          # Whitespace or comments
             ([0-9]+)                 # 2. Width of image in pixels
             (?:\s+|\#.*\n)*          # Whitespace or comments
             ([0-9]+)                 # 3. Height of image in pixels
             (?:\#.*\n)*              # Possible comments
             \s                       # A single whitespace character
             ([\000-\377]*)           # 4. Raster image data
          ''', re.X)
      
          def __init__(self, f):
              m = self._pbm_re.match(f.read())
              if not m:
                  raise IOError("Can't parse PBM file.")
              self.width = int(m.group(2))             # Width in pixels
              self.height = int(m.group(3))            # Height in pixels
              self.row = (self.width + 7) // 8         # Width in bytes
              self.raster = m.group(4)
              if len(self.raster) != self.height * self.row:
                  raise IOError("Size of raster is {} but width x height = {}."
                                .format(len(self.raster), self.height * self.row))
      
          def getpixel(self, x, y):
              # Negative coordinates are treated as offsets from the end,
              # like Python's slice indexes.
              if x < 0: x += self.width
              if y < 0: y += self.height
              if x < 0 or x >= self.width or y < 0 or y >= self.height:
                  raise ValueError("Coords ({},{}) are out of range (0,0)-({},{})."
                                   .format(x, y, self.width - 1, self.height - 1))
              return (ord(self.raster[y * self.row + x // 8]) >> (7 - x % 8)) & 1