一、图像轮廓
1.图像轮廓
#边缘检测可以把图像的边缘检测出来,但是边缘是不连续的
#将边缘连接成一个整体,构成轮廓
#图像轮廓注意事项
#1.图像轮廓处理的对象是二值图像,需要预先进行阈值分割(得到二值图像)或者边缘检测(Canny边缘检测得到的图像就是黑白的)
#2.查找轮廓的时候会改变原始图像,需要将原始图像备份
#3.在openCv中二值图像白色是前景,黑色是背景或者孔。所以,对象必须是白色,背景必须是黑色,否则就转换。
#寻找图像的轮廓信息函数:cv2.findContours
#image,contours,hierarchy=cv2.findContours(原始图像,轮廓检索模式,轮廓的近似方法)
#image是修改后的原始图像,contours是轮廓,hierarchy是图像的拓扑信息(轮廓层次)
#轮廓检索模式:cv2.RETR_TREE
#cv2.RETR_EXTERNAL:表示只检索外轮廓
#cv2.RETR_LIST:检测的轮廓不建立等级关系
#cv2.RETR_CCOMP:建立两个等级的轮廓,上面一层是外边界,里面一层是内孔的边界信息。
# 如果内孔里面还有一个连通物体,这个物体的边界也在顶层
#cv2.RETR_TREE:建立一个等级树的轮廓:一般都用这个
#轮廓的近似方法
#cv2.CHAIN_APPROX_NONE:存储所有的轮廓点
#cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直方向、对角线方向的元素,只保留该方向的终点坐标。例如一个矩形轮廓只用四个点保存轮廓信息
#cv2.drawContours():绘制图像的轮廓信息
#dst=cv2.drawContours(原始图像,contours,contourldx,colour,thickness)
#contours是绘制的轮廓的数组,contourldx是需要绘制的边缘索引,如果全部绘制就-1
#color是绘制的颜色,为BGR格式的,thickness是画笔的粗细
import cv2
import numpy as np
img=cv2.imread("/Users/macbook/Desktop/face.png")#原始图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转换成灰度图像
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#转换成二值图像
cv2.imshow("original",img)
#寻找轮廓信息:树结构等级关系,压缩水平、垂直、对角线方向的元素
img1,contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#绘制轮廓信息的时候,原始图像会发生改变,要把原始图像复制一份
img_changed=img.copy()#**************************************************************
#绘制轮廓信息:用红色的厚度为1的画笔画出全部的外轮廓
result=cv2.drawContours(img_changed,contours,-1,(0,0,255),1)
cv2.imshow("result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
二、直方图
1.直方图的基本概念
#直方图:
#横坐标是图像中各个像素点的灰度级,纵坐标是该灰度级的像素个数
#归一化直方图:
#横坐标是图像中各个像素点的灰度级,纵坐标是该灰度级出现的概率,就是用个数/像素点总数
#概念:DIMS:使用参数的数量,灰度直方图就是1;BINS参数子集的数目;Range:一般就是【0,255】
2.绘制直方图
#hist函数用来绘制直方图
#hist(数据源,像素级)
#数据源:图像,必须是一维数组 数据源=原始图像.ravel()
#像素级一般是256,即[0,255]
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
cv2.imshow("original",img)
#绘制灰度直方图,直接就会绘制出来
plt.hist(img.ravel(),256)
cv2.waitKey(0)
cv2.destroyAllWindows()
3.使用opencv统计直方图和绘制
#使用opencv统计直方图
#hist=cv2.calcHist(image,channels,mask,histSize,ranges,accumulate)
#hist是返回值:返回的是直方图,本质上是一个一维数组,不是真正意义上的直方图
#image是原始图像,要用[]使用
#channels:指定通道,灰度图像直接就是[0],彩色图像[0][1][2]分别对应BGR
#mask:掩码图像。统计整幅图像的直方图,就用none;统计图像某一部分的直方图,就用掩码图像
#histSize:BINS的数量,一般是[256]
#ranges:像素值的范围,一般就是[0,255]
#accumulate:默认是false。如果是true,可以用于从多个对象中绘制单个直方图,或者用于实时更新直方图
#绘制直方图
#plt.plot(统计直方图的结果,颜色)
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png")
#使用opencv统计直方图
#蓝色通道的统计直方图
histb=cv2.calcHist([img],[0],None,[256],[0,255])#默认accumulate是false
#绿色通道的统计直方图
histg=cv2.calcHist([img],[1],None,[256],[0,255])
#红色通道的统计直方图
histr=cv2.calcHist([img],[2],None,[256],[0,255])
#绘制opencv统计直方图
plt.plot(histb,color='b')#绘制颜色是蓝色的蓝色通道的直方图
plt.plot(histg,color='g')#绘制颜色是绿色的绿色通道的直方图
plt.plot(histr,color='r')#绘制颜色是红色的红色通道的直方图
4.使用掩膜的直方图Mask
#生成一个与原始图像大小相同的黑色的图像 mask=np.zeros(image.shape,np.uint8)
#在黑色图像上再添加一张白色的图片 mask[x1:x2,y1:y2]=255
#掩膜之后图片的处理结果就是只保留图片在掩膜白色区域的部分,用来针对图片中的某一部分处理
import import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#生成掩膜
mask=np.zeros(img.shape,np.uint8)#生成与原始图像大小相同的黑色图片
mask[200:400,200:400]=255#掩膜的中间区域是白色
#有掩膜的直方图
hist=cv2.calcHist([img],[0],mask,[256],[0,255])
#没有掩膜的直方图
hist1=cv2.calcHist([img],[0],None,[256],[0,255])
#绘制有掩膜的直方图
plt.plot(hist)
#绘制没有掩膜的直方图
plt.plot(hist1)
5.掩膜图像的处理
#掩膜之后图片的处理结果就是只保留图片在掩膜白色区域的部分,用来针对图片中的某一部分处理
#生成一个与原始图像大小相同的黑色的图像 mask=np.zeros(image.shape,np.uint8)
#在黑色图像上再添加一张白色的图片 mask[x1:x2,y1:y2]=255
#生成掩膜图像 cv2.bitwise_and(img,mask)
#mask就是掩膜图像,img是原始图像
import cv2
import numpy as np
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#构建掩膜图像
mask=np.zeros(img.shape,np.uint8)
mask[50:100,50:100]=255
#生成掩膜图像
result=cv2.bitwise_and(img,mask)
cv2.imshow("result",result)
cv2.waitKey(0)
cv2.destroyAllWindows()
6.直方图均衡化原理
#直方图的均衡化处理原因:
#如果一幅图像占有全部可能的灰度级,并且均匀分布。那么该图像就会有高对比度和多变的灰色色调。图像的细节会更加丰富,质量更高
#直方图均衡化的算法:
#1.计算统计直方图,对统计直方图进行归一化处理,并且逐步加和得到累计直方图
#2.将累计直方图进行区间转换:将累计直方图中的纵坐标乘上255得到像素值结果,新的横坐标就是该结果,纵坐标就是原来的概率
#3.在累计直方图中,概率相近的原始值,会被处理成相同的值
#应用场景:医疗图像识别、车牌识别、人脸识别
#函数:cv2.equalizeHist(scr)
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#直接绘制直方图,不进行均衡化处理
plt.hist(img.ravel(),256)
plt.figure()#创建新的窗口
#进行均衡化处理的直方图
img1=cv2.equalizeHist(img)
#绘制均衡化处理后的直方图
plt.hist(img1.ravel(),256)
7.subplot函数的使用
#subplot函数的使用:subplot(行数,列数,窗口序号)
#当三个参数都小于10,就可以去掉逗号,例如subplot(2,3,4)=subplot(234)
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#不进行直方图均衡化的直方图的绘制
plt.subplot(1,2,1)
plt.hist(img.ravel(),256)#进行一行两列第一个窗口的绘制
#进行直方图均衡化的直方图绘制
img1=cv2.equalizeHist(img)
plt.subplot(122)
plt.hist(img1.ravel(),256)#进行一行两列第二个窗口的绘制
8.matplotlib.pyplot.imshow函数使用
#imshow(要绘制图像,cmap)
#cmap:默认情况下是RGB图像;
# 如果是灰度图像,就用plt.cm.gray
#如果是通过opencv读取的图像,默认是BGR颜色空间,但是matplotlib.pyplot.imshow()默认的颜色空间是RGB,所以要进行转换颜色空间
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png")#原始图像是BGR颜色空间的图像
img_gray=cv2.cvtColor(img,cv2.COLOR_BGRA2GRAY)#将原始图片转换成灰度图片
#在下列的图片中,只有第四个图像的显示结果是正确的
#两行两列的第一个窗口的显示:使用默认通道顺序显示img--显示结果是错的
plt.subplot(2,2,1)
plt.imshow(img)
plt.axis('off')#坐标轴显示关闭
#两行两列的第二个窗口显示:使用灰度显示img--显示结果是错的
plt.subplot(222)
plt.imshow(img,plt.cm.gray)
plt.axis('off')#坐标轴显示关闭
#两行两列第三个窗口显示:使用默认通道顺序显示img_gray--显示结果是错的
plt.subplot(223)
plt.imshow(img_gray)
plt.axis('off')#坐标轴显示关闭
#两行两列第四个窗口显示:使用灰度显示img_gray--显示结果是对的
plt.subplot(224)
plt.imshow(img_gray,plt.cm.gray)
plt.axis('off')#坐标轴显示关闭
#彩色图像的正确展示
b,g,r=cv2.split(img)
img1=cv2.merge([r,g,b])
plt.suplot(121)
plt.imshow(img1)
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(img_gray,plt.cm.gray)
plt.axis('off')
9.直方图均衡化的对比
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#两行两列的第一个窗口:原始的灰度图像的显示
plt.subplot(2,2,1)
plt.imshow(img,plt.cm.gray)#使用灰度图像显示的方式
plt.axis('off')#关闭图像的坐标轴
#两行两列的第二个窗口:经过直方图均衡化的图像的显示
img1=cv2.equalizeHist(img)#对原始图像进行直方图均衡化
plt.subplot(2,2,2)
plt.imshow(img1,plt.cm.gray)#使用灰度图像显示的方式
plt.axis('off')#关闭图像的坐标轴
#两行两列的第三个窗口:没有经过均衡化的直方图
plt.subplot(2,2,3)
plt.hist(img.ravel(),256)
#两行两列的第四个窗口:经过均衡化的直方图
plt.subplot(224)
plt.hist(img1.ravel(),256)
三、傅里叶变换
1.numpy实现傅立叶变换
#numpy实现傅立叶变换函数
#numpy.fft.fft2:实现傅立叶变换,返回的是一个复数数组
#numpy.fft.fftshift:将零频率分量移到频谱中心
#20*np.log(np.abs(fshift)):设置频谱的范围,映射到0-255
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#实现傅立叶变换,获得低频和高频信息
f=np.fft.fft2(img)
#将低频信息移到频谱中心
fshift=np.fft.fftshift(f)
#设置频谱的范围
result=20*np.log(np.abs(fshift))
#设置一行两列的第一个窗口:
plt.subplot(1,2,1)
plt.imshow(img,plt.cm.gray)#用灰度通道的形式展现原始的灰度图片
plt.title("original")#设置第一个窗口的名字是original
plt.axis('off')#去除图像的坐标轴
#设置一行两列的第二个窗口:
plt.subplot(1,2,2)
plt.imshow(result,plt.cm.gray)#用灰度通道的形式展现经过傅立叶变换的图片
plt.title("result")#设置第一个窗口的名字是result
plt.axis('off')#去除图像的坐标轴
plt.show()
2.numpy实现逆傅立叶变换
#傅立叶变换的过程是可逆的,图像经过傅立叶变换和逆傅立叶变换后,能够恢复到原始图像
#可以在频域对图像进行处理,在频域的处理会反映在变换图像上
#numpy.fft.ifft2:实现逆傅立叶变换
#numpy.fft.ifftshift:fftshift的逆函数:将低频由频谱中心移到零频位置上
#iimg=np.abs:设置值的范围,调整到【0-255】
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#傅立叶变换
f=np.fft.fft2(img)#实现傅立叶变换,得到低频和高频的信息
fshift=np.fft.fftshift(f)#将零频律分量移到频谱中心
result1=20*np.log(np.abs(fshift))#傅立叶变换的结果
#逆傅立叶变换
i1=np.fft.ifftshift(fshift)#将低频由频谱中心移到零频位置上
i2=np.fft.ifft2(i1)#实现逆傅立叶变换
result2=np.abs(i2)#设置值的范围,调整到【0-255】
plt.subplot(1,3,1)
plt.imshow(img,plt.cm.gray)
plt.title("original")
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(result1,plt.cm.gray)
plt.title("result1")
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(result2,plt.cm.gray)
plt.title("result2")
plt.axis('off')
plt.show()
3.高通滤波演示
细节会丢失,增强边缘尖锐信息
#低频:对应图像内变化缓慢的灰度分量
#例如:在一幅大草原的图像中,低频表示广袤的颜色趋向于一致的草原
#高频:对应图像内变化越来越快的灰度分量,由灰度的尖锐过度造成的
#例如:在一幅大草原的图像中,其中狮子的边缘等信息
#滤波:接受和拒绝一定频率的分量
#通过低频的滤波器是低通滤波器:低频通过,高频衰减,图像将会变模糊(边缘信息丢失,细节保留)
#通过高频的滤波器是高通滤波器:高频通过,低频衰减,图像增强了尖锐细节,但是图像的对比度降低(边缘信息保留,细节丢失)
#先对图像进行傅立叶变换,再对图像的低频和高频进行处理以达到特殊目的,再进行逆傅立叶变换返回图像域
#特殊目的:图像增强、图像去噪、边缘检测、特征提取、压缩、加密等
import cv2
import numpy as np
import matplotlip as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#傅立叶变换
f=np.fft.fft2(img)#进行傅立叶变换,得到高频和低频信息
fshift=np.fft.fftshift(f)#将零频区域移到频谱中心
#高通滤波器,去掉低频,低频已经被移到了中心
rows,cols=img.shape
crow,ccol=int(rows/2),int(cols/2)
fshift[crow-30:crow+30,ccol-30:ccol+30]=0
#逆傅立叶变换
i1=np.fft.ifftshift(fshift)#将频谱中心移到原处
i2=np.fft.ifft(i1)#逆傅立叶变换
result=np.abs(i2)#设置值的范围,调整到【0-255】
plt.subplot(1,2,1)
plt.imshow(img,plt.cm.gray)
plt.title("original")
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(result,plt.cm.gray)
plt.title("result")
plt.axis('off')
plt.show()
4.opencv实现傅立叶变换
#cv2.dft(scr,转换标识)
#返回结果是双通道的,第一个是结果的实数部分,第二个是结果的虚数部分
#scr:np.float32(原始图像)
#转换标识:cv2.DFT_COMPLEX_OUTPUT,输出一个复数阵列
#numpy.fft.fftshift:将零频律分量移动到频谱中心
#结果图像=20*np.log(cv2.magnitude(实部部分,虚部部分))
import cv2
import numpy as np
import matplotlip as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#傅立叶变换
f=cv2.dft(np.float32(img),cv2.DFT_COMPLEX_OUTPUT)#傅立叶变换
fshift=np.fft.fftshift(f)#将零频律分量移动到频谱中心
result=20*np.log(cv2.magnitude(fshift[:,:,0],fshift[:,:,1]))
plt.subplot(121)
plt.imshow(img,plt.cm.gray)
plt.title("orginal")
plt.axis('off')
plt.subplot(122)
plt.imshow(result,plt.cm.gray)
plt.title("result")
plt.axis('off')
plt.show()
5.opencv实现逆傅立叶变换
import cv2
import numpy as np
import matplotlip.pyplot as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#傅立叶变换
f=cv2.dft(np.float32(img),cv2.DFT_COMPLEX_OUTPUT)#傅立叶变换
fshift=np.fft.fftshift(f)#将零频移动到频谱中心
result1=np.log(cv2.magnitude(fshift[:,:,0],fshift[:,:,1]))#得到傅立叶变换的结果
ishift=np.fft.ifftshift(fshift)#将低频由频谱中心移到零频位置上
i=cv2.idft(ishift)#逆傅立叶变换
result2=cv2.magnitude(i[:,:,0],i[:,:,1])#得到逆傅立叶变换结果
plt.subplot(1,3,1)
plt.imshow(img,plt.cm.gray)
plt.title("original")
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(result1,plt.cm.gray)
plt.title("result1")
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(result2,plt.cm.gray)
plt.title("result2")
plt.axis('off')
plt.show()
6.低通滤波示例
import cv2
import numpy as np
import matplotlip as plt
img=cv2.imread("/Users/macbook/Desktop/face.png",cv2.IMREAD_GRAYSCALE)
#傅立叶变换
f=cv2.dft(np.float32(img),cv2.DFT_COMPLEX_OUTPUT)#傅立叶变换
fshift=np.fft.fftshift(f)#将零频移动到频谱中心
result1=np.log(cv2.magnitude(fshift[:,:,0],fshift[:,:,1]))#傅立叶变换结果图像
#低通滤波器
rows,cols=img.shape
mask=np.zeros((rows,cols,2),np.uint8)
crows,ccols=int(rows/2),int(cols/2)
mask[crows-30:crows+30,ccols-30:ccols+30]=1
fshift1=fshift*mask#滤波
#逆傅立叶变换
i1=np.fft.ifftshift(fshift1)#将频谱中心移到原处
i2=cv2.idfs(i1)#逆傅立叶变换
result2=cv2.magnitude(i2[:,:,0],i2[:,:,1])#得到逆傅立叶变换结果
plt.subplot(1,2,1)
plt.imshow(img,plt.cm.gray)
plt.title("original")
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(result2,plt.cm.gray)
plt.title("result2")
plt.axis('off')
plt.show()