首页
视频
资源
登录
原
OpenCV 图像金字塔、轮廓与模板匹配(学习笔记)
2981
人阅读
2024/1/16 15:39
总访问:
2993275
评论:
0
收藏:
0
手机
分类:
opencv
![](https://img.tnblog.net/arcimg/hb/3c9a034e352c4476b4ec6d8cc07a0263.png) >#OpenCV 图像金字塔、轮廓与模板匹配(学习笔记) [TOC] ## 图像金字塔 tn2>初始化代码。 ```python import cv2 #opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt#Matplotlib是RGB %matplotlib inline def cv_show(img,name): cv2.imshow(name,img) cv2.waitKey() cv2.destroyAllWindows() ``` ### 高斯金字塔 tn2>在OpenCV中,高斯金字塔是一种图像处理技术,它用于将一幅图像分解成多个不同分辨率的图像版本,其中每个版本都是原始图像的模糊和缩小版本。 这个过程可以帮助我们在不同尺度上分析和处理图像。 ![](https://img.tnblog.net/arcimg/hb/a179c9a293e64e82a8a4400d7f7cf8ce.png) tn2>高斯金字塔:向下采样方法(缩小) ![](https://img.tnblog.net/arcimg/hb/0c84b7844a174048ad53abe9e563a9d4.png) tn2>高斯金字塔:向上采样方法(放大) ![](https://img.tnblog.net/arcimg/hb/506b42d96bbb49ef926df146c4290fc0.png) tn2>查看原始图片大小。 ```python img=cv2.imread("AM.png") cv_show(img,'img') print (img.shape) ``` ![](https://img.tnblog.net/arcimg/hb/97f77490ee3c4be78e883ad47da19297.png) >(442, 340, 3) tn2>放大操作。(大小翻一倍) ```python up=cv2.pyrUp(img) cv_show(up,'up') print (up.shape) ``` ![](https://img.tnblog.net/arcimg/hb/dfe33989c07a4e2a91fd3cd14f2d9e6d.png) >(884, 680, 3) tn2>缩小一倍。 ```python down=cv2.pyrDown(img) cv_show(down,'down') print (down.shape) ``` ![](https://img.tnblog.net/arcimg/hb/aa6c096cd44a42dd81c8d8248f542bd7.png) >(221, 170, 3) tn2>放大两倍 ```python up2=cv2.pyrUp(up) cv_show(up2,'up2') print (up2.shape) ``` ![](https://img.tnblog.net/arcimg/hb/f2a57d7cccd240e6ac906f7d2f0ea967.png) >(1768, 1360, 3) tn2>放大后再缩小,我们会发现它与原有的图片相比比较模糊。 ```python up=cv2.pyrUp(img) up_down=cv2.pyrDown(up) cv_show(np.hstack((img,up_down)),'up_down') ``` ![](https://img.tnblog.net/arcimg/hb/903ec85858a64e1ba32412dd424bfc3f.png) ### 拉普拉斯金字塔 tn2>拉普拉斯金字塔的构建基于高斯金字塔,主要计算每一层与其下一层之间的差异,也就是高斯金字塔中的每一层图像与其下一层图像的差异。 将这些细节图像与高斯金字塔的上一层相应尺度的图像相加,就可以还原出原始图像。 ![](https://img.tnblog.net/arcimg/hb/ddd7a7af8d5849bf8fc8ff86eee32c46.png) ```python down=cv2.pyrDown(img) down_up=cv2.pyrUp(down) l_1=img-down_up cv_show(l_1,'l_1') ``` ![](https://img.tnblog.net/arcimg/hb/d626b65230ad45739690d94ef7c32225.png) ## 图像轮廓 tn2>通常我们再获取图像轮廓的时候,调用`cv2.findContours(img,mode,method)`方法。 `img`:通常是二值化后的灰度图。 `mode`:轮廓检索模式。一共有以下四种模式: `cv2.RETR_EXTERNAL`:只检索最外面的轮廓; `cv2.RETR_LIST`:检索所有的轮廓,并将其保存到一条链表当中; `cv2.RETR_CCOMP`:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界; `cv2.RETR_TREE`:检索所有的轮廓,并重构嵌套轮廓的整个层次; `method`:轮廓逼近方法 `cv2.CHAIN_APPROX_NONE`:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。 `cv2.CHAIN_APPROX_SIMPLE`:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。 ![](https://img.tnblog.net/arcimg/hb/46640391eb6c4f059fd1ac71f269705b.png) tn2>为了更高的准确率,使用二值图像。 ```python img = cv2.imread('contours.png') # 转成灰度图 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 设置阈值在127-255之间,进行二值化处理 ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) cv_show(thresh,'thresh') ``` ![](https://img.tnblog.net/arcimg/hb/158dcfbcaf83488ba86ebf7033a4576f.png) ```python # 检测图像中的对象边界 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) ``` ### 绘制轮廓 ```python #传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度 # 注意需要copy,要不原图会变。。。 draw_img = img.copy() res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2) cv_show(res,'res') ``` ![](https://img.tnblog.net/arcimg/hb/6d377465fb8742b9ae09b6428a6a7db9.png) tn2>绘制第一个。 ```python draw_img = img.copy() res = cv2.drawContours(draw_img, contours, 0, (0, 0, 255), 2) cv_show(res,'res') ``` ![](https://img.tnblog.net/arcimg/hb/177320e392bc49b2bc38e6ba8a0f483e.png) ### 轮廓特征 tn2>计算第一个图像的面积和周长。 ```python cnt = contours[0] #面积 cv2.contourArea(cnt) ``` >8500.5 ```python #周长,True表示闭合的 cv2.arcLength(cnt,True) ``` >437.9482651948929 ### 轮廓近似 tn2>轮廓近似(Contour Approximation)是图像处理和计算机视觉中的一种技术,用于减少轮廓的顶点数目,以简化轮廓的表示。 ![](https://img.tnblog.net/arcimg/hb/f3afa7ef8fc14e20bc7c933b2b94e9e5.png) ```python img = cv2.imread('contours2.png') # 二值化处理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_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') ``` ![](https://img.tnblog.net/arcimg/hb/1a2d2927d7bb4b2e87599bcb4cf60a7b.png) ```python # 计算轮廓周长(弧长)乘以的值越小0.01轮廓绘制越清晰 epsilon = 0.01*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,'res') ``` ![](https://img.tnblog.net/arcimg/hb/833177c3c8ee4bf98823d26ca1ad4859.png) ```python epsilon = 0.15*cv2.arcLength(cnt,True) ``` ![](https://img.tnblog.net/arcimg/hb/b73a812df96149c29382f1e3e702a3cf.png) ### 边界矩形 ```python img = cv2.imread('contours.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) cnt = contours[0] # 使用矩形包裹 x,y,w,h = cv2.boundingRect(cnt) # 绘制矩形框 img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) cv_show(img,'img') ``` ![](https://img.tnblog.net/arcimg/hb/133a97fcb8f943bfbab5909f3d460e0e.png) ```python # 计算第一个图的面积 area = cv2.contourArea(cnt) # 计算包裹这个图的矩形面积 x, y, w, h = cv2.boundingRect(cnt) rect_area = w * h extent = float(area) / rect_area print ('轮廓面积与边界矩形比',extent) ``` >轮廓面积与边界矩形比:0.5154317244724715 ### 外接圆 tn2>使用圆进行包裹。 ```python (x,y),radius = cv2.minEnclosingCircle(cnt) center = (int(x),int(y)) radius = int(radius) img = cv2.circle(img,center,radius,(0,255,0),2) cv_show(img,'img') ``` ![](https://img.tnblog.net/arcimg/hb/2f6d5d56aa5440789cbcea0f3359c06d.png) ## 模板匹配 tn2>模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv里有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是AxB大小,而模板是axb大小,则输出结果的矩阵是(A-a+1)x(B-b+1) tn>简单来讲:模板匹配就像在一张图片里找到一张小图片的位置,就像找到拼图的一块在整个拼图上的位置一样。 ```python # 模板匹配 img = cv2.imread('lena.jpg', 0) template = cv2.imread('face.jpg', 0) h, w = template.shape[:2] ``` ```python img.shape ``` >(263, 263) ```python template.shape ``` >(110, 85) | 模板匹配模式 | 描述 | | ------------ | ------------ | | TM_SQDIFF|计算平方不同,计算出来的值越小,越相关| | TM_CCORR|计算相关性,计算出来的值越大,越相关| | TM_CCOEFF|计算相关系数,计算出来的值越大,越相关| | TM_SQDIFF_NORMED|计算归一化平方不同,计算出来的值越接近0,越相关| | TM_CCORR_NORMED|计算归一化相关性,计算出来的值越接近1,越相关| | TM_CCOEFF_NORMED|计算归一化相关系数,计算出来的值越接近1,越相关| tn2>公式: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'] ``` ```python res = cv2.matchTemplate(img, template, cv2.TM_SQDIFF) res.shape ``` >(154, 179) ```python min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # 匹配结果矩阵中最小值,匹配结果矩阵中最大值,最小值的位置,最大值的位置 min_val, max_val, min_loc, max_loc ``` >(39168.0, 74403584.0, (107, 89), (159, 62)) tn2>遍历所有的模式: ```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() ``` ![](https://img.tnblog.net/arcimg/hb/b84f0dab06f6441e877d814fb98285de.png) ![](https://img.tnblog.net/arcimg/hb/22d38d8e72094dad8290608249a403f9.png) ![](https://img.tnblog.net/arcimg/hb/5f02dcb619954ac28a2d7a819d82a4c3.png) ![](https://img.tnblog.net/arcimg/hb/49c1c6453233487b98214b170baa6d5b.png) ![](https://img.tnblog.net/arcimg/hb/314ad8ec594546eda77c728ece7aca28.png) ![](https://img.tnblog.net/arcimg/hb/360399b8c1024d52a6564bee3c70c50e.png) ### 匹配多个对象 tn2>匹配多个金币。 ```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) ``` ![](https://img.tnblog.net/arcimg/hb/9e69b44ecb1b472aa1a6461974343453.png)
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739
👈{{preArticle.title}}
👉{{nextArticle.title}}
评价
{{titleitem}}
{{titleitem}}
{{item.content}}
{{titleitem}}
{{titleitem}}
{{item.content}}
尘叶心繁
这一世以无限游戏为使命!
博主信息
排名
6
文章
6
粉丝
16
评论
8
文章类别
.net后台框架
178篇
linux
18篇
linux中cve
1篇
windows中cve
0篇
资源分享
10篇
Win32
3篇
前端
28篇
传说中的c
5篇
Xamarin
9篇
docker
15篇
容器编排
101篇
grpc
4篇
Go
15篇
yaml模板
1篇
理论
2篇
更多
Sqlserver
4篇
云产品
39篇
git
3篇
Unity
1篇
考证
2篇
RabbitMq
23篇
Harbor
1篇
Ansible
8篇
Jenkins
17篇
Vue
1篇
Ids4
18篇
istio
1篇
架构
2篇
网络
7篇
windbg
4篇
AI
19篇
threejs
2篇
人物
1篇
嵌入式
20篇
python
20篇
HuggingFace
8篇
pytorch
10篇
opencv
6篇
Halcon
5篇
最新文章
最新评价
{{item.articleTitle}}
{{item.blogName}}
:
{{item.content}}
关于我们
ICP备案 :
渝ICP备18016597号-1
网站信息:
2018-2024
TNBLOG.NET
技术交流:
群号656732739
联系我们:
contact@tnblog.net
欢迎加群
欢迎加群交流技术