MATLAB:从二进制图像中分割单个字母

时间:2014-10-30 04:27:00

标签: matlab image-processing computer-vision

我正在进行一个光学字符识别项目,我正在尝试创建一个程序来识别图像中的字母。我正在按照Mathworks上的教程(Digit Classification)进行操作。在他们的例子中,他们的训练图像已经分开。不幸的是,我在一个文件中提供了包含数百个字母的训练图像。

以下是一个示例:

我需要一种有效的方法将每个单独的字母分割成图像,所以我将有一个26Xn数组,其中26是字母表中的每个字母,n是包含单个字母的n个图像数据变量。由于字母之间的分隔并不总是相等,因此手动分割每个训练图像中的字母或尝试按指定长度分割字母将是非常繁琐的。

有没有人知道MATLAB函数或一种简单的方法,我可以识别每个连续白色物体的高度和长度,并将所有单个白色物体的黑色背景存储在上述26Xn阵列中(或至少存储在某种类型的数组中,以后我可以将它处理成26xn数组)?

2 个答案:

答案 0 :(得分:9)

如果要提取图像中的每个角色,可以使用regionprops轻松完成。只需使用BoundingBox属性即可提取每个字符周围的边界框。执行此操作后,我们可以将每个字符放在cell数组中以进行进一步处理。如果要将其存储到26 x N数组中,则需要识别每个字母的第一个字母,以便您可以选择该字母应该插入第一个维度的插槽。因为您想先将字符分段,我们将专注于此。因此,让我们将图像加载到MATLAB中。请注意,原始图像是在GIF中,当我将它加载到我的计算机上时......它看起来很混乱。我已将图像重新保存为PNG,如下所示:

enter image description here

让我们把它读到MATLAB中:

im = imread('http://i.stack.imgur.com/q7cnA.png');

现在,您可能会注意到某些字母之间存在一些不连续性。我们能做的是进行形态学开放以弥补这些差距。但是,我们不会使用此图像来提取实际字符。我们只使用这些来获取字母的边界框:

se = strel('square', 7);
im_close = imclose(im, se);

现在,您可以像这样调用regionprops来查找图像中的所有边界框(应用形态学后):

s = regionprops(im_close, 'BoundingBox');

s中返回的是一种结构,其中此结构中的每个元素都包含一个封装框,该边界框封装了图像中检测到的对象。在我们的例子中,这是一个单一的角色。每个对象的BoundingBox属性是一个4元素数组,其格式如下:

[x y w h]

(x,y)是边界框左上角的列和行坐标,wh是边界框的宽度和高度。我们接下来要做的是创建一个4列矩阵,将所有这些边界框属性封装在一起,其中每一行表示一个边界框:

bb = round(reshape([s.BoundingBox], 4, []).');

有必要对值进行舍入,因为如果要从图像中提取字母,我们必须在整数坐标中执行此操作,因为这是图像自然定义的方式。如果你想要很好地说明这些边界框,下面的代码将在我们检测到的每个字符周围绘制一个红色框:

imshow(im);
for idx = 1 : numel(s)
    rectangle('Position', bb(idx,:), 'edgecolor', 'red');
end

这就是我们得到的:

enter image description here

最后的工作是提取所有字符并将它们放入cell数组中。我正在使用cell数组,因为字符大小不均匀,因此将其放入cell数组将适应不同的大小。因此,只需循环遍历我们拥有的每个边界框,然后提取像素的边界框以获取每个字符并将其放入单元格数组中。因此:

chars = cell(1, numel(s));
for idx = 1 : numel(s)
    chars{idx} = im(bb(idx,2):bb(idx,2)+bb(idx,4)-1, bb(idx,1):bb(idx,1)+bb(idx,3)-1);
end

如果你想要一个角色,只需ch = chars{idx}; idx,其中imshow(ch);是1到任意数字的任意数字。您还可以通过{{1}}

查看此字符的外观

这应该会给你足够的开始。祝你好运!

答案 1 :(得分:2)

您正在寻找bwlabel标记图片中的每个字母 您可能会觉得有用的另一个工具是regionprops,尤其是'Image'属性。

在您的comment中,您声明您在使用Matlab标记您的区域的顺序时遇到困难:Matlab的矩阵和图像以列主要顺序存储在内存中(这是一列又一列),因此"发现"二进制图像中的新组件,从上到下,从左到右。为了逐行探索图像,您可能需要考虑转置图像:

[ind map] = imread('http://i.gyazo.com/0ca8d4416a52b8bc3401da0b71a527fd.gif'); %//read indexed image
BW = max( ind2rgb(ind,map), [], 3 ) > .15; %//convert RGB image to binary mask
seg = regionprops( BW.', 'Image' ); %'// transpose input mask
seg = arrayfun( @(x) x.Image.', seg, 'Uni', 0 ); %'// flip back

现在,您将单独的字母放在单元格数组seg中的单元格中。

请注意,通过向regionprops提供二进制输入,您无需明确调用bwlabel