大體思路:由于墨滴的不同參數會對墨滴的形態產生一定的影響,故如果通過研究墨滴的形態則通過海量的數據就可以大概確定墨滴的各項參數指標的范圍。通過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()