影象處理1--傅立葉變換(Fourier Transform )

古來聖賢皆寂寞發表於2019-01-15

樓下一個男人病得要死,那間壁的一家唱著留聲機;對面是弄孩子。樓上有兩人狂笑;還有打牌聲。河中的船上有女人哭著她死去的母親。人類的悲歡並不相通,我只覺得他們吵鬧 。

OpenCV是一個基於BSD許可(開源)發行的跨平臺計算機視覺庫,可以執行在Linux、Windows、Android和Mac OS作業系統上。它輕量級而且高效——由一系列 C 函式和少量 C++ 類構成,同時提供了Python、Ruby、MATLAB等語言的介面,實現了影象處理和計算機視覺方面的很多通用演算法。
OpenCV用C++語言編寫,它的主要介面也是C++語言,但是依然保留了大量的C語言介面。該庫也有大量的Python、Java and MATLAB/OCTAVE(版本2.5)的介面。這些語言的API介面函式可以通過線上文件獲得。如今也提供對於C#、Ch、Ruby,GO的支援。
所有新的開發和演算法都是用C++介面。一個使用CUDA的GPU介面也於2010年9月開始實現。

影象的空間域濾波:空間域濾波,空間域濾波就是用各種模板直接與影象進行卷積運算,實現對影象的處理,這種方法直接對影象空間操作,操作簡單,所以也是空間域濾波。

頻域濾波說到底最終可能是和空間域濾波實現相同的功能,比如實現影象的輪廓提取,在空間域濾波中我們使用一個拉普拉斯模板就可以提取,而在頻域內,我們使用一個高通濾波模板(因為輪廓在頻域內屬於高頻訊號),可以實現輪廓的提取,後面也會把拉普拉斯模板頻域化,會發現拉普拉斯其實在頻域來講就是一個高通濾波器。

既然是頻域濾波就涉及到把影象首先變到頻域內,那麼把影象變到頻域內的方法就是傅立葉變換。關於傅立葉變換,感覺真是個偉大的發明,尤其是其在訊號領域的應用。高通濾波器,又稱低截止濾波器、低阻濾波器,允許高於某一截頻的頻率通過,而大大衰減較低頻率的一種濾波器。它去掉了訊號中不必要的低頻成分或者說去掉了低頻干擾。

import cv2 as cv

import numpy as np

from matplotlib import pyplot as plt

 

img = cv.imread('23.png', 0)

f = np.fft.fft2(img)

fshift = np.fft.fftshift(f)

#取絕對值:將複數變化成實數

#取對數的目的為了將資料變化到較小的範圍(比如0-255)

s1 = np.log(np.abs(f))

s2 = np.log(np.abs(fshift))

plt.subplot(121),plt.imshow(s1,'gray'),plt.title('original')

plt.subplot(122),plt.imshow(s2,'gray'),plt.title('center')

 

這個圖就是把時域影象(大概是方波)變成了一系列的正弦波的線性疊加,其等價關係可以表示為:

f()=A1sin(w1x+ϕ1)+A2sin(w2x+ϕ2)+...


那麼w1,w2,...可以看成是頻率的變化(一般認為就是從1,2,…n定死了),所有的A就是對應頻率下的振幅,所有的ϕ就是對應頻率下的相位,那麼對於任一個訊號,如果都認為頻率w是從1,2,3…一直增加的話,那麼每個訊號就只由一組振幅與一組ϕ來決定,他們的不同決定了最終訊號的不同。

再來理解下什麼是振幅,振幅就是各個頻率下的訊號的決定程度有多大,如果某個頻率的振幅越大,那麼它對原始訊號的的重要性越大,像上圖,當然是w=1的時候振幅最大,說明它對總的訊號影響最多(去掉w=1的訊號,原始訊號講嚴重變形)。越往後面,也就是越高頻,振幅逐漸減小,那麼他們的作用就越小,而他們對於整體訊號又有什麼影響呢?既然越小,那就是影響小,所以其實去掉,原始訊號也基本上不變,他們影響就在於對原始訊號的細節上的表現,比如原始訊號上的邊邊角角,偶爾有個小凸起凹槽什麼的,這些小細節部分都是靠這些個影響不大的高頻訊號來表現出來的。深入推廣一下,這就很好理解為什麼影象的高頻訊號其實表現出來的就是影象的邊緣輪廓、噪聲等等這些細節的東西了,而低頻訊號,表現的卻是影象上整塊整塊灰度大概一樣的區域了(這些個區域又稱為直流分量區域)。

再來理解下什麼是相位,相位表示其實表面對應頻率下的正弦分量偏離原點的程度,再借用下上述部落格中的一個圖,把分量示意圖放大了:

上圖看到,如果各個頻率的分量相位都是0的話,那麼每個正弦分量的最大值(在頻率軸附近的那個最大值)都會落在頻率軸為0上,然而上述圖並不是這樣。在說簡單一點,比如原始訊號上有個凹槽,正好是由某一頻率的分量疊加出來的,那麼如果這個頻率的相位變大一點或者變小一點的話,帶來的影響就會使得這個凹槽向左或者向右移動一下,也就是說,相位的作用就是精確定位到訊號上一點的位置的。 好了,有了上述的概念,再來看看影象的傅立葉變換,上述舉得例子是一維訊號的傅立葉變換,並且訊號是連續的,我們知道影象是二維離散的,連續與離散都可以用傅立葉進行變換,那麼二維訊號無非就是在x方向與y方向都進行一次一維的傅立葉變換得到,這麼看來,可以想象,它的頻率構成就是一個網格矩陣了,橫軸從w=1到n,縱軸也是這樣。所有影象的頻率構成都認為是這樣的,那麼不同的就是一幅圖的振幅與相位了(振幅與相位此時同樣是一個網格矩陣),也就是說你在opencv或者matlab下對影象進行傅立葉變換後其實是可以得到影象的振幅圖與相點陣圖的,而想把影象從頻域空間恢復到時域空間,必須要同時有影象的振幅圖與相點陣圖才可以,缺少一個就恢復的不完整。

在這裡插入一個獲取視訊的程式碼

從攝像頭捕獲視訊

OpenCV提供了一個非常簡單的介面,用來相機捕捉實時流。
任務:從相機中獲取一個視訊(由於練習時家裡的臺式沒有攝像頭,就直接獲取一個本地視訊),把它轉換成灰度級的視訊並顯示出來。

要捕獲一個視訊,你需要建立一個可視的物件cv.VideoCapture()。引數可以是裝置索引,也可以是視訊檔案的名稱(這裡用視訊檔名稱)。裝置索引只是指定哪個攝像頭的號碼,如0、1、2。

 1 import cv2 as cv
 2 
 3 cap = cv.VideoCapture('test.mp4')
 4 while cap.isOpened():
 5     # 逐幀捕獲
 6     ret, frame = cap.read()
 7     # 對幀進行操作
 8     gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
 9     # 展示結果
10     cv.imshow('frame', gray)
11     if cv.waitKey(1) & 0xFF == ord('q'):
12         break
13 
14 # 一切完成後,釋放捕獲
15 cap.release()
16 cv.destroyAllWindows()

回到正題,傅立葉空間的變幻程式碼介紹開始:

1.獲取圖片振幅資訊

 1 import cv2 as cv
 2 import numpy as np
 3 from matplotlib import pyplot as plt
 4 
 5 img = cv.imread('你想要插入的圖片', 0#0代表傳入的是灰度影象,1代表彩色影象)
 6 f = np.fft.fft2(img)
 7 fshift = np.fft.fftshift(f)
 8 #取絕對值:將複數變化成實數
 9 #取對數的目的為了將資料變化到較小的範圍(比如0-255)
10 s1 = np.log(np.abs(f))
11 s2 = np.log(np.abs(fshift))
12 plt.subplot(121),plt.imshow(s1,'gray'),plt.title('original')
13 plt.subplot(122),plt.imshow(s2,'gray'),plt.title('center')

注意的是,這個程式的result其實並沒有什麼含義,顯示出來的可以看成是頻域後影象的振幅資訊,並沒有相位資訊,ϕ=atan(numpy包中自帶一個angle函式可以直接根據複數的實部與虛部求出角度(預設出來的角度是弧度)。像上述程式出來的f與fshift都是複數,就可以直接angle函式一下,比如試試並把對應的相點陣圖像顯示出來

 1 import cv2 as cv
 2 import numpy as np
 3 from matplotlib import pyplot as plt
 4 
 5 img = cv.imread('23.png', 0)
 6 
 7 f = np.fft.fft2(img)
 8 fshift = np.fft.fftshift(f)
 9 #取絕對值:將複數變化成實數
10 #取對數的目的為了將資料變化到較小的範圍(比如0-255)
11 ph_f = np.angle(f)
12 ph_fshift = np.angle(fshift)
13 
14 plt.subplot(121),plt.imshow(ph_f,'gray'),plt.title('original')
15 plt.subplot(122),plt.imshow(ph_fshift,'gray'),plt.title('center')
View Code

result就是影象上每個畫素點對應的相點陣圖,其實是毫無規律的,理解就是偏移的角度。

Ok再來說說程式中為什麼要有一個np.fft.fftshift(f)中心化操作,整個影象是在傅立葉變換的一個週期內完成的,將其看成橫縱兩個方向的一維傅立葉變換,在每個方向上都會有高頻訊號和低頻訊號,那麼傅立葉變換將低頻訊號放在了邊緣,高頻訊號放在了中間,然而一副影象,很明顯的低頻訊號多而明顯,所以將低頻訊號採用一種方法移到中間,在時域上就是對f乘以(-1)^(M+N),換到頻域裡面就是位置的移到了。

影象變換到頻域後就可以進行操作了,目前接觸到的頻域操作似乎也就是一些濾波操作,如同空域裡面的濾波操作一樣,不過原理不一樣了,後面再說說一些頻域濾波方法。好了一旦操作完,得到的資料還是頻域資料,那麼如何將其變換到時域呢?這裡就是傅立葉反變換了,公式表示就如同前面那樣。這個頻域變換到時域的操作就是逆向傅立葉變換再走一遍(比如先反中心化,在逆變換)。

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 
 5 img = cv2.imread('23.png',0) #直接讀為灰度影象
 6 f = np.fft.fft2(img)
 7 fshift = np.fft.fftshift(f)
 8 #取絕對值:將複數變化成實數
 9 #取對數的目的為了將資料變化到0-255
10 s1 = np.log(np.abs(fshift))
11 plt.subplot(131),plt.imshow(img,'gray'),plt.title('original')
12 plt.subplot(132),plt.imshow(s1,'gray'),plt.title('center')
13 # 逆變換
14 f1shift = np.fft.ifftshift(fshift)
15 img_back = np.fft.ifft2(f1shift)
16 #出來的是複數,無法顯示
17 img_back = np.abs(img_back)
18 plt.subplot(133),plt.imshow(img_back,'gray'),plt.title('img back')
View Code

可以看到恢復的一模一樣。

(振幅是複數的實數部,相位是複數的虛數部)我們說,恢復一個頻域影象需要影象的振幅以及相位,而一個複數也正好包含這些,振幅就是實部虛部的平方和開方,相位就是atan()

,前面說過。那麼現在假設我們只用一副影象的振幅或者相位來將頻域內影象恢復到時域會怎麼樣呢?下面給出只用振幅、只用相位以及兩者在聯合起來來恢復的程式:

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 
 5 img = cv2.imread('23.png',0) #直接讀為灰度影象
 6 f = np.fft.fft2(img)
 7 fshift = np.fft.fftshift(f)
 8 #取絕對值:將複數變化成實數
 9 #取對數的目的為了將資料變化到0-255
10 s1 = np.log(np.abs(fshift))
11 plt.subplot(221),plt.imshow(img,'gray'),plt.title('original')
12 plt.xticks([]),plt.yticks([])
13 #---------------------------------------------
14 # 逆變換--取絕對值就是振幅
15 f1shift = np.fft.ifftshift(np.abs(fshift))
16 img_back = np.fft.ifft2(f1shift)
17 #出來的是複數,無法顯示
18 img_back = np.abs(img_back)
19 #調整大小範圍便於顯示
20 img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
21 plt.subplot(222),plt.imshow(img_back,'gray'),plt.title('only Amplitude')
22 plt.xticks([]),plt.yticks([])
23 #---------------------------------------------
24 # 逆變換--取相位
25 f2shift = np.fft.ifftshift(np.angle(fshift))
26 img_back = np.fft.ifft2(f2shift)
27 #出來的是複數,無法顯示
28 img_back = np.abs(img_back)
29 #調整大小範圍便於顯示
30 img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
31 plt.subplot(223),plt.imshow(img_back,'gray'),plt.title('only phase')
32 plt.xticks([]),plt.yticks([])
33 #---------------------------------------------
34 # 逆變換--將兩者合成看看
35 s1 = np.abs(fshift) #取振幅
36 s1_angle = np.angle(fshift) #取相位
37 s1_real = s1*np.cos(s1_angle) #取實部
38 s1_imag = s1*np.sin(s1_angle) #取虛部
39 s2 = np.zeros(img.shape,dtype=complex) 
40 s2.real = np.array(s1_real) #重新賦值給s2
41 s2.imag = np.array(s1_imag)
42 
43 f2shift = np.fft.ifftshift(s2) #對新的進行逆變換
44 img_back = np.fft.ifft2(f2shift)
45 #出來的是複數,無法顯示
46 img_back = np.abs(img_back)
47 #調整大小範圍便於顯示
48 img_back = (img_back-np.amin(img_back))/(np.amax(img_back)-np.amin(img_back))
49 plt.subplot(224),plt.imshow(img_back,'gray'),plt.title('another way')
50 plt.xticks([]),plt.yticks([])
View Code

 

可以看到,僅僅振幅的恢復圖啥也不是,僅僅的相點陣圖還有那麼點意思,當然也是啥也不是。最後是把振幅與相位分別作為頻域內複數的實部和虛部,得到的恢復圖才與原來的一樣。

基於此,我們來做一個有趣的實驗,假設有兩幅影象,將這兩幅影象進行傅立葉變換到頻域,然後把用一個影象的振幅做為振幅,用另一幅影象的相位作為相位生成一副新的影象,那麼,這個影象會怎麼樣呢?你覺得生成的影象會更像取振幅的那副還是取相位的那副呢?來看看吧:

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 
 5 img_flower = cv2.imread('v',0) #直接讀為灰度影象
 6 img_man = cv2.imread('v',0) #直接讀為灰度影象
 7 plt.subplot(221),plt.imshow(img_flower,'gray'),plt.title('origial1')
 8 plt.xticks([]),plt.yticks([])
 9 plt.subplot(222),plt.imshow(img_man,'gray'),plt.title('origial_2')
10 plt.xticks([]),plt.yticks([])
11 #--------------------------------
12 f1 = np.fft.fft2(img_flower)
13 f1shift = np.fft.fftshift(f1)
14 f1_A = np.abs(f1shift) #取振幅
15 f1_P = np.angle(f1shift) #取相位
16 #--------------------------------
17 f2 = np.fft.fft2(img_man)
18 f2shift = np.fft.fftshift(f2)
19 f2_A = np.abs(f2shift) #取振幅
20 f2_P = np.angle(f2shift) #取相位
21 #---圖1的振幅--圖2的相位--------------------
22 img_new1_f = np.zeros(img_flower.shape,dtype=complex) 
23 img1_real = f1_A*np.cos(f2_P) #取實部
24 img1_imag = f1_A*np.sin(f2_P) #取虛部
25 img_new1_f.real = np.array(img1_real) 
26 img_new1_f.imag = np.array(img1_imag) 
27 f3shift = np.fft.ifftshift(img_new1_f) #對新的進行逆變換
28 img_new1 = np.fft.ifft2(f3shift)
29 #出來的是複數,無法顯示
30 img_new1 = np.abs(img_new1)
31 #調整大小範圍便於顯示
32 img_new1 = (img_new1-np.amin(img_new1))/(np.amax(img_new1)-np.amin(img_new1))
33 plt.subplot(223),plt.imshow(img_new1,'gray'),plt.title('another way')
34 plt.xticks([]),plt.yticks([])
35 #---圖2的振幅--圖1的相位--------------------
36 img_new2_f = np.zeros(img_flower.shape,dtype=complex) 
37 img2_real = f2_A*np.cos(f1_P) #取實部
38 img2_imag = f2_A*np.sin(f1_P) #取虛部
39 img_new2_f.real = np.array(img2_real) 
40 img_new2_f.imag = np.array(img2_imag) 
41 f4shift = np.fft.ifftshift(img_new2_f) #對新的進行逆變換
42 img_new2 = np.fft.ifft2(f4shift)
43 #出來的是複數,無法顯示
44 img_new2 = np.abs(img_new2)
45 #調整大小範圍便於顯示
46 img_new2 = (img_new2-np.amin(img_new2))/(np.amax(img_new2)-np.amin(img_new2))
47 plt.subplot(224),plt.imshow(img_new2,'gray'),plt.title('another way')
48 plt.xticks([]),plt.yticks([])
View Code

重點來了:如果兩張圖片的維度不一樣,也就是矩陣的shape不一樣時,彙報錯ValueError: operands could not be broadcast together with shapes,所以變換的兩張圖片維度一定要一樣,也就是說大小要一樣,這個解決了好久,其他也是,兩張圖片處理時是通過np的方法形成的矩陣,矩陣大小一定要一樣才能繼續計算,否則是無法處理的。

合成的影象,是不是很有趣,影象3是圖1的振幅加圖2的相位,影象4是圖1的相位加上圖2的振幅。很明顯的可以看到,新影象佔用誰的相位就越像誰,為什麼會這樣?很簡單,可以理解振幅不過描述影象灰度的亮度,佔用誰的振幅不過使得結果哪些部分偏亮或者暗而已,而影象是個什麼樣子是由它的相位決定的。相位描述的是一個方向,方向正確了,那麼最終的結果離你的目的就不遠了。可想而知,方向對於一件事物是多麼的重要,大自然的規律尚且如此,更別說做人做事了,找準並相信一個方向,慢慢的走下去吧,總有一天會看到成果的,哪怕你的振幅不對,走的慢一點,但是最終也能走的像模像樣的,不會說到了人生的最後,回頭一看,再來感嘆哎呀這是什麼玩意,那就很悲哀了。

下面開始講濾波器啦!

我們只說了開頭(怎麼變換)和結尾(怎麼變回去),那麼中間我們要做的東西才是傅立葉變換的目的—頻域下的各種變化操作。

這裡主要介紹頻域下的濾波–低通濾波器,高通濾波器,帶通帶阻濾波器。

我們知道,影象在變換加移動中心後,從中間到外面,頻率上依次是從低頻到高頻的,那麼我們如果把中間規定一小部分去掉,是不是相對於把低頻訊號去掉了呢?這也就是相當於進行了高通濾波。這個濾波模板畫出來可能就是這樣的:

 

黑色為0,白色為1,把這個模板去和影象進過傅立葉變換的頻域矩陣去與(相乘)一下就實現了高通濾波。

高通濾波器程式碼如下

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 
 5 img_man = cv2.imread('lip',0) #直接讀為灰度影象
 6 plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
 7 plt.xticks([]),plt.yticks([])
 8 #--------------------------------
 9 rows,cols = img_man.shape
10 mask = np.ones(img_man.shape,np.uint8)
11 mask[rows//2-30:rows//2+30,cols//2-30:cols//2+30] = 0
12 #--------------------------------
13 f1 = np.fft.fft2(img_man)
14 f1shift = np.fft.fftshift(f1)
15 f1shift = f1shift*mask
16 f2shift = np.fft.ifftshift(f1shift) #對新的進行逆變換
17 img_new = np.fft.ifft2(f2shift)
18 #出來的是複數,無法顯示
19 img_new = np.abs(img_new)
20 #調整大小範圍便於顯示
21 img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
22 plt.subplot(122),plt.imshow(img_new,'gray'),plt.title('Highpass')
23 plt.xticks([]),plt.yticks([])

可以看到,高通濾波器有利於提取影象的輪廓,這裡我們從原理上分析一下為什麼,影象的輪廓或者邊緣或者一些噪聲處,灰度變化劇烈,那麼在把它們經過傅立葉變換後,就會變成高頻訊號(我們知道高頻時捕捉細節的),所以在把影象低頻訊號濾掉以後剩下的自然就是輪廓了。也可以這麼說,灰度變化劇烈的地方是高頻資訊,輪廓既是如此。傅立葉空間中亮度代表振幅,振幅越大,亮度越高,該頻率下資訊越多,而相位則是蘊含著資訊。

舉手投足山水間,溫文爾雅真君子,他與世界相遇 他自與世界相蝕 ,他自不辱使命 使他與眾生相聚。

反過來我們來看看空間域濾波中的拉普拉斯模板,現在我們把這個模板進行傅立葉變換到頻域看看:

1 import numpy as np
2 import matplotlib.pyplot as plt
4 laplacian = np.array([[0,1,0],[1,-4,1],[0,1,0]])
5 f = np.fft.fft2(laplacian)
6 f1shift = np.fft.fftshift(f)
7 img = np.log(np.abs(f1shift))
8 plt.imshow(img,'gray')

可以看到,這個模板的頻域變換下四周特別亮,也就是是個高通濾波器。其它空間域下的模板都可以轉到頻域下來看看。

下面再來試試低通濾波器什麼效果,構造個低通濾波器也很簡單,把上述模板中的1變成0,0變成1,其實就是低通了:

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 img_man = cv2.imread('lip',0) #直接讀為灰度影象
 5 plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
 6 plt.xticks([]),plt.yticks([])
 7 #--------------------------------
 8 rows,cols = img_man.shape
 9 mask = np.zeros(img_man.shape,np.uint8)
10 mask[rows//2-20:rows//2+20,cols//2-20:cols//2+20] = 1
11 #--------------------------------
12 f1 = np.fft.fft2(img_man)
13 f1shift = np.fft.fftshift(f1)
14 f1shift = f1shift*mask
15 f2shift = np.fft.ifftshift(f1shift) #對新的進行逆變換
16 img_new = np.fft.ifft2(f2shift)
17 #出來的是複數,無法顯示
18 img_new = np.abs(img_new)
19 #調整大小範圍便於顯示
20 img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
21 plt.subplot(122),plt.imshow(img_new,'gray'),plt.title('Highpass')
22 plt.xticks([]),plt.yticks([])
低通濾波器

可以看到低通濾波後影象除了輪廓模糊了外,基本上沒什麼變化,影象的大部分資訊基本上都保持了。從原理上來看,影象的主要資訊都集中在低頻上,所以低通濾波器的效果是這樣也是可以理解的。上述的高通、低通濾波器的構造有0,1構成的理想濾波器,也是最簡單的濾波器,還有一些其他的濾波器,比如說高斯濾波器,butterworth濾波器等等,下面是參考岡薩雷斯書上的圖:

 

 還有就是把高通低通都結合一部分到一個模板上形成的帶通濾波器,這在一些場合會很有用,還是以理想的帶通濾波器實驗下:

 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 img_man = cv2.imread('lip',0) #直接讀為灰度影象
 5 plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
 6 plt.xticks([]),plt.yticks([])
 7 #--------------------------------
 8 rows,cols = img_man.shape
 9 mask1 = np.ones(img_man.shape,np.uint8)
10 mask1[rows//2-8:rows//2+8,cols//2-8:cols//2+8] = 0
11 mask2 = np.zeros(img_man.shape,np.uint8)
12 mask2[rows//2-80:rows//2+80,cols//2-80:cols//2+80] = 1
13 mask = mask1*mask2
14 #--------------------------------
15 f1 = np.fft.fft2(img_man)
16 f1shift = np.fft.fftshift(f1)
17 f1shift = f1shift*mask
18 f2shift = np.fft.ifftshift(f1shift) #對新的進行逆變換
19 img_new = np.fft.ifft2(f2shift)
20 #出來的是複數,無法顯示
21 img_new = np.abs(img_new)
22 #調整大小範圍便於顯示
23 img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
24 plt.subplot(122),plt.imshow(img_new,'gray')
25 plt.xticks([]),plt.y
 1 import cv2
 2 import numpy as np
 3 import matplotlib.pyplot as plt
 4 img_man = cv2.imread('lip',0) #直接讀為灰度影象
 5 plt.subplot(121),plt.imshow(img_man,'gray'),plt.title('origial')
 6 plt.xticks([]),plt.yticks([])
 7 #--------------------------------
 8 rows,cols = img_man.shape
 9 mask1 = np.ones(img_man.shape,np.uint8)
10 mask1[rows//2-8:rows//2+8,cols//2-8:cols//2+8] = 0
11 mask2 = np.zeros(img_man.shape,np.uint8)
12 mask2[rows//2-80:rows//2+80,cols//2-80:cols//2+80] = 1
13 mask = mask1*mask2
14 #--------------------------------
15 f1 = np.fft.fft2(img_man)
16 f1shift = np.fft.fftshift(f1)
17 f1shift = f1shift*mask
18 f2shift = np.fft.ifftshift(f1shift) #對新的進行逆變換
19 img_new = np.fft.ifft2(f2shift)
20 #出來的是複數,無法顯示
21 img_new = np.abs(img_new)
22 #調整大小範圍便於顯示
23 img_new = (img_new-np.amin(img_new))/(np.amax(img_new)-np.amin(img_new))
24 plt.subplot(122),plt.imshow(img_new,'gray')
25 plt.xticks([]),plt.yticks([])

 

這就是帶通的效果,既可以保留一部分低頻,也可以保留一部分高頻,至於保留多少,怎麼保留就視問題的不同而不同了。 

最後宣告幾點:

1.所有影象處理部分的23.png,lip,v都是我自己測試時用的資料,在自己做影象處理時可以直接替換成相應的檔名(執行的py檔案要和影象在同一目錄),其他程式碼視情況改變,如果不是想執行其他功能,可以直接用。

2.結果的圖片沒有放上,因為用的linux系統,剛剛配置不想截圖浪費時間。

3.關於庫的問題,ananconda裡有numpy,matplotlin.pyplot庫,但是cv2庫要自己下載,下載方法用pip,一句話,在終端輸入如下程式碼

pip install opencv-python

至於pip的安裝:

linux下:

下載檔案 wget https://bootstrap.pypa.io/get-pip.py --no-check-certificate

執行安裝 python get-pip.py 這就安裝好了 

windows下:

參見網址

https://jingyan.baidu.com/article/ff42efa9d630e5c19e220207.html 

 

相關文章