javaopencvimage-processing

Getting squares from a grid in OpenCV, why cant system detect more squares?


I've been trying to create a chessboard reader, nothing fancy so far, just want to be able to read the squares presented. The problem seems to be that while some squares are detectable others are being disregarded by the system. Currently I've read and attempted all solutions from these similar questions:

Python OpenCV: Rubik's cube solver color extraction

How to get the cells of a sudoku grid with OpenCV?

Square detection in image

The image I am currently working with:

enter image description here

I've taken the image and applied a list of processes:

B2G -> Thresh -> Blur -> CannyLineDet -> Inverted -> FindCountours

The output prior to ROI chopping is:

enter image description here

The output ROIs are currently as follows:

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

This is the code, but its in Java, if the posted solution is in python that is fine as it is fairly easy to convert between.

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

boolean writeFile = true;
// Mat src =
// Imgcodecs.imread("C:\\Users\\thorf\\Documents\\JavaWS\\openCVtest\\src\\openCVtest\\linesinput.png");
Mat src = Imgcodecs.imread("C:\\Users\\thorf\\Documents\\JavaWS\\openCVtest\\src\\openCVtest\\chessboard.png");
Mat grey = new Mat();
Size size = new Size(3, 3);
double[][] sharpenKernel = { { -1, -1, -1 }, { -1, 9, -1 }, { -1, -1, -1 } };

Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, size);

Imgproc.cvtColor(src, grey, Imgproc.COLOR_BGR2GRAY);

Mat threshed = new Mat();
Imgproc.threshold(grey, threshed, 200, 255, Imgproc.THRESH_OTSU);
Imgcodecs.imwrite("threshed.png", threshed);
showWaitDestroy("threshed", threshed);

Mat blur = new Mat();
Imgproc.medianBlur(threshed, blur, 5);
Imgcodecs.imwrite("blur.png", blur);
showWaitDestroy("blur", blur);
        
Mat edges = new Mat();
Imgproc.Canny(blur, edges, 50, 400);
Imgcodecs.imwrite("edges.png", edges);
showWaitDestroy("edges", edges);
        
Mat inv = new Mat();
Core.bitwise_not(edges, inv);
Imgcodecs.imwrite("inv.png", inv);
showWaitDestroy("inv", inv);
        
processROIs(inv, src);

As can be seen only certain squares are being detected, often those that are white and have pieces in them, however this is not always the case.

My question is whether there is a better way to do this, or whether I am missing something in this implementation? First time using CV so any help is appreciated.

EDIT: I can't divide the image into sections as the input will not always be this image. It may be in another border etc which prevents me from finding the outer bounds.


Solution

  • OpenCV has an out-of-the-box method to find chessboard corners: https://docs.opencv.org/4.5.1/d9/d0c/group__calib3d.html#ga93efa9b0aa890de240ca32b11253dd4a

    In java it would look something like:

    //for a standard 8x8 chessboard, the method needs the inner corners
    int nrows = 7; 
    int ncols = 7;
    MatOfPoint2f corners = new MatOfPoint2f();
    Calib3d.findChessboardCorners(myImg, corners, new Size(nrows, ncols));