目录
上一篇: OpenCv_01——图像的基本操作
下一篇: OpenCv_03——图像特征
2. 图像处理
测试图像自取区
boss.jpg car.jpg card1 card2 cat.jpg dog.jpg girl.jpg girl1.jpg girl1_.jpg huo1.jpg img1.jpg maliao.jpg maliao_coin.jpg
2.1 图像阙值
#导包
import cv2
import matplotlib.pyplot as plt
#读取图片
img_cat=cv2.imread('cat.jpg')
ret,thresh1=cv2.threshold(img_cat,127,255,cv2.THRESH_BINARY)
ret,thresh2=cv2.threshold(img_cat,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3=cv2.threshold(img_cat,127,255,cv2.THRESH_TRUNC)
ret,thresh4=cv2.threshold(img_cat,127,255,cv2.THRESH_TOZERO)
ret,thresh5=cv2.threshold(img_cat,127,255,cv2.THRESH_TOZERO_INV)
titles=['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images=[img_cat,thresh1,thresh2,thresh3,thresh4,thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
2.2 图像平滑
#导包
import cv2
import matplotlib.pyplot as plt
#读数据
img=cv2.imread('cat.jpg')
#输出图片
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#均值滤波
#简单的平均卷积操作
blur=cv2.blur(img,(3,3))
cv2.imshow('blur',blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
#方框滤波
#基本和均值一样,可以选择归一化
box=cv2.boxFilter(img,-1,(3,3),normalize=True)
cv2.imshow('box',box)
cv2.waitKey(0)
cv2.destroyAllWindows()
#方框滤波
#基本和均值一样,可以选择归一化,容易越界
box=cv2.boxFilter(img,-1,(3,3),normalize=True)
cv2.imshow('box',box)
cv2.waitKey(0)
cv2.destroyAllWindows()
#高斯滤波
#高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的
aussian=cv2.GaussianBlur(img,(1,1),1)
cv2.imshow('aussian',aussian)
cv2.waitKey(0)
cv2.destroyAllWindows()
#中值滤波
#相当于用中值代替
median=cv2.medianBlur(img,5)
cv2.imshow('median',median)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np
#展示所有的
res=np.hstack((blur,aussian,median))
print(res)
cv2.imshow('median vc average',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
[[[122 147 191]
[121 146 190]
[120 145 189]
...
[114 138 184]
[114 138 184]
[115 139 185]]
[[121 146 190]
[121 146 190]
[119 144 188]
...
[113 137 183]
[114 138 184]
[114 138 184]]
[[120 145 189]
[119 144 188]
[118 143 187]
...
[112 136 182]
[113 137 183]
[114 138 184]]
...
[[178 201 233]
[178 201 233]
[178 201 233]
...
[191 211 240]
[192 212 242]
[193 213 243]]
[[180 203 235]
[180 203 235]
[180 203 235]
...
[192 211 242]
[192 212 242]
[193 213 243]]
[[181 204 236]
[181 204 236]
[181 204 236]
...
[192 212 243]
[192 212 243]
[193 213 243]]]
2.3 形态学操作
2.3.1 腐蚀操作
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('huo1.jpg')
cv2.imshow('huo',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904131831570](https://i-blog.csdnimg.cn/blog_migrate/b08f208f79ac179dc56ce6f28ef67337.png)
#腐蚀操作
kernel=np.ones((3,3),np.uint8)
erosion=cv2.erode(img,kernel,iterations=1)
cv2.imshow('erosion',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904131903460](https://i-blog.csdnimg.cn/blog_migrate/14b3038668131cf6756ad477df9480f9.png)
#膨胀操作
kernel=np.ones((3,3),np.uint8)
dilate=cv2.dilate(img,kernel,iterations=1)
cv2.imshow('dilate',dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904132011245](https://i-blog.csdnimg.cn/blog_migrate/0db5064a08ae26950b7b8c2ae90ec5b2.png)
2.3.2 开运算与闭运算
import cv2
import numpy as np
#开运算:先腐蚀,再膨胀
img=cv2.imread('huo1.jpg')
kerne1=np.ones((5,5),np.uint8)
opening=cv2.morphologyEx(img,cv2.MORPH_OPEN,kerne1)
cv2.imshow('opening',opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904133340381](https://i-blog.csdnimg.cn/blog_migrate/a04dff186a7810d374ff77c0751f0b97.png)
#闭运算:先膨胀,再腐蚀
img=cv2.imread('huo1.jpg')
kerne1=np.ones((5,5),np.uint8)
closing=cv2.morphologyEx(img,cv2.MORPH_CLOSE,kerne1)
cv2.imshow('closing',closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904133401255](https://i-blog.csdnimg.cn/blog_migrate/6ec8d25d0232e3e033a3c613aa1aa05a.png)
2.3.3 梯度运算
import cv2
import numpy as np
import matplotlib.pyplot as plt
#分别输出膨胀与腐蚀的图片
pie=cv2.imread('yuan.jpg')
kernel=np.ones((7,7),np.uint8)
dilate=cv2.dilate(pie,kernel,iterations=5)
erosion=cv2.erode(pie,kernel,iterations=5)
res=np.hstack((dilate,erosion))
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904133611776](https://i-blog.csdnimg.cn/blog_migrate/b3ffab86ab3d4bc1f61664ec7d347e52.png)
#梯度=膨胀-腐蚀
#梯度运算,输出边界图
gradient=cv2.morphologyEx(pie,cv2.MORPH_GRADIENT,kernel)
cv2.imshow('gradient',gradient)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904133653646](https://i-blog.csdnimg.cn/blog_migrate/2dff45cfbc38cf2ca200713a3fea3642.png)
2.3.4 礼帽与黑帽
import cv2
import numpy as np
import matplotlib.pyplot as plt
#礼帽=原始数据-开运算结果
img=cv2.imread('huo1.jpg')
kernel=np.ones((7,7),np.uint8)
tohat=cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('tohat',tohat)
cv2.waitKey(0)
cv2.destroyAllWindows()
#黑帽
img=cv2.imread('huo1.jpg')
kernel=np.ones((7,7),np.uint8)
blackhat=cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
cv2.imshow('blackhat',blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.4 图像梯度
2.4.1 Sobel算子
import cv2
import numpy as np
import matplotlib.pyplot as plt
img=cv2.imread('yuan.jpg',cv2.IMREAD_GRAYSCALE)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
![image-20220904134410221](https://i-blog.csdnimg.cn/blog_migrate/5cdbd9d2449b9b49143e00e9de021950.png)
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
#白到黑是整数,黑到白就是负数了,所有的负数会被截断成0,所以要取绝对值
cv_show('sobelx',sobelx)
![image-20220904135300584](https://i-blog.csdnimg.cn/blog_migrate/c9c7bbf76bb4f8ba0818dbb58be20100.png)
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx=cv2.convertScaleAbs(sobelx)
cv_show('sobelx',sobelx)
![image-20220904135334871](https://i-blog.csdnimg.cn/blog_migrate/7110241a8b9774f58d8c5cdbaee83516.png)
sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely=cv2.convertScaleAbs(sobely)
cv_show('sobely',sobely)
![image-20220904135403247](https://i-blog.csdnimg.cn/blog_migrate/a09f42d915497561daa5a54fd0bc21df.png)
#同时输出,比较
res=np.hstack((sobelx,sobely))
cv_show('res',res)
![image-20220904135431245](https://i-blog.csdnimg.cn/blog_migrate/47b513686b00f0c7c2453e6e0d5b809e.png)
#分别计算x和y,再求和
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show('sobelxy',sobelxy)
![image-20220904135600152](https://i-blog.csdnimg.cn/blog_migrate/60cf4b9984c2f230e8dc841d0a980a22.png)
#不建议直接计算
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy=cv2.convertScaleAbs(sobelxy)
cv_show('sobelxy',sobelxy)
#读取图片,用Sobel算子进行边缘输出
img=cv2.imread('boss.jpg',cv2.IMREAD_GRAYSCALE)
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx=cv2.convertScaleAbs(sobelx)
sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely=cv2.convertScaleAbs(sobely)
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
#效果图与原图的灰度图合并输出
res=np.hstack((img,sobelxy))
cv_show('res',res)
![image-20220904135759612](https://i-blog.csdnimg.cn/blog_migrate/e916e71ae65fa5d44ac2dcc63aceddc1.png)
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy=cv2.convertScaleAbs(sobelxy)
cv_show('sobelxy',sobelxy)
![image-20220904135928499](https://i-blog.csdnimg.cn/blog_migrate/251e8779b34c42a5d6be2e5ee1bd17a3.png)
2.4.2 Scharr算子与Lapkacian算子
Scharr算子
Lapkacian算子
import cv2
import numpy as np
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#比较
img=cv2.imread('boss.jpg',cv2.IMREAD_GRAYSCALE)
#Sobel算子
sobelx=cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely=cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx=cv2.convertScaleAbs(sobelx)
sobely=cv2.convertScaleAbs(sobely)
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
#Scharr算子
scharrx=cv2.Scharr(img,cv2.CV_64F,1,0)
scharry=cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx=cv2.convertScaleAbs(scharrx)
scharry=cv2.convertScaleAbs(scharry)
scharrxy=cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
#laplacian算子
laplacian=cv2.Laplacian(img,cv2.CV_64F)
laplacian=cv2.convertScaleAbs(laplacian)
#输出比较
res=np.hstack((sobelxy,scharrxy,laplacian))
cv_show('res',res)
2.5 边缘检测
Canny边缘检测
- 使用高斯滤波器,以平滑图像,滤除噪声。
- 计算图像中每个像素点的梯度强度和方向。
- 应用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
- 应用双赋值(Double-Threshold)检测来确定真实和潜在的边缘。
- 通过抑制独立的弱边缘最终完成边缘检测。
高斯滤波器
梯度和方向
![image-20220904141710899](https://i-blog.csdnimg.cn/blog_migrate/469fbc1b007211cca87c149880f836a7.png)
非极大值抑制
双阙值检测
import cv2
import numpy as np
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.imread('cat.jpg',cv2.IMREAD_GRAYSCALE)
#进行边缘检测
#minvalue和maxvalue的值由自己设置
v1=cv2.Canny(img,20,60)
v2=cv2.Canny(img,50,100)
res=np.hstack((v1,v2))
cv_show('res',res)
2.6 图像金字塔
向下采样法(缩小)
向上采样法(放大)
- 将图像在每个方向扩大为原来的两倍,新增的行和列用0填充
- 使用先前同样的内核(乘以四)与放大后的图像卷积,获得近似值
普拉斯金字塔
对输入图像实现金字塔的reduce操作就会生成不同分辨率的图像、对这些图像进行金字塔expand操作,然后使用reduce减去expand之后的结果就会得到图像拉普拉斯金字塔图像。
输入图像G(0)
金字塔reduce操作生成 G(1), G(2), G(3)
拉普拉斯金字塔:
L0 = G(0)-expand(G(1))
L1 = G(1)-expand(G(2))
L2 = G(2)–expand(G(3))
G(0)减去expand(G(1))得到的结果就是两次高斯模糊输出的不同,所以L0称为DOG(高斯不同)、它约等于LOG所以又称为拉普拉斯金字塔。所以要求的图像的拉普拉斯金字塔,首先要进行金字塔的reduce操作,然后在通过expand操作,最后相减得到拉普拉斯金字塔图像。
拉普拉斯金字塔生成过程
import cv2
import numpy as np
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.imread('girl.jpg')
cv_show('img',img)
print(img.shape)
![image-20220904143756578](https://i-blog.csdnimg.cn/blog_migrate/faa9aefdfb63b1c8abc5fd646f351c88.png)
#向上采样法
up=cv2.pyrUp(img)
cv_show('up',up)
print(up.shape)
#(1392, 1200, 3)
#向下采样法
down=cv2.pyrDown(img)
cv_show('down',down)
print(down.shape)
#(348, 300, 3)
#拉普拉斯金字塔
down=cv2.pyrDown(img)
down_up=cv2.pyrUp(down)
result=img-down_up
cv_show('result',result)
![image-20220904144303914](https://i-blog.csdnimg.cn/blog_migrate/22d9b2d6a14b1ec9ca2b3850ce604d5c.png)
2.7 轮廓检测
2.7.1 图像轮廓
cv2.findContours(img,mode,method)
mode:轮廓检索模式
参数 | 说明 |
---|---|
RETR_EXTERNAL | 只检索最外面的轮廓 |
RETR_LIST | 检索所有的轮廓,并将其保存到一条链表中 |
RETR_CCOMP | 检索所有的轮廓,并将它们组织为两层;顶层是各部分的外部链接,第二层是空洞的边界 |
RETR_TREE | 检索所有的轮廓,并重构嵌套轮廓的层次 |
medthod:轮廓逼近方法
参数 | 说明 |
---|---|
CHAIN_APPROX_NONE | 以Freem链码的方式输出轮廓,所有其他方法输出多边形(顶点的轮廓) |
CHAIN_APPROX_SIMPLE | 压缩水平的、垂直的和斜的部分,也就是,函数只保留它们的终点部分 |
为了更高的准确率,使用二值图像
import cv2
import numpy as np
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#为了更高的准确率,使用二值图像
img=cv2.imread('car.jpg')
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)
cv_show('binary',binary)
![image-20220904152321883](https://i-blog.csdnimg.cn/blog_migrate/9fa3d23d5e8d65ffa07a8ce9f49d3b7b.png)
2.7.2 绘制轮廓
cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
参数 | 说明 |
---|---|
第一个参数 | 指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓 |
第二个参数 | 是轮廓本身,在Python中是一个list; |
thickness参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。
#引入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
#需要注意copy,要不原图会变
res=img.copy()
res=cv2.drawContours(res,contours,-1,(0,0,255),2)
cv_show('res',res)
![image-20220904152416483](https://i-blog.csdnimg.cn/blog_migrate/6a138c531a5646e498185ef7fc0af8d3.png)
#轮廓特征
cnt=contours[0]
#面积
cv2.contourArea(cnt)
#0.0
#周长,True表示闭合的
cv2.arcLength(cnt,True)
#0.0
2.7.3 轮廓近似
cv2.approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)
参数 | 说明 |
---|---|
InputArray curve | 输入的点集 |
OutputArray approxCurve | 输出的点集,当前点集是能最小包容指定点集的。画出来即是一个多边形 |
double epsilon | 指定的精度,也即是原始曲线与近似曲线之间的最大距离 |
bool closed | 若为true,则说明近似曲线是闭合的,反之,若为false,则断开 |
img=cv2.imread('img1.jpg')
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)
![image-20220904152838721](https://i-blog.csdnimg.cn/blog_migrate/e72bc58a800548bb699a95b5b2da4f4b.png)
espsilon=0.05*cv2.arcLength(cnt,True)
approx=cv2.approxPolyDP(cnt,espsilon,True)
draw_img=img.copy()
res=cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
cv_show('res',res)
2.7.4 边界矩形
cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
-
第一个参数:img是原图
-
第二个参数:(x,y)是矩阵的左上点坐标
-
第三个参数:(x+w,y+h)是矩阵的右下点坐标
-
第四个参数:(0,255,0)是画线对应的rgb颜色
-
第五个参数:2是所画的线的宽度
img=cv2.imread('img1.jpg')
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]
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)
![image-20220904153123870](https://i-blog.csdnimg.cn/blog_migrate/068d0e348529cfc51656500eed6a8316.png)
#轮廓面积与边界矩形比
area=cv2.contourArea(cnt)
x,y,w,h=cv2.boundingRect(cnt)
rect_area=w*h
extent=float(area)/rect_area
print("轮廓面积与边界矩形比",extent)
#轮廓面积与边界矩形比 0.7065451180472189
2.7.5 外接圆
center, radius = cv.minEnclosingCircle( points )
参数 | 描述 |
---|---|
center | 返回值,圆的中心 |
radius | 返回值,半径 |
points | 目标物体的点 |
(x,y),radius=cv2.minEnclosingCircle(cnt)
center=(int(x),int(y))
radius=int(radius)
img=cv2.circle(img,center,radius,(0,2555,0),2)
cv_show('img',img)
![image-20220904153337132](https://i-blog.csdnimg.cn/blog_migrate/4e9741636f464b5afe96b16b82220429.png)
2.8 模板匹配
模板匹配和卷积原理很像,模板在原图像上从原点开始滑动,计算模板与(图像被模板覆盖的地方)的差别程度,这个差别程度的计算方法在opencv中有6种,然后将每次计算的结果放入一个矩阵里,作为结果输出。假如原图形是A乘B大小,而模板是a乘b大小,则结果输出的矩阵是(A-a+1)×(B-b+1)
import cv2
import numpy as np
import matplotlib.pyplot as plt
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#模板匹配
img=cv2.imread('girl1.jpg',0)
template=cv2.imread('girl1_.jpg',0)
h,w=template.shape[:2]
h
#901
w
#629
img.shape
#(2340, 1080)
template.shape
#(901, 629)
methods=['cv2.TM_CCOEFF','cv2.TM_CCOEFF_NORMED','cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED','cv2.TM_SQDIFF','cv2.TM_SQDIFF_NORMED']
方法 | 说明 |
---|---|
TM_CCOEFF | 计算相关系数,计算出来的值越大,越相关。 |
TM_CCOEFF_NORMED | 计算归一化相关系数,计算出来的值越接近1,越相关。 |
TM_CCORR | 计算相关性,计算出来的值越打,越相关。 |
TM_CCORR_NORMED | 计算归一化相关性,计算出来的值越接近1,越相关。 |
TM_SQDIFF | 计算平方不同,计算出来的值越小,越相关。 |
TM_SQDIFF_NORMED | 计算归一化平方不同,计算出来的值越接近0,越相关。 |
res=cv2.matchTemplate(img,template,cv2.TM_SQDIFF)
res.shape
#(1440, 452)
cv2.minMaxLoc(src, mask=None)
函数功能:假设有一个矩阵a,现在需要求这个矩阵的最小值,最大值,并得到最大值,最小值的索引。
咋一看感觉很复杂,但使用这个cv2.minMaxLoc()函数就可全部解决。函数返回的四个值就是上述所要得到的
min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(res)
min_val
#190976.0
max_val
#8067120640.0
min_loc
#(256, 422)
max_loc
#(451, 0)
eval是Python的一个内置函数,功能十分强大,这个函数的作用是,返回传入字符串的表达式的结果。
就是说:将字符串当成有效的表达式 来求值 并 返回计算结果。
cv2.rectangle(img, pt1, pt2, color, thickness, lineType, shift )
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,20)
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('maliao.jpg')
img_gray=cv2.cvtColor(img_rgb,cv2.COLOR_BGR2GRAY)
template=cv2.imread('maliao_coin.jpg',0)
h,w=template.shape[:2]
res=cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
#取匹配度大于80%的坐标
threshold=0.8
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)
2.9 直方图
2.9.1 直方图定义
cv2.calcHist(images,channels,mask,histSize,ranges)
参数 | 说明 |
---|---|
images | 原图像图像格式为uint8或float32.当传入函数时应用中括号[]括,例如[img]。 |
channels | 同样用中括号来括它会告知函数我们统幅图像的直方图。如果入图像是灰度图它的值就是[0],如果是彩色图像的传入的参数可以是[0][1][2],它们分别对应着BGR。 |
mask | 掩膜图像。统整幅图像的直方图就把它为None。如果你想同图像某一分的直方图的,你就制作一个掩膜图像并使用它。 |
histSize | BIN的数目。也应用种括号来括。 |
ranges | 像素值的范围为[0,256]。 |
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.imread('girl1.jpg',0)#0表示灰度图
hist=cv2.calcHist([img],[0],None,[256],[0,256])
hist.shape
#(256, 1)
#ravel()将多维数据展平为一维数据
plt.hist(img.ravel(),256)
plt.show()
img=cv2.imread('girl1.jpg')
color=('b','g','r')
for i,col in enumerate(color):
histr=cv2.calcHist([img],[i],None,[256],[0,256])
plt.plot(histr,color=col)
plt.xlim([0,256])
#创建mask掩码
mask=np.zeros(img.shape[:2],np.uint8)
mask[100:300,100:400]=255
cv_show('mask',mask)
img=cv2.imread('cat.jpg',0)
plt.hist(img.ravel(),256)
plt.show()
#均衡化函数
equ=cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()
#均衡化之后的图像
res=np.hstack((img,equ))
cv_show('res',res)
2.9.3 直方图均衡化
cv2.createCLAHE(clipLimit,tileGridSize)
参数 | 说明 |
---|---|
clipLimit | 裁剪限制,此值与对比度受限相对应,对比度限制这个参数是用每块的直方图的每个bins的数和整图的平均灰度分布数的比值来限制的。 裁剪则是将每块图像直方图中超过ClipLimit的bins多出的灰度像素数去除超出部分,然后将所有bins超出的像素数累加后平均分配到所有bins。 |
tileGridSize | 图像被分成称为“tiles”(瓷砖、地砖、小方地毯、片状材料、块状材料)的小块,在OpenCV中,tilesGridSize默认为8x8 ,即整个图像被划分为8纵8横共64块。然后对每一个块进行直方图均衡处理。 |
cat=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
res_cat=cat.apply(img)
res=np.hstack((img,equ,res_cat))
cv_show('res',res)
2.10 傅里叶
2.10.1 傅里叶概述
傅里叶变换
我们生活在时间的世界中,早上7:00起来吃早饭,8:00去挤地铁,9:00开始上班,,,以时间为参照就是时域分析。
但是我们在频域中一切都是静止的。
傅里叶变换的作用
- 高频:变化剧烈的灰度分量,例如边界。
- 低频:变化缓慢的灰度分量,例如一片大海。
滤波
-
低通滤波器:只保留低频,会使图像模糊。
-
高通滤波器:只保留高频,会使图像细节增强。
-
opencv中主要是以cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32格式。
-
得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现。
-
cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才可能展示(0,255)
2.10.2 代码实现
import cv2
import numpy as np
import matplotlib.pyplot as plt
cv2.dft(原始图像,转换标识)
这里的原始图像必须是np.float32格式。所以,我们首先需要使用cv2.float32()函数将图像转换。
而转换标识的值通常为cv2.DFT_COMPLEX_OUTPUT,用来输出一个复数阵列。
cv2.magnitude(参数1,参数2)
参数1:浮点型x坐标值,也就是实部
参数2:浮点型y坐标值,也就是虚部,它必须和参数1具有相同的大小(size)
得到频谱图像的幅度之后,还需要将幅度映射到灰度空间[0,255]内,使其以灰度图像显示出来。与前篇博文一样,使用20*np.log(cv2.magnitude())。
img=cv2.imread('dog.jpg',0)
img_float32=np.float32(img)
dft=cv2.dft(img_float32,flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift=np.fft.fftshift(dft)
#得到灰度图能表示的形式
magnitude_sepctrum=20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_sepctrum,cmap='gray')
plt.title('Magnitude Spectrum'),plt.xticks([]),plt.yticks([])
plt.show()
img=cv2.imread('dog.jpg',0)
img_float32=np.float32(img)
dft=cv2.dft(img_float32,flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift=np.fft.fftshift(dft)
rows,cols=img.shape
crow,ccol=int(rows/2),int(cols/2) #中心位置
#低通滤波
mask=np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30]=1
#IDFT
fshift=dft_shift*mask
f_ishift=np.fft.ifftshift(fshift)
img_back=cv2.idft(f_ishift)
img_back=cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('Input Image'),plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(img_back,cmap='gray')
plt.title('Result'),plt.xticks([]),plt.yticks([])
plt.show()