使用Hugin拼接扫描图像
目录
为什么?
所用软件
测试图片
脚本
4.1 第一次尝试:一次性拼接所有图片
4.2 完善:一次拼接两张图片
附录
参考文献
- 为什么?
我的目的是将一些地图数字化。首先通过扫描将它们转换为栅格图像,然后再将栅格图像转换为可缩放的图形。整个两步过程如下所示:
扫描 -> 矢量化
地图 -> 栅格图像 -> 可缩放图形
在上述第一步中,由于一些地图的面积大于我的扫描仪表面(A4大小),因此我必须多次扫描地图,每次扫描不同的区域(有重叠部分),然后将这些较小的图像拼接成最终图像。Hugin在这第一步中起到了关键作用。
本文的目的是记录如何使用Hugin的命令行工具自动化拼接过程,而不深入讨论每个工具及其相关的命令行选项。
- 所用软件
在网上搜索时,发现有很多软件可以进行拼接,但到目前为止,Hugin似乎是最佳选择,尤其是因为它是免费且开源的。唯一的缺点是Hugin的学习曲线有点陡峭,尽管它有一个GUI界面。
除了Hugin之外,其他软件包(也是免费、开源和跨平台的)也有所帮助:
ImageMagick:用于栅格图像处理的“瑞士军刀”。
GIMP:用于基于GUI的栅格图像处理,是Adobe PhotoShop的替代品。
Inkscape:用于可缩放图形编辑,基于SVG格式。这主要用于栅格图像的矢量化。
在基于Debian的发行版上安装这些软件包的命令如下:
bash
$ sudo apt install hugin
$ sudo apt install imagemagick
$ sudo apt install gimp
$ sudo apt install inkscape
(注意:原文中的“gimp-plugin-registry”可能是一个错误或不再需要的包名,因此在此处省略。通常,安装GIMP时会自动包含所需的插件。)
- 测试图片
测试图片是一张1600x1000像素的数字照片,它被当作杂志中要扫描的原始图片:
为了测试拼接功能,将原始图片分成4张较小的(1000x600像素)图片,并带有重叠部分,以代表4张扫描的图片,顺序如下:
请注意,为了模拟图像扫描过程中的实际情况,在拼接之前,“扫描”的图片(除第一张外)会按小角度旋转:
2.jpg:顺时针旋转1°;
3.jpg:逆时针旋转1°;
4.jpg:顺时针旋转2°;
因此,任务是使用Hugin拼接这4张“扫描”的图片。
- 脚本
4.1 第一次尝试:一次性拼接所有图片
为了自动化拼接过程,使用了一个shell脚本来按特定顺序调用各种Hugin命令行工具。以下脚本是从Hugin关于拼接扫描图像的教程中下载的。
请注意,我对原始脚本进行了小幅修改,用hugin_executor替换了pto2mk和make,如此处所述。输入图像文件名也已更改以适应我们的情况。
然而,尝试运行此脚本并一次性拼接所有图像可能不会产生理想的结果,因为Hugin可能在查找图像之间的共同部分时感到困惑。
4.2 改进:一次拼接两张图片
可能在一步中提供多张图片会使Hugin在寻找图片间的共同部分时感到困惑…如果我们逐步拼接图片,每次只拼接两张图片会怎么样呢?
让我们创建一个新的脚本来测试这个想法:
bash
$ cat stitch-two.sh
#! /bin/bash
±----------+
| 1 | 2 |
±----±----+
| 3 | 4 |
±----------+
分三步拼接上面的4张图片:
1. 1.jpg + 2.jpg => top.jpg
2. 3.jpg + 4.jpg => bot.jpg
3. top.jpg + bot.jpg => final.jpg
该函数按以下顺序接受参数:
$1: 第一个文件名
$2: 第二个文件名
$3: 输出前缀(输出格式为JPG)
$4: JPG质量,1-100
$5: hfov(以度为单位)
function stitch_two(){
pto_gen --projection=0 --fov=$5 -o project.pto $1 $2
pto_lensstack -o project1.pto --new-lens i1 project.pto
cpfind -o project1.pto --multirow project1.pto
cpclean -o project2.pto project1.pto
linefind -o project3.pto project2.pto
pto_var -o setoptim.pto --opt r,d,e,!r0,!d0,!e0 project3.pto
autooptimiser -n -o autoptim.pto setoptim.pto
pano_modify --projection=0 --fov=AUTO --center --canvas=AUTO --crop=AUTO \
–ldr-file=JPG --ldr-compression=$4 -o autoptim2.pto autoptim.pto
hugin_executor -s -p $3 autoptim2.pto
}
开始拼接,Hugin!
stitch_two 1.jpg 2.jpg top 90 10
stitch_two 3.jpg 4.jpg bot 90 10
stitch_two top.jpg bot.jpg final 90 10
像以前一样准备一个新文件夹,并调用新脚本(./stitch-two.sh),我们得到了以下结果,看起来相当不错:
经过测试,这4张图片也可以以不同的顺序成功拼接(首先拼接左右部分,然后拼接整体)。实际上,多步方法不仅限于拼接2x2图片数组,理论上它适用于任何维度的图片数组,并且该数组可以首先逐行或逐列进行拼接。
使用多步拼接过程的另一个好处是,它还保留了中间步骤的拼接结果,如果最终结果有误,我们可以检查中间步骤以查看哪两张图片导致了问题,并尝试相应地调整输入图片。
基于之前的bash函数stitch_two(),以下是可用于拼接多于两张图片(在一行或一列中)的函数stitch_multi():
bash
$1: 输入文件名的数组
$2: 输出前缀
$3: JPG质量,1-100
$4: hfov(以度为单位)
function stitch_multi(){
tmp=tmp.jpg
inputs=
1
f
i
r
s
t
=
1 first=
1first={inputs[0]}
inputs=( “${inputs[@]:1}” )
cp $first $tmp
while (( ${#inputs[@]} )); do
next=( "${inputs[0]}" )
inputs=( "${inputs[@]:1}" )
echo "stitch_two $tmp $next $2 $3 $4"
stitch_two $tmp $next $2 $3 $4
cp $2.jpg $tmp
done
mv $tmp $2.jpg
} #
示例:拼接一个2x3的图片数组
inputs=( 1.jpg 2.jpg 3.jpg )
stitch_multi $inputs left 90 10
inputs=( 4.jpg 5.jpg 6.jpg )
stitch_multi $inputs right 90 10
inputs=( left.jpg right.jpg )
stitch_multi $inputs final 90 10
5 附录
5.1 屏幕截图提示
要从网站(如google、baidu等)获取高分辨率数字地图,我们可以从浏览器中截取许多屏幕截图:
每个屏幕截图覆盖一个小区域;
相邻的屏幕截图具有足够的重叠;
将所有屏幕截图拼接成一张大图片。
显然,每个屏幕截图的尺寸越大越好。购买更大的显示器是一种选择,但大型显示器也有分辨率限制。我们能否获得尺寸大于显示器分辨率的屏幕截图呢?是的!本节将介绍如何实现这一点。请注意,专家可能有更复杂的方法从专业网站获取高分辨率地图。下面描述的简单方法仅适用于临时使用。
根据维基百科,响应式网页设计(RWD)是一种网页设计方法,旨在使网页在各种设备和窗口或屏幕尺寸上都能良好地呈现,从最小到最大显示尺寸,以确保可用性和满意度。为了满足这一要求,浏览器供应商提供了一些功能。例如,Firefox提供了响应式设计模式(RDM),其中网页开发人员可以定义要在其上呈现网页的设备的屏幕尺寸。定义的设备尺寸与用于网页开发的显示器的分辨率无关,而是用于模拟目标设备(如Pad或Mobile)。利用RDM功能的技巧概述如下:
进入浏览器的开发者模式;
打开RDM模式;
定义具有最大可能分辨率的自定义设备;
使用自定义设备访问所需的地图网站(在开发者模式下);
使用内置的屏幕截图工具或扩展程序捕获全页内容作为图像;
我遇到了Firefox(Windows版107.0 64位)的RDM模式的一些问题,如果设备尺寸大于3800x3750,截图就会失败且没有任何提示。然后我尝试了Google Chrome,效果更好。以下是在Windows 10上使用Google Chrome(107.0.5304.107 64位)捕获9999x9999截图的简要说明:
• 打开一个标签页并转到所需的网站(例如earthol.com);
• 从菜单–>更多工具–>DevTools,打开DevTools窗口:
∘ DevTools窗口可能会停靠在当前网页的一侧,或者它是未停靠的(在一个单独的窗口中);如果DevTools窗口停靠在当前网页内,请点击自定义–>停靠大小–>将窗口停靠到单独的窗口中,以将其取消停靠。这为当前网页提供了更大的可见区域。
∘ 在DevTools窗口旁边,注意到当前页面的顶部添加了一个工具栏。尺寸(Dimensions)项是我们想要放大的。从尺寸的下拉列表中选择编辑…,这将转到模拟设备设置页面。我们也可以通过点击DevTools窗口右侧菜单栏中的设置图标进入相同的设置页面(这将打开设置窗口;在左侧栏中点击设备以进入设置类别,右侧将显示模拟设备列表);
• 点击右侧栏顶部的添加自定义设备…按钮,将出现一个设备表单;
• 在设备表单中填写适当的信息,然后点击添加按钮添加刚刚定义的设备,最后关闭设置页面。以下是我定义的自定义设备:
∘ 名称:biggest
∘ 分辨率:9999x9999
∘ 设备像素比:1
∘ 设备类型:选择桌面
∘ 与用户代理相关的项:无需触碰
• 现在我们返回到当前网页(确保DevTools窗口仍然打开);选择biggest作为设备,尺寸将自动更改为定义的值(即9999x9999)。
• 导航到当前页面的所需位置(对于地图网站使用适当的缩放比例),等待一会儿,这是为了确保当前页面的所有内容(可见和不可见的)都已下载并呈现。
• 从当前页面顶部工具栏的最右侧菜单图标中点击捕获全尺寸截图。
• 如果一切顺利,将出现一个文件保存对话框,用于指定文件名以保存截图。
就是这样。很简单,不是吗?
是否有可能使截图尺寸大于9999x9999?我想是可能的,如果我们能够修改浏览器的源代码(Mozilla Firefox是完全免费和开源的)并重新编译它。如果我们不想弄脏源代码…Hugin来拯救。
以下是从earthol.com捕获圆明园卫星地图的示例:
• 为了获得最多的细节,我将地图放大到最大,因此区域的大小略大于9999x9999。
• 根据大致估算,整个区域可以被4张截图覆盖(即2x2截图)。
• 在每个earthol.com页面的顶部,都有一个工具按钮,可以将当前窗口以经度和纬度指定的位置为中心。
• 使用此工具,可以测量出圆明园的区域位于经度范围[116.28, 116.315]和纬度范围[39.995, 40.02]内,并有足够的边距;
• 现在很容易确定4张截图中每一张的中心位置(经度,纬度):
∘ 左上:(116.289, 40.014)
∘ 右上:(116.306, 40.014)
∘ 左下:(116.289, 40.001)
∘ 右下:(116.306, 40.001)
以下是按这种方式拍摄的4张截图的缩略图:
另请注意,从earthol.com上截取的屏幕截图在每侧都包含一些图标/文本/空白,我们需要在拼接之前将其裁剪掉,因为这些内容不是地图的一部分,更糟糕的是,它们会在拼接过程中误导Hugin。
以下是使用ImageMagick裁剪图像四边的示例脚本:
#!/bin/bash
#https://imagemagick.org/Usage/crop/#chop
每边要裁剪的像素
上=200
下=100
左=100
右=100
$1 输入文件
$2 输出文件
function chop_one_img(){
convert 1−chop0x上 top.jpg
convert top.jpg -gravity South -chop 0x下bot.jpgconvertbot.jpg−chop{左}x0 left.jpg
convert left.jpg -gravity East -chop 右x02
rm top.jpg bot.jpg left.jpg
}
for f in *.png; do
chop_one_img f{f%.png}.jpg
done
最终拼接的图像尺寸为16000x16000,中心部分是圆明园的区域(已突出显示)。 如果我们减小圆明园周围的边距大小,则图像尺寸可以减小到12000x10000。
注:这段翻译中存在一些问题,比如变量名称“上”、“下”、“左”、“右”在bash脚本中并不适用,因为bash脚本不支持非英文字符作为变量名。这里为了保留原文的直观性,仍然按照原文进行翻译。在实际应用中,应将这些变量名替换为英文,如"top", “bottom”, “left”, “right”。另外,“function chop_one_img(){” 这一行中的括号也存在错误,应该是 “function chop_one_img() {”。此外,“convert” 命令现在已被 “magick” 命令替代,因为在新版本的 ImageMagick 中,推荐使用 “magick” 命令。但是,为了保持与原文的一致性,这里仍然使用 “convert”。在实际应用中,应根据安装的 ImageMagick 版本选择正确的命令。
5.2 ImageMagick 小抄
• 检查资源策略:convert -list resource
• 更改资源策略:vi /etc/ImageMagick-6/policy.xml
• 获取图像信息:identify -verbose <输入>
• 去除exif元数据:convert <输入> -strip <输出>
• 从彩色转换为灰度:convert <输入> -colorspace Gray <输出>
• 更改jpg/png文件的质量:convert <输入> -quality <1到100的值> <输出>
• 下采样:convert <输入> -resize 50% <输出>
• 更改图像大小:convert <输入> -size 800x600 <输出>
• 旋转:convert <输入> -rotate <角度> <输出>; 可能使用GIMP GUI对此任务更直观。
• 转换颜色深度:convert <输入> -colors <颜色数> <输出>
6 参考文献
• Panorama 脚本简述
• Hugin的教程
• ImageMagick 在线文档