一、图像金字塔
在池化中,有一个金字塔池化,他们的意思都差不多,就是利用不同尺度大小的特征,而图像金字塔池化也是一样,对于一张图像而言,
尺寸越小,包含的信息越多,相应的分辨率也会大大减小,所以图像金字塔就是不同尺寸的相同图像。
(1)高斯金字塔
(i)高斯金字塔向下采样(下采样)[缩小]
下采样过程中,H、W 依次减小一半,面积相应的减小为原来的1/4。
1、使用高斯滤波器对图像进行平滑处理
2、将所有偶数行和列丢弃(h、w 减半)
语法:
down_img = cv2.pyrDown(img)
常见的高斯核3x3,5x5:
(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)
如果先下采样,在上采样,会不会恢复呢?
大小可以恢复,但是图像的真实度存在丢失,恢复不了。因为不管是下采样还是上采样,都存在着失真的过程。
(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)
二、轮廓检测
语法:
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)
二值化图
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)
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)
(2)轮廓特征
(1)面积
cnt = contours[0]
cv2.contourArea(cnt)
(2)周长
cnt = contours[0]
cv2.arcLength(cnt,True)
(3)轮廓近似
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)
(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)
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)
三、模板匹配
(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()
(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)
|