<p>您正在使用OpenCV在Python中工作,但是我将使用MATLAB和DIPimage来给您一个答案。我希望这个答案是关于概念的,而不是关于代码的。我确信在Python中使用OpenCV可以实现所有这些功能。在</p>
<p>我的目标是找到棋盘的四个角。网格本身是可以猜到的,因为它只是一个等距的划分板,没有必要尝试检测所有的线。四个角给出了透视变换的所有信息。在</p>
<p>检测电路板的最简单方法是识别出它是浅色的,背景是深色的。从灰度值图像开始,我应用一个小的闭合值(我使用了一个直径为7像素的圆,这适用于我用作示例的下采样图像,但是您可能需要适当地增加全尺寸图像的大小)。结果如下:</p>
<p><a href="https://i.stack.imgur.com/sk39h.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/sk39h.png" alt="enter image description here"/></a></p>
<p>接下来,我使用Otsu阈值选择进行二进制化,并删除孔(该部分不重要,如果有孔,其余部分也可以工作)。我们现在看到的连接元件对应于电路板和相邻的电路板(或电路板周围的其他白色物体)。在</p>
<p>选择最大的连接组件是一个相当常见的过程。在下面的代码中,我标记图像(标识连接的组件),计算每个连接组件的像素数,然后选择像素最多的一个。在</p>
<p>最后,从这个结果中减去它的腐蚀,我们只剩下板边缘的像素(这里是蓝色覆盖在输入图像上):</p>
<p><a href="https://i.stack.imgur.com/ipUMH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ipUMH.png" alt="enter image description here"/></a></p>
<p>我用来寻找角点的技巧非常简单,但是在这里失败了,因为其中一个角不在图像中。在这四条边上使用Hough可能是一种更有效的方法。使用<a href="https://stackoverflow.com/a/44454619/7328782">this other answer</a>获得一些关于如何实现这一点的想法和代码。在</p>
<p>在任何情况下,我都会在棋盘的左上角找到离图像左上角最近的边缘像素。其他3个角也一样。这些结果是上图中的红点。在</p>
<p>这里的第三个选项是将轮廓转换为多边形,使用Douglas–Peucker算法简化它,丢弃沿着图像边缘的边(这是图像中不存在角点的地方),并延伸该边任一侧的两条边,以找到图像外部的顶点。在</p>
<p>下面是MATLAB(带<a href="https://github.com/DIPlib/diplib" rel="nofollow noreferrer">DIPimage</a>)代码。在</p>
<pre class="lang-matlab prettyprint-override"><code>img = readim('https://i.stack.imgur.com/GYZGa.jpg');
img = colorspace(img,'gray');
% Downsample, makes display easier
img = gaussf(img,2);
img = img(0:4:end,0:4:end);
% Simplify and binarize
sim = closing(img,7);
brd = threshold(sim); % uses Otsu threshold selection
% Fill the holes
brd = fillholes(brd);
% Keep only the largest connected component
brd = label(brd);
msr = measure(brd);
[~,I] = max(msr,'size');
brd = brd == msr(I).id;
% Extract edges
brd = brd - erosion(brd,3,'rectangular');
% Find corners
pts = findcoord(brd);
[~,top_left] = min(sum(pts.^2,2));
[~,top_right] = min(sum((pts-[imsize(brd,1),0]).^2,2));
[~,bottom_left] = min(sum((pts-[0,imsize(brd,2)]).^2,2));
[~,bottom_right] = min(sum((pts-[imsize(brd,1),imsize(brd,2)]).^2,2));
% Make an image with corner pixels set
cnr = newim(brd,'bin');
cnr(pts(top_left,1),pts(top_left,2)) = 1;
cnr(pts(top_right,1),pts(top_right,2)) = 1;
cnr(pts(bottom_left,1),pts(bottom_left,2)) = 1;
cnr(pts(bottom_right,1),pts(bottom_right,2)) = 1;
cnr = dilation(cnr,3);
% Save images
writeim(sim,'so1.png')
out = overlay(img,brd,[0,0,255]);
out = overlay(out,cnr,[255,0,0]);
writeim(out,'so2.png')
</code></pre>