Wednesday, April 14, 2010

Learning OpenCV: Smoothing image in OpenCV

ใน OpenCV มีฟังก์ชันการทำ smoothing image มาให้ ตอนแรกไม่เคยคิดมาก่อนว่า smoothing = blurring การทำ smoothing ใน OpenCV ใช้คำสั่ง

void cvSmooth(
      
    const   CvArr*     src,
    CvArr*                dst,
    int                        smoothtype =CV_GAUSSIAN,
    int                        param1=3,
    int                        param2=0,
    int                        param3=0,
    int                        param4=0
);

โดยรวมแล้วคือการเฉลี่ยค่าของ pixel (จริงๆ คือค่าใช้ CvArr นั้นๆ แต่ต่อไปนี้ถือว่าเราประมวลกับภาพ จึงขอเรียก pixel เพื่อความสะดวก) นั้นๆ ด้วย pixel ที่อยู่รอบข้าง

ตัวแปร smoothtype มีค่าคือ CV_BLUR, CV_BLUR_NO_SCALE, CV_MEDIAN, CV_GAUSSIAN, CV_BILATERAL

CV_BLUR คือการทำเฉลี่ยค่า pixel ด้วยค่า pixel รอบๆ ข้าง โดยขนาด pixel รอบข้างกำหนดไว้ใน param1, param2

CV_BLUR_NO_SCALE คือผลรวมค่า pixel ด้วยค่า pixel รอบๆ ข้าง(แบบเดียวกับ CV_BLUR) ผลลัพธ์ที่ได้จะเร็วกว่า CV_BLUR (เพราะใช้ผลรวมในขณะที่ CV_BLUR ต้องหารด้วย param1*param2 อีกที) ข้อควรระวังคือ dst จะต้องมี bit depth ที่มากกว่า src ไม่งั้นจะเกิดการ overflow ได้

CV_MEDIAN เหมือน CV_BLUR แต่ใช้ค่ามัธยฐานแทนค่าเฉลี่ยเลขคณิต ด้วยคุณสมบัติของมัธยฐานที่ส่วนใหญ่ไม่มีผลกระทบต่อข้อมูลที่โดดในกลุ่ม ดังนั้นการใช้วิธีนี้จะทนต่อ noisy image ได้ดีกว่าแบบ CV_BLUR ทั้งสองแบบ

CV_GAUSSIAN คือการใช้ค่าเฉลี่่ยแบบ GAUSSIAN โดยค่า pixel แต่ละ pixel จะถูกถ่วงน้ำหนักด้วยด้วยค่าที่แปรผกผันกับระยะห่างจาก pixel ที่ต้องการ  ยิ่งไกลมากผลของ pixel นั้นก็จะน้อย param1, param2 แสดงถึงขนาดของ filter window  param3,param4 คือค่า σ ในแนวนอนและแนวตั้ง Gaussian distribution ตามลำดับ 


ใน OpenCV มีการ optimize โคดเป็นพิเศษสำหรับ gaussian kernel ขนาด 3x3, 5x5, 7x7 โดยตั้งค่า param3=0


แต่จุดอ่อนของ GAUSSIAN smooth คือ gaussian assume ว่า noise จะเกิดกระจายได้ทั่วๆไม่ได้กระจุกที่ใดที่หนึ่งเป็นพิเศษ และค่าของ pixel จะมีความกระจายแบบต่อเนื่่อง(เข้าใจว่าเป็นผลมาจากการ assumption ว่าเป็นกระจายแบบ gaussian) ซึ่งในส่วน edge ของภาพ pixel จะกระจายไม่ต่อเนื่องกับ pixel ข้างเคียง(ก็เป็นขอบนี่มันก็ต้องตัดกันสิ) ผลที่ได้คือ Gaussian จะ smooth ส่วน edge ทิ้งไป

CV_BILATERAL โดยหลักการของ bilateral filtering นั้นจะคำนวณ pixel โดยถ่วงน้ำหนักจากทั้ง space (ระยะห่าง ยิ่งห่างมากยิ่งมีน้ำหนักน้อย) และ range(ความแตกต่างของสียิ่งแตกต่างมากยิ่งมีน้ำหนักน้อย) ใน OpenCV การถ่วงน้ำหนักที่ใช้ จะใช้ Guassian distribution ทั้ง space และ range(จริงๆ ใช้ distribution อื่นก็ได้) การ smooth แบบนี้จะรักษา edge ของภาพไว้ได้ดีกว่าแบบ CV_GAUSSIAN  param1 จะเป็นค่า σ สำหรับ spatial domain, param2 จะเป็นค่า σ สำหรับ color domain


ค่า σ ใน gaussian distribution จะหมายถึงค่า standard deviation ของการกระจ่ายการตั้งค่า σ ให้มากจะเป็นเพิ่มน้ำหนักให้กับ pixel (เพราะในความเป็นจริงตามสูตร ระยะห่างทั้ง space และ color จะคิดเป็นจำนวนเท่าของ σ)






No comments:

Post a Comment