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?
The image I am currently working with:
I've taken the image and applied a list of processes:
B2G -> Thresh -> Blur -> CannyLineDet -> Inverted -> FindCountours
The output prior to ROI chopping is:
The output ROIs are currently as follows:
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.
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));