image - 基于 "areas"将图像分割成较小图像的算法

标签 image algorithm split

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

让我们以这张图片为例:

Example
(来源:s-ul.eu)

我给算法这些矩形:

Example
(来源:s-ul.eu)

我希望它输出不同的图像,通过赋予水平轴更多的重要性来划分(因为论坛和 HTML 文档就像“写作”,如果这有意义的话),像这样:

Example
(来源:s-ul.eu)

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

然后我会做一些事情来优化它,这样它就不会以 50 亿张图像结束,然后是 bbcode 等,我自己,这不是问题。我正在寻找的是某种可以自己进行除法的算法,这样(这样一条水平线必须从一边到另一边)。

最佳答案

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

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

然后您可以使用 ImageMagick,它安装在大多数 Linux 发行版上,适用于 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

然后进行“连通分量分析”,找出所有与相同颜色像素 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

我们实际上并不想要那个 - 我们想要的是该命令在终端上的输出,它为您提供所有“连接的组件”,看起来像这样:

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)

每一行对应一张图片。第二个字段告诉您它在图像中的位置,最后一个字段告诉您它的颜色。我们想要黑色的,即 colour=gray(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%),以便它们趋向于彼此对齐。

关于image - 基于 "areas"将图像分割成较小图像的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49719608/

相关文章:

java - 如何使用java中的字符串分割删除字符串前面的空格?

javascript - 拆分单词和随机/混杂字母

python - 从图像中删除背景 - Python

php - 使用php上传照片无需重新加载

javascript - 图像描述网站

algorithm - 每增加一个 n 就加倍的算法的 bigO 是多少?

algorithm - 在特定时刻找到无限数字流中特定数字的计数

mysql - 比较范围的算法

css - 调整 Squarespace 标题图像容器的大小不会调整内部图像的大小

java - 数组越界问题