Halcon Review Topics-Chapter 3-Calibration and Measurement (Single Camera)

Chapter 3 Calibration and Measurement ( Single Camera )

The measurement is to convert the pixel distance into the actual distance, and the fitting is placed on the defect detection, and the target shape is geometrically processed, so as to directly perform mathematical measurement from the geometric parameters

The measurement often requires the calibration of camera parameters, which are the internal and external parameters of the camera. According to this parameter, the pixel distance is converted into the actual distance. ⚠️The measurement often first performs image distortion correction

The first section calibration

1.1 Calibration board

In the actual camera project, we will use a variety of calibration boards, such as checkerboard calibration boards or circular array calibration boards, as shown in the following figure:

The material of the calibration board is generally glass, cardboard, plastic, etc.

The size of the calibration is also different, often the distance between the centers of the dots of the calibration plate is 4mm, usually a 7*7 array

The calibration board has the following characteristics:

  1.  Generally, the calibration board needs to fill 1/3 or 1/4 of the camera's field of view
  2. The imaging gray value of the calibration plate should be greater than 128
  3. When shooting the calibration board, it is best to rotate the calibration board and take 9-16 calibration boards with different rotation angles.
  4. The number of shots of the calibration board has nothing to do with the subsequent measurement accuracy

1.2 Single camera calibration

The purpose of single-camera calibration: distortion correction and a two-dimensional image measurement (mainly the actual size represented by 1 pixel).

The reason why calibration is important is that the camera often produces distortion and scaling after imaging. Therefore, it is necessary to establish a model to construct the three-dimensional spatial data of the object based on the image information. Then the geometric and optical parameters of the camera are required, and the camera is relative to the world. The orientation of the coordinate system.

When the computer is measuring, the camera calibration must be completed first, that is, the camera calibration. The so-called camera calibration is to determine the internal and external parameters of the camera. The internal parameters refer to the inherent properties of the camera, and the external parameters refer to the distortion caused by the object, etc.

The above-mentioned world coordinate system is one of several commonly used coordinate systems

Function table of each coordinate system

Name / notation

Features

Image pixel coordinate system /(u,v)

The image coordinate system with the pixel as the unit and the upper left point of the image as the origin

Image physical coordinate system /(x,y)

In mm units , physical units image pixel positions , the origin of coordinates and the camera image plane at the intersection of

Camera coordinate system /(Xc,Yc,Zc)

In mm units , to the optical center of the camera as an origin  , Zc axis coincides with the optical axis , perpendicular to the imaging plane , the imaging direction is the positive direction , Xc and Yc axis parallel to the coordinate system and the image of the physical

World coordinate system /(Xw, Yw, Zw)

This coordinate system describes the position of any object in the environment and satisfies the right-hand rule

The relationship between the image pixel coordinate system and the physical coordinate system . In fact, the physical coordinate system is the actual physical size coordinate system. Assume that the origin of our image pixel coordinate system coordinate system is in the upper left corner , and the physical coordinate system is in the image center . The physical dimensions of the pixel in the u-axis and v-axis directions are dx and dy, then:

u =  x/dx + u0

v = y / dy + v0

Among them, the unit of the physical coordinate system is mm, and the unit of the pixel coordinate system is pixel pixel, then the unit of dx is mm/pixel mm/pixel. Obviously the unit of x/dx is pixel, and the point (u0, v0) is the coordinate of the intersection of the optical axis and the image plane. , dx and dy are the physical dimensions of the unit pixel in the x and y directions, respectively

The above paragraph is transformed into the following picture:

The world coordinate system and the pixel coordinate system can also be represented by the above figure

The M in the above figure is a 3*4 projection matrix. The element values ​​of the M1 matrix are completely determined by the camera's internal parameters ax, ay, u0 and v0, where (u0, v0) are the coordinates of the origin of the pixel coordinate system, and ax and ay represent pixels The scale factor on the vertical and horizontal axes of the coordinate system, that is, ax = f/dx, ay=f/dy, and the M2 matrix is ​​determined by the camera's external parameters.

The world coordinate system to the pixel coordinate system, the transition from the camera coordinate system in the middle, Xw represents the x axis of the world coordinate system, the unit is mm, uv represents the horizontal and vertical axis of the pixel coordinate system, the unit is pixel, from the world coordinate system to the pixel coordinate The conversion of the system is the conversion from mm to pixel.

In Halcon, you can use the operator of the calibration file to perform single-camera calibration.

//生成标定文件算子,输入标定板参数即可
gen_caltab( : : XNum每行黑色标志圆点数量, 
				YNum, 
				MarkDist两个就近圆点中心之间的距离单位是meter, 
				DiameterRatio黑色圆点直径和两个圆点中心距离比值, 
				CalPlateDescr存放标定板描述文件路径.descr文件, 
				CalPlatePSFile存放标定板图像文件路径.ps文件)

1.3 Example of single camera calibration

First, use the above operator gen_caltab() to generate .descr and .ps files to specify the calibration parameters

The second step is to select the descr file just generated in the calibration board options, as shown below

The third step is to select the calibration. In addition, you need to pay attention to the camera parameters. When selecting the camera, you need to consider the actual width and height and focal length of the pixel.

The fourth step is to select the acquisition assistant and select the Gray image

The fifth step, click on the capture to get the picture, but you need to check the status of the picture. If the status shows: the quality problem is detected, don’t care, if it shows: the picture fails, you need to collect the picture again. Collect about 15 pictures, and make sure that the angles are different .

The sixth step, select the result, where the camera parameter is the internal parameter, and the camera pose is the external parameter. It should be noted that the file saved by the internal parameter is .cal and the file saved by the external parameter is .dat

At this point, even if the calibration of the single camera is completed, the following simple demonstration measurement, the specific measurement method is shown in Section 2

The seventh step, the measurement assistant, load in the above internal reference file .cal and external reference file .dat

The eighth step, use the measurement assistant to measure

At this point, the calibration of the camera has been completed, and the settings of the internal and external parameters of the camera have been completed, but the distortion correction has not yet been performed.

Section 2 Distortion Correction

 The calibration of a single camera is to obtain the internal and external parameters of the camera, but what must be completed before the measurement is the correction of image distortion, and in the process of distortion correction, external parameters are often not needed.

The so-called distortion is caused by the internal structure of the lens. Distorted objects are often one-dimensional and two-dimensional. Therefore, external parameters do not have much effect on the correction of distortion, but external parameters have a great effect in the operation of three-dimensional objects. .

The correction of distortion has the following six steps:

Obviously, for the correction of distortion, the key is how to obtain the distortion correction matrix. Next, let's look at a picture with distortion.

Obviously the object in the above picture is a calibration plate with obvious distortion, if it is used, it will produce unimaginable errors. Therefore, it must be repaired by distortion correction.

Simply put, the internal parameters of the camera are adjusted to obtain the internal parameters with no distortion effect, as described in the following program:

/*通过矫正畸变的算子,把单相机标定好的内参外参,进行参数修改,获得正确的参数
*/
change_radial_distortion_cam_par(Mode,算法模式
						CamParamIn, 输入相机内参
						DistortionCoeffs,一般是0
						CamParamOut输出相机内参)
/*产生映射,相当于放射矩阵*/
gen_radial_distortion_map(Map,输出映射数据
 				CamParamIn,原始相机内参即标定的内参 
				CamParamOut, 矫正过的相机内参
				MapType算法模式)
/*应用变换到图片*/
map_image(Image,需要矫正的图片
	      Map,映射数据
		  ImageMapped,输出矫正后的图片)

After the transformation of the distortion correction matrix, the corrected picture can be obtained

Section 3 Measuring Rectangle

Measurement steps:

  1. Place the measuring rectangle in the area to be measured, Start and End and the included angle Phi indicate the direction to be measured, the angle of the starting point, etc.
  2. Find the edge of the image to be measured inside the measuring rectangle
  3. Project the edge in grayscale, find the edge in the vertical projection direction, and then calculate the distance between which side and which side

According to the direction of the measurement rectangle , the negative edge is defined as from light to dark , and the positive edge is from dark to light.

Example 1 (based on edge pairs)

Result graph:

Explanation:

Edge pair

Detection process:

  1. gen_measure_rectangle2()
  2. measure_pairs ()
  3. close_measure()
dev_update_window ('off')
dev_close_window ()

read_image (Fuse, 'fuse')
get_image_size (Fuse, Width, Height)
dev_open_window_fit_image (Fuse, 0, 0, Width, Height, WindowID)
set_display_font (WindowID, 12, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Fuse)
set_display_font (WindowID, 12, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()

Row := 297
Column := 545
Length1 := 80
Length2 := 10
Angle := rad(90)
gen_rectangle2 (ROI, Row, Column, Angle, Length1, Length2)

// 生成测量矩形
// gen_measure_rectangle2( : : Row, Column, Phi, 矩形半宽Length1, 半高Length2, 图片Width, Height, Interpolation差值算法 : MeasureHandle输出测量矩形句柄)
gen_measure_rectangle2 (Row, Column, Angle, Length1, Length2, Width, Height, 'bilinear', MeasureHandle)
dev_display (ROI)
disp_continue_message (WindowID, 'black', 'true')
stop ()

/*	两个边缘作为一对,测量该对之间的距离,以及边缘对和边缘对之间的距离
		注意这里的第一条边缘是说的每个边缘对中的第一个边缘,所以输出的是个数组
		同理,第二条边缘也是每个边缘对的第二个,输出的也是个数组
	边缘对内部的距离就是边缘对中第一个和第二个边缘的距离,同样输出的也是数组
	边缘对之间的距离是每个边缘对的中心点到另一个边缘对的中心点的距离
*/

/*measure_pairs(Image : : MeasureHandle测量矩形句柄, 
				Sigma平滑参数, 
				Threshold最小边缘像素变化幅度, 
				Transition边缘类型是正还是负, 
				Select选择第几个边缘对,
				RowEdgeFirst输出第一个边缘的中心行坐标, 
				ColumnEdgeFirst, 
				AmplitudeFirst输出第一个边缘的像素变化幅度即一阶差分导数值, 
				RowEdgeSecond输出第二个边的中心行坐标, 
				ColumnEdgeSecond, 
				AmplitudeSecond, 
				IntraDistance输出边缘对内部边缘之间的距离, 
				InterDistance第1边缘对的第2条边 到 第2边缘对第1个边缘的距离)
*/
measure_pairs (Fuse, MeasureHandle, 1, 1, 'negative', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
disp_continue_message (WindowID, 'black', 'true')
stop ()

// 解析来就是结果可视化了
for i := 0 to |RowEdgeFirst| - 1 by 1
// 获得多边形轮廓(输出轮廓,输入多边形轮廓的线段转折点的横坐标点,列坐标点)
    gen_contour_polygon_xld (EdgeFirst, [-sin(Angle + rad(90)) * Length2 + RowEdgeFirst[i],-sin(Angle - rad(90)) * Length2 + RowEdgeFirst[i]], [cos(Angle + rad(90)) * Length2 + ColumnEdgeFirst[i],cos(Angle - rad(90)) * Length2 + ColumnEdgeFirst[i]])
// 另一个多边形轮廓
    gen_contour_polygon_xld (EdgeSecond, [-sin(Angle + rad(90)) * Length2 + RowEdgeSecond[i],-sin(Angle - rad(90)) * Length2 + RowEdgeSecond[i]], [cos(Angle + rad(90)) * Length2 + ColumnEdgeSecond[i],cos(Angle - rad(90)) * Length2 + ColumnEdgeSecond[i]])
// 显示上述轮廓,上图中的青色就是第一个轮廓,洋红色就是第二个,
    dev_set_color ('cyan')
    dev_display (EdgeFirst)
    dev_set_color ('magenta')
    dev_display (EdgeSecond)
// 设置接下来的字体颜色是蓝色
    dev_set_color ('blue')
    if (i == 0)
        set_tposition (WindowID, RowEdgeFirst[i] + 5, ColumnEdgeFirst[i] + 20)
    else
        set_tposition (WindowID, RowEdgeFirst[i] - 40, ColumnEdgeFirst[i] + 20)
    endif
    write_string (WindowID, 'width: ' + IntraDistance[i] + ' pix')
endfor
disp_continue_message (WindowID, 'black', 'true')
stop ()


close_measure (MeasureHandle)
dev_update_window ('on')
dev_clear_window ()

Example 2 (non-edge pair)

The output measurement arrays of Example 1 and Example 2 are all control variable arrays, that is, regular arrays, so the index starts from 0

Independent edge measurement steps:

  1. gen_measrue_rectangle2()
  2. measure_pos()
  3. close_measure()

Result graph:

dev_close_window ()
read_image (Image, 'ic_pin')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
// draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
Row := 47
Column := 485
Phi := 0
Length1 := 420
Length2 := 10
dev_set_color ('green')
dev_set_draw ('margin')
dev_set_line_width (3)
//生成一个矩形区域
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
// 生成一个测量矩形在上述区域上
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', MeasureHandle)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
// 设置运行参数
dev_update_pc ('off')
dev_update_var ('off')
// n时测量次数
n := 100
count_seconds (Seconds1)
for i := 1 to n by 1
// 使用边缘对测量
    measure_pairs (Image, MeasureHandle, 1.5, 30, 'negative', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, PinWidth, PinDistance)
endfor
count_seconds (Seconds2)
Time := Seconds2 - Seconds1
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_color ('red')
disp_line (WindowHandle, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
// sum是元素求和函数
avgPinWidth := sum(PinWidth) / |PinWidth|
avgPinDistance := sum(PinDistance) / |PinDistance|
numPins := |PinWidth|
dev_set_color ('yellow')
disp_message (WindowHandle, 'Number of pins: ' + numPins, 'image', 200, 100, 'yellow', 'false')
disp_message (WindowHandle, 'Average Pin Width:  ' + avgPinWidth, 'image', 260, 100, 'yellow', 'false')
disp_message (WindowHandle, 'Average Pin Distance:  ' + avgPinDistance, 'image', 320, 100, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\pins_result')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
Row1 := 0
Column1 := 600
Row2 := 100
Column2 := 700
dev_set_color ('blue')
disp_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
stop ()
// 这个只是更改显示区域,并不是裁剪了图片
dev_set_part (Row1, Column1, Row2, Column2)
dev_display (Image)
dev_set_color ('green')
dev_display (Rectangle)
dev_set_color ('red')
disp_line (WindowHandle, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
close_measure (MeasureHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

// 这里完成了第一次的测量,开始另一个区域测量
dev_set_color ('green')
* draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
Row := 508
Column := 200
Phi := -1.5708
Length1 := 482
Length2 := 35
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', MeasureHandle)
stop ()

//不是用边缘对的测量方法  
// 不把边缘按对来分,每个边缘都是一个独立的边缘
/measure_pos(输入图片,
			输出测量句柄,
			平滑参数,	
			边缘差分最小阈值,
			边缘正负类型,
			选择哪个边缘,
			输出边缘中心点的行坐标列坐标,
			输出对应边缘差分值,
			输出每个相邻边缘的中心点距离)
/
measure_pos (Image, MeasureHandle, 1.5, 30, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
// 根据得到的信息来计算高度
PinHeight1 := RowEdge[1] - RowEdge[0]
PinHeight2 := RowEdge[3] - RowEdge[2]
dev_set_color ('red')
disp_line (WindowHandle, RowEdge, ColumnEdge - Length2, RowEdge, ColumnEdge + Length2)
disp_message (WindowHandle, 'Pin Height:  ' + PinHeight1, 'image', RowEdge[1] + 40, ColumnEdge[1] + 100, 'yellow', 'false')
disp_message (WindowHandle, 'Pin Height:  ' + PinHeight2, 'image', RowEdge[3] - 120, ColumnEdge[3] + 100, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\pins_height_result')
close_measure (MeasureHandle)
dev_set_draw ('fill')
dev_set_line_width (1)
dev_close_window ()
read_image (Image, 'ic_pin')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
Row := 47
Column := 485
Phi := 0
Length1 := 420
Length2 := 10
dev_set_color ('green')
dev_set_draw ('margin')
dev_set_line_width (3)
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', MeasureHandle)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_update_pc ('off')
dev_update_var ('off')
n := 100
count_seconds (Seconds1)
for i := 1 to n by 1
    measure_pairs (Image, MeasureHandle, 1.5, 30, 'negative', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, PinWidth, PinDistance)
endfor
count_seconds (Seconds2)
Time := Seconds2 - Seconds1
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_color ('red')
disp_line (WindowHandle, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
avgPinWidth := sum(PinWidth) / |PinWidth|
avgPinDistance := sum(PinDistance) / |PinDistance|
numPins := |PinWidth|
dev_set_color ('yellow')
disp_message (WindowHandle, 'Number of pins: ' + numPins, 'image', 200, 100, 'yellow', 'false')
disp_message (WindowHandle, 'Average Pin Width:  ' + avgPinWidth, 'image', 260, 100, 'yellow', 'false')
disp_message (WindowHandle, 'Average Pin Distance:  ' + avgPinDistance, 'image', 320, 100, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\pins_result')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
Row1 := 0
Column1 := 600
Row2 := 100
Column2 := 700
dev_set_color ('blue')
disp_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
stop ()
dev_set_part (Row1, Column1, Row2, Column2)
dev_display (Image)
dev_set_color ('green')
dev_display (Rectangle)
dev_set_color ('red')
disp_line (WindowHandle, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
close_measure (MeasureHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_set_color ('green')
* draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
Row := 508
Column := 200
Phi := -1.5708
Length1 := 482
Length2 := 35
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'nearest_neighbor', MeasureHandle)
stop ()
measure_pos (Image, MeasureHandle, 1.5, 30, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
PinHeight1 := RowEdge[1] - RowEdge[0]
PinHeight2 := RowEdge[3] - RowEdge[2]
dev_set_color ('red')
disp_line (WindowHandle, RowEdge, ColumnEdge - Length2, RowEdge, ColumnEdge + Length2)
disp_message (WindowHandle, 'Pin Height:  ' + PinHeight1, 'image', RowEdge[1] + 40, ColumnEdge[1] + 100, 'yellow', 'false')
disp_message (WindowHandle, 'Pin Height:  ' + PinHeight2, 'image', RowEdge[3] - 120, ColumnEdge[3] + 100, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\pins_height_result')
close_measure (MeasureHandle)
dev_set_draw ('fill')
dev_set_line_width (1)

Example 3 (shape matching + positioning measurement)

  1. Match the target shape and locate its position
  2. According to the change of the target in each frame, an affine matrix is ​​formed
  3. According to the radiation matrix, the same transformation is performed on the area of ​​the measurement rectangle
  4. Edge measurement of the measurement area
dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'board/board.seq', 'default', -1, 1, FGHandle)
grab_image (Image, FGHandle)
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_open_window (Height + 70, 0, Width, 120, 'black', WindowHandleText)
dev_set_window (WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
set_display_font (WindowHandleText, 16, 'mono', 'true', 'false')
dev_set_color ('red')
dev_display (Image)
Row1 := 188
Column1 := 182
Row2 := 298
Column2 := 412
gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
area_center (Rectangle, Area, Row, Column)
Rect1Row := -102
Rect1Col := 5
Rect2Row := 107
Rect2Col := 5
RectPhi := 0
RectLength1 := 170
RectLength2 := 5
// 设置2个测量矩形的矩形区域
gen_rectangle2 (Rectangle1, Row + Rect1Row, Column + Rect1Col, RectPhi, RectLength1, RectLength2)
gen_rectangle2 (Rectangle2, Row + Rect2Row, Column + Rect2Col, RectPhi, RectLength1, RectLength2)
reduce_domain (Image, Rectangle, ImageReduced)
create_shape_model (ImageReduced, 4, 0, rad(360), rad(1), 'none', 'use_polarity', 30, 10, ModelID)
get_shape_model_contours (ShapeModel, ModelID, 1)
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_translate (HomMat2DIdentity, Row, Column, HomMat2DTranslate)
affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DTranslate)
dev_display (Image)
dev_set_color ('green')
dev_display (ShapeModelTrans)
dev_set_color ('blue')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Rectangle1)
dev_display (Rectangle2)
dev_set_draw ('fill')
dev_set_line_width (1)
dev_set_color ('yellow')
disp_message (WindowHandle, ['Press left button to start','and stop the demo'], 'window', 12, 12, 'black', 'true')
get_mbutton (WindowHandle, Row3, Column3, Button1)
wait_seconds (0.5)
Button := 0
while (Button != 1)
    dev_set_window (WindowHandle)
    dev_set_part (0, 0, Height - 1, Width - 1)
    grab_image (ImageCheck, FGHandle)
    dev_display (ImageCheck)
    count_seconds (S1)
    find_shape_model (ImageCheck, ModelID, 0, rad(360), 0.7, 1, 0.5, 'least_squares', 4, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
    count_seconds (S2)
    dev_display (ImageCheck)
    if (|Score| > 0)
        dev_set_color ('green')
        hom_mat2d_identity (HomMat2DIdentity)
        hom_mat2d_translate (HomMat2DIdentity, RowCheck, ColumnCheck, HomMat2DTranslate)
        hom_mat2d_rotate (HomMat2DTranslate, AngleCheck, RowCheck, ColumnCheck, HomMat2DRotate)
        affine_trans_contour_xld (ShapeModel, ShapeModelTrans, HomMat2DRotate)
        dev_display (ShapeModelTrans)
// 针对像素点进行仿射变换,参数(放射矩阵,像素行列坐标,输出变换后的行列坐标)
        affine_trans_pixel (HomMat2DRotate, Rect1Row, Rect1Col, Rect1RowCheck, Rect1ColCheck)
        affine_trans_pixel (HomMat2DRotate, Rect2Row, Rect2Col, Rect2RowCheck, Rect2ColCheck)
        gen_rectangle2 (Rectangle1Check, Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2)
        gen_rectangle2 (Rectangle2Check, Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2)
        dev_set_color ('blue')
        dev_set_draw ('margin')
        dev_set_line_width (3)
        dev_display (Rectangle1Check)
        dev_display (Rectangle2Check)
        dev_set_draw ('fill')
        count_seconds (S3)
// 根据上述的测量矩形区域经过变换后得到仿射结果区域,然后测量该区域的边缘距离
        gen_measure_rectangle2 (Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
        gen_measure_rectangle2 (Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
        measure_pairs (ImageCheck, MeasureHandle1, 2, 90, 'positive', 'all', RowEdgeFirst1, ColumnEdgeFirst1, AmplitudeFirst1, RowEdgeSecond1, ColumnEdgeSecond1, AmplitudeSecond1, IntraDistance1, InterDistance1)
        measure_pairs (ImageCheck, MeasureHandle2, 2, 90, 'positive', 'all', RowEdgeFirst2, ColumnEdgeFirst2, AmplitudeFirst2, RowEdgeSecond2, ColumnEdgeSecond2, AmplitudeSecond2, IntraDistance2, InterDistance2)
        close_measure (MeasureHandle1)
        close_measure (MeasureHandle2)
        count_seconds (S4)
// 显示结果
        dev_set_color ('red')
        disp_line (WindowHandle, RowEdgeFirst1 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 - RectLength2 * sin(AngleCheck), RowEdgeFirst1 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst1 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeSecond1 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 - RectLength2 * sin(AngleCheck), RowEdgeSecond1 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond1 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeFirst2 - RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 - RectLength2 * sin(AngleCheck), RowEdgeFirst2 + RectLength2 * cos(AngleCheck), ColumnEdgeFirst2 + RectLength2 * sin(AngleCheck))
        disp_line (WindowHandle, RowEdgeSecond2 - RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 - RectLength2 * sin(AngleCheck), RowEdgeSecond2 + RectLength2 * cos(AngleCheck), ColumnEdgeSecond2 + RectLength2 * sin(AngleCheck))
        dev_set_line_width (1)
        NumLeads := |IntraDistance1| + |IntraDistance2|
        MinDistance := min([InterDistance1,InterDistance2])
        dev_set_window (WindowHandleText)
        dev_set_part (0, 0, 119, Width - 1)
        dev_clear_window ()
        disp_message (WindowHandleText, 'Matching: Time: ' + ((S2 - S1) * 1000)$'5.2f' + 'ms , Score: ' + Score$'7.5f', 'image', 20, 20, 'green', 'false')
        disp_message (WindowHandleText, 'Measure:  Time: ' + ((S4 - S3) * 1000)$'5.2f' + ' ms, Num. leads: ' + NumLeads$'2d', 'image', 50, 20, 'red', 'false')
        disp_message (WindowHandleText, '          Min. lead dist: ' + MinDistance$'6.3f', 'image', 80, 20, 'red', 'false')
    endif
    dev_error_var (Error, 1)
    dev_set_check ('~give_error')
    get_mposition (WindowHandle, R, C, Button)
    dev_error_var (Error, 0)
    dev_set_check ('give_error')
    if (Error != H_MSG_TRUE)
        Button := 0
    endif
endwhile
dev_set_window (WindowHandleText)
dev_close_window ()
clear_shape_model (ModelID)
close_framegrabber (FGHandle)

The fourth section measuring arc

General steps:

  1. Capture image
  2. Calibration image
  3. Distortion correction
  4. measuring
    1. Create a measurement arc
    2. Convert pixel distance to actual distance (according to internal and external parameters)
  5. Show results

The target to be measured is an arc or a non-straight line, as shown in the figure below

Measure arc result

Example one (creating an arc)

// measure_arc.hdev
read_image (Zeiss1, 'zeiss1')
get_image_size (Zeiss1, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width / 2, Height / 2, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_display (Zeiss1)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
// 画一个圆圈或者写入参数
* draw_circle (WindowHandle, Row, Column, Radius)
Row := 275
Column := 335
Radius := 107
AngleStart := -rad(55)
AngleExtent := rad(170)
dev_set_draw ('fill')
dev_set_color ('green')
dev_set_line_width (1)
// 获得椭圆上的一个点
// get_points_ellipse(get_points_ellipse( : : Angle=上图中的AgnleStart+AngleExtent, Row, Column椭圆中心点行列坐标, Phi椭圆长轴和水平的夹角, Radius1椭圆长半轴2 : RowPoint, ColPoint输出椭圆在Angle角度上的一个点)
get_points_ellipse (AngleStart + AngleExtent, Row, Column, 0, Radius, Radius, RowPoint, ColPoint)
// 显示一段圆弧,参数(窗口句柄,中心点行列坐标,角度范围,起点行列坐标)根据起点行列坐标再根据角度范围方向来绘制圆弧)
disp_arc (WindowHandle, Row, Column, AngleExtent, RowPoint, ColPoint)
dev_set_line_width (3)
//生成一个测量弧形
// gen_measure_arc( : : CenterRow, CenterCol, Radius, AngleStart, AngleExtent, AnnulusRadius见上图, Width, Height图片宽高, Interpolation 差值算法: MeasureHandle输出测量结果句柄)
gen_measure_arc (Row, Column, Radius, AngleStart, AngleExtent, 10, Width, Height, 'nearest_neighbor', MeasureHandle)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
count_seconds (Seconds1)
n := 10
for i := 1 to n by 1
// 开始测量弧形
// measure_pos(Image : : MeasureHandle测量弧形句柄, Sigma平滑参数, Threshold最小边缘幅度即梯度值, Transition是正还是负边缘, Select选择哪些边缘 : RowEdge, ColumnEdge输出边缘结果的行列坐标, Amplitude边缘幅度, Distance在一个测量弧形里面,各边缘之间的连续距离)
// ⚠️Distance注意两点,1⃣️在一个测量矩形内,2⃣️连续边缘之间的连续距离,即不是两个连续边缘的中心点直线距离,注意区别
    measure_pos (Zeiss1, MeasureHandle, 1, 10, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
endfor
count_seconds (Seconds2)
Time := (Seconds2 - Seconds1) / n
disp_continue_message (WindowHandle, 'black', 'true')
* stop ()
// pp表示两个点,即求两个点之间的距离
distance_pp (RowEdge[1], ColumnEdge[1], RowEdge[2], ColumnEdge[2], IntermedDist)
* dev_display (Zeiss1)
dev_set_color ('red')
* disp_circle (WindowHandle, RowEdge, ColumnEdge, RowEdge - RowEdge + 1)
disp_line (WindowHandle, RowEdge[1], ColumnEdge[1], RowEdge[2], ColumnEdge[2])
dev_set_color ('yellow')
disp_message (WindowHandle, 'Distance: ' + IntermedDist, 'image', 250, 80, 'yellow', 'false')
* dump_window (WindowHandle, 'tiff_rgb', 'C:\\Temp\\zeiss_result')
close_measure (MeasureHandle)
dev_set_line_width (1)
* disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/Mrsherlock_/article/details/109583966