图像傅里叶变换dft(含python代码)

目录

  • 前言
  • 快速傅里叶变换之numpy
  • openCV中的傅里叶变换
    • np.zeros数组
    • cv2.dft()和cv2.idft()
  • DFT的性能优化
    • cv2.getOptimalDFTSize()
    • 覆盖法填充0
    • 函数cv2.copyMakeBorder填充0
    • 时间对比

前言

在学习本篇博客之前需要参考
https://blog.csdn.net/GiffordY/article/details/92838671
https://blog.csdn.net/qq_41821067/article/details/111143629

快速傅里叶变换之numpy

python的numpy中的fft()函数可以进行快速傅里叶变换,

import cv2
import numpy as np
from matplotlib import pyplot as plt
#读取图片的灰色图像
img=cv2.imread("F:/people.png",0)
#对图像进行傅里叶变换,输出结果是一个复杂的组
f=np.fft.fft2(img)
#print(f)
#进行频率变换,得到图像中心频率
fshift=np.fft.fftshift(f)
#构建振幅谱,输出数组绝对值的log
magnitude_spectrum=20*np.log(np.abs(fshift))
#把显示界面分割成1*2的网格,121将参数合起来写,1是行数,2是列数,最后一个1是标号
plt.subplot(121),plt.imshow(img,cmap="gray")#cmap是将标量数据映射成色彩图
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()

图像傅里叶变换dft(含python代码)_第1张图片

#快速傅里叶逆变换
#获取频谱图片的长宽
rows,cols=img.shape
#取频谱图像中心位置
crow,ccol=int(rows/2),int(cols/2)
#以中心为原点,上取30,下取30,设置为0
fshift[crow-30:crow+30,ccol-30:ccol+30]=0
#对图像逆平移,图像从中心变为左上角
f_ishift=np.fft.ifftshift(fshift)
#用快速傅里叶逆变换恢复为空间域图像
img_back=np.fft.ifft2(f_ishift)
#取绝对值?
img_back=np.abs(img_back)
plt.subplot(131),plt.imshow(img,cmap='gray')
plt.title("input image"),plt.xticks([]),plt.yticks([])
plt.subplot(132),plt.imshow(img_back,cmap="gray")
plt.title("image after HPF"),plt.xticks([]),plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title("Result in JET"),plt.xticks([]),plt.yticks([])
plt.show()

图像傅里叶变换dft(含python代码)_第2张图片

openCV中的傅里叶变换

np.zeros数组

a=np.zeros((1,2,2))
b=np.zeros((1,2))
print(a)
print(b)

在这里插入图片描述
可以看出zeros的第三个参数是数组的个数

cv2.dft()和cv2.idft()

openCV中的傅里叶变换的函数是cv2.dft()和cv2.idft()

import cv2
import numpy as np
from matplotlib import pyplot as plt

#读取图片的灰色图像
img=cv2.imread("F:/people.png",0)
#cv2
#dft函数的输出结果是双通道的,第一个参数是结果的实数部分,第二个是结果的叙述部分
dft=cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift=np.fft.fftshift(dft)
#将实部和虚部都转换为实部,乘以20是扩大值,投射到空间域
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()

#cv2的逆dft
rows,cols=img.shape
crow,ccol=int(rows/2),int(cols/2)
#创建一个有固定格式的数组
mask=np.zeros((rows,cols,2),np.uint8)
#中心上取30,下取30,左取30,右取30,设置为1
#与高频对应的部分设置为1
print(mask)
mask[crow-30:crow+30,ccol-30:ccol+30]=1
#与低频对应的地区设置为0
fshift=dft_shift*mask
#将低频区域转移到中间位置
f_ishift=np.fft.ifftshift(fshift)
img_back=cv2.idft(f_ishift)
#使用cv2.magnitude将实部和虚部投影到空间域,将实部和虚部转换为实部
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.subplot(122),plt.imshow(img_back,cmap="gray")
plt.show()

打印的mask的值
图像傅里叶变换dft(含python代码)_第3张图片
dft后的图
图像傅里叶变换dft(含python代码)_第4张图片
逆傅里叶后的图,这里是类似低通滤波器,模糊边缘
图像傅里叶变换dft(含python代码)_第5张图片

DFT的性能优化

数组的大小对DFT的性能有一定的影响,当数组的大小是2的指数或2、3、5的倍数的时候DFT的效率最高。所以要修改输入图像的大小为以上才可以提高代码运行效率

cv2.getOptimalDFTSize()

以上可以被cv2.dft()和np.fft.fft2()使用

import cv2
img=cv2.imread('F:\people.png',0)
rows,cols=img.shape
print(rows,cols)
# 返回DFT 最优尺寸大小
nrows=cv2.getOptimalDFTSize(rows)
ncols=cv2.getOptimalDFTSize(cols)
print(nrows,ncols)

图像傅里叶变换dft(含python代码)_第6张图片
可看到数组的大小优原来的(144,93)变为2和3的倍数(144,96),此时数组变大,在Cv2中需要用zeros函数进行补0,在numpy中不需要补0,只需要指定fft运算的大小

覆盖法填充0

import cv2
import numpy as np
img=cv2.imread('F:\people.png',0)
# cv2.imshow("img",img)
# cv2.waitKey()
rows,cols=img.shape
print(rows,cols)
# 返回DFT 最优尺寸大小
nrows=cv2.getOptimalDFTSize(rows)
ncols=cv2.getOptimalDFTSize(cols)
print(nrows,ncols)
#创建一个大小为(nrows,ncols)的0数组
nimg=np.zeros((nrows,ncols))
nimg[:rows,:cols]=img
print(nimg.shape)

图像傅里叶变换dft(含python代码)_第7张图片
我们可看到nimg的大小变为(144,96),说明已经填充0了

函数cv2.copyMakeBorder填充0

right=ncols-cols
bottom=nrows-rows
# 有颜色的常数值边界,还需要value
bordertype=cv2.BORDER_CONSTANT
#value:如果borderType为cv2.BORDER_CONSTANT时需要填充的常数值,这里是0就是填充0
nimg=cv2.copyMakeBorder(img,0,bottom,0,right,bordertype,value=0)
print(nimg)

图像傅里叶变换dft(含python代码)_第8张图片

时间对比

from timeit import timeit
def test1():
    fft1 = np.fft.fft2(img)
print(timeit(stmt=test1,number=1))
def test2():
    fft2 = np.fft.fft2(img, [nrows, ncols])
print(timeit(stmt=test2,number=1))
#timeit(np.fft.fft2(img))
#%timeit fft2=np.fft.fft2(img,[nrows,ncols])
# 观察opencv
def test3():
    dft1=cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
def test4():
    dft2=cv2.dft(np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT)
print(timeit(stmt=test3,number=1))
print(timeit(stmt=test4,number=1))

图像傅里叶变换dft(含python代码)_第9张图片
我们可以看到DFT数组优化之后代码运行速度变快,同时opencv比numpy的傅里叶变换速度快

你可能感兴趣的:(数字水印,opencv,傅里叶变换,python)