一、图像金字塔
在池化中,有一个金字塔池化,他们的意思都差不多,就是利用不同尺度大小的特征,而图像金字塔池化也是一样,对于一张图像而言,
尺寸越小,包含的信息越多,相应的分辨率也会大大减小,所以图像金字塔就是不同尺寸的相同图像。
![在这里插入图片描述](https://img-blog.csdnimg.cn/bf22a4f61c2744e6952ceb396ab7a959.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_18,color_FFFFFF,t_70,g_se,x_16)
(1)高斯金字塔
(i)高斯金字塔向下采样(下采样)[缩小]
下采样过程中,H、W 依次减小一半,面积相应的减小为原来的1/4。
1、使用高斯滤波器对图像进行平滑处理
2、将所有偶数行和列丢弃(h、w 减半)
语法:
down_img = cv2.pyrDown(img)
常见的高斯核3x3,5x5: ![在这里插入图片描述](https://img-blog.csdnimg.cn/cd37aa18165842c1a997e74369426c7f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
(ii)高斯金字塔向上采样(上采样)[放大]
1、将图像在每个方向扩大为原来的两倍,新增的行和列以0填充
2、使用先前同样的内核(乘以4)与放大后的图像卷积,获得近似值。
语法:
up_img = cv2.pyrUp(img)
(iii) 代码示例
import cv2
import numpy as np
img = cv2.imread('lena1.jpg')
down = cv2.pyrDown(img)
up = cv2.pyrUp(img)
def cv_show(img):
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyWindow()
cv_show(img)
cv_show(down)
cv_show(up)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f321518efd8c4b88ae74411dae1bce15.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/84a47cd7a38b43ffa73ee9338ca9554f.png)
如果先下采样,在上采样,会不会恢复呢?
大小可以恢复,但是图像的真实度存在丢失,恢复不了。因为不管是下采样还是上采样,都存在着失真的过程。
![在这里插入图片描述](https://img-blog.csdnimg.cn/bb2f5a1e5c2c407788897e5175a02279.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
(2)拉普拉斯金字塔
图像的拉普拉斯金字塔可以由图像的高斯金字塔得到,没有单独的函数。
公式:
L
i
=
G
i
?
p
y
r
U
p
(
p
y
r
D
o
w
n
(
G
i
)
)
L_{i} = {G}_i - pyrUp(pyrDown(G_{i}))
Li?=Gi??pyrUp(pyrDown(Gi?)) or
L
i
=
G
i
?
p
y
r
U
p
(
G
i
+
1
)
L_{i} = {G}_i - pyrUp(G_{i+1})
Li?=Gi??pyrUp(Gi+1?)
G
i
+
1
=
p
y
r
D
o
w
n
(
G
i
)
G_{i+1} = pyrDown(G_{i})
Gi+1?=pyrDown(Gi?)
(i)代码示例
down = cv2.pyrDown(img)
down_up = cv2.pyrUp(down)
l_img = img-down_up
cv_show(l_img)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ada603482b984b3f8f512135bd0660c2.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
二、轮廓检测
语法:
cv2.findContours(img,mode,method)
mode:轮廓检索模式
- cv2.RETR_EXTERNAL : 只检索最外面的轮廓;
- cv2.RETR_LIST : 检索所有的轮廓,并将其保存到一条链表当中;
- cv2.RETR_CCOMP : 检索所有的轮廓,并将他们组织为两层;顶层是各部门的外部边界,第二层是空洞的边界;
- cv2.RETR_TREE : 检索所有的轮廓,并重构嵌套轮廓的整个层次; #常用
method:轮廓逼近方法
- cv2.CHAIN_APPROX_NONE :以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列);
- cv2.CHAIN_APPROX_SIMPLE :压缩水平的、垂直的和斜的部门,也就是函数只保留他们的终点部分;
img = cv2.imread('lena1.jpg')
gray_img = cv2.imread('lena1.jpg',cv2.IMREAD_GRAYSCALE)
ret,thresh = cv2.threshold(gray_img,127,255,cv2.THRESH_BINARY)
二值化图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/482702c6d0114e458d06f94008f9d8fa.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
binary,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
(1)绘制轮廓
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)
- draw_img : 在哪张图像中去画出轮廓;
- contours : 通过寻找轮廓得到的轮廓列表;
- -1,表示,把所有的轮廓都画上,当然也可以 指定 1,2,3,4等画第几个,一般都是 -1
- (0,0,255)代表用什么颜色去画轮廓;B、G、R
- 2,代表画出轮廓的粗细
draw_img = img.copy()
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)
cv_show(res)
![在这里插入图片描述](https://img-blog.csdnimg.cn/12ffb2843f4c467f9ab1f4a8eaefd159.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
img = cv2.imread('img.png')
gray_img = cv2.imread('img.png',cv2.IMREAD_GRAYSCALE)
ret,thresh = cv2.threshold(gray_img,127,255,cv2.THRESH_BINARY)
binary,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
draw_img = img.copy()
res = cv2.drawContours(draw_img,contours,-1,(0,0,255),2)
cv_show(res)
![在这里插入图片描述](https://img-blog.csdnimg.cn/95338e445e494122ac9bcbd4a9fc7dca.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_15,color_FFFFFF,t_70,g_se,x_16)
(2)轮廓特征
(1)面积
cnt = contours[0]
cv2.contourArea(cnt)
(2)周长
cnt = contours[0]
cv2.arcLength(cnt,True)
(3)轮廓近似
![在这里插入图片描述](https://img-blog.csdnimg.cn/16f828f05d3d4d30bb0e5849a6c02d7a.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_20,color_FFFFFF,t_70,g_se,x_16)
img = cv2.imread('img.png')
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[1]
draw_img = img.copy()
res = cv2.drawContours(draw_img,contours,1,(0,0,255),2)
epsilon = 0.09*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
draw_img = img.copy()
res = cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
cv_show(res)
![在这里插入图片描述](https://img-blog.csdnimg.cn/cdf4f43c5f434a808db650a006f21cab.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_8,color_FFFFFF,t_70,g_se,x_16)
(i)边界矩形
x,y,w,h = cv2.boundingRect()
- 返回四个值,分别是x,y,w,h;
- x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
然后利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,0,255), 2)画出矩行
第一个参数:img是原图
第二个参数:(x,y)是矩阵的左上点坐标
第三个参数:(x+w,y+h)是矩阵的右下点坐标
第四个参数:(0,255,0)是画线对应的rgb颜色
第五个参数:2是所画的线的宽度
img = cv2.imread('img.png')
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[1]
draw_img = img.copy()
res = cv2.drawContours(draw_img,contours,1,(0,0,255),2)
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
cv_show(img)
![在这里插入图片描述](https://img-blog.csdnimg.cn/90f45250c042474c87c7d59758bff173.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_6,color_FFFFFF,t_70,g_se,x_16)
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
print("轮廓面积和边界矩形面积比值:",extent)
(ii)外接圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
- (x,y) 圆心
- radius 半径
- cnt 轮廓(可以选取哪一个轮廓)
img = cv2.circle(img,center,radius,(0,0,255),2) 画出圆
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img = cv2.circle(img,center,radius,(0,0,255),2)
cv_show(img)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ca3c9798a5d7406b8f0a23eaec9ccbf2.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_7,color_FFFFFF,t_70,g_se,x_16)
三、模板匹配
(i)单目标匹配
模板匹配和卷积原理很像,模板在原图像撒花姑娘从原点开始滑动,计算模板和(原图中被模板覆盖的地方)的差别程度,这个差别程度
的计算方法有6种,然后将每次计算的结果放入一个矩阵中,作为结果输出。假如原图像的大小为AXB,模板大小为 axb,则输出结果矩阵
为(A-a+1)x(B-b+1)。
语法:
res = cv2.matchTemplate(img,template,method)
- res : 每个窗口的得到的结果值。相当于 那脸去整个人图像 滑动,没滑动一次,得到对应窗口的一个计算差别程度的值,
根据计算方法的不同,选择最大或者最小的。
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
- minVal:最小值,可输入NULL表示不需要。
- maxVal :最大值,可输入NULL表示不需要。
- minLoc:最小值的位置,可输入NULL表示不需要,Point类型。
- maxLoc:最大值的位置,可输入NULL表示不需要,Point类型。
计算差别程度(method):
cv2.TM_SQDIFF :计算平方不同,计算出来的值越小,越相关;
cv2.TM_CCORR :计算相关性,计算出来的值越大,越相关;
cv2.TM_CCOEFF :计算相关系数,计算出来的值越大,越相关;
cv2.TM_SQDIFF_NORMED :计算归一化平方不同,计算出来的值越接近于0,越相关;
cv2.TM_CCORR_NORMED :计算归一化相关性,计算出来的值越接近于1,越相关;
cv2.TM_CCOEFF_NORMED :计算归一化相关系数,计算出来的值越接近于1,越相关;
img = cv2.imread('lena1.jpg',0 )
template = cv2.imread('face.jpg',0)
h,w = template.shape[:2]
method = ['cv2.TM_SQDIFF',
'cv2.TM_CCORR',
'cv2.TM_CCOEFF',
'cv2.TM_SQDIFF_NORMED',
'cv2.TM_CCORR_NORMED',
'cv2.TM_CCOEFF_NORMED']
for meth in range(len(method)):
img2 = img.copy()
res = cv2.matchTemplate(img,template,meth)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
if meth 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(method[meth])
plt.show()
![在这里插入图片描述](https://img-blog.csdnimg.cn/3e60b868e9484821bba3eca929e8d571.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_13,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/e40e371e7b8d4517a5bc50cf2d134444.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/8c96d47414d649aa9c61e159f1a2dac1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_13,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/2033fb59ef1f4e3492c6fd468ad996f4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/3ecc61f702c3499dbfcbf792a17e14bd.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/65bbc4c18a6d45ed98b195847015d297.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16)
(ii)多目标匹配
多个人脸,或者多个目标去匹配。
img = cv2.imread('most.jpg' )
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
template = cv2.imread('face2.jpg',0)
h,w = template.shape[:2]
result = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where(result>=threshold)
for pt in zip(*loc[::-1]):
bottom_right = (pt[0]+w,pt[1]+h)
cv2.rectangle(img,pt,bottom_right,(0,0,255),1)
cv_show(img)
![在这里插入图片描述](https://img-blog.csdnimg.cn/27228fc197f84b4991451b991792d13f.jpg) ![在这里插入图片描述](https://img-blog.csdnimg.cn/dba0a3a992c84d53885c72efdc480f90.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_12,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/ea679c66b7cd4dfe9bc47310b61b642f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5rex5bqm6I-c6bihLei-vumXu-ilvw==,size_11,color_FFFFFF,t_70,g_se,x_16)
|