3. 图像采集与读取
在机器视觉项目中,图像采集与读取是连接物理世界与算法处理的第一道桥梁。无论后续的定位、测量、缺陷检测算法多么精妙,如果图像采集环节出现丢帧、格式错乱、灰度失真或噪声过大,整个视觉系统的稳定性都将无从谈起。本章围绕 Halcon 环境下的图像获取链路,系统讲解相机连接方式、文件读取策略、格式转换规则以及预处理的基本方法,帮助学习者建立从“硬件触发”到“内存图像”再到“可分析图像”的完整认知。
一、核心原理:图像数据在 Halcon 中的表示与流转
Halcon 使用 HImage 对象(对应底层 Hobject)来承载图像数据。一个图像对象不仅包含像素矩阵,还携带通道数、位深、宽高、区域信息等元数据。理解图像在内存中的组织方式是后续所有操作的基础。
图像采集的核心原理涉及三个层面:
- 物理层:相机通过 GigE Vision、USB3 Vision、Camera Link 或 GenICam 协议将光信号转换为数字信号,并传输到主机内存。
- 驱动层:Halcon 通过接口算子(如
open_framegrabber)加载对应厂商的采集驱动,建立与相机的通信会话。 - 应用层:开发者通过
grab_image或grab_image_async从采集队列中获取一帧图像,并将其转换为 Halcon 内部格式。
对于图像文件读取,Halcon 支持 BMP、JPEG、PNG、TIFF、JPEG 2000 等常见格式,也支持多页 TIFF 和图像序列。读取时需注意:JPEG 是有损压缩,会引入块效应;PNG 支持无损压缩和 Alpha 通道;TIFF 可保存多帧或 16 位深度数据。Halcon 的 read_image 算子会自动识别文件头并解析格式,但开发者仍需关注位深和通道数的隐式转换。
关键认知:Halcon 中图像坐标系原点位于左上角,行坐标(Row)向下增长,列坐标(Column)向右增长。这与许多数学坐标系不同,在后续 ROI 选取和结果显示时需时刻注意。
二、方法流程:从相机连接到图像预处理的标准路径
一个完整的图像获取与预处理流程通常包含以下步骤。下面以 GigE 工业相机为例,给出标准流程。
2.1 相机连接与参数配置
Halcon 通过 open_framegrabber 建立与相机的连接。该算子需要指定采集接口、设备编号、色彩模式、位深、触发模式等参数。以下为典型代码:
* 打开 GigE 相机,设备编号 0,彩色 RGB,8 位深度
open_framegrabber ('GigEVision', 0, 0, 0, 0, 0, 0, 'default', -1, 'default', -1, 'false', 'default', 'cam0', 0, -1, AcqHandle)
* 设置曝光时间(微秒)
set_framegrabber_param (AcqHandle, 'ExposureTime', 5000.0)
* 设置增益
set_framegrabber_param (AcqHandle, 'Gain', 1.5)
* 设置触发模式为软触发
set_framegrabber_param (AcqHandle, 'TriggerMode', 'On')
set_framegrabber_param (AcqHandle, 'TriggerSource', 'Software')
连接成功后,使用 grab_image 同步采集一帧,或使用 grab_image_async 启动异步连续采集。异步采集可避免因图像处理耗时导致的丢帧,适合高速产线。
2.2 图像文件读取与格式转换
当相机不可用或需要离线调试时,从文件读取图像是常用手段。Halcon 提供 read_image 算子,支持单张和多张读取:
* 读取单张图像
read_image (Image, 'D:/images/part_001.png')
* 读取多页 TIFF 中的第 3 帧
read_image (ImageTiff, 'D:/images/stack.tiff', 3)
* 读取图像序列(文件名带数字编号)
read_image (ImageSeq, 'D:/images/part_00' + Index + '.png')
格式转换是图像处理中高频操作。Halcon 提供 convert_image_type 用于位深转换,change_domain 用于改变图像域,rgb1_to_gray 用于彩色转灰度。以下为常见转换场景:
* 彩色转灰度(加权法:0.299R + 0.587G + 0.114B)
rgb1_to_gray (ImageColor, ImageGray)
* 将 16 位图像转为 8 位(自动缩放或截断)
convert_image_type (Image16, Image8, 'byte')
* 将图像从 RGB 转为 HSV 色彩空间
trans_from_rgb (ImageColor, ImageH, ImageS, ImageV, 'hsv')
经验提示:当从 16 位转 8 位时,默认采用截断方式,即超过 255 的像素值被置为 255。若图像动态范围较窄,建议先使用 scale_image 或 min_max_gray 获取实际灰度范围,再做线性拉伸,避免信息丢失。
2.3 预处理基础操作
预处理的目标是改善图像质量,为后续特征提取创造有利条件。常用操作包括:
- 去噪:
median_image(中值滤波)去除椒盐噪声,gauss_filter(高斯滤波)平滑图像。 - 对比度增强:
scale_image(灰度拉伸)、equ_histo_image(直方图均衡化)。 - 形态学操作:
gray_opening、gray_closing用于去除亮/暗细节。 - ROI 裁剪:
reduce_domain将处理区域限定在感兴趣区域,减少计算量。
* 中值滤波去除噪声(掩膜大小 5x5)
median_image (ImageGray, ImageMedian, 'circle', 5, 'mirrored')
* 高斯滤波平滑
gauss_filter (ImageMedian, ImageSmooth, 3)
* 灰度线性拉伸,增强对比度
min_max_gray (ImageSmooth, ImageSmooth, 0, 10, Min, Max, Range)
scale_image (ImageSmooth, ImageScaled, 255.0 / (Max - Min), -255.0 * Min / (Max - Min))
* 裁剪 ROI
gen_rectangle1 (ROI, 100, 200, 400, 600)
reduce_domain (ImageScaled, ROI, ImageROI)
三、案例场景:产线相机连接与离线图像批处理
以下通过两个典型场景,展示上述方法的综合应用。
3.1 场景一:在线相机实时采集与显示
某电子元件装配线需要检测引脚是否缺失。相机安装于传送带上方,采用软触发模式,每次到位信号触发一次采集。代码如下:
open_framegrabber ('GigEVision', 0, 0, 0, 0, 0, 0, 'default', -1, 'default', -1, 'false', 'default', 'cam_pin', 0, -1, AcqHandle)
set_framegrabber_param (AcqHandle, 'ExposureTime', 8000.0)
set_framegrabber_param (AcqHandle, 'Gain', 1.0)
for i := 1 to 100 by 1
* 等待外部触发信号
set_framegrabber_param (AcqHandle, 'TriggerSoftware', 1)
grab_image (Image, AcqHandle)
* 实时显示
dev_display (Image)
* 预处理:灰度化 + 中值滤波
rgb1_to_gray (Image, ImageGray)
median_image (ImageGray, ImageDenoised, 'circle', 3, 'mirrored')
* 后续检测步骤(略)
endfor
close_framegrabber (AcqHandle)
该场景中,grab_image 为阻塞式采集,若图像处理耗时超过帧间隔,会丢失触发信号。此时应改用 grab_image_async 并设置合理的队列长度。
3.2 场景二:离线批量读取与格式统一
在算法开发阶段,工程师常需要处理一批来自不同相机的历史图像。这些图像可能包含 8 位灰度、24 位彩色、16 位深度等不同格式。统一格式是保证算法稳定性的前提。
list_files ('D:/defect_samples', 'files', ImageFiles)
tuple_regexp_select (ImageFiles, '.*\\.(png|bmp|tif)$', SelectedFiles)
for i := 0 to |SelectedFiles| - 1 by 1
read_image (Image, SelectedFiles[i])
* 获取图像通道数和位深
get_image_pointer1 (Image, Pointer, Type, Width, Height)
* 统一转为 8 位灰度
if (Type == 'uint2')
convert_image_type (Image, ImageByte, 'byte')
endif
if (Type == 'real')
scale_image (Image, ImageScaled, 1.0, 0)
convert_image_type (ImageScaled, ImageByte, 'byte')
endif
count_channels (Image, Channels)
if (Channels == 3)
rgb1_to_gray (Image, ImageByte)
endif
* 保存统一格式
write_image (ImageByte, 'png', 0, 'D:/unified/' + i + '.png')
endfor
常见陷阱:read_image 读取 JPEG 文件时,Halcon 会自动解码为 8 位灰度或 RGB,但不会提示原始压缩质量。若后续进行亚像素边缘提取,JPEG 的压缩伪影会被误识别为真实边缘。建议在精度要求高的场景使用 PNG 或 TIFF 格式。
四、误区与复盘:图像获取阶段的典型错误
根据多年项目经验,以下问题在初学者和工程现场中反复出现,需要特别警惕。
4.1 误区一:忽略相机参数与环境的匹配
曝光时间、增益、白平衡等参数并非越大越好。曝光过长会导致运动模糊,增益过大会放大噪声。正确做法是:先固定光照,再调整曝光使灰度直方图峰值位于 180-220 之间,最后微调增益。
4.2 误区二:混淆图像位深与显示范围
16 位图像的灰度范围是 0-65535,但显示器只能显示 0-255。直接显示 16 位图像会看到全黑或全白。必须使用 dev_display 前先做 scale_image 映射到 8 位范围,或使用 dev_set_lut 设置显示查找表。
4.3 误区三:格式转换时丢失关键信息
从彩色转灰度时,Halcon 默认使用 ITU-R BT.601 加权系数。若图像中目标颜色与背景颜色在灰度上接近,直接转换会导致对比度不足。此时应分析 RGB 三个通道的直方图,选择分离度最好的通道,或使用 decompose3 分解后单独处理。
4.4 误区四:预处理过度导致特征失真
预处理并非越强越好。过大的高斯核会模糊边缘,影响亚像素精度;多次中值滤波会改变区域形状。建议遵循“最小必要干预”原则:先做轻度去噪,验证效果后再逐步增强。
4.5 复盘清单
| 检查项 | 推荐做法 | 常见错误 |
|---|---|---|
| 相机连接 | 使用 info_framegrabber 验证设备枚举 |
设备编号写死,换相机后无法连接 |
| 触发模式 | 产线用硬件触发,实验室用软触发 | 触发信号未接导致一直超时 |
| 图像格式 | 统一为 8 位灰度或 24 位 RGB | 16 位图像直接参与 8 位算法 |
| 预处理顺序 | 先裁剪 ROI,再滤波,最后增强 | 先全局增强导致 ROI 外噪声放大 |
| 内存管理 | 循环中及时 clear_obj 释放对象 |
长时间运行内存持续增长 |
图像采集与读取是视觉系统的“入口”,其质量直接决定后续算法的上限。建议学习者在实际项目中建立标准化的采集配置模板,并针对不同光照、不同材质工件,记录一组经过验证的参数组合。这样既能保证开发效率,也能在产线调试时快速定位问题根源。通过本章的学习,应能独立完成从相机连接、图像读取、格式转换到基础预处理的完整链路搭建,为后续的定位、测量与缺陷检测打下坚实基础。