目录
一、图像直方图
1、直方图
灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。横坐标是灰度级,纵坐标是灰度级出现的频率。
直方图是对图像的中的像素点的值进行统计,一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数,即横坐标表示图像中各个像素点的灰度级,纵坐标表示具有该灰度级的像素个数。
matplotlib绘制直方图
#encoding:utf-8
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('data/cat.jpg')
plt.hist(img.ravel(), 256)
plt.show()
cv_show('src',img)
- plt.hist(数据源, 像素级) : 数据源必须是一维数组,通常需要通过函数ravel()拉直图像 像素级一般是256,表示[0, 255]
opencv绘制直方图
#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/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])
hist=cv2.calcHist(images,channels,mask,histSize,ranges,accumulate)
- hist表示直方图,返回的是一个二维数组
- images: 原图像,图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img]
- channels: 表示指定通道,通道编号需要用中括号括起,输入图像是灰度图像时,它的值为[0],彩色图像则为[0]、[1]、[2],分别表示B、G、R
- mask: 表示掩码图像,统计整副图像的直方图,设为None,统计图像的某一部分直方图时,需要掩码图像
- histSize:表示BINS的数目即灰度级,也应用中括号括来
- ranges: ranges表示像素值范围,常为 [0,256]
- accumulate:表示累计叠加标识,默认为false,如果被设置为true,则直方图在开始分配时不会被清零,该参数允许从多个对象中计算单个直方图,或者用于实时更新直方图;多个直方图的累积结果用于对一组图像的直方图计算
使用mask与不使用mask进行对比绘制直方图
#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/cat.jpg', 0) #0表示灰度图
# 创建掩膜mask
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:400] = 255
masked_img = cv2.bitwise_and(img, img, mask=mask)#利用掩膜(mask)进行“与”操作
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,'red'), plt.plot(hist_mask,'black')
plt.xlim([0, 256])
plt.show()
img_mask=cv2.bitwise_and(src1, src2, dst=None, mask=None)
- src1、src2:为输入图像或标量,标量可以为单个数值或一个四元组
- dst:可选输出变量,如果需要使用非None则要先定义,且其大小与输入变量相同
- mask:图像掩膜,可选参数,为8位单通道的灰度图像,用于指定要更改的输出图像数组的元素,即输出图像像素只有mask对应位置元素不为0的部分才输出,否则该位置像素的所有通道分量都设置为0
- img_mask:结果图像矩阵,如果dst传入了实参,则返回值与dst对应实参相同
2、直方图均衡化
直方图均衡化是一种简单有效的图像增强技术,通过改变图像的直方图来改变图像中各像素的灰度,主要用于增强动态范围偏小的图像的对比度。原始图像由于其灰度分布可能集中在较窄的区间,造成图像不够清晰。例如,过曝光图像的灰度级集中在高亮度范围内,而曝光不足将使图像灰度级集中在低亮度范围内。
采用直方图均衡化,可以把原始图像的直方图变换为均匀分布(均衡)的形式,这样就增加了像素之间灰度值差别的动态范围,从而达到增强图像整体对比度的效果。换言之,直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。
#encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('data/cat.jpg',0) #0表示灰度图
equ = cv2.equalizeHist(img) #将要均衡化的原图像【要求是灰度图像】作为参数传入,则返回值即为均衡化后的图像。
plt.hist(equ.ravel(),256)
plt.show()
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) #自适应直方图均衡化
res_clahe = clahe.apply(img)
res = np.hstack((img,equ,res_clahe))
cv_show('res',res)
直方图均衡化结果:
原始图、直方图均衡化后的图与自适应直方图均衡化后的结果图展示:
- cv2.equalizeHist(img) 表示进行直方图均衡化
- cv2.createCLAHA(clipLimit=8.0, titleGridSize=(8, 8)) 用于生成自适应均衡化图像:clipLimit颜色对比度的阈值, titleGridSize进行像素均衡化的网格大小,即在多少网格下进行直方图的均衡化操作
二、傅里叶变换
傅里叶变换(Fourier Transform,简称FT)常用于数字信号处理,它的目的是将时间域上的信号转变为频率域上的信号。随着域的不同,对同一个事物的了解角度也随之改变,因此在时域中某些不好处理的地方,在频域就可以较为简单的处理。同时,可以从频域里发现一些原先不易察觉的特征。傅里叶定理指出“任何连续周期信号都可以表示成(或者无限逼近)一系列正弦信号的叠加。
傅里叶变换可以应用于图像处理中,经过对图像进行变换得到其频谱图。从谱频图里频率高低来表征图像中灰度变化剧烈程度。图像中的边缘信号和噪声信号往往是高频信号,而图像变化频繁的图像轮廓及背景等信号往往是低频信号。这时可以有针对性的对图像进行相关操作,例如图像除噪、图像增强和锐化等。
傅里叶变换的目的更多情况下是为了对频率进行过滤,通过修改频率以达到图像增强、图像去噪、边缘检测、特征提取、压缩加密等效果。
1、Numpy实现傅里叶变换与傅里叶逆变换
# -*- coding: utf-8 -*-
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#读取图像
img = cv.imread('data/cat.jpg', 0)
#傅里叶变换
f = np.fft.fft2(img) #快速傅里叶变换算法得到频率分布
fshift = np.fft.fftshift(f) #默认结果中心点位置是在左上角,,调用fftshift()函数转移到中间位置
res = np.log(np.abs(fshift)) #fft结果是复数, 其绝对值结果是振幅
#傅里叶逆变换
ishift = np.fft.ifftshift(fshift)
iimg = np.fft.ifft2(ishift) #实现图像逆傅里叶变换,返回一个复数数组
iimg = np.abs(iimg) #将复数转换为0至255范围
#展示结果
plt.subplot(131), plt.imshow(img, 'gray'), plt.title('Original Image')
plt.axis('off')
plt.subplot(132), plt.imshow(res, 'gray'), plt.title('Fourier Image')
plt.axis('off')
plt.subplot(133), plt.imshow(iimg, 'gray'), plt.title('Inverse Fourier Image')
plt.axis('off')
plt.show()
2、OpenCV实现傅里叶变换与傅里叶逆变换
# -*- coding: utf-8 -*-
import numpy as np
import cv2
from matplotlib import pyplot as plt
#读取图像
img = cv2.imread('data/cat.jpg', 0)
#傅里叶变换
dft = cv2.dft(np.float32(img), flags = cv2.DFT_COMPLEX_OUTPUT)
dftshift = np.fft.fftshift(dft) #将频谱低频从左上角移动至中心位置
res1= 20*np.log(cv2.magnitude(dftshift[:,:,0], dftshift[:,:,1])) #频谱图像双通道复数转换为0-255区间
#傅里叶逆变换
ishift = np.fft.ifftshift(dftshift)
iimg = cv2.idft(ishift)
res2 = cv2.magnitude(iimg[:,:,0], iimg[:,:,1])
#显示图像
plt.subplot(131), plt.imshow(img, 'gray'), plt.title('Original Image')
plt.axis('off')
plt.subplot(132), plt.imshow(res1, 'gray'), plt.title('Fourier Image')
plt.axis('off')
plt.subplot(133), plt.imshow(res2, 'gray'), plt.title('Inverse Fourier Image')
plt.axis('off')
plt.show()
- cv2.dft()输出结果是是双通道的,第一个通道是结果的实数部分,第二个通道是结果的虚数部分,并且输入图像要首先转换成 np.float32 格式。由于输出的频谱结果是一个复数,需要调用cv2.magnitude()函数将傅里叶变换的双通道结果转换为0到255的范围。
- cv2.magnitude(x, y):x表示浮点型X坐标值,即实部;y表示浮点型Y坐标值,即虚部;最终输出结果为幅值。
3、高通滤波器
高通滤波器是指通过高频的滤波器,衰减低频而通过高频,常用于增强尖锐的细节,但会导致图像的对比度会降低。该滤波器将检测图像的某个区域,根据像素与周围像素的差值来提升像素的亮度。通过高通滤波器覆盖掉中心低频部分,将255两点变换为0,同时保留高频部分。
通过高通滤波器将提取图像的边缘轮廓
img = cv2.imread('data/cat.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()
4、低通滤波器
低通滤波器是指通过低频的滤波器,衰减高频而通过低频,常用于模糊图像。低通滤波器与高通滤波器相反,当一个像素与周围像素的插值小于一个特定值时,平滑该像素的亮度,常用于去燥和模糊化处理。如PS软件中的高斯模糊,就是常见的模糊滤波器之一,属于削弱高频信号的低通滤波器。低通滤波器中心区域为白色255,其他区域为黑色0。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('data/cat.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()