我们有时候希望对图像的某个小部分进行操作,而不是对整个图像进行运算。有两种方法,ROI和widthStep。
1. ROI
设置一个ROI区域使用cvSetImageROI,取消一个ROI使用cvResetImageROI。函数原型分别如下:
void cvSetImageROI( IplImage* image, CvRect rect );
void cvResetImageROI( IplImage* image );
rect就是我们要操作的图像的某个区域。实例如下:
#include <cv.h>
#include <highgui.h>
int main(int argc, char* argv[])
{
IplImage* src;
CvRect rect = cvRect(70, 70, 50, 50);
if (argc == 2 && ((src = cvLoadImage(argv[1], 1)) != NULL)) {
cvSetImageROI(src, rect);
cvAddS(src, cvScalar(50), src);
cvResetImageROI(src);
cvNamedWindow("roi_add", CV_WINDOW_AUTOSIZE);
cvShowImage("roi_add", src);
cvWaitKey();
cvReleaseImage(&src);
cvDestroyWindow("roi_add");
}
return 0;
}
这里我们将ROI区域的灰度值增加50。
2. widthStep
有了ROI,为什么还需要使用widthStep。ROI只能串行的处理,需要不断设置和重置,而使用widthStep可以连续的操作多个子区域。实例如下:
#include <cv.h>
#include <highgui.h>
int main(int argc, char* argv[])
{
IplImage* src;
CvRect rect = cvRect(100, 20, 50, 50);
if (argc == 2 && ((src = cvLoadImage(argv[1], 1)) != NULL)) {
IplImage* sub_img = cvCreateImageHeader(cvSize(rect.width, rect.height),
src->depth, src->nChannels);
sub_img->origin = src->origin;
sub_img->widthStep = src->widthStep;
sub_img->imageData = src->imageData +
rect.y * src->widthStep +
rect.x * src->nChannels;
cvAddS(sub_img, cvScalar(50), sub_img);
cvNamedWindow("sub_add", CV_WINDOW_AUTOSIZE);
cvShowImage("sub_add", src);
cvWaitKey();
cvReleaseImageHeader(&sub_img);
cvDestroyWindow("sub_add");
cvReleaseImage(&src);
}
return 0;}
注意:
在这里我们只创建了一个子图像的头,它的数据域在原图像中。我们通过widthStep来操作原图像的数据,从而达到修改原图像子区域的操作。
子图像的widhtStep等于原图像的widthStep,因为操作了一行后,欲操作下一行,必须将数据域指针加上widthStep。