OpenCV——图像轮廓
我们的目标:
能够掌握轮廓查找与绘制的方法
能够掌握轮廓面积及长度的计算方法
能够编程实现形状匹配
能够掌握轮廓的几何形状拟合方法
任务一 凸包绘制
案例一 获取凸包
import cv2
# 读取图片并转至灰度模式
img = cv2.imread('contours2.png', 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 图片轮廓
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
# 寻找凸包并绘制凸包(轮廓)
hull = cv2.convexHull(cnt)
cv2.polylines(img,[hull],True,(255,0,0),2)
# 显示图片
cv2.imshow('line', img)
cv2.waitKey()
cv2.destroyAllWindows()
练习:实物凸包检测
import cv2
# 读取图片并转至灰度模式
img = cv2.imread('hand.png', 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, binary = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)
# 图片轮廓
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_NONE)
n=len(contours) #轮廓个数
contoursImg=[]
x=0 #初始化要绘制的轮廓索引
for i in range(n):
area = cv2.contourArea(contours[i])
if area>10000:
print(f"轮廓{i}的面积:\n{area}")
x=i
cnt = contours[x]
cv2.imshow("binary",binary)
#寻找凸包并绘制凸包(轮廓)
hull = cv2.convexHull(cnt)
cv2.polylines(img,[hull],True,(0,255,0),2)
cv2.drawContours(img,contours,x,(0,0,255), 3)
# 显示图片
cv2.imshow('line', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
任务二 凸缺陷检测
案例二:凸缺陷
import cv2
o = cv2.imread('contours2.png')
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0]) # 得到的是索引,要再轮廓中选出来
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(o,start,end,[0,0,255],2)
cv2.circle(o,far,5,[255,0,0],-1)cv2.imshow('result',o)
cv2.waitKey(0)
cv2.destroyAllWindows()
任务三 轮廓常见特征值
案例一:宽高比
import cv2
o = cv2.imread('binaryhand.png')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])
cv2.rectangle(o,(x,y),(x+w,y+h),(255,255,255),3)
aspectRatio = float(w)/h
print(aspectRatio)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
案例二:Extend
import cv2
o = cv2.imread('binaryhand.png')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])
cv2.drawContours(o,contours[0],-1,(0,0,255),3)
cv2.rectangle(o,(x,y),(x+w,y+h),(255,0,0),3)
rectArea=w*h
cntArea=cv2.contourArea(contours[0])
extend=float(cntArea)/rectArea
print(extend)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
案例三:最大值和最小值及它们的位置
import cv2
import numpy as np
o = cv2.imread('ct2.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[3] #coutours[0]、coutours[1]是左侧字母R
#--------使用掩膜获取感兴趣区域的最值-----------------
#需要注意minMaxLoc处理的对象为灰度图像,本例中处理对象为灰度图像gray
#如果希望获取彩色图像的,需要提取各个通道,将每个通道独立计算最值
mask = np.zeros(gray.shape,np.uint8)
mask=cv2.drawContours(mask,[cnt],-1,255,-1)
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(gray,mask = mask)
print("minVal=",minVal)
print("maxVal=",maxVal)
print("minLoc=",minLoc)
print("maxLoc=",maxLoc)
#--------使用掩膜获取感兴趣区域并显示-----------------
masko = np.zeros(o.shape,np.uint8)
masko=cv2.drawContours(masko,[cnt],-1,(255,255,255),-1)
loc=cv2.bitwise_and(o,masko)
cv2.imshow("mask",loc)
#显示灰度结果
#loc=cv2.bitwise_and(gray,mask)
#cv2.imshow("mask",loc)
#--------释放窗口-----------------
cv2.waitKey()
cv2.destroyAllWindows()
案例四:平均颜色及平均灰度
meanVal = cv2.mean(o,mask = mask) #mask是区域,所以必须是单通道的
print("meanVal=\n",meanVal)
任务四 实践:轮廓特征值的应用场景
案例:分类1
import cv2
import numpy as np
img = cv2.imread('face.png')
cv2.imshow("original",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
h,w,c=img.shape
mask = np.zeros((h,w,c),np.uint8)
for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),3)
ratio = float(w)/h
if ratio<1:
cv2.drawContours(mask,[cnt],-1,(0,0,255), -1)
#n+=1
print(ratio,"是长的椭圆")
else:
cv2.drawContours(mask,[cnt],-1,(0,255,255), -1)
#n+=1
print(ratio,"是扁的椭圆")
cv2.imshow("result",mask)
cv2.waitKey()
cv2.destroyAllWindows()
案例:分类2
import cv2
import numpy as np
img = cv2.imread('face.png')
cv2.imshow("original",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
h,w,c=img.shape
mask = np.zeros((h,w,c),np.uint8)for cnt in contours:
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),3)
ratio = float(w)/h
rectArea=w*h
cntArea=cv2.contourArea(contours[0])
extend=float(cntArea)/rectArea
print(extend)
if ratio<1:
cv2.drawContours(mask,[cnt],-1,(0,0,255), -1)
print(ratio,"是长的椭圆")
else:
cv2.drawContours(mask,[cnt],-1,(0,255,255), -1)
print(ratio,"是扁的椭圆")
if extend==0.9818696450428397:
cv2.drawContours(mask,[cnt],-1,(255,0,255), -1)
cv2.imshow("result",mask)
cv2.waitKey()
cv2.destroyAllWindows()
我们下次见拜拜!