Showing posts with label image segmentation. Show all posts
Showing posts with label image segmentation. Show all posts

Thursday, April 15, 2010

Open CV: Resize Image and Image Pyramids

Resize Image

การ resize image ใน OpenCV จริงๆ แล้วไม่น่าจะมีอะไรยุ่งยากในการใช้ ลองดูคำสั่งกันก่อน


void cvResize(
    const CvArr*  src,
    CvArr*           dst,
    int                    interpolation = CV_INTER_LINEAR
);

src, dst คือภาพต้นฉบับและผลลัพธ์โดยดูจากขนาดของภาพใน header (IplImage) ควรระวังการตั้ง ROI ในภาพต้นฉบับ พารามิเตอร์สุดท้ายคือฟังก์ชันในการประมาณค่า interpolate ค่า pixel โดยมีค่าเป็น

  1. CV_INTER_NN nearest neighbor
  2. CV_INTER_LINEAR Bilinear
  3. CV_INTER_AREA Pixel area re-sampling
  4. CV_INTER_CUBIC Bicubic interpolation

Image Pyramids

Image pyramids คือ collection ของ image  โดยเริ่มจาก image เริ่มต้นแล้วลดขนาดไปเรื่อยๆ จนถึงจุดที่ต้องการ ในหนังสือกล่าวถึง image pyramid สองแบบคือ gaussian pyramid กับ laplacian pyramid

Gaussian Pyramids จะเริ่มต้นที่ภาพต้นแบบเรียกว่าเลเยอร์ที่ 0 (แทนด้วย G0) เราจะสร้าง เลเยอร์ีที่ G(i+1) จากเลเยอร์ Gi โดยการ convolute Gi ด้วย gaussian kernel แล้วลบแถวคู่และหลักคู่ของภาพออกไป จะได้ภาพที่ขนาดเหลือหนึ่งในสี่ของเดิม ทำได้โดยใช้คำสั่ง

void cvPyrDown(
    IplImage* src,
    IplImage* dst,
    IplFilter filter = IPL_GAUSSIAN_5x5
);

ถ้าต้องการ ขยายภาพขึ้นมาใช้คำสั่ง

void cvPyrUp(
    IplImage* src,
    IplImage* dst,
    IplFilter filter = IPL_GAUSSIAN_5x5
);

แต่ภาพที่ได้จะคำสั่ง cvPyrUp จะไม่เท่ากับภาพก่อนหน้า เพราะว่ามีข้อมูลที่หายไปจากการ down sampling collection ของข้อมูลเหล่านี้จะเรียกว่า Laplicain Pyramids ลองดูรูปภาพตัวอย่างจากหนังสือ Learning OpenCV ของ OReilly


ไอ้ส่วนที่วงสีแดงไว้ผมว่าลูกศรน่าจะกลับทิศนะ
แล้วปัญหาคือไอ้ Image Pyramids นี่เกี่ยวกับ image segmentation ยังไงล่ะ


เขาบอกว่า การทำ image pyramids ทำให้การ segment สามารถ segment ที่ภาพเล็กๆ ก่อนแล้วค่อย map กลับเป็นภาพใหญ่ทีหลัง แน่นอน OpenCV ได้ใส่ฟังก์ชันนี้มาใ้ห้ท่านแล้ว

void cvPyrSegmentation(
    IplImage* src,
    IplImage* dst,
    CvMemStorage* storage,
    CvSeq** comp,
    int level,
    double threshold1,
    double threshold2
);

src, dst คือต้นฉบับและผลลัพธ์(เนื่องจาก OpenCV ใช้ dst ในการคำนวณด้วย ดังนั้นยังไงก็ต้องใส่) int คือจำนวน level ของ pyramids (จะต้องระวังด้วย ว่าขนาดของความกว้างและความยาวของภาพใน src จะต้องหารด้วย 2^(levlel-1) ลงตัว)

stroage เป็น memory storage ที่ OpenCV ต้องการใช้ (รายละเอียดใน Memory Storage)

comp จะเป็น sequence ที่สร้างมาจาก cvPyrSegmentation เป็นข้อมูลเกี่ยวกับ connected component (cvConnectedComp) ซึ่งอธิบายโดย
typedef struct CvConnectedComponent {
    double area;            // พื้นที่ของ component
    CvScalar value;       // สีเฉลี่ยของพื้นที่นั้น
    CvRect rect;           // กรอบสี่เหลี่ยมรอบ component นั้น
    CvSeq* contour;    // ในฟังก์ชัน cvPyrSegmentation ไม่ได้เซต แต่หมายถึง sequence ของ contour(ไว้อธิบายในเรื่อง contour)
};

ลองมาดูตัวอย่างเพื่อความเข้าใจในการ segmentation ด้วย cyPyrSegmentation 

CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* comp = NULL;
cvPyrSegmentation( src, dst, storage, &comp, 4, 200, 50 );
int n_comp = comp->total;
for( int i=0; i
     CvConnectedComp* cc = (CvConnectedComp*) cvGetSeqElem( comp, i );
do_something_with( cc );

cvReleaseMemStorage( &storage );


จากโคด เราจะได้ sequence ของ connected component ซึ่งส่งต่อให้ฟังก์ชัน do_something_with

Learning OpenCV: more about image segmentation in OpenCV

ต่อจากเรื่อง image morphology ยังมีเรื่องค้างอีกนิดหน่อยเีกี่ยวกับการ segment ข้อมูล
เรื่องการคือการทำ Flood Fill แนวคิดของ flood fill นี้อาจจะเคยเห็นกันมาแล้วบ้างจากโปรแกรมแต่งรูปต่างๆ
คือจะมีเลือกจุดในรูปภาพ (seed point) แล้วทั้ง seed point และจุดรอบข้างที่มีสีเหมือนกัน(หรือใกล้เคียงกันตามกำหนด) จะถูกแทนที่ด้วยสีที่กำหนด และประเด็นคืออะไร จริงๆ แล้วประเด็นสำคัญคือ ผลที่ได้จาก flood ่่fill operation นั้นจะเป็นพื้นที่ๆ ต่อเนื่องกันพื้นที่หนึ่ง เรียกได้ว่าเป็นการ segment ด้วยสี ลองดูการประกาศฟังก์ชัน


void cvFloodFill(
    IplImage* img,
    CvPoint seedPoint,
    CvScalar newVal,
    CvScalar loDiff = cvScalarAll(0),
    CvScalar upDiff = cvScalarAll(0),
    CvConnectedComp* comp = NULL,
    int flags = 4,
    CvArr* mask = NULL
);

พารามิเตอร์จะเป็น img รูปภาพที่จะ fill, seedPoint คือตำแหน่ง seed point  newVal คือสีที่จะ fill loDiff กับ upDiff คือผลต่างค่าที่จะยอมรับได้ที่จะต้องแทนที่สี(หรือว่าเป็นพื้้นที่เดียวกันนั่นเอง) ปกติผลต่างนัั้นจะคำนวณระหว่าง pixel ที่ติดกันยกเว้นถ้ามี flag CV_FLOODFILL_FIXED_RANGE จะคำนวณผลต่างจาก seed point เท่านั้น

CvConnectedComp จะเก็บข้อมูลสถิติเกี่ยวกับพื้นที่ๆ ถูก fill จะยกยอดไปอธิบายในเรื่อง Image Pyramids


mask ถ้ากำหนดจะต้องมีขนาด 1 channel และขนาดกว้างและยาวกว่า img (เพื่อการคำนวณ filter ภายใน) โดย pixel (x+1,y+1) ใน mask จะ map กับ x,y ใน img โดยการทำงาน Flood Fill จะ fill img เฉพาะในส่วนที่ mask ตรงตำแหน่งเป็น 0 
ผลการ Flood Fill สามารถ กำหนดให้ fill ทั้ง  img และ mask หรือ fill เฉพาะ mask อย่างเดียวก็ได้


flag จะประกอบด้วยข้อมูลสามส่วน
        แปดบิทล่าง จะมีค่าเป็น 4,8 ใช้กำหนดทิศทางในการ fill โดย 4 จะเป็นการ fill เฉพาะแนวตั้งและแนวนอนและ 8 จะ fill รอบด้านทั้งแปดทิศ
        แปดบิทกลาง จะกำหนดว่า mask จะถูกกำหนดว่า mask จะถูก fill ด้วยค่าอะไรถ้า set เป็น 0 จะถูก fill ด้วยค่า 1s(127)
        แปดบิดบน จะเป็นการเซตค่า CV_FLOODFILL_FIXED_RANGE (ที่อธิบายไปแล้ว) และ CV_FLOODFILL_MASK_ONLY fill เฉพาะ mask เท่านั้น

ลองยกตัวอย่าง flag ถ้าเราต้องการให้  fill ทั้งแปดทิศ, fill เฉพาะ mask, fill mask ด้วยค่า 47

flag = 8 | CV_FLOODFILL_MASK_ONLY | CV_FLOODFILL_FIXED_RANGE | (47<<8)

(น่าจะไม่มีปัญหา bitwise or และ shift bit ธรรมดา)