我需要一种编程方式来获取扫描图像(假设为 PNG 或任何其他方便的图像格式)并将其分解为许多较小的图像。扫描的图像是一个网格,网格的框将始终具有相同的大小并且位于相同的相对位置。由于图像是扫描的,因此它们不一定位于相同的绝对位置。每个框中都有一个角色,理想情况下我想将角色保存为自己的图像文件,没有任何框边框。
我更喜欢 PHP 和 ImageMagick,我认为这将是正确的工具组合。不过,如果有更好的方法,我会灵活处理。
最佳答案
这是解决问题的算法方法的开始......
我使用为测试目的而创建的图像,名为 box.jpg
,尺寸为 352x232 像素:
目标是识别红色框并提取“Dave”图片。
我的算法方法如下:
将图片缩放到原来的宽度,但高度只有1个像素;同时转换为灰度并增加对比度;使用 ImageMagick 可以发出的每个像素属性的文本描述。这样您应该能够找到垂直红线像素积累极端颜色值的两个点。 (垂直红线像素与灰色字母像素一起将具有更常见的颜色值。)
在另一个方向上做同样的事情:将图片缩放到原来的高度,但宽度只有1个像素(转换为灰度,增加对比度,使用文字描述...yadda-亚达)。您会发现水平红线像素积累极端颜色值的两个点。 (垂直红线与灰色字母像素相结合将具有更“平均”的颜色值。)
识别两个结果中每个颜色值峰值的位置:这将为您提供要从原始图像中提取的子图像的几何形状。
从原始图像中提取子图像。根据需要裁剪每一侧。
我无法详细阐述完整的算法,但以下是我在步骤 1 和 2 中使用的命令。
第 1 步的命令
convert \
-type grayscale \
-depth 8 \
box.jpg \
-scale x1\! \
-contrast-stretch 6x6 \
columns.txt
第 1 步的结果
这是columns.txt
的内容:
# ImageMagick pixel enumeration: 352,1,255,gray
0,0: ( 0, 0, 0) \#000000 black <-- left outer image border
1,0: (253,253,253) #FDFDFD gray(253,253,253)
2,0: (255,255,255) #FFFFFF gray(255,255,255)
3,0: (255,255,255) #FFFFFF gray(255,255,255)
[...]
20,0: (255,255,255) #FFFFFF white
21,0: (255,255,255) #FFFFFF white
[...]
46,0: (255,255,255) #FFFFFF white
47,0: (255,255,255) #FFFFFF white
48,0: (243,243,243) #F3F3F3 gray(243,243,243)
49,0: ( 0, 0, 0) #000000 black <-- left box border (ex-red)
50,0: ( 0, 0, 0) #000000 gray(0,0,0) <-- left box border (ex-red)
51,0: ( 0, 0, 0) #000000 black <-- left box border (ex-red)
52,0: ( 0, 0, 0) #000000 black <-- left box border (ex-red)
53,0: (221,221,221) #DDDDDD gray(221,221,221)
54,0: (231,231,231) #E7E7E7 gray(231,231,231)
55,0: (236,236,236) #ECECEC gray(236,236,236)
[...]
247,0: (236,236,236) #ECECEC gray(236,236,236)
248,0: (216,216,216) #D8D8D8 gray(216,216,216)
249,0: ( 0, 0, 0) #000000 black <-- right box border (ex-red)
250,0: ( 1, 1, 1) #010101 gray(1,1,1) <-- right box border (ex-red)
251,0: ( 0, 0, 0) #000000 black <-- right box border (ex-red)
252,0: ( 1, 1, 1) #010101 gray(1,1,1) <-- right box border (ex-red)
253,0: (226,226,226) #E2E2E2 gray(226,226,226)
254,0: (244,244,244) #F4F4F4 gray(244,244,244)
255,0: (244,244,244) #F4F4F4 gray(244,244,244)
[...]
303,0: (255,255,255) #FFFFFF white
304,0: (255,255,255) #FFFFFF white
305,0: (255,255,255) #FFFFFF white
[...]
342,0: (255,255,255) #FFFFFF white
343,0: (255,255,255) #FFFFFF white
344,0: (255,255,255) #FFFFFF gray(255,255,255)
345,0: (255,255,255) #FFFFFF gray(255,255,255)
346,0: (255,255,255) #FFFFFF gray(255,255,255)
347,0: (255,255,255) #FFFFFF gray(255,255,255)
348,0: (255,255,255) #FFFFFF gray(255,255,255)
349,0: (255,255,255) #FFFFFF gray(255,255,255)
350,0: (253,253,253) #FDFDFD gray(253,253,253)
351,0: ( 0, 0, 0) #000000 black <-- right outer image border
(注意:ImageMagick 调用 #FFFFFF
的颜色值有时白色
,有时灰色,这似乎有点令人困惑(255,255,255)
-- 以及调用 #000000
的颜色值,有时 black
,有时 gray(0,0,0)
...也许是一个错误?无论如何,不会阻止我们在这里...)
第 2 步的命令
convert \
-type grayscale \
-depth 8 \
box.jpg \
-scale 1x\! \
-contrast-stretch 6x6 \
rows.txt
第 2 步的结果
这是rows.txt
的内容(这次我去掉了令人困惑的颜色名称):
# ImageMagick pixel enumeration: 1,232,255,gray
0,0: ( 0, 0, 0) #000000 <-- top outer image border
0,1: (255,255,255) #FFFFFF
0,2: (255,255,255) #FFFFFF
0,3: (255,255,255) #FFFFFF
0,4: (255,255,255) #FFFFFF
0,5: (255,255,255) #FFFFFF
0,6: (255,255,255) #FFFFFF
0,7: (255,255,255) #FFFFFF
0,8: (255,255,255) #FFFFFF
0,9: (255,255,255) #FFFFFF
0,10: (255,255,255) #FFFFFF
[...]
0,46: (255,255,255) #FFFFFF
0,47: (255,255,255) #FFFFFF
0,48: (240,240,240) #F0F0F0
0,49: ( 0, 0, 0) #000000 <-- top box border (ex-red)
0,50: ( 0, 0, 0) #000000 <-- top box border (ex-red)
0,51: ( 0, 0, 0) #000000 <-- top box border (ex-red)
0,52: ( 0, 0, 0) #000000 <-- top box border (ex-red)
0,53: (225,225,225) #E1E1E1
0,54: (234,234,234) #EAEAEA
[...]
0,207: (244,244,244) #F4F4F4
0,208: (230,230,230) #E6E6E6
0,209: ( 0, 0, 0) #000000 <-- bottom box border (ex-red)
0,210: ( 0, 0, 0) #000000 <-- bottom box border (ex-red)
0,211: ( 0, 0, 0) #000000 <-- bottom box border (ex-red)
0,212: ( 0, 0, 0) #000000 <-- bottom box border (ex-red)
0,213: (234,234,234) #EAEAEA
0,214: (245,245,245) #F5F5F5
[...]
0,229: (255,255,255) #FFFFFF
0,230: (255,255,255) #FFFFFF
0,231: ( 0, 0, 0) #000000 <-- bottom outer image border
从这两个结果我们可以可靠地得出结论:
- 左侧垂直红色框边框线位于像素列 49-52 处。
- 右侧垂直红色框边框线位于像素列 249-252 处。
- 顶部水平红框边框线位于第 49-52 像素行。
- 底部水平红框边框线位于第 209-222 像素行。
- 根据 1. 和 2.,您可以计算出红色框的“内部宽度”为 197(249 减去 52)。那么我们使用 196 作为提取的子图像的宽度。
- 根据 3. 和 4.,您可以计算出红色框的“内部高度”为 157(209 减去 52)。那么我们使用 156 作为提取的子图像的高度。
- 裁剪的水平偏移需要为 52 像素。我们选择 53。
- 裁剪的垂直偏移需要为 52 像素。我们选择 53。
因此,我们从原始图像中剪切子图像的命令可以是:
convert -crop 196x156+53+53 box3.jpg sub-box.jpg
或者,为了使图像尺寸更好地与该网页的白色背景区分开来:
convert -crop 196x156+53+53 box3.jpg -colorize 20,0,20 sub-box.jpg
结果图像:
您现在可以在图像上应用 OCR:
tesseract sub-box.jpg OCR-subbox 1>/dev/null && cat OCR-subbox.txt
Dave
关于php - 如何检测图像中的框并将它们作为单独的文件拉出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10074860/