一、傅里叶变换
傅里叶变换的详细过程及推导可以看一个大佬写的,我这里就不介绍了,链接:傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎
我这里就介绍一下傅里叶变换的一些概念和opencv中如何实现傅里叶变换:
低频:变化缓慢的灰度分量,非边界
高频:变化剧烈的灰度分量,如边界
低通滤波器:只保留低频,效果:会使图片模糊
高通滤波器:只保留高频,效果:会增强图片细节
(1)傅里叶变换
在opencv中提供了傅里叶变换函数,cv2.dft()和逆变换函数cv2.idft(),在官方文档中要求输入的图片为np.float32格式
图像经过傅里叶变换后频率为0会在左上角,通常会经过变换,将频率为0变换到中心位置,可以使用shift变换来实现
使用函数cv2.dft()进行傅里叶变换返回的是双通道(实部,虚部),需要转换为图片格式(0,255)才能显示
代码实现:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
cat = cv.imread('../de/cat.jpg', 0)
cat_32 = np.float32(cat)
cat_dft = cv.dft(cat_32, flags=cv.DFT_COMPLEX_OUTPUT) # 进行傅里叶变换,DFT_COMPLEX_OUTPUT傅里叶变换方法
cat_shift = np.fft.fftshift(cat_dft) # 进行shift变换
# 映射到灰度图中
cat_gray = 20*np.log(cv.magnitude(cat_shift[:, :, 0], cat_shift[:, :, 1])) # cv2.magnitude()转换后数值小,需要映射到(0, 255)所以需要转换
plt.subplot(221), plt.imshow(cat, 'gray'), plt.title('cat'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(cat_gray, 'gray'), plt.title('cat_dft'), plt.xticks([]), plt.yticks([])
plt.show()
效果:
原图和经过傅里叶变换后的对比,经傅里叶变换后,中间最亮的区域就是频率为0,越往外频率就越大。
(2)低通滤波器
低通滤波器:只保留低频,效果:会使图片模糊。
原理:经过傅里叶变换和shift变换,将低频集中在了中间位置,只需要制作一个和输入图片大小一致的mask,此mask的格式只需要将中间一部分置为1,周围为0,然后将mask与经过傅里叶变换和shift变换的结果相乘,就得到了只剩低频的结果。
代码实现:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
cat = cv.imread('../de/cat.jpg', 0)
cat_32 = np.float32(cat)
cat_dft = cv.dft(cat_32, flags=cv.DFT_COMPLEX_OUTPUT) # 进行傅里叶变换,DFT_COMPLEX_OUTPUT傅里叶变换方法
cat_shift = np.fft.fftshift(cat_dft) # 进行shift变换
w, h = cat.shape
x = int(w/2)
y = int(h/2)
print(x, y)
mask = np.zeros((w, h, 2), np.uint8) # 构造mask
mask[(x-50):(x+50), (y-50):(y+50)] = 1
fcat_shift = cat_shift * mask
fcat = np.fft.ifftshift(fcat_shift) # 逆shift
cat_back = cv.idft(fcat) # 逆傅里叶
cat_back = cv.magnitude(cat_back[:, :, 0], cat_back[:, :, 1]) # 映射到(0,255)
plt.subplot(221), plt.imshow(cat, 'gray'), plt.title('cat'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(cat_back, 'gray'), plt.title('cat_back'), plt.xticks([]), plt.yticks([])
plt.show()
效果图:
(3)高通滤波器
高通滤波器:只保留高频,效果:会增强图片细节
原理:和低通滤波器的原理几乎一致,只是构造mask时,将是1的变成0,0的变成1,这样就把低频的去掉,只保留高频。
代码实现:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
cat = cv.imread('../de/cat.jpg', 0)
cat_32 = np.float32(cat)
cat_dft = cv.dft(cat_32, flags=cv.DFT_COMPLEX_OUTPUT) # 进行傅里叶变换,DFT_COMPLEX_OUTPUT傅里叶变换方法
cat_shift = np.fft.fftshift(cat_dft) # 进行shift变换
w, h = cat.shape
x = int(w/2)
y = int(h/2)
print(x, y)
mask = np.ones((w, h, 2), np.uint8)
mask[(x-50):(x+50), (y-50):(y+50)] = 0
fcat_shift = cat_shift * mask
fcat = np.fft.ifftshift(fcat_shift)
cat_back = cv.idft(fcat)
cat_back = cv.magnitude(cat_back[:, :, 0], cat_back[:, :, 1])
plt.subplot(221), plt.imshow(cat, 'gray'), plt.title('cat'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(cat_back, 'gray'), plt.title('cat_back'), plt.xticks([]), plt.yticks([])
plt.show()
效果图:
二、Harris角点检测
Harris角点检测其具体原理可以看知乎上一位大佬写的,链接:图像处理基础(七)Harris 角点检测 - 知乎,这上面有具体的原理和数学公式推导过程,我这里只介绍实现代码。
在opencv中Harris角点检测为:cv2.cornerHarris(img, blockSize, ksize, k)
img:数据类型为float32的的输入图像
blockSize:角点检测中指定区域的大小
ksize:Sober求导中使用窗口的大小
k:取值参数,[0.04, 0.06]
实现代码:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('../de/c.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
print(img_gray)
img_gray = np.float32(img_gray)
des = cv.cornerHarris(img_gray, 2, 3, 0.04)
img[des > 0.1*des.max()] = [255, 0, 0] # 某一个自相似变化程度大于0.1倍的最大值我就可以认为这个就是一个角点
plt.imshow(img), plt.xticks([]), plt.yticks([])
plt.show()
效果图:
对于黑白图像效果还是比较不错的。