我有一个640x480的二进制图像(0s和255s)。图像中有一个白色的斑点(接近圆形),我想找到斑点的质心(它总是凸起的)。基本上,我们正在处理的是2D布尔矩阵。如果可能的话,我希望运行时线性或更好 - 这可能吗?
到目前为止有两条思路:
numpy.where()
功能答案 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
结果:
它是一个日志图,所以它确实说明了结合这两种方法的优势。
这是我用于测试的图像:
答案 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分辨率,找到一个白色像素,然后您就可以准确了解在哪里搜索质心。