Image Transforms in OpenCV
จาก Morange Wiki
เนื้อหา
Fourier Transform
วัตถุประสงค์
- หาค่า Fourier Transform ของรูปภายโดยใช้ OpenCV
- รู้วิธีหา utilize ของ FFT ในฟังก์ชั่น numpy
- สร้างแอปพลิเคชั่นเล็กๆของ Fourier Transform
- ใช้ฟังก์ชั่นในการทำงานคือ cv2.dft() , cv2.idft()
Fourier Transform in Numpy
- ในการหาฟูเรียร์โดยใช้ Numpy โดยใน Numpy นั้นจะมี Package เพื่อหามันคือ np.fft.fft2() ในการหานั้นเราจะใช้ ความถี่ของรูปร่างในการหาซึ่งจะเป็น อาร์เรย์ที่ซับซ้อนเป็นอย่างมาก โดยอาร์กิวเมนต์แรก คือ ภาพที่นำเข้ามาซึ่งเป็นภาพสีเทา และอาร์กิวเม้นที่สองจะเป็นตัวเลือกที่ตัดสินใจขนาดของอาร์เรย์ที่แสดงเอาท์พุทออกมา ถ้ามีมากกว่าขนาดของภาพที่นำ ภาพที่นำเข้าจะมีค่า padded เท่ากับ 0 ก่อนจะนำไปคำนวน FFT ถ้าเป็นภาพที่น้อยกว่า ภาพที่นำเข้าจะถูกตัด หากไม่มีข้อโต้แย้งอื่น ภาพเอ้าท์พุทจะเป็นเช่นเดียวกับภาพอินพุท
CODE EXAMPLE
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('../media/Lenna.png',0) f = np.fft.fft2(img) 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()
Result
JET
- สำหรับการหาค่าความถี่ของ ตอนนี้จะเรียนรู้เกี่ยวกับ Operation เกี่ยวกับ ความถี่ของ domain โดยจะหาความสูงผ่านการกรอง และ การ reconstruct ในการหา INVERT DFT นั้นจะสามารถลบค่าความถี่ต่ำของ masking กับ รูปร่างของหน้าต่างขนาด 60x60 ในการ inverse shift นั้นจะใช้ฟังก์ชั่น np.fft.ifftshift() ทดลองใช้ CODE
CODE EXAMPLE
import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('../media/Lenna.png',0) f = np.fft.fft2(img) fshift = np.fft.fftshift(f) magnitude_spectrum = 20*np.log(np.abs(fshift)) 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) 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()
Result
Fourier Transform in OpenCV
- ใน OpenCV นั้นการค่า ฟูเรียร์ จะใช้ฟังก์ชั่น cv2.dft() และ cv2.idft() เพื่อหาค่าที่ Return กลับมาก่อนหน้า โดยจะเปรียบเทียบกับ แชแนลแรกและชิ้นส่วนจริงๆ โดยผลลัพธ์ที่สองนั้น จะได้รับ imaginary part เป็นผลลัพธ์ โดยรูปนั้นจะต้องถูกแปลงเป็น np.float32 ก่อนเสมอ ดูวิธีทำได้ด้านล่าง
Code Example
import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('Lenna.png',0) 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()
- ต่อไปจะเป็นการทำ Inverse DFT เหมือนกับครั้งก่อน เราจะสร้าง HPF มาก่อน และมาดูวิธีการลบค่าความถี่สูงในรูปภาพ
Inverse DFT Code Ex.
import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('Lenna.png',0) 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])) rows, cols = img.shape crow,ccol = rows/2 , cols/2 # create a mask first, center square is 1, remaining all zeros mask = np.zeros((rows,cols,2),np.uint8) mask[crow-30:crow+30, ccol-30:ccol+30] = 1 # apply mask and inverse DFT 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()
Result
Performance Optimization of DFT
- ผลการดำเนินงานของการคำนวณ DFT นั้น จะดีมากกว่าสำหรับบางอย่างของขนาดอาร์เรย์ โดยจะทำให้รวดเร็วขึ้นเมื่อ ขนาดของอาร์เรย์ นั้นมี Power ทั้ง 2 อาร์เรย์ โดยขนาดของ Product นั้น เท่ากับ 2's 3's และ 5's โดยที่จะสามารถประมวลผลได้อย่างมีประสิทธิภาพ ดังนั้นถ้าหากมีความกังวลใจเกี่ยวกับประสิทธิภาพของ CODE เราจะสามารถปรับเปลี่ยนขนาดของอาร์เรย์ให้มีขนาดที่เหมาะสมใดๆ โดยที่จะหาค่า DFT ใน OpenCV นั้น จะต้องหาค่า pad zeros ด้วยตนเอง แต่สำหรับ Numpy จะต้องหาค่าเฉพาะตัวของ ขนาด FFT ในการคำนวณ และ จะหาค่า pad zeros เองโดยอัตโนมัติ
ทดลองเขียนโดย IPython ได้ว่า
In [16]: img = cv2.imread('messi5.jpg',0) In [17]: rows,cols = img.shape In [18]: print rows,cols 342 548 #ผลลัพธ์ In [19]: nrows = cv2.getOptimalDFTSize(rows) In [20]: ncols = cv2.getOptimalDFTSize(cols) In [21]: print nrows, ncols 360 576 #ผลลัพธ์
- จะเห็นว่า (342,548) จะโดนเปลี่ยนเป็น (260,576) จากนั้นค่า pad จะเป็น 0 สำหรับ และการเพิ่มประสิทธิภาพของการคำนวณ DFT นั้น สามารถทำได้โดยสร้าง big zero array และ ก๊อปปี้มัน หรือใช้ cv2.copyMakeBorder()
- EXAMPLE
nimg = np.zeros((nrows,ncols)) nimg[:rows,:cols] = img
- หรือ
right = ncols - cols bottom = nrows - rows bordertype = cv2.BORDER_CONSTANT #just to avoid line breakup in PDF file nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
- ตอนนี้สามารถคำนวณค่า DFT performance โดยใช้ Numpy ฟังก์ชั่น :
In [22]: %timeit fft1 = np.fft.fft2(img) 10 loops, best of 3: 40.9 ms per loop In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols]) 100 loops, best of 3: 10.4 ms per loop
- ตอนนี้สามารถเร่งความเร็วได้ 4x หรือ 4 เท่า โดยใช้ OpenCV ฟังก์ชั่นว่า
In [24]: %timeit dft1= cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT) 100 loops, best of 3: 13.5 ms per loop In [27]: %timeit dft2= cv2.dft(np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT) 100 loops, best of 3: 3.11 ms per loop
Why Laplacian is a High Pass Filter?
CODE
import cv2 import numpy as np from matplotlib import pyplot as plt # simple averaging filter without scaling parameter mean_filter = np.ones((3,3)) # creating a guassian filter x = cv2.getGaussianKernel(5,10) gaussian = x*x.T # different edge detecting filters # scharr in x-direction scharr = np.array([[-3, 0, 3], [-10,0,10], [-3, 0, 3]]) # sobel in x direction sobel_x= np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]) # sobel in y direction sobel_y= np.array([[-1,-2,-1], [0, 0, 0], [1, 2, 1]]) # laplacian 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 xrange(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()