【问题标题】:OpenCV different approach on detecting go boardOpenCV检测围棋板的不同方法
【发布时间】:2016-05-26 11:01:33
【问题描述】:

我正在开发一个能够识别GO board 并创建SGF file 的Android 应用程序。

我制作了一个版本,它能够检测板并扭曲透视以使其成为方形(下面的代码和示例图片)不幸的是,添加石头时会变得有点困难。(下图)

关于普通围棋的重要事项:

  • 圆形黑白石头
  • 板上有黑线
  • 板材颜色从白色到浅棕色不等,有时带有木纹
  • 石头放置在两条线的交点上

如果我错了,请纠正我,但我认为我目前的方法不是一个好方法。 有人知道如何将石头和线条与图片的其余部分分开吗?

我的代码:

    Mat input = inputFrame.rgba(); //original image
    Mat gray = new Mat();          //grayscale image

    //convert image to grayscale
    Imgproc.cvtColor( input, gray, Imgproc.COLOR_RGB2GRAY);

    //try to improve histogram (more contrast)
    equalizeHist(gray, gray);

    //blur image
    Size s = new Size(5,5);
    GaussianBlur(gray, gray, s, 0);

    //apply adaptive treshold 
    adaptiveThreshold( gray, gray, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY,11,2);

    //adding secondary treshold, removes a lot of noise
    threshold(gray, gray, 0, 255, Imgproc.THRESH_BINARY + Imgproc.THRESH_OTSU);

一些图片:


(来源:eightytwo.axc.nl)


(来源:eightytwo.axc.nl)

编辑: 05-03-2016

耶!设法正确检测线石头和颜色。前提条件是图片只能是板子本身,不能看到任何其他背景。
我使用 houghLinesP(60 行)和 houghCircles(17 圈),在我的手机(第 1 代 Moto G)上的持续时间约为 5 秒。
当它必须在不同的角度和闪电条件下工作时,检测板和翘曲是一个相当大的挑战。仍然在努力

仍然欢迎提出不同方法的建议!


(来源:eightytwo.axc.nl)

编辑: 15-03-2016

我找到了一个很好的方法来让线与交叉类型的形态变换相交,当照片直接在板上方拍摄时效果惊人,不幸的是不是在一个角度时(见下文)
(来源:eightytwo.axc.nl)

在我上次的更新中,我展示了线和石头检测以及从正上方拍摄的照片,从那时起我一直致力于检测板并以某种方式扭曲它,以便我的线和石头检测变得有用。

哈里斯角检测
我努力获得正确的参数设置,我仍然不确定它们是否是最佳的,在使用哈里斯角之前找不到关于如何优化图像的太多信息。现在它检测到许多角落都是有用的。虽然感觉它可以工作。 (上面有图片的例子)

    Mat corners = new Mat();
    Imgproc.cornerHarris(image, corners, 5, 3, 0.03);

    Mat mask = new Mat(corners.size(), CvType.CV_8U, new Scalar(1));
    Core.MinMaxLocResult maxVal = Core.minMaxLoc(corners);

    Core.inRange(corners, new Scalar(maxVal.maxVal * 0.01), new Scalar(maxVal.maxVal), mask);

交叉型形态变换
当直接从上方拍摄照片时效果很好,从某个角度使用或旋转板不起作用(示例中的图片中线)

    Imgproc.GaussianBlur(image, image, new Size(5, 5), 0);
    Imgproc.adaptiveThreshold(image, image, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY_INV, 11, 2);

    int morph_elem = 1;     //0: Rect - 1: Cross - 2: Ellipse
    int morph_size = 5;

    int morph_operator = 0; //0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat
    Mat element = getStructuringElement( morph_elem, new Size(2 * morph_size + 1, 2 * morph_size + 1), new Point( morph_size, morph_size ));
    morphologyEx(image, image, morph_operator + 2, element);

等高线和 houghlines
如果外板线上没有石头并且光线条件不苛刻,它会很好地工作。轮廓通常只是棋盘的一部分(下一行以图片为例)

    Imgproc.GaussianBlur(image, image, new Size(5, 5), 0);
    Imgproc.adaptiveThreshold(image, image, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY_INV, 11, 2);

    Mat hierarchy = new Mat();
    MatOfPoint biggest     = null;
    int contourId          = 0;
    double biggestArea     = 0;

    double minSize = 2000;
    List<MatOfPoint> contours = new ArrayList<>();

    findContours(InvertedImage, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

    //find biggest
    for( int x = 0; x < contours.size() ; x++ ){

        double area = Imgproc.contourArea(contours.get(x));

        if( area > minSize && area > biggestArea ){

            biggestArea = area;
            biggest     = contours.get(x);
            contourId   = x;
        }
    }

提供正确的图片所有这三种方法都有效,但还不够可靠。欢迎对参数、图像预处理、不同方法或任何可能改进检测的任何想法=)

link to picture

编辑: 31-03-2016

检测线条和石头已经基本解决了,所以我将结束这个问题。 created a new one 用于准确检测和变形。

任何对我的进展感兴趣的人:this is my GOSU Snap Alpha channel 现在不要期望太多!

编辑: 2016 年 16 月 10 日

更新:我看到有些人仍在关注这个问题。 我测试了更多东西并开始使用 Tensorflow,我的神经网络看起来很有希望, you can have a look at it here. 还有很多工作要做,我当前的图像数据集很糟糕,现在我正在努力获取一个大数据集。

该应用程序最好使用带有粗线条和良好闪电的方板。

【问题讨论】:

    标签: android opencv image-recognition baduk


    【解决方案1】:

    假设您不想“强迫”最终用户拍摄最干净的照片(例如使用某些 QR 码扫描仪之类的叠加层)

    也许您可以对不同的内核使用一些形态学转换:

    • 使用矩形内核打开和关闭线条
    • 使用椭圆内核打开和关闭以获取石头(应该可以在某个点反转图像以恢复白色或黑色)

    看看http://docs.opencv.org/2.4/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.html(抱歉这个是用C++写的,但我觉得这在Java里差不多)

    我尝试了这些操作来从数独中删除网格以避免单元格提取中的噪音,它就像一个魅力。

    让我知道这些信息对你有用(这肯定是一个非常有趣的案例)

    【讨论】:

    • 谢谢!我明白这个想法。必须对其进行测试,并将结果与​​您联系。
    • 我对这个建议非常满意,不幸的是,对于与这个不同的项目来说更是如此。我设法移除了线条(请参阅链接),但我也无法在不移除线条的情况下移除石头。 dropbox.com/s/hdvtshj1e481u4c/lineremoval.png?dl=0 旁边说这不是一个很快的转换,最后我希望能够每秒处理至少 2 张图片(而不是当前的每 3 秒 1 张),以便在游戏中获得连续注册进展
    • 根据您的编辑,我发现您可以检测到您想要的内容。对于处理时间,我能想到的最简单的事情就是在处理之前降低图片分辨率。尝试将分辨率除以 1.5、2、2.5、3 等,然后观察结果和处理时间。这些转换必须检查每个像素,将初始分辨率除以 2 将使您的处理时间减少近 4。
    • 谢谢!!这似乎有很大帮助,将尝试更多以获得最佳结果,我将检查是否可以从拍摄较小的照片开始,而不是我现在使用的全分辨率照片。你为什么建议1.5、2.2、5.3? 2.2 似乎比 2 更好,所以我很好奇这是基于什么
    • 是的,板子检测工作得很好,不幸的是,当人们拍照时,板子和周围的一些空间都是可见的。现在,当外板线的棋子少于 8 颗时,我能够检测到它,但有时会有更多的棋子,这仍然是一个问题,我对不同的方法有一些想法,但到目前为止还没有希望,很快我就会发布更新以比较它们,并希望获得一些反馈以改进它们或获得一些建议
    【解决方案2】:

    我正在开发相同的程序。我完全避免找线。 首先使用透视变换将板子变成正方形。找到 19x19 网格的边缘。然后假设板是 19x19,你可以计算线条的位置。这对我很有效。然后计算最接近石头中心的交点,以确定石头在哪一行和哪一行。对我来说效果很好。可能只是针对不同照明条件和不同颜色的宝石和板材的校准程序。

    【讨论】:

    • 如何定位板子以执行正确的透视变换?
    • 基本调用find contours来获取board的所有轮廓。
    • 然后找到最大面积轮廓,然后找到该轮廓的凸包。这通常有效。
    猜你喜欢
    • 1970-01-01
    • 2023-01-18
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多