对于图像 I I I,位置 ( x , y ) (x,y) (x,y)处的图像灰度值表示为 I ( x , y ) I(x,y) I(x,y),则图像的 ( i , j ) (i,j) (i,j)阶矩 m ( i , j ) m_{(i,j)} m(i,j)表示为:
m ( i , j ) = ∑ x ∑ y x i y j I ( x , y ) (1) m_{(i,j)}=\sum_{x}\sum_{y}x^{i}y^{j}I(x,y)\tag{1} m(i,j)=x∑y∑xiyjI(x,y)(1)
比如对于 m 0 , 0 = ∑ x ∑ y I ( x , y ) m_{0,0}=\sum_{x}\sum_{y}I(x,y) m0,0=∑x∑yI(x,y),表示图像灰度总和。
图像质心 ( x ‾ , y ‾ ) (\overline{x},\overline{y}) (x,y)可以表示为:
x ‾ = m 1 , 0 m 0 , 0 , y ‾ = m 0 , 1 m 0 , 0 (2) \overline{x}=\frac{m_{1,0}}{m_{0,0}}, \overline{y}=\frac{m_{0,1}}{m_{0,0}}\tag{2} x=m0,0m1,0,y=m0,0m0,1(2)
在《机器视觉算法与应用》(第二版)第3.5.2.4节中,介绍了一种使用灰度值距求得亚像素级精度圆的位置和面积,书中介绍该方法在处理小物体时,灰度值距能得到精确度更好的处理结果。
在Halcon中该方法归纳为area_center_gray算子。该函数签名为
area_center_gray(Regions, Image : : : Area, Row, Column)
输入参数为待计算区域Regions和图像Image,输出参数为面积Area,圆心坐标Row、Column。
在官方文档中,介绍了计算方法:对于面积Area则表示为Region区域内图像Image的灰度值和 m 0 , 0 m_{0,0} m0,0。对于圆心,则与公式(2)一致。圆半径计算公式为:
r = A r e a f o r e g r o u n d × π 2 r=\sqrt[2]{\frac{Area}{foreground\times \pi}} r=2foreground×πArea
foreground表示前景灰度值,即圆内灰度值。
import cv2
import numpy as np
import math
def area_center_gray(contour, image):
mots = cv2.moments(contour)
x = mots["m10"] / mots["m00"]
y = mots["m01"] / mots["m00"]
center = (x, y)
# 使用mask,仅统计contour内像素
mask = np.zeros_like(image)
cv2.drawContours(mask, [contour], -1, 255, -1)
image = cv2.bitwise_and(image, mask)
area = cv2.sumElems(image)[0]
return center, area
org_img = cv2.imread("images\\gray_hole.bmp", 0)
_, th_img = cv2.threshold(org_img, 50, 255, cv2.THRESH_BINARY)
foreground_val = 255
contours, _ = cv2.findContours(th_img, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
center, area = area_center_gray(cnt, org_img)
radius = math.sqrt(area / foreground_val / math.pi)
函数area_center_gray
基本模拟Halcon中表现,由于OpenCV中没有Region对象,因此使用contour
替换,函数返回圆心center
和灰度值面积area
。
在测试代码中,使用简单阈值分割和findcontours
函数,对圆区域进行定位。通过公式(2)计算圆半径radius
。拟合结果如下所示: