73

I have an image converted in a CvMat Matrix say CVMat source. Once I get a region of interest from source I want the rest of the algorithm to be applied to that region of interest only. For that I think I will have to somehow crop the source matrix which I am unable to do so. Is there a method or a function that could crop a CvMat Matrix and return another cropped CvMat matrix? thanks.

Angie Quijano
  • 4,167
  • 3
  • 25
  • 30
Waqar
  • 957
  • 2
  • 8
  • 14
  • 1
    Do you want it in the pre 2.0 c style or the post 2.0 c++ style? please re-tag your question according to your answer – Boaz Nov 25 '11 at 13:58

6 Answers6

154

OpenCV has region of interest functions which you may find useful. If you are using the cv::Mat then you could use something like the following.

// 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);

Documentation for extracting sub image

Chris
  • 8,030
  • 4
  • 37
  • 56
  • 6
    What do you mean this doesn't copy the data? – Jameo Jan 21 '13 at 20:34
  • 7
    It means it only creates a reference to that image region and not a copy. This means that if you change the croppedImage it also changes the imagesource. If you do not want this behavior you can create a copy explicitly. – Rui Marques Feb 13 '13 at 20:11
  • What if I want an ellipse region instead of a Rectangle region of interest? – Sohaib Oct 07 '13 at 15:07
  • 2
    @Sohaib Then we need to use what we call a "mask", which is usually available as an extra parameter on processing functions. – Samuel Audet May 02 '15 at 22:27
  • hey i have doubt ,my image is of size(3264*2448).I am able to plot a point.But the point x OR y is not in device coordinates(eg 2400,1864 etc).Can someone help how to convert the cv::Point to device coordinates – Mukesh Jun 03 '15 at 09:53
  • what if the original matrix is destructed? DOn't you need a deep copy? – Vlad Nov 13 '15 at 16:49
  • Could you clarify what the in parameters to the cv::Rect are? From what I found its x, y, width, height. Is that correct? – Björn Larsson Feb 19 '18 at 10:33
  • 2
    what happens to `croppedImage ` if I call `image.release()`? – dashesy Mar 01 '19 at 02:26
  • what about OpenCV4Android? `val croppedMatGray = Mat(matGray, rect)` - it's not copy too? just reference? – user924 Jun 14 '19 at 10:38
50

I know this question is already solved.. but there is a very easy way to crop. you can just do it in one line-

Mat cropedImage = fullImage(Rect(X,Y,Width,Height));
MMH
  • 1,676
  • 5
  • 26
  • 43
25

To get better results and robustness against differents types of matrices, you can do this in addition to the first answer, that copy the data :

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);
pacongfar
  • 361
  • 3
  • 4
11

To create a copy of the crop we want, we can do the following,

// 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();
Reed Richards
  • 4,178
  • 8
  • 41
  • 55
  • 1
    This add nothing to the answer already provided. Also you're missing a semicolon and have incorrect variables names. BTW, you can do this with `Mat crop = img(Rect(...)).clone()` – Miki Feb 18 '16 at 21:48
  • Fixed typos. I do think it adds in the sense that it does everything in one line. As for the clone or copyTo in this case I guess it's just what one favors. – Reed Richards Feb 18 '16 at 22:03
1

I understand this question has been answered but perhaps this might be useful to someone...

If you wish to copy the data into a separate cv::Mat object you could use a function similar to this:

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];
        }
    }
}

It would be important to note that this would only function properly on single channel images.

strudelheist
  • 49
  • 1
  • 5
  • This helped me a lot. I created a version that extracts ROIs from 16 bit per pixel images. https://gist.github.com/fernandoc1/e69e4c09d0bf4b09076af40c06b13450 – Fernando Sep 24 '19 at 21:54
-4

You can easily crop a Mat using opencv funtions.

setMouseCallback("Original",mouse_call);

The mouse_callis given below:

 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;

        }
    }

For details you can visit the link Cropping the Image using Mouse