Opencv计算机视觉之路(三)——图像处理(一)傅里叶变换

计算机视觉系列:傅里叶变换

——————————————————————————

1. 傅里叶变换简介

    Joseph Fourier是一位18世纪的法国数学家,在数学领域,他认为一切事物均可以用波形来描述,所有观察到的波形也可以有一系列的简单的且频率不同的正弦曲线相加得到,也就是说,人们看到的波形是由多个波形相加得到的。

    当我们看到图像中哪些区域的信号变化特别强烈,哪些区域的信号变化不是很强烈,从而可以标记和区分噪声区域、感兴趣区域、前景、背景等。原始图像由许多频率组成,便可以分离这些频率来理解图像和提取感兴趣区域等。

1.1 频率变换

    下面通过傅里叶频率变化来介绍图像的幅度普,幅度普呈现了原始图像在变化方面的一种表示:图像最明亮的像素放到中央,然后逐渐变暗,在边缘上的像素最暗,这样可以发现图像中亮、暗像素的百分比。

    在opencv环境中,许多算法实现了处理图像的功能,这些算法在numpy中也有实现,且更容易使用。首先使用Numpy做频率变换,Numpy有一个FFT(快速傅里叶变换)包来完成这个工作,np.fft.fft2()为我们提供了一个复杂数组的频率转换,即一幅图像的离散傅里叶变换。

    它的第一个参数是输入图像,它是灰度图像。第二个参数是可选的,它决定了输出数组的大小。如果它大于输入图像的大小,则输入图像在计算FFT之前填充了0。如果它小于输入图像,输入图像将被裁剪。如果没有参数传递,输出数组的大小将与输入相同。

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

img = cv2.imread('test.jpg', 0) #直接读为灰度图像
f = np.fft.fft2(img)            #做频率变换
fshift = np.fft.fftshift(f)     #转移像素做幅度普

s1 = np.log(np.abs(fshift))#取绝对值:将复数变化成实数取对数的目的为了将数据变化到0-255
plt.subplot(131)
plt.imshow(img, 'gray')
plt.title('original')

plt.subplot(132)
plt.imshow(s1,'gray')
plt.title('center')

plt.show()

    得到的结果如下:
这里写图片描述
    也许你会问为什么用 l o g 函数去映射,而不是采取以下的归一化的形式去用,我看了下矩阵的元素,绝大多数的像素数值都很小,如果采用以下的形式去归一化,绝大多数的数值均很小,会得到一个黑色的图像,归一化的东西本文不在详细介绍,归一化这种东西本来就是建模里面一个不好掌控的度。

X X m i n X m a x X

    你可以在中心看到更多的白色区域,表示低频率的内容更多。

                                                本小节结束
—————————————————————————————————————————

1.1 频域变换

    下一步进行频域变换,比如高通滤波和重建图像,也就是找到逆DFT。为此,你只需用一个矩形窗口大小的60x60来移除低频部分。然后使用np.fft.ifftshift()应用反向移动,使DC组件再次出现在左上角。然后使用np.ifft2()函数找到反FFT。得到的结果将会是一个复数,可以取它的绝对值。

1.1.1 高通滤波器介绍

    高通滤波器(HPF)是检测图像的某个区域,然后根据像素与周围像素的差值来提升该像素亮度的滤波器。

    以如下的核(kernal)为例

[[0, -0.25, 0],
[-0.25, 1, -0.25],
[0, -0.25, 0]]

    核是一组权重的集合,他会应用与原图像的一个区域,并生成目标区域的一个像素。比如,大小为7的核意味着(7x7)个原图像的像素会产生目标图像的一个像素。可以将核视为一个窗口,这个窗口在原图像上移动时,覆盖区域的像素会按着某种形式透过此窗口,形成一个像素点;随着窗口的不断移动,形成最终的目的图像。

    在计算完中央像素与周围临近像素的亮度差值以后,如果亮度变化很大,中央像素的亮度会增加,这在边缘检测中十分有效,下一篇文章将会介绍边缘检测。高通滤波器有一种称为半径的属性,决定多大面积的临近像素参与滤波运算。

    举一个高通滤波器的例子,在设置核后,与读入的图像进行卷积运算,卷积运算可以使用cv2提供的函数实现。

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

kernel_9 = np.array([[-1, -1, -1],
                     [-1, 8, -1],
                     [-1, -1, -1]])

kernel_25 = np.array([[-1, -1, -1, -1, -1],
                      [-1, 1, 2, 1, -1],
                      [-1, 2, 4, 2, -1],
                      [-1, 1, 2, 1, -1],
                      [-1, -1, -1, -1, -1]])

img = cv2.imread('test.jpg')
ndimg = np.array(img)

k3 = cv2.filter2D(ndimg, -1, kernel_9)      #convolve calculate 
k5 = cv2.filter2D(ndimg, -1, kernel_25)     #-1 means size-1

plt.subplot(131)
plt.imshow(img)
plt.title("source image")

plt.subplot(132)
plt.imshow(k3)
plt.title("kernel = 3")

plt.subplot(133)
plt.imshow(k5)
plt.title("kernel = 5")

plt.show()

    得到的结果如下:
这里写图片描述

    与高通滤波器相反的还有低通滤波器(LPF),低筒滤波器与高通滤波器相反,当一个像素与周围像素的插值小于一个特定值时,平滑该像素的亮度,用于去燥和模糊化,比如PS软件中的高斯模糊,就是常见的模糊滤波器之一,属于削弱高频信号的低通滤波器。

    做一个简单的低通滤波器

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

kernel_25h = np.array([[-1, -1, -1, -1, -1],
                      [-1, 1, 2, 1, -1],
                      [-1, 2, 4, 2, -1],
                      [-1, 1, 2, 1, -1],
                      [-1, -1, -1, -1, -1]])

kernel_25l = np.array([[0.04, 0.04, 0.04, 0.04, 0.04],
                      [0.04, 0.04, 0.04, 0.04, 0.04],
                      [0.04, 0.04, 0.04, 0.04, 0.04],
                      [0.04, 0.04, 0.04, 0.04, 0.04],
                      [0.04, 0.04, 0.04, 0.04, 0.04]])

img = cv2.imread('test.jpg')
ndimg = np.array(img)

k3 = cv2.filter2D(ndimg, -1, kernel_25h)
k5 = cv2.filter2D(ndimg, -1, kernel_25l)

plt.subplot(131)
plt.imshow(img)
plt.title("source image")

plt.subplot(132)
plt.imshow(k3)
plt.title("kernel5hpf")

plt.subplot(133)
plt.imshow(k5)
plt.title("kernel5lpf")
plt.show()

    结果如下:中间的图为高通滤波,最右方的图为模糊化后的。
这里写图片描述
                                                本小节结束
—————————————————————————————————————————

猜你喜欢

转载自blog.csdn.net/asd20172016/article/details/80904634
今日推荐