- #! /usr/bin/env python
- #coding=utf-8
- from __future__ import unicode_literals
- import cv2
- import numpy as np
- '''
- 傅立叶变换演示
- 频谱图像窗口: 显示图像滤波后的频谱
- - size: 滤波器大小
- - flag:滤波器类型,0 为低通滤波, 1为高通滤波
- 图像窗口: 显示原图像和滤波后频谱进行反变换的图像
- '''
- def fft(img):
- '''对图像进行傅立叶变换,并返回换位后的频谱'''
- assert img.ndim==2, 'img should be gray.'
- rows, cols = img.shape[:2]
- # 计算最优尺寸
- nrows = cv2.getOptimalDFTSize(rows)
- ncols = cv2.getOptimalDFTSize(cols)
- # 根据新尺寸,建立新变换图像
- nimg = np.zeros((nrows, ncols))
- nimg[:rows,:cols] = img
- # 傅立叶变换
- fft_mat= cv2.dft(np.float32(nimg), flags=cv2.DFT_COMPLEX_OUTPUT)
- # 换位,低频部分移到中间,高频部分移到四周
- min_value = np.min(fft_mat)
- return np.fft.fftshift(fft_mat)
- def fft_img(shift_mat):
- '''将频谱转换为可视图像'''
- # log函数中加1,避免log(0)出现.
- log_mat= cv2.log(1 + cv2.magnitude(shift_mat[:,:,0], shift_mat[:,:,1]))
- # 标准化到0~255之间
- cv2.normalize(log_mat, log_mat, 0, 255, cv2.NORM_MINMAX)
- return np.uint8(np.around(log_mat))
- def ifft(fshift_mat):
- '''傅立叶反变换,返回反变换图像'''
- # 反换位,低频部分移到四周,高频部分移到中间
- f_ishift_mat = np.fft.ifftshift(fshift_mat)
- # 傅立叶反变换
- img_back = cv2.idft(f_ishift_mat)
- img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
- cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX)
- return np.uint8(np.around(img_back))
- def do_filter(_=None):
- '''滤波,并显示'''
- size = cv2.getTrackbarPos('size', dft_spectrum_window)
- flag = cv2.getTrackbarPos('flag', dft_spectrum_window)
- filter_mat, mask = None, None
- # 低通滤波
- if flag == 0:
- mask = np.zeros((frows, fcols ,2),np.float32)
- mask[frows/2-size/2:frows/2+size/2, fcols/2-size/2:fcols/2+size/2] = 1
- # 高通滤波
- else:
- mask = np.ones((frows, fcols ,2),np.float32)
- mask[frows/2-size/2:frows/2+size/2, fcols/2-size/2:fcols/2+size/2] = 0
- # 滤波后的频谱
- filter_mat = fft_shift_mat * mask
- # 同时显示原图像和反变换后的图像
- cv2.imshow(dft_image_window, combine_images([img, ifft(filter_mat)]))
- # 显示滤波后的频谱图像
- cv2.imshow(dft_spectrum_window, fft_img(filter_mat))
- def combine_images(images, axis=1):
- '''
- 使用numpy函数合并图像。
- @type images: list or iter
- @param images: 图像列表,图像成员的维数必须相同
- @type axis: int
- @param axis: 合并方向。 axis=0时,图像垂直合并,axis = 1 时, 图像水平合并。
- @return 合并后的图像
- '''
- ndim = images[0].ndim
- shapes = np.array([mat.shape for mat in images])
- assert np.all(map(lambda e: len(e)==ndim, shapes)), 'all images should be same ndim.'
- if axis == 0:# 垂直方向合并图像
- # 合并图像的 cols
- cols = np.max(shapes[:, 1])
- # 扩展各图像 cols大小,使得 cols一致
- copy_imgs = [cv2.copyMakeBorder(img, 0, 0, 0, cols-img.shape[1],
- cv2.BORDER_CONSTANT, (0,0,0)) for img in images]
- # 垂直方向合并
- return np.vstack(copy_imgs)
- else:# 水平方向合并图像
- # 合并图像的 rows
- rows = np.max(shapes[:, 0])
- # 扩展各图像rows大小,使得 rows一致
- copy_imgs = [cv2.copyMakeBorder(img, 0, rows-img.shape[0], 0, 0,
- cv2.BORDER_CONSTANT, (0,0,0)) for img in images]
- # 水平方向合并
- return np.hstack(copy_imgs)
- if __name__ == '__main__':
- img = cv2.imread('lena.jpg',0)
- rows, cols = img.shape[:2]
- # 频谱窗口名称
- dft_spectrum_window = 'spectrum'
- # 图像窗口名称
- dft_image_window = 'image'
- cv2.namedWindow(dft_spectrum_window)
- cv2.namedWindow(dft_image_window)
- # 创建size tracker, size为过滤器大小,初始大小为50
- cv2.createTrackbar('size', dft_spectrum_window, 50, min(rows, cols), do_filter)
- # 创建flag tracker, flag=0时,为低通滤波, flag=1时,为高通滤波,初始设置为低通滤波
- cv2.createTrackbar('flag', dft_spectrum_window, 0, 1, do_filter)
- fft_shift_mat = fft(img)
- frows, fcols = fft_shift_mat.shape[:2]
- do_filter()
- cv2.waitKey(0)
- cv2.destroyAllWindows()
- #该片段来自于http://www.codesnippet.cn/detail/110220148692.html
来源: http://www.codesnippet.cn/detail/110220148692.html