OpenCV(七)之直方图与傅里叶变换

Hist & Fourier transform系列


Hist & Fourier transform-直方图

直方图(Histogram),又称质量分布图,是一种统计报告图,由一系列高度不等的纵向条纹或线段表示数据分布的情况。 一般用横轴表示数据类型,纵轴表示分布情况。


calcHist函数
	function
	计算一组数组的直方图。
	函数cv :: calcHist计算一个或多个数组的直方图,用于递增直方图bin的元组的元素是从相同位置的相应输入数组中获取的。 
	下面的示例显示了如何计算彩色图像的2D色相饱和度直方图:

calcHist

	参数
	
	images	源数组。它们都应具有相同的深度,CV_8U,CV_16U或CV_32F,并且大小相同。它们中的每一个都可以具有任意数量的通道。
	nimages	源图像数量。
	channels	用于计算直方图的dims通道列表。通道 可以分别统计BGR通道 0,1,2
	第一个数组通道的编号从0到图像[0] .channels- 1,第二个数组通道从图像[0] .channels到图像[0] .channels+图像[1]计数。 
	channels- 1,依此类推。
	mask	可选掩模。如果矩阵不为空,则它必须是与images [i]大小相同的8位数组。非零掩码元素标记直方图中计数的数组元素。
	hist	输出直方图,是一个密集或稀疏的dims -dimensional数组。
	dims	直方图维度必须为正且不大于CV_MAX_DIMS(在当前OpenCV版本中等于32)。
	histSize	每个维度中的直方图大小数组。直方图X轴大小 假如0-256 也可以自定义为 0-10 10-20 .... 246-256 即步长
	ranges		像素范围
	uniform	指示直方图是否均匀的标志(见上文)。
	accumulate	积累标签。如果已设置,则直方图在分配时不会在开头清除。此功能使您可以从多组数组计算单个直方图,或者及时更新直方图。

	function
	def equalizeHist(src, dst=None):
	均衡灰度图像的直方图。
	该函数使用以下算法均衡输入图像的直方图:
	1.计算src的直方图H。
	2.标准化直方图,使直方图区间的总和为255。
	3.计算直方图的积分:

在这里插入图片描述

	4.使用H'作为查找表变换图像:???(x,y)= H'(???(x,y))
	该算法使亮度归一化并增加图像的对比度。

	参数
	src	源8位单通道图像。
	dst	与src具有相同大小和类型的目标图像。

	function
	def bitwise_and(src1, src2, dst=None, mask=None):
	计算两个数组或数组和标量的每元素逐位连接。
	该函数计算每元素按位逻辑连接:
	当src1和src2具有相同大小时,两个数组:

a
当src2由Scalar构造或具有与src1.channels()
相同数量的元素时,数组和标量:
a
src1是从Scalar构造的,或者与src2.channels()
具有相同数量的元素时的标量和数组:
c
在浮点阵列的情况下,它们的机器特定位表示(通常符合IEEE754)用于操作。
在多通道阵列的情况下,每个通道都是独立处理的。
在上面的第二和第三种情况中,标量首先转换为数组类型。

	参数
	src1  第一个源数组或标量。
	src2  第二个源数组或标量。
	dst  与输入数组具有相同大小和类型的目标arrayb。
	mask  可选操作掩码,8位单通道数组,指定要更改的目标数组的元素。

	function
	def createCLAHE(clipLimit=None, tileGridSize=None):
# 读取灰度值图像
img = cv2.imread('tiger.png',0)
cv_show('img',img)
#在calcHist函数中,参数需要加上 [参数]
hist = cv2.calcHist([img],[0],None,[256],[0,256])
print(hist.shape)
#显示
plt.hist(img.ravel(),256)
plt.show()

Systemout:(256, 1)

tiger

Hist

#分成三个通道统计
img_bgr = cv2.imread('cat.jpg')
color = ['b','g','r']
#循环输出
for i,col in enumerate(color):
    histr = cv2.calcHist([img_bgr],[i],None,[256],[0,256])
    plt.plot(histr,color=col)
plt.show()

hist_rgb

#mask操作
#创建mask
mask = np.zeros(img.shape[:2],np.uint8)
mask[100:300,100:400]=255
cv_show('mask',mask)
#与操作
mask_img = cv2.bitwise_and(img,img,mask=mask)
cv_show("mask_img",mask_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(mask_img,'gray')
plt.subplot(224)
plt.plot(hist_full)
plt.plot(hist_mask)
plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#直方图均衡化
hist = cv2.calcHist([img],[0],None,[256],[0,256])
plt.subplot(121)
plt.plot(hist)
plt.hist(img.ravel(),256)
#用equalizeHist均衡化
equ = cv2.equalizeHist(img)
plt.subplot(122)
plt.hist(equ.ravel(),256)
plt.show()
res = np.hstack((img,equ))
cv_show('res',res)

hist
hist2hist

# 自适应直方图均衡化
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)

Hist2hist2hist


分析:

直方图均衡化能够调节图像的整体对比度,能够使得整体呈像较为清晰,但是也有可能会使得局部太过明亮,丢失细节,所以,使用自适应的直方图均衡化能够很好完成需要。


Hist & Fourier transform-傅里叶变换

知乎参考文档.

傅立叶变换是一种分析信号的方法,它可分析信号的成分,也可用这些成分合成信号。许多波形可作为信号的成分,比如正弦波、方波、锯齿波等,傅立叶变换用正弦波作为信号的成分。

公式:

fourier
在图像处理中的应用:

  • 傅里叶变换的作用:
    高频:变化剧烈的灰度分量,例如边界
    低频:变化缓慢的灰度分量,例如平缓的大海

  • 滤波:
    低通滤波器:只保留低频,会使得图像模糊
    高通滤波器:只保留高频,会使得图像细节增强

openCV中:

  • 在openCV中主要就是cv2.dft()和cv2.idft() 输入图像需要先转换成np.float32格式
  • 得到的结果中频率为0的部分会在左上角,通常要转换到中心位置,可以通过shift变换来实现
  • cv2.dft()返回的结果是双通道的(实部,虚部),通常还需要转换成图像格式才能显示(0,255)

	function
	def dft(src, dst=None, flags=None, nonzeroRows=None):
	
	参数
	src  源数组可能是实数或复数。
	dst	目标数组的大小和类型取决于标志。
	flags	转换标志表示以下值的组合:
	DFT_INVERSE执行逆1D或2D变换而不是默认的正向变换。
	DFT_SCALE缩放结果:除以数组元素的数量。通常,它与DFT_INVERSE结合使用。
	DFT_ROWS对输入矩阵的每一行执行正向或反向变换。此标志使您可以同时转换多个向量,并可 用于减少开销(有时比处理本身大几倍)以执行3D和更高维度的转换等。
	DFT_COMPLEX_OUTPUT执行1D或2D实数组的正向变换。结果虽然是一个复杂的数组,但具有复共轭对称性(CCS,详见下面的函数说明)。这样的数组可以打包成与输入大小相同的实数数组,这是最快的选项,也就是默认情况下该功能的作用。但是,您可能希望获得完整的复杂阵列(用于更简单的频谱分析,等等)。传递该标志以使该函数能够生成全尺寸复杂输出数组。
	DFT_REAL_OUTPUT执行1D或2D复杂阵列的逆变换。结果通常是相同大小的复杂数组。但是,如果源阵列具有共轭复数对称性(例如,它是使用DFT_COMPLEX_OUTPUT标志进行正向变换的结果),则输出是实数组。虽然函数本身不检查输入是否对称,但您可以传递标志然后函数将采用对称并生成实际输出数组。注意,当输入被打包到实数组中并执行逆变换时,该函数将输入视为打包的复共轭对称数组。因此,输出也将是一个真正的数组。
	nonzeroRows  - 当参数不为零时,该函数假定只有输入数组的第一个非零行(DFT_INVERSE未设置)或仅输出数组的第一个非零行(设置为DFT_INVERSE)包含非零。因此,该函数可以更有效地处理其余行并节省一些时间。该技术对于使用DFT计算阵列互相关或卷积非常有用。

	function
	np.fft.fftshift(img)#将图像中的低频部分移动到图像的中心
	cv2.magnitude(img)#将sqrt(x^2 + y^2) 计算矩阵维度的平方根
	np.fft.ifftshift(img)# 进图像的低频和高频部分移动到图像原来的位置
	cv2.idft(img) # 进行傅里叶的逆变化

代码实现:

#转换成float32的图像
img_float32 = np.float32(img)
#傅里叶变换
dft = cv2.dft(img_float32,flags=cv2.DFT_COMPLEX_OUTPUT)
#将低频值转换到中心点
dft_shift = np.fft.fftshift(dft)
#得到灰度图能显示的形式,用cv2自带的函数将dft后得到的结果,转换成灰度图,但数值很小,仍需要做一些计算
magnitude_spectrum =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_spectrum,cmap='gray')
plt.title("magnitude_spectrum")
plt.xticks([])
plt.yticks([])

plt.show()

fourier


低通滤波器

#低通滤波器
#读取灰度值图像
img = cv2.imread('tiger.png',0)
#转换成float32的图像
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)
#低通滤波,做一个掩模,为什么channels为2?
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30]=1

#IDFT,逆运算
idft_shift = dft_shift*mask
idft_shift = np.fft.ifftshift(idft_shift)
img_back = cv2.idft(idft_shift)
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('tiger.png',0)
#转换成float32的图像
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)
#高通滤波,做一个掩模,为什么channels为2?
mask = np.ones((rows,cols,2),np.uint8)
mask[crow-30:crow+30,ccol-30:ccol+30]=0

#IDFT
idft_shift = dft_shift*mask
idft_shift = np.fft.ifftshift(idft_shift)
img_back = cv2.idft(idft_shift)
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()

在这里插入图片描述


在频域中的层次分明,效率快,逻辑清晰。


END

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值