失败笔记本-HALCON篇-002
项目场景:
现在有一张图片如下:
要用HALCON检测出图片左侧尺子的边(直线),中间工件的方孔(矩形),右侧两个工件的轮廓和位置(圆形和圆心)。这是在水下拍摄的一张图片,图片中背景很杂乱,干扰很多,光照也不足。这是一个比较复杂的工程,让我们先来问问ChatGPT有什么样的建议:
假设你是一个资深的HALCON工程师,现在你遇到了这样一个任务,需要你检测出一张水下图片中的尺子边缘(直线),工件方孔(矩形),空心圆工件边缘和位置(圆形大小和圆心位置)。但是这张图片的质量较差(相对于图像处理来说),背景很杂乱,干扰很多,光照也不足,工件上还有反光和光晕,你会怎么做呢?
要在质量较差、背景杂乱、干扰多、光照不足且有反光和光晕的水下图片中检测尺子边缘、方孔、空心圆工件的边缘和位置,需要综合运用HALCON的图像处理功能。以下是一个详细的步骤:
图像预处理:
去噪:使用高斯滤波、中值滤波等方法对图像进行平滑处理,减少噪声。
增强对比度:使用直方图均衡化或自适应对比度增强技术(如CLAHE)来改善图像对比度。
光照补偿:通过局部对比度增强或者使用背景减除的方法来均衡光照。
反光和光晕处理:
反射去除:可以通过多尺度Retinex算法或基于反射模型的算法来减少图像中的反光和光晕影响。
边缘检测:
边缘增强:使用Sobel、Canny等边缘检测算子来突出图像中的边缘。
阈值分割:自适应阈值或Otsu方法可以帮助分割出可能的目标边缘区域。
形状检测:
直线检测:使用Hough变换检测尺子的边缘直线。
矩形检测:通过区域增长或形态学操作(如闭运算)先提取潜在的方孔区域,然后使用最小外接矩形法检测矩形。
圆形检测:使用Hough圆变换检测空心圆工件的边缘和位置。
验证和细化:
形状匹配:基于几何模型匹配或者模板匹配方法来验证和细化检测结果。
排除错误检测:通过形状和尺寸约束来排除误检测。
步骤实现细节:
使用gauss_image或median_image函数进行平滑处理。
使用equalize_histogram或clahe函数进行对比度增强。
使用dyn_threshold或local_deviation函数进行光照补偿。
使用edges_sub_pix函数进行亚像素级别的边缘检测。
使用hough_lines和hough_circle函数进行直线和圆的检测。
使用select_shape函数基于形状特征(如面积、长宽比)筛选目标区域。
使用find_shape_model或find_shape_model_3d进行形状匹配和细化。
还给出了参考的代码:
read_image (Image, 'underwater_image.jpg')
* 图像预处理
gauss_image(Image, SmoothedImage, 3)
equalize_histogram(SmoothedImage, EnhancedImage)
* 反光和光晕处理
* 使用Retinex算法或其他方法处理反光问题(假设实现为 Retinex)
* 边缘检测
edges_sub_pix(EnhancedImage, Edges, 'canny', 1, 20, 40)
* 直线检测
lines_gauss (Edges, Lines, 1, 20, 40, 'light', 'false', 'true', 'false')
* 矩形检测
* 区域检测并形态学处理
threshold(EnhancedImage, Regions, 128, 255)
connection(Regions, ConnectedRegions)
select_shape(ConnectedRegions, Rectangles, 'rectangularity', 'and', 0.9, 1.0)
* 圆形检测
hough_circle(Edges, Circles, 10, 100)
* 结果显示和验证
dev_display(EnhancedImage)
dev_set_color('green')
dev_display(Lines)
dev_set_color('blue')
dev_display(Rectangles)
dev_set_color('red')
dev_display(Circles)
ok,ChatGPT给出了一个大致的思路,打开图片–过滤噪声–对比度增强–去除反射–边缘检测–形状识别。
让我们参考给出的示例程序来试一试:(我只能说这波GPT是错的)
1.图像预处理
分析:
在这一部分,我们要先打开图片,然后转换灰度,高斯滤波一番,进行图像的直方图均衡化处理。
使用以下代码:
rgb1_to_gray (Image, GrayImage)
gauss_image (GrayImage, ImageGauss, 3)
equalize_histogram(SmoothedImage, EnhancedImage)
出现问题:
- 首先是gauss_image()算子报警告:
- 其次居然出现了equalize_histogram()是未知算子的错误!
问题分析:
- gauss_image()算子报警告是因为在Halcon低版本中使用的是gauss_image,gauss_image已经过时,仅出于向后兼容的原因提供。新应用程序应改用gauss_filter算子,参考大神回答解决:Halcon图像处理基础篇,gauss_image/gauss_filter
- 在HALCON中直方图均衡化的算子是equ_histo_image(),参考大神回答解决:Halcon图像处理基础篇,gauss_image/gauss_filter
解决方案:
当然是把程序中使用错误的算子进行改正:
rgb1_to_gray (Image, GrayImage)
gauss_image (GrayImage, ImageGauss, 3)
equ_histo_image(ImageGauss, EnhancedImage)
进行了这三步操作后,图片效果如下:
观察效果:较暗的地方突出了,希望特征能够顺利提取出来。预处理这里还有可以尝试的手段:如使用 emphasize() 或者illuminate() 增强图像的高频区域(边缘和拐角),使图像看起来更清晰。
2.边缘检测
分析:
使用代码:
edges_sub_pix (EnhancedImage, Edges, 'canny', 1, 20, 40)
效果如下:
哎呀,感觉有戏啊。参数的调整后面再说,让我们先把流程做完。
3.直线检测
分析:
使用代码:
lines_gauss (Edges, Lines, 1, 20, 40, 'light', 'false', 'true', 'false')
出现问题:
ok,直接报错了啊,Image data management: wrong object-ID (HALCON错误代码: 4052)。
问题分析:
寻求大佬帮助,啊原来是因为算子的第一个参数是xld格式的,参考大佬回答:HALCON错误代码: 4052。
查看lines_gauss()算子的介绍:halcon lines_gauss算子详解
Image (input_object) :输入图像
Lines (output_object) :检测线条(XLD)
Sigma (input_control) :高斯滤波值
Low (input_control) :滞后阈值分割的低阈值
High (input_control) :滞后阈值分割的高阈值
LightDark (input_control) :提取线条类型( ‘dark’,‘light’)
ExtractWidth (input_control) :是否提取线宽(‘false’,‘true’)
LineModel (input_control) :用来调整线条位置和宽度的线模型(‘bar-shaped’, ‘gaussian’, ‘none’, ‘parabolic’)
CompleteJunctions (input_control) :在断连的部分是否添加节点使线条连续(‘false’, ‘true’)
这样看来在上一步canny检测之后的输出结果是XLD轮廓,在Halcon中,使用XLD表示亚像素的轮廓和多边形。常用edges_sub_pix算子来提取亚像素轮廓(halcon中XLD的概念及算子应用)。
解决方案:
可以试着对XLD轮廓直接进行操作:
- 借鉴大佬的教程:Halcon 第四章『图像特征和提取』◆第5.3节:XLD轮廓处理—分割、筛选、连接or拟合
问题还是存在的,这样的场景下轮廓线杂乱无章,较难提取有用的特征,我希望画面还是要干净一些才行。
3.再次直线检测
分析:
矩形检测中没有使用xld轮廓,我们先进行矩形的检测试试看,使用代码:
threshold(EnhancedImage, Regions, 0, 143)
connection(Regions, ConnectedRegions)
select_shape(ConnectedRegions, Rectangles, 'rectangularity', 'and', 0.9, 1.0)
效果如下:
好好好,突然把左侧尺子边缘测出来了,那么思路来了,如果能把上图右侧蓝色区域补起来,那么尺子两个边就都能检测到。
- 我们先fill_up()一步,填充效果较差
- 那就使用shape_trans(),强行将其补成矩形
- 再用图片高度条件筛选
代码如下:
connection(Regions, ConnectedRegions)
shape_trans (ConnectedRegions, RegionTrans, 'rectangle1')
select_shape(RegionTrans, Rectangles, 'height', 'and', Height, Height)
效果如下:
但是这样的弊端很大,尺子的一部分被遮盖了起来,测出来的其实不是真实边缘:
4.圆形检测
这个直线检测是真难啊,暂时没有什么好的办法,我们先对俩圆进行检测:
- 先提取ROI,参考Halcon图像预处理-感兴趣区域(ROI)
我们使用 gen_rectangle1()算子和reduce_domain()算子对图片进行裁剪,只提取有圆形的区域。 - 然后我们进行二值化;
- 按照面积筛选;
- 取最小外接圆。
效果如下:
ok,看着非常不错。
5.矩形检测
ok,最后是矩形的检测,让我们复制检测圆形的思路:
- 先提取ROI
- 二值化
- 填充后分离形状
- 形状修正为内接矩形
出现问题:
咋就是说,其实问题很大,转化出来的内接矩形其实是不准的,识别的形状它很不规则,如下图所示:
救命啊,这个怎么能修正为正好合适的规则矩形呢,用外接矩形转换太大,内接矩形又太小。
6.输出结果显示在图片上
okk,最后我们把这俩圆的圆点坐标和半径求出来,标在图片上:
- 先求圆心坐标和半径,参考大佬的代码:halcon 寻找圆 半径和圆心
- 然后在图片上绘制点和线,
- 这里是在窗体上绘制的教程:温故而知新(一)Halcon 画线,虚线,圆,矩形
这是手动绘制点和线等形状。 - ok,原来是可以先创建region,然后用paint_region()算子:Halcon中Region绘制到图像方法–paint_region()
- 最后把文字信息显示上来。
欧克,结果如下:
注意:
很曲折好不好,添加点和线是在图片上添加的,先画了一个region然后添加在图片上,而添加文字是添加在窗口,用了外部算子,代码如下:(真心觉得这些操作没有OpenCV方便呢?)
gen_circle (Circle, Row, Column, 2)
paint_region (Circle, Image, ImageResult, [0, 255, 0], 'fill')
gen_region_line (RegionLines, Row-Radius, Column-Radius, Row+Radius, Column-Radius)
gen_region_line (RegionLines1, Row-Radius, Column+Radius, Row+Radius, Column+Radius)
paint_region (RegionLines, ImageResult, ImageResult1, [0, 255, 0], 'fill')
paint_region (RegionLines1, ImageResult1, ImageResult2, [0, 255, 0], 'fill')
font_name :='Courier'
font_size := 20
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_display (ImageResult2)
disp_message (WindowHandle, '半径:' + Radius +'\n圆心坐标:(' + Row +',' + Column +')' , 'image', Row+Radius, Column+Radius, 'green', 'false')
总结:
好好好,在002中,首先复习了001中的颜色反转操作,学到了HALCON中有region和XLD的区别,小东西花样还挺多。这个项目做的很差,练习时长两周半的我要再想想其他办法搞一下。