Opencv总结2——图像金字塔与轮廓检测

纯手打持续更新中~

1、轮廓检测(findContours)

cv2.findContours (img,mode,method)

mode:轮廓检索模式

  • RETR_EXTERNAL :只检索最外面的轮廓;

  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;

  • RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

  • RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;(最常用这个)

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。

  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

输入图像的要求,必须是二值的!(更高的准确率)

python 复制代码
img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 这一步对图像二值处理
cv_show(thresh,'thresh')
python 复制代码
binary, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

binary 为二值化之后的结果

contours为轮廓信息

hierarchy 表示层级

绘制轮廓(drawContours)

python 复制代码
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')
python 复制代码
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2)
cv_show(res,'res')

轮廓特征与近似(contourArea)

轮廓特征计算

python 复制代码
cnt = contours[0]
#面积
cv2.contourArea(cnt)
#周长,True表示闭合的
cv2.arcLength(cnt,True)

轮廓近似

python 复制代码
img = cv2.imread('contours2.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[0]

draw_img = img.copy()
res = cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res,'res')

这里用到了近似函数approxPolyDP

python 复制代码
epsilon = 0.15*cv2.arcLength(cnt,True)  # 0.15 越小是越貼合的
approx = cv2.approxPolyDP(cnt,epsilon,True) #cnt是轮廓,epsilon是指定需要比较的值,一般是周长的倍数

draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')

2、模板匹配(matchTemplate)

两张图片,现在是要看第一张图片是在第二张图片的哪一个部分。

把右边的图片分成九宫格,然后opencv会从左到右,从上到下进行一点点的匹配(逐像素匹配,像素点的差异),看看左边的图像是在右边的哪个位置。

模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1)

模板匹配的代码(代码在notebook中运行):

python 复制代码
# 模板匹配
img = cv2.imread('lena.jpg', 0)
template = cv2.imread('face.jpg', 0)
h, w = template.shape[:2] 

img.shape # 输出(263, 263)
template.shape # 输出(110, 85)

有以下6种差异计算方法:

  • TM_SQDIFF:计算平方不同,计算出来的值越小,越相关

  • TM_CCORR:计算相关性,计算出来的值越大,越相关

  • TM_CCOEFF:计算相关系数,计算出来的值越大,越相关

  • TM_SQDIFF_NORMED:计算归一化平方不同,计算出来的值越接近0,越相关(推荐用归一化的,结果会更可靠一些。)

  • TM_CCORR_NORMED:计算归一化相关性,计算出来的值越接近1,越相关

  • TM_CCOEFF_NORMED:计算归一化相关系数,计算出来的值越接近1,越相关

  • 公式:https://docs.opencv.org/3.3.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d

python 复制代码
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
           'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']

cv2.minMaxLoc() 是专门用于提取匹配结果矩阵(res)中极值(最小值 / 最大值)对应坐标的核心函数.

最小值就是根据需要匹配的图中,找到原图中的一个匹配点,后续根据h和w就能画出一个候选的方框。

python 复制代码
res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
res.shape # (154, 179)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # min_val:39168.0 max_val:74403584.0 min_loc:(107, 89) max_loc:(159, 62)
python 复制代码
for meth in methods:
    img2 = img.copy()

    # 匹配方法的真值
    method = eval(meth)
    print (method)
    res = cv2.matchTemplate(img, template, method)
    min_val, max_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()

示例

如果是匹配多个对象

python 复制代码
img_rgb = cv2.imread('mario.jpg')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('mario_coin.jpg', 0)
h, w = template.shape[:2]

res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8
# 取匹配程度大于%80的坐标
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)

3、图像金字塔(pyrUp,pyrDown)

把图像组合成金字塔的形状,可以用于图像特征提取,每层的特征提取的结果组合在一起。

高斯 金字塔:向下采样方法(缩小)用高斯核,然后把偶数列全部去掉。

高斯 金字塔:向上采样方法(放大)

用相同的卷积核来卷积,可以想象10这个像素平均的分给了周围的像素点。

代码实验

python 复制代码
img=cv2.imread("AM.png")
cv_show(img,'img')
print (img.shape) # (442, 340, 3)
python 复制代码
# 上采样
up=cv2.pyrUp(img)
cv_show(up,'up')
print (up.shape) #(884, 680, 3)
python 复制代码
#下采样方法
down=cv2.pyrDown(img)
cv_show(down,'down')
print (down.shape) # (221, 170, 3)

拉普拉斯金字塔

拉普拉斯金字塔的每一层 = 当前层的高斯图像 - 上采样后的下一层高斯图像。

python 复制代码
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
l_1=img-down_up
cv_show(l_1,'l_1')
相关推荐
数字孪生家族6 小时前
视频+数字孪生技术在隧道智慧综合管控平台中的典型应用
人工智能·视频孪生技术·智慧隧道建设·数字孪生交通·空间智能应用
dulu~dulu6 小时前
机器学习题目总结(二)
人工智能·机器学习·支持向量机·聚类·集成学习·降维·贝叶斯分类器
咬人喵喵6 小时前
神经网络:教电脑像人脑一样思考
人工智能·深度学习·神经网络
古城小栈6 小时前
Spring Boot 3.3 整合 AI 工具链:自动生成接口文档
人工智能·spring boot·后端
翔云 OCR API6 小时前
文档识别接口:赋能企业高效办公与加速信息的数字化转型
开发语言·人工智能·python·计算机视觉·ocr·语音识别
Mintopia6 小时前
🌐 长期视角:WebAIGC 技术的社会价值边界与伦理底线
前端·人工智能·aigc
Mintopia6 小时前
🧩 为 AI 提供专业可信的工具,实现“思路猜想”
人工智能·llm·aigc
neardi临滴科技6 小时前
Neardi Pi 4-3588:开启 8K 极速智能,赋能企业级边缘计算新时代
人工智能·嵌入式硬件·边缘计算·rk3588·开发板
思通数据6 小时前
AI智能预警系统:矿山、工厂与油气站安全管理架构浅析
人工智能·深度学习·安全·目标检测·机器学习·计算机视觉·架构