首页IT科技halcon两张图片拼在一起(Halcon图像拼接)

halcon两张图片拼在一起(Halcon图像拼接)

时间2025-08-05 03:38:56分类IT科技浏览5814
导读: 图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要。...

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

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

1 拼接步骤

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

输入图像

图像几何校正

图像预处理

对每幅图进行特征点提取

对特征点进行匹配

进行图像配准

图像融合

对重叠边界进行特殊处理

2 拼接条件

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

图像应具有一定的特征        。

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

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

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

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

3 特征点提取

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

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

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

    SURF 特征点提取与描述主要包含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求解是图像配准的核心        ,其求解的算法流程如下                        。

检测每幅图像中特征点        。

计算特征点之间的匹配           。

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

迭代精炼H变换矩阵            。

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

重复迭代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)

   图像效果如下:

7 拼接示例

    示例如图:

    代码如下:‍

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)

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
react hooks setstate回调(【React-Hooks进阶】useState回调函数的参数 / useEffect发送网络请求/ useRef / useContext)