上一篇主要介绍了图像拼接的一些原理和方法,这一篇将主要介绍步骤和例程:

接上一篇:

基于特征的接拼方法,分为四个步骤

1、特征检测:从图像中检测出显著且独特的图像特征,诸如:闭合区域,直线段,边缘,轮廓,点等。

2、特征匹配:从相似度确定图像之间特征的对应关系,又分为如下几类:

2.1:使用空域关系的方法

2.2:使用不变描述符的方法

2.3:松弛方法

2.4:金字塔和小波方法

3、变换模型的估计:变换函数选择和函数参数估计

4、图像变换和重采样:可以通过前向或后向的方式来实现,插值的方法有最近邻插值、双线性插值、双三次函数插值、二次样条插值、三次B样条插值、高阶B样条插值。

基于特征的方法普遍适用于局部结构信息更显著的情况,能够处理图像之间复杂变形的情况,不足之处是特征检测困难且不稳定,最关键的一点是需要有一种判断力很强的、鲁棒性能好的且对图像之间变化保持不变的特征匹配算法。

下面是Halcon自带例程,如何拼接图像

  1. **此例程讲解了如何将几张局部的PCB图像拼接居一张大的马赛克PCB图像。
  2. **此例程使用算子proj_match_points_ransac和算子 gen_projective_masaic完成上述工作。
  3. **请注意:这个PCB图像有一几处看起来像拼接逢合线的破损点,为了更好的区分真正的缝合线,例程呈现逢合线。
  4. dev_update_off ()
  5. dev_close_window ()
  6. dev_open_window (, , , , 'white', WindowHandle)
  7. dev_set_color ('green')
  8. set_display_font (WindowHandle, , 'mono', 'true', 'false')
  9. **一张一张的读取图像。
  10. gen_empty_obj (Images)
  11. for J := to by
  12. read_image (Image, 'mosaic/pcb_' + J$'')
  13. concat_obj (Images, Image, Images)
  14. dev_display (Image)
  15. disp_message (WindowHandle, 'Image ' + J$'d', 'image', -, -, 'black', 'true')
  16. wait_seconds ()
  17. endfor
  18. disp_continue_message (WindowHandle, 'black', 'true')
  19. stop ()
  20. * To show the point matches that are used to compute the projective
  21. * transformation between the images, we will show all images in a large
  22. * tiled image with some space between the images so that the extents
  23. * of the images are easily visible.
  24. dev_set_window_extents (-, -, / , / )
  25. tile_images_offset (Images, TiledImage, [,,,,,], [,,,,,], [-,-,-,-,-,-], [-,-,-,-,-,-], [-,-,-,-,-,-], [-,-,-,-,-,-], , )
  26. dev_clear_window ()
  27. dev_display (TiledImage)
  28. disp_message (WindowHandle, 'All 6 images', 'window', , , 'black', 'true')
  29. disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', / - , , 'black', 'true')
  30. stop ()
  31. * Now we compute point matches between the five pairs of images and with this
  32. * the projective transformation between the image pairs. Note that the code
  33. * below calls the point operator for each image pair. Since the images form
  34. * a strip, with a little book keeping we could make the process a little more
  35. * efficient by saving the points from the last iteration (ImageT in pair J will
  36. * be identical to ImageF in pair J+). This is not done here because such an
  37. * optimization would be quite cumbersome in the general case where the images
  38. * can lie in a general configuration that cannot be represented by a strip.
  39. dev_clear_window ()
  40. dev_display (TiledImage)
  41. disp_message (WindowHandle, 'Point matches', 'window', , , 'black', 'true')
  42. * We define the image pairs, i.e., which image should be mapped to which image.
  43. From := [,,,,]
  44. To := [,,,,]
  45. Num := |From|
  46. * We need a variable to accumulate the projective transformation matrices.
  47. ProjMatrices := []
  48. * Furthermore, since we want to create a rigid mosaic below we need to
  49. * accumulate all the point correspondences and the number of matches per
  50. * image pair.
  51. Rows1 := []
  52. Cols1 := []
  53. Rows2 := []
  54. Cols2 := []
  55. NumMatches := []
  56. * Now we can determine the transformations between the five image pairs.
  57. for J := to Num - by
  58. F := From[J]
  59. T := To[J]
  60. select_obj (Images, ImageF, F)
  61. select_obj (Images, ImageT, T)
  62. * Extract the points in both images.
  63. points_foerstner (ImageF, , , , , 0.3, 'gauss', 'false', RowJunctionsF, ColJunctionsF, CoRRJunctionsF, CoRCJunctionsF, CoCCJunctionsF, RowAreaF, ColAreaF, CoRRAreaF, CoRCAreaF, CoCCAreaF)
  64. points_foerstner (ImageT, , , , , 0.3, 'gauss', 'false', RowJunctionsT, ColJunctionsT, CoRRJunctionsT, CoRCJunctionsT, CoCCJunctionsT, RowAreaT, ColAreaT, CoRRAreaT, CoRCAreaT, CoCCAreaT)
  65. * Determine the point matches and the transformation for the current
  66. * image pair.
  67. proj_match_points_ransac (ImageF, ImageT, RowJunctionsF, ColJunctionsF, RowJunctionsT, ColJunctionsT, 'ncc', , , , , , , 0.5, 'gold_standard', , , ProjMatrix, Points1, Points2)
  68. * Accumulate the transformation matrix.
  69. ProjMatrices := [ProjMatrices,ProjMatrix]
  70. * Accumulate the point matches and number of point matches.
  71. Rows1 := [Rows1,subset(RowJunctionsF,Points1)]
  72. Cols1 := [Cols1,subset(ColJunctionsF,Points1)]
  73. Rows2 := [Rows2,subset(RowJunctionsT,Points2)]
  74. Cols2 := [Cols2,subset(ColJunctionsT,Points2)]
  75. NumMatches := [NumMatches,|Points1|]
  76. * Generate crosses that represent the extracted points in the tiled image.
  77. * Note that we have to take the row offsets of the images in the tiled image
  78. * into account.
  79. gen_cross_contour_xld (PointsF, RowJunctionsF + (F - ) * , ColJunctionsF, , rad())
  80. gen_cross_contour_xld (PointsT, RowJunctionsT + (T - ) * , ColJunctionsT, , rad())
  81. * Generate a representation of the matched point pairs as lines. We create
  82. * XLD contours from the lines so that we can zoom into the graphics window
  83. * to take a closer look at the matches.
  84. RowF := subset(RowJunctionsF,Points1) + (F - ) *
  85. ColF := subset(ColJunctionsF,Points1)
  86. RowT := subset(RowJunctionsT,Points2) + (T - ) *
  87. ColT := subset(ColJunctionsT,Points2)
  88. gen_empty_obj (Matches)
  89. for K := to |RowF| - by
  90. gen_contour_polygon_xld (Match, [RowF[K],RowT[K]], [ColF[K],ColT[K]])
  91. concat_obj (Matches, Match, Matches)
  92. endfor
  93. * Now display the extracted data.
  94. dev_set_color ('blue')
  95. dev_display (Matches)
  96. dev_set_color ('green')
  97. dev_display (PointsF)
  98. dev_display (PointsT)
  99. endfor
  100. disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', / - , , 'black', 'true')
  101. stop ()
  102. * Finally, we can generate the mosaic image from the projective transformations.
  103. gen_projective_mosaic (Images, MosaicImage, , From, To, ProjMatrices, 'default', 'false', MosaicMatrices2D)
  104. get_image_size (MosaicImage, Width, Height)
  105. dev_set_window_extents (-, -, Width / , Height / )
  106. dev_clear_window ()
  107. dev_display (MosaicImage)
  108. disp_message (WindowHandle, 'Projective mosaic', 'window', , , 'black', 'true')
  109. disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', Height / - , , 'black', 'true')
  110. stop ()
  111. * To show more clearly that the folds visible in the image do not result from the
  112. * mosaicking, we display the seams between the images in the mosaic image.
  113. * This can be done most easily by creating an image that contains the border
  114. * of the images, generating a mosaic from it, and segmenting the resulting
  115. * mosaic image.
  116. get_image_size (Image, Width, Height)
  117. gen_image_const (ImageBlank, 'byte', Width, Height)
  118. gen_rectangle1 (Rectangle, , , Height - , Width - )
  119. paint_region (Rectangle, ImageBlank, ImageBorder, , 'margin')
  120. gen_empty_obj (ImagesBorder)
  121. for J := to by
  122. concat_obj (ImagesBorder, ImageBorder, ImagesBorder)
  123. endfor
  124. gen_projective_mosaic (ImagesBorder, MosaicImageBorder, , From, To, ProjMatrices, 'default', 'false', MosaicMatrices2D)
  125. threshold (MosaicImageBorder, Seams, , )
  126. dev_clear_window ()
  127. dev_display (MosaicImage)
  128. disp_message (WindowHandle, 'Seams between the\nimages', 'window', , , 'black', 'true')
  129. dev_set_color ('yellow')
  130. dev_display (Seams)
  131. disp_message (WindowHandle, 'Click \'Run\'\nto continue', 'window', , , 'black', 'true')
  132. stop ()
  133. * If you look very closely at the projective mosaic above, you may note that
  134. * there is a very slight projective distortion in the mosaic. This happens
  135. * because the transformations cannot be determined with perfect accuracy
  136. * because of very small errors in the point coordinates due to noise. Because
  137. * of the strip configuration, essentially the overlapping area between the image
  138. * pairs can act like a hinge around which the images may rotate out of the image
  139. * plane. In this example, we know that the mapping between the images must
  140. * be a rigid transformation. If we want to force the transformation to be rigid
  141. * we can simply use bundle_adjust_mosaic.
  142. bundle_adjust_mosaic (, , From, To, ProjMatrices, Rows1, Cols1, Rows2, Cols2, NumMatches, 'rigid', MosaicMatrices2D, Rows, Cols, Error)
  143. * Now, we can generate the mosaic image from the rigid transformations.
  144. gen_bundle_adjusted_mosaic (Images, MosaicImageRigid, MosaicMatrices2D, 'default', 'false', TransMatrix2D)
  145. get_image_size (MosaicImageRigid, Width, Height)
  146. dev_set_window_extents (-, -, Width / , Height / )
  147. dev_clear_window ()
  148. dev_display (MosaicImageRigid)
  149. disp_message (WindowHandle, 'Rigid mosaic', 'window', , , 'black', 'true')

带逢合线的图像                    找定位点

最终图像:

下面我们看一下另一个例程:

这个例程使用proj_match_points_ransac_guided 和 gen_projective_mosaic

主要介绍如何使用金字塔算法快速获取两个图像的特征点进行拼接。

  1. * This example program shows how images can be combined
  2. * into a mosaic image using proj_match_points_ransac_guided
  3. * and gen_projective_mosaic.
  4. * It is shown how the calculation of the projection between two
  5. * images can be accelerated using an image pyramid.
  6. *
  7. * Initializations
  8. ImgPath := '3d_machine_vision/mosaic/'
  9. ImgName := 'bga_r_'
  10. Times := []
  11. Colors := ['red','coral','yellow','lime green']
  12. read_image (Images, ImgPath + ImgName + ['',''])
  13. dev_update_off ()
  14. dev_close_window ()
  15. dev_open_window_fit_size (, , , , , , WindowHandle)
  16. dev_open_window_fit_size (, , , , , , WindowHandle1)
  17. set_display_font (WindowHandle, , 'mono', 'true', 'false')
  18. set_display_font (WindowHandle1, , 'mono', 'true', 'false')
  19. * The internal camera parameters of the used camera
  20. * (necessary to eliminate radial distortions)
  21. CamParam := [0.0121693,-2675.63,7.40046e-006,7.4e-006,290.491,258.887,,]
  22. change_radial_distortion_cam_par ('adaptive', CamParam, , CamParOut)
  23. change_radial_distortion_image (Images, Images, Images, CamParam, CamParOut)
  24. * To show the point matches that are used to compute the
  25. * transformation between the images, we will show both images in a
  26. * tiled image with some space between the images so that the extents
  27. * of the images are easily visible.
  28. tile_images_offset (Images, TiledImage, [,], [,], [-,-], [-,-], [-,-], [-,-], , )
  29. *
  30. * Now we can determine the transformations between the image pairs.
  31. From :=
  32. To :=
  33. select_obj (Images, ImageF, From)
  34. select_obj (Images, ImageT, To)
  35. *
  36. * Repeat the calculation times with a different number of pyramid levels
  37. for NumLevels := to by
  38. *
  39. dev_clear_window ()
  40. dev_set_window (WindowHandle)
  41. dev_clear_window ()
  42. dev_display (TiledImage)
  43. disp_message (WindowHandle, ['Calculate point matches','with ' + NumLevels + ' pyramid levels','Please wait ...'], 'window', , , 'black', 'true')
  44. *
  45. * Calculate the projection between the two images
  46. * Check the procedure's comments for details
  47. count_seconds (S1)
  48. proj_match_points_ransac_pyramid (ImageF, ImageT, NumLevels, RowFAll, ColFAll, RowTAll, ColTAll, ProjMatrix, Points1, Points2)
  49. count_seconds (S2)
  50. Times := [Times,S2 - S1]
  51. *
  52. * Display point correspondences
  53. gen_cross_contour_xld (PointsF, RowFAll, ColFAll, , rad())
  54. gen_cross_contour_xld (PointsT, RowTAll + , ColTAll, , rad())
  55. RowF := subset(RowFAll,Points1)
  56. ColF := subset(ColFAll,Points1)
  57. RowT := subset(RowTAll,Points2) +
  58. ColT := subset(ColTAll,Points2)
  59. gen_empty_obj (Matches)
  60. for K := to |RowF| - by
  61. gen_contour_polygon_xld (Match, [RowF[K],RowT[K]], [ColF[K],ColT[K]])
  62. concat_obj (Matches, Match, Matches)
  63. endfor
  64. dev_display (TiledImage)
  65. dev_set_color ('blue')
  66. dev_display (Matches)
  67. dev_set_color ('green')
  68. dev_display (PointsF)
  69. dev_display (PointsT)
  70. disp_message (WindowHandle, [|RowF| + ' point matches','Time used: ' + (S2 - S1)$'.3' + ' s'], 'window', , , 'black', 'true')
  71. *
  72. * Generate the mosaic image
  73. gen_projective_mosaic (Images, MosaicImage, , From, To, ProjMatrix, [,], 'false', MosaicMatrices2D)
  74. *
  75. * Display mosaic image
  76. get_image_size (MosaicImage, Width, Height)
  77. dev_set_window (WindowHandle1)
  78. dev_resize_window_fit_image (MosaicImage, , , [,], )
  79. dev_clear_window ()
  80. dev_display (MosaicImage)
  81. disp_message (WindowHandle1, 'Projective mosaic (used ' + NumLevels + ' pyramid levels)', 'window', , , 'black', 'true')
  82. disp_continue_message (WindowHandle1, 'black', 'true')
  83. stop ()
  84. endfor
  85. *
  86. * Display execution times
  87. dev_set_window (WindowHandle)
  88. dev_close_window ()
  89. MaxTime := max(Times)
  90. BaseRow :=
  91. RectHeight :=
  92. disp_message (WindowHandle1, ['Time in s:','(#levels used)'], 'image', BaseRow + , , 'black', 'true')
  93. for Index := to |Times| - by
  94. gen_rectangle1 (Rectangle, BaseRow - RectHeight * Times[Index] / MaxTime, + Index * , BaseRow, + Index * )
  95. disp_message (WindowHandle1, [Times[Index]$'.3','(' + (Index + ) + ')'], 'image', BaseRow + , + * Index, 'black', 'true')
  96. dev_set_color (Colors[Index])
  97. dev_set_draw ('fill')
  98. dev_display (Rectangle)
  99. endfor
  100. disp_finished_message (WindowHandle1, 'black', 'true')

 

 

Halcon一日一练:图像拼接技术2:步骤与例程的更多相关文章

  1. Halcon一日一练:读取文件目录图像的三种方法

    第一种方法: 读了一个单一图像: read_image(Image,'fabrik') 这种方式可以快速的读取软件自身携带的库图像文件,系统设定了库图像映像文件的快速读取方式,我们也可以通过绝对地址的 ...

  2. Halcon一日一练:图像拼接技术

    图像拼接技术就是针对同一场景的一系列图片,根据图片的特征,比如位置,重叠部分等,拼接成一张大幅的宽视角的图像. 图像拼接要求拼接后图像最大程度的与原图一致,失真尽可能的小,并且要尽量做到天衣无缝即没有 ...

  3. Halcon一日一练:图像设备介绍

    Halcon在设计之初就提供了完整的图像采集方案,适应了多种图像设备采集图像,以及各种不同环境的采集方案. 通常情况下,图像的采集应该是所有机器视觉项目首要解决的任务,不幸的是,需要解决图像采集的问题 ...

  4. Halcon一日一练:创建三通道图像

    首先理解一个什么是三通道图像: 三通道图像就是彩色图像,我们之前黑白相机或黑白电视机都是彩用的灰阶图像,即单通道图像,一般是2的8次方个灰阶,即256个灰阶.彩色图像采用RGB,红绿蓝三个通道来合成彩 ...

  5. Halcon一日一练:图像、变量实时更新

    某些场合,我们需要刷新图像来识别图像处理过程的差异性,便于调试判断问题和预测.Halcon提供了图像刷新操作,这些操作不会改变程序的最终处理结果. 例程: **实时刷新图像 dev_update_wi ...

  6. Halcon一日一练:图像分辨率与像素

    1.图像像素: 像素是指由图像的小方格即所谓的像素(pixel)组成的,这些小方块都有一个明确的位置和被分配的色彩数值,而这些一小方格的颜色和位置就决定该图像所呈现出来的样子.像素是构成图像的基本单元 ...

  7. Halcon一日一练:CAD类型的相关操作

    大很多场合,需要在视觉程序中导入CAD文档,比如,在3C行业,需要对手机外壳进行CNC加工,或者点胶操作,此时,需要获取产品的各个点的数据.如果将CAD直接导入,就会大的减少编程工作量,同时也能达到很 ...

  8. Halcon一日一练:图像采集设备的基本参数

    因操作图像处理之前,需要对图像进行采集.采集图像,我们首先要确定的是图像的像素和采集的效率.这些都需要对设备进行配置与操作.现实情况是图像设备有各自不同的采集方式,配置也各不相同.这就需要设备提供商提 ...

  9. Halcon一日一练:获取程序运行时间

    很多时候,我们需要知道每个函数的运算周期,以提高程序的运行效率.知道运行时间对于图像算法处理很重要 Halcon提供相关的算子,我们先来看代码: **获取图像处理时间 read_image(Image ...

随机推荐

  1. 【开发技术】java+mysql 更改表字段的步骤

    1).首先通过SQL更改MYSQL库中的表结构(下面是一些例子) ALTER TABLE `illegalactivate` ADD `macethaddress` varchar(250)  NOT ...

  2. NSString拼接字符串

    NSString* string; // 结果字符串 02 NSString* string1, string2; //已存在的字符串,需要将string1和string2连接起来 03   04 / ...

  3. JAVA BASE64

    Base64编码说明:     Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式. 如果剩下的字符不足3个字节, ...

  4. CCF系列之最优灌溉(201412-4)

    试题编号:201412-4试题名称:最优灌溉时间限制: 1.0s内存限制: 256.0MB 问题描述 雷雷承包了很多片麦田,为了灌溉这些麦田,雷雷在第一个麦田挖了一口很深的水井,所有的麦田都从这口井来 ...

  5. jQuery hover() 方法

    $("p").hover(function(){ $("p").css("background-color","yellow&qu ...

  6. python_如何定义装饰器类?

    案例: 实现一个能将函数调用信息记录到日志的装饰器 需求: 把每次函数的调用时间,执行时间,调用次数写入日志 可以对被装饰函数分组,调用信息记录到不同日志 动态修改参数,比如日志格式 动态打开关闭日志 ...

  7. myeclipse环境搭建

    公司来了几个新人,老是在教他们环境搭建这些,每次在帮他们调试代码的时候老是不厌其烦的看着他们坐等myeclipse编译了,校验了什么的,而且在编码的时候也不使用快捷键,然后我就只能默默的坐回去了.为了 ...

  8. 微信H5支付网络环境未能通过安全验证,请稍后再试(获取终端ip )

    在写微信H5支付的时候需要获取终端IP使用官方的方法是不对的报错如下: 故重写一个:如下 function get_client_ip(){ if(getenv('HTTP_CLIENT_IP') & ...

  9. Docker for Web Developers目录

    在OpenStack在私有云占主导定位之后,后起之秀Docker在PaaS平台.CI/CD.微服务领域展露锋芒.作为Web Developers,我们有必要学习和掌握这门技术. 1. 运行第一个Doc ...

  10. Go语言学习索引

    <Go并发编程实战>示例项目 项目地址: https://github.com/hyper-carrot/goc2p 项目安装: 用git clone获取项目,并将其根目录作为一个工作区. ...