直方图
1. 直方图
绘制直方图(两种)
(1)cv2.calcHist() + matplotlib.pyplot.plot(hist,color)
hist = cv2.calcHist(images,channels,mask,histSize,ranges)
返回值:
hist 是一个 shape 为 (256,1) 的数组,表示 0-255 每个像素值对应的像素个数,下标即为相应的像素值
参数:
images:原图像格式为 uint8 或 float32,当传入时应用中括号 [] 括起来,例如 [img]
channels:选择图像的通道,用中括号括起来。如果图像是灰度图,它的值就是 [0];如果是彩色图像的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。
mask:掩膜,是一个大小和 image 一样的 np 数组,其中把需要处理的部分指定为 1,不需要处理的部分指定为 0。一般设置为 None 表示处理整幅图像
histSize:BIN 的数目(使用多少个 bin 柱子,一般为 256),用中括号括来
ranges:像素值范围常为 [0,256]
matplotlib.pyplot.plot(hist,color) 进行绘制
(2)matplotlib.pyplot.hist()
matplotlib.pyplot.hist(img.ravel(),bins,ranges,color)
img.ravel():将原图像的 array 数组转成一维的数组
bins:条形的个数
ranges:为灰度范围 [0,255]
color:指定颜色
# opencv图像读取的格式是BGR
# matplotlib读取图像的格式是RGB
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#直方图
img = cv2.imread("lena.png",0) #0表示灰度图
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.hist(img.ravel(),256) #ravel()将多维数组降位一维,返回的是视图
plt.suptitle("gray")
plt.show()
img2 = cv2.imread("lena.png")
color = ("b","g","r")
#enumerate()函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
for i,col in enumerate(color):
hist = cv2.calcHist([img2],[i],None,[256],[0,256])
plt.plot(hist,color = col)
plt.xlim([0,256])
plt.suptitle("color")
掩膜 mask 操作
用选定的图像、图形或物体,对处理的图像(全部或局部)进行遮挡,来控制图像处理的区域或处理过程。用于覆盖的特定图像或物体称为掩膜。
数字图像处理中,图像掩膜主要用于:
① 提取感兴趣区,用预先制作的感兴趣区掩模与待处理图像相乘,得到感兴趣区图像,感兴趣区内图像值保持不变,而区外图像值都为 0。
② 屏蔽作用,用掩模对图像上某些区域作屏蔽,使其不参加处理或不参加处理参数的计算,或仅对屏蔽区作处理或统计。
③ 结构特征提取,用相似性变量或图像匹配方法检测和提取图像中与掩膜相似的结构特征。
④ 特殊形状图像的制作。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 创建mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
img = cv2.imread("lena.png", 0)
masked_img = cv2.bitwise_and(img, img, mask=mask) #bitwise_and对每个像素值进行二进制与操作
result = np.hstack((mask,img,masked_img))
result = cv2.resize(result, (0, 0), fx=0.5, fy=0.5) #x/y均缩小一半
cv_show("mask",result)
plt.imshow(result)
图像基本运算
dst = add(src1, src2, mask=noArray(), dtype=-1) #相加 dst = src1 + src2
dst = subtract(src1, src2, mask=noArray(),dtype=-1) #相减 dst = src1 - src2
dst = multiply(src1, src2, double scale=1,dtype=-1) #相乘 dst = scale*src1*src2
dst = divide(src1, src2, double scale=1,dtype=-1) #相除 dst = scale*src1/src2
dst = divide(double scale, src2, dtype=-1) #相除 dst = scale/src2
dst = scaleAdd(src1, double alpha, src2) #dst = alpha*src1 + src2
dst = addWeighted(src1, double alpha, src2, double beta, double gamma, dtype=-1) #dst = alpha*src1 + beta*src2 + gamma
dst = sqrt(src) #计算每个矩阵元素的平方根
dst = pow(src, double power) #src的power次幂
dst = exp(src) #dst = e**src(**表示指数的意思)
dst = log(src) #对数 dst = log(abs(src))
四个按位操作函数
对图像(灰度图像或彩色图像均可)每个像素值进行二进制位操作
bitwise_and(src1, src2, mask=noArray()) #与 dst = src1 & src2
bitwise_or(src1, src2, mask=noArray()) #或dst = src1 | src2
bitwise_xor(src1, src2, mask=noArray()) #异或 dst = src1 ^ src2
bitwise_not(src, mask=noArray()) #非 dst = ~src
2. 直方图均衡化
cv2.equalizeHist(img) 将原图像【要求是灰度图像】传入,返回值即为均衡化后的图像
#import、函数cv_show与前面一样,省略,仅修改下面
img = cv2.imread("lena.png",0) #0表示灰度图
equ = cv2.equalizeHist(img) #直方图均衡化
plt.hist(equ.ravel(),256) #绘制图
plt.show()
3. 自适应直方图均衡化
用于生成自适应均衡化图像
cv2.createCLAHA(clipLimit, titleGridSize)
clipLimit:颜色对比度的阈值
titleGridSize:进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
#import、函数cv_show与前面一样,省略,仅修改下面
img = cv2.imread("lena.png",0) #0表示灰度图
equ = cv2.equalizeHist(img) #直方图均衡化
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) #生成自适应均衡化图像
res_clahe = clahe.apply(img) #进行自适应直方图均衡化
result = np.hstack((img,equ,res_clahe))
result = cv2.resize(result, (0, 0), fx=0.5, fy=0.5) #x/y均缩小一半
cv_show("Compare the three graphs",result)
plt.imshow(result)
傅里叶变换
傅里叶变换的作用
高频:变化剧烈的灰度分量,例如边界
低频:变化缓慢的灰度分量,例如一片大海
滤波
低通滤波器:只保留低频,会使得图像模糊
高通滤波器:只保留高频,会使得图像细节增强
(1)进行傅里叶变化:cv2.dft(img, cv2.DFT_COMPLEX_OUTPUT)
img 需要先转换成 np.float32 格式;
cv2.DFT_COMPLEX_OUTPUT 傅里叶变化的方法;
cv2.dft() 返回的结果是双通道的(实部虚部),通常还需要转换成图像格式才能展示(0,255)。
得到的结果中频率为 0 的部分会在左上角,通常要转换到中心位置,可以通过 shift 变换来实现。
(2)进行傅里叶的逆变化:cv2.idft(img)
img 需要先转换成 np.float32 格式;
得到的结果中频率为 0 的部分会在左上角,通常要转换到中心位置,可以通过 shift 变换来实现。
(3)cv2.magnitude(x, y) 将
s
q
r
t
(
x
2
+
y
2
)
sqrt(x^2 + y^2)
sqrt(x2+y2) 计算矩阵维度的平方根;
(4)np.fft.fftshift(img) 将图像中的低频部分移动到图像的中心;
(5)np.fft.ifftshift(img) 将图像的低频和高频部分移动到图像原来的位置;
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('lena.png',0)
img_float32 = np.float32(img) #转换成np.float32格式
#傅里叶变化
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
#将变化后的图像的低频转移到中心位置
dft_shift = np.fft.fftshift(dft)
#使用cv2.magnitude将实部和虚部转换为实部,乘以20是为了使得结果更大
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
本笔记记录学习OpenCV,若有错误,欢迎批评指正,学习交流。