Halcon 《机器视觉算法及应用》十例(其二)
**此程序演示了如何使用极性转换来校正CD上的序列号。 可以使用OCR读取矫正后的数字。**初始化dev_update_off ()read_image (Image, 'cd_print')dev_close_window ()dev_open_window_fit_image (Image, 0, 0, 640, 480, WindowHandle) //打开一个新的图形窗口,该窗口保留给定图
***该实例采用:名场漫反射正面照明
**此程序演示了如何使用极性转换来校正CD上的序列号。 可以使用OCR读取矫正后的数字。
*
*初始化
dev_update_off ()
read_image (Image, 'cd_print')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, 640, 480, WindowHandle) //打开一个新的图形窗口,该窗口保留给定图像的纵横比(aspect ratio) 。
get_image_size (Image, Width, Height)
dev_set_draw ('margin')
dev_set_line_width (2)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
Pi := rad(180)
*
* 初始化变量
AnnulusInner := 0.90
AnnulusOuter := 0.99
这里假设:环面的内径和外径与外边界半径之比是恒定的,在此是0.90和0.99,这样可以做到尺度不变性。
CharWidthFraction := 0.01
*
* 分割外圆
mean_image (Image, ImageMean, 51, 51) //均值滤波
dyn_threshold (Image, ImageMean, RegionDynThresh, 15, 'dark') //动态阈值分割 https://blog.csdn.net/qq_20161893/article/details/51072354
dyn_threshold(OrigImage,ThresholdImage : RegionDynThresh :Offset,LightDark : )
offset设定邻域比较的区间范围,灰度值变化在offset范围内均是可以接受的。令 g_{o} = g_{OrigImage}, g_{t} = g_{ThresholdImage}分别代表原图和参考图中的像素点的灰度值.我们的做法是把参考图像的灰度值加上(减去)一个Offset,然后去和原图的像素点逐像素对应地进行比较。下面看Halcon中给出的这些公式:
The condition for LightDark = 'light' is:g_o>=g_t+offset ,light就提取相对参考图更亮的区域。
For LightDark='dark' ,the conditon is: g_o<=g_t-offset ,dark就提取相对参考图更暗的区域
For LightDark='equal',g_t-offset<=g_o<=g_t+offset,选取和参考图差不多的区域。
fill_up (RegionDynThresh, RegionFillUp) //填充区域中的孔
gen_contour_region_xld (RegionFillUp, ContourBorder, 'border') //从区域RegionFillUp中给的区域生成XLD轮廓
fit_circle_contour_xld (ContourBorder, 'ahuber', -1, 0, 0, 3, 2, CenterRow, CenterColumn, Radius, StartPhi, EndPhi, PointOrder) //拟合圆
dev_display (Image)
dev_set_color ('green')
dev_display (ContourBorder)
dev_disp_text ('Segmented circle', 'window', 12, 12, 'black', [], [])
dev_disp_text ('Press Run (F5) to continue', 'window', 'bottom', 'right', 'black', [], [])
stop ()
*
* 将带有字符的环转换为极坐标
WidthPolar := 2 * Pi * Radius * AnnulusOuter //极坐标的宽
HeightPolar := Radius * (AnnulusOuter - AnnulusInner) //极坐标的高
RadiusStart := Radius * AnnulusOuter //极径的开始
RadiusEnd := Radius * AnnulusInner //极径的结束
AngleStart := 2 * Pi - 2 * Pi / WidthPolar //角度开始
AngleEnd := 0 //角度结束
1、起始半径对应环面的外边界,而结束半径对应环面的内边界,这样保证变换后图像上的字符向上。
2、极坐标变换是逆时针的,所以需要使结束的角度小于开始的角度,以保证字符从左向右。最后为了避免变换后图像第一列与最后一列一样,变换时不含最后一个离散角。
polar_trans_image_ext (Image, PolarTransImage, CenterRow, CenterColumn, AngleStart, AngleEnd, RadiusStart, RadiusEnd, WidthPolar, HeightPolar, 'bilinear') //将图像中的圆弧转换为极坐标 https://blog.csdn.net/m0_37706292/article/details/89138568 关键点在于极坐标系原点的选取以及起始角度的设置
dev_resize_window_fit_image (PolarTransImage, 0, 0, 1000, 1000) // 用保持给定图像长宽比的最大最小尺寸来更改图形窗口大小
dev_display (PolarTransImage)
stop ()
*
* 分割字符
CharWidth := WidthPolar * CharWidthFraction //计算字符的大致尺寸
CharHeight := CharWidth //计算字符的大致尺寸
mean_image (PolarTransImage, ImageMean, 2 * CharWidth, 2 * CharHeight) //均值滤波,使用比字符本身大2倍的滤波器
dyn_threshold (PolarTransImage, ImageMean, RegionThreshold, 10, 'dark') //动态阈值滤波
connection (RegionThreshold, ConnectedRegions) //连通区域
select_shape (ConnectedRegions, RegionChar, ['height','width','row'], 'and', [CharHeight * 0.1,CharWidth * 0.3,HeightPolar * 0.25], [CharHeight * 1.1,CharWidth * 1.1,HeightPolar * 0.75]) //选择轮廓特征 https://blog.csdn.net/a623406978/article/details/76651419
本算子使用三个区域特征:区域高度、区域宽度、区域重心纵向坐标
(1)高度的最小值必须设置的相对很小,因为需要分割出序列中的连字号
(2)宽度的最小值也需要设置的很小,因为分割“I”个“1”这样的字符,最大值比字符尺寸稍大
(3)重心在变换后的图像纵向中心左右,但在需要读取“.”和“,”时没用意义
sort_region (RegionChar, RegionCharSort, 'character', 'true', 'row') //区域排序
dev_set_colored (12)
dev_display (PolarTransImage)
dev_display (RegionCharSort)
stop ()
*
*读取特征
read_ocr_class_mlp ('Industrial_Rej.omc', OCRHandle) //读取halcon自带模型:Industrial_Rej.omc
do_ocr_multi_class_mlp (RegionCharSort, PolarTransImage, OCRHandle, Class, Confidence) //输入字符排序、极坐标图像、mlp分类模型,输出字符分类、置信度
* Concatenate the single characters to one string
SNString := sum(Class)
*
* 可视化结果
dev_resize_window_fit_image (Image, 0, 0, 640, 480)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
dev_disp_text ('S/N: ' + SNString, 'window', 12, 12, 'black', [], [])
polar_trans_region_inv (RegionCharSort, XYTransRegion, CenterRow, CenterColumn, AngleStart, AngleEnd, RadiusStart, RadiusEnd, WidthPolar, HeightPolar, Width, Height, 'nearest_neighbor')
将极坐标中的区域转换回笛卡尔坐标。
dev_set_colored (12)
dev_display (XYTransRegion)
*
* 清除分类
clear_ocr_class_mlp (OCRHandle)
dev_disp_text (' End of program ', 'window', 'bottom', 'right', 'black', [], [])
参考:
几种滤波器(均值滤波、中值滤波、高斯滤波、拉普拉斯)
https://www.cnblogs.com/gspuser/p/13473701.html
值得借鉴之处:
1.互为逆算子:
polar_trans_image_ext 笛卡尔坐标 ==》 极坐标
polar_trans_region_inv 极坐标 ==》 笛卡尔坐标
2.将单个字符分割:动态阈值分割方法
mean_image (PolarTransImage, ImageMean, 2 * CharWidth, 2 * CharHeight) //均值滤波
dyn_threshold (PolarTransImage, ImageMean, RegionThreshold, 10, 'dark') //动态阈值滤波
connection (RegionThreshold, ConnectedRegions) //连通区域
3.字符识别:
read_ocr_class_mlp ('Industrial_Rej.omc', OCRHandle) //读取模型
do_ocr_multi_class_mlp (RegionCharSort, PolarTransImage, OCRHandle, Class, Confidence) //识别字符
4.字符分割还可以使用segment_characters 算子
segment_characters(ImageMean, PolarTransImage, ImageForeground, RegionForeground, 'local_auto_shape', 'false', 'false', 'bold', 22, 22, 0, 10, UsedThreshold)
select_characters(RegionForeground, RegionChar, 'false', 'bold', 25, 25, 'false', 'false', 'none', 'false', 'medium', 'false', 0, 'completion')//单字符选择
* closing_circle(RegionForeground, RegionClosing, 2) //单字符选择还可以用闭运算+连通域
* connection(RegionClosing, ConnectedRegions)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)