[转]OpenCV鼠标交互 (原文链接已失效 ) 绘制任意形状并获得区域图像:原理同上,使用CvSeq记录轨迹点,然后用cvFillConvexPoly填充多边形区域形成掩模,最后用cvCopy拷贝区域图像。支持两种绘图模式,描点式(如PS之钢笔)和拖动式:
#include <opencv2\opencv.hpp>
#include <opencv\cxcore.h>
#include <opencv\highgui.h>
#include <opencv\cv.h>
#include <iostream>
using namespace std ;
using namespace cv;
struct MouseArgs{
IplImage* img;
CvPoint p_start;
CvPoint p_end;
CvSeq* seq;
CvMemStorage* storage;
int points;
MouseArgs() :img(0 ), points(0 ){
p_start = cvPoint(-1 , -1 );
p_end = cvPoint(-1 , -1 );
storage = cvCreateMemStorage(0 );
seq = cvCreateSeq(CV_32SC2, sizeof (CvSeq), sizeof (CvPoint), storage);
}
void Destroy(){
if (!img)
cvReleaseImage(&img);
cvReleaseMemStorage(&storage);
seq = NULL;
img = NULL;
}
};
void MouseDraw(int event, int x, int y, int flags, void *param);
int main(int argc, char ** argv)
{
char * imf = argc >= 2 ? argv[1 ] : "test.png" ;
IplImage* pImg_org = cvLoadImage(imf, 1 );
if (!pImg_org){
cout << "cann't load image!" << endl;
return -1 ;
}
MouseArgs* m_arg = new MouseArgs();
m_arg->img = cvCloneImage(pImg_org);
cvNamedWindow("Draw ROI" , CV_WINDOW_AUTOSIZE);
cvSetMouseCallback("Draw ROI" ,
MouseDraw,
(void *)m_arg);
while (1 )
{
cvShowImage("Draw ROI" , m_arg->img);
if (cvWaitKey(100 ) == 27 )
break ;
}
if (m_arg->points < 1 )
return 0 ;
cout << m_arg->points << endl;
for (int i = 0 ; i < m_arg->points; i++){
CvPoint line = *CV_GET_SEQ_ELEM(CvPoint, m_arg->seq, i);
cout << line.x << "," << line.y << "; " ;
}
IplImage* mask = cvCreateImage(cvGetSize(pImg_org), 8 , 1 );
cvZero(mask);
CvPoint* PointArr = new CvPoint[m_arg->points];
cvCvtSeqToArray(m_arg->seq, PointArr);
cvFillConvexPoly(mask, PointArr, m_arg->points, cvScalarAll(255 ), CV_AA, 0 );
delete [] PointArr;
cvNamedWindow("Mask" , CV_WINDOW_AUTOSIZE);
cvShowImage("Mask" , mask);
IplImage* roi = cvCreateImage(cvGetSize(pImg_org), 8 , 3 );
cvCopy(pImg_org, roi, mask);
cvNamedWindow("ROI" , CV_WINDOW_AUTOSIZE);
cvShowImage("ROI" , roi);
cvWaitKey(0 );
cvDestroyWindow("Draw ROI" );
cvDestroyWindow("Mask" );
cvDestroyWindow("ROI" );
m_arg->Destroy();
delete m_arg;
cvReleaseImage(&pImg_org);
cvReleaseImage(&mask);
cvReleaseImage(&roi);
getchar();
return 0 ;
}
void MouseDraw(int event, int x, int y, int flags, void *param)
{
MouseArgs* m_arg = (MouseArgs*)param;
if (!m_arg->img)
return ;
if (event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON))
{
m_arg->p_start = cvPoint(x, y);
}
else if (event == CV_EVENT_LBUTTONDOWN)
{
m_arg->p_start = cvPoint(x, y);
cvSeqPush(m_arg->seq, &m_arg->p_start);
m_arg->points += 1 ;
if (m_arg->p_start.x>0 && m_arg->p_end.x>0 ){
cvLine(m_arg->img, m_arg->p_start, m_arg->p_start, cvScalar(128 , 0 , 255 ));
}
}
else if (event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON))
{
CvPoint pt = cvPoint(x, y);
if (m_arg->p_start.x > 0 ){
cvLine(m_arg->img, m_arg->p_start, pt, cvScalar(128 , 0 , 255 ));
m_arg->p_start = pt;
cvSeqPush(m_arg->seq, &m_arg->p_start);
m_arg->points += 1 ;
}
}
}
CvPoint* point = new CvPoint[length ];
int i;
for (i = 0 ; i < length ; i++)
point [i]=*CV_GET_SEQ_ELEM(CvPoint,contours,i);
CvMemStorage* storage1 = cvCreateMemStorage(0 );
CvSeq* seq = cvCreateSeq( CV_32SC2,
sizeof(CvSeq),
sizeof(CvPoint),
storage1 );
for ( i = 0 ; i
cvSeqPush( seq,&point [i]);