1. 什么是畸变
- 畸变是指镜头的畸变,分为径向畸变和切向畸变。
- 需要注意的是,我们在这里讨论的是对镜头径向畸变的矫正。
2. 算法矫正镜头畸变的步骤
- 先标定相机内外参:
使用标定助手和圆点标定板标定相机的内外参,保存不同角度的标定板图像大约12张。需要注意的是,这里的标定板图像是有畸变的。 - 求理想内参:
Halcon给我们提供了一个算子change_radial_distortion_cam_par ,它可以帮助我们获得一个没有畸变的内参。
根据指定的径向畸变确定新的摄像机参数。
* 参数1:自适应
* 参数2:填入第1步中得到的内参
* 参数3:径向畸变写0
* 参数4:返回径向畸变为0的内参
change_radial_distortion_cam_par ('adaptive', CameraParameters, 0, CamParamOut)
- 用理想内参矫正图像
- 先求一个Map映射
* 参数1:返回Map映射
* 参数2:有畸变的内参
* 参数3:径向畸变为0的内参
* 参数4:插值算法
gen_radial_distortion_map (Map, CameraParameters, CamParamOut, 'bilinear')
- 然后使用Map映射来矫正有径向畸变的图像(第1步中保存的12张标定板图像),把矫正过的图像保存下来。
map_image (Image, Map, ImageMapped)
- 利用矫正后的图像重新求一次内外参
用第3步中保存的图像重新求内参和外参。 - 利用新的内外参进行测量
3. Halcon代码
进行以下工作还是需要的工具有,相机+镜头+实验架+圆点标定板
以下代码作为参考,理解为主。
*1求出内参
CameraParameters := ['area_scan_division',0.00423375,-23259.8,3.75308e-006,3.75e-006,591.731,469.686,1280,960]
*2求理想内参
change_radial_distortion_cam_par ('adaptive', CameraParameters, 0, CamParamOut)
*3求map映射
list_files ('D:/1', ['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])
gen_radial_distortion_map (Map, CameraParameters, CamParamOut, 'bilinear')
*矫正
map_image (Image, Map, ImageMapped)
write_image (ImageMapped, 'tiff', 0, 'D:/2/'+Index)
endfor
write_cam_par (CamParamOut, 'D:/new.cal')
****用矫正后的图进行测量
read_cam_par ('D:/newrec.cal', CameraParamnew)
read_pose ('D:/newrec.dat', Posenew)
CameraParameters := ['area_scan_division',0.00423375,-23259.8,3.75308e-006,3.75e-006,591.731,469.686,1280,960]
read_pose ('D:/wai1.dat', Pose)
CameraParameters := ['area_scan_division',0.00423375,-23259.8,3.75308e-006,3.75e-006,591.731,469.686,1280,960]
CameraPose := [0.000690838,0.0267898,0.171678,0.13436,2.32878,155.631,0]
open_framegrabber ('DirectShow', 1, 1, 0, 0, 0, 0, 'default', 8, 'rgb', -1, 'false', 'default', '[0] camera1', 0, -1, AcqHandle)
grab_image_start (AcqHandle, -1)
while (true)
grab_image_async (Image, AcqHandle, -1)
* gen_radial_distortion_map (Map, CameraParameters, CamParamOut, 'bilinear')
* map_image (Image, Map, ImageMapped)
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, Regions, 13, 72)
connection (Regions, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 0, 16324.1)
select_shape (SelectedRegions, SelectedRegions1, 'area', 'and', 3152.96, 3848.25)
fill_up (SelectedRegions1, RegionFillUp)
boundary (RegionFillUp, RegionBorder, 'inner')
gen_region_line (ROI_0, 406.148, 611.412, 416.918, 843.709)
intersection (RegionBorder, ROI_0, RegionIntersection)
get_region_points (RegionIntersection, Rows, Columns)
***转成世界坐标
image_points_to_world_plane (CameraParameters, CameraPose, Rows, Columns, 'm', X, Y)
distance_pp (X[0], Y[0], X[1], Y[1], Distance)
scale_image (GrayImage, ImageScaled, 3.35526, -44)
dev_display (ImageScaled)
dev_get_window (WindowHandle)
set_display_font (WindowHandle, 26, 'mono', 'true', 'false')
disp_line (WindowHandle, Rows[0], Columns[0],Rows[1],Columns[1])
disp_message (WindowHandle, '距离'+Distance*1000+'mm', 'image', 481, 657, 'black', 'true')
endwhile
close_framegrabber (AcqHandle)