10

I am developing some image processing tools in iOS. Currently, I have a contour of features computed, which is of type InputArrayOfArrays.

Declared as:

std::vector<std::vector<cv::Point> > contours_final( temp_contours.size() );

Now, I would like to extract areas of the original RGB picture circled by contours and may further store sub-image as cv::Mat format. How can I do that?

Thanks in advance!

karlphillip
  • 87,606
  • 33
  • 227
  • 395
feng63600
  • 173
  • 1
  • 2
  • 13

3 Answers3

25

I'm guessing what you want to do is just extract the regions in the the detected contours. Here is a possible solution:

using namespace cv;

int main(void)
{
    vector<Mat> subregions;
    // contours_final is as given above in your code
    for (int i = 0; i < contours_final.size(); i++)
    {
        // Get bounding box for contour
        Rect roi = boundingRect(contours_final[i]); // This is a OpenCV function

        // Create a mask for each contour to mask out that region from image.
        Mat mask = Mat::zeros(image.size(), CV_8UC1);
        drawContours(mask, contours_final, i, Scalar(255), CV_FILLED); // This is a OpenCV function

        // At this point, mask has value of 255 for pixels within the contour and value of 0 for those not in contour.

        // Extract region using mask for region
        Mat contourRegion;
        Mat imageROI;
        image.copyTo(imageROI, mask); // 'image' is the image you used to compute the contours.
        contourRegion = imageROI(roi);
        // Mat maskROI = mask(roi); // Save this if you want a mask for pixels within the contour in contourRegion. 

        // Store contourRegion. contourRegion is a rectangular image the size of the bounding rect for the contour 
        // BUT only pixels within the contour is visible. All other pixels are set to (0,0,0).
        subregions.push_back(contourRegion);
    }

    return 0;
}

You might also want to consider saving the individual masks to optionally use as a alpha channel in case you want to save the subregions in a format that supports transparency (e.g. png).

NOTE: I'm NOT extracting ALL the pixels in the bounding box for each contour, just those within the contour. Pixels that are not within the contour but in the bounding box are set to 0. The reason is that your Mat object is an array and that makes it rectangular.

Lastly, I don't see any reason for you to just save the pixels in the contour in a specially created data structure because you would then need to store the position for each pixel in order to recreate the image. If your concern is saving space, that would not save you much space if at all. Saving the tightest bounding box would suffice. If instead you wish to just analyze the pixels in the contour region, then save a copy of the mask for each contour so that you can use it to check which pixels are within the contour.

lightalchemist
  • 9,052
  • 4
  • 39
  • 52
  • Hi, thanks for the code. This solution extract a rectangle area by using function boundingRect, right? Is there any way only to store areas within the contours? Also, I have some problem convert vector back to cvMat.. any look on this? Thanks. – feng63600 Apr 17 '12 at 14:40
  • I've edited my answer. Also, you can convert a Mat object in the vector subregions to CvMat like this: CvMat m = subregions[i]; – lightalchemist Apr 18 '12 at 04:06
0

You are looking for the cv::approxPolyDP() function to connect the points.

I shared a similar use of the overall procedure in this post. Check the for loop after the findContours() call.

Community
  • 1
  • 1
karlphillip
  • 87,606
  • 33
  • 227
  • 395
  • Thanks for quick response. But what I meant here 'contours_final' is indeed is return value of cv::approxPolyDP(), sorry for being unclear. I think the other way to put my question is how to set the final_contour as a ROI, so that I could get regions on the original image. I am not doing it in real-time. just a static image. Thanks again! – feng63600 Apr 17 '12 at 03:12
  • i am trying to make the mask of eclipse but this function is showing error while i make its object like `ellipse const mask(img,Point(20,40), Size(60,40),0,0,360, Scalar(0,0,0));` – AHF Apr 03 '14 at 05:52
0

I think what you're looking for is cv::boundingRect(). Something like this:

using namespace cv;
Mat img = ...;
...
vector<Mat> roiVector;
for(vector<vector<Point> >::iterator it=contours.begin(); it<contours.end(); it++) {
    if (boundingRect( (*it)).area()>minArea) {
        roiVector.push_back(img(boundingRect(*it)));
    }
}

cv::boundingRect() takes a vector of Points and returns a cv::Rect. Initializing a Mat myRoi = img(myRect) gives you a pointer to that part of the image (so modifying myRoi will ALSO modify img).

See more here.

Steve Heim
  • 767
  • 10
  • 24
  • hmm, this function returns a rectangle area, right? Please refer to my comments above and give me more suggestions;) – feng63600 Apr 17 '12 at 15:29