1,Opencv中的ROI介绍

ROI(Region of Interest)是指图像中的一个矩形区域,可能你后续的程序需要单独处理这一个小区域,如图所示



如上图所示,就是ROI的一个例子,如果你对图像设置了ROI,那么,Opencv的大多数函数只在该ROI区域内运算(只处理该ROI区域),如果没设ROI的话,就会出来整幅图像。
ROI非常有用,例如我们想把图像中的人脸扣出来,进行人脸识别。需要注意的时候,ROI一定在图像内部,而不能超出图像的范围。


对图像设定ROI的函数是:


cvSetImageROI(IplImage* src,CvRect rect);
src表示的是源图像,rect只的是ROI区域。


如果要取消ROI区域,那么使用函数:


cvResetImageROI(IplImage* src);
这个函数,就把src上的ROI区域取消掉。


下面举几个例子:


例子1:
从一幅大图像中,取出一小块图像并保存这一个小块图像。
代码如下:

/* 读取大图像 */ 

IplImage *img1 = cvLoadImage("elvita.jpg", 1); 

 

/* 设置图像的ROI区域 

   注意ROI区域不要越界,必须在大图像的内部 */ 

cvSetImageROI(img1, cvRect(10, 15, 150, 250)); 

 

/* 为小图像分配内存空间 

   cvGetSize(img1)返回的是一个CvSize结构体,意思就是返回了图像img1的宽度和高度,由于 

img已经设置了ROI,所以cvGetSize函数对ROI区域有效,所以,返回的是ROI区域的宽度和高度 */ 

IplImage *img2 = cvCreateImage(cvGetSize(img1), 

                               img1->depth, 

                               img1->nChannels); 

 

/* 把img1的ROI区域拷贝到img2*/ 

cvCopy(img1, img2, NULL); 

 

/* 取消img1上的ROI区域 */ 

cvResetImageROI(img1);



例子2:
两幅不同大小的图像相加

/* 加载图像 
   注意,这两幅图像有不同的宽度和高度 */ 
IplImage *img1 = cvLoadImage("elvita.jpg", 1);  /* 大图像  */ 
IplImage *img2 = cvLoadImage("fifi.jpg", 1);    /* 较小的图像*/ 
 
/* 定义ROI区域的坐标*/ 
CvRect rect = cvRect(25, 25, img2->width, img2->height); 
 
/* 对图像img1设置ROI1区域 */ 
cvSetImageROI(img1, rect); 
 
/* 两幅图像相加 
   注意,通过对img1设置ROI区域后,两幅图像,其实有相同的宽度和高度了。 */ 
cvAdd(img1, img2, img1, NULL); 
 
/* 取消感兴趣区域,即ROI区域*/ 
cvResetImageROI(img1);






例子3:在一个特定区域进行模板匹配 ( 关于模板匹配的完整代码下载 )

IplImage *src = cvLoadImage("myphoto.jpg", 1); 
IplImage *template = cvLoadImage("eye.jpg", 1); 
 
CvRect rect = cvRect(25, 25, 120, 120); 
 
//设置ROI区域 
cvSetImageROI(src, rect); 
 
IplImage *result = cvCreateImage(cvSize(rect.width  - tpl->width  + 1, 
                                     rect.height - tpl->height + 1), 
                              IPL_DEPTH_32F, 1); 
 
/* 进行模板匹配 */ 
cvMatchTemplate(src, template, result, CV_TM_SQDIFF); 
 
/* 查找最匹配的坐标 */ 
CvPoint    minlocation, maxlocation; 
double    minvalue, maxvalue; 
cvMinMaxLoc(result, &minvalue, &maxvalue, &minlocation, &maxlocation, 0); 
 
/* 在源图像上画出矩形*/ 
cvRectangle(src, 
            cvPoint(minlocation.x, minlocationc.y), 
            cvPoint(minlocation.x + template->width, minlocationc.y + template->height), 
            CV_RGB(255, 0, 0), 1, 0, 0 ); 
 
cvResetImageROI(src);




在上面的例子中,先定义ROI区域,再进行模板匹配,这样会加快匹配的速度,因为,只在ROI区域进行模板匹配运算。


例子4:ROI区域像素值的访问
可以想把ROI区域拷贝到一幅新的图像中,然后再访问其像素值

/* 假设已经有了一幅 8-bit 3通道图像*/ 


 

/* ROI的坐标*/ 

CvRect rect = cvRect(10, 20, 50, 60); 


 

/* ROI区域的子图像 */ 

IplImage* subimg; 


 

/* 设置ROI区域 */ 

cvSetImageROI(img, rect); 


 

//ROI区域拷贝 

cvCopy(img, subimg, NULL); 


 

//释放ROI区域 

cvResetImageROI(img); 


 

/* 然后,就可以对subimg进行访问,其实就是访问ROI区域 */

或者可以通过ROI的左边信息进行访问

/* ROI区域的坐标 */ 
CvRect rect = cvRect(10, 20, 50, 60); 
 
//设置ROI区域 
cvSetImageROI(img, rect); 
 
/* 假设,把整个ROI区域赋值为0 */ 
for (i = rect.y; i < (rect.y + rect.height); i++) { 
    for (j = rect.x; j < (rect.x + rect.width); j++) { 
        ((uchar*)(img->imageData + i * img->widthStep))[j*3] = 0; 
        ((uchar*)(img->imageData + i * img->widthStep))[j*3+1] = 0; 
        ((uchar*)(img->imageData + i * img->widthStep))[j*3+2] = 0; 
    } 

}




用截取的部分图像创建新图像--关于cvGetSubRect,cvGetImage的用法  

不需要分配数据存储空间);rect是要截取的区域;返回指向所存矩阵。
例如:

CvMat *pMat = cvCreateMatHeader(100, 100, CV_8UC1);  //创建一个100*100的矩阵头 
 
   CvRect rect = cvRect(0, 0, 100, 100);  //要截取的区域,与创建的矩阵大小一样 
 
   cvGetSubRect(pImg, pMat, rect);  //pImg为指向图像的指针,pMat指向存储所接图像的矩阵,返回值和pMat相等

也可以简化为:

  CvMat *pMat = cvGetSubRect(pImg, cvCreateMatHeader(100, 100, CV_8UC1), cvRect(0, 0, 100, 100));

  IplImage* cvGetImage( const CvArr* arr, IplImage* image_header )可以把刚才存入矩阵的数据转存为图像。把CvMat *传给arr;image_header

只需为图像头就行,不用分配数据存储空间 ;返回所存图像的指针。

例如:

  IplImage *pSubImg = cvCreateImageHeader(cvSize(100, 100), 8, 1);  //创建一个100*100的图像头

  cvGetImage(pMat, pSubImg); //pMat为存储数据的矩阵,pSubImg指向图像,返回值与pSubImg相等

也可以简化为:

  IplImage *pSubImg = cvGetImage(pMat, cvCreateImageHeader(cvSize(100, 100), 8, 1));

截取子图最后简化为:

  IplImage *pSubImg = cvGetImage(cvGetSubRect(pImg, cvCreateMatHeader(100, 100, CV_8UC1), cvRect(0, 0, 100, 100)), cvCreateImageHeader(cvSize(100, 100), 8, 1));  //好乱...读明白这句费劲儿