在图像中查找边(矩形边框)

nav*_*pai 3 python image-manipulation imagemagick edge-detection

我在背景上有一张粘滞便笺的图像(比如一堵墙或一台笔记本电脑),我想要检测粘滞便笺的边缘(粗略检测也可以正常工作),这样我就可以对其进行裁剪.

我计划使用ImageMagick进行实际裁剪,但我仍坚持检测边缘.

理想情况下,我的输出应该给我4个边界点的坐标,这样我就可以在它上面运行我的裁剪.

我该怎么办呢?

stickynote

Kur*_*fle 6

你可以用ImageMagick做到这一点.

可以提出不同的IM方法.这是我想到的第一个算法.它假定"粘滞便笺"不会在较大的图像上倾斜或旋转:

  1. 第一阶段:使用canny边缘检测来显示便签的边缘.
  2. 第二阶段:确定边缘的坐标.

Canny边缘检测

此命令将创建描绘原始图像中所有边的黑白+图像:

convert                              \
  http://i.stack.imgur.com/SxrwG.png \
 -canny 0x1+10%+30%                  \
  canny-edges.png
Run Code Online (Sandbox Code Playgroud)

精明-edges.png

确定边的坐标

假设图像大小为XxY像素.然后,您可以将图像调整为一1xY列和Xx1一行像素,其中每个像素的颜色值是与相应列/行像素位于同一行或相同列中的所有像素的各个像素的平均值.

作为一个可以在下面看到的例子,我将首先将新的canny-edges.png调整为4xYXx4图像:

identify -format  " %W x %H\n"  canny-edges.png
 400x300

convert canny-edges.png -resize 400x4\!   canny-4cols.png
convert canny-edges.png -resize   4x300\! canny-4rows.png
Run Code Online (Sandbox Code Playgroud)

canny-4cols.png

精明-4cols.png

canny-4rows.png

精明-4rows.png

既然先前的图像可视化了将图像压缩大小调整为几列或几行像素的效果,那么我们就可以用一列和一行来实现.同时我们将输出格式更改为文本,而不是PNG,以获取这些像素为白色的坐标:

convert canny-edges.png -resize 400x1\!   canny-1col.txt
convert canny-edges.png -resize   1x300\! canny-1row.txt
Run Code Online (Sandbox Code Playgroud)

以下是输出的一部分canny-1col.txt:

# ImageMagick pixel enumeration: 400,1,255,gray
0,0: (0,0,0)  #000000  gray(0)
1,0: (0,0,0)  #000000  gray(0)
2,0: (0,0,0)  #000000  gray(0)
[....]
73,0: (0,0,0)  #000000  gray(0)
74,0: (0,0,0)  #000000  gray(0)
75,0: (10,10,10)  #0A0A0A  gray(10)
76,0: (159,159,159)  #9F9F9F  gray(159)
77,0: (21,21,21)  #151515  gray(21)
78,0: (156,156,156)  #9C9C9C  gray(156)
79,0: (14,14,14)  #0E0E0E  gray(14)
80,0: (3,3,3)  #030303  gray(3)
81,0: (3,3,3)  #030303  gray(3)
[....]
162,0: (3,3,3)  #030303  gray(3)
163,0: (4,4,4)  #040404  gray(4)
164,0: (10,10,10)  #0A0A0A  gray(10)
165,0: (7,7,7)  #070707  gray(7)
166,0: (8,8,8)  #080808  gray(8)
167,0: (8,8,8)  #080808  gray(8)
168,0: (8,8,8)  #080808  gray(8)
169,0: (9,9,9)  #090909  gray(9)
170,0: (7,7,7)  #070707  gray(7)
171,0: (10,10,10)  #0A0A0A  gray(10)
172,0: (5,5,5)  #050505  gray(5)
173,0: (13,13,13)  #0D0D0D  gray(13)
174,0: (6,6,6)  #060606  gray(6)
175,0: (10,10,10)  #0A0A0A  gray(10)
176,0: (10,10,10)  #0A0A0A  gray(10)
177,0: (7,7,7)  #070707  gray(7)
178,0: (8,8,8)  #080808  gray(8)
[....]
319,0: (3,3,3)  #030303  gray(3)
320,0: (3,3,3)  #030303  gray(3)
321,0: (14,14,14)  #0E0E0E  gray(14)
322,0: (156,156,156)  #9C9C9C  gray(156)
323,0: (21,21,21)  #151515  gray(21)
324,0: (159,159,159)  #9F9F9F  gray(159)
325,0: (10,10,10)  #0A0A0A  gray(10)
326,0: (0,0,0)  #000000  gray(0)
327,0: (0,0,0)  #000000  gray(0)
[....]
397,0: (0,0,0)  #000000  gray(0)
398,0: (0,0,0)  #000000  gray(0)
399,0: (0,0,0)  #000000  gray(0)
Run Code Online (Sandbox Code Playgroud)

如您所见,文本中检测到的边缘也会影响像素的灰度值.所以我们可以-threshold 50%在我们的命令中引入一个额外的操作,以获得纯黑+白输出:

convert canny-edges.png -resize 400x1\!   -threshold 50% canny-1col.txt
convert canny-edges.png -resize   1x300\! -threshold 50% canny-1row.txt
Run Code Online (Sandbox Code Playgroud)

我不会在这里引用新文本文件的内容,你可以尝试一下,如果你感兴趣的话就找自己.相反,我会做一个快捷方式:我将输出像素颜色值的文本表示,<stdout>并直接为所有非黑色像素grep它:

convert canny-edges.png -resize 400x1\!   -threshold 50% txt:- \
| grep -v black

  # ImageMagick pixel enumeration: 400,1,255,srgb
  76,0: (255,255,255)  #FFFFFF  white
  78,0: (255,255,255)  #FFFFFF  white
  322,0: (255,255,255)  #FFFFFF  white
  324,0: (255,255,255)  #FFFFFF  white

convert canny-edges.png -resize   1x300\! -threshold 50% txt:- \
| grep -v black

  # ImageMagick pixel enumeration: 1,300,255,srgb
  0,39: (255,255,255)  #FFFFFF  white
  0,41: (255,255,255)  #FFFFFF  white
  0,229: (255,255,255)  #FFFFFF  white
  0,231: (255,255,255)  #FFFFFF  white
Run Code Online (Sandbox Code Playgroud)

从上面的结果可以得出结论,其他图像中的贴纸的四个像素坐标是:

  1. 左下角: (323|40)
  2. 右上角: (77|230)

区域的宽度为246像素,高度为190像素.

(ImageMagick假设其坐标系的原点位于图像的左上角.)

要立即剪切原始图像中的便签,您可以执行以下操作:

convert http://i.stack.imgur.com/SxrwG.png[246x190+77+40] sticky-note.png
Run Code Online (Sandbox Code Playgroud)

粘note.png

更多的探索选择

autotrace

您可以通过将中间"canny-edges.png"转换为SVG矢量图形来简化上述过程(甚至可以将其转换为自动运行的脚本),例如通过运行它autotrace...

如果粘滞便笺倾斜或旋转,这可能很有用.

霍夫线检测

一旦你有"canny"线,你也可以对它们应用Hough Line Detection算法:

convert              \
  canny-edges.png    \
 -background black   \
 -stroke red         \
 -hough-lines 5x5+20 \
  lines.png
Run Code Online (Sandbox Code Playgroud)

lines.png

请注意,-hough-lines操作员将检测到的线从一条边(具有浮点值)扩展并绘制到原始图像的另一条边.

当前一个命令最终将行转换为PNG时,-hough-lines操作符实际上在内部生成MVG文件(Magick Vector Graphics).这意味着您实际上可以读取MVG文件的源代码,并确定"红线"图像中描述的每一行的数学参数:

convert              \
  canny-edges.png    \
 -hough-lines 5x5+20 \
  lines.mvg
Run Code Online (Sandbox Code Playgroud)

这是更复杂的,也适用于不严格水平和/或垂直的边缘.

但是您的示例图像确实使用了水平和垂直边缘,因此您甚至可以使用简单的shell命令来发现这些.

生成的MVG文件中总共有80行描述.您可以识别该文件中的所有水平线:

cat lines.mvg                              \
 | while read a b c d e ; do               \
     if [ x${b/0,/} == x${c/400,/} ]; then \
       echo "$a    $b    $c   $d    $e" ;  \
     fi;                                   \
   done

    line     0,39.5    400,39.5    # 249
    line     0,62.5    400,62.5    # 48
    line     0,71.5    400,71.5    # 52
    line     0,231.5   400,231.5   # 249
Run Code Online (Sandbox Code Playgroud)

现在识别所有垂直线:

cat lines.mvg                              \
 | while read a b c d e; do                \
     if [ x${b/,0/} == x${c/,300} ]; then  \
        echo "$a    $b    $c   $d    $e" ; \
     fi;                                   \
   done

   line     76.5,0   76.5,300     # 193
   line    324.5,0  324.5,300     # 193
Run Code Online (Sandbox Code Playgroud)