如何仅从对象边界获取对象质心?
How to Get Object Centroid just from Object Boundary?
我有 2 个分割图像。一个是otsu binary,一个是outer boundary 获取自otsu's.
大津二进制:
对象边界:
以及像这样查找质心的代码:
def getCentroid(img):
row, col = img.shape
xVal = 0
yVal = 0
n = 0.0
for x in range(0,row):
for y in range(0,col):
if (img[x,y] == 0):
xVal += x
yVal += y
n += 1.0
xVal /= n
yVal /= n
return [np.int64(np.round(xVal)),np.int64(np.round(yVal))]
但是,该代码似乎只适用于 otsu 的代码。以下是结果:
大津二进制:
对象边界:
那么,如何从对象边界找到对象质心?
注意:我不想使用 built-in 函数,因为我想了解算法的工作原理。
算法很简单:只需平均所有边界像素坐标即可。然而,这将不是真正的质心。要找到真实的,请对对象中包含的所有像素(不仅是边界)进行平均。
如果对象是 凸面,则平均边界将起作用。凸物体是两个内部点之间的连接不会与其边界相交的物体。 将对象分解为此类组件 的最简单方法可能是将其分解为不重叠的矩形,同时尽量将矩形的数量保持在最低限度。矩形质心的平均值(乘以矩形面积)将是对象的质心。
错误很简单。由于这种情况:if (img[x,y] == 0):
,您的算法仅处理黑色像素。您的边界图像包含大部分黑色像素。可以安全地假设此类图像中所有黑色像素的质心非常接近图像的中心。
相关图片宽 402 像素,高 302 像素。您的算法给我们 (x=201, y=151)
作为质心——这符合预期。
要正确处理对象边界,我们需要将边界设为黑色,其他部分设为白色。这很简单,只需将图像反转即可(例如 255 - img
)。那么你的算法returns(x=165, y=123)
,就更有意义了。
代码
import cv2
import numpy as np
def getCentroid(img):
row, col = img.shape
xVal = 0
yVal = 0
n = 0.0
for x in range(0,row):
for y in range(0,col):
if (img[x,y] == 0):
xVal += x
yVal += y
n += 1.0
xVal /= n
yVal /= n
return [np.int64(np.round(xVal)),np.int64(np.round(yVal))]
a = cv2.imread('cnt.png', 0)
c1 = getCentroid(a) # Original
c2 = getCentroid(255 - a) # Inverse
b = cv2.cvtColor(a, cv2.COLOR_GRAY2BGR)
cv2.circle(b, (c1[1], c1[0]), 3, (0,0,255))
cv2.circle(b, (c2[1], c2[0]), 3, (0,255,0))
cv2.imwrite('cnt_out.png', b)
示例输出
注:红色是原图的质心,绿色是倒像的质心。
我有 2 个分割图像。一个是otsu binary,一个是outer boundary 获取自otsu's.
大津二进制:
对象边界:
以及像这样查找质心的代码:
def getCentroid(img):
row, col = img.shape
xVal = 0
yVal = 0
n = 0.0
for x in range(0,row):
for y in range(0,col):
if (img[x,y] == 0):
xVal += x
yVal += y
n += 1.0
xVal /= n
yVal /= n
return [np.int64(np.round(xVal)),np.int64(np.round(yVal))]
但是,该代码似乎只适用于 otsu 的代码。以下是结果:
大津二进制:
对象边界:
那么,如何从对象边界找到对象质心?
注意:我不想使用 built-in 函数,因为我想了解算法的工作原理。
算法很简单:只需平均所有边界像素坐标即可。然而,这将不是真正的质心。要找到真实的,请对对象中包含的所有像素(不仅是边界)进行平均。
如果对象是 凸面,则平均边界将起作用。凸物体是两个内部点之间的连接不会与其边界相交的物体。 将对象分解为此类组件 的最简单方法可能是将其分解为不重叠的矩形,同时尽量将矩形的数量保持在最低限度。矩形质心的平均值(乘以矩形面积)将是对象的质心。
错误很简单。由于这种情况:if (img[x,y] == 0):
,您的算法仅处理黑色像素。您的边界图像包含大部分黑色像素。可以安全地假设此类图像中所有黑色像素的质心非常接近图像的中心。
相关图片宽 402 像素,高 302 像素。您的算法给我们 (x=201, y=151)
作为质心——这符合预期。
要正确处理对象边界,我们需要将边界设为黑色,其他部分设为白色。这很简单,只需将图像反转即可(例如 255 - img
)。那么你的算法returns(x=165, y=123)
,就更有意义了。
代码
import cv2
import numpy as np
def getCentroid(img):
row, col = img.shape
xVal = 0
yVal = 0
n = 0.0
for x in range(0,row):
for y in range(0,col):
if (img[x,y] == 0):
xVal += x
yVal += y
n += 1.0
xVal /= n
yVal /= n
return [np.int64(np.round(xVal)),np.int64(np.round(yVal))]
a = cv2.imread('cnt.png', 0)
c1 = getCentroid(a) # Original
c2 = getCentroid(255 - a) # Inverse
b = cv2.cvtColor(a, cv2.COLOR_GRAY2BGR)
cv2.circle(b, (c1[1], c1[0]), 3, (0,0,255))
cv2.circle(b, (c2[1], c2[0]), 3, (0,255,0))
cv2.imwrite('cnt_out.png', b)
示例输出
注:红色是原图的质心,绿色是倒像的质心。