Halcon图像拼接

这篇具有很好参考价值的文章主要介绍了Halcon图像拼接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

    图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要。

    如按下图是将两张楼房图片拼接成一个图像。

Halcon图像拼接

1 拼接步骤

     要实现图像拼接,简单来说要实现以下步骤:

  1. 输入图像

  2. 图像几何校正

  3. 图像预处理

  4. 对每幅图进行特征点提取

  5. 对特征点进行匹配

  6. 进行图像配准

  7. 图像融合

  8. 对重叠边界进行特殊处理

2 拼接条件

    图像的拼接要具备以下几个条件:

  • 图像应具有一定的特征。

  • 图像要有重叠部分,一般重叠部分占总图像的1/4以上较合适。

  • 图像的背景亮度差异不能太大,应该低于10个灰度值,否则难以拼接成功。

  • 图像的方位差异不能太大,图像应该来源同一方位。

  • 拼合边界过渡应平滑,以消除接拼痕迹。

3 特征点提取

    基于SRUF 的特征点的提取与匹配

    为了使拼接具有良好的精度和鲁棒性,同时又使其具有较好的实时性,本实验采用SURF 算法完成图像序列特征点的提取。

    SURF 算法又称快速鲁棒特征,借鉴了SIFT 中简化近似的思想,将DoH 中的高斯二阶微分模板进行了近似简化,使得模板对图像的滤波只需要进行几个简单的加减法运算,并且这种运算与滤波模板的尺寸无关。实验证明,SURF 算法较SIFT 在运算速度上要快3 倍左右,综合性能要优于SIFT 算法。

    SURF 特征点提取与描述主要包含4 个步骤:

  1. 检测尺度空间极值。

  2. 精炼特征点位置。

  3. 计算特征点的描述信息。

  4. 生成描述特征点的特征向量。

    halcon特征点特取的算子如下:


select_obj (Images, ImageF, F)
select_obj (Images, ImageT, T)
* 提取两幅图像中的点。
points_foerstner (ImageF, 1, 2, 3, 200, 0.3, 'gauss', 'false', RowJunctionsF, ColJunctionsF, CoRRJunctionsF, CoRCJunctionsF, CoCCJunctionsF, RowAreaF, ColAreaF, CoRRAreaF, CoRCAreaF, CoCCAreaF)
points_foerstner (ImageT, 1, 2, 3, 200, 0.3, 'gauss', 'false', RowJunctionsT, ColJunctionsT, CoRRJunctionsT, CoRCJunctionsT, CoCCJunctionsT, RowAreaT, ColAreaT, CoRRAreaT, CoRCAreaT, CoCCAreaT)

4 图像配准

    图像配准是一种确定待拼接图像间的重叠区域以及重叠位置的技术,它是整个图像拼接的核心。本节采用的是基于特征点的图像配准方法,即通过匹配点对构建图像序列之间的变换矩阵,从而完成全景图像的拼接。

    变换矩阵H求解是图像配准的核心,其求解的算法流程如下。

  1. 检测每幅图像中特征点。

  2. 计算特征点之间的匹配。

  3. 计算图像间变换矩阵的初始值。

  4. 迭代精炼H变换矩阵。

  5. 引导匹配。用估计的H去定义对极线附近的搜索区域,进一步确定特征点的对应。

  6. 重复迭代4)和5)直到对应点的数目稳定为止。

    图像配准算子如下:


    * 确定当前图像对的点匹配和变换。
    proj_match_points_ransac (ImageF, ImageT, RowJunctionsF, ColJunctionsF, RowJunctionsT, ColJunctionsT, 'ncc', 21, 0, 0, 480, 640, 0, 0.5, 'gold_standard', 1, 4364537, ProjMatrix, Points1, Points2)
    * 累加变换矩阵。
    ProjMatrices := [ProjMatrices,ProjMatrix]
    * 累积点数匹配和点数匹配。
    Rows1 := [Rows1,subset(RowJunctionsF,Points1)]
    Cols1 := [Cols1,subset(ColJunctionsF,Points1)]
    Rows2 := [Rows2,subset(RowJunctionsT,Points2)]
    Cols2 := [Cols2,subset(ColJunctionsT,Points2)]
    NumMatches := [NumMatches,|Points1|]
    * 生成表示平铺图像中提取点的十字。
    * 请注意,我们必须考虑平铺图像中图像的行偏移。
    gen_cross_contour_xld (PointsF, RowJunctionsF + (F - 1) * 500, ColJunctionsF, 6, rad(45))
    gen_cross_contour_xld (PointsT, RowJunctionsT + (T - 1) * 500, ColJunctionsT, 6, rad(45))
    * 生成匹配点对的线表示。我们从线条中创建XLD轮廓,以便放大图形窗口,更仔细地查看匹配。
    RowF := subset(RowJunctionsF,Points1) + (F - 1) * 500
    ColF := subset(ColJunctionsF,Points1)
    RowT := subset(RowJunctionsT,Points2) + (T - 1) * 500
    ColT := subset(ColJunctionsT,Points2)
    gen_empty_obj (Matches)
    for K := 0 to |RowF| - 1 by 1
        gen_contour_polygon_xld (Match, [RowF[K],RowT[K]], [ColF[K],ColT[K]])
        concat_obj (Matches, Match, Matches)
    endfor

5 图像融合

        根据仿射变换矩阵进行图像融合。

        关闭窗口后重新打开

gen_projective_mosaic (Images, MosaicImage, 2, From, To, ProjMatrices, 'default', 'false', MosaicMatrices2D)
get_image_size (MosaicImage, Width, Height)

6 图像合并

    单纯将多张图片按几行几列合并成一张大图并显示。


* 关闭窗口后重新打开
dev_close_window()
dev_open_window (0, 0, 600, 400, 'black', WindowHandle)
* 创建一张空白图片
gen_empty_obj (Images)
* 遍历文件夹
list_files ('C:/Users/Administrator/Desktop/test', ['files','follow_links'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
    * 缩放图片到图片统一大小
    zoom_image_size (Image, ImageZoom, 200, 200, 'constant')
    concat_obj (Images, ImageZoom, Images)
endfor
* 合并图片(按行填充,一行填满4张图片后再填充下一行)
tile_images (Images, TiledImage, 4, 'horizontal')
dev_display (TiledImage)

   图像效果如下:

Halcon图像拼接

7 拼接示例

    示例如图:

Halcon图像拼接

    代码如下:‍文章来源地址https://www.toymoban.com/news/detail-416593.html


dev_update_off ()
dev_close_window ()
dev_open_window (0, 0, 640, 480, 'white', WindowHandle)
dev_set_color ('green')
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* Read in the images and show them one-by-one.  Please not the fold-like
* degradations running across the PCB.
gen_empty_obj (Images)
for J := 1 to 6 by 1
    read_image (Image, 'mosaic/pcb_' + J$'02')
    concat_obj (Images, Image, Images)
    dev_display (Image)
    disp_message (WindowHandle, 'Image ' + J$'d', 'window', 12, 12, 'black', 'true')
    *wait_seconds (1)
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*显示用于计算投影的点匹配
*在图像之间进行转换,我们将以大屏幕显示所有图像
*平铺图像在图像之间留有一定的空间,以便
*这些图像中的大部分很容易看到。
dev_set_window_extents (-1, -1, 640 / 4, 2980 / 4)
tile_images_offset (Images, TiledImage, [0, 500, 1000, 1500, 2000, 2500], [0, 0, 0, 0, 0, 0], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], 640, 2980)
dev_clear_window ()
dev_display (TiledImage)
disp_message (WindowHandle, 'All 6 images', 'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', 2980 / 4 - 50, 12, 'black', 'true')
stop ()
*现在我们计算五对图像之间的点匹配,并以此计算图像对之间的投影变换。
*请注意,下面的代码为每个图像对调用点运算符。由于图像形成一条带,
*只需稍加簿记,我们就可以通过保存上一次迭代的点来提高过程的效率
*(J对中的ImageT将与J+1对中的ImageF相同)。这里没有这样做,
*因为在一般情况下,这样的优化会非常麻烦,因为图像可能位于无法用条带表示的一般配置中。
dev_clear_window ()
dev_display (TiledImage)
disp_message (WindowHandle, 'Point matches', 'window', 12, 3, 'black', 'true')
*我们定义了图像对,即哪个图像应该映射到哪个图像。
From := [1, 2, 3, 4, 5]
To := [2, 3, 4, 5, 6]
Num := |From|
* 我们需要一个变量来累加投影变换矩阵。
ProjMatrices := []
*此外,因为我们想要在下面创建一个刚性马赛克,所以我们需要累积所有点对应和匹配图像对的数量。
Rows1 := []
Cols1 := []
Rows2 := []
Cols2 := []
NumMatches := []
* 现在我们可以确定五个图像对之间的转换。
for J := 0 to Num - 1 by 1
    F := From[J]
    T := To[J]
    select_obj (Images, ImageF, F)
    select_obj (Images, ImageT, T)
    * 提取两幅图像中的点。
    points_foerstner (ImageF, 1, 2, 3, 200, 0.3, 'gauss', 'false', RowJunctionsF, ColJunctionsF, CoRRJunctionsF, CoRCJunctionsF, CoCCJunctionsF, RowAreaF, ColAreaF, CoRRAreaF, CoRCAreaF, CoCCAreaF)
    points_foerstner (ImageT, 1, 2, 3, 200, 0.3, 'gauss', 'false', RowJunctionsT, ColJunctionsT, CoRRJunctionsT, CoRCJunctionsT, CoCCJunctionsT, RowAreaT, ColAreaT, CoRRAreaT, CoRCAreaT, CoCCAreaT)
    * 确定当前图像对的点匹配和变换。
    proj_match_points_ransac (ImageF, ImageT, RowJunctionsF, ColJunctionsF, RowJunctionsT, ColJunctionsT, 'ncc', 21, 0, 0, 480, 640, 0, 0.5, 'gold_standard', 1, 4364537, ProjMatrix, Points1, Points2)
    * 累加变换矩阵。
    ProjMatrices := [ProjMatrices,ProjMatrix]
    * 累积点数匹配和点数匹配。
    Rows1 := [Rows1,subset(RowJunctionsF,Points1)]
    Cols1 := [Cols1,subset(ColJunctionsF,Points1)]
    Rows2 := [Rows2,subset(RowJunctionsT,Points2)]
    Cols2 := [Cols2,subset(ColJunctionsT,Points2)]
    NumMatches := [NumMatches,|Points1|]
    * 生成表示平铺图像中提取点的十字。
    * 请注意,我们必须考虑平铺图像中图像的行偏移。
    gen_cross_contour_xld (PointsF, RowJunctionsF + (F - 1) * 500, ColJunctionsF, 6, rad(45))
    gen_cross_contour_xld (PointsT, RowJunctionsT + (T - 1) * 500, ColJunctionsT, 6, rad(45))
    * 生成匹配点对的线表示。我们从线条中创建XLD轮廓,以便放大图形窗口,更仔细地查看匹配。
    RowF := subset(RowJunctionsF,Points1) + (F - 1) * 500
    ColF := subset(ColJunctionsF,Points1)
    RowT := subset(RowJunctionsT,Points2) + (T - 1) * 500
    ColT := subset(ColJunctionsT,Points2)
    gen_empty_obj (Matches)
    for K := 0 to |RowF| - 1 by 1
        gen_contour_polygon_xld (Match, [RowF[K],RowT[K]], [ColF[K],ColT[K]])
        concat_obj (Matches, Match, Matches)
    endfor
    * 现在显示提取的数据。
    dev_set_color ('blue')
    dev_display (Matches)
    dev_set_color ('green')
    dev_display (PointsF)
    dev_display (PointsT)
endfor
disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', 2980 / 4 - 50, 12, 'black', 'true')
stop ()
* 最后,我们可以从投影变换生成马赛克图像。
gen_projective_mosaic (Images, MosaicImage, 2, From, To, ProjMatrices, 'default', 'false', MosaicMatrices2D)
get_image_size (MosaicImage, Width, Height)
dev_set_window_extents (-1, -1, Width / 3, Height / 3)
dev_clear_window ()
dev_display (MosaicImage)
disp_message (WindowHandle, 'Projective mosaic', 'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', Height / 3 - 50, 12, 'black', 'true')
stop ()
* 为了更清楚地显示图像中可见的褶皱不是马赛克造成的,我们在马赛克图像中显示图像之间的接缝。
*这可以通过创建包含图像边界的图像、从中生成马赛克并分割生成的马赛克图像来实现。
get_image_size (Image, Width, Height)
gen_image_const (ImageBlank, 'byte', Width, Height)
gen_rectangle1 (Rectangle, 0, 0, Height - 1, Width - 1)
paint_region (Rectangle, ImageBlank, ImageBorder, 255, 'margin')
gen_empty_obj (ImagesBorder)
for J := 1 to 6 by 1
    concat_obj (ImagesBorder, ImageBorder, ImagesBorder)
endfor
gen_projective_mosaic (ImagesBorder, MosaicImageBorder, 2, From, To, ProjMatrices, 'default', 'false', MosaicMatrices2D)
threshold (MosaicImageBorder, Seams, 128, 255)
dev_clear_window ()
dev_display (MosaicImage)
disp_message (WindowHandle, 'Seams between the\nimages', 'window', 12, 12, 'black', 'true')
dev_set_color ('yellow')
dev_display (Seams)
disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', 550, 12, 'black', 'true')
stop ()
*如果你仔细观察上面的投影马赛克,你可能会注意到
*马赛克中有一个非常轻微的投影失真。这种情况会发生
*因为变换不能精确地确定
*因为噪声导致的点坐标误差非常小。因为
*在条形结构中,基本上是图像之间的重叠区域
*成对的图像可以像一个铰链一样绕着它旋转,离开图像平面。
*在这个例子中,我们知道图像之间的映射必须是刚性变换。如果我们想强制转换为刚性,
*我们可以简单地使用bundle_adjust_mosaic。
bundle_adjust_mosaic (6, 1, From, To, ProjMatrices, Rows1, Cols1, Rows2, Cols2, NumMatches, 'rigid', MosaicMatrices2D, Rows, Cols, Error)
* 现在,我们可以从刚性变换生成马赛克图像。
gen_bundle_adjusted_mosaic (Images, MosaicImageRigid, MosaicMatrices2D, 'default', 'false', TransMatrix2D)
get_image_size (MosaicImageRigid, Width, Height)
dev_set_window_extents (-1, -1, Width / 3, Height / 3)
dev_clear_window ()
dev_display (MosaicImageRigid)
disp_message (WindowHandle, 'Rigid mosaic', 'window', 12, 12, 'black', 'true')

到了这里,关于Halcon图像拼接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Redis常用的数据结构及实际应用场景

    本文介绍了Redis中常用的数据结构,包括字符串、列表、集合、哈希表、有序集合和Bitmap,并结合实际案例详细说明了它们在各种场景下的使用。 Redis是一种基于内存的高性能键值存储系统,拥有多种数据结构,每种数据结构都具有独特的特点和适用场景。了解这些数据结构

    2024年02月08日
    浏览(47)
  • 机器人物理交互场景及应用的实际意义

    机器人物理交互场景是指机器人与物理世界或人类进行实际的物理互动和交互的情境。这些场景涉及机器人在不同环境和应用中使用其物理能力,以执行任务、提供服务或与人类互动。 医疗协助 : 外科手术助手 :机器人可以用于外科手术,提供高精度的操作,减小手术风险

    2024年02月05日
    浏览(53)
  • 【docker系列】docker解决的实际问题及应用场景

    笔者打算写一个完整系列的docker知识总结,本文是第一篇,主要介绍docker是什么?主要的应用场景是什么?解决了哪些问题?和虚拟机有什么区别? Docker 是一个开源的容器引擎,它轻巧,且易移植,“build once, configure once and run anywhere”。使用go语言开发,并遵从apache2.0协议

    2023年04月08日
    浏览(41)
  • DC电源模块不同的尺寸可以适应实际应用场景

    BOSHIDA DC电源模块不同的尺寸可以适应实际应用场景 DC电源模块是现代电子设备的必备部件之一,其可提供稳定的直流电源,保证电子设备正常运行。DC电源模块尺寸的选择直接影响到其适应的应用场景及其性能表现。本文将从尺寸方面分析DC电源模块的适应性,探讨其不同尺

    2024年02月11日
    浏览(48)
  • 边缘计算技术主要有哪几种?如何应用在实际场景中?

    边缘计算是一种新的计算架构,它将计算资源移动到靠近终端用户的边缘设备中,以实现更快、更可靠、更安全的数据传输和处理。边缘AI智能则是指将人工智能算法和模型部署到边缘设备上,使其能够在设备本身上执行计算和决策,而不需要发送数据到云端进行处理。这种

    2024年02月11日
    浏览(45)
  • Java单例模式详解--七种单例模式实现+单例安全+实际应用场景

    保证了一个类只有一个实例,并且提供了一个全局访问点。单例模式的主要作用是节省公共资源,方便控制,避免多个实例造成的问题。 实现单例模式的三点: 私有构造函数 私有静态变量维护对象实例 公有静态方法提供获取实例对象 七种单例模式实现 1.静态类:第一次运

    2024年02月04日
    浏览(59)
  • 深入云原生—基于KubeWharf深度剖析-以公司实际应用场景为例深度解读

    各位好,这里是难忘,本人对云原生也是研究了2年多了,算是略有所得,本次就来深入云原生—基于KubeWharf深度剖析场景与解读。我们需要先了解一下 KubeWharf,可能很多人都感觉到有点陌生吧,下面我们来一起学习! KubeWharf 是字节跳动基础架构团队在对 Kubernetes 进行了大

    2024年01月23日
    浏览(63)
  • 中文编程工具开发语言开发的实际案例:触摸屏点餐软件应用场景实例

    中文编程工具开发语言开发的实际案例:触摸屏点餐软件应用场景实例 软件特色: 1、功能实用,操作简单,不会电脑也会操作,软件免安装,已内置数据库。软件在关闭的时候,可以设置会员数据备份到U盘,数据本机备份一份,U盘备份一份,双重备份数据安全。 2、软件既

    2024年02月08日
    浏览(42)
  • 编程应用实际场景:台球厅怎么样用电脑给客人计时,台球计时收费系统操作教程

    一、前言 准确控制顾客在店内游玩的时间,从而控制店内的各项成本,并提升店内的客流量。 在顾客享受计时项目的时候,可以同时添加其他食物消费,并将单据合并统一结账。 软件中的会员功能可以为客户办理会员 可以使用灯控器控灯,在开始计时的时候,开灯,结账后

    2024年02月04日
    浏览(129)
  • Python与OpenCV环境中,借助SIFT、单应性、KNN以及Ransac技术进行实现的图像拼接算法详细解析及应用

    一、引言 在当今数字化时代,图像处理技术的重要性不言而喻。它在无人驾驶、计算机视觉、人脸识别等领域发挥着关键作用。作为图像处理的一个重要部分,图像拼接算法是实现广阔视野图像的重要手段。今天我们将会讲解在Python和OpenCV环境下,如何使用SIFT、单应性、K

    2024年02月15日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包