php - 如何检测图像中的框并将它们作为单独的文件拉出?

标签 php image-processing imagemagick ocr tesseract

我需要一种编程方式来获取扫描图像(假设为 PNG 或任何其他方便的图像格式)并将其分解为许多较小的图像。扫描的图像是一个网格,网格的框将始终具有相同的大小并且位于相同的相对位置。由于图像是扫描的,因此它们不一定位于相同的绝对位置。每个框中都有一个角色,理想情况下我想将角色保存为自己的图像文件,没有任何框边框。

我更喜欢 PHP 和 ImageMagick,我认为这将是正确的工具组合。不过,如果有更好的方法,我会灵活处理。

最佳答案

这是解决问题的算法方法的开始......

我使用为测试目的而创建的图像,名为 box.jpg,尺寸为 352x232 像素:

The test image...

目标是识别红色框并提取“Dave”图片。

我的算法方法如下:

  1. 将图片缩放到原来的宽度,但高度只有1个像素;同时转换为灰度并增加对比度;使用 ImageMagick 可以发出的每个像素属性的文本描述。这样您应该能够找到垂直红线像素积累极端颜色值的两个点。 (垂直红线像素与灰色字母像素一起将具有更常见的颜色值。)

  2. 在另一个方向上做同样的事情:将图片缩放到原来的高度,但宽度只有1个像素(转换为灰度,增加对比度,使用文字描述...yadda-亚达)。您会发现水平红线像素积累极端颜色值的两个点。 (垂直红线与灰色字母像素相结合将具有更“平均”的颜色值。)

  3. 识别两个结果中每个颜色值峰值的位置:这将为您提供要从原始图像中提取的子图像的几何形状。

  4. 从原始图像中提取子图像。根据需要裁剪每一侧。

我无法详细阐述完整的算法,但以下是我在步骤 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

从这两个结果我们可以可靠地得出结论:

  1. 左侧垂直红色框边框线位于像素列 49-52 处。
  2. 右侧垂直红色框边框线位于像素列 249-252 处。
  3. 顶部水平红框边框线位于第 49-52 像素行。
  4. 底部水平红框边框线位于第 209-222 像素行。
  5. 根据 1. 和 2.,您可以计算出红色框的“内部宽度”为 197(249 减去 52)。那么我们使用 196 作为提取的子图像的宽度。
  6. 根据 3. 和 4.,您可以计算出红色框的“内部高度”为 157(209 减去 52)。那么我们使用 156 作为提取的子图像的高度。
  7. 裁剪的水平偏移需要为 52 像素。我们选择 53。
  8. 裁剪的垂直偏移需要为 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

结果图像:
enter image description here

您现在可以在图像上应用 OCR:

tesseract sub-box.jpg OCR-subbox 1>/dev/null && cat OCR-subbox.txt

  Dave

关于php - 如何检测图像中的框并将它们作为单独的文件拉出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10074860/

相关文章:

c# - 我们可以以编程方式比较具有相同分辨率的不同图像吗?

ruby-on-rails - 所有版本创建后Carrierwave回调

php - Bootstrap 表单 $_POST 为空

javascript - 我正在尝试将数据从数据库提取到选择框中

php - 具有多线程持久化和刷新的 Doctrine Entity Manager

graphics - 投影变换

php - cURL 返回不同

matlab - MATLAB 中不使用循环的图像分量乘法?

python - 获取图像中垂直线的边缘/线

c# - 使用 Magick.NET 生成带标题的图像