缺陷检测解决策略之六:测量和拟合 缺陷检测解决策略之六:测量和拟合 缺陷检测解决策略之六:测量和拟合
示例1:定位(模板匹配) +测量
用测量矩形找液面
* 窗口设置
dev_close_window ()
dev_update_off ()
* 读取图像
read_image (Image, 'ampoules/ampoules_01')
* 获取图像大小
get_image_size (Image, Width, Height)
* 窗口显示设置
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_set_line_width (2)
dev_set_draw ('margin')
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
* 生成矩形区域
gen_rectangle1 (Rectangle, 230, 280, 317, 330)
* 获取区域图像
reduce_domain (Image, Rectangle, ImageModel)
* 创建模板匹配模型
create_shape_model (ImageModel, 'auto', 0, 0, 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
* 生成测量矩形对象(量程 150 和 40)
gen_measure_rectangle2 (0, 0, rad(90), 75, 20, Width, Height, 'bilinear', MeasureHandle)
* 阈值
Tolerance := 15
* 图像数量
NumImages := 8
* 遍历所有图像
for Index := 1 to NumImages by 1
* 读取图像
read_image (Image, 'ampoules/ampoules_' + Index$'.2d')
*
ColumnEdges := []
FillLevelHeight := []
* 模板匹配
find_shape_model (Image, ModelID, 0, 0, 0.7, 0, 0.1, 'least_squares', 0, 0.9, Row, Column, Angle, Score)
* 获取Y的均值
MeanRow := mean(Row)
* 确定液体标准高度
RefLevel := MeanRow - 160
dev_display (Image)
dev_set_line_width (1)
dev_set_color ('white')
* 生成矩形(ROI区域)
gen_rectangle2 (AcceptLevel, RefLevel, mean(Column), 0, 30 + (max(Column) - min(Column)) / 2, Tolerance)
dev_display (AcceptLevel)
dev_set_line_width (2)
Errors := 0
* 遍历所有匹配对象
for Idx := 0 to |Score| - 1 by 1
* 测量对象,向下移动135像素
translate_measure (MeasureHandle, MeanRow - 135, Column[Idx])
* 显示测量范围
gen_rectangle2 (Rectangle1,MeanRow - 135, Column[Idx], rad(90), 75, 20)
* 测量
measure_pos (Image, MeasureHandle, 2, 7, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
* 边缘Y
FillLevelHeight := [FillLevelHeight,RowEdge]
* 边缘X
ColumnEdges := [ColumnEdges,ColumnEdge]
* 显示十字叉
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 15, 0)
* 生成矩形(卡出的点,周围的矩形)
gen_rectangle2 (FillLevel, RowEdge, ColumnEdge, 0, 28, 20)
* 如果超过阈值,则报NG(红),否则OK
* 边缘Y-液体标准高度 大于 阈值Tolerance,则error
if (abs(FillLevelHeight[Idx] - RefLevel) >= Tolerance)
gen_rectangle2 (ChamberSingle, MeanRow - 133, Column[Idx], 0, 35, 90)
gen_cross_contour_xld (Cross, FillLevelHeight[Idx], ColumnEdges[Idx], 15, 0)
gen_rectangle2 (FillLevel, FillLevelHeight[Idx], ColumnEdges[Idx], 0, 28, 20)
Errors := Errors + 1
dev_set_color ('red')
dev_display (ChamberSingle)
disp_message (WindowHandle, 'NG', 'image', FillLevelHeight[Idx] - 50, ColumnEdges[Idx] - 10, 'red', 'false')
else
disp_message (WindowHandle, 'OK', 'image', FillLevelHeight[Idx] - 50, ColumnEdges[Idx] - 10, 'green', 'false')
dev_set_color ('green')
endif
dev_display (FillLevel)
dev_display (Cross)
endfor
* 如果有一个NG,则显示不良品,否则为良品
if (Errors > 0)
disp_message (WindowHandle, Errors + ' BAD', 'window', 10, 12, 'red', 'true')
else
disp_message (WindowHandle, 'All OK', 'window', 10, 12, 'forest green', 'true')
endif
* 显示设置
if (Index < NumImages)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
endif
endfor
* 清除测量对象句柄
close_measure (MeasureHandle)
* 清除模板句柄
clear_shape_model (ModelID)
示例2:定位+测量
* ------------------------------------------------------------------------------------------------
* This example program uses shape-based matching to align ROIs for the measure
* tool, which then inspects individual razor blades.
* The program can be run in two modes: (1) with the full affine transformation
* (2) using translate_measure
* Modify the next line to switch between the modes.
USING_TRANSLATE_MEASURE := 0
* ------------------------------------------------------------------------------------------------
* general configuration of HDevelop
dev_update_window ('off')
* image acquisition and window size
read_image (ModelImage, 'razors1')
get_image_pointer1 (ModelImage, Pointer, Type, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (ModelImage)
* colors and other settings for the visualization
dev_set_color ('cyan')
dev_set_draw ('margin')
dev_set_line_width (2)
stop ()
* ------------------- start of the application ----------------
* -> select the model object
Row1 := 46
Column1 := 57
Row2 := 79
Column2 := 94
gen_rectangle1 (ROIPart1, Row1, Column1, Row2, Column2)
gen_rectangle1 (ROIPart2, Row1 + 364, Column1 + 13, Row2 + 364, Column2 + 13)
union2 (ROIPart1, ROIPart2, ModelROI)
area_center (ModelROI, Area, CenterROIRow, CenterROIColumn)
dev_display (ModelImage)
dev_display (ModelROI)
stop ()
* -> create the model
reduce_domain (ModelImage, ModelROI, ImageROI)
create_shape_model (ImageROI, 4, 0, 0, 'auto', 'none', 'use_polarity', 30, 10, ModelID)
inspect_shape_model (ImageROI, ShapeModelImage, ShapeModelRegion, 1, 30)
get_shape_model_contours (ShapeModel, ModelID, 1)
dev_clear_window ()
dev_set_color ('blue')
dev_display (ShapeModelRegion)
stop ()
* step 1: create variables describing the measurement ROIs and display them
Rect1Row := 244
Rect1Col := 73
DistColRect1Rect2 := 17
Rect2Row := Rect1Row
Rect2Col := Rect1Col + DistColRect1Rect2
RectPhi := rad(90)
RectLength1 := 122
RectLength2 := 2
gen_rectangle2 (MeasureROI1, Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2)
gen_rectangle2 (MeasureROI2, Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2)
dev_display (ModelImage)
dev_set_color ('yellow')
dev_display (MeasureROI1)
dev_display (MeasureROI2)
* translate measurement ROIs to lie on XLD model (without clipping!)
get_system ('clip_region', OriginalClipRegion)
set_system ('clip_region', 'false')
move_region (MeasureROI1, MeasureROI1Ref, -CenterROIRow, -CenterROIColumn)
move_region (MeasureROI2, MeasureROI2Ref, -CenterROIRow, -CenterROIColumn)
set_system ('clip_region', OriginalClipRegion)
DistRect1CenterRow := Rect1Row - CenterROIRow
DistRect1CenterCol := Rect1Col - CenterROIColumn
DistRect2CenterRow := Rect2Row - CenterROIRow
DistRect2CenterCol := Rect2Col - CenterROIColumn
if (USING_TRANSLATE_MEASURE != 0)
* -> measure objects are created only once in advance and then translated later
gen_measure_rectangle2 (Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
gen_measure_rectangle2 (Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
endif
stop ()
* step 2: find the objects in another image
read_image (SearchImage, 'razors2')
dev_display (SearchImage)
find_shape_model (SearchImage, ModelID, 0, 0, 0.8, 0, 0.5, 'least_squares', 0, 0.7, RowCheck, ColumnCheck, AngleCheck, Score)
if (|Score| > 0)
for i := 0 to |Score| - 1 by 1
* step 3: determine the affine transformation
vector_angle_to_rigid (0, 0, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject)
affine_trans_contour_xld (ShapeModel, ModelAtNewPosition, MovementOfObject)
dev_display (ModelAtNewPosition)
* step 4: measure width and distance of the teeth
* -> display the moved ROIs
affine_trans_region (MeasureROI1Ref, MeasureROI1AtNewPosition, MovementOfObject, 'constant')
affine_trans_region (MeasureROI2Ref, MeasureROI2AtNewPosition, MovementOfObject, 'constant')
dev_display (MeasureROI1AtNewPosition)
dev_display (MeasureROI2AtNewPosition)
affine_trans_pixel (MovementOfObject, DistRect1CenterRow, DistRect1CenterCol, Rect1RowCheck, Rect1ColCheck)
affine_trans_pixel (MovementOfObject, DistRect2CenterRow, DistRect2CenterCol, Rect2RowCheck, Rect2ColCheck)
if (USING_TRANSLATE_MEASURE != 0)
* -> translate the already created measure objects
translate_measure (MeasureHandle1, Rect1RowCheck, Rect1ColCheck)
translate_measure (MeasureHandle2, Rect2RowCheck, Rect2ColCheck)
measure_pairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1)
measure_pairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all', RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2)
else
* -> create new measure objects and destroy them after the measurement
RectPhiCheck := RectPhi + AngleCheck[i]
gen_measure_rectangle2 (Rect1RowCheck, Rect1ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
gen_measure_rectangle2 (Rect2RowCheck, Rect2ColCheck, RectPhiCheck, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
* step 5: perform the measurement
measure_pairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1)
measure_pairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all', RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2)
close_measure (MeasureHandle1)
close_measure (MeasureHandle2)
endif
* step 6: check for too short or missing teeth
NumberTeeth1 := |Width1|
NumberTeeth2 := |Width2|
dev_set_color ('red')
if (NumberTeeth1 < 37)
for j := 0 to NumberTeeth1 - 2 by 1
if (Distance1[j] > 4.0)
RowFault := round(0.5 * (RowEdge11[j + 1] + RowEdge21[j]))
ColFault := round(0.5 * (ColEdge11[j + 1] + ColEdge21[j]))
disp_rectangle2 (WindowHandle, RowFault, ColFault, 0, 4, 4)
dev_open_window (0, Width + 20, 80, 80, 'black', WindowHandleZoom)
dev_set_part (RowFault - 10, ColFault - 10, RowFault + 10, ColFault + 10)
dev_display (SearchImage)
disp_rectangle2 (WindowHandleZoom, RowFault, ColFault, 0, 4, 4)
stop ()
dev_close_window ()
dev_set_part (0, 0, Height - 1, Width - 1)
endif
endfor
endif
if (NumberTeeth2 < 37)
for j := 0 to NumberTeeth2 - 2 by 1
if (Distance2[j] > 4.0)
RowFault := round(0.5 * (RowEdge12[j + 1] + RowEdge22[j]))
ColFault := round(0.5 * (ColEdge12[j + 1] + ColEdge22[j]))
disp_rectangle2 (WindowHandle, RowFault, ColFault, 0, 4, 4)
dev_open_window (0, Width + 20, 80, 80, 'black', WindowHandleZoom)
dev_set_part (RowFault - 10, ColFault - 10, RowFault + 10, ColFault + 10)
dev_display (SearchImage)
disp_rectangle2 (WindowHandleZoom, RowFault, ColFault, 0, 4, 4)
stop ()
dev_close_window ()
dev_set_part (0, 0, Height - 1, Width - 1)
endif
endfor
endif
dev_set_color ('yellow')
stop ()
endfor
endif
* ------------------- end of the application -----------------
* clean up
if (USING_TRANSLATE_MEASURE != 0)
close_measure (MeasureHandle1)
close_measure (MeasureHandle2)
endif
dev_update_window ('on')
clear_shape_model (ModelID)
示例3:blob+拟合
* This example checks bottle necks for defects.
* First, the bottle is detected with basic morphology,
* edge detection and circle fitting.
* Then, the neck area is transformed with a polar transformation.
* After that, in the transformed image a dynamic threshold is used
* to detect defects. Finally, the results are displayed.
*
*
* tuning parameters
SmoothX := 501
ThresholdOffset := 25
MinDefectSize := 50
*
* initialization
PolarResolution := 640
RingSize := 70
get_system ('store_empty_region', StoreEmptyRegion)
set_system ('store_empty_region', 'false')
read_image (Image, 'bottles/bottle_mouth_01')
dev_update_off ()
dev_close_window ()
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, 640, 512, WindowHandle1)
set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')
dev_display (Image)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_open_window_fit_size (0, 648, RingSize, PolarResolution, 150, 512, WindowHandle)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('red')
*
* Main loop
*
* Detect defects in bottle necks
for Index := 1 to 16 by 1
read_image (Image, 'bottles/bottle_mouth_' + Index$'.02')
*
* Part 1: Use basic morphology to detect bottle
auto_threshold (Image, Regions, 2)
select_obj (Regions, DarkRegion, 1)
opening_circle (DarkRegion, RegionOpening, 3.5)
closing_circle (RegionOpening, RegionClosing, 25.5)
fill_up (RegionClosing, RegionFillUp)
boundary (RegionFillUp, RegionBorder, 'outer')
dilation_circle (RegionBorder, RegionDilation, 3.5)
reduce_domain (Image, RegionDilation, ImageReduced)
*
* Find the bottle center by fitting a circle to extracted edges
edges_sub_pix (ImageReduced, Edges, 'canny', 0.5, 20, 40)
segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 4, 2)
union_cocircular_contours_xld (ContoursSplit, UnionContours, 0.9, 0.5, 0.5, 200, 50, 50, 'true', 1)
length_xld (UnionContours, Length)
select_obj (UnionContours, LongestContour, sort_index(Length)[|Length| - 1] + 1)
fit_circle_contour_xld (LongestContour, 'ahuber', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
*
* Part 2: Transform the ring-shaped bottle neck region to a rectangle
gen_circle (Circle, Row, Column, Radius)
dilation_circle (Circle, RegionDilation, 5)
erosion_circle (Circle, RegionErosion, RingSize - 5)
difference (RegionDilation, RegionErosion, RegionDifference)
reduce_domain (Image, RegionDifference, ImageReduced)
polar_trans_image_ext (ImageReduced, ImagePolar, Row, Column, 0, rad(360), Radius - RingSize, Radius, PolarResolution, RingSize, 'nearest_neighbor')
*
* Part 3: Find defects with a dynamic threshold
* Note the strong smoothing in x-direction in the transformed image.
scale_image_max (ImagePolar, ImageScaleMax)
mean_image (ImageScaleMax, ImageMean, SmoothX, 3)
dyn_threshold (ImageScaleMax, ImageMean, Regions1, 55, 'not_equal')
connection (Regions1, Connection)
select_shape (Connection, SelectedRegions, 'height', 'and', 9, 99999)
* ignore noise regions
closing_rectangle1 (SelectedRegions, RegionClosing1, 10, 20)
union1 (RegionClosing1, RegionUnion)
* re-transform defect regions for visualization
polar_trans_region_inv (RegionUnion, XYTransRegion, Row, Column, 0, rad(360), Radius - RingSize, Radius, PolarResolution, RingSize, 1280, 1024, 'nearest_neighbor')
*
* Part 4: Display results
* display original image with results
dev_set_window (WindowHandle1)
dev_display (Image)
dev_set_color ('blue')
dev_display (RegionDifference)
dev_set_color ('red')
dev_display (XYTransRegion)
* display polar transformed inspected region with results
* The image and resulting region are rotated by 90 degrees
* only for visualization purposes! (I.e. to fit better on the screen)
* The rotation is NOT necessary for the detection algorithm.
dev_set_window (WindowHandle)
rotate_image (ImagePolar, ImageRotate, 90, 'constant')
dev_display (ImageRotate)
count_obj (RegionUnion, Number)
if (Number > 0)
mirror_region (RegionUnion, RegionMirror, 'diagonal', PolarResolution)
mirror_region (RegionMirror, RegionMirror, 'row', PolarResolution)
dev_display (RegionMirror)
disp_message (WindowHandle1, 'Not OK', 'window', 12, 12, 'red', 'false')
else
disp_message (WindowHandle1, 'OK', 'window', 12, 12, 'forest green', 'false')
endif
if (Index < 16)
disp_continue_message (WindowHandle1, 'black', 'true')
stop ()
endif
endfor
* Reset system parameters
set_system ('store_empty_region', StoreEmptyRegion)
示例4: blob+拟合
* This example program shows how fit_rectangle2_contour_xld can be used to
* detect manufacturing errors of punched holes in a metal part. The errors
* show up as small protrusions of the metal into the hole. They can be detected
* by fitting rectangles to the edges of the hole robustly (i.e., with outlier
* suppression) and the calculating the distances of the edges to the rectangle
* sides using dist_rectangle2_contour_points_xld. Since the corners of the
* holes are slightly rounded, some extra processing must be performed to
* disregard the corners in the check for errors.
dev_update_off ()
read_image (Image, 'punched_holes')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
* Since the metal part is backlit, the processing speed can be increased
* significantly by constructing a ROI for the subpixel-precise edge extraction
* that is as small as possible. This can easily be achieved by thresholding and
* morphology.
fast_threshold (Image, Region, 128, 255, 10)
boundary (Region, Border, 'inner')
dilation_rectangle1 (Border, EdgeROI, 7, 7)
reduce_domain (Image, EdgeROI, ImageReduced)
* Perform the edge extraction.
edges_sub_pix (ImageReduced, Edges, 'canny', 1.7, 40, 120)
* Remove edge fragments that are too short.
select_shape_xld (Edges, RectangleEdges, 'contlength', 'and', 500, 100000)
* Fit rectangles to the holes' edges using the outlier suppression of Tukey.
fit_rectangle2_contour_xld (RectangleEdges, 'tukey', -1, 0, 0, 3, 2, Row, Column, Phi, Length1, Length2, PointOrder)
* Create rectangles with the fitted parameters for visualization purposes.
gen_rectangle2_contour_xld (Rectangles, Row, Column, Phi, Length1, Length2)
dev_set_color ('yellow')
dev_display (Rectangles)
* Check whether the holes are OK.
count_obj (RectangleEdges, Number)
for I := 0 to Number - 1 by 1
select_obj (RectangleEdges, RectangleEdge, I + 1)
* Get the contour's coordinates.
get_contour_xld (RectangleEdge, Rows, Cols)
* Create a rectangle with the appropriate rectangle parameters.
gen_rectangle2_contour_xld (Rect, Row[I], Column[I], Phi[I], Length1[I], Length2[I])
* Get the coordinates of the rectangle's corners.
get_contour_xld (Rect, RowC, ColC)
* Calculate the distances of all the contour points to the four corners of the
* rectangle.
D1 := sqrt((Rows - RowC[0]) * (Rows - RowC[0]) + (Cols - ColC[0]) * (Cols - ColC[0]))
D2 := sqrt((Rows - RowC[1]) * (Rows - RowC[1]) + (Cols - ColC[1]) * (Cols - ColC[1]))
D3 := sqrt((Rows - RowC[2]) * (Rows - RowC[2]) + (Cols - ColC[2]) * (Cols - ColC[2]))
D4 := sqrt((Rows - RowC[3]) * (Rows - RowC[3]) + (Cols - ColC[3]) * (Cols - ColC[3]))
* The distance of the contour points to the corners of the rectangle is given
* by the minimum of the four distances. This distance is used to exclude
* contour points that are too close to the corners from the check for errors.
DistCorner := min2(min2(D1,D2),min2(D3,D4))
* Calculate the distances of the contour points of the rectangle.
dist_rectangle2_contour_points_xld (RectangleEdge, 0, Row[I], Column[I], Phi[I], Length1[I], Length2[I], Dist)
* Check whether the hole is OK by examining the distances of the contour
* points to the rectangle. A hole is OK if all points that lie more than seven
* pixels from the corners have a distance of less than one pixel to the fitted
* rectangle. To do so, we could use the following code:
* RectangleOK := true
* for J := 0 to |Dist| - 1 by 1
* if (DistCorner[J] > 7.0 and Dist[J] > 1.0)
* RectangleOK := false
* break
* endif
* endfor
* A much faster way to do this in HDevelop is to generate a mask that
* contains 0 for all points that should not be taken into account and 1
* otherwise. To do so, we subtract the minimum distance of 7.0 from the
* distances to the corners and take the maximum of 0.0 and the resulting
* values. This sets all the distances that are too close to the corners to 0.
* To set all other values to 1, we can simply take the sign of the values.
Mask := sgn(max2(DistCorner - 7.0,0.0))
* We can now multiply the distances to the rectangle with the mask and
* check whether the maximum distance is smaller than the maximum allowed
* distance of 1.0.
RectangleOK := max(Dist * Mask) <= 1.0
* Display whether the hole is OK.
if (RectangleOK)
dev_set_color ('green')
get_string_extents (WindowHandle, 'OK', Ascent, Descent, Width, Height)
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
write_string (WindowHandle, 'OK')
else
dev_set_color ('red')
get_string_extents (WindowHandle, 'Not OK', Ascent, Descent, Width, Height)
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
write_string (WindowHandle, 'Not OK')
endif
endfor
三 距离计算
PP的距离
* Calculate the distance between two points
*
dev_close_window ()
read_image (Image, 'mreut')
dev_open_window (0, 0, 512, 512, 'white', WindowID)
dev_display (Image)
dev_set_color ('black')
threshold (Image, Region, 180, 255)
* dev_clear_window ()
dev_display (Region)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10000, 100000000)
get_region_contour (SelectedRegions, Rows, Columns)
RowPoint := 80
ColPoint := 250
NumberTuple := |Rows|
dev_set_color ('red')
dev_set_draw ('margin')
* Display a circle that represented one point
gen_circle (Circle, RowPoint, ColPoint, 10)
dev_display (Circle)
dev_set_color ('green')
* Calculate the distance between points of the contour
* of the selected region and the displayed point
for I := 1 to NumberTuple by 10
gen_cross_contour_xld (Cross, Rows[I], Columns[I], 6, 0.785398)
gen_contour_polygon_xld (Contour, [Rows[I],RowPoint], [Columns[I],ColPoint])
dev_set_color ('green')
dev_display (Cross)
dev_set_color ('white')
dev_display (Contour)
distance_pp (RowPoint, ColPoint, Rows[I], Columns[I], Distance)
wait_seconds (0.02)
endfor