大体思路:由于墨滴的不同参数会对墨滴的形态产生一定的影响,故如果通过研究墨滴的形态则通过海量的数据就可以大概确定墨滴的各项参数指标的范围。通过OpenCV对墨滴的喷出的形状进行图像处理,对墨滴图像进行一系列的分析,通过一系列参数存入Mysql数据库中最终找到参数与墨滴形态的关系。本篇博客是通过拿标准墨滴、参数墨滴的图像和Mysql数据库中的数据进行对比从而得出相应的结论。(当然这里的标准墨滴只不过是本人的一个例子而已,为了简化后续操作而自我设定的,故再次声明一下)
代码已经完全实现,有点繁琐,由于时间原因,本篇博客我会持续更新补充直到完全补充完毕...
实现步骤:
1、捕获标准墨滴图像,对其进行一系列处理,获取其周长circum_origin、面积area_origin
2、捕获测试墨滴图像,对其进行一系列处理,获取其周长circum_test、面积area_test、最小外接圆面积area_test_radius、最小外接圆周长circum_test_radius、最小外接圆直径diameter_test_radius
3、将标准墨滴图像与测试墨滴图像进行加权融合,并获取其交集部分周长circum_intersection、面积area_intersection
4、将这些参数存入到drop数据库下的shape表中,并与墨滴的工艺参数进行主外键关联,墨滴工艺参数主要为:黏度、表面张力
5、通过海量的数据,进行范围查找,即可由墨滴的形状参数确定出墨滴的工艺参数,从而达到我的课题目的。
一、墨滴的图像
标准墨滴图像:
测试墨滴图像:
二、墨滴通过灰度和二值化处理后的图像
(后续需要对测试图像和原图像进行加权融合操作,故这里需要通过ROI区域获取,指定图像的长宽,我这里使用的长宽为:250*250像素)
标准墨滴预处理后的图像:
测试墨滴预处理后的图像:
三、Mysql数据库的设计
我这里使用的是Mysql数据库,数据库名称为drop
,里面存放shape
表,表中属性分别为:id、circum、area、circum_radius、area_radius、diameter_radius
。
列名 | 类型即精度 | 数据说明 | 描述 |
---|---|---|---|
id | int | primary key、NOT NULL 、AUTO_INCREMENT | 主键,递增,唯一,不为空 |
circum | decimal(12,4) | 共12位小数数据,其中小数位数4位 | 存放图像的周长数据 |
area | decimal(12,4) | 共12位小数数据,其中小数位数4位 | 存放图像的面积数据 |
area_radius | decimal(12,4) | 共12位小数数据,其中小数位数4位 | 存放图像最小外接圆的面积数据 |
circum_radius | decimal(12,4) | 共12位小数数据,其中小数位数4位 | 存放图像最小外接圆的周长数据 |
diameter_radius | decimal(12,4) | 共12位小数数据,其中小数位数4位 | 存放图像最小外接圆的直径数据 |
后续表还会进行补充完善...
在drop数据库下创建shape表
import pymysql
DBHOST = 'localhost'
DBUSER = 'root'
DBPASS = 'beyond'
DBNAME = 'drop'
DBSET = 'utf8'try:conn = pymysql.connect(host = DBHOST,user = DBUSER,password= DBPASS,database= DBNAME,charset= DBSET)#连接drop这个数据库print('seccessfull!!!')cur = conn.cursor()cur.execute("DROP TABLE IF EXISTS shape")#创建water表之前先检查是否存在这个表,若存在则删除sql = "CREATE TABLE shape(id int primary key NOT NULL AUTO_INCREMENT, circum decimal(12,4), area decimal(12,4), area_radius decimal(12,4), circum_radius decimal(12,4), diameter_radius decimal(12,4))"#创建表cur.execute(sql)print('create table seccess!!!')except pymysql.Error as e:print('table create is defeated!' + str(e))
四、获取测试墨滴的轮廓周长、轮廓面积、最小外接圆周长、最小外接圆面积、最小外接圆直径,为了方便后续处理和与数据库一致,这里的数据只保留四位小数
import cv2
import numpy as np
import pymysql
from matplotlib import pyplot as plt
from math import sqrtDBHOST = 'localhost'
DBUSER = 'root'
DBPASS = 'beyond'
DBNAME = 'drop'
DBSET = 'utf8'def show_photo(name,picture):#图像显示函数cv2.imshow(name,picture)cv2.waitKey(0)cv2.destroyAllWindows()#显示测试墨滴图像
img_test = cv2.imread('E:\Jupyter_workspace\study\data/test.png')
img_origin = cv2.imread('E:\Jupyter_workspace\study\data/origin_1.png')
#img_test = cv2.imread('E:\Jupyter_workspace\study\mysql\image/4.png')
#img_test = cv2.imread('E:\Jupyter_workspace\study\data/a1.png')
show_photo('img_test ',img_test )
show_photo('img_origin ',img_origin )#将照片转换为灰度图、二值化,获取其轮廓并将轮廓绘制
gray = cv2.cvtColor(img_test,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)
#show_photo('gray',gray)
cnt = contours[0]draw_img = img_test.copy()
test_outline =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
show_photo('test_outline',test_outline)#轮廓周长
circum_test = format(cv2.arcLength(cnt,True), '.4f')
#circum = int(cv2.arcLength(cnt,True))#轮廓所对应的周长,True表示闭合的
print("轮廓周长为:" + circum_test)
#轮廓面积
area_test = format(cv2.contourArea(cnt),'.4f')#轮廓所对应的面积
print("轮廓面积为:" + area_test)#轮廓最小外接圆
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_test,center,radius,(255,255,255),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寻找内外轮廓
image, 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, contours, i, (255, 255, 255), -1)#这里的(255,255,0)代表cyan,也可自定义show_photo('radius',img_radius)img_gray = cv2.cvtColor(img_radius, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 寻找二值化图中的轮廓
image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
cv2.drawContours(img_radius, [cnt], 0, (0, 0, 255), 2)area_test_radius = format(cv2.contourArea(cnt),'.4f')
circum_test_radius = format(cv2.arcLength(cnt,True), '.4f')
diameter_test_radius = format(cv2.arcLength(cnt,True)/3.1416, '.4f')print("最小外接圆的周长为:");print(circum_test_radius)
print("最小外接圆的面积为:");print(area_test_radius)
print("最小外接圆的直径为:");print(diameter_test_radius)img_test = cv2.imread('E:\Jupyter_workspace\study\data/test.png')
img_origin = cv2.imread('E:\Jupyter_workspace\study\data/origin_1.png')
res = cv2.addWeighted(img_test,0.5,img_origin,0.5,0)#加权融合
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]draw_img = res.copy()
res =cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)show_photo('res',res)img_gray = cv2.cvtColor(res, cv2.COLOR_BGR2GRAY)
_,th = cv2.threshold(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(hierarchy)#使用np.squeeze压缩hierarch的成为一维数据
#print(hierarchy.shape)for i in range(len(contours)):# 存在父轮廓,说明是里层if (hierarchy[i]!= -1):cv2.drawContours(res, contours, i, (255, 255,0), -1)#这里的(255,255,0)代表cyan,也可自定义show_photo('img_radius_full',img_radius_full) #轮廓周长
circum_intersection = format(cv2.arcLength(cnt,True), '.4f')#轮廓所对应的周长,True表示闭合的
print("并集轮廓周长为:" + circum_intersection)
#轮廓面积
area_intersection = format(cv2.contourArea(cnt),'.4f')#轮廓所对应的面积
print("并集轮廓面积为:" + area_intersection)try:conn = pymysql.connect(host = DBHOST,user = DBUSER,password= DBPASS,database= DBNAME,charset= DBSET)#连接drop这个数据库print('seccessfull!!!')cur = conn.cursor()sql = "INSERT INTO shape(circum,area,area_radius,circum_radius,diameter_radius) VALUE (%s,%s,%s,%s,%s)"#向表中插入数据value = (circum_test,area_test,area_test_radius,circum_test_radius,diameter_test_radius)cur.execute(sql,value)conn.commit()print('insert seccess!!!')
except pymysql.Error as e:print('insert is defeated!' + str(e))conn.rollback()conn.close()