Преобразование изображения в OpenCV — преобразование Фурье
В этом блоге будет представлено преобразование изображения в OpenCV, включая преобразование Фурье изображения с помощью numpy, OpenCV и некоторые приложения преобразования Фурье;
2D Discrete Fourier Transform (DFT) двумерное дискретное преобразование Фурье
Быстрое преобразование Фурье (БПФ) Быстрое преобразование Фурье
Преобразование Фурье используется для анализа частотных характеристик различных фильтров. Для изображения используется двумерное дискретное преобразование Фурье (ДПФ), чтобы найти частотную область. Для расчета ДПФ используется быстрый алгоритм, называемый быстрым преобразованием Фурье (БПФ).
- OpenCV использует cv2.dft() и cv2.idft() для реализации преобразования Фурье, что более эффективно (в 3 раза быстрее, чем OpenCV)
- Numpy использует np.ifft2() и np.fft.ifftshift() для реализации преобразования Фурье, которое более удобно в использовании;
1. Рендеринг
Рендеринг изображения в градациях серого по сравнению с преобразованием Фурье выглядит следующим образом:Видно, что белая область находится в основном в центре, и отображается больше низкочастотного контента. После того, как преобразование Фурье удаляет низкочастотное содержимое, эффект выглядит следующим образом:
Видно, что после использования прямоугольной фильтрации эффект не очень хороший, и есть эффект ряби, гауссова фильтрация может быть лучше; После того, как преобразование Фурье удаляет высокочастотное содержимое, эффект выглядит следующим образом:Удалите высокочастотный контент в изображении, т.е. примените LPF к изображению, это фактически размывает изображение. Независимо от того, является ли каждый фильтр HPF (фильтр высоких частот) или LPF (фильтр нижних частот), становится ясно с первого взгляда:Лаплас — фильтр высоких частот;
2. Принцип
- Оптимизация производительности ДПФ: при определенном размере массива производительность вычисления ДПФ выше. Самый быстрый, когда размер массива равен степени 2. Массивы размеров 2, 3 и 5 также могут обрабатываться очень эффективно.
Чтобы добиться наилучшей производительности, вы можете найти оптимальный размер с помощью функции cv2.getOptimalDFTSize(), предоставляемой OpenCV. Затем изображение дополняется массивом оптимального размера для производительности, который для OpenCV необходимо вручную дополнять нулями. Но с помощью Numpy вы можете указать новый размер для расчета БПФ, который будет автоматически дополнен нулями.
При использовании оптимального массива эффективность может быть увеличена практически в 4 раза. А сам OpenCV почти в 3 раза быстрее, чем Numpy;
Лаплас — фильтр высоких частот (High Pass Filter)
3. Исходный код
3.1 Numpy реализует преобразование Фурье
# 傅里叶变换
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('ym3.jpg', 0)
# 使用Numpy实现傅里叶变换:fft包
# fft.fft2() 进行频率变换
# 参数1:输入图像的灰度图
# 参数2:>输入图像 用0填充; <输入图像 剪切输入图像; 不传递 返回输入图像
f = np.fft.fft2(img)
# 一旦得到结果,零频率分量(直流分量)将出现在左上角。
# 如果要将其置于中心,则需要使用np.fft.fftshift()将结果在两个方向上移动。
# 一旦找到了频率变换,就能找到幅度谱。
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()
# 找到了频率变换,就可以进行高通滤波和重建图像,也就是求逆DFT
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
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)
# 图像渐变章节学习到:高通滤波是一种边缘检测操作。这也表明大部分图像数据存在于频谱的低频区域。
# 仔细观察结果可以看到最后一张用JET颜色显示的图像,有一些瑕疵(它显示了一些波纹状的结构,这就是所谓的振铃效应。)
# 这是由于用矩形窗口mask造成的,掩码mask被转换为sinc形状,从而导致此问题。所以矩形窗口不用于过滤,更好的选择是高斯mask。)
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()
3.2 OpenCV реализует преобразование Фурье
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('ym3.jpg', 0)
rows, cols = img.shape
print(rows, cols)
# 计算DFT效率最佳的尺寸
nrows = cv2.getOptimalDFTSize(rows)
ncols = cv2.getOptimalDFTSize(cols)
print(nrows, ncols)
nimg = np.zeros((nrows, ncols))
nimg[:rows, :cols] = img
img = nimg
# OpenCV计算快速傅里叶变换,输入图像应首先转换为np.float32,然后使用函数cv2.dft()和cv2.idft()。
# 返回结果与Numpy相同,但有两个通道。第一个通道为有结果的实部,第二个通道为有结果的虚部。
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(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()
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# 首先创建一个mask,中心正方形为1,其他均为0
# 如何删除图像中的高频内容,即我们将LPF应用于图像。它实际上模糊了图像。
# 为此首先创建一个在低频时具有高值的掩码,即传递LF内容,在HF区域为0。
mask = np.zeros((rows, cols, 2), np.uint8)
mask[crow - 30:crow + 30, ccol - 30:ccol + 30] = 1
# 应用掩码Mask和求逆DTF
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('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
3.3 ФВЧ или ФНЧ?
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 简单的均值滤波
mean_filter = np.ones((3, 3))
# 构建高斯滤波
x = cv2.getGaussianKernel(5, 10)
gaussian = x * x.T
# 不同的边缘检测算法Scharr-x方向
scharr = np.array([[-3, 0, 3],
[-10, 0, 10],
[-3, 0, 3]])
# Sobel_x
sobel_x = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
# Sobel_y
sobel_y = np.array([[-1, -2, -1],
[0, 0, 0],
[1, 2, 1]])
# 拉普拉斯
laplacian = np.array([[0, 1, 0],
[1, -4, 1],
[0, 1, 0]])
filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]
filter_name = ['mean_filter', 'gaussian', 'laplacian', 'sobel_x', \
'sobel_y', 'scharr_x']
fft_filters = [np.fft.fft2(x) for x in filters]
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
mag_spectrum = [np.log(np.abs(z) + 1) for z in fft_shift]
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(mag_spectrum[i], cmap='gray')
plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
plt.show()