【问题标题】:Creating a chessboard mask to check the status of the squares on a chessboard创建棋盘掩码以检查棋盘上方格的状态
【发布时间】:2015-06-28 02:29:56
【问题描述】:

我想从棋盘中提取方格,并根据它们的坐标标记每个方格,即 a1、a2、... h8。我的目标是创建一个“掩码”来检查每个方块是否存在一块。我目前正在使用 Emgu CV 在 C# 中编写一个程序来执行此操作。

用于测试的图片可以在here找到。

由于没有计算机视觉方面的经验,我只遵循以基本思想为指导的简单代码示例。我的第一个线索是tutorial,它告诉我如何制作一个简单的形状检测器。虽然测试图像比示例图像更复杂,但它不是很准确。

不准确的正方形检测(图像略有不同)

结果有两个问题:1)并非所有的方块都被检测为方块; 2) 创建了 91 个框(而不是 64 个)来可视化检测到的正方形。

为了解决问题 #1,我使用了具有膨胀和中值平滑的二进制阈值来进一步“简化”图像,结果要好得多但不完整(由于噪声):

在应用二元阈值、膨胀、中值平滑和腐蚀后

对正方形进行可视化和计数

由于我不知道的原因,似乎多次检测到同一个方块(即问题 #2),我不知道如何解决这个问题。我最初的想法是一旦检测到每个方块就给它们一个标签,但现在似乎不切实际。

问题

  1. 我可以使用哪些方法来消除方块 b3 和 g6 上的滤波后噪声?
  2. 我可以使用哪些方法来正确地按行顺序对正方形进行计数和排序?
  3. 假设我设法标记了每个正方形,那么我如何“保存”正方形的区域以重新用作新帧的蒙版?拥有 64 个独特的掩码在计算上是否昂贵?
  4. 如何最大化方块的检测率?

【问题讨论】:

  • 你做了很多好事!您是否考虑过备份并简化问题?您基本上已经创建了一个算法,可以计算任意 n 个任意颜色的正方形。一个更简单的问题是检测“棋盘”,例如一个 8x8 的交替模式网格。
  • @AdamFinley 我应该如何检测交替模式的网格?我与一些工程专业的学生交谈,一个建议是从左到右检测像素的强度,其中陡峭的值表示不同正方形的边缘。我现在的问题是我有想法,但我不知道如何实施。
  • 您的问题不清楚您是否将始终将算法应用于相同的棋盘(即相同的视点、比例等),或者您是否正在考虑一般情况。如果是这种情况,您是否考虑过使用固定网格而不是检测正方形?在我看来,这将大大简化问题,并将您的工作减少到检测棋盘的一个角以定位网格,然后将每个正方形内的图像(可以裁剪)提供给棋子检测算法。我曾经在类似的情况下使用过这种方法,效果很好。
  • @edu_ 我正在考虑一般情况,例如安装在可调节夹具上的朝下摄像头。就我而言,我可以通过调整处理函数的参数来校准程序,直到检测到所有方块。感谢您对使用固定网格的建议,我将尝试实现它。对于固定网格方法,您是否必须处理任何失真校正?
  • @Dennis,正如您在我的回答中看到的那样(也可以作为您实施的起点),前几个蓝色方块(从左上角算起)几乎与棋盘方格,但是当我们向右下角移动时,这不会发生,这表明要么存在失真,要么棋盘方格的大小不同(或两者都相同)。我没有处理过这些情况,但强烈建议您纠正解决方案中的失真。

标签: opencv image-processing computer-vision emgucv


【解决方案1】:

关于我在原始问题中的评论,我实现了一些可以作为固定网格构造示例的东西:

#define SQUARE_SIZE 131
#define OFFSET_X 75
#define OFFSET_Y 75
#define NUM_SQUARES_X 8
#define NUM_SQUARES_Y 8

using namespace std;
using namespace cv;

int main(){

    // Directory settings
    const string pathToData = "../data/";

    vector<string> filenames = std::vector<string>();

    // Load filenames
    glob(pathToData, filenames, false);

    if(filenames.size() <= 0){
        cout << "no images were found..." << endl;
        return -1;
    }


    Mat chessboard = imread(pathToData+"chessboard.jpg", IMREAD_UNCHANGED);

    for (int i=0;i<NUM_SQUARES_X;i++){
        for (int j=0;j<NUM_SQUARES_Y;j++){

            int startX = OFFSET_X + SQUARE_SIZE*i;
            int startY = OFFSET_Y + SQUARE_SIZE*j;
            int endX = startX + SQUARE_SIZE;
            int endY = startY + SQUARE_SIZE;

            rectangle(chessboard, Point(startX,startY), Point(endX,endY), Scalar(255,0,0), 3, 8, 0);
        }
    }

    namedWindow("chessboard", WINDOW_NORMAL);
    imshow("chessboard", chessboard);  

    cv::waitKey(0); 

    return 0;
}

上述代码的输出如下图所示:

当然,您必须微调参数(偏移和方形尺寸),因为我没有花太多时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2016-02-28
    相关资源
    最近更新 更多