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

Jul*_*vka 4 matlab image-processing computer-vision

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

这是一个示例:

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

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

ray*_*ica 9

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

在此输入图像描述

我们将其读入MATLAB:

im = imread('http://i.stack.imgur.com/q7cnA.png');
Run Code Online (Sandbox Code Playgroud)

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

se = strel('square', 7);
im_close = imclose(im, se);
Run Code Online (Sandbox Code Playgroud)

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

s = regionprops(im_close, 'BoundingBox');
Run Code Online (Sandbox Code Playgroud)

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

[x y w h]
Run Code Online (Sandbox Code Playgroud)

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

bb = round(reshape([s.BoundingBox], 4, []).');
Run Code Online (Sandbox Code Playgroud)

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

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

这就是我们得到的:

在此输入图像描述

最后的工作是提取所有字符并将它们放入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
Run Code Online (Sandbox Code Playgroud)

如果你想要一个角色,只需做一个从1到尽可能多的任何数字的ch = chars{idx};地方idx.你也可以看到这个角色的样子imshow(ch);

这应该有希望给你足够的开始.祝好运!


Sha*_*hai 2

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

在您的评论中,您指出您对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
Run Code Online (Sandbox Code Playgroud)

现在,您将分隔的字母放在元胞数组的单元格中seg

请注意,通过提供regionprops二进制输入,您不需要显式调用bwlabel.