这次学习的是轮廓检测和模版匹配,由于一些问题,导致花费了大量的时间。(有可能是图像选择的问题)
轮廓检测:
mode:轮廓检索模式 RETR_EXTERNAL:只检索最外层轮廓 RETR_LIST:检索所有的轮廓,并将其保存的一条链表中 RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各个部分的外部边界,第二层是空洞的边界 RETR_TREE:检查所有轮廓,并重构嵌套轮廓的整个层次 method轮廓逼近方法 CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列) CHAIN_APPROX_SIMPLE:压缩水平的,垂直的和斜的部分,函数只保留他们的终点部分
首先第一步是引入图像:(为更高准确率,使用二值图像)
img=cv2.imread('people.jpg')
print(img.shape)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
print(thresh.shape)
binary,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
然后接下来是绘制边框:
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
#注意copy,要不原图会变
draw_ = img.copy()
res=cv2.drawContours(img,contours,-1,(0,0,255),2) #2代表线条宽度,-1代表全部
cv_show('b',res)
res =cv2.drawContours(draw_,contours,0,(0,0,255),2)
cv_show('c',res)
#轮廓特征
cnt = contours[0]
#面积
s=cv2.contourArea(cnt)
#周长,Ture表示闭合
c=cv2.arcLength(cnt,True)
#轮廓近似:
epsilon = 0.1*cv2.arcLength(cnt,True) #自己设置也可以,通常安装周长的百分比
approx = cv2.approxPolyDP(cnt,epsilon,True)
drwaContours(图像,轮廓索引,-1(表示全部的轮廓,其他数字代表对应的的轮廓),颜色,线条的厚度)
这是轮廓的完整的代码:
img=cv2.imread('people.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
binary,contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
s=cv2.contourArea(cnt)
c=cv2.arcLength(cnt,True)
draw_ = img.copy()
res=cv2.drawContours(img,[cnt],-1,(0,0,255),2)
#图像轮廓近似
epsilon = 0.1*c
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_ = img.copy()
res=cv2.drawContours(draw_,[approx],-1,(0,0,255),2)
边界矩形:
在轮廓检测的基础上对轮廓进行框取:
#边界矩形
img=cv2.imread('people.jpg')
gray=cv2.cvtColor(img,cv2.COLOR_BGR2RGBA)
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
cnt = contours[0]
x,y,w,h=cv2.boundingRect(cnt) #B G R
img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) #2代表线条宽度
cv_show('e',img)
轮廓面积与边界矩形比值:(目前还不太清楚它有啥用)
rect_ =w * h
area = cv2.contourArea(cnt)
extent = float(area)/rect_ #轮廓面积与边界矩形比值
print(extent)
轮廓的学习中cv2.findContours(img.mode,method)此处一直报错,有的版本是两个值,有的是三个值,自己瞎鼓弄了好久才解决这个问题。
接着是模板匹配,单个匹配在结果的显示上一直有问题(可以用多个匹配来代替单个匹配)
TM_SQDIFF: 计算平方不同,计算值越小,越相关 TM_CCORR: 计算相关性,计算出来的值越大,越相关 TM_CCOEFF:计算相关系数,计算出来的值越大,越相关 归一化更可靠 TM_SQDIFF_NORMED :计算归一化平方不同,计算出来的值越接近0,越相关 TM_CCORR_NORMED :计算归一化相关性,计算出来的值越接近1,越相关 TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关
一共6函数,下面的3个函数更可靠。
methods =['cv2.TM_SQDIFF','cv2.TM_CCORR','cv2.TM_CCOEFF','cv2.TM_SQDIFF_NORMED','cv2.TM_CCORR_NORMED','cv2.TM_CCOEFF_NORMED']
img = cv2.imread('people.jpg',0)
print(img.shape)
img1 = cv2.imread('people1.jpg',0)
cv_show('a',img1)
print(img1.shape)
for meth in methods:
img2=img.copy()
method=eval(meth)
print(method)
res=cv2.matchTemplate(img,img1,method) #小值
cv_show('a',res)
print(res.shape) #结果=A-a+1,B-b+1
min_val ,max_val , min_joc,max_joc= cv2.minMaxLoc(res)
#最小值,最大值,最小值坐标位置,最大值坐标位置
#cv2.TM_SQDIFF cv2.TM_SQDIFF_NORMED 取最小值
if method in [cv2.TM_SQDIFF,cv2.TM_SQDIFF_NORMED]:
top = min_joc
else:
top = max_joc
tmp = cv2.imread('people1.jpg')
h, w = tmp.shape[:2]
bottom = (top[0]+w,top[1]+h)
print('bottom')
print(bottom)
#画矩形
cv2.rectangle(img1,top,bottom,255,2)
plt.subplots(221) #第一个参数代表子图的行数;第二个参数代表该行图像的列数; 第三个参数代表每行的第几个图像。
plt.imshow(res,cmap='gray')
plt.xticks([]),plt.yticks([])#隐藏坐标轴
plt.subplots(222)
plt.imshow(img2,cmap='gray')
plt.xticks([]),plt.yticks([])
plt.suptitle(meth)
plt.show()
这是将6个函数放在一起,可以观察一下他们的差别。(我这里的结果不知道为什么一直有问题,于是我将多个匹配来代替单个匹配)
img = cv2.imread('people.jpg')
gary=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
tmp = cv2.imread('people1.jpg')
h,w=tmp.shape[:2]
res =cv2.matchTemplate(img,tmp,cv2.TM_CCOEFF_NORMED)
threshold =0.8
loc =np.where(res>=threshold)
for pt in zip(*loc[::-1]): #*表示可选参数
bottom =(pt[0]+w,pt[1]+h)
cv2.rectangle(img,pt,bottom,(0,0,255),2)
cv2.imshow('sss',img)
cv2.waitKey(0)
接下来我继续去寻找出现问题的原因,(也可能只用多个结果匹配) 按照自己的节奏去完成暑假给自己定的目标。