有没有办法判断一个圆是否有这样的缺陷?圆度不起作用。还是有办法消除它们?

perimeter = cv2.arcLength(cnts[0],True)
area = cv2.contourArea(cnts[0])
roundness = 4*pi*area/(perimeter*perimeter)
print("Roundness:", roundness)发布于 2022-11-21 20:25:19
“圆度”测量对周长的精确估计很敏感。cv2.arcLength()所做的是添加每个多边形边的长度,它严重高估了轮廓的长度。我认为这是这个措施对你不起作用的主要原因。有了一个更好的周长估计器,你就会得到有用的结果。
另一种可能更有用的度量是“圆度”,定义为半径的变异系数。简而言之,计算每个多边形顶点(即轮廓点)到质心的距离,然后确定这些距离的变异系数(== std /平均值)。
我编写了一个快速Python脚本,从OpenCV轮廓开始计算它:
import cv2
import numpy as np
# read in OP's example image, making sure we ignore the red arrow
img = cv2.imread('jGssp.png')[:, :, 1]
_, img = cv2.threshold(img, 127, 255, 0)
# get the contour of the shape
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contour = contours[0][:, 0, :]
# add the first point as the last, to close it
contour = np.concatenate((contour, contour[0, None, :]))
# compute centroid
def cross_product(v1, v2):
"""2D cross product."""
return v1[0] * v2[1] - v1[1] * v2[0]
sum = 0.0
xsum = 0.0
ysum = 0.0
for ii in range(1, contour.shape[0]):
v = cross_product(contour[ii - 1, :], contour[ii, :])
sum += v
xsum += (contour[ii - 1, 0] + contour[ii, 0]) * v
ysum += (contour[ii - 1, 1] + contour[ii, 1]) * v
centroid = np.array([ xsum, ysum ]) / (3 * sum)
# Compute coefficient of variation of distances to centroid (==circularity)
d = np.sqrt(np.sum((contour - centroid) ** 2, axis=1))
circularity = np.std(d) / np.mean(d)发布于 2022-11-25 16:00:56
这让我想到了一个类似的问题。您可以计算形状的签名。签名可以定义为,对于形状边界的每个像素,该像素与形状中心之间的距离。
对于一个完美的圆,从边界到中心的距离应该是恒定的(在一个理想的连续世界中)。当缺陷出现在圆的边缘(凹痕或过度)时,理想的常量线会变成一条摇摆的曲线,在缺陷上会有很大的变化。
例如,用FFT来检测这些变化是相当容易的,这样就可以量化缺陷的重要性。
您可以将此解决方案扩展到任意给定的形状。如果你的理想形状是正方形,你可以计算签名,这会给你一些正弦曲线。缺陷将以同样的方式出现在曲线上,并且可以用与圆相同的逻辑来检测。

我不能给你一个代码示例,因为项目是为一个公司的项目,但这个想法仍然存在。
发布于 2022-11-25 21:52:16
这里有一种在Python/OpenCV中实现这一功能的方法。
输入:

import cv2
import numpy as np
# Read image
img = cv2.imread('circle_defect.png')
hh, ww = img.shape[:2]
# threshold on white to remove red arrow
lower = (255,255,255)
upper = (255,255,255)
thresh = cv2.inRange(img, lower, upper)
# get Hough circles
min_dist = int(ww/5)
circles = cv2.HoughCircles(thresh, cv2.HOUGH_GRADIENT, 1, minDist=min_dist, param1=150, param2=15, minRadius=0, maxRadius=0)
print(circles)
# draw circles on input thresh (without red arrow)
circle_img = thresh.copy()
circle_img = cv2.merge([circle_img,circle_img,circle_img])
for circle in circles[0]:
# draw the circle in the output image, then draw a rectangle
# corresponding to the center of the circle
(x,y,r) = circle
x = int(x)
y = int(y)
r = int(r)
cv2.circle(circle_img, (x, y), r, (0, 0, 255), 1)
# draw filled circle on black background
circle_filled = np.zeros_like(thresh)
cv2.circle(circle_filled, (x,y), r, 255, -1)
# get difference between the thresh image and the circle_filled image
diff = cv2.absdiff(thresh, circle_filled)
# apply morphology to remove ring
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
result = cv2.morphologyEx(diff, cv2.MORPH_OPEN, kernel)
# count non-zero pixels
defect_count = np.count_nonzero(result)
print("defect count:", defect_count)
# save results
cv2.imwrite('circle_defect_thresh.jpg', thresh)
cv2.imwrite('circle_defect_circle.jpg', circle_img)
cv2.imwrite('circle_defect_circle_diff.jpg', diff)
cv2.imwrite('circle_defect_detected.png', result)
# show images
cv2.imshow('thresh', thresh)
cv2.imshow('circle_filled', circle_filled)
cv2.imshow('diff', diff)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()没有红箭的输入:

根据输入绘制的红色圆圈:

从HoughCircle圈:

差异:

消除差异:

文本结果:
defect count: 500https://stackoverflow.com/questions/74523496
复制相似问题