07 图像金字塔与轮廓检测
import cv2
import matplotlib.pyplot as plt
import numpy as np
get_ipython().run_line_magic('matplotlib','inline')
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
高斯金字塔:
向下采样,缩小,提取特征
将Gi与高斯内和卷积,将所有偶数行列去除。
向上采样,扩大
img = cv2.imread('AM.png')cv_show(img,'img')print (img.shape)
#上采样1次
up = cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape)
#下采样
down = cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape)
#上采样2次
up2 = cv2.pyrUp(up)
cv_show(up2,'up2')
print (up2.shape)
#先上采样再下采样
up = cv2.pyrUp(img)
up_down = cv2.pyrDown(up)
cv_show(up_down,'up_down')
#对比原图、先上采样再下采样的组合图
cv_show(np.hstack((img,up_down)),'up_down')
up = cv2.pyrUp(img)
up_down = cv2.pyrDown(up)
cv_show(img-up_down,'img-up_down')
拉普拉斯金字塔
Li=Gi-PyrUp(PyrDown(Gi))
轮廓检测
cv2.findContours(img,mode,method)
mode:轮廓检索模式
•RETR_EXTERNAL:只检索最外侧的轮廓
•RETR_LIST:检索所有轮廓并保存到一条链表
•RETR_CCOMP:检索所有轮廓并将他们组织为两层:顶层是各部分的外界边界,第他们组织为两层:顶层是各部分的外界边界,第二层是空洞的边界
•RETR_TREE:检索所有轮廓,并重构嵌套轮廓的整个层次
method:轮廓逼近方法
•CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方式输出多边形(顶点的序列)。
•CHAIN_APPROX_SIMPLE:压缩水平垂直和斜的部分,函数只保留他们的终点部分。
#图像预处理img = cv2.imread('contours.jpg')gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)cv_show(thresh,'thresh')
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
绘制轮廓
cv_show(img,'img')
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度,注意copy
#-1所有轮廓 (0,0,255)BGR 2线条宽度
draw_img = img.copy()
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),4)
cv_show(res,'res')
轮廓特征
cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt,True)
轮廓近似
img = cv2.imread('contours2.png')gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_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)cv_show(res,'res')
epsilon = 0.01*cv2.arcLength(cnt,True)#0.1粗糙
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_img = img.copy()
res = cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
cv_show(res,'res')
边界矩形
img = cv2.imread('contours.jpg')gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)cnt = contours[2]x,y,w,h = cv2.boundingRect(cnt)img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)cv_show(img,'img')
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/ rect_area
print('轮廓面积与边界矩形',extent)
外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')
模板匹配
•TM_SQDIFF:计算平方不同,计算出来值越小,越相关
•TM_CCORR:计算相关性,计算出来值越大,越相关
•TM_CCOEFF:计算相关系数,计算出来值越大,越相关
•TM_SQDIFF_NORMED:计算归一化平方不同,越接近0,越相关
•TM_CCORR_NORMED:计算归一化相关性,越接近1,越相关
•TM_CCOEFF_NORMED:计算归一化相关系数,越接近1,越相关
img = cv2.imread('lena.png',0)template = cv2.imread('face.png',0)h,w = template.shape[:2]
img.shape
template.shape
methods = ['cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
res = cv2.matchTemplate(img,template,1)#1可以变为cv2.TM_CCOEFF
res.shape
min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(res)
min_val
max_val
min_loc#最小值位置左上点
max_loc
for meth in methods:
img2 = img.copy()
#匹配方法的真值
method = eval(meth)
print(method)
res = cv2.matchTemplate(img,template,method)
min_val,min_val,min_loc,max_loc = cv2.minMaxLoc(res)
#如果平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED,取最小值
if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w,top_left[1] + h)
#画矩形
cv2.rectangle(img2,top_left,bottom_right,255,2)
plt.subplot(121),plt.imshow(res,cmap='gray')
plt.xticks([]),plt.yticks([])#隐藏坐标轴
plt.subplot(122),plt.imshow(img2,cmap='gray')
plt.xticks([]),plt.yticks([])#隐藏坐标轴
plt.suptitle(meth)
plt.show()
匹配多个
img_rgb = cv2.imread('mario.png')
img_gray = cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.png',0)
h,w = template.shape[:2]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
#取匹配程度大于百分之八十的坐标
loc = np.where(res >= threshold)
for pt in zip(*loc[::-1]):#*表示可选参数
bottom_right = (pt[0] + w,pt[1] + h)
cv2.rectangle(img_rgb,pt,bottom_right,(0,0,255),2)
cv2.imshow('img_rgb',img_rgb)
cv2.waitKey(0)