在线性时间内在二进制图像中查找特定索引?

时间:2012-05-02 07:46:35

标签: python image-processing numpy boolean python-imaging-library

我有一个640x480的二进制图像(0s和255s)。图像中有一个白色的斑点(接近圆形),我想找到斑点的质心(它总是凸起的)。基本上,我们正在处理的是2D布尔矩阵。如果可能的话,我希望运行时线性或更好 - 这可能吗?

到目前为止有两条思路:

  1. 使用numpy.where()功能
  2. 对每列和每行中的值求和,然后找出最大值基于这些数字的位置......但是有一种快速有效的方法吗?这可能只是我对python相对较新的一种情况。

4 个答案:

答案 0 :(得分:6)

此代码将找到任何形状图像的质心。它会完全找到rez = 1。增加rez会增加网格间距,因此可以大幅提高搜索速度,但成本会明显降低。如果blob的大小在边界内是已知的,您可以使用高rez搜索链接低rez搜索,从而快速且价格合理地找到答案

import Image

def find_centroid_faster(im, rez):
    width, height = im.size
    XX, YY, count = 0, 0, 0
    for x in xrange(0, width, rez):
        for y in xrange(0, height, rez):
            if im.getpixel((x, y)) == 255:
                XX += x
                YY += y
                count += 1
    return XX/count, YY/count

例如,如下图所示:

im = Image.open('blob.png')
print find_centroid(im, 1)
print find_centroid(im, 20)
#output:
(432, 191)
(430, 190)

使用timeit第一个选项的时间(线性时间O(n))的运行时间为1.7s,第二个0.005s

除非您对尺寸和形状有一些限制,否则您无法比O(n)更好地找到确切的答案。 ,你可以牺牲速度的准确性。上面的代码是O(n/(rez ** 2)),这可能是一个巨大的改进。报告结果的准确性为:± rez / 2,每个维度。

<强>更新

sega_sai写了一段很好的numpy代码(见下文),找到了质心。我已经修改它以利用网格间距,通过使用切片。它的运作方式与上述相同:

def find_centroid_faster_numpy(im,rez):
        h, w = im.size
        arr = np.array(im)
        arr_rez = arr[::rez,::rez]
        ygrid, xgrid  = np.mgrid[0:w:rez, 0:h:rez]
        xcen, ycen = xgrid[arr_rez == 255].mean(), ygrid[arr_rez == 255].mean()
        return xcen, ycen

以下是timeit范围内这两个函数的rez结果:

enter image description here

它是一个日志图,所以它确实说明了结合这两种方法的优势。

这是我用于测试的图像:

enter image description here

答案 1 :(得分:2)

质心坐标是点坐标的算术平均值。 如果你想要线性解决方案,只需逐像素,并计算每个坐标的平均值,其中像素为白色,这是质心。

在一般情况下,你可能无法使它比线性更好,但是,如果你的圆形物体比图像小得多,你可以通过首先搜索它来加速它(采样一些随机像素) ,或像素网格,如果你知道blob足够大),然后使用BFS或DFS查找所有白点。

答案 2 :(得分:2)

此代码:

import Image, numpy as np
def getBlobCenter(imname):
        im = Image.open(imname)
        w, h = im.size
        arr = np.array(im)
        xgrid, ygrid = np.mgrid[0:w, 0:h]
        xcen, ycen = xgrid[arr == 255].mean(), ygrid[arr == 255].mean()
        return xcen, ycen

对于fraxel提供的640x480图片需要10毫秒

答案 3 :(得分:1)

根据blob的大小,我会说大幅降低图像的分辨率可能会达到你想要的效果。

将其降低到1/10分辨率,找到一个白色像素,然后您就可以准确了解在哪里搜索质心。