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


Magnitude Spectrum 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


JET

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

Fourier OpenCV

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()

Result

Fourier Performance Code Example