因爱智能

halcon之屌炸天的变形匹配(1)

在日常工程应用中,我们通常通过halcon的 shape-based matching(形状匹配)进行各种定位,

如以前文章介绍的这样,理解各个参数并灵活应用通常就能得到很好的匹配效果和匹配速度,

当待匹配物体有轻微变形时,并不影响得到的匹配结果,然后当待匹配物体有较大变形时,如

塑料产品在成形时变形、纺织产品的花纹因为褶皱变形等,要想得到精确的定位结果就显得捉襟见肘,

 

如下图所示,印刷品有较大变形,在用shape-based matching时,定位结果就不尽如人意,因为

shape-based matching本身得到的匹配结果只是一个点(row,col),我们根据匹配结果通过仿射变换

将模板转换到匹配位置时就这个熊样。

 

怎么办?怎么办?如果有一种匹配模式,匹配结果可以根据待匹配物体自动进行变形多好!

如下图所示,简直完美,有木有?有木有!这就是我们今天要介绍的local deformable matching (局部变形匹配)

 

 

 

local deformable matching的基本流程和 shape-based matching相似:

所以在此之前闭上眼睛好好感受一下, shape-based matching掌握的怎么样,要不要回顾一下历史文章,相似参数不做介绍。

 

(1)create_local_deformable_model 创建变形模板

ScaleMin、ScaleMax、ScaleStep:

指定行列最小最大变形尺度例(0.9,1.1,0.01)用于指定相对于原图的变形范围

 

(2)find_local_deformable_model 匹配

ImageRectified :

匹配到的变形后模板图像

VectorField: 

变形矢量区,里面存储了匹配区域每个点变形后的位置,之所以叫vector是因为每个点为存储了行列坐标(x,y),动态图中的网格就是以此算出的.

返回的区域大小是创建模板时domain的最小外界矩形大小,当然你可以通过ParamName参数中的expand_border扩展区域等到更大的区域。

DeformedContours:

匹配到的轮廓,非模板轮廓而是经过变形得出的轮廓,动态图中的绿色轮廓即是此

ResultType:'deformed_contours', 'image_rectified', 'vector_field'可指定需要得出的结果分别对应ImageRectified VectorFiedl DeformedContours,

ParamName:

deformation_smoothness:平滑的度,对于变形越大参数越大

expand_border:扩展ImageRecfified VectorField 区域

 

附注:生成变形网格的函数,此函数隔10个像素取值

复制代码

gen_warped_mesh (VectorField, WarpedMesh, 10) gen_empty_obj (WarpedMesh) count_obj (VectorField, Number) for Index := 1 to Number by 1 select_obj (VectorField, ObjectSelected, Index) *把vector转换成存储行坐标和列坐标图像 vector_field_to_real (ObjectSelected, DRow, DCol) get_image_size (VectorField, Width, Height) *取行坐标 for ContR := 0.5 to Height[0] - 1 by Step Col1 := [0.5:Width[0] - 1] tuple_gen_const (Width[0] - 1, ContR, Row1) get_grayval_interpolated (DRow, Row1, Col1, 'bilinear', GrayRow) get_grayval_interpolated (DCol, Row1, Col1, 'bilinear', GrayCol) gen_contour_polygon_xld (Contour, GrayRow, GrayCol) concat_obj (WarpedMesh, Contour, WarpedMesh) endfor *取列坐标 for ContC := 0.5 to Width[0] - 1 by Step Row1 := [0.5:Height[0] - 1] tuple_gen_const (Height[0] - 1, ContC, Col1) get_grayval_interpolated (DRow, Row1, Col1, 'bilinear', GrayRow) get_grayval_interpolated (DCol, Row1, Col1, 'bilinear', GrayCol) gen_contour_polygon_xld (Contour, GrayRow, GrayCol) concat_obj (WarpedMesh, Contour, WarpedMesh) endfor endfor return ()

复制代码

 

 

总结:一句话形容halcon的局部变形匹配功能,那就是“屌炸天”,本人也在多个项目中应用取得了极其好的效果。

然而本片文章只是浅尝辄止,更深层次的应用还需要各位看官动手实践,夜深了~窗外下着雨,各位晚安。

halcon之扫描文档祛底色增

本来想通过扫描后打印,想法是好的,但是打印出来的文件不是自己想象的那样,打印出来有底色,

而且很严重,那该怎么办才能解决?

 

熟悉photoshop的通常通过色阶调整来达到此目的,但是今天介绍的是用halcon灰度拉伸函数(scale_image)

来达到此目的。下图是halcon祛底色的效果。

 

 

 

在halcon的可视化工具-灰度直方图中可以找到,例如此图将(0,130)拉伸到(0,255)

 

代码实现

1

2

3

4

5

6

7

8

read_image (Image, 'test.png')

 

gmin:=0

gmax:=130

multi:=255.0/(gmax-gmin)

add:=-multi * gmin

 

scale_image (Image,ImageScale, multi, add)

halcon中你不知道的标定板细节

本人文着重阐述以下问题:

 

  • halcon是否只能使用halcon专用的标定板?
  • halcon标定板如何生成?
  • halcon标定板如何摆放,拍照数量有无限制?

 

halcon是否只能使用halcon专用的标定板?

 

halcon提供了简便、精准的标定算子并且提供了标定助手,这无疑大大方便了广大开发者。

在halcon中有两种方式可以进行标定:

  • 如halcon自带例程中出现的,用halcon定义的标定板  ,如下图

  • 用户自定义标定板,用户可以制作任何形状、形式的标定板

 

 

 

所以,halcon并非只能使用专用标定板,也可以使用自定义标定板就行标定。

 

使用halcon定义标定板的优势是可以使用halcon的标定板提取算子,提取标记点,而当使用自己定义的标定板格式则需要自己完成此部分工作。

 

halcon标定板如何生成?

 

 

  1. gen_caltab(::XNum,YNum,MarkDist,DiameterRatio,CalTabDescrFile,CalTabPSFile :) 算子来制作一个标定板 XNum 每行黑色标志圆点的数量。 YNum 每列黑色标志圆点的数量。 MarkDist 两个就近黑色圆点中心之间的距离。单位是meter DiameterRatio 黑色圆点直径与两圆点中心距离的比值。 CalTabDescrFile 标定板描述文件的文件路径(.descr)。这两个文件路径是用来存放文件的 CalTabPSFile 标定板图像文件的文件路径(.ps),

其中,.descr文件为标定板描述文件,.ps文件为标定板图形文件,可以用photoshop(PS)打开

 

一个30*30的标准标定板的示例

  1. 1 gen_caltab(7,7,0.00375,0.5,'E:/halcon/30_30.descr','E:/halcon/30_30.ps') 2 黑色圆点行数: 7 3 黑色圆点列数: 7 4 外边框长度: 30mm*30mm 5 黑色圆点半径: 0.9375mm (3.75/4) 6 圆点中心间距: 3.75mm

     

 

halcon标定板如何摆放,拍照数量有无限制?

 

  • 值得注意的是,并非标定数量越多,越能取得高的精度,halcon建议拍摄数量在9-16张,并且对摆放位置做了建议,如下图所示
  • 标定板充满标定视野的1/3-1/4,对于标定板成像灰度值亮度应大于128,以便halcon算子能较顺利的提取到标定板

 

 

 

  •   使用halcon标定板的精度如下图所示

   

Halcon学习(二十)摄像机标定常用函数(一)

在HALCON所有算子中,变量皆是如上格式,即:图像输入:图像输出:控制输入:控制输出,其中四个参数任意一个可以为空。控制输入量可以是变量、常量、表达式,控制输出以及图像输入和输入必须是变量,以存入算子计算结果中。

1.caltab_points:从标定板中读取marks中心坐标,该坐标值是标定板坐标系统里的坐标值,该坐标系统以标定板为参照,向右为X正,下为Y正,垂直标定板向下为Z正。该算子控制输出为标定板中心3D坐标。

2.create_calib_data:创建Halcon标定数据模型。输出一个输出数据模型句柄。

3.set_calib_data_cam_param:设定相机标定数据模型中设置相机参数的原始值和类型。设置索引,类型,以及相机的原始内参数等。

4.set_calib_data_calib_object:在标定模型中设定标定对象。设定标定对象句柄索引,标定板坐标点储存地址。

5.find_caltab:分割出图像中的标准标定板区域。输出为标准的标定区域,控制

6.find_marks_and_pose:抽取标定点并计算相机的内参数。输出MARKS坐标数组,以及估算的相机外参数。

即标定板在相机坐标系中的位姿,由3个平移量和3个旋转量构成。

7.set_calib_data_observ_points( : : CalibDataIDCameraIdxCalibObjIdx,CalibObjPoseIdxRowColumnIndexPose : )

收集算子6的标定数据,将标定数据储存在标定数据模型中。输入控制分别为标定数据模型句柄,相机索引,标定板索引,位姿索引,行列坐标,位姿。

8.calibrate_cameras( : : CalibDataID : Error) 标定一台或多台相机,依据CalibDataID中的数据。控制输出平均误差。

9.get_calib_data( : : CalibDataIDItemTypeItemIdxDataName : DataValue) 获得标定数据。

依靠索引号和数据名称来返回输出的数据值。可查询与模型相关的数据,与相机相关的数据(包括相机的内外参数等),与标定对象相关的数据,与标定对象的姿态相关的数据。控制输出是要查询的标定数据。

如:get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam) //查询相机的位姿

get_calib_data (CalibDataID, 'calib_obj_pose', [0, NumImage], 'pose', Pose) //查询标定板位姿

10.write_cam_par( : : CameraParamCamParFile : ) 记录相机的内参数,输入控制为内参数,输出控制为

存取相机内参数的文件名。

11.set_origin_pose( : : PoseInDXDYDZ : PoseNewOrigin)

设置新的坐标原点,控制输入为原始的位姿和沿着世界坐标系的三个坐标轴的平移量,控制输出为新的位姿。

Halcon学习(十九)标定文件的生成

Halcon标定文件的生成,需要有以下几个步骤:

1.创建一个标定数据模板,由create_calib_data算来完成。

2.指定相机的类型,初始化相机内部参数,由set_calib_data_cam_param算子来完成。

3.指定标定板的描述文件,由set_calib_data_calib_object算子完成。

4.收集观察数据,有算子set_calib_data_observ_points完成。也就是收集标定板上圆点的中心坐标,跟各个校正板的位置姿态。

5.配置校正过程。由算子set_calib_data完成。

6.将数据整合进行标定计算。calibrate_cameras

7.获得标定参数。get_calib_data

8.记录标定参数,write_cam_par

StartCamPar := [0.016,   0,    0.0000074,    0.0000074,   326,   247,    652,    494]

解释一下这个数组的意思。

面阵相机有14或18个参数(根据想相机的畸变模式),对于线阵相机有17个参数。这些参数可以分开为内部相机参数、外部相机参数。

面阵相机(division模式)

Focus(焦距):远焦镜头镜头焦距的长度

Kappa:扭曲系数

Sx,Sy:两像素间距

Cx,Cy:中心点坐标

Whith,Height:图像的宽高

面阵相机(polynomia模式):

Focus(焦距):远焦镜头镜头焦距的长度

K1, K2, K3, P1,P2:扭曲系数

Sx,Sy:两像素间距

Cx,Cy:中心点坐标

Whith,Height:图像的宽高

线阵相机不做具体介绍

Halcon学习(二十一)摄像机标定常用函数(二)

1.read_cam_par( : : CamParFile : CameraParam)

从文件夹中读取相机的内参数。

2.disp_caltab( : : WindowHandleCalTabDescrFileCameraParamCaltabPoseScaleFac : )

利用相机内外参数,把标定板模型投影到图像平面,显示标定点和连接线,X,Y轴也被显示出来。

3.vector_to_pose( : : WorldXWorldYWorldZImageRowImageColumnCameraParam,MethodQualityType : PoseQuality)

计算世界坐标和图像坐标之间关系的绝对位姿参数。其中世界坐标至少选择不在同一条直线上的三个点。

世界坐标上的点如果在一个平面上,应该选择'planar_analytic' 作为Method的参数。输出位姿和位姿质量。

4.write_pose( : : PosePoseFile : )

把位姿写入TXT文件。

5.get_mbutton( : : WindowHandle : RowColumnButton)

返回鼠标点击的图像点像素坐标,以及鼠标按钮值,左键0,中间键2,右键4.

6.image_points_to_world_plane( : : CameraParamWorldPoseRowsColsScale : X,Y)

把图像坐标转化成Z=0平面的世界坐标,输出为世界坐标的X,Y

7.pose_to_hom_mat3d( : : Pose : HomMat3D)

把3D位姿转化成齐次变换矩阵。

8.affine_trans_point_3d( : : HomMat3DPxPyPz : QxQyQz)

进行两个坐标系之间的3D坐标的仿射变换。

       / Qx \             / Px \

| Qy | = HomMat3D * | Py | | Qz | | Pz | \ 1 / \ 1 / 9.project_3d_point( : :  XYZCameraParam :  RowColumn) 把3D点映射到图像坐标系,返回图像坐标系中该点的行列坐标。  

10.smallest_rectangle2(Regions : : : RowColumnPhiLength1Length2)

返回包含一个区域的最小环绕矩形。

11.gen_measure_rectangle2( : : RowColumnPhiLength1Length2WidthHeight,Interpolation : MeasureHandle)

返回和矩形边垂直的边缘。

12.measure_pairs(Image : : MeasureHandleSigmaThresholdTransitionSelect :RowEdgeFirstColumnEdgeFirstAmplitudeFirstRowEdgeSecondColumnEdgeSecond,AmplitudeSecondIntraDistanceInterDistance)

抽取和矩形边垂直的边缘对。返回各测量对之间的距离。

13.close_measure( : : MeasureHandle : )

删除测量句柄。

14.gen_region_polygon_filled( : Region : RowsColumns : )

创建多边形填充区域,输出为一个区域。

15.gen_region_polygon_filled( : Region : RowsColumns : )

提取直线极其宽度,输出为XLD形式数组。

16.hom_mat3d_compose( : : HomMat3DLeftHomMat3DRight : HomMat3DCompose)

输出两个齐次矩阵的乘积。

17.hom_mat3d_translate_local( : : HomMat3DTxTyTz : HomMat3DTranslate)

相对于新坐标系统,增加一个平移量到齐次矩阵HomMat3D中,输出为新的齐次矩阵。

18.hom_mat3d_rotate_local( : : HomMat3DPhiAxis : HomMat3DRotate)

相对于新坐标系统,增加一个绕着某个坐标轴的旋量到齐次矩阵HomMat3D中,输出为新的齐次矩阵。

17.contour_to_world_plane_xld(Contours : ContoursTrans : CameraParamWorldPose,Scale : )

转换XLD轮廓进入Z=0的世界坐标平面,输出形式为xld_cont(-array) → object

18.get_contour_xld(Contour : : : RowCol)

返回轮廓点的行列坐标。

19.tuple_mean( : : Tuple : Mean)

返回数组的平均值

20.map_image(ImageMap : ImageMapped : : )

对图像进行校正,输出为校正后的图像。

附:摄像机校正和利用校正后的结果进行测量以及图像校正的程序段

 

* Attention:
* This program reads the interior camera parameters from the file
* 'camera_parameters.dat', which, e.g., could be generated by the program
* 'camera_calibration_interior.hdev'
*
ImgPath := '3d_machine_vision/calib/'
dev_close_window ()
dev_open_window (0, 0, 652, 494, 'black', WindowHandle)
dev_update_off ()
dev_set_draw ('margin')
dev_set_line_width (1)
set_display_font (WindowHandle, 14, 'courier', 'true', 'false')
* Read the interior camera parameters from file
read_cam_par ('camera_parameters.dat', CamParam)
*
* Determine the exterior camera parameters and world coodinates from image points
*
* The exterior camera parameters can be determined from an image, where the
* calibration plate is positioned directly on the measurement plane
read_image (Image, ImgPath+'calib_11')
dev_display (Image)
* parameter settings for find_caltab and find_marks_and_pose
SizeGauss := 3
MarkThresh := 200
MinDiamMarks := 10
StartThresh := 128
DeltaThresh := 10
MinThresh := 18
Alpha := 0.9
MinContLength := 15
MaxDiamMarks := 100
CaltabName := 'caltab_30mm.descr'
find_caltab (Image, Caltab, CaltabName, SizeGauss, MarkThresh, MinDiamMarks)
dev_set_color ('green')
dev_display (Caltab)
* Here, the final camera parameters are already known and can be used instead of the starting values
* used in the program 'camera_calibration_interior.hdev'
find_marks_and_pose (Image, Caltab, CaltabName, CamParam, StartThresh, DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks, RCoord, CCoord, PoseForCalibrationPlate)
dev_set_color ('red')
disp_caltab (WindowHandle, CaltabName, CamParam, PoseForCalibrationPlate, 1)
dev_set_line_width (3)
disp_circle (WindowHandle, RCoord, CCoord, gen_tuple_const(|RCoord|,1.5))
* caltab_points (CaltabName, X, Y, Z)
* camera_calibration (X, Y, Z, RCoord, CCoord, CamParam, InitialPoseForCalibrationPlate, 'pose', CamParamUnchanged, FinalPoseFromCalibrationPlate, Errors)
* To take the thickness of the calibration plate into account, the z-value
* of the origin given by the camera pose has to be translated by the
* thickness of the calibration plate.
* Deactivate the following line if you do not want to add the correction.
set_origin_pose (PoseForCalibrationPlate, 0, 0, 0.00075, PoseForCalibrationPlate)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* Alternatively, the exterior camera parameters can  be determined from
* at least three point correspondances between the WCS and the pixel coordinate system
read_image (Image, ImgPath+'caliper_01')
dev_display (Image)
* Set the world coordinates of three points on the rule
X := [0,50,100,80]
Y := [5,0,5,0]
Z := [0,0,0,0]
* Set the respective image plane coordinates of the three points
RCoord := [414,227,85,128]
CCoord := [119,318,550,448]
*
disp_cross (WindowHandle, RCoord, CCoord, 6, 0)
* create_pose (-50, 25, 400, 0, 0, -30, 'Rp+T', 'gba', 'point', InitialPose)
vector_to_pose (X, Y, Z, RCoord, CCoord, CamParam, 'iterative', 'error', FinalPose, Errors)
* camera_calibration (X, Y, Z, RCoord, CCoord, CamParam, InitialPose, 'pose', CamParamUnchanged, FinalPose, Errors)
write_pose (FinalPose, 'pose_from_three_points.dat')
* Now, transform a point measured interactively into the WCS
dev_update_window ('on')
dev_display (Image)
while (1)
    disp_message (WindowHandle, 'Measure one point: left mouse button', 'window', 12, 12, 'red', 'false')
    disp_message (WindowHandle, 'Exit measure mode: right mouse button', 'window', 36, 12, 'red', 'false')
    get_mbutton (WindowHandle, Row, Column, Button)
    if (Button = 4)
        break
    endif
    dev_display (Image)
    dev_set_color ('green')
    disp_cross (WindowHandle, Row, Column, 6, 0)
    image_points_to_world_plane (CamParam, FinalPose, Row, Column, 1, X1, Y1)
    disp_message (WindowHandle, 'X = '+X1, 'window', 320, 400, 'red', 'false')
    disp_message (WindowHandle, 'Y = '+Y1, 'window', 340, 400, 'red', 'false')
endwhile
* Apply the measure tool and transform the resulting point coordinates
* into the WCS
dev_set_color ('red')
dev_display (Image)
* Set the world coordinates of four points defining a ROI for the measure tool
ROI_X_WCS := [-2,-2,112,112]
ROI_Y_WCS := [0,0.5,0.5,0]
ROI_Z_WCS := [0,0,0,0]
* Determine the transformation matrix from the WCS into the CCS
pose_to_hom_mat3d (FinalPose, CCS_HomMat_WCS)
* Transform the point coordintes into the image coordinate system
affine_trans_point_3d (CCS_HomMat_WCS, ROI_X_WCS, ROI_Y_WCS, ROI_Z_WCS, CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ)
project_3d_point (CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ, CamParam, RectangleRow, RectangleCol)
gen_region_polygon_filled (ROI, RectangleRow, RectangleCol)
smallest_rectangle2 (ROI, RowCenterROI, ColCenterROI, PhiROI, Length1ROI, Length2ROI)
* Create a measure
gen_measure_rectangle2 (RowCenterROI, ColCenterROI, PhiROI, Length1ROI, Length2ROI, 652, 494, 'bilinear', MeasureHandle)
measure_pairs (Image, MeasureHandle, 0.4, 5, 'all_strongest', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
close_measure (MeasureHandle)
dev_display (Image)
disp_message (WindowHandle, 'Measuring the position of the pitch lines', 'window', 450, 25, 'red', 'false')
dev_set_color ('green')
RowPitchLine := (RowEdgeFirst+RowEdgeSecond)/2.0
ColPitchLine := (ColumnEdgeFirst+ColumnEdgeSecond)/2.0
disp_cross (WindowHandle, RowPitchLine, ColPitchLine, 6, 0)
image_points_to_world_plane (CamParam, FinalPose, RowPitchLine, ColPitchLine, 1, X1, Y1)
for i := 1 to |X1| by 1
    set_tposition (WindowHandle, RowEdgeFirst[i-1]+5, ColumnEdgeFirst[i-1]-20)
    if (i=|X1|)
        set_tposition (WindowHandle, RowEdgeFirst[i-1], ColumnEdgeFirst[i-2])
    endif
    write_string (WindowHandle, X1[i-1]$'.3f'+'mm')
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_display (Image)
* Apply a line extraction and transform the resulting xld contours
* into the WCS
* Set the world coordinates of four points defining a ROI
ROI_X_WCS := [11,11,13,13]
ROI_Y_WCS := [4,6,6,4]
ROI_Z_WCS := [0,0,0,0]
* Transform the point coordinates into the image coordinate system
affine_trans_point_3d (CCS_HomMat_WCS, ROI_X_WCS, ROI_Y_WCS, ROI_Z_WCS, CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ)
project_3d_point (CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ, CamParam, RectangleRow, RectangleCol)
* Visualize the square in the original image
disp_polygon (WindowHandle, [RectangleRow,RectangleRow[0]], [RectangleCol,RectangleCol[0]])
dev_display (Image)
* create the ROI
gen_region_polygon_filled (ROI, RectangleRow, RectangleCol)
reduce_domain (Image, ROI, ImageReduced)
* Extract the lines
lines_gauss (ImageReduced, Lines, 1, 3, 8, 'dark', 'true', 'bar-shaped', 'true')
* Adapt the pose of the measurement plane to the tilted plane of the vernier
RelPose := [0,3.2,0,-14,0,0,0]
pose_to_hom_mat3d (FinalPose, HomMat3D)
pose_to_hom_mat3d (RelPose, HomMat3DRel)
hom_mat3d_compose (HomMat3D, HomMat3DRel, HomMat3DAdapted)
* Alternatively, the adaption can be done using the operators
* hom_mat3d_translate_local and hom_mat3d_rotate_local
* as shown in the following to lines
hom_mat3d_translate_local (HomMat3D, 0, 3.2, 0, HomMat3DTranslate)
hom_mat3d_rotate_local (HomMat3DTranslate, rad(-14), 'x', HomMat3DAdapted)
hom_mat3d_to_pose (HomMat3DAdapted, PoseAdapted)
* Transform the xld contour to the WCS using the adapted pose
contour_to_world_plane_xld (Lines, ContoursTrans, CamParam, PoseAdapted, 1)
get_contour_xld (ContoursTrans, YOfContour, XOfContour)
tuple_mean (XOfContour, MeterReading)
dev_display (Lines)
disp_message (WindowHandle, 'Meter reading: '+MeterReading$'.3f'+'mm', 'window', 400, 180, 'green', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_close_inspect_ctrl (YOfContour)
dev_close_inspect_ctrl (XOfContour)
* Now, transform the whole image
WidthMappedImage := 652
HeightMappedImage := 494
dev_display (Image)
* First, determine the scale for the mapping
* (here, the scale is determined such that in the
*   surroundings of the points P0 and P1,  the image scale of the
*   mapped image is similar to the image scale of the original image)
distance_pp (X[0], Y[0], X[1], Y[1], DistP0P1WCS)
distance_pp (RCoord[0], CCoord[0], RCoord[1], CCoord[1], DistP0P1PCS)
Scale := DistP0P1WCS/DistP0P1PCS
* Then, determine the parameter settings for set_origin_pose such
* that the point given via get_mbutton will be in the center of the
* mapped image
dev_display (Image)
disp_message (WindowHandle, 'Define the center of the mapped image', 'window', 12, 12, 'red', 'false')
get_mbutton (WindowHandle, CenterRow, CenterColumn, Button1)
image_points_to_world_plane (CamParam, FinalPose, CenterRow, CenterColumn, 1, CenterX, CenterY)
set_origin_pose (FinalPose, CenterX-Scale*WidthMappedImage/2.0, CenterY-Scale*HeightMappedImage/2.0, 0, PoseNewOrigin)
gen_image_to_world_plane_map (Map, CamParam, PoseNewOrigin, 652, 494, WidthMappedImage, HeightMappedImage, Scale, 'bilinear')
map_image (Image, Map, ImageMapped)
dev_clear_window ()
dev_display (ImageMapped)
* In case, only one image has to be mapped, the operator
* image_to_world_plane can be used instead of the operators
* gen_image_to_world_plane_map together with map_image.
image_to_world_plane (Image, ImageMapped, CamParam, PoseNewOrigin, WidthMappedImage, HeightMappedImage, Scale, 'bilinear')

Halcon学习(二十二)摄像机标定(函数详解)

摄像机标定程序:

注意:E:/calibration_image :为标定图像文件路径

      'E:/calibration_description/caltab_123mm.descr:为标定描述文件路径


*作者:骑蚂蚁上高速

*程序开始

list_files ('E:/calibration_image', 'files', ImageFiles)

TmpCtrl_AllMarkRows := []

TmpCtrl_AllMarkColumns := []

TmpCtrl_StartPoses := []

TmpCtrl_ReferenceIndex := 0

StartParameters := [0.008,0,5.2e-006,5.2e-006,640,512,1280,1024]

for Index := 0 to |ImageFiles|-1 by 1

    read_image (Image, ImageFiles[Index])

    find_caltab (Image, TmpObj_PlateRegion, 'E:/calibration_description/caltab_123mm.descr', 3, 112, 5)

    find_marks_and_pose (Image, TmpObj_PlateRegion, 'E:/calibration_description/caltab_123mm.descr', StartParameters, 128, 10, 18, 0.9, 15, 100, TmpCtrl_MarkRows, TmpCtrl_MarkColumns, TmpCtrl_EstimatedPose)

    TmpCtrl_AllMarkRows := [TmpCtrl_AllMarkRows, TmpCtrl_MarkRows]

    TmpCtrl_AllMarkColumns := [TmpCtrl_AllMarkColumns, TmpCtrl_MarkColumns]

    TmpCtrl_StartPoses := [TmpCtrl_StartPoses, TmpCtrl_EstimatedPose]

endfor

caltab_points ('E:/calibration_description/caltab_123mm.descr', TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z)

camera_calibration (TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z, TmpCtrl_AllMarkRows, TmpCtrl_AllMarkColumns, StartParameters, TmpCtrl_StartPoses, 'all', CameraParameters, TmpCtrl_FinalPoses, TmpCtrl_Errors)

tuple_select_range (TmpCtrl_FinalPoses, 7*TmpCtrl_ReferenceIndex, 7*TmpCtrl_ReferenceIndex + 6, CameraPose)

set_origin_pose (CameraPose, 0.0, 0.0, 0.001, CameraPose)

stop ()


一、读入图像,函数如下

list_files ('E:/calibration_image', 'files', ImageFiles)

for Index := 0 to |ImageFiles|-1 by 1

    read_image(Image, ImageFiles[Index])

endfor

注释:'E:/calibration_image':为图像路径,图像文件索引是从0开始的,所以|ImageFiles|(文件数量)减去1。

算子:read_image(:Image :FileName):读取名称为FileName的图像Image。

二、提取图像Images中标定板上的圆形标志来确定标定板的有效区域,算子如下:

find_caltab(Image:Caltab:CalTabDescrFile,SizeGauss,MarkThresh,MinDiamMarks:)

    

确定标定板上圆形标志点的二维坐标,并得到摄像机外部参数的初始值,算子如下:

find_marks_and_pose (Image,CalTabRegion: :CalTabDescrFile ,StartCamParam ,StartThresh,                            DeltaThresh,MinThresh,Alpha,MinContLength,MaxDiamMarks:Rcoord,Ccoord,                        StartPose)

   

注释函数find_caltab在图像中寻找标定板是基于标定板的特征——在一个亮的区域中存在黑色标定点。首先使用高斯滤波器进行图像平滑。参数SizeGauss确定高斯滤波器的尺寸。SizeGauss值越大进行图像平滑的幅度就越大,这在图像噪声比较大时是必要的。在进行图像平滑操作后,为了寻找标定板的位置,我们进行一个阈值分割,可以参考灰度直方图,灰度值范围由最小值MarkThresh到最大值255,因此,MarkThresh必须小于标定板上白色区域的灰度值,并且最好大于图像中其他大范围较亮的区域的灰度值。在阈值分割得到的多个区域中,其中包含孔的数量最符合标定板上标定点数量的凸状区域被选中。为了减少噪声影响,直径小于MinDiamMarks的孔将被除去。标志点的数量可以从标定板描述文件(CalTabDescrFile)中读出。

    函数find_marks_and_pose提取标定板上各个标志点,并精确得到它们在图像坐标系中的坐标。上面我们已经通过函数find_caltab找到了标定板的区域,这时我们首先在输入图像Image的这个区域(CalTabRegion)中应用边缘检测。这个边缘检测通过参数Alpha进行控制。Alpha的值越大 ,边缘检测的灵敏度也就越高,这将使边缘检测时找到更多的细节,但同时对噪声的抑制能力下降。在边缘图像中,提取出封闭的轮廓线。为了更准确的寻找轮廓线,对边缘的振幅进行一个阀值操作。所有振幅高的点(标定点的边界)都被选中。首先,这个阀值设置为StartTh

resh。如果寻找封闭轮廓线或估计位姿失败,这个阀值接连地减DeltaThresh 直到阀值降低到最小值MinThresh。

    闭合的轮廓线的数量必须与标定板描述文件(CalTabDescrFile)中描述的标志点的数量一致,并且这些闭合轮廓线的形状必须是椭圆状的。长度比MinContLength 短的轮廓线或者轮廓线形成区域的直径大MaxDiamMarks(如标定板的外框)的,这些轮廓线将被忽略抛弃。


三、保存坐标值


TmpCtrl_AllMarkRows := []

TmpCtrl_AllMarkColumns := []

TmpCtrl_StartPoses := []


TmpCtrl_AllMarkRows := [TmpCtrl_AllMarkRows, TmpCtrl_MarkRows]

TmpCtrl_AllMarkColumns := [TmpCtrl_AllMarkColumns, TmpCtrl_MarkColumns]

TmpCtrl_StartPoses := [TmpCtrl_StartPoses, TmpCtrl_EstimatedPose]


注释:标定点的在图像坐标系中的坐标存储 

在两个数组中,第一个数组存储所有点的行

 

坐标,第二个数组存储所有点的列坐标,并

 

且要保证两个数组的值一一对应。这些数组

 

的长度取决于标定板上标定点的个数以及

 

拍摄的标定图像的数量。它们的存储顺序是 

按照图像顺序排列的,也就是说刚开始的m

 

个值存储的是第一幅图像中m个标定点的

 

坐标值,这个顺序和函数caltab_points返回

 

的数组X,Y,Z中的存储顺序是一致的。


四、摄像机标定输入参数

StartParameters := [0.008,0,5.2e-006,5.2e-006,640,512,1280,1024]

    初始值摄像机标定是一个非常复杂的非线性优化的问题,因此就需要为摄像机的参数提供尽量精确的初始值。摄像机内部参数的初始值主要由CCD传感器和镜头的说明书确定。面阵摄像机的内参初始值可以输入一个

数 组 [f,k,Sx,Sy,Cx,Cy,NumColumns,NumRows]也就是说 ,不仅要提供摄像机的初始内参,还要提供图像的宽(NumColumns)和高(NumRows)。

  

五、确定摄像机的内参,误差分析,算子如下

camera_calibration(: :NX,NY,NZ,Nrow,Ncol,StartCamParam,                                                        NstartPose,EstimateParams:CamParam,NfinalPose,Errors)

函数如下:

caltab_points ('E:/calibration_description/caltab_123mm.descr', TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z)

camera_calibration (TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z, TmpCtrl_AllMarkRows, TmpCtrl_AllMarkColumns,                     StartParameters, TmpCtrl_StartPoses, 'all', CameraParameters,                                     TmpCtrl_FinalPoses, TmpCtrl_Errors)

    

    在给定了摄像机的内外参数的初始值之后,已知三维位置的标定点可以转换到摄像机坐标系中。然后,寻求一组摄像机的参数可以使通过计算投影到图像上的标定点坐标和直接从图像中提取出的标定点的坐标的距离最小。这个最小化的过程将返回相当精确的摄像机参数。然而,为了获得最高精度的摄像机参数,需要拍摄标定板的多幅图像,在拍摄时,标定板被放置在图像的不同位置并且旋转的角度也不同,以致于使用外部方位的所有自由度。如果拍摄一幅包含标定板的图像,最优化的参数包括摄像机的内参和一组外参。此时,最优化的目标是确定所有这些参数能够满足每幅图中通过投影计算得到的点坐标和图像中直接提取的坐标值距离最小。在HALCON中 ,使用 camera_calibration 函数就是实现这个功能。

 

六、选择某幅图像作为参考位姿,确定摄像机外参

TmpCtrl_ReferenceIndex := 0

注释:TmpCtrl_ReferenceIndex:为将要设置为参考位姿势的图像。0代表第一张。1代表第二张。以此类推。

tuple_select_range (TmpCtrl_FinalPoses, 7*TmpCtrl_ReferenceIndex, 7*TmpCtrl_ReferenceIndex + 6, CameraPose)

set_origin_pose (CameraPose, 0.0, 0.0, 0.001, CameraPose)

注释:tuple_select_range:进行数组选择。

      set_origin_pose   :计算摄像机外部参数。


halcon学习笔记——(11)Image,region,xld初步

一 读取的3种方式:

read_image( image,'filename') //image 是输出对象,后面是输入文件的路径和名称

读取多图: 
1,申明一个数组,分别保存路径

ImagePath:=[] ImagePath[0]:='D:/1.bmp' ImagePath[1]:='D:/2.bmp' ImagePath[2]:='D:/3.bmp' for i:=0 to 2 by 1 read_image(Image,ImagePath[i]) endfor

2,for 循环  
  

for i:=1 to 3 by 1 read_image(Image,'D:/’+'i'+'.bmp') endfor

3, 读取目录下所有文件 
助手,打开图像,选择路径,插入代码

list_files(输入文件目录地址,选取的要求(files指定选取文件格式,recursive递归,深入所有,derectories选取文件夹,follow_links,max_depth 5...),输出的被选择的文件列表)

选择符合规则的tuple,其中\\.是转义符,等价于'-->' 
tuple_regexp_select(文件名字,['\\.(bmp|tif)$','ignore_case忽略大小写'],输出) 
fabric文件路径 
  
二 图像变量Region 
预处理:

消除噪声 mean_image/ binomial_filter 抑制小斑点或者细线 median_image 平滑 smooth_image 保存边缘的平滑 anisotropic_diffusion

 

变量Region: 
Region 为某些附和要求性质的像素的子集,或者说一些被选择的图块区域s,region大小不受图像限制,有fill和margin两种表达方式,类似于游程编码,可用于压缩,eg:用a2b3c4代表aabbbcccc

region操作: 
选择相应区域

select_shape(regions,output,'select type',..requirements)

计算相应区域的面积,中心坐标:

area_center(regions,area,row,column)

不规则区域的转换:

shape_trans(region,regiontrans,type)

image

convex hull凸包围(由外向内包围)

outer_circle 外圆(能够包括对象的半径最小的圆形)

inner_circle 内圆

rectangle1 正矩形

rectangle2 最小包围矩形

inner_rectangle1 最大内矩形

三 图型变量XLD(eXtended Line Descriptions)

XLD代表亚像素级别的轮廓或者多边形

threshold_sub_pix(inputimage, output,requirement)   gen_contour_region_xld(inputRegion,output,...)

XLD的选择操作(select_shape_xld/selet_contours_xld):

select_shape_xld(XLD:SelectedXLD:Features,Operation,Min,Max:)   select_contours_xld(Contours:SelectedContours:Feature,Min1,Max1,Min2,Max2:)

计算xld的面积以及中心位置:

area_center_xld(XLD:::Area,row,column,pointOrder)

xld的合并操作:

union_colliner_contours_xld: 合并同一直线的xld   union_cocircular_contours_xld: 合并同圆的xld   union_adjacent_contours_xld: 合并相邻的xld

xld的转换操作与region类似:

shape_trans_xld(XLD:XLDTrans:Type:)

有上面几个类型

Xld的分割操作(segment_contours_xld)

把初始xld分割成直线,直线和圆,直线和椭圆

segment_contours_xld(Contours: ContoursSplit: Mode,SmoothCont, MaxLineDist1, MaxLineDist2:)

image

Xld 的拟合操作(fit_***_contour_xld)  把不完整的形状拟合完整

fit_line_contour_xld   fit_circle_contour_xld   fit_ellipse_contour_xld   fit_rectangle2_contour_xld

总结:

图像和视频,文件的读取

Region和XLD的初步介绍

注意:

在使用edges_sub_pix提取出来的结果,往往不是完整的圆形,需要用union来整合出完整的圆形。

 

原文来自:Burning_foot的博客

作者:韩兆新

出处:http://hanzhaoxin.cnblogs.com/

halcon学习笔记——(12)图像分割

一,基本的图像通道知识不予介绍 
二,单通道图像分割 
1阈值分割 
全局阈值,局部阈值法,直方图自动阈值(自适应阈值)

指定全局阈值

threshold( Image: Region: MinGray, MaxGray) //人工设置阈值

局部阈值法,后面再加以描述

直方图自动阈值(自适应阈值)

auto_threshold( Image: Region:Sigma:)

//自动阈值输入必须是是单通道图像,会有多阈值分割,Sigma用于对灰度直方图进行高斯平滑,决定了平滑的程度(分割细致程度),当sigma很大时,灰度直方图基本会被平滑为只剩下一个波峰,而分割是根据平滑后直方图的波谷来进行的,Sigma小,分割的越细致。

image

三,彩色图像的分割

decompose3 trans_from_rgb(red,green,blue,result1,result2,result3,colortypespace)

四,整理常用的提取简单结果的函数

使用感兴趣区域(Region Of Interesting,ROI)可以进一步缩小定义区域。这样可以避免处理无关区域,从而减少运算时间。 
1,设置ROI,方法是用图形窗口的设置ROI助手,然后手动画出并插入代码

gen_rectangle1(ROI_0, *****)

2,reduce_domain用于截取所画出的ROI

reduce_domain(fullImage,ROIarea,ReducedImage)

3,通常在threshod后,试用connection选择出连通区域,然后用面积和形状选择法选出自己关注的形状

threshold() connection(Region, OutputRegion) select_shape(input,output, Requirments....)

五,其他函数:

crop_rectangle1(Image : ImagePart : Row1, Column1, Row2, Column2 : )

//切出一个矩形区域,Image:输入的多通道图片,ImagePart:输出的多通道图片

 

原文来自: Burning_foot的博客

作者:韩兆新

出处:http://hanzhaoxin.cnblogs.com/

halcon学习笔记——(8)由标定板得到测量平面位姿

如图:由标定板位姿获取测量板位姿

image

1.pose_to_hom_mat3d( : : Pose : HomMat3D)

把三维位姿转化为齐次变换矩阵

2.hom_mat3d_translate_local( : : HomMat3D, Tx, Ty, Tz : HomMat3DTranslate)

相对于新坐标系的平移变换

/ 1 0 0  \  / Tx \

HomMat3DTranslate = HomMat3D * | 0 1 0 t | t = | Ty | | 0 0 1 | \ Tz / \ 0 0 0 1 / 返回值为HomMat3DTranslate矩阵。3.hom_mat3d_rotate_local( : :HomMat3D, Phi, Axis : HomMat3DRotate)  

相对于新坐标系的旋转变换,输出为原 HomMat3D右乘旋转矩阵后的齐次变换矩阵。

4.hom_mat3d_to_pose( : : HomMat3D : Pose)

把齐次矩阵转化为3D位姿态。利用0类代码,即先平移顺序RPT,旋转gba,以点的形式表达位姿。

 

原文来自:大疯熊和小兔子的幸福生活

作者:韩兆新

出处:http://hanzhaoxin.cnblogs.com/