查找图像中的空白区域

时间:2010-07-22 15:43:12

标签: python language-agnostic image-processing numpy python-imaging-library

这个问题在某种程度上与语言无关,但我选择的工具恰好是一个小数组。

我正在做的是通过PIL获取两个图像的区别:

img = ImageChops.difference(img1, img2)

我想找到包含从一张图片到另一张图片的变化的矩形区域。当然有内置的.getbbox()方法,但是如果有两个区域有变化,它会从一个区域返回一个框到另一个区域,如果每个角落只有1个像素变化,它将返回整个图像。

例如,考虑以下o是非零像素:

______________________
|o            ooo    |
|      oooo   ooo    |
|      o             |
|      o  o          |
|                    |
|     oo       o     |
|    o  o     ooo    |
|     oo     ooooo   |
|             ooo    |
|              o     |
|____________________|

我想获得包含每个非零区域的边界框的4x4元组。对于

的边缘情况
oooo
o
o  o

结构,我并不十分担心如何处理 - 无论是单独还是一起获取两个部分,因为倒L形的边界将完全重叠单个像素的边界。

我从来没有做过任何先进的图像处理,所以我想在我真正写任何东西之前得到一些输入(如果我已经使用的模块中有预先存在的方法,我欢迎他们!)。

我的psuedocode-ish版本是这样的:

for line in image:
   started = False
   for pixel in line:
      if pixel and not started:
         started = True
         save start coords
      elif started and not pixel:
         started = False
         save end coords (x - 1 of course)

这应该给我一个坐标列表,但是我必须确定这些区域是否是连续的。我可以用图形搜索来做到这一点吗? (我们上学期在算法中做了大量的DFS和BFS)当然我想我可以这样做/与之前的循环结合使用?

我不会在“大”图像上执行此操作 - 它们是从网络摄像头中取出的,而我目前拥有的最好的图像是640x480。我最多只能做720p或1080p,但这对未来来说已经足够了,这不是一个真正的问题。

所以我的问题:我是走在正确的道路上还是离开了?更重要的是,是否有任何内置功能阻止我重新发明轮子?最后,有什么好的资源我应该看一下(教程,论文等)会有帮助吗?

谢谢!

3 个答案:

答案 0 :(得分:17)

我相信scipy's ndimage module拥有您需要的一切......

这是一个简单的例子

import numpy as np
import scipy as sp
import scipy.ndimage.morphology

# The array you gave above
data = np.array( 
        [
           [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 
           [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 
        ])


# Fill holes to make sure we get nice clusters
filled = sp.ndimage.morphology.binary_fill_holes(data)

# Now seperate each group of contigous ones into a distinct value
# This will be an array of values from 1 - num_objects, with zeros
# outside of any contigous object
objects, num_objects = sp.ndimage.label(filled)

# Now return a list of slices around each object
#  (This is effectively the tuple that you wanted)
object_slices =  sp.ndimage.find_objects(objects)

# Just to illustrate using the object_slices
for obj_slice in object_slices:
    print data[obj_slice]

输出:

[[1]]
[[1 1 1]
 [1 1 1]]
[[1 1 1 1]
 [1 0 0 0]
 [1 0 0 1]]
[[1]]
[[0 1 1 0]
 [1 0 0 1]
 [0 1 1 0]]
[[0 0 1 0 0]
 [0 1 1 1 0]
 [1 1 1 1 1]
 [0 1 1 1 0]
 [0 0 1 0 0]]

请注意,如果您需要实际的指示,“object_slices”基本上是您最初要求的。

编辑:只是想指出尽管它似乎正确处理了

的边缘情况
[[1 1 1 1]
 [1 0 0 0]
 [1 0 0 1]]

它实际上没有(因此额外的孤独[[1]])。如果你打印出“对象”数组并看一下对象3& 4。

[[1 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0]
 [0 0 0 0 0 0 3 3 3 3 0 0 0 2 2 2 0 0 0 0]
 [0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 3 0 0 4 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 5 5 0 0 0 0 0 0 0 6 0 0 0 0 0]
 [0 0 0 0 5 5 5 5 0 0 0 0 0 6 6 6 0 0 0 0]
 [0 0 0 0 0 5 5 0 0 0 0 0 6 6 6 6 6 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 0 0 0 0 0]]

希望有所帮助!

[1]

答案 1 :(得分:1)

您可以在图像中查找已连接的组件,然后确定这些组件的边界框。

答案 2 :(得分:1)

群集程序包(ie this)应该能够完成大部分工作(找到连接的像素)。因此,查找群集的边界框非常简单。