算法根据"区域"将图像分割成较小的图像。

时间:2018-04-08 15:38:07

标签: image algorithm split

所以,让我说我有一个图像,我想让用户在这个图像中给我一组矩形,然后我想分割图像,以便它可以用于,比方说,一个论坛或一个HTML文档,矩形将在链接标记之间结束。这意味着,当这个较大的图像被分成较小的图像时,每个水平分割必须从一侧到另一侧,而垂直的图像则不需要这样做。

让我们以此图片为例:

Example

我给算法这些矩形:

Example

我希望它输出不同的图像,通过给予横轴更重要(因为论坛和HTML文档就像"写",如果这有意义),像这样:

Example

如您所见,水平线从一侧到另一侧,而垂直线可以从不同的水平线开始。

然后我会做一些事情来优化它,所以它最终不会有50亿个图像,然后是bbcode等,我自己也没有问题。我正在寻找的是一种可以通过这种方式进行划分的算法(这样一条水平线必须从一边到另一边)。

1 个答案:

答案 0 :(得分:3)

假设您在名为coords.txt的文件中有覆盖框的坐标,如下所示:

139 49 281 220
306 46 462 225
49 167 170 338
239 142 364 320
427 100 570 291

然后您可以使用大多数Linux发行版上安装的 ImageMagick ,并且可以在终端(命令提示符)的命令行中用于macOS和Windows。

首先,获取图像尺寸:

convert scooby.png -format "%w %h" info:
620 365

现在制作另一张相同尺寸但纯黑色的图像:

convert -size ${w}x${h} xc:black grid.png

现在阅读coords.txt文件,一次一行,对于那里的每一行,在网格上绘制4条白线:

  • 整个图片位于框顶部的一个全宽,
  • 整个图片位于框底部的一个完整宽度
  • 根据垂直方面的两个

看起来像这样:

while read x1 y1 x2 y2 ; do
   convert grid.png -fill white \
      -draw "line 0,$y1 $w,$y1" \
      -draw "line 0,$y2 $w,$y2" \
      -draw "line $x1,$y1 $x1,$y2" \
      -draw "line $x2,$y1 $x2,$y2" grid.png
done < coords.txt

这会在grid.png给你这个 - 应该看起来很熟悉:

enter image description here

然后执行&#34;连接组件分析&#34; 查找4个连接到相同颜色像素的所有像素:

convert grid.png \
   -define connected-components:verbose=true        \
   -define connected-components:area-threshold=100  \
   -connected-components 4 -normalize result.png

它会为您提供一个标记图像,其中您想要的所有黑色矩形都被识别为具有独特且越来越明亮的颜色:

enter image description here

我们实际上并不想要 - 我们想要的是终端上的输出,该命令为您提供所有&#34;连接的组件&#34; ,看起来像这样:

Objects (id: bounding-box centroid area mean-color):
  0: 620x46+0+0 309.5,22.5 28520 gray(0)
  61: 620x26+0+339 309.5,351.5 16120 gray(0)
  51: 142x65+428+226 498.5,258.0 9230 gray(0)
  49: 124x65+240+226 301.5,258.0 8060 gray(0)
  1: 620x293+0+46 308.7,189.8 7930 gray(255)
  9: 157x50+463+50 541.0,74.5 7850 gray(0)
  47: 120x65+50+226 109.5,258.0 7800 gray(0)
  8: 155x50+307+50 384.0,74.5 7750 gray(0)
  60: 449x17+171+321 395.0,329.0 7633 gray(0)
  57: 255x28+365+292 492.0,305.5 7140 gray(0)
  6: 141x50+140+50 210.0,74.5 7050 gray(0)
  5: 139x50+0+50 69.0,74.5 6950 gray(0)
  11: 141x41+140+101 210.0,121.0 5781 gray(0)
  10: 139x41+0+101 69.0,121.0 5699 gray(0)
  35: 107x52+463+168 516.0,193.5 5564 gray(0)
  13: 120x41+307+101 366.5,121.0 4920 gray(0)
  27: 89x52+50+168 94.0,193.5 4628 gray(0)
  48: 68x65+171+226 204.5,258.0 4420 gray(0)
  15: 107x41+463+101 516.0,121.0 4387 gray(0)
  50: 62x65+365+226 395.5,258.0 4030 gray(0)
  29: 68x52+171+168 204.5,193.5 3536 gray(0)
  56: 124x28+240+292 301.5,305.5 3472 gray(0)
  54: 120x28+50+292 109.5,305.5 3360 gray(0)
  17: 139x24+0+143 69.0,154.5 3336 gray(0)
  33: 62x52+365+168 395.5,193.5 3224 gray(0)
  46: 49x65+0+226 24.0,258.0 3185 gray(0)
  52: 49x65+571+226 595.0,258.0 3185 gray(0)
  32: 57x52+307+168 335.0,193.5 2964 gray(0)
  24: 107x24+463+143 516.0,154.5 2568 gray(0)
  26: 49x52+0+168 24.0,193.5 2548 gray(0)
  36: 49x52+571+168 595.0,193.5 2548 gray(0)
  18: 99x24+140+143 189.0,154.5 2376 gray(0)
  30: 41x52+240+168 260.0,193.5 2132 gray(0)
  59: 120x17+50+321 109.5,329.0 2040 gray(0)
  16: 49x41+571+101 595.0,121.0 2009 gray(0)
  55: 68x28+171+292 204.5,305.5 1904 gray(0)
  34: 34x52+428+168 444.5,193.5 1768 gray(0)
  28: 30x52+140+168 154.5,193.5 1560 gray(0)
  22: 62x24+365+143 395.5,154.5 1488 gray(0)
  14: 34x41+428+101 444.5,121.0 1394 gray(0)
  53: 49x28+0+292 24.0,305.5 1372 gray(0)
  21: 57x24+307+143 335.0,154.5 1368 gray(0)
  31: 24x52+282+168 293.5,193.5 1248 gray(0)
  7: 24x50+282+50 293.5,74.5 1200 gray(0)
  25: 49x24+571+143 595.0,154.5 1176 gray(0)
  19: 41x24+240+143 260.0,154.5 984 gray(0)
  12: 24x41+282+101 293.5,121.0 984 gray(0)
  58: 49x17+0+321 24.0,329.0 833 gray(0)
  23: 34x24+428+143 444.5,154.5 816 gray(0)
  2: 306x2+0+47 152.5,47.5 612 gray(0)
  20: 24x24+282+143 293.5,154.5 576 gray(0)
  38: 120x4+50+221 109.5,222.5 480 gray(0)
  44: 107x4+463+221 516.0,222.5 428 gray(0)
  4: 157x2+463+47 541.0,47.5 314 gray(0)
  3: 155x2+307+47 384.0,47.5 310 gray(0)
  39: 68x4+171+221 204.5,222.5 272 gray(0)
  40: 66x4+240+221 272.5,222.5 264 gray(0)
  42: 62x4+365+221 395.5,222.5 248 gray(0)
  41: 57x4+307+221 335.0,222.5 228 gray(0)
  37: 49x4+0+221 24.0,222.5 196 gray(0)
  45: 49x4+571+221 595.0,222.5 196 gray(0)
  43: 34x4+428+221 444.5,222.5 136 gray(0)

每一行对应一个图像。第二个字段告诉您它在图像中的位置,最后一个字段告诉您它的颜色。我们想要黑色的,即颜色=灰色(0),因为我们开始使用黑色网格。

让我们看一下第三行,其中142x65+428+226为第二个字段,颜色为图像中的半透明洋红色:

convert scooby.png -fill "rgba(255,0,255,0.5)" -draw "rectangle 428,226 570,291" one.png

enter image description here

很好,所以现在让我们把每一个切出来并保存在自己的图像中:

i=0
for s in "${images[@]}"; do
   printf -v name "sub-%04d.png" $i
   convert "$image" -crop "$s" "$name"
   ((i=i+1))
done

让我们看看它们的名称和数量:

ls sub*
sub-0000.png    sub-0006.png    sub-0012.png    sub-0018.png    sub-0024.png    sub-0030.png    sub-0036.png    sub-0042.png    sub-0048.png    sub-0054.png    sub-0060.png
sub-0001.png    sub-0007.png    sub-0013.png    sub-0019.png    sub-0025.png    sub-0031.png    sub-0037.png    sub-0043.png    sub-0049.png    sub-0055.png    sub-0061.png
sub-0002.png    sub-0008.png    sub-0014.png    sub-0020.png    sub-0026.png    sub-0032.png    sub-0038.png    sub-0044.png    sub-0050.png    sub-0056.png
sub-0003.png    sub-0009.png    sub-0015.png    sub-0021.png    sub-0027.png    sub-0033.png    sub-0039.png    sub-0045.png    sub-0051.png    sub-0057.png
sub-0004.png    sub-0010.png    sub-0016.png    sub-0022.png    sub-0028.png    sub-0034.png    sub-0040.png    sub-0046.png    sub-0052.png    sub-0058.png
sub-0005.png    sub-0011.png    sub-0017.png    sub-0023.png    sub-0029.png    sub-0035.png    sub-0041.png    sub-0047.png    sub-0053.png    sub-0059.png

让我们看看放在网格上的所有部分:

enter image description here

而且,让我们看看其中一个子图像,注意我们可以看到它在原始图像中的来源:

identify sub-0059.png 
sub-0059.png PNG 49x4 620x365+0+221 8-bit sRGB 139c 931B 0.000u 0:00.000

那张是原始图像中的坐标0,221。

这是完整的代码。

#!/bin/bash

# Pick up filename from parameter
image=$1

# Get width and height
read w h < <(convert "$image" -format "%w %h" info:)
echo DEBUG: width=$w, height=$h

# Make image same size but black
convert -size ${w}x${h} xc:black grid.png

# Read through coords.txt adding white lines accordingly to "grid.png"
while read x1 y1 x2 y2 ; do
   convert grid.png -fill white \
      -draw "line 0,$y1 $w,$y1" \
      -draw "line 0,$y2 $w,$y2" \
      -draw "line $x1,$y1 $x1,$y2" \
      -draw "line $x2,$y1 $x2,$y2" grid.png
done < coords.txt
echo DEBUG: You can view sliced grid in file "grid.png"

# Now do a "Connected Components Analysis" and store coordinates of sub-images in array
images=( $(convert grid.png -define connected-components:verbose=true  -define connected-components:area-threshold=100 -connected-components 4 -normalize result.png | awk '/(0)/{print $2}') )

# Now chop out images from original according to coordinates
i=0
for s in "${images[@]}"; do
   printf -v name "sub-%04d.png" $i
   convert "$image" -crop "$s" "$name"
   ((i=i+1))
done

你刚跑:

./script scooby.png

注意:如果你想让网格的线条略微变胖,以便它们可以偏离几个像素,但仍然将图像分割成几个像素宽的微小滑块,你可以添加像这样的笔触宽度:

...
...
# Read through coords.txt adding white lines accordingly
while read x1 y1 x2 y2 ; do
  convert grid.png -fill white -stroke white -strokewidth 5 \
     -draw "line 0,$y1 $w,$y1" \
     ...
     ...

enter image description here

作为替代方案,我猜你可以将你从文件中读取的坐标四舍五入到最接近的位置,比如5像素(或图像宽度的1%),这样它们就可以相互排列。