文章目录
前言一、算法设计1.1改进一1.2改进二
二、完整代码总结
前言
物品的分拣是许多工业生产线必不可少的部分。最初的物品分拣工作由人工完成,分拣效率低,需要消耗大量的人力,对工人的安全和健康也存在一定的威胁,并且受到很多因素的干扰,有可能出现错误分拣或者损坏物料的情况。所以,有必要设计一种自动分拣系统来解决这个问题。本文以螺丝的分拣为例,设计一种基于形状匹配的螺丝识别算法
一、算法设计
流水线工作环境应处于明亮的室内,流水线的输送皮带颜色应该是暗色系,黑色最佳,相机摄取到的图片如图 对其进行阈值分割,可得到结果 结果较好,但这种算法过于简单,很难应对更复杂的情况。所以,本文对该算法做两点改进。 第一, 增强系统对光照不均匀的鲁棒性。 第二, 当图片中出现其他物体时,系统也能准确识别出螺丝,而不会出现误检的情况
1.1改进一
倘若系统工作环境光照突然变的不均匀,那么图片中的某些区域将会变的很亮,某些区域又比较暗,这会极大地干扰阈值分割。 为解决此问题,可考虑采用形态学的方法,先将灰度图像进行开操作,然后再用灰度图像减去开操作之后的图像,便可使得整张图片的亮度均匀。原图和结果分别见下图 从上图中可以看出,左半部分亮度明显比右半部分亮,经过形态学操作之后,整张图片亮度变得均匀了,便于后续阈值分割
1.2改进二
实际工作中,流水线上可能会混入其他的物品,此时该系统还应该保证能准确的定位到螺丝,并且不会误定位其他物品。 在对原图做了光照均匀化处理之后,再采用基于形状匹配的算法,利用python+opencv进行编程。结果见图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201225101508826.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Jvb2tzaHU2,size_16,color_FFFFFF,t_70)
二、完整代码
from cv2 import cv2
import numpy as np
import matplotlib.pyplot as plt
def tem(path):
'''
该函数功能是生成一个用于matchshape的轮廓,返回值是一个螺丝轮廓。
参数说明,
path:模板图片,要求只有一个螺丝目标,背景无干扰,不然影响后续匹配精度
'''
tem = cv2.imread(path)
# 灰度化
gray_tem = cv2.cvtColor(tem,cv2.COLOR_BGR2GRAY)
# mask = np.zeros(gray_tem.shape,np.uint8)
# 定义一个101尺寸的矩形核,用于减弱光照不均匀的影响。这个核的尺寸要足够大,小了不行
k = np.ones((101,101),np.uint8)
# 定义一个15尺寸的矩形核,用于滤波
k1 = np.ones((15,15),np.uint8)
# 对灰度图进行开操作,将局部很亮的区域扩大,很暗的地方基本不变。这类似在二值图上进行开操作,只不过在这里是在灰度图上
# 操作,效果就是扩大亮区域,对于暗区域影响不大
opend_tem = cv2.morphologyEx(gray_tem,cv2.MORPH_OPEN,k)
# 将灰度图减去开操作之后的图,相当于亮的减亮的,暗的减暗的,减完之后整张图灰度值就均匀了,为了相减之后灰度值不至于太小
# 加一个偏量100
add_tem = cv2.addWeighted(gray_tem,1,opend_tem,-1,100)
# 阈值化
_,binary_tem =cv2.threshold(add_tem,180,255,cv2.THRESH_BINARY)
# 用开操作去噪
opening_tem = cv2.morphologyEx(binary_tem,cv2.MORPH_OPEN,k1)
_,contours,_ = cv2.findContours(opening_tem,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
n = len(contours)
s = []
# 将轮廓面积值放入列表s中
for i in range(n):
s.append(cv2.contourArea(contours[i]))
# 为了防止去噪后依然有一些小块干扰,通过一个循环只返回轮廓面积最大的那个作为模板
for i in range(n):
if s[i] == max(s):
# 这一步是为了查看轮廓图片,可不要
# mask = cv2.drawContours(mask,contours,i,(255,255,255),-1)
return contours[i]
def detect(gray,o,tem):
'''
该函数用于将待匹配图片与模板图片进行比对,返回检测成功的目标图片和目标的最小矩形。
参数说明,
gray,待匹配图片的灰度图像
o,原图
tem,模板轮廓
'''
# 二值化
_,binary = cv2.threshold(gray,210,255,cv2.THRESH_BINARY)
# 用开操作滤波
k = np.ones((8,8),np.uint8)
opening = cv2.morphologyEx(binary,cv2.MORPH_OPEN,k)
# 找图片中轮廓
_,contours,_ = cv2.findContours(opening,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
n = len(contours)
# 存储形状匹配成功的轮廓面积
s = []
# 存储形状匹配成功轮廓的索引值
b = []
# 存储最终匹配成功的目标最小矩形
rects = []
# 存储轮廓的所有面积值
s1 = []
rets = []
for i in range(n):
s1.append(cv2.contourArea(contours[i]))
for i in range(n):
# 形状匹配
ret = cv2.matchShapes(tem,contours[i],1,0)
rets.append(ret)
# print('第%d个轮廓形状匹配度:%f\n'%(i,ret))
# print('第%d个轮廓形状面积:%f\n'%(i,cv2.contourArea(contours[i])))
# 设置一个阈值,小于该阈值则认为与模板形状相似,可用于下一步比较。该阈值需要通过实验得到。这一步是粗过滤
# 可以将那些形状明显不相符的目标过滤掉
if ret area1 and s1[b[i]] |