Original link: http://codewenda.com/python%E4%BD%BF%E7%94%A8opencv%E5%A4%84%E7%90%86sudoku%E9%97%AE%E9%A2%98/
I'm doing an interesting project: use OpenCV to resolve Sudoku from the input image (e.g., Google Goggles, etc.). I have finished the task, but in the end I found a little problem with my coming here.
I use the Python API of OpenCV 2.3.1 to program.
Here's what I did:
- Read the picture
- Find Outlines
- Select the area of maximum area (also a bit equal to square).
- Find Corner points
For example, the following:
Note that the Green Line is correctly aligned with the true boundaries of the Sudoku, so the Sudoku can be correctly distorted. Check the next picture)
- Transform an image into a perfect square
Example Image:
- Perform OCR (I use the method I gave in the simple Digit recognition OCR in Opencv-python)
And this method works well.
Problem:
Check out this image.
The following results are given in step 4 of the execution of this image:
The red Line drawn is the original contour and is the true contour of the Sudoku boundary.
The Green Line drawn is an approximate contour, which will distort the image's outline.
Of course, there is a difference between a green line and a red line on the top of Sudoku. So at the moment of bending, I didn't get the primitive boundaries of Sudoku.
My question:
How do you distort the image on the correct boundary of Sudoku, the red line, or how to eliminate the difference between the red and green lines? Is there such a way in OpenCV?
Reply:
I have a solution, but you have to convert it to opencv yourself. It is written in mathematics.
The first step is to adjust the brightness in the image by dividing each pixel by the result of the close operation:
123 |
src = ColorConvert[Import[ "http://davemark.com/images/sudoku.jpg" ], "Grayscale" ]; white = Closing[src, DiskMatrix[ 5 ]]; srcAdjusted = Image[ImageData[src] / ImageData[white]] |
The next step is to find the Sudoku area, so I can ignore (cloak) the background. To do this, I use the Join component analysis and select the component with the largest convex area:
12345 |
components
=
ComponentMeasurements[
[email protected][srcAdjusted], {
"ConvexArea"
,
"Mask"
}][[
All
,
2
]];
largestComponent
= Image[SortBy[components, First][[
-
1
,
2
]]]
|
By filling in this image, I get the mask of the Sudoku grid:
1 |
mask = FillingTransform[largestComponent] |
Now, I can use the second derivative filter to find vertical and horizontal lines in two different images:
12 |
lY
= ImageMultiply[MorphologicalBinarize[GaussianFilter[srcAdjusted,
3
, {
2
,
0
}], {
0.02
,
0.05
}], mask];
lX
= ImageMultiply[MorphologicalBinarize[GaussianFilter[srcAdjusted,
3
, {
0
,
2
}], {
0.02
,
0.05
}], mask];
|
I use connection component analysis again to extract gridlines from these images. The grid line is much longer than the number, so I can use the caliper length to select the components that are only connected by the grid line. Sort by location, I get 2x10 masks for each vertical/horizontal gridline in the image:
12345678 |
verticalGridLineMasks
=
SortBy[ComponentMeasurements[
lX, {
"CaliperLength"
,
"Centroid"
,
"Mask"
},
# > 100 &][[All,
2
]],
#[[2, 1]] &][[All, 3]];
horizontalGridLineMasks
=
SortBy[ComponentMeasurements[
lY, {
"CaliperLength"
,
"Centroid"
,
"Mask"
},
# > 100 &][[All,
2
]],
#[[2, 2]] &][[All, 3]];
|
Next, I take each pair of vertical/horizontal gridlines, enlarge them, calculate the pixel-by-node intersection, and calculate the center of the result. These points are the intersection of gridlines:
1234567 |
centerOfGravity[l_] :
=
ComponentMeasurements[Image[l],
"Centroid"
][[
1
,
2
]]
gridCenters
=
Table[centerOfGravity[
ImageData[Dilation[Image[h], DiskMatrix[
2
]]]
*
ImageData[Dilation[Image[v], DiskMatrix[
2
]]]], {h,
horizontalGridLineMasks}, {v, verticalGridLineMasks}];
|
The final step is to define the two interpolation functions for the X/Y mapping through these points and convert the images using these features:
123456 |
fnX
= ListInterpolation[gridCenters[[
All
,
All
,
1
]]];
fnY
= ListInterpolation[gridCenters[[
All
,
All
,
2
]]];
transformed
=
ImageTransformation[
srcAdjusted, {fnX @@ Reverse[
#], fnY @@ Reverse[#]} &, {9*50, 9*50},
PlotRange
-
> {{
1
,
10
}, {
1
,
10
}}, DataRange
-
> Full]
|
All operations are basic image processing functions, so it is also possible in OPENCV. Image transformations based on splines may be more difficult, but I don't think you really need it. It is possible to use the perspective transforms that are now used on each individual cell to give good enough results.
Code question: http://codewenda.com/topics/python/
Stackoverflow:how to remove convexity defects in a Sudoku square?
* Reprint please indicate the link of this article and the English link of StackOverflow
Python uses OpenCV to handle Sudoku problems