AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 786767
Accepted
Binarus
Binarus
Asked: 2024-11-17 19:19:45 +0800 CST2024-11-17 19:19:45 +0800 CST 2024-11-17 19:19:45 +0800 CST

如何自动旋转矩形图像区域几度,使其左边框垂直(使用命令行工具,如 imagemagick)

  • 772

我有几千张图像,其主要特征如附图所示:所有图像都在(几乎)黑色的框架中,而实际图像内容几乎总是在白色背景上。

现在我想旋转实际图像内容,使该内容的左边框垂直。然后我想裁剪(修剪)图像,以便丢弃黑色边框,但完全保留实际内容。也就是说,即使包含实际内容的区域不是完美的矩形,也必须保留该区域的所有内容,这意味着之后黑色边框的剩余部分仍然可见。

考虑到我想要以这种方式处理的图像数量,我想我必须使用命令行工具来完成。过去,我曾使用 ImageMagick 完成此类工作(进行更简单的转换),但我真的不介意结合使用几种不同的工具来完成这项任务。

我已经尝试过的:

我研究过如何对图像进行倾斜校正,这种方法大多数时候都有效。但是,我发现的倾斜校正方法是将文本行设为水平。这很好,因为它使阅读更容易,但当然在大多数情况下,保存文本的区域的边框之后不会分别垂直或水平。这不是我想要的。

为了更详细地解释,我想:

  1. 检测黑框和包含实际图像内容的区域之间的左边缘。
  2. 沿着该边缘画一条(不可见的)直线。
  3. 确定该线与垂直线之间的角度。
  4. 将整个图像旋转该角度(负数),使得步骤 1 中的边缘变为垂直。
  5. 修剪图像,丢弃尽可能多的黑色框架,但保留包含实际内容的完整区域(因此,如果该区域不是完美的矩形,则接受保留黑色框架的其余部分)。

有人可以解释一下如何做到这一点吗,最好使用命令行工具?

在此处输入图片描述

imagemagick
  • 3 3 个回答
  • 44 Views

3 个回答

  • Voted
  1. meuh
    2024-11-17T20:14:16+08:002024-11-17T20:14:16+08:00

    对于简单干净的示例,您可以执行以下操作:使用 imagemagicktrim删除大部分外边框,然后尝试旋转 1 度(为现在较大图像的新添加像素添加匹配的黑色背景),再次修剪,然后查看图像尺寸是否缩小。取最佳缩小尺寸。

    file=in.png
    convert "$file" -trim out.png
    minwidth=$(identify -format '%w' out.png)
    minrot=0
    for rot in $(seq 1 30)
    do      convert out.png -background black -rotate -"$rot" out2.png
            convert out2.png -trim out3.png
            width=$(identify -format '%w' out3.png)
            echo "$rot degrees, width $width"
            if [ $width -lt $minwidth ]
            then    minwidth=$width minrot=$rot
            else    break
            fi
    done
    echo "choose rotate $minrot for min width $minwidth"
    convert out.png -background black -rotate -"$minrot" out2.png
    convert out2.png -trim result.png
    display result.png
    

    对于我得到的测试图像:

    1 degrees, width 381
    2 degrees, width 375
    3 degrees, width 369
    4 degrees, width 363
    5 degrees, width 355
    6 degrees, width 359
    choose 5 width=355
    

    带箭头文字的旋转图像

    如果实际帧比示例的单色性稍差一些,您可以尝试-trim在选项前加上前缀,-fuzz 15%以获得更近似的像素颜色比较。

    • 3
  2. Best Answer
    meuh
    2024-11-18T04:09:41+08:002024-11-18T04:09:41+08:00

    此答案试图通过使用 的功能来加快速度-trim,即在新图像的信息中保留旧画布内新图像的偏移量。首先,我们进行全局修剪以获得图像,其中:所需白色空间的最上角应与图像顶部相邻,所需白色空间的最左角应与图像左侧相邻。这是下图中虚线黄色矩形。

    我们重新分页此图像,使画布与新图像的大小相同。

    顶部的薄水平切片(高度见$stripwidth下方脚本)被放入文件 中line1.png,即红色矩形。它被修剪(放入文件 中out4.png),如蓝色矩形所示。%X结果图像的箭头偏移量应为找到最上角的位置。为了获得更好的估计,修剪图像的一半宽度(%w/2)被添加到此(下图中夸大了)。

    类似地,切出一个薄的垂直切片并修剪。偏移量%Y是找到最左角的位置,加上一半的高度%h/2。

    例如,如果红色条带的修剪结果line1.png为蓝色out4.png,则identify out4.png可能输出

    out4.png PNG 14x2 387x432+36+0 ...
    

    这表示图像为 14x2 像素,画布(line1.png)大小为 387x432,x 轴偏移量为 36 像素,y 轴偏移量为 0 像素。 带注释

    现在,我们得到了左上角三角形对边和邻边的长度。如果我们使用反正切计算角度,这就是使这个三角形消失所需的旋转,从而使上角与左边缘对齐。

    file=in.png
    # fuzz='-fuzz 15%'
    stripwidth=2
    convert "$file" $fuzz -trim out.png
    minwidth=$(identify -format '%w' out.png)
    
    convert out.png +repage -crop ${minwidth}x${stripwidth}+0+0 line1.png
    convert line1.png $fuzz -trim out4.png
    opp=$(identify -format '0 %X +%w/2' out4.png)
    
    ht=$(identify -format '%h' out.png)
    convert out.png +repage -crop ${stripwidth}x${ht}+0+0 line2.png
    convert line2.png $fuzz -trim out5.png
    adj=$(identify -format '0 %Y +%h/2' out5.png)
    
    minrot=$(echo "scale=2; pi=4*a(1); 
        opp=$opp; adj=$adj; 
        a(opp/adj)*180/pi" |
        bc -l)
    
    convert out.png -background black -rotate -"$minrot" out2.png
    convert out2.png $fuzz -trim result.png
    display result.png
    

    请注意,a()中的 是 arctan(以弧度为单位)bc。identify -format用于%w %h %X %Y获取原始画布中修剪图像的宽度、高度、x 偏移量、y 偏移量。 额外的0是因为 imagemagick 添加了前导+符号,并且bc不处理它。

    结果是 5.76 度,如以下sh -x输出所示:

    + convert out.png +repage -crop 387x2+0+0 line1.png
    + convert line1.png -trim out4.png
    ++ identify -format '0 %X +%w/2' out4.png
    + opp='0 +36 +15/2'
    ++ identify -format %h out.png
    + ht=432
    + convert out.png +repage -crop 2x432+0+0 line2.png
    + convert line2.png -trim out5.png
    ++ identify -format '0 %Y +%h/2' out5.png
    + adj='0 +381 +19/2'
    ++ echo 'scale=2; pi=4*a(1); 
            opp=0 +36 +15/2; adj=0 +381 +19/2; 
            a(opp/adj)*180/pi'
    ++ bc -l
    + minrot=5.76
    + convert out.png -background black -rotate -5.76 out2.png
    + convert out2.png -trim result.png
    
    • 2
  3. Binarus
    2024-11-20T05:20:03+08:002024-11-20T05:20:03+08:00

    以下解决方案基于@meuh 的想法。如果您觉得我的解决方案有用,请为他的答案点赞。首先,我将发布我的代码,然后解释我所做的更改,仅提及不明显的内容。

    该代码基于一些对于我必须处理的图像来说是安全的假设:

    1. 原始图像中白色区域的左边缘相对于垂直线的旋转不超过 5 度。
    2. 原始图像中的白色区域至少为 2000 像素高、1000 像素宽。
    #!/usr/bin/bash
    
    file=ScanImage7123.tif
    stripwidth=4
    
    convert "$file" -fuzz 20% -trim out.png
    width=$(identify -format '%w' out.png)
    height=$(identify -format '%h' out.png)
    
    (( wd = (width / 2) ))
    (( l1yoff = (height / 10) ))
    (( l2yoff = (height - l1yoff) ))
    
    convert out.png +repage -crop ${wd}x${stripwidth}+0+${l1yoff} line1.png
    IFS=" x+" read a b x1 d < <(convert -fuzz 50% line1.png -format "%@" info:)
    
    convert out.png +repage -crop ${wd}x${stripwidth}+0+${l2yoff} line2.png
    IFS=" x+" read a b x2 d < <(convert -fuzz 50% line2.png -format "%@" info:)
    
    (( a = (x1 - x2) ))
    (( b = (l2yoff - l1yoff) ))
    rad2deg="57.2957795130823208768"
    
    angle=$(perl -E "say atan2(${a}, ${b}) * ${rad2deg}")
    
    convert out.png -background black -rotate -${angle} out2.png
    convert out2.png -fuzz 20% -trim result.png
    

    这里的想法是,我们实际上不需要找到白色区域的角。这很重要,因为对我来说,可靠地找到角是不可能的,即使尝试不同的 值stripwidth。

    我的真实世界图像来自扫描仪,这意味着白色区域的边缘不是很清晰。这使得找到顶角变得相当困难。通常,我们可以按以下方式找到顶边:在第一个convert操作(修剪)之后,转到第一行像素(在顶部),从左到右沿着它走,并在第一个白色像素处停止;然后你就找到了角落。

    如果白色区域已经是水平的或接近水平的,这实际上是不可能的,并且顶部边缘越不“清晰”,则越困难。

    因此,我将第二次操作裁剪的区域(“线”)convert从顶部边缘移开,距离为图像高度的十分之一。这确保了我们在该线(文件名)中有一个清晰且相对锐利的从黑色到白色的水平过渡line1.png。

    我想避免在第一行出现两次水平过渡(例如左侧黑色 -> 白色,右侧白色 -> 黑色)。这只是因为我不知道imagemagick如果该行中有多个过渡,下一步会发生什么。因此,在裁剪该行时,我只使用一半的图像宽度。[旁注:该行中仍可能有多个过渡,具体取决于白色区域的内容(例如黑色文本),但这在我的第一次测试中没有造成问题。]

    第三个convert操作输出类似 的内容0x10+45+0。部分0x10表示上述转换的尺寸,+45是X转换开始的坐标。这是我们想要的值;构造read将其保存在 中x1。

    第二条“线”(文件名 )也采用同样的方法line2.png,从图像底部裁剪出十分之一的图像高度(第四个convert操作)。在下一行(第五个convert操作)中,X将第二行中黑色到白色的过渡坐标保存在 中x2。

    现在我们可以计算出第 1 行和第 2 行两个过渡之间的水平和垂直距离,并根据这些距离计算出旋转角度。

    我使用 Perl 来执行该计算,因为bc它没有提供该atan2()函数,在这种情况下我显然更喜欢它,因为它能够处理水平或垂直距离(甚至两者)的情况0。

    其余部分应该是不言自明的。

    • 2

相关问题

  • 如何将很多选项传递给 ImageMagick?

  • 安装 ImageMagick 后我没有工具 imgout

  • GNU 与 for 循环并行?

  • 自动恢复扫描照片边缘的垂直度

  • 使用 ImageMagick 创建具有多行的调色板图像

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve