1. 為什么要拼接
如果你的被射物足夠小;
如果你的鏡頭視野足夠大;
如果你的銀子足夠多,可以買更牛的相機,更牛的鏡頭。。。
如果你沒有那么多的如果,項目多了,圖像拼接在所難免。
2. 效果是啥
借助Halcon自帶的例子,就是將下面兩張圖像,拼接為一個更寬的圖像。
圖像1:
圖像2:
拼接后的圖像:
有沒有變得更寬?
3. 拼接步驟
- 讀取圖像
- 提取特征點
- 計算變換矩陣
- 拼接
參考Halcon例程proj_match_points_distortion_ransac.hdev,逐步分析。該例程是基於特征點來拼接圖像的。
3.1. 讀取圖像並顯示圖像
代碼:
read_image (Image1, 'building_01')
read_image (Image2, 'building_02')
get_image_size (Image1, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image1)
disp_message (WindowHandle, 'Image 1 to be matched', 'image', -1, -1, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_display (Image2)
disp_message (WindowHandle, 'Image 2 to be matched', 'image', -1, -1, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
效果:
3.2. 獲取特征點
該例程是基於圖像的特征點進行拼接圖像的,需要獲取兩張圖像的特征點。
何為特征點?根據算子points_foerstner的解釋,特征點有兩類,一類名為交點特征點,指的是那些圖像邊沿的點,另一類稱作區域特征點,如,圖像的顏色和亮度與周圍不同的點。
代碼:
points_foerstner (Image1, 1, 2, 3, 50, 0.1, 'gauss', 'true', Rows1, Columns1, CoRRJunctions, CoRCJunctions, CoCCJunctions, RowArea, ColumnArea, CoRRArea, CoRCArea, CoCCArea)
points_foerstner (Image2, 1, 2, 3, 50, 0.1, 'gauss', 'true', Rows2, Columns2, CoRRJunctions, CoRCJunctions, CoCCJunctions, RowArea, ColumnArea, CoRRArea, CoRCArea, CoCCArea)
- 1
- 2
- 3
3.3. 計算仿射變換矩陣
根據兩幅圖像的特征點,計算出仿射變換矩陣。
代碼:
proj_match_points_ransac (Image1, Image2, Rows1, Columns1, Rows2, Columns2, 'ncc', 10, 0, 0, Height, Width, 0, 0.5, 'gold_standard', 2, 42, HomMat2DUnrectified, Points1Unrectified, Points2Unrectified)
- 1
3.3. 拼接
根據仿射變換矩陣進行拼接。
代碼:
concat_obj (Image1, Image2, Images)
gen_projective_mosaic (Images, MosaicImageUnrectified, 1, 1, 2, HomMat2DUnrectified, 'default', 'false', MosaicMatrices2DUnrectified)
- 1
- 2
- 3
效果:
顯示接縫代碼:
projective_trans_pixel (MosaicMatrices2DUnrectified[9:17], [0,493], [0,0], RowTrans, ColumnTrans)
gen_contour_polygon_xld (Contour, RowTrans, ColumnTrans)
- 1
- 2
- 3
接縫效果:
仔細觀察圖像拼接的接縫處,發現拼接的效果並不理想,接縫是錯開的。原因是兩張圖像的徑向畸變造成的。何為徑向畸變?這是鏡頭固有的,當焦距很大或很小時,拍出的圖像尤其明顯,圖像的邊緣處向前凹,或者向里凸的效果,仔細觀察原來的兩張圖像,邊緣處是向里凸進去的。
課外知識
相機內參數:
f:相機的主矩,即焦距
k:徑向扭曲的大小,即徑向畸變,一般不考慮切向畸變
sx,sy:圖像傳感器在水平和垂直方向上相鄰像素之間的距離
cx,cy: 投影中心在成像平面的垂直投影
- 1
- 2
- 3
- 4
相機外參數:
平移向量X,Y,Z
旋轉向量X,Y,Z
透視矯正
- 1
- 2
- 3
相機的內外參數是相機標定的重點。
因此,例程的后半部分就是消除這種徑向畸變對拼接的影響,Halcon中有對應的算子,使用起來很方便。
4. 消除徑向畸變
4.1. 讀出圖像
同上
4.2. 計算仿射變換矩陣
注意,使用了消除徑向畸變的算子。代碼:
proj_match_points_distortion_ransac (Image1, Image2, Rows1, Columns1, Rows2, Columns2, 'ncc', 10, 0, 0, Height, Width, 0, 0.5, 'gold_standard', 1, 42, HomMat2D, Kappa, Error, Points1, Points2)
- 1
4.3. 預處理
消除圖像中的鏡像畸變。
代碼:
CamParDist := [0.0,Kappa,1.0,1.0,0.5 * (Width - 1),0.5 * (Height - 1),Width,Height]
change_radial_distortion_cam_par ('fixed', CamParDist, 0, CamPar)
change_radial_distortion_image (Image1, Image1, Image1Rect, CamParDist, CamPar)
change_radial_distortion_image (Image2, Image2, Image2Rect, CamParDist, CamPar)
- 1
- 2
- 3
- 4
- 5
效果:
圖像1(原圖)
圖像1(去除徑向畸變后)
圖像2(原圖)
圖像2(去除徑向畸變后)
第一組圖效果不是很明顯,仔細觀察第二組圖,兩個邊緣是不是被拉平了?
4.4. 圖像拼接
同上。
最終的效果:
仔細觀察接縫處,這次圖像拼接的很好。
5. 代碼
完整代碼如下:
* This example shows how to use proj_match_points_distortion_ransac to
* match two images in a mosaicking application.
* 該例子說明在拼接應用中,如何使用proj_match_points_distortion_ransac算子
* 拼接兩張圖片(基於特征點匹配拼接圖像)
*
* Initialization
* 初始化
dev_update_off ()
* Read and display the images
* 讀取並顯示圖像
read_image (Image1, 'building_01')
read_image (Image2, 'building_02')
get_image_size (Image1, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image1)
disp_message (WindowHandle, 'Image 1 to be matched', 'image', -1, -1, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_display (Image2)
disp_message (WindowHandle, 'Image 2 to be matched', 'image', -1, -1, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
* Extract points to be matched from the images
* 獲取特征點
points_foerstner (Image1, 1, 2, 3, 50, 0.1, 'gauss', 'true', Rows1, Columns1, CoRRJunctions, CoRCJunctions, CoCCJunctions, RowArea, ColumnArea, CoRRArea, CoRCArea, CoCCArea)
points_foerstner (Image2, 1, 2, 3, 50, 0.1, 'gauss', 'true', Rows2, Columns2, CoRRJunctions, CoRCJunctions, CoCCJunctions, RowArea, ColumnArea, CoRRArea, CoRCArea, CoCCArea)
*
* We will first perform a normal projective matching that does not take
* the radial distortions into account to show the errors that are caused
* by neglecting the radial distortions.
* 首先,不考慮徑向畸變的情況下,執行圖像拼接,我們會看到由於徑向畸變的影響
* 接縫處的拼接效果並不理想
proj_match_points_ransac (Image1, Image2, Rows1, Columns1, Rows2, Columns2, 'ncc', 10, 0, 0, Height, Width, 0, 0.5, 'gold_standard', 2, 42, HomMat2DUnrectified, Points1Unrectified, Points2Unrectified)
* Construct a projective mosaic from the two unrectified images.
* 將兩個未修改(有徑向畸變)的圖像構造為一個投影拼接(projective mosaic)
concat_obj (Image1, Image2, Images)
gen_projective_mosaic (Images, MosaicImageUnrectified, 1, 1, 2, HomMat2DUnrectified, 'default', 'false', MosaicMatrices2DUnrectified)
*
* Display unrectified results
* 顯示結果
get_image_size (MosaicImageUnrectified, Width, Height)
dev_set_window_extents (-1, -1, Width, Height)
dev_clear_window ()
dev_display (MosaicImageUnrectified)
* Display seam line
* 顯示拼接縫隙
projective_trans_pixel (MosaicMatrices2DUnrectified[9:17], [0,493], [0,0], RowTrans, ColumnTrans)
gen_contour_polygon_xld (Contour, RowTrans, ColumnTrans)
set_line_style (WindowHandle, [1,5])
dev_set_line_width (1)
dev_set_color ('yellow')
dev_display (Contour)
set_line_style (WindowHandle, [])
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (3)
gen_circle (Circle, [82,402], [228,223], [15,15])
dev_display (Circle)
* 從結果看,不考慮徑向畸變的情況下,接縫處的拼接效果並不理想,接縫處是錯開的
Message := 'The mosaic image does not fit'
Message[1] := 'perfectly, if radial distortions'
Message[2] := 'are not taken into account.'
disp_message (WindowHandle, Message, 'image', 200, 300, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
* Now, we will perform a projective matching that takes the radial
* distortions into account.
* 這次,去除徑向畸變的影響,再次執行拼接
get_image_size (Image1, Width, Height)
proj_match_points_distortion_ransac (Image1, Image2, Rows1, Columns1, Rows2, Columns2, 'ncc', 10, 0, 0, Height, Width, 0, 0.5, 'gold_standard', 1, 42, HomMat2D, Kappa, Error, Points1, Points2)
* Construct camera parameters for the purpose of rectifying the images,
* i.e., to remove the radial distortions.
* 為了修改圖像,構造相機參數
* 如,去除徑向畸變
CamParDist := [0.0,Kappa,1.0,1.0,0.5 * (Width - 1),0.5 * (Height - 1),Width,Height]
* Remove the radial distortions from the images.
* 去除圖像中的徑向畸變
change_radial_distortion_cam_par ('fixed', CamParDist, 0, CamPar)
change_radial_distortion_image (Image1, Image1, Image1Rect, CamParDist, CamPar)
change_radial_distortion_image (Image2, Image2, Image2Rect, CamParDist, CamPar)
* Construct a mosaic from the two rectified images. Note that the images
* fit together perfectly.
* 使用去除了徑向畸變的圖像構造拼接圖像
* 可以看到圖像拼接的很好
concat_obj (Image1Rect, Image2Rect, ImagesRect)
gen_projective_mosaic (ImagesRect, MosaicImage, 1, 1, 2, HomMat2D, 'default', 'false', MosaicMatrices2D)
*
* Display rectified results
* 顯示修改后的結果
get_image_size (MosaicImage, Width, Height)
dev_set_window_extents (-1, -1, Width, Height)
dev_clear_window ()
dev_display (MosaicImage)
* Display seam line
* 顯示接縫
projective_trans_pixel (MosaicMatrices2D[9:17], [0,493], [0,0], RowTrans, ColumnTrans)
gen_contour_polygon_xld (Contour2, RowTrans, ColumnTrans)
set_line_style (WindowHandle, [1,5])
dev_set_line_width (1)
dev_set_color ('yellow')
dev_display (Contour2)
set_line_style (WindowHandle, [])
dev_set_draw ('margin')
dev_set_color ('green')
dev_set_line_width (3)
gen_circle (Circle, [124,496], [244,239], [15,15])
dev_display (Circle)
Message := 'The mosaic image fits perfectly,'
Message[1] := 'if radial distortions are taken'
Message[2] := 'into account.'
disp_message (WindowHandle, Message, 'image', 200, 300, 'black', 'true')
* 輸出拼接后的圖像
write_image(MosaicImage, 'bmp', 0,'result.bmp')
資料
- Halcon例程和幫助文檔
- 利用halcon進行圖像拼接的基本教程