通过计算机视觉分割和标记棋盘

信息处理 图像处理 计算机视觉 opencv 图像分割
2022-01-30 07:35:32

由于几乎没有计算机视觉方面的经验/知识,我目前正在尝试分割和标记棋盘上的单独方块(即 a1 ... h8)。我的目标是利用这些信息,通过网络摄像头和机械臂与 AI 实际下棋。

我正在用 C#(使用 Emgu CV)编写视觉程序,以实现更简单的编程和 GUI 实现。作为我的第一步,我尝试按照本教程来检测正方形。

在此处输入图像描述

正如我们所看到的,并非所有的方块都被检测到,我相信有些方块被检测到不止一次(因为创建了 91 个框)。

问题

  1. 在确定 Canny 阈值和阈值链接的合适值时要考虑哪些因素?IEgray.Canny(cannyThreshold, cannyThresholdLinking)
  2. 原始图像中的正方形对我们来说是直线,但对计算机来说,它略微倾斜。这是什么原因?是因为边缘有锯齿吗?
  3. 为什么大部分方块都没有检测到?会不会是灯光?
  4. 我应该研究哪些适当的技术/方法来解决这个问题?我现在只熟悉关键字:Canny、Hough(我相信的圈子)和 Sobel。

代码

Image<Bgr, Byte> image = new Image<Bgr, Byte>(Emgu_CV.Properties.Resources.Chessboard).Resize(0.15, INTER.CV_INTER_LINEAR);
Image<Gray, Byte> gray = image.Convert<Gray, Byte>(); //.PyrDown().PyrUp() worsens detection

imageBox.Image = image;

double cannyThreshold = 180.0;
double cannyThresholdLinking = 150.0;   

Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking);

List<MCvBox2D> boxList = new List<MCvBox2D>();

using (MemStorage storage = new MemStorage())
    for (Contour<Point> contours = cannyEdges.FindContours(); contours != null; contours = contours.HNext)
    {
        Contour<Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage); // don't quite understand the purpose of *0.05
        if (contours.Area > 250 && contours.Area < 10000)
        {
            if (currentContour.Total == 4)
            {
                bool isSquare = true;
                Point[] pts = currentContour.ToArray();
                LineSegment2D[] edges = PointCollection.PolyLine(pts, true);

                for (int i = 0; i < edges.Length; i++)
                {
                    double angle = Math.Abs(edges[(i + 1) % edges.Length].GetExteriorAngleDegree(edges[i]));

                    if (angle < 80 || angle > 95)
                    {
                         isSquare = false;
                         break;
                    }

                    if (isSquare) boxList.Add(currentContour.GetMinAreaRect());                    
                } 
            }
        }     
    }

Image<Bgr, Byte> squareImage = image.CopyBlank();
foreach (MCvBox2D box in boxList)
    squareImage.Draw(box, new Bgr(Color.Yellow), 1);
outputBox.Image = squareImage;
3个回答

我曾经做过类似的事情。您应该尝试一下OpenCV 的棋盘检测也有关于数独方块检测的作品,这可能会给你一个提示。

如果这些对您不起作用,那么我会建议以下内容:忘记检测棋盘。最初,假设每一块都到位并拍摄板的快照(您甚至可以手动放置初始板,没关系)。然后,每当移动一块时,抓取一个新图像并应用两个图像的差异(这有点像背景减法)。请注意,通过这种方式,您可以轻松获取移动部件的位置。而且由于您事先知道这件作品以及先前位置的内容,因此您可以获得移动的完整信息。

就像你展示的那样,使用向下看的相机。

检测直线的规范算法是氡(线霍夫)变换,因为它将线转换为点。轮廓检测过滤器,然后是这种变换的阈值,应该会给你一个很好的分割。然后使用分水岭算法来标记您的区域。

如果您没有完全锁定 C#,我会推荐 MATLAB 计算机视觉系统工具箱中的detectCheckerboardPoints函数。它比 OpenCV 中的类似功能更强大。