【问题标题】:MATLAB: Segment individual letters from a binary imageMATLAB:从二进制图像中分割单个字母
【发布时间】:2014-12-26 00:37:30
【问题描述】:

我正在从事一个光学字符识别项目,我正在尝试创建一个程序来识别图像中的字母。我正在关注 Mathworks(Digit Classification) 上的教程。在他们的示例中,他们的训练图像已经分开。不幸的是,我获得了在单个文件中包含数百个字母的训练图像。

这是一个示例:

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

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

【问题讨论】:

  • 请查找两种技术,“连接组件标记”和“投影轮廓”。两者都受 MATLAB 支持。
  • 谢谢,bwlabel 似乎工作正常,但有没有办法控制 bwlabel 使区域从左上角的 x 开始,然后向右和向下移动?它似乎在最左边,这使它在字母周围跳跃,而不是方便我组织成一个字母数组。

标签: matlab image-processing computer-vision


【解决方案1】:

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

让我们将其读入 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

这是我们得到的:

最后的工作是提取所有字符并将它们放入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 是从 1 到我们拥有的字符数之间的任意数字。你也可以通过imshow(ch);看到这个角色的样子

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

【讨论】:

    【解决方案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

    【讨论】:

      猜你喜欢
      • 2011-10-22
      • 1970-01-01
      • 2023-03-06
      • 2017-04-20
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2018-02-21
      相关资源
      最近更新 更多