目录
记录平时视觉学习过程中的知识点,如有错误,请指正。
一.相机和成像知识
1.成像原理
相机输出图像的过程:
首先物体的光进入镜头成像后,图像是打在感光芯片上的。芯片上有许多微小颗粒的传感器,每个(或每几个)传感器都会将光线变化转换为电信号变化,输出到外部系统。所以图像的每个像素点,实际上是对应相机的感光传感器的,两者间就像有通道连接一样,传感器对外界光线的变化导致像素变化,组合到图像上就是图像的变化。
黑白图像,可能只需要对应一个灰度通道。彩色的对应多个通道,然后根据色彩比例显示结果。
2.工业相机
- 工业相机、工控机这些电子产品,相对于日常电子产品,最大的区别就是稳定、抗干扰能力强。好多时候工业产品需要在极端的环境下长时间稳定地进行工作。而工业相机相比于传统民用相机,它具有更高的图像稳定性、高传输能力和高抗干扰能力。
本质功能就是将光信号转变成有序的电信号。- 工业相机知识拓展:工业相机及相关配件选型。
- 如下分别是公司所用的2款相机型号,华睿的面阵相机、dasla的线扫相机(也叫线阵相机)的参数截图:
二.视觉小知识
1. 阈(yu)值化
阈值化是一种图像分割的方法,用于从一幅图片里面提取我们需要的部分。比如分离图像的前景和背景。其基本原理就是利用一幅图像各个部分之间的像素差异,通过设定一个灰度值的阈值,截取出我们需要的部分 。
2.相机内参、相机外参
内参是描述相机内部属性的参数,包括焦距、主点(光学中心)坐标、畸变系数等。内参通常在相机标定时确定,因为它们通常对于特定相机型号是固定的,不随时间变化。一旦相机内参被确定,它们在相机的使用过程中通常是保持不变的。
外参是描述相机在世界坐标系中的位置和姿态的参数,通常包括旋转矩阵和平移向量。外参在不同的相机位置或拍摄时刻可能会发生变化。例如,在立体视觉中,如果您有两个相机,那么它们的相对位置和方向会在每次移动相机时发生变化,从而导致外参的变化。
如果相机不发生位置和方向的变化,比如相机固定在一个固定位置,那么外参在很长一段时间内可能保持不变。然而,如果相机的位置或方向发生变化,例如移动相机或更改拍摄角度,外参会随之变化。
3.标定和标定板
1.标定
标定的本质是建立一个测量的标准系统。
在标定的时候,摄像机通过带有固定间距图案阵列的平板(即标定板)拍摄图像,然后经过标定算法计算,得出拍摄图像的几何模型,进而得到高精度的测量和重建结果,最后通过相关算法校正镜头畸变,从而提高机器视觉应用中图像测量、摄影测量的精度。
通过像机标定我们可以知道些什么?
- 外参数矩阵。告诉你现实世界点(世界坐标)是怎样经过旋转和平移,然后落到另一个现实世界点(摄像机坐标)上。
- 内参数矩阵。告诉你上述那个点在1的基础上,是如何继续经过摄像机的镜头、并通过针孔成像和电子转化而成为像素点的。
- 畸变矩阵。告诉你为什么上面那个像素点并没有落在理论计算该落在的位置上,还产生了一定的偏移和变形。
上述3点的每一个转换,都有已经有成熟的数学描述,通过计算我们完全可以精确地重现现实世界的任意一个点到其数字图像只上对应像素点的投影过程。
2.标定板
标定板就是带有固定间距图案阵列的平板。
4.腐蚀和膨胀
1.膨胀
膨胀主要用于扩大区域像素,使边缘像素连接在一起。
2.腐蚀
腐蚀主要用于减小区域像素,使边缘像素断开。
5.拟合
用一个参数模型来表示特征,说的直白点就是把平面上一系列的点,用一条光滑的曲线连接起来。简单的特征描述就是线性边缘可以使用线性模型表示,圆形等等,复杂一些的比如车辆的完成轮廓。
6.亚像素
例如两个感官原件上的像素之间有4.5um的间距,宏观上它们是连在一起的,微观上它们之间还有无数微小的东西存在,这些存在于两个实际物理像素之间的像素,就被称为“亚像素”。亚像素实际上应该是存在的,只是缺少更小的传感器将其检测出来而已,因此只能在软件上将其近似计算出来。
亚像素可以表示为如下图所示,每四个红色点围成的矩形区域为实际原件上的像素点,黑色点为亚像素点:
7.Halcon中基于形状的模板匹配过程
Halcon中一个完整的模板匹配过程如下:
- 读取并显示图像;
- 确定模板ROI及检测ROI;
- 创建模型;
- 匹配模板;
- ROI仿射变换,得到ROI位置。
8.九点标定(手眼标定)
九点标定是手眼标定的一种,用于找到图像坐标系和物理坐标系的转化关系。
操作步骤为: 在物体上打9个点(12或16个点也可以),然后拍照,此时会拿到该图像坐标系中的其中9个点的坐标,把机械手分别移动到移动到这9个点的上方,每个点上拍一张图片,记录轴平台实际图像上的9个点坐标。到此,得到了2个组标记集合,图像坐标集合和其对应的轴平台坐标集合共18个坐标点,带入标定算法即可拿到坐标系的对应关系。此后每次移动机器人的时候将坐标关系方程带入坐标即可控制机械手走到准确位置。
9.单相机标定(内外参标定)
内外参(单相机)标定相机本身的,需要用到标定板。在相机出厂后,在车间安装完可能会产生一些形变,通过内外参标定来解决此问题。
内参数用于相机拍照时候填写,然后用于拿到标准的图片。
外参用于在测量物体距离时候用到,外参拿到的是每个像素对应的实际物理坐标位置,比如每个像素对应的mm数值,然后在测量物体距离的时候会用到。
1.大致操作步骤
- 准备标定板:
- 常用棋盘格标定板
- 确定标定板的尺寸(如9x6格)
- 确定每个格子的实际物理尺寸(如25mm)
- 采集标定图像:
public class CameraCalibration
{
private List<Mat> calibrationImages = new List<Mat>();
public void CaptureImage(Mat frame)
{
// 保存不同角度的标定板图像
calibrationImages.Add(frame.Clone());
}
}
- 角点检测:
public class CornerDetection
{
private Size patternSize = new Size(9, 6); // 标定板内角点数
private List<VectorOfPointF> imagePoints = new List<VectorOfPointF>();
public bool DetectChessboardCorners(Mat image)
{
VectorOfPointF corners = new VectorOfPointF();
bool found = CvInvoke.FindChessboardCorners(
image,
patternSize,
corners,
CalibCbType.AdaptiveThresh | CalibCbType.NormalizeImage
);
if (found)
{
// 亚像素角点检测
Mat grayImage = new Mat();
CvInvoke.CvtColor(image, grayImage, ColorConversion.Bgr2Gray);
CvInvoke.CornerSubPix(
grayImage,
corners,
new Size(11, 11),
new Size(-1, -1),
new MCvTermCriteria(30, 0.1)
);
imagePoints.Add(corners);
}
return found;
}
}
- 计算标定板三维坐标:
public class CalibrationPoints
{
private Size patternSize = new Size(9, 6);
private float squareSize = 25.0f; // 每个格子的实际尺寸(mm)
public VectorOfPoint3D32F CalculateObjectPoints()
{
VectorOfPoint3D32F objectPoints = new VectorOfPoint3D32F();
List<MCvPoint3D32f> points = new List<MCvPoint3D32f>();
for (int i = 0; i < patternSize.Height; i++)
{
for (int j = 0; j < patternSize.Width; j++)
{
points.Add(new MCvPoint3D32f(
j * squareSize,
i * squareSize,
0.0f
));
}
}
objectPoints.Push(points.ToArray());
return objectPoints;
}
}
5.相机标定
public class CameraCalibrator
{
private Mat cameraMatrix = new Mat();
private Mat distCoeffs = new Mat();
public void Calibrate(
List<VectorOfPoint3D32F> objectPoints,
List<VectorOfPointF> imagePoints,
Size imageSize)
{
VectorOfMat rotationVectors = new VectorOfMat();
VectorOfMat translationVectors = new VectorOfMat();
double error = CvInvoke.CalibrateCamera(
objectPoints,
imagePoints,
imageSize,
cameraMatrix,
distCoeffs,
rotationVectors,
translationVectors,
CalibType.Default,
new MCvTermCriteria(30, 1e-6)
);
}
public void SaveCalibrationResults(string filename)
{
// 保存标定结果
using (FileStorage fs = new FileStorage(filename, FileStorage.Mode.Write))
{
fs.Write(cameraMatrix, "camera_matrix");
fs.Write(distCoeffs, "distortion_coefficients");
}
}
}
6.图像校正
public class ImageCorrection
{
private Mat cameraMatrix;
private Mat distCoeffs;
public Mat UndistortImage(Mat distortedImage)
{
Mat undistortedImage = new Mat();
CvInvoke.Undistort(
distortedImage,
undistortedImage,
cameraMatrix,
distCoeffs
);
return undistortedImage;
}
}
2.标定步骤总结
- 准备工作
- 准备标定板
- 设置相机参数
- 引入必要的库
- 图像采集
- 采集15-20张不同角度的标定板图像
- 确保图像清晰、无模糊
- 角点检测
- 对每张图像进行角点检测
- 进行亚像素级别的角点优化
- 计算三维坐标
- 建立世界坐标系
- 计算标定板角点的三维坐标
- 相机标定
- 计算相机内参矩阵
- 计算畸变系数
- 计算重投影误差
- 结果验证与应用
- 保存标定结果
- 进行图像校正
- 验证标定效果
3.注意事项
- 采集图像时应该:
- 保持标定板平整
- 使用不同的角度和位置
- 避免运动模糊
- 标定精度依赖于:
- 标定图像的数量和质量
- 角点检测的准确性
- 标定板的制作精度
- 实际应用中:
- 定期进行标定
- 保存标定参数
- 监控标定效果
10.hsv颜色模型
在Halcon中,HSV颜色识别是一种常用的图像处理技术,它利用HSV色彩模型中的色相(Hue)、饱和度(Saturation)和亮度(Value)三个分量来识别和分割图像中的特定颜色区域。
HSV色彩模型是一种基于人类视觉感知的颜色表示方式,它将颜色分为色相(Hue)、饱和度(Saturation)和亮度(Value)三个分量。色相代表颜色的种类,如红色、黄色或蓝色等;饱和度表示颜色的鲜艳程度,饱和度越高颜色越鲜艳;亮度表示颜色的明暗程度,亮度越高颜色越明亮。
三.例程
1.识别回形针方向
1.介绍
首先用二值化分割出较暗的区域,然后把每个回形针分离,接着找到每个回形针的弧度和区域中心,然后画一个起点为区域中心的箭头,并将弧度转化为角度,即可得到每个回形针的角度。
2.代码
*识别回形针方向例程
*关闭窗口更新
dev_update_window ('off')
*读取图像
read_image (Paperclip, 'D:/private/OneDrive/桌面/images/paperclip.png')
*得到图片信息
get_image_size (Paperclip, Width, Height)
*关闭激活的活动图形显示窗口
dev_close_window ()
*打开图形窗口
dev_open_window (0, 0, Width/2, Height/2, 'black', WindowHandle)
*显示图像
dev_display (Paperclip)
*显示字体设置
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
*在屏幕的右下角显示“单击’Run(F5)'以继续”
disp_continue_message (WindowHandle, 'black', 'true')
*停止程序执行
stop()
*二值化图像,该方法可以自动选出暗(dark)的区域,或者自动选出亮(light)的区域
binary_threshold (Paperclip, Dark, 'max_separability', 'dark', UsedThreshold)
*把每个回形针分离开
connection (Dark, ConnectedRegions)
*根据形状选择区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 5000, 10000)
*设置显示全部填充
dev_set_draw ('fill')
*设置为多个颜色通道
dev_set_colored (12)
*显示图像
dev_display (SelectedRegions)
*在屏幕的右下角显示“单击’Run(F5)'以继续”
disp_continue_message (WindowHandle, 'black', 'true')
stop()
dev_display (Paperclip)
dev_set_color ('green')
dev_display (SelectedRegions)
*检测区域的方向,单位是弧度,参数一为区域,参数二为和x轴的夹角
orientation_region (SelectedRegions, Phi)
*检测每个区域的中心
area_center (SelectedRegions, Area, Row, Column)
*显示轮廓的线宽
dev_set_line_width (3)
dev_set_draw ('margin')
Length :=80
dev_set_color ('blue')
*显示箭头,起始坐标Row,Column,终止坐标Row - Length * sin(Phi),Row - Length * sin(Phi),箭头头部长4
disp_arrow (WindowHandle, Row, Column, Row - Length * sin(Phi), Column + Length * cos(Phi), 4)
*显示角度,把弧度转化成角度值
disp_message (WindowHandle, deg(Phi)$'3.1f' + ' deg', 'image', Row, Column - 100, 'black', 'false')
dev_update_window ('on')
原图:
识别图:
3.总结
1.二值化
图像处理中的二值化是一种将灰度图像转换为只有两种可能值(通常是0和255,分别代表黑色和白色)的过程。这个过程在数字图像处理中非常常见,因为它可以简化图像数据,突出图像的主要特征,并降低后续处理的复杂性。
二值化的关键步骤之一是选择一个阈值。这个阈值将用于确定图像中的每个像素是应该被赋予0(黑色)还是255(白色)。有许多方法可以用来确定这个阈值,包括全局阈值(对整个图像使用单一阈值)和局部阈值(根据图像的局部特性为每个像素或区域选择阈值)。
一旦确定了阈值,就可以对图像进行二值化操作了。对于每个像素,将其灰度值与阈值进行比较。如果灰度值大于或等于阈值,则将该像素设置为白色(或255);否则,将其设置为黑色(或0)。
2.焊盘定位
1.介绍
应用矩形拟合方式定位焊盘点位置。大概步骤如下:
- 1.二值化,通过灰度和面积先过滤一波杂质
- 2.将一个区域分为多个区域
- 3.通过面积和长宽比来筛选特征
- 4.填充区域,好多图形中间有空缺,需要填完整
- 5.形状转换,填充边缘凹进去的区域
- 6.提取边界形状
- 7.腐蚀图像
- 8.联结整个区域,把多个区域合并为一个
- 9.提取边缘像素
- 裁取感兴趣区域
- 从灰度图中提取亚像素轮廓
- 10.选择轮廓
- 11.相邻的联结起来
- 12.利用轮廓拟合矩形
- 13.把矩形显示在窗体
2.代码
*1.二值化,通过灰度和面积先过滤一波杂质
*2.将一个区域分为多个区域
*3.通过面积和长宽比来筛选特征
*4.填充区域,好多图形中间有空缺,需要填完整
*5.形状转换,填充边缘凹进去的区域
*6.提取边界形状
*7.腐蚀图像
*8.联结整个区域,把多个区域合并为一个
*9.提取边缘像素
*裁取感兴趣区域
*从灰度图中提取亚像素轮廓
*10.选择轮廓
*11.相邻的联结起来
*12.利用轮廓拟合矩形
*13.把矩形显示在窗体
read_image (Image, 'die_pads')
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width*2, Height*2, 'black', WindowHandle)
dev_display (Image)
fast_threshold (Image, Region, 185, 255, 20)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 150, 99999)
fill_up (SelectedRegions, RegionFillUp)
shape_trans (RegionFillUp, RegionTrans, 'convex')
boundary (RegionTrans, RegionBorder, 'inner')
dilation_circle (RegionBorder, RegionDilation,2.5)
union1 (RegionDilation, RegionUnion)
reduce_domain (Image, RegionUnion, ImageReduced)
edges_sub_pix (ImageReduced, Edges, 'sobel_fast', 0.5, 20, 40)
select_shape_xld (Edges, SelectedXLD, 'area', 'and', 150, 99999)
union_adjacent_contours_xld (SelectedXLD, UnionContours, 10, 1, 'attr_keep')
fit_rectangle2_contour_xld (UnionContours, 'regression', -1, 0, 0, 3, 2, Row, Column, Phi, Length1, Length2, PointOrder)
gen_rectangle2_contour_xld (Rectangle, Row, Column, Phi, Length1, Length2)
dev_display (Image)
dev_set_colored (12)
dev_display (Rectangle)
3.总结
1.Blob分析
Blob分析是将图像进行二值化,分割得到前景和背景,然后进行连通区域检测,从而得到Blob块的过程。简单来说,Blob分析就是在一块“光滑”区域内,将出现“灰度突变”的小区域寻找出来。
如下图这块布料,表面纹理比较均匀。如果这块布料上面没有瑕疵,那么,我们是检测不到“灰度突变”的;相反,如果在布料生产过程中,由于种种原因,形成孔洞、裂缝,那么,我们就能在这块布料上面检测到纹理,经二值化(Binary Thresholding)处理后的图像中色斑可认为是blob。而这些部分,就是生产过程中造成的瑕疵,这个过程,就是Blob分析。
2.拟合
拟合流程:
- 采集图像。
- 图像预处理。
- 边缘轮廓提取。
- 轮廓分割或合并。
- 根据轮廓进行拟合。
2.AOI缺陷检测
缺陷检测的一般包括:
1. 产品边缘:凹凸缺陷。
2. 产品内部:污点、内部凹凸点、瑕疵、孔洞、破损、烫伤、油渍侵染。
3. 划痕。
1.饼干检测
1.介绍
如下为饼干原图,我们要对饼干进行良率分析,有洞孔或者裂纹就认为饼干不合格。
2.代码
此案例属于缺陷检测部分,这里运用BLob分析+特征分析做检测。
* Blob+特征
read_image (Image, 'food/hazelnut_wafer_01')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_update_window ('off')
dev_set_line_width (3)
dev_set_draw ('margin')
dev_set_colored (12)
set_display_font (WindowHandle, 20, 'mono', 'true', 'false')
for Index := 1 to 24 by 1
read_image (Image, 'food/hazelnut_wafer_' + Index$'.02')
*错误1:'smooth_histo'
binary_threshold (Image, Region, 'smooth_histo', 'light', UsedThreshold)
opening_circle (Region, RegionOpening, 8.5)
rectangularity (RegionOpening, Rectangularity)
*错误2:area_holes计算空洞的面积
area_holes (RegionOpening, Area)
if (Area>300 or Rectangularity<0.92)
dev_set_color ('red')
Text:='Not OK'
else
dev_set_color ('green')
Text:='OK'
endif
dev_display (Image)
dev_display (RegionOpening)
*注意:disp_message颜色如果不填写,就会以系统颜色为主
disp_message (WindowHandle, Text, 'window', 12, 12, '', 'false')
stop ()
endfor