Friday, April 16, 2010

Learning OpevCV: Discrete Fourier Transform and Discrete Cosine Transform

มาถึงการ transform ที่มองไม่เห็นภาพเท่า ไม่เข้าใจตั้งแต่เรียน EE math แล้วว่าทำไปเพื่ออะไร มาดูตัวอย่างก็เข้าใจขึ้นมานิดนึง ว่าบางทีการคำนวณในระนาบ x,y มันลำบาก เลยต้อง transform แล้วค่อยคำนวณ ดูอย่างในตอน Log Polar

Discrete Fourier Transform
เอาไว้ transform จากโดเมนที่เป็น discrete ซึ่ง  ปกติตามสูตร(หาได้ทั่วไป) ค่า O(big oh) จะเป็น N^2 มันเลยมีวิธีคิดได้หลายวิธี เช่น fast Fourier Transform (FFT) ซึ่งได้ประมาณ O(N*logN) ฟังก์ชัน cvDFT สามารถคำนวณ FFT สำหรับ CvArr มิติเดียวหรือสองมิติ (ในกรณีที่ CvArr เป็นสองมิติ สามารถเลือกได้ว่า จะคำนวณ FFT สองมิติ หรือมอง CvArr เป็น array มิติเดียวหลายตัว ซึ่งจะคำนวณเร็วทำทีละตัว)

ตามปกติ algorithm ในการคำนวณ DFT จะมีเคสพิเศษที่คำนวณได้รวดเร็วกว่าการคำนวณแบบปกติ ในกรณีของ OpenCV ก็เช่นกัน ถ้า CvArr มีขนาด 2^m*3^n*5^n  จะสามารถคำนวณได้ดีเป็นพิเศษ(เข้าใจว่าในกรณีนี้จะใข้ FFT คำนวณ)
ลองมาดูฟังก์ชันการคำนวณ DFT กัน

void cvDFT(
    const CvArr* src,
    CvArr* dst,
    int flags,
    int nonzero_rows = 0
);

src, dst คือตันฉบับและผลลัพธ์ ถ้าต้นฉบับมี channel (แสดงถึง มีแต่ ส่วน real) ผลลัพธ์จะมีการ packing เป็นพิเศษ(นัยว่าเพื่อประหยัดเนื้อที่)
flags

  • CV_DXT_FORWARD  
  • CV_DXT_INVERSE  คำนวณย้อนกลับ(ค่าไม่เท่าเดิมนะ ถ้าจะได้เท่าเดิมต้อง scale กันก่อน)
  • CV_DXT_SCALE ใช้ในการ scale ค่า
  • CV_DXT_INV_SCALE, CV_DXT_INVERSE_SCALE รวมสองอันข้างบนไว้
  • CV_DXT_ROWS บอก cvDFT ว่า CvArr สองมิตินั่นคือ CvArr มิติเดียวหลายตัว
nonzero_rows บอกจำนวนแถวที่ padding ค่า 0 ไว้

จากที่บอกไป cvDFT สามารถคำนวณ CvArr บางขนาดได้ดีกว่าบางขนาด ซึ่งเราสามารถหาได้จากฟังก์ชัน cvGetOptimalDFTSize() ซึ่งจะให้ค่าที่ optimal ออกมา เราก็จึงต้องทำการแปลง CvArr ของเราให้ใหญ่ขึ้นตามขนาดนั้น แล้วก็ padding แถวที่เหลือด้วยค่า 0 แล้วก็ใช้ nonzero_rows บอกให้ cvDFT รู้ว่า padding กี่แถวเพื่อจะได้ละเลยไปซะทำให้การทำงานเร็วขึ้น (padding column ไม่เกี่ยว) ซึ่งค่านี้จำเป็นทั้งสำหรับการทำ forward และ inverse 

Spectrum Multiplication


Convolution and DFT
ในหัวข้อนี้จะแสดงเรื่องประโยชน์ของ DFT (เออ เพิ่งเจอตัวแรก) คือการ convolute ภาพต่างๆ นั้นมันจะยากวิธีง่ายๆ คือก็ transform ภาพโดย DFT ทำแบบเดียวกับ kernel แล้วเอาสองตัวนี้มา Multiplication กันหลังจากนั้นก็ inverse transform ผลลัพธ์ (มันจะ่ง่ายกว่าเหรอ) ลองดูในตัวอย่าง 6-5 ในหนังสือ Learning OpenCV ของ Oreilly 


Discrete Cosine Transform
ใช้เหมือนกับ DFT เพียงแต่ว่า DCT ไม่มีส่วน imagination (i) 

void cvDCT(
    const CvArr* src,
    CvArr* dst,
    int flags
);

พารามิเตอร์ใช้แบบเดียวกับ DFT (ตอนนี้ง่ายแฮะ)


No comments:

Post a Comment