news 2026/4/3 6:23:33

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/3/26 5:32:04

反序列化漏洞详解:从原理到实战(非常详细,附工具包及学习资源包)

一、什么是反序列化 1.1 漏洞简介 PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测&…

作者头像 李华
网站建设 2026/3/29 0:01:01

老王ST7571 灰度lcd显示屏 u8g2 驱动

u8g2:https://github.com/olikraus/u8g2/wiki/ ardunio 使用 U8X8_ST7571_128X96_4W_SW_SPI display(ST7571_CLK, ST7571_DATA, ST7571_CS, ST7571_DC ,ST7571_RESET); git最新的支持demo里面有U8X8_ST7571_G12896_4W_SW_SPI,但是目前最新的u8g2里面…

作者头像 李华
网站建设 2026/4/2 8:02:02

2025最强福利!9款免费AI论文生成润色工具,提升学术原创性必备!

作为一名常年与论文打交道的科研人员,我深知你正面临的痛点:deadline近在眼前初稿却一字未动、辛苦写的内容查重率超标、导师的修改意见晦涩难懂、复杂图表插入耗时耗力……2025年,AI论文工具已成为学术创作的标配,但市场上鱼龙混…

作者头像 李华
网站建设 2026/3/27 19:13:31

RISC-V指令集小白指南:通俗解释常用操作码

RISC-V指令集入门:从“看不懂的机器码”到读懂CPU在做什么你有没有试过打开一段汇编代码,看到一堆像addi a0, a0, 1或者jal ra, func这样的语句时一头雾水?它们不像C语言那样直观,但又确实是程序真正运行在CPU上的“原生语言”。而…

作者头像 李华