天天看點

openCV 滑鼠框選并顯示框選區域

cvSetImageROI函數(基于給定的矩形設定圖像的ROI(感興趣區域,region of interesting))

void cvSetImageROI(IplImage* image,CvRect rect) 參數: image 圖像頭,待處理圖像 rect ROI 感興趣區域矩形   cvResetImageROI函數(釋放基于給定的矩形設定圖像的ROI(感興趣區域,region of interesting)) void cvResetImageROI(IplImage* image) 參數: image 圖像頭,待處理圖像   cvcop函數(拷貝一個數組給另一個數組) 在使用這個函數之前,你必須用cvCreateImage()一類的函數先開一段記憶體,然後傳遞給dst。cvCopy會把src中的資料複制到dst的記憶體中。 copy隻會複制ROI區域,相當于函數cvCopy從輸入數組中複制標明的成分到輸出數組。 void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL ); 參數: src  輸入數組 dst  輸出數組 mask  操作掩碼是8比特單通道的數組,它指定了輸出數組中被改變的元素   cvCloneImage函數(複制圖像資料) 在使用函數之前,不用開辟記憶體。該函數會自己開一段記憶體,然後複制好image裡面的資料,然後把這段記憶體中的資料傳回給你。

clone是把所有的都複制過來,也就是說不論你是否設定Roi,Coi等影響copy的參數,clone都會原封不動的克隆過來。 IplImage* cvCloneImage( const IplImage* image ); 參數:image 輸入源圖像資料 傳回值: IplImage*  輸出圖像指針 注意:使用cvCloneImage()容易造成記憶體洩露,是以慎用。

cvCloneImage()每次使用時編譯器會配置設定新的記憶體空間,不會覆寫以前的内容,是以如果在循環中使用記憶體會迅速減小,每次用完都需要用cvRelease來釋放。

解決方法是使用cvCopy函數代替。

 源代碼:

#include <cv.h>
#include <highgui.h>
#include <stdio.h>

IplImage* src = 0; 
IplImage* tmp = 0; 
IplImage* tmp1 = 0;
IplImage* org = 0;
void on_mouse( int event, int x, int y, int flags, void* ustc)
{
	static CvPoint pre_pt = {-1,-1};
	static CvPoint cur_pt = {-1,-1};
	CvFont font;
	cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA);//初始化字型
	char temp[16];
	
	if( (event == CV_EVENT_LBUTTONDOWN)&&(flags) )//滑鼠左鍵按下時
	{ 
		sprintf(temp,"(%d,%d)",x,y);//格式化字元串
		pre_pt = cvPoint(x,y);//擷取目前點坐标值
		cvPutText(src,temp, pre_pt, &font, cvScalar(0,0, 0, 255));//在圖像是列印字元
		cvCircle( src, pre_pt, 2,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );//在圖像上畫圓
		cvShowImage( "src", src );
		//cvCopy(src,tmp);//這句有沒有,就是單目标和多目标的問題
	}
	else if( (event == CV_EVENT_MOUSEMOVE) && (flags & CV_EVENT_LBUTTONDOWN))
	{//滑鼠移動并且滑鼠左鍵按下
		sprintf(temp,"(%d,%d)",x,y);//格式化字元串
		cur_pt = cvPoint(x,y);//擷取目前點坐标值		
		cvPutText(src,temp, cur_pt, &font, cvScalar(0,0, 0, 255));//在圖像是列印字元
		cvRectangle(src, pre_pt, cur_pt, cvScalar(0,255,0,0), 2, 8, 0 );//在圖像上畫矩形
		cvShowImage( "src", src );
		cvCopy(tmp,src);//将img複制到臨時圖像tmp上,用于實時顯示
	}
	else if( event == CV_EVENT_LBUTTONUP )
	{//滑鼠左鍵彈起
		sprintf(temp,"(%d,%d)",x,y);//字型格式化
		cur_pt = cvPoint(x,y);//擷取目前點坐标值		
		cvPutText(src,temp, cur_pt, &font, cvScalar(0,0, 0, 255));//在圖像是列印字元
		cvCircle( src, cur_pt, 2,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 );//在圖像上畫圓
		cvRectangle( src, pre_pt, cur_pt, cvScalar(0,255,0,0), 2, 8, 0 );//在圖像上畫矩形
		cvShowImage( "src", src );

		/******************************************************************/
		int width=abs(pre_pt.x-cur_pt.x); //兩點橫坐标差 
        int height=abs(pre_pt.y-cur_pt.y); //兩點縱坐标差 
        if(width==0 || height==0)  
        {  //兩者中有一個為零時銷毀視窗
            cvDestroyWindow("dst");  
            return;  
        }  
        tmp1 = cvCreateImage(cvSize(width,height),org->depth,org->nChannels);  
        CvRect rect;  
        if(pre_pt.x<cur_pt.x && pre_pt.y<cur_pt.y)  
        {  
            rect=cvRect(pre_pt.x,pre_pt.y,width,height);  
        }  
        else if(pre_pt.x>cur_pt.x && pre_pt.y<cur_pt.y)  
        {  
            rect=cvRect(cur_pt.x,pre_pt.y,width,height);  
        }  
        else if(pre_pt.x>cur_pt.x && pre_pt.y>cur_pt.y)  
        {  
            rect=cvRect(cur_pt.x,cur_pt.y,width,height);  
        }  
        else if(pre_pt.x<cur_pt.x && pre_pt.y>cur_pt.y)  
        {  
            rect=cvRect(pre_pt.x,cur_pt.y,width,height);  
        }  
        cvSetImageROI(org,rect);//設定圖像的感興趣區域  
        cvCopy(org,tmp1); //将感興趣區域複制到tmp1 
        cvResetImageROI(org);//釋放圖像的感興趣區域  
        cvDestroyWindow("dst");//銷毀上次的顯示圖像  
        cvNamedWindow("dst",1);//建立視窗  
        cvShowImage("dst",tmp1); //顯示感興趣的圖像 
        cvSaveImage("dst.jpg",tmp1); //儲存感興趣圖像 
/******************************************************************/
	}
}
int main()
{
	src=cvLoadImage("lena.jpg",1);//讀入圖像
	tmp=cvCloneImage(src);//複制圖像到臨時圖像上 
	org=cvCloneImage(src);//儲存原始圖像 
	cvNamedWindow("src",1);//建立視窗
	cvSetMouseCallback( "src", on_mouse, 0 );//注冊滑鼠響應回調函數
	
	cvShowImage("src",src);//顯示圖像
	cvWaitKey(0);//等待按鍵按下 
	cvDestroyAllWindows();//銷毀所有視窗
	cvReleaseImage(&src);//釋放圖像
	cvReleaseImage(&tmp);//釋放圖像
	return 0;
}
           

效果圖:

openCV 滑鼠框選并顯示框選區域