การทำ affine จะสามารถ transform รูปสี่เหลี่ยมผืนผ้าไปเป็นรูปสี่เหลี่ยมด้านขนาน ในขณะที่ homography สามารถ transform ไปเป็นรูปสี่เหลี่่ยมคางหมูได้ (เหมือนมุมมองเปลี่ยน)
ประโยชน์หนึ่งของการใช้ transformation คือการที่วัตถุอันเดียวกันถูกมองด้วยมุมมองที่ต่างกัน เช่นภาพถ่ายของวัตถุเดียวกันแต่คนละมุม ซึ่ง affine transformation สามารถใช้ได้ในหลายกรณี ยกเว้นบางกรณีทีต้องใช้ perspective transformation(homography) แต่ homography มีพารามิเตอร์มากกว่า
affine transformation คือการ transform แบบ linear transformation ตามด้วยการ translation ดังนั้นปกติในภาพ 2 มิติการทำ linear transformation สามารถใช้ matrix 2x2 แทนได้ และ ใช้ matrix 2x1 แทนการ translation ได้ (เลยเป็นที่มีของ matrix 2x3 ในที่กล่าวมาในตอนแรก) ส่วน perspective คือการหมุนในระนาบสามมิติแล้ว map กลับมาที่ระนาบสองมิติ (เลยทำไมต้อง 3x3)
การ transform ทั้ง affine และ perspective สามารถนำมาใช้ได้ทั้งการ transform แบบ dense (ภาพหรือว่าจุดที่ต่อกันเป็นภาพ) หรือแบบ sparse (list ของจุด) เราลองมาดูเป็นกรณีไป
Dense Affine Transform
เริ่มดูจากคำสั่ง
void cvWarpAffine(
const CvArr* src,
CvArr* dst,
const CvMat* map_matrix,
int flags = CV_INTER_LINEAR | CV_WARP_FILL_OUTLIERS,
CvScalar fillval = cvScalarAll(0)
);
src, dst คือภาพต้นฉบับและผลลัพธ์เหมือนเช่นเคย
map_matrix คือ matrix 2x3 ที่จะใช้ transform แบบ affine
flag จะบอกถึงวิธีการคำนวณในกรณีที่ pixel ไม่สามารพ map ได้โดยตรง และสามารถเพิ่ม(ด้วย boolean or) ตัวเลือกต่อไปนี้
- CV_WARP_FILL_OUTLIERS fill ส่วนที่ไม่สามารถ map ได้ด้วย fillval
- CV_WARP_INVERSE_MAP ให้ map จาก dst ไป src แทน
ในหนังสือแนะนำให้ใช้วิธีการทำ Dense Affine Transformation อย่างอื่นคือ
void cvGetQuadrangleSubPix(
const CvArr* src,
CvArr* dst,
const CvMat* map_matrix
);
ซึ่่งจะเห็นว่ามีพารามิเตอร์น้อยกว่า (header ในการประมวลผลก็จะน้อยกว่า) และสามารถ transform ได้ทีละหลายๆภาพ(หนังสือไม่ได้บอกว่าทำยังไง)
ปัญหาคือ ถ้าไม่ต้องการคำนวณ map_matrix เอง OpenCV ก็มีฟังก์ชันในการคำนวณให้
CvMat* cvGetAffineTransform(
const CvPoint2D32f* pts_src,
const CvPoint2D32f* pts_dst,
CvMat* map_matrix
);
โดย pts_src จะเป็นจุดในต้นฉบับสามจุด (ซึ่งเพียงพอกับการกำหนดมุมของสี่เหลี่ยมผืนผ้า) และ pts_dst จะเป็นจุดในผลลัพธ์ที่ต้องการสามจุดเช่นกัน (ก็เพียงพอกับการกำหนดมุมของสี่เหลี่ยมด้านขนาน) ผลลัพธ์ที่ได้จะอยู่ใน map_matrix อีกฟังก์ชันหนึ่งที่กล่าวถึงในหนังสือคือ cv2DRotationMatrix ซึ่งคำนวณ map_matrix จากการหมุนรูปภาพ (ซึ่งเข้าใจว่าไม่สามารถแทนการ stretch กับ shrink ได้)
Sparse Affine Transformations
เป็นการ affine transform กลุ่มของจุด
void cvTransform(
const CvArr* src,
CvArr* dst,
const CvMat* transmat,
const CvMat* shiftvec = NULL
);
ในหนังสือแนะนำวิธีการใช้ฟังก์ชันนี้สองวิธี แต่ความเห็นส่วนตัวแนะนำวิธีที่ ใช้ transmat เป็น matrix 2x3 เช่นเดียวกับการทำ Dense Affine Transformation
Dense Perspective Transformation
void cvWarpPerspective(
const CvArr* src,
CvArr* dst,
const CvMat* map_matrix,
int flags = CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS,
CvScalar fillval = cvScalarAll(0)
);
การใช้งานแบบเดียวกับ Dense Affine Translation ทุกอย่างยกเว้น map_matrix ต้องเป็น 3x3
และหา map_matrix ได้ด้วย
CvMat* cvGetPerspectiveTransform(
const CvPoint2D32f* pts_src,
const CvPoint2D32f* pts_dst,
CvMat* map_matrix
)
คล้ายๆ การหา map_matrix ของ Dense Affine Transformation เพียงแต่ ต้องกำหนดสี่จุด (เพราะว่า สามจุดไม่เพียงพอต่อการกำหนดสี่เหลี่ยมคางหมูได้อีกต่อไป)
Sparse Perspective Transformation
เปิดมาด้วยฟังก์ชันเลย
void cvPerspectiveTransform(
const CvArr* src,
CvArr* dst,
const CvMat* mat
);
โดยที่ถ้า mat เป็น matrix 3x3 จะเป็นการ project ภาพสองมิติไปยังสองมิติ(เนื้อหาในตอนนี้) ถ้าเป็น 4x4 จะเป็นการ project จาก 4 มิติไปยัง 3 มิติ (ยังหาอ่านไม่เจอ)
No comments:
Post a Comment