打开CV平凡圆检测如何获得最小二乘而不是轮廓?

2024-06-12 04:54:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我的目标是用显微镜精确测量孔的直径。工作流程是:拍摄图像、进行拟合、拟合、将像素半径转换为毫米、写入csv

skewed hough circle

这是我的图像处理脚本的输出,用于测量孔的直径。我有一个问题,我的圆拟合似乎是优先匹配轮廓,而不是像最小二乘法的东西

我也曾多次尝试过这样的尝试:

many fits to avg

我这里的问题是我喜欢快速扫描,以确保圆适合。取舍是,我的合身度越高,合身度越现实,我的合身度越少,就越容易确保数字正确。我的圆圈并不总是像这一个那么漂亮和圆,所以它对我很重要

这是我的脚本拟合圆,如果你能看一下,告诉我如何在5个圆的顺序上进行更多的最小二乘法。我不想使用最小圆检测,因为流体正在流过这个孔,所以我希望它更像一个液压直径——谢谢

(thresh, blackAndWhiteImage0) = cv2.threshold(img0, 100, 255, cv2.THRESH_BINARY) #make black + white 
median0 = cv2.medianBlur(blackAndWhiteImage0, 151) #get rid of noise 
circles0 = cv2.HoughCircles(median0,cv2.HOUGH_GRADIENT,1,minDist=5,param1= 25, param2=10, minRadius=min_radius_small,maxRadius=max_radius_small) #fit circles to image

Tags: csv图像脚本目标半径像素流程cv2
3条回答

我的一个建议是研究cv2.fitEllipse()

OpenCV fitEllipse example on ballons

OpenCV fitEllipse result

希望您可以使用椭圆宽度/高度之间的纵横比来区分奇数

我建议计算nathancy's answer中的掩模,但只需计算他计算的掩模opening中的像素数(这是对孔面积的无偏估计),然后使用radius = sqrt(area/pi)将面积转换为半径。这将为您提供与孔面积相同的圆半径,并对应于获得最佳拟合圆的一种方法

获得最佳拟合圆的另一种方法是获取孔的轮廓(如nethancy答案中cv.findContours返回的cnts),finding its centroid,然后计算每个顶点到质心的平均距离。这将大致对应于孔周长圆的最小二乘拟合

*我之所以说近似,是因为轮廓的顶点是轮廓的近似值,并且这些顶点之间的距离可能不一致。但是错误应该非常小。


下面是使用DIPlib的代码示例(披露:我是作者)(注意:下面的import PyDIP语句要求您安装DIPlib,您不能使用pip安装它,GitHub页面上有一个针对Windows的二进制版本,或者您需要从源代码构建它)

import PyDIP as dip
import imageio
import math

img = imageio.imread('https://i.stack.imgur.com/szvc2.jpg')
img = dip.Image(img[:,2600:-1])
img.SetPixelSize(0.01, 'mm')      # Use your actual values!
bin = ~dip.OtsuThreshold(dip.Gauss(img, [3]))
bin = dip.Opening(bin, 25)
#dip.Overlay(img, bin - dip.BinaryErosion(bin, 1, 3)).Show()

msr = dip.MeasurementTool.Measure(dip.Label(bin), features=['Size', 'Radius'])
#print(msr)

print('Method 1:', math.sqrt(msr[1]['Size'][0] / 3.14), 'mm')
print('Method 2:', msr[1]['Radius'][1], 'mm')

MeasurementTool.Measure函数计算'Size',这是面积;和'Radius',返回每个边界像素和质心之间距离的最大、平均、最小和标准偏差。从'Radius'取第二个值,即平均半径

这将产生:

Method 1: 7.227900647539411 mm
Method 2: 7.225178113501325 mm

但请注意,我指定了一个随机像素大小(每像素0.01mm),您需要填写正确的像素到mm转换值

请注意,这两个估计值非常接近。这两种方法都是良好的无偏估计。第一种方法在计算上比较便宜

这里是另一种拟合圆的方法,通过使用连接的组件从二进制图像中获取等效的圆心和半径,并使用Python/OpenCV/Skimage从中绘制圆

输入:

enter image description here

import cv2
import numpy as np
from skimage import measure

# load image and set the bounds
img = cv2.imread("dark_circle.png")

# convert to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# blur
blur = cv2.GaussianBlur(gray, (3,3), 0)

# threshold
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# apply morphology open with a circular shaped kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
binary = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# find contour and draw on input (for comparison with circle)
cnts = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
c = cnts[0]
result = img.copy()
cv2.drawContours(result, [c], -1, (0, 255, 0), 1)

# find radius and center of equivalent circle from binary image and draw circle
# see https://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.regionprops
# Note: this should be the same as getting the centroid and area=cv2.CC_STAT_AREA from cv2.connectedComponentsWithStats and computing radius = 0.5*sqrt(4*area/pi) or approximately from the area of the contour and computed centroid via image moments.
regions = measure.regionprops(binary)
circle = regions[0]
yc, xc = circle.centroid
radius = circle.equivalent_diameter / 2.0
print("radius =",radius, "  center =",xc,",",yc)
xx = int(round(xc))
yy = int(round(yc))
rr = int(round(radius))
cv2.circle(result, (xx,yy), rr, (0, 0, 255), 1)

# write result to disk
cv2.imwrite("dark_circle_fit.png", result)

# display it
cv2.imshow("image", img)
cv2.imshow("thresh", thresh)
cv2.imshow("binary", binary)
cv2.imshow("result", result)
cv2.waitKey(0)


显示轮廓(绿色)与圆拟合(红色)比较的结果:

enter image description here

圆半径和圆心:

radius = 117.6142467296168   center = 220.2169911178609 , 150.26823599797507



可以使用Scipy获得(轮廓点和圆之间)最小二乘拟合方法。例如,请参见:

https://gist.github.com/lorenzoriano/6799568

https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.curve_fit.html

相关问题 更多 >