今天想在OpenCV中实现鼠标在图像中移动时以鼠标为中心固定大小区域的放大显示,就像在淘宝中鼠标移动到宝贝图片上的效果。这样的例子有很多,我就想自己实现该功能,于是写了如下代码:
const char *window_original="original";
const char *window_test="test";
CvPoint p_start,p_end;
const int band=60;
IplImage *img=NULL;
IplImage *temp=NULL;
void mouse_callback(int event,int x,int y,int flags,void* param)
{
IplImage *img_resize=cvCreateImage(cvSize(200,200),IPL_DEPTH_8U,3);
temp=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCopyImage(img,temp);
CvPoint p_start,p_end;
switch(event)
{
case CV_EVENT_MOUSEMOVE:
if(x-band/2<0)
{
if(y-band/2<0)
{
p_start=cvPoint(0,0);
p_end=cvPoint(x+band/2,y+band/2);
}
else if(y+band/2>temp->height)
{
p_start=cvPoint(0,y-band/2);
p_end=cvPoint(x+band/2,temp->height);
}
else
{
p_start=cvPoint(0,y-band/2);
p_end=cvPoint(x+band/2,y+band/2);
}
}
else if(x+band/2>temp->width)
{
if(y-band/2<0)
{
p_start=cvPoint(x-band/2,0);
p_end=cvPoint(temp->width,y+band/2);
}
else if(y+band/2>temp->height)
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(temp->width,temp->height);
}
else
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(temp->width,y+band/2);
}
}
else
{
if(y-band/2<0)
{
p_start=cvPoint(x-band/2,0);
p_end=cvPoint(x+band/2,y+band/2);
}
else if(y>temp->height-band/2)
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(x+band/2,temp->height);
}
else
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(x+band/2,y+band/2);
}
}
cvRectangle(temp,p_start,p_end,cvScalar(0x00,0xff,0x00));
cvShowImage(window_original,temp);
cvSetImageROI(temp,cvRect(MIN(p_start.x,p_end.x),MIN(p_start.y,p_end.y),CV_IABS(p_start.x-p_end.x),CV_IABS(p_start.y-p_end.y)));
cvResize(temp,img_resize);
cvShowImage(window_test,img_resize);
cvResetImageROI(temp);
cvReleaseImage(&img_resize);
break;
}
}
int main(int argc, char* argv[])
{
img=cvLoadImage("E:/opencv_project/console/Debug/Lena.jpg");
cvNamedWindow(window_original,CV_WINDOW_AUTOSIZE);
cvNamedWindow(window_test,CV_WINDOW_AUTOSIZE);
cvShowImage(window_original,img);
cvSetMouseCallback(window_original,mouse_callback,0);
while(1)
{
if(cvWaitKey(15)==27)
break;
}
cvDestroyAllWindows();
cvReleaseImage(&img);
cvReleaseImage(&temp);
return 0;
}
结果,功能正常,但是运行一段时间后就报cv::exception错误。打开任务管理一看,鼠标移动后程序所占用的内存几乎是直线上升。经过一段时间的查找后发现,程序问题在以下部分:
IplImage *img_resize=cvCreateImage(cvSize(200,200),IPL_DEPTH_8U,3);
temp=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
以上两句代码在回调函数中为变量分配空间,每次调用回调函数都会分配空间并且不能释放,导致内存泄露。解决方法是将img_resize定义为全局变量,并且变量初始化放在main函数中,如下所示:
const char *window_original="original";
const char *window_test="test";
CvPoint p_start,p_end;
const int band=60;
IplImage *img=NULL;
IplImage *temp=NULL;
IplImage *img_resize=NULL;
void mouse_callback(int event,int x,int y,int flags,void* param)
{
//IplImage *img_resize=cvCreateImage(cvSize(200,200),IPL_DEPTH_8U,3);
//temp=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCopyImage(img,temp);
CvPoint p_start,p_end;
switch(event)
{
case CV_EVENT_MOUSEMOVE:
if(x-band/2<0)
{
if(y-band/2<0)
{
p_start=cvPoint(0,0);
p_end=cvPoint(x+band/2,y+band/2);
}
else if(y+band/2>temp->height)
{
p_start=cvPoint(0,y-band/2);
p_end=cvPoint(x+band/2,temp->height);
}
else
{
p_start=cvPoint(0,y-band/2);
p_end=cvPoint(x+band/2,y+band/2);
}
}
else if(x+band/2>temp->width)
{
if(y-band/2<0)
{
p_start=cvPoint(x-band/2,0);
p_end=cvPoint(temp->width,y+band/2);
}
else if(y+band/2>temp->height)
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(temp->width,temp->height);
}
else
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(temp->width,y+band/2);
}
}
else
{
if(y-band/2<0)
{
p_start=cvPoint(x-band/2,0);
p_end=cvPoint(x+band/2,y+band/2);
}
else if(y>temp->height-band/2)
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(x+band/2,temp->height);
}
else
{
p_start=cvPoint(x-band/2,y-band/2);
p_end=cvPoint(x+band/2,y+band/2);
}
}
cvRectangle(temp,p_start,p_end,cvScalar(0x00,0xff,0x00));
cvShowImage(window_original,temp);
cvSetImageROI(temp,cvRect(MIN(p_start.x,p_end.x),MIN(p_start.y,p_end.y),CV_IABS(p_start.x-p_end.x),CV_IABS(p_start.y-p_end.y)));
cvResize(temp,img_resize);
cvShowImage(window_test,img_resize);
cvResetImageROI(temp);
break;
}
}
int main(int argc, char* argv[])
{
img=cvLoadImage("E:/opencv_project/console/Debug/Lena.jpg");
temp=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
img_resize=cvCreateImage(cvSize(200,200),IPL_DEPTH_8U,3);
cvNamedWindow(window_original,CV_WINDOW_AUTOSIZE);
cvNamedWindow(window_test,CV_WINDOW_AUTOSIZE);
cvShowImage(window_original,img);
cvSetMouseCallback(window_original,mouse_callback,0);
while(1)
{
if(cvWaitKey(15)==27)
break;
}
cvDestroyAllWindows();
cvReleaseImage(&img);
cvReleaseImage(&temp);
return 0;
}
重新运行程序,以上问题解决。