<p>我建议计算<a href="https://stackoverflow.com/a/60289641/7328782">nathancy's answer</a>中的掩模,但只需计算他计算的掩模<code>opening</code>中的像素数(这是对孔面积的无偏估计),然后使用<code>radius = sqrt(area/pi)</code>将面积转换为半径。这将为您提供与孔面积相同的圆半径,并对应于获得最佳拟合圆的一种方法</p>
<p>获得最佳拟合圆的另一种方法是获取孔的轮廓(如nethancy答案中<code>cv.findContours</code>返回的<code>cnts</code>),<a href="https://en.wikipedia.org/wiki/Centroid#Of_a_polygon" rel="nofollow noreferrer">finding its centroid</a>,然后计算每个顶点到质心的平均距离。这将大致对应于孔周长圆的最小二乘拟合</p>
<p><sup>*我之所以说近似,是因为轮廓的顶点是轮廓的近似值,并且这些顶点之间的距离可能不一致。但是错误应该非常小。</sup></p>
<hr/>
<p>下面是使用<a href="https://github.com/DIPlib/diplib" rel="nofollow noreferrer">DIPlib</a>的代码示例(披露:我是作者)(注意:下面的<code>import PyDIP</code>语句要求您安装DIPlib,您不能使用<code>pip</code>安装它,GitHub页面上有一个针对Windows的二进制版本,或者您需要从源代码构建它)</p>
<pre class="lang-py prettyprint-override"><code>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')
</code></pre>
<p><code>MeasurementTool.Measure</code>函数计算<code>'Size'</code>,这是面积;和<code>'Radius'</code>,返回每个边界像素和质心之间距离的最大、平均、最小和标准偏差。从<code>'Radius'</code>取第二个值,即平均半径</p>
<p>这将产生:</p>
<pre><code>Method 1: 7.227900647539411 mm
Method 2: 7.225178113501325 mm
</code></pre>
<p>但请注意,我指定了一个随机像素大小(每像素0.01mm),您需要填写正确的像素到mm转换值</p>
<p>请注意,这两个估计值非常接近。这两种方法都是良好的无偏估计。第一种方法在计算上比较便宜</p>