直方图与傅里叶变换
一、直方图
import cv2
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline #专有魔法指令,即时显示
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
cv2.destoryAllWindows()
img = cv2.imread('cat.jpg', 0) # 表示灰度图
hist = cv2.calcHist([img], [0], None, [256], [0, 256]) # 注意中括号[]
hist.shape
# 结果是(256,1):一共有0-255的256个取值,1表示是个二维的
plt.hist(img.ravel(), 256) # img.ravel()是多维矩阵变一维矩阵
plt.show
plt.hist(src,pixels)
src:数据源,注意这里只能传入一维数组,使用src.ravel()可以将二维图像拉平为一维数组。
pixels:像素级,一般输入256。
\
img = cv2.imread('cat.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操作
img = cv2.imread('cat.jpg', 0) # 表示灰度图
# 创建mask
mask = np.zeros(img.shape[:2], np.uint8) # 8位无符号整型
mask[100:300, 100:400] = 255 # 把要保存的部分置为255
cv_show(mask, 'mask')
masked_img = cv2.bitwise_and(img, img, mask=mask) # 与操作
cv_show(masked_img , 'masked_img ')
hist_full = cv2.calcHist([img], [0], None, [256], [0, 256]) # 不带掩码
hist_mask = cv2.calcHist([img], [0], mask, [256], [0, 256]) # 带掩码
plt.subplot(221), plt.imshow(img, 'gray')
plt.subplot(222), plt.imshow(mask, 'gray')
plt.subplot(223), plt.imshow(masked_img, 'gray')
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
plt.xlim([0, 256])
plt.show()
img.shape[:2] 取彩色图片的长、宽。
如果img.shape[:3] 则取彩色图片的长、宽、通道。
关于img.shape[0]、[1]、[2]
img.shape[0]:图像的垂直尺寸(高度)
img.shape[1]:图像的水平尺寸(宽度)
img.shape[2]:图像的通道数
在矩阵中,[0]就表示行数,[1]则表示列数。
直方图均衡化
可以提高 对比度
\
# 不做均衡化
img = cv2.imread('cat.jpg', 0) # 0表示灰度图 #clahe
plt.hist(img.ravel(), 256); # ravel返回的是视图,用ravel()方法将数组a拉成一维数组
plt.show()
# 做均衡化
equ = cv2.equalizeHist(img)
plt.hist(equ.ravel(), 256)
plt.show()
res = np.hstack((img, equ))
cv.show(res, 'res')
自适应直方图均衡化
将整个图像分隔成一个个小的
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
res_clahe = clahe.apply(img) # apply(func,*args,**kwargs)的返回值就是func()的返回值,apply()的元素参数是有序的,元素的顺序必须和func()形式参数的顺序一致
res = np.hstack((img, equ, res_clahe))
cv_show(res, 'res')
二、傅里叶变换
傅里叶变换
傅里叶变换的作用
(1)高频:变化剧烈的灰度变量,例如边界
(2)低频:变化缓慢的灰度变量,例如一片大海
滤波
(1)低通滤波器:只保留低频,会使得图像模糊
(2)高通滤波器:只保留高频,会使得图像细节增强
(3)opencv中主要就是cv2.dft()和cv2.idft(),输入图像需要先转换成np.float32格式
(4)得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现
(5)cv2.dft()返回的结果是双通道的(实部, 虚部),通常还需要转换成图像格式才能展示(0, 255)
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('lena.jpg', 0)
img_float32 = np.float32(img)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft) # shift操作,低频值转换到中间
# 得到灰度图能表示的形式
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0], dft_shift[:,:,1])) # 转换两个通道,结果非常小,映射出来*20
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum , cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
# 低频
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('lena.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()
# 高频
img = cv2.imread('lena.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.ones((rows, cols, 2), np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 0
# 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()
三、常用函数
-
cv2.calcHist(img, channels, mask, histSize, ranges)
像素直方图统计: img:原图像格式为uint8或floart32。当传入函数时应用中括号[]来,例如[img],通常是灰度图 channels:同样用中括号,他会告诉我们统幅图像的直方图。如果入图像是灰度图它的值就是[0],如果是彩色图像 的传入的参数可以是[0][1][2],他们分别对应着BGR。 mask:掩码图像。统整幅图像的直方图就把它为None。但是如果你想统图像某一分的直方图的,就制作一个掩码图 像并使用它。 histSize:BIN的数目。也应用中括号括来,可以自己指定直方图的size大小 ranges:像素值范围常为[0256]
-
cv2.bitwise_and(img, img, mask=mask)
与操作
-
cv2.equalizeHist(img)
直方图均衡化
-
cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
自适应直方图均衡化 clipLimit:颜色对比度的阈值 titleGridSize:进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
-
cv2.dft()
执行傅里叶变换
-
cv2.idft()
傅里叶逆变换
-
cv2.magnitude(a1, a2)
用于求取传入数据的平方根
Numpy中的傅里叶变换
主要使用np.fft.fft2()、np.fft.fftshift()以及20*np.log(np.abs(fshift))函数来实现。
np.fft.fft2()
numpy.fft.fft2(img, s=None, axes=(-2, -1), norm=None)
1
参数如下:
img:输入图像(二维数组),即灰度图像
s:可选参数,它决定输出数组的大小。如果它大于输入图像的大小,则在计算FFT之前用零填充输入图像。如果小于输入图像,将裁切输入图像。如果未传递任何参数,则输出数组的大小将与输入的大小相同
axes:计算FFT的轴。如果未给出,则使用最后两个轴。轴上重复的索引表示该轴上的变换执行了多次
norm:可选参数
返回值是一个复数数组
对于np.fft.fft()以及np.fft.fftn()函数,第一个参数分别是一维数组和n维数组,返回值均为复数数组,第二个参数同上。
np.fft.fftshift()
函数参数主要是np.fft.fft2()函数的输出,即复数数组。此函数可以将零频率分量移到频谱中心。变换之后的频谱显示范围从[0, N]变为:[-N/2,N/2-1](N为偶数)或[-(N-1)/2,(N-1)/2](N为奇数)。
20*np.log(np.abs(fshift))
函数参数主要是np.fft.fftshift()函数的输出,傅里叶变换得到的结果是一个复数数组,不能直接用于显示图像,要想得到频谱灰度图像,需要一个映射,把复数映射[0, 255]之间。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('./opencv.png',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()