工业视觉原理
机器视觉结合到工厂的生产线中,诞生了工业视觉,那么这个领域的技术路线是什么呢?
工业视觉不管技术多复杂,基于目前的理解,我暂时将以上 4 个功能归纳如下:
(1)所有技术的起点是 "找到目标",无论是使用传统二值化查找、找圆、找线,还是深度学习找目标,都是先找到目标
(2)基于找到的目标,才可以进行后续的测量、定位
(3)基于测量的结果,才能判定检测结果
(4)基于定位的结果,才能控制机器人
总结起来有四种基本功能 —— 识别、测量、定位和检测,实现难度依次递增
- 识别:在一张图片上获取上目标的特征,关键过程是找到该目标
- 测量:基于找到的目标测算其与其他参照物的距离、角度、圆心、半径等
- 定位:用于确定目标在真实世界的位置,便于后续机器人控制
- 检测:最常用的类型,但是通常是非标准的,只针对某种场景,如尺寸不良、缺陷有无
识别
- 指甄别目标物体的物理特征,包括外形、颜色、字符、条码等,常见的应用场景是 OCR,读取零部件上的字母、数字、字符(例如条形码、二维码等)用于溯源
- 基于目标特征,在完整一幅图像中识别目标,可能涉及到 ROI 选择,颜色通道信息,二值化,外形方面可直接做模板匹配,扫码啥的直接有现成的各种算子、工具做,各方面都很成熟,不用太多额外代码,典型的拿来主义
测量
- 指把获取的图像像素信息标定成常用的度量衡单位,然后在图像中精确地计算出目标物体的几何尺寸,主要应用于高精度及复杂形态测量
- 比如距离、角度,距离就需要先做像素尺寸标定,知道每个像素大小,然后确定像素个数,比如测量圆的半径、圆心距,需要先识别到圆,测量水平线距离,也需要先识别到直线,然后确定距离
定位
- 指获取目标物体的位置信息,可以是二维或者是三维的位置信息,进而辅助执行后续操作,常用于元件对位,辅助机器人完成装配、拾取等
- 也常用到模板匹配和测量模型,还需要做标定,关联图像坐标和机械坐标,也有些标准机专门做一些简单的动作
检测
- 指对目标物体的表面状态进行检测,进而判断产品在生产制造状态中是否存在缺陷,内涵和种类繁多,例如检测零部件缺陷、污染物、功能性瑕疵等
- 检测说难也不难,通常都是非标的,只针对某种应用场景,比如外观缺陷检测,尺寸不良检测等等,缺陷有无检测起来会比较容易,仅仅判断有无即可,难度更大一点的确定缺陷类型,通常一个项目,甲方会要求检测各种缺陷类型并区分统计,以方便甲方后续针对性改进工序
目标查找技术路线
在以上基础中,“找到目标” 往往是第一步,要想从图片中找到目标,关键是利用目标的特征(比如:灰度值、边界、形状)去遍历搜索,比如找不规则的形状的物体,可以使用阈值化、模板匹配和形状匹配;找规则物体时,可以使用霍夫变换、模板匹配、形状匹配等,那么图像上目标特征有哪些?
- 在图像处理和计算机视觉领域,图像特征可以用来解决目标识别、图像匹配、视觉跟踪、三维重建等一系列问题。图像特征主要包括三种类型:(1) 角点 (Corner);(2) 边缘 (Edge);(3) 区域 (Blob);(4) 山脊 (Ridge),其实就是点、线、面、曲线
- 角点:应用最为广泛,因为角点在任意方向的一个微小变动都会引起图像灰度的很大变化。“角点”(conrner) 也称之为 “兴趣点”(interest point) 或 “关键点”(key point) 或 “特征点”(feature)
- 孤立的点:与角点不同,孤立的点是一个被背景像素围绕的前景像素,或一个被前景像素围绕的背景像素
- 线与曲线:是一条细边缘线段,其两侧的背景灰度与线段的像素灰度存在显著差异
- 边缘:区别于线,一般指局部不连续的的图像特征,边缘点是灰度阶跃变化的像素点,即灰度值变化显著,导数较大或极大的地方
- 面:图片上的一个区域
低级特征检测
在 opencv 中,有以下图像的特征检测与匹配算子,用于检测以上的特征点
- 特征检测:特征检测的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域
- 特征点:由关键点(key point)和描述子(Descriptor)组成,其中,描述子通常是一个向量,描述了该关键点周围的像素信息。只要两个特征点的描述子在向量空间上的距离相近,就可以认为它们是相同的特征点
除了特征点检测,还有边缘检测,其原理如下
- 用于识别对象的边界(边缘)或图像中的区域,边缘特征是像素强度的突然变化,要检测边缘,需要在相邻像素中寻找这样的变化,也就是梯度
- 红色区曲线表示原始边缘,绿色曲线表示一阶微分结果,蓝色区域表示二级微分结果。可知一阶微分算子可以检测图像边缘。对于剧烈变化的图像边缘,一阶微分效果比较理想。但对于缓慢变化的图像边缘,通过对二阶微分并寻找过零点可以很精确的定位边缘中心
传统机器视觉定位
1. 阈值化
- 根据灰度值和灰度值的限制将图像划分为多个区域,或提取图像中的目标物体,是最基本的阈值处理方法
- 如果图像的直方图存在明显边界,容易找到图像的分割阈值;但如果图像直方图分界不明显,则很难找到合适的阈值,甚至可能无法找到固定的阈值有效地分割图像
- 函数 threshold () 可以将灰度图像转换为二值图像,图像完全由像素 0 和 255 构成,呈现出只有黑白两色的视觉效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 生成灰度图像
hImg, wImg = 512, 512
img = np.zeros((hImg, wImg), np.uint8) # # 创建黑色图像 RGB=0
cv2.rectangle(img, (60,60), (450,320), (127,127,127), -1) # -1 表示矩形填充
cv2.circle(img, (256, 256), 120, (205,205,205), -1) # -1 表示圆形填充
# 添加高斯噪声
mu, sigma = 0.0, 25.0
noiseGause = np.random.normal(mu, sigma, img.shape)
imgNoise = img + noiseGause
imgNoise = np.uint8(cv2.normalize(imgNoise, None, 0, 255, cv2.NORM_MINMAX)) # 归一化为 [0,255]
# 阈值处理
ret, imgBin1 = cv2.threshold(img, 63, 255, cv2.THRESH_BINARY) # 阈值分割, thresh=63
ret, imgBin2 = cv2.threshold(img, 125, 255, cv2.THRESH_BINARY) # 阈值分割, thresh=125
ret, imgBin3 = cv2.threshold(img, 175, 255, cv2.THRESH_BINARY) # 阈值分割, thresh=175
show_images([img,imgNoise,imgBin1,imgBin2,imgBin3])
plt.bar(bins[:-1], histNP[:])
- 形状匹配
- 模板匹配的过程就是用模板图像作为一个滑动窗口在源图像中滑动,每滑动一个像素,记录该像素处匹配的程度,相似程度最大的位置对应模板匹配结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Mat m_input = Imgcodecs.imread(input_path); //输入
Mat m_template = Imgcodecs.imread(template_path); //模板
// 创建比较结果图
int result_rows = m_input.rows() - m_template.rows() + 1;
int result_cols = m_input.cols() - m_template.cols() + 1;
Mat g_result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
// 将结果图进行归一化
Imgproc.matchTemplate(m_target, m_template, g_result, Imgproc.TM_CCORR_NORMED);
Core.normalize(g_result, g_result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
// 得到模板位置
Core.MinMaxLocResult mmlr = Core.minMaxLoc(g_result);
Point matchLocation = mmlr.maxLoc; // 此处使用maxLoc还是minLoc取决于使用的匹配算法
System.out.println(matchLocation.x + "-----" + matchLocation.y);
// 返回模板的中间坐标
double x = matchLocation.x + (m_template.cols() / 2);
double y = matchLocation.y + (m_template.rows() / 2);
double[] tile = {x, y};
- 霍夫变换
- 经过直线公式转换后,在原始图片是一个直线的点,会映射到霍夫空间的一个点上,通过统计霍夫空间中映射点的次数,可以确定原始图片的点。如上图检测到 10 个边缘点,依次取两个点去求解公式的两个参数 、,然后将这两个参数绘制到霍夫空间(横轴 、纵轴 ),对于那些在一条直线上的点,其 , 值相等,所以绘制到霍夫空间的同一点
- 变换不同的公式,可以通过霍夫空间检测直线、圆、椭圆
- Blob 匹配
- Blob 在计算机视觉中通常指的是图像中的一块连续区域,这些区域具有某些共同的属性,比如颜色或灰度值。OpenCV 提供了 SimpleBlobDetector 类,它可以用于检测图像中的 blob,并根据不同的特征对它们进行过滤
- Blob 检测指识别和标记 blob 区域,目前有 3 种方法进行斑点检测:高斯拉普拉斯 (LoG)、高斯差分 (DoG) 和黑森行列式 (DoH)
1
2
3
4
5
6
7im = cv2.imread("blob.jpg", cv2.IMREAD_GRAYSCALE)
# 使用默认参数设置检测器.
detector = cv2.SimpleBlobDetector_create()
# 检测blob.
keypoints = detector.detect(im)
# 使用圆形绘制斑点.
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
使用深度学习定位
除以上传统机器视觉的手段外,还可以引入深度学习辅助定位,如使用语义分割,直接分割目标位置,使用目标检测定位目标,使用关键点检测目标中心等