正在做一個(gè)基于內(nèi)容的圖像檢索項(xiàng)目,客戶要求可以讓用戶提取圖片上的任意形狀的子圖作為輸入。為了實(shí)現(xiàn)這個(gè)功能,花了不少精力,中間繞了不少圈子?,F(xiàn)在問(wèn)題總算解決了,把主要的思路記錄一下,希望能幫到有同樣需求的朋友。 由于這個(gè)項(xiàng)目使用了第三方的開(kāi)源圖像庫(kù)opencv,所以這個(gè)功能也是借助opencv來(lái)實(shí)現(xiàn)的。 首先需要解決的是在圖片中繪制曲線的問(wèn)題,思路很簡(jiǎn)單,只需要響應(yīng)鼠標(biāo)事件通過(guò)描點(diǎn)、連線的方式就可以完成。在opencv中需要使用回調(diào)來(lái)響應(yīng)鼠標(biāo)事件,opencv中文站上有很好的示例,關(guān)鍵代碼: ![]() #include "cv.h" #include "highgui.h" #include <stdio.h> #include <stdlib.h> IplImage* inpaint_mask = 0; IplImage* img0 = 0, *img = 0, *inpainted = 0; CvPoint prev_pt = {-1,-1}; void on_mouse( int event, int x, int y, int flags, void* zhang) { if( !img ) return; if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) ) prev_pt = cvPoint(-1,-1); else if( event == CV_EVENT_LBUTTONDOWN ) prev_pt = cvPoint(x,y); else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) ) { CvPoint pt = cvPoint(x,y); if( prev_pt.x < 0 ) prev_pt = pt; cvLine( inpaint_mask, prev_pt, pt, cvScalarAll(255), 5, 8, 0 ); cvLine( img, prev_pt, pt, cvScalarAll(255), 5, 8, 0 ); prev_pt = pt; cvShowImage( "image", img ); } } int main( int argc, char** argv ) { char* filename = argc >= 2 ? argv[1] : (char*)"fruits.jpg"; if( (img0 = cvLoadImage(filename,-1)) == 0 ) return 0; printf( "Hot keys: \n" cvNamedWindow( "image", 1 ); img = cvCloneImage( img0 ); inpainted = cvCloneImage( img0 ); inpaint_mask = cvCreateImage( cvGetSize(img), 8, 1 ); cvZero( inpaint_mask ); cvZero( inpainted ); cvShowImage( "image", img ); cvShowImage( "watershed transform", inpainted ); cvSetMouseCallback( "image", on_mouse, 0 ); } 第二步,利用封閉曲線提取圖形,時(shí)間和精力都主要浪費(fèi)在這一塊了,最開(kāi)始的想法是通過(guò)掃描線的方法獲取,但最終做出來(lái)的效果差強(qiáng)人意,連自己這關(guān)都過(guò)不了。最后幾經(jīng)轉(zhuǎn)折,找到了這樣一個(gè)函數(shù)cvFloodFill(),這個(gè)函數(shù)可根據(jù)邊界填充圖像連通域,正是我所需要的。關(guān)鍵代碼: ![]() if(event == CV_EVENT_RBUTTONUP) { cvFloodFill(maskImg,cvPoint(x,y),cvScalarAll(255)); cvSaveImage("maskImg.bmp",maskImg); IplImage *segImage=cvCreateImage(cvGetSize(img),8,3);; cvCopy(img,segImage,maskImg); cvSaveImage("segImage.bmp",segImage); cvCopy(segImage,proc->img); cvReleaseImage(&segImage); cvDestroyWindow("Key Image"); }
效果如下: |
|