实时识别骰子的点数_Halcon

本文就把这种用Halcon编写的实时识别色子点数的算法分享出来
本文会有两个关于图像分割的
核心算法:
距离变换与分水岭算法

distance_transform (ConnectedRegions, DistanceImage, ‘octagonal’, ‘true’, 1000, 1000)

watersheds_threshold (ImageScaleMax, Basins, 10)

识别的效果如下:
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
本文是使用Halcon编写算法,下一篇博客会再提供一篇用开源视觉库OpenCV 编写的算法。


* Image Acquisition 01: Code generated by Image Acquisition 01
dev_close_window ()
dev_open_window (0, 0, 500, 500, 'black', WindowHandle)
*dev_set_draw ('margin')
*dev_set_color ('black')
set_display_font (WindowHandle, 30, 'mono', 'true', 'false')
list_files ('D:/Dices/', ['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)
ResultIndex:=1
for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
    get_image_size (Image, Width, Height)
    threshold (Image, Regions, 180, 255)
    fill_up (Regions, RegionFillUp)
    connection (RegionFillUp, ConnectedRegions)
    distance_transform (ConnectedRegions, DistanceImage, 'octagonal', 'true', 1000, 1000)
    convert_image_type (DistanceImage, ImageConverted, 'byte')
    invert_image (ImageConverted, ImageInvert)
    scale_image_max (ImageInvert, ImageScaleMax)
    *watersheds (ImageScaleMax, Basins1, Watersheds)
    watersheds_threshold (ImageScaleMax, Basins, 10)
    intersection (Basins, ConnectedRegions, RegionIntersection)
    
    select_shape (RegionIntersection, SelectedRegions, 'area', 'and', 30000, 100000)
    count_obj (SelectedRegions, Number)
    dev_display (Image)
    for Index1 := 1 to Number by 1
        select_obj (SelectedRegions, ObjectSelected, Index1)
        reduce_domain (Image, ObjectSelected, ImageReduced)
        threshold (ImageReduced, Regions1, 0, 150)
        fill_up (Regions1, RegionFillUp1)
        connection (RegionFillUp1, ConnectedRegions1)
        select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 200, 20000)
        count_obj (SelectedRegions1, Number1)
        area_center (ObjectSelected, Area, Row, Column)
        disp_message (WindowHandle, Number1, 'image', Row, Column, 'green', 'false')
        
    endfor
*     dump_window_image (Image1, WindowHandle)
*         write_image (Image1, 'jpg', 0, 'D:/Dices/Results/'+ResultIndex+'.jpg')
*         ResultIndex:=ResultIndex+1
    stop()
endfor

感兴趣的可以把数据集下载下来,跑一跑程序,看下效果。
那么下面开始讲解本文的核心算法:
1,
距离变换算法
distance_transform(Region : DistanceImage : Metric, Foreground, Width, Height : )
以下是介绍:

Name
distance_transform — Compute the distance transformation of a region.

Signature
distance_transform(Region : DistanceImage : Metric, Foreground, Width, Height : )

Description
distance_transform computes for every point of the input region Region (or its complement, respectively) the distance of the point to the border of the region. The parameter Foreground determines whether the distances are calculated for all points within the region (Foreground = 'true') or for all points outside the region (Foreground = 'false'). The distance is computed for every point of the output image DistanceImage, which has the specified dimensions Width and Height. The input region is always clipped to the extent of the output image. If it is important that the distances within the entire region should be computed, the region should be moved (see move_region) so that it has only positive coordinates and the width and height of the output image should be large enough to contain the region. The extent of the input region can be obtained with smallest_rectangle1.

The parameter Metric determines which metric is used for the calculation of the distances. If Metric = 'city-block', the distance is calculated from the shortest path from the point to the border of the region, where only horizontal and vertical “movements” are allowed. They are weighted with a weight of 1. If Metric = 'chessboard', the distance is calculated from the shortest path to the border, where horizontal, vertical, and diagonal “movements” are allowed. They are weighted with a weight of 1. If Metric = 'octagonal', a combination of these approaches is used, which leads to diagonal paths receiving a higher weight. If Metric = 'chamfer-3-4', horizontal and vertical movements are weighted with a weight of 3, while diagonal movements are weighted with a weight of 4. To normalize the distances, the resulting distance image is divided by 3. Since this normalization step takes some time, and one usually is interested in the relative distances of the points, the normalization can be suppressed with Metric = 'chamfer-3-4-unnormalized'. Finally, if Metric = 'euclidean', the computed distance is approximately Euclidean.

Execution Information
Multithreading type: reentrant (runs in parallel with non-exclusive operators).
Multithreading scope: global (may be called from any thread).
Processed without parallelization.
Parameters
Region (input_object)  region(-array) → object
Region for which the distance to the border is computed.

DistanceImage (output_object)  image → object (int4)
Image containing the distance information.

Metric (input_control)  string → (string)
Type of metric to be used for the distance transformation.

Default value: 'city-block'
List of values: 'chamfer-3-4', 'chamfer-3-4-unnormalized', 'chessboard', 'city-block', 'euclidean', 'octagonal'
Foreground (input_control)  string → (string)
Compute the distance for pixels inside ('true') or outside ('false') the input region.

Default value: 'true'
List of values: 'false', 'true'
Width (input_control)  extent.x → (integer)
Width of the output image.

Default value: 640

Suggested values: 160, 192, 320, 384, 640, 768

Typical range of values: 1 ≤ Width

Height (input_control)  extent.y → (integer)
Height of the output image.

Default value: 480

Suggested values: 120, 144, 240, 288, 480, 576
Typical range of values: 1 ≤ Height

看不懂没关系,本文会以图示分析该算法,直观明了:
距离变换算法计算的是传入该算法的每个不联通的区域里的每个点到该区域边缘的最近距离,计算方式常用的方式是
‘chamfer-3-4’, ‘chamfer-3-4-unnormalized’, ‘chessboard’, ‘city-block’, ‘euclidean’, ‘octagonal’
‘city-block’:水平垂直方向
‘chessboard’: 水平垂直方向+对角线四个方向
‘octagonal’: 正八边形八个方向,如下图:
在这里插入图片描述
就是这画红线的八个方向。
关于算法的原理,如下:
在这里插入图片描述
比如说,这个不规则的多边形是我传入给算法的其中一个区域,
那么其中的红点是我要计算的距离值,
显而易见,这条最短距离如下:
在这里插入图片描述
那么,该最短距离就会传给这个像素的值。
在实际运行中,该算法的工作效果如下:
在这里插入图片描述
在这里插入图片描述
上面这些不同颜色的框框是传进去的各个区域,连通域已被打散。
得出来的这些亮亮的点就是结果,最亮代表该点离边缘的距离越大,反映在8位图像上也就是最亮。
经过图像格式转换就会变成下面的样子:
在这里插入图片描述

这就会为下面的联通域的分水岭的算法做出铺垫。
下面开始讲解分水岭算法阈值分割:

watersheds_threshold (Operator)
Name
watersheds_threshold — Extract watershed basins from an image using a threshold.

Signature
watersheds_threshold(Image : Basins : Threshold : )

Description
The operator watersheds_threshold segments regions (basins) that are separated from each other by a watershed that has a height of at least Threshold.

In the first step, watersheds_threshold computes the watersheds without applying a threshold, resulting in the same basins that would be obtained when calling watersheds (for more details please refer to the description of watersheds). In the second step, the basins are successively merged if they are separated by a watershed that is smaller than Threshold. Let B1 and B2 be the minimum gray values of two neighboring basins and W the minimum gray value of the watershed that separates the two basins. The watershed is eliminated and the two basins are merged if
max{
    
     W - B1 , W - B2 } < Threshold
The thus obtained basins are returned in Basins.

If Threshold is set to 0, watersheds_threshold is comparable to watersheds except that no watersheds but only expanded basins are returned. If Threshold is set to the maximum gray value range of Image then no two basins are separated by a watershed exceeding Threshold, and hence, Basins will contain only one region.
Execution Information
Multithreading type: reentrant (runs in parallel with non-exclusive operators).
Multithreading scope: global (may be called from any thread).
Processed without parallelization.
Parameters
Image (input_object)  singlechannelimage → object (byte / uint2 / real)
Image to be segmented.

Basins (output_object)  region-array → object
Segments found (dark basins).

Threshold (input_control)  number → (integer / real)
Threshold for the watersheds.

Default value: 10

Suggested values: 0, 5, 10, 20, 30, 50

Restriction: Threshold >= 0

看不懂没关系,下面图示讲解:
那么字如其名,将图像看成地理上的地形地貌,
该立体图可以如下所示:
在这里插入图片描述
在这里插入图片描述
该立体图对应的是那张经过距离变换的图像:
在这里插入图片描述
分水岭嘛,就是在峡谷最低哇处开口注水,然后地形地貌高耸的地方就会形成大坝,或者说是一条条脊。
详细理论讲解可以看该博客图像处理——分水岭算法

https://blog.csdn.net/fengye2two/article/details/79116105
或者教材,《数字图像处理》冈萨雷斯版
然后加上阈值分割:具体图示如下:
请添加图片描述
算法的原文讲解其实是和以上图示是一样的。
运行我的程序,
你就会看到,识别效果很完美。

おすすめ

転載: blog.csdn.net/m0_47472749/article/details/120185047