Halcon line_scan.hdev 例程解析
【以上图片来自halcon运行过程】
line_scan.hdev这个例程很有意思,它模拟读取线扫相机生成的行数较少的条形图片,然后对图片进行简单的拼接,并对图中的对象进行region提取、合并。
* general configuration of HDevelop
dev_update_window ('off')
dev_set_color ('red')
stop ()
* ------------------- start of the application ----------------
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'clips/clips.seq', 'default', -1, -1, AcqHandle)
grab_image (Image, AcqHandle)
get_image_pointer1 (Image, Pointer, Type, ImageWidth, ImageHeight)
* step 1: initial configuration before starting the loop
* -> the clips can extend over 4 images
MaxImagesRegions := 4
* -> create an empty image to which grabbed images are tiled later
gen_image_const (TiledImage, 'byte', ImageWidth, ImageHeight * MaxImagesRegions)
* -> so far no regions have been extracted
gen_empty_region (PrevRegions)
ClipsProcessedSofar := 0
* -> open a window large enough for the current and the previous 4 images
dev_close_window ()
dev_open_window (0, 0, ImageWidth / 2, ImageHeight * (MaxImagesRegions + 1) / 2, 'gray', WindowHandle)
stop ()
第一步的代码主要是一些图像的读取和变量准备、显示窗口的准备工作,要点如下:
使用了索引文件clips.seq来作为图像的采集接口;
设定最大的图像保留数量为4,就该例程所针对的对象而言,同一个回形针最多出现在四幅连续的图像中,因此这个设定已经足够;
设定了一个变量用来存储已经被处理的前序regions,即PrevRegions;
设定一个计数器用于计量已被处理的图像数量;
设定显示窗口为实际图像宽度的一半*实际图像高度的2.5倍(即5倍单张图片高度)。
* step 2: process images in a loop
while (1)
* -> the current image is displayed at the bottom of the window
dev_set_part (-MaxImagesRegions * ImageHeight, 0, ImageHeight - 1, ImageWidth - 1)
grab_image (Image, AcqHandle)
threshold (Image, CurrRegions, 0, 80)
* -> after this operator, PrevMergedRegions are "finished" and can be processed
merge_regions_line_scan (CurrRegions, PrevRegions, CurrMergedRegions, PrevMergedRegions, ImageHeight, 'top', MaxImagesRegions)
connection (PrevMergedRegions, ClipCandidates)
select_shape (ClipCandidates, FinishedClips, 'area', 'and', 4500, 7000)
* -> if the clips are to be displayed together with the unfinished regions, they
* must be moved to the coordinate system of the current image
move_region (FinishedClips, ClipsInCurrentImageCoordinates, -ImageHeight, 0)
* => enable the following lines to display the "finished" and current regions together
* dev_clear_window ()
* dev_display (Image)
* dev_set_color ('blue')
* dev_display (CurrMergedRegions)
* dev_set_color ('yellow')
* dev_display (ClipsInCurrentImageCoordinates)
* stop ()
* -> the tiled image is displayed at the top of the window
dev_set_part (0, 0, (MaxImagesRegions + 1) * ImageHeight - 1, ImageWidth - 1)
* -> move the clips from the coordinates of the most recent image to those of the tiled image
move_region (FinishedClips, ClipsInTiledImageCoordinates, (MaxImagesRegions - 1) * ImageHeight, 0)
count_obj (FinishedClips, NumberClips)
ClipsProcessedSofar := ClipsProcessedSofar + NumberClips
* -> determine position and orientation
area_center (ClipsInTiledImageCoordinates, AreaClips, RowClips, ColumnClips)
orientation_region (ClipsInTiledImageCoordinates, PhiClips)
* -> add gray values of the surrounding rectangles
shape_trans (ClipsInTiledImageCoordinates, AroundClips, 'rectangle1')
add_channels (AroundClips, TiledImage, GrayValuesAroundClips)
* visualization
dev_clear_window ()
dev_display (GrayValuesAroundClips)
for i := 0 to NumberClips - 1 by 1
disp_arrow (WindowHandle, RowClips[i], ColumnClips[i], RowClips[i] - sin(PhiClips[i]) * 140, ColumnClips[i] + cos(PhiClips[i]) * 140, 2)
endfor
set_tposition (WindowHandle, 10, 12)
if (ClipsProcessedSofar == 13)
ClipsProcessedSofar := 0
write_string (WindowHandle, 'All 13 clips have been processed')
else
write_string (WindowHandle, 'Clips processed so far: ' + ClipsProcessedSofar)
endif
* -> the current image is displayed at the bottom of the window
dev_set_part (-MaxImagesRegions * ImageHeight, 0, ImageHeight - 1, ImageWidth - 1)
dev_display (Image)
dev_set_color ('blue')
dev_display (CurrMergedRegions)
stop ()
* prepare for the next iteration
copy_obj (CurrMergedRegions, PrevRegions, 1, -1)
* -> the tiled image is displayed at the top of the window
dev_set_part (0, 0, (MaxImagesRegions + 1) * ImageHeight - 1, ImageWidth - 1)
* -> cut off the oldest image from the top of the tiled image ...
crop_part (TiledImage, TiledImageMinusOldest, ImageHeight, 0, ImageWidth, (MaxImagesRegions - 1) * ImageHeight)
* -> ... and add the current image at the bottom
concat_obj (TiledImageMinusOldest, Image, ImagesToTile)
tile_images_offset (ImagesToTile, TiledImage, [0,(MaxImagesRegions - 1) * ImageHeight], [0,0], [-1,-1], [-1,-1], [-1,-1], [-1,-1], ImageWidth, MaxImagesRegions * ImageHeight)
endwhile
stop ()
第二步的代码是采用循环来处理图片,要点如下:
采用dev_set_part控制显示窗口,令其可以显示五张图片的大小,即从-4*图像高度显示到1*图像高度的区域;
采用merge_regions_line_scan算子对连续两张图片得到的region区域进行合并和保留(关于该算子的使用方法请详见另一篇博文),执行对第一张图片的处理时,没有前序图片的相关区域;
对当前图片中灰度为0-80的区域进行提取,得到回针的region;
每次处理完一幅图片的内容后,将该幅图片中,面积在4500到7000之间的region找出来(因为一个完整的回形针其region大小大约为6200左右,这也要求回形针的region大小基本一致,且不能有两枚回形针边界发生粘黏),并通过move_region的方式移动该region到当前图像的上方区域;
统计找到的完整回形针个数,并进行数量统计;
使用tile_image_offset算子来进行前后图像的拼接;
判断回形针的方向,用shape_trans将回形针的区域切割出来,并由add_channels算子把图像填充到区域中,计算出回形针的方向,再将方向的箭头显示出来。
小结:
1. merge_regions_line_scan算子能够对前后相接的连续图片间,判断提取到的regions是否在边界处有连通关系,从而将连续帧中的同一物体进行合并提取;
2. 通过move_regions和tile_image_offset算子进行regions的移动和图像的合并。