找到"黑色矩形"在图像上 - 语言独立

时间:2014-04-06 23:41:30

标签: image opencv image-processing

我正在编写一个小图像分析程序,只是为了好玩。图像分析一直让我着迷。我正在尝试在扫描的文档上找到区域。这些区域将由明确定义的填充黑色矩形标记(预先打印在页面上)。

我的问题是定位矩形。我知道SIFT \ SURF找到“功能”,但我试图找到具体的东西。这就是我在想的事情。我不确定这是“正确的”方式还是有更好的主意。

首先使用一些库我会将图像转换为灰度,也许是PGM,因为这是我以前在学校工作的原因。对于分析,我首先计划通过OpenCV中的最先进的偏移校正算法或我发现的其他东西来运行图像。一旦我有了偏斜的图像,我就会在一个相当高的压力下对它进行阈值处理。矩形将是直黑色,因此我使用相当高的阈值。然后,我将通过实验确定一个尺寸合适的黑色矩形,以便在图像上滑动。在图像上滑动我的矩形时,我将确定最大像素百分比相同的区域。我会截止,比如说90%。如果我窗口中包含的90%的像素是黑色的,我必须找到一个矩形。我的理由是,一个真正的黑色矩形滑过“几乎”黑色矩形的东西很可能是一个黑色矩形。由于我对图像进行了校正,我可以假设矩形是“足够”直线上下。然后,我可以跟踪在图像上找到矩形的(x,y)偏移并标记它们。

有人会建议更好的方法吗?

2 个答案:

答案 0 :(得分:2)

可能有很多种方法可供使用。 (人们可以很容易地提出10种或更多种方法。)


想法#1 - Canny边缘检测;找到适合轮廓的矩形


想法#2 - 使用Hough变换查找所有行;迭代通过线交叉创建的所有区域。


想法#3 - (对#2的改进)通过预处理将Hough变换限制为水平和垂直线。


创意#4 - 计算整个图像的水平和垂直轮廓;发现逢低;遍历所有候选区域。

这个想法是基于这样的假设:黑色矩形足够大,它们在水平和垂直投影轮廓中都留下了“凹陷”,尽管图像中存在其他噪声对象,但这种情况仍然可以检测到。

  • cv::reduce

    • dim = 0或1分别用于减少行或列
    • 使用CV_REDUCE_AVG标志
  • cv::threshold分别应用于水平和垂直投影配置文件。

  • 对于现在阈值为零/非零的每个配置文件,找到零的运行。这些是可能包含深色矩形的行范围和列范围。

  • 对于候选行范围和列范围的每个组合,计算平均像素值以确定它是否是真正的暗矩形。


创意#5 - 使用积分图像(求和面积表)快速计算任意矩形的平均像素值


预处理理念 - 使用形态膨胀(或侵蚀)来“擦除”不能成为大型连续黑匣子的东西。


预处理理念 - 使用预处理来增强水平和垂直边缘;抑制其他方向的边缘。

答案 1 :(得分:1)

我不知道这是否是一种更好的方法,但首先想到的是扫描线解决方案(假设黑色或白色像素):我从顶部检查每条扫描线到底。在每条扫描线中,我从左到右检查每个像素。 A"第一个"黑色像素可能是一个矩形的左上角。如果线上有足够的连续黑色像素以满足我所需的最小宽度,请将[left,width]保留在可能的rects列表中。找到线上所有可能的矩形起点和宽度。

要使矩形停留在列表中并增加高度,下一个扫描线必须具有相同的[左,宽]出现,否则矩形完成(如果其高度符合我所需的最小高度)或丢弃或被忽略为身高太短。

您可以轻松地为两个矩形垂直或水平彼此过于接近的情况添加逻辑。重叠的矩形会比较复杂,但仍然可以使用添加的代码进行检测。

这里有一些伪代码:

for s := 1 to scanlinecount do
  begin
  pixel := 1
  while pixel <= scanlinewidth do
    if black(s, pixel) then // possible rect
      begin
      left := pixel
      repeat
        inc(pixel)
      until (pixel > scanlinewidth) or white(s, pixel)
      width := pixel - left
      if width >= MINWIDTH then // wide enough
        rememberrect(s, left, width) // bumps height if already in list
      end
    else inc(pixel)
  end

找到的rects列表存储了每个找到的矩形的起始扫描线,最左边的像素,宽度和高度。 &#34;记住&#34;例程检查列表中的每个rect:

rememberrect(currentline, left, width):
for r := 1 to rectlist.count do
  if rectlist[r].left = left
   & rectlist[r].width = width
   & rectlist[r].y + rectlist[r].height = currentline then
     begin // found rect continuing on scanline
     inc(rectlist[r].height)
     exit
     end
inc(rectlist.count) // add new rect to list
rectlist[rectlist.count].left := left
rectlist[rectlist.count].width := width
rectlist[rectlist.count].y := currentline
rectlist[rectlist.count].height := 1

如果当前扫描线上的黑色像素组与前一扫描线上的一组具有相同的最左边像素和宽度(您将知道它们是垂直连续的,因为矩形的起始扫描线在list加上它的高度将等于当前的扫描线)然后记住将找到和记住的矩形的高度减去1.否则,记住初始高度为1的新矩形。

在最后一条扫描线之后,你会有一长串的rect候选列表,其中很多只有1像素高。删除或忽略列表中不够高的任何rects。为了避免增加一长串无用的候选人:在每个扫描线的开头标记所有发现到目前为止&#34;完成&#34;。如果记住正确增长现有的矩形或添加新的矩形,请将该矩形标记为&#34; grow&#34;。在每条扫描线的末尾,任何仍然标记为已完成并且不够高的矩形都可以从列表中删除。

相关问题