如何在OpenCV中裁剪CvMat?

74

我有一张图片被转换成了一个CvMat矩阵,比如说CVMat源代码。一旦我从源代码中获得感兴趣的区域,我希望剩下的算法只应用于那个感兴趣的区域。为此,我认为我将不得不对我无法做到的源矩阵进行裁剪。是否有一种方法或函数可以裁剪一个CvMat矩阵并返回另一个裁剪后的CvMat矩阵?谢谢。


1
你想要使用早期的C风格还是后期的C++风格?请根据你的答案重新标记你的问题。 - Boaz
6个回答

158

OpenCV有感兴趣区域函数,你可能会发现它很有用。如果你正在使用cv::Mat,那么你可以使用以下方式:

// You mention that you start with a CVMat* imagesource
CVMat * imagesource;

// Transform it into the C++ cv::Mat format
cv::Mat image(imagesource); 

// Setup a rectangle to define your region of interest
cv::Rect myROI(10, 10, 100, 100);

// Crop the full image to that image contained by the rectangle myROI
// Note that this doesn't copy the data
cv::Mat croppedImage = image(myROI);

提取子图的文档


6
你的意思是这个不能复制数据? - Jameo
7
这意味着它仅创建对该图像区域的引用,而不是副本。这意味着,如果您更改了被裁剪的图像(croppedImage),原始图像(imagesource)也会发生变化。如果您不希望出现这种行为,可以显式地创建一个副本。 - Rui Marques
如果我想要一个椭圆形区域而不是矩形区域作为感兴趣的区域,该怎么办? - Sohaib
2
@Sohaib 然后我们需要使用所谓的“掩码”,通常作为处理函数的额外参数提供。 - Samuel Audet
2
如果我调用 image.release()croppedImage 会发生什么? - dashesy
显示剩余4条评论

50

我知道这个问题已经被解决了...但是有一个非常简单的方法可以裁剪。你只需要在一行中完成它-

Mat cropedImage = fullImage(Rect(X,Y,Width,Height));

3
fullImage() 函数是从哪获取的?编辑:不用管,它就是 cv::Mat 图像本身... - mozzbozz
1
简单而有效! - MsLate
1
上面说这不是复制内容,只是一个引用。这是真的吗? - KansaiRobot

25
为了获得更好的结果并增强对不同类型矩阵的鲁棒性,除了第一个答案中的方法外,您还可以进行以下操作:复制数据。
cv::Mat source = getYourSource();

// Setup a rectangle to define your region of interest
cv::Rect myROI(10, 10, 100, 100);

// Crop the full image to that image contained by the rectangle myROI
// Note that this doesn't copy the data
cv::Mat croppedRef(source, myROI);

cv::Mat cropped;
// Copy the data into new matrix
croppedRef.copyTo(cropped);

11

为了创建我们想要的作物的副本,我们可以执行以下操作:

// Read img
cv::Mat img = cv::imread("imgFileName");
cv::Mat croppedImg;

// This line picks out the rectangle from the image
// and copies to a new Mat
img(cv::Rect(xMin,yMin,xMax-xMin,yMax-yMin)).copyTo(croppedImg);

// Display diff
cv::imshow( "Original Image",  img );
cv::imshow( "Cropped Image",  croppedImg);
cv::waitKey();

1
这对已经提供的答案没有任何添加。而且你缺少了一个分号和错误的变量名。顺便说一下,你可以使用 Mat crop = img(Rect(...)).clone() 来完成这个任务。 - Miki
修正了拼写错误。我认为它的优点在于可以一行完成所有操作。至于克隆或复制到,在这种情况下,我想只是个人偏好。 - Reed Richards

1
我明白这个问题已经得到了回答,但也许这对某些人有用...如果您希望将数据复制到单独的cv :: Mat对象中,您可以使用类似于此的函数:
void ExtractROI(Mat& inImage, Mat& outImage, Rect roi){
    /* Create the image */
    outImage = Mat(roi.height, roi.width, inImage.type(), Scalar(0));

    /* Populate the image */
    for (int i = roi.y; i < (roi.y+roi.height); i++){
        uchar* inP = inImage.ptr<uchar>(i);
        uchar* outP = outImage.ptr<uchar>(i-roi.y);
        for (int j = roi.x; j < (roi.x+roi.width); j++){
            outP[j-roi.x] = inP[j];
        }
    }
}

需要注意的是,这只适用于单通道图像

这对我帮助很大。我创建了一个版本,可以从每像素16位的图像中提取感兴趣区域(ROIs)。https://gist.github.com/fernandoc1/e69e4c09d0bf4b09076af40c06b13450 - Fernando

-4

使用OpenCV函数可以轻松地裁剪Mat。

setMouseCallback("Original",mouse_call);

下面是mouse_call

 void mouse_call(int event,int x,int y,int,void*)
    {
        if(event==EVENT_LBUTTONDOWN)
        {
            leftDown=true;
            cor1.x=x;
            cor1.y=y;
           cout <<"Corner 1: "<<cor1<<endl;

        }
        if(event==EVENT_LBUTTONUP)
        {
            if(abs(x-cor1.x)>20&&abs(y-cor1.y)>20) //checking whether the region is too small
            {
                leftup=true;
                cor2.x=x;
                cor2.y=y;
                cout<<"Corner 2: "<<cor2<<endl;
            }
            else
            {
                cout<<"Select a region more than 20 pixels"<<endl;
            }
        }

        if(leftDown==true&&leftup==false) //when the left button is down
        {
            Point pt;
            pt.x=x;
            pt.y=y;
            Mat temp_img=img.clone();
            rectangle(temp_img,cor1,pt,Scalar(0,0,255)); //drawing a rectangle continuously
            imshow("Original",temp_img);

        }
        if(leftDown==true&&leftup==true) //when the selection is done
        {

            box.width=abs(cor1.x-cor2.x);
            box.height=abs(cor1.y-cor2.y);
            box.x=min(cor1.x,cor2.x);
            box.y=min(cor1.y,cor2.y);
            Mat crop(img,box);   //Selecting a ROI(region of interest) from the original pic
            namedWindow("Cropped Image");
            imshow("Cropped Image",crop); //showing the cropped image
            leftDown=false;
            leftup=false;

        }
    }

更多细节请访问链接使用鼠标裁剪图像


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接