openCV (六) 图像金字塔与轮廓检测 学习回顾记录

一、图像金字塔

在池化中,有一个金字塔池化,他们的意思都差不多,就是利用不同尺度大小的特征,而图像金字塔池化也是一样,对于一张图像而言,
尺寸越小,包含的信息越多,相应的分辨率也会大大减小,所以图像金字塔就是不同尺寸的相同图像。

在这里插入图片描述

(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=GipyrUp(pyrDown(Gi))
or
L i = G i − p y r U p ( G i + 1 ) L_{i} = {G}_i - pyrUp(G_{i+1}) Li=GipyrUp(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 :压缩水平的、垂直的和斜的部门,也就是函数只保留他们的终点部分;
# 1、图像处理  灰度图--->二值图   提高精度
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)

二值化图
在这里插入图片描述

# 2、寻找轮廓,并保存在相应的列表里边(contours)
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,代表画出轮廓的粗细
# 3、 绘制轮廓

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)
#cv_show(thresh)

binary,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

#绘制轮廓

draw_img = img.copy()
# -1,画出两个轮廓  可选 0,1
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)# 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)
#cv_show(res)

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) #得到矩形 w,h
rect_area = w*h
extent = float(area)/rect_area
print("轮廓面积和边界矩形面积比值:",extent)

#轮廓面积和边界矩形面积比值: 0.3365312107247591

(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,越相关;
# 1、首先读入 原始图像和要匹配的图
img = cv2.imread('lena1.jpg',0 )# 512,512
template = cv2.imread('face.jpg',0)  #186,157
h,w = template.shape[:2]
# res = cv2.matchTemplate(img,template,meth) #(327, 356)  512-186+1=327,512-157+1=356
    


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) #(327, 356) 
    # 
    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
    # 检测框的 w,h
    bottom_right = (top_left[0]+w,top_left[1]+h) #得到 检测框的 w,h

    # 画矩形  (原图,(左顶点位置),(框的w,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' )# 512,512
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
template = cv2.imread('face2.jpg',0)  #186,157
h,w = template.shape[:2]

result = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
#print(result)
threshold = 0.8

# 取匹配程度大于 80%的坐标
loc = np.where(result>=threshold)

for pt in zip(*loc[::-1]):
    #print(pt)
    bottom_right = (pt[0]+w,pt[1]+h)
    cv2.rectangle(img,pt,bottom_right,(0,0,255),1)

cv_show(img)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值