通过图像处理,分析数码印花的喷头所喷出来的墨滴形状,与标准墨滴形状对比分析,来判断墨水及其喷头设备的状态,由两部分构成
PS:获取墨滴形状照片和标准墨滴形状照片都是手绘的,将就的看吧,主要功能已经实现了,思路也就是这些。
主要思路:
1,首先通过高速摄像头捕获数码印花喷头喷出的墨滴照片
2,将照片进行灰度和二值处理
3,获取照片中墨滴的的边缘
4,获取边缘所围成的墨滴面积
5,对墨滴边缘进行外接圆绘制,并获取外接圆的直径
6,将图片绘制最小外接圆求出面积及其直径
7,将图像和标准墨滴图像进行加权融合,并获取交集部分轮廓图像
8,获取交集部分轮廓面积的大小
9,由以上数据分析,反推出墨水的工艺和喷头设备的状态情况
OpenCV部分
一、将彩色的照片转化为黑色背景、灰度图、二值化
由第一步将拍摄的彩色照片绘制成黑色背景下的二值图
效果如下:
二、获取照片的轮廓(我这里使用的是内轮廓)
import cv2
import numpy as np
from matplotlib import pyplot as plt
from math import sqrtdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()img = cv2.imread('E:\Jupyter_workspace\study\data/water.png')
show_photo('img ',img )gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[1]draw_img = img.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
show_photo('res',res)
原图:
捕获内轮廓后的结果:
三、计算密闭轮廓的面积和周长
cv2.arcLength(cnt,True)#轮廓所对应的周长,True表示闭合的
cv2.contourArea(cnt)#第一个轮廓所对应的面积
四、绘制墨滴内轮廓的最小外接圆
x, y, w, h = cv2.boundingRect(cnt)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img_radius = cv2.circle(img,center,radius,(0,255,0),2)#(B,G,R),2为轮廓粗细程度
show_photo('img_radius',img_radius)
墨滴内轮廓的最小外接圆:
五、填充最小外接圆,方便后续求轮廓
img_gray = cv2.cvtColor(img_radius, cv2.COLOR_BGR2GRAY)
_,th = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 寻找轮廓,使用cv2.RETR_CCOMP寻找内外轮廓
img_radius_full, contours, hierarch = cv2.findContours(th, cv2.RETR_CCOMP, 2)
# 找到内层轮廓并填充hierarchy = np.squeeze(hierarch)#使用np.squeeze压缩hierarch的成为一维数据for i in range(len(contours)):# 存在父轮廓,说明是里层if (hierarchy[i][3] != -1):cv2.drawContours(img_radius_full, contours, i, (255, 255, 0), -1)#这里的(255,255,0)代表cyan,也可自定义show_photo('img_radius_full',img_radius_full)
#cv2.imwrite('E:\Python-workspace\OpenCV\OpenCV/yanyu.jpg', img)
将墨滴内轮廓的最小外接圆填充:
六、绘制最小外接圆轮廓
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[0]draw_img = img.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
show_photo('res',res)
墨滴内轮廓的最小外接圆轮廓:
七、获取最小外接圆面积、周长、直径和半径
#最小外接圆的周长
cv2.arcLength(cnt,True)#轮廓所对应的周长,True表示闭合的#最小外接圆的面积
cv2.contourArea(cnt)#轮廓所对应的面积#最小外接圆直径
cv2.arcLength(cnt,True)/2/3.1415926#最小外接圆直径
sqrt(int(cv2.contourArea(cnt)/3.1415926))
八、与标准墨滴样式进行加权融合
import cv2
import matplotlib.pyplot as plt
import numpy as npimg_1 = cv2.imread('E:\Jupyter_workspace\study\data/water.png')
img_2 = cv2.imread('E:\Jupyter_workspace\study\data/water_img.png')res = cv2.addWeighted(img_1,0.6,img_2,0.4,0)#加权融合
#R = αx + βy + b
#其中x为img_1,y为img_2,α为0.4权重,β为0.6权重,b为0偏移量
#plt.imshow(res)
show_photo('res',res)gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,50,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#cnt = contours[5]
cnt = contours[0]
cnt1 = contours[5]draw_img = res.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
res =cv2.drawContours(draw_img,[cnt1],-1,(0,255,0),2)
show_photo('res',res)
标准墨滴:
获取墨滴与标准墨滴进行加权融合:
九、绘制获取墨滴图像和标准墨滴图像交集部分轮廓
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,50,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#cnt = contours[5]
cnt = contours[0]
cnt1 = contours[5]draw_img = res.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
res =cv2.drawContours(draw_img,[cnt1],-1,(0,255,0),2)
show_photo('res',res)
获取墨滴和标准墨滴交集轮廓:
十、计算获取墨滴与标准墨滴交集部分面积
cv2.contourArea(cnt)#轮廓所对应的面积
到此,通过opencv已经获取了足够多的数据,由这些数据进行工艺上的对墨水配料反推加工
整合代码如下:
import cv2
import numpy as np
from matplotlib import pyplot as plt
from math import sqrtdef show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()test_img = cv2.imread('E:\Jupyter_workspace\study\data/water.png')#测试图
origin_img = cv2.imread('E:\Jupyter_workspace\study\data/water_img.png')#标准图show_photo('test ',test_img )#测试图像gray = cv2.cvtColor(test_img,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)cnt = contours[0]#1为内轮廓,0为外轮廓draw_img = test_img.copy()
outline =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
show_photo('outline',outline)#内轮廓length = cv2.arcLength(cnt,True)
area = cv2.contourArea(cnt)
print('轮廓周长为:',length)#轮廓所对应的周长,True表示闭合的
print('轮廓面积为:',area)#轮廓所对应的面积'''
绘制轮廓的最小外接圆
'''
x, y, w, h = cv2.boundingRect(cnt)
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
draw_radius_img = test_img.copy()
img_radius = cv2.circle(draw_radius_img,center,radius,(0,255,0),2)#(B,G,R),2为轮廓粗细程度
show_photo('img_radius',img_radius)'''
填充最小外接圆
'''
img_gray = cv2.cvtColor(img_radius, cv2.COLOR_BGR2GRAY)
_,th = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 寻找轮廓,使用cv2.RETR_CCOMP寻找内外轮廓
img_radius_full, contours, hierarch = cv2.findContours(th, cv2.RETR_CCOMP, 2)
# 找到内层轮廓并填充hierarchy = np.squeeze(hierarch)#使用np.squeeze压缩hierarch的成为一维数据for i in range(len(contours)):# 存在父轮廓,说明是里层if (hierarchy[i][3] != -1):cv2.drawContours(img_radius_full, contours, i, (255, 255, 0), -1)#这里的(255,255,0)代表cyan,也可自定义show_photo('img_radius_full',img_radius_full) r_c = cv2.arcLength(cnt,True)#轮廓所对应的周长,True表示闭合的
r_s = cv2.contourArea(cnt)#轮廓所对应的面积
# c = Π*d = 2*Π*r
# s = Π*r*r
r_d = r_c/3.1415926print('最小外接圆轮廓周长为:',r_c)#轮廓所对应的周长,True表示闭合的
print('最小外接圆轮廓面积为:',r_s)#轮廓所对应的面积
print('最小外接圆轮廓直径为:',r_d)#轮廓所对应的面积'''
与标准墨滴图像进行加权融合
'''
res = cv2.addWeighted(origin_img,0.6,test_img,0.4,0)#加权融合
#R = αx + βy + b
#其中x为img_1,y为img_2,α为0.4权重,β为0.6权重,b为0偏移量
#plt.imshow(res)
show_photo('res',res)gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)#转换为灰度图
ret, thresh = cv2.threshold(gray,50,255,cv2.THRESH_BINARY)#对图像进行二值处理,小于127为0,大于127为255
binary, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#cnt = contours[0]
cnt1 = contours[5]
#cnt1 = contours[5]draw_mix_img = res.copy()
mix_img =cv2.drawContours(draw_mix_img,[cnt1],-1,(0,0,255),2)
#res =cv2.drawContours(draw_img,[cnt1],-1,(0,255,0),2)
show_photo('mix_img',mix_img)mixed_s = cv2.contourArea(cnt1)#轮廓所对应的面积
mixed_c = cv2.arcLength(cnt1,True)#轮廓所对应的周长,True表示闭合的print('交集轮廓周长为:',mixed_c)#轮廓所对应的周长
print('交集轮廓面积为:',mixed_s)#轮廓所对应的面积
print('\n')if area < 9000 :print('警报:喷头堵塞!!!')
elif mixed_s > 1000 :print("警报:墨水形状不标准!!!")
elif r_d > 110 :print('警报:墨水过于粘稠!!!')
else :print("一切正常")
测试墨滴图像:
绘制墨滴外轮廓:
绘制墨滴最小外接圆:
填充最小外接圆:
与标准墨滴进行加权融合:
获取交集部分:
控制台结果显示: