目前我正在使用数独网格,我有二进制图像。我正在使用Regionprops
来获取连接组件的区域,然后将图像的其余部分变为黑色。在此之后,我调用 OCR 方法来尝试读取数独数字。问题是,这仅在图像中的数独网格笔直且直立时才有效。如果它旋转一点点,我就无法拉动数字。这是我到目前为止的代码:
% get grid connected parts
conn_part = bwconncomp(im_binary);
% blacken area outside
stats = regionprops(conn_part,'Area');
im_out = im_binary; % Make mask
im_out(vertcat(conn_part.PixelIdxList{[stats.Area] < 825 | [stats.Area] > 2500})) = 0;
imagesc(im_out);
title("Numbers pulled");
sudokuNum = ocr(im_out,'TextLayout','Block','CharacterSet','0123456789');
sudokuNum.Text;
其中im_binary
是二进制图像
im_out
为输出图像
stats
是从包含所连接组件区域的regionprops
返回的对象
我知道我可以通过以下方式在获得 OCR 结果之前旋转图像:
im_out = imrotate(im_out, angle)
但是我不知道网格的角度,因为这是循环浏览多个图像的功能的一部分。我研究了regionprops
方法,因为有一个属性"方向",我可以从那里提取,但我不明白我实际上如何使用它。它还指出regionprops
将返回一个介于 -90 和 90 之间的值,但我的图像可以旋转 90 度以上。
不要旋转连接的组件或二进制图像。首先使用二值图像确定旋转,然后旋转原始灰度或彩色输入图像,然后对旋转的图像进行二值化。您将能够使用插值进行变换,这将大大改善您的结果。它确实需要执行两次二值化步骤,但我认为此步骤通常不会太昂贵。
regionprops
方向特征是通过将椭圆"拟合"到形状来计算的。这仅对细长对象有意义。对于方形数独网格,这不会产生任何有价值的信息。
相反,看看获得最小费雷特直径的角度。费雷特直径是任意角度下投影的长度。在一个角度上,这个投影是最小的。它必须与正方形的主轴之一成相对应的角度。以下是有关如何在 MATLAB 中计算 Feret 直径的更多信息。
另一种选择是例如使用霍夫变换来检测网格的线。
请注意,拼图的几何形状永远不会告诉您哪一边是向上的。您在这里得到的角度应取模 π/2(即限制在 -π/4 到 π/4 的范围)。
要知道方向是向上的,您可以通过尝试阅读文本来做,如果失败,请旋转 90 度并重试。