OpenCV检测go board

时间:2016-02-15 13:45:49

标签: android opencv image-recognition baduk

我正在开发一款能够识别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);

一些图片:

empty board http://roelept82.eightytwo.axc.nl/pic/device-2016-02-15-130011.png filledboard http://roelept82.eightytwo.axc.nl/pic/device-2016-02-15-131431.png

编辑: 05-03-2016

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

仍欢迎有关不同方法的建议!!

filledboard http://roelept82.eightytwo.axc.nl/pic/detect.png

编辑: 15-03-2016

我找到了一种很好的方法来获得与十字型形态变换的线相交,当图片直接在板上方拍摄时,效果很惊人,不幸的是在一定角度时(见下文) morph http://roelept82.eightytwo.axc.nl/pic/morph.png

在我的上一次更新中,我展示了线条和石头检测,上面直接拍摄了一张照片,从那时起,我一直致力于检测电路板,并以我的线和石头检测变得有用的方式对其进行翘曲。

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

    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

comparison http://roelept82.eightytwo.axc.nl/pic/comparison.png

编辑: 31-03-2016

检测线和石头几乎已经解决了所以我将关闭这个问题。 created a new one用于准确检测和扭曲。

任何对我的进步感兴趣的人:this is my GOSU Snap Alpha channel现在不要期待它的大部分内容!

编辑: 16-10-2016

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

该应用最适合使用方形板,粗线和闪亮。

2 个答案:

答案 0 :(得分:3)

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

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

  • 使用行的矩形内核打开和关闭
  • 使用椭圆内核打开和关闭以获取宝石(应该可以在某些时候反转图像以取回白色或黑色)

看看http://docs.opencv.org/2.4/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.html(对不起,这个是C ++,但我认为这在Java中几乎相同)

我尝试过这些操作从数独中移除网格以避免细胞提取中的噪音,它就像一个魅力。

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

答案 1 :(得分:0)

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

相关问题