news 2026/6/15 11:19:03

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

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

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')

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

binary 为二值化之后的结果

contours为轮廓信息

hierarchy 表示层级

绘制轮廓(drawContours)

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

轮廓特征与近似(contourArea)

轮廓特征计算

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

轮廓近似

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

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中运行):

# 模板匹配 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

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就能画出一个候选的方框。

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)
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()

示例

如果是匹配多个对象

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这个像素平均的分给了周围的像素点。

代码实验

img=cv2.imread("AM.png") cv_show(img,'img') print (img.shape) # (442, 340, 3)

# 上采样 up=cv2.pyrUp(img) cv_show(up,'up') print (up.shape) #(884, 680, 3)
#下采样方法 down=cv2.pyrDown(img) cv_show(down,'down') print (down.shape) # (221, 170, 3)

拉普拉斯金字塔

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

down=cv2.pyrDown(img) down_up=cv2.pyrUp(down) l_1=img-down_up cv_show(l_1,'l_1')
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 15:19:47

Java核心面试题终极总结:从基础到进阶,覆盖高频考

Java作为后端开发的主流语言,其核心知识点始终是面试考察的重点。无论是校招还是社招,面试官都会围绕Java基础、面向对象、集合框架、异常处理、关键字特性等核心模块展开提问。本文整理了Java开发中高频出现的38道核心面试题,按知识模块进行…

作者头像 李华
网站建设 2026/6/6 10:17:17

张雪峰推崇 “干安全有前景”,为何众多网友并不认同?

在一次演讲中,张雪峰老师说:学网络安全/信息安全准没错 但实际情况是,很多网友并不买账。 一位大二的网安专业的同学,在社交媒体上发文咨询: 一开始报网安是因为看到说网络安全前景很好,but这一年随着我在…

作者头像 李华
网站建设 2026/6/5 6:58:47

本地搭云盘还能远程用?Cloudreve + cpolar内网穿透的简单方案

文章目录 前言1. 安装Docker2. 使用Docker拉取镜像3. 创建并启动Cloudreve容器4. 本地访问测试5. 公网远程访问本地Cloudreve5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 前言 Cloudreve 是一款个人和团队都能用的云盘系统,支持文件…

作者头像 李华
网站建设 2026/6/13 22:17:14

职场笔杆子必看!2025公文写作软件TOP3对比

作为一名体制内笔杆子,写作公文的痛谁懂,临时的派稿任务,格式要求超严格,内容要求严谨合规,加班改稿也都是经常的事。 随着AI的不断发展,人工智能的写作能力越来越强,为写作带来显著的提效&…

作者头像 李华
网站建设 2026/6/10 10:38:41

Jenkins 2.528.3 与 GitLab 深度集成:实现自动构建

在 Jenkins 2.528.3 版本中,实现 GitLab 代码推送(Push)后自动触发构建,主要依赖于 GitLab Plugin 或 Generic Webhook Trigger Plugin。以下是两种主流方法的详细配置指南,帮助构建高效的自动化流水线。核心配置概览自…

作者头像 李华