C++ 使用 OpenCV,尝试提取由 ArrayOfArrays 描述的图片区域

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10176184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:42:59  来源:igfitidea点击:

With OpenCV, try to extract a region of a picture described by ArrayOfArrays

c++opencvcontour

提问by feng63600

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

我正在 iOS 中开发一些图像处理工具。目前,我计算了一个特征轮廓,它是 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?

现在,我想提取由轮廓圈出的原始 RGB 图片区域,并可能进一步将子图像存储为 cv::Mat 格式。我怎样才能做到这一点?

Thanks in advance!

提前致谢!

回答by lightalchemist

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).

如果您想以支持透明度的格式(例如 png)保存子区域,您可能还需要考虑保存单个蒙版以选择性地用作 alpha 通道。

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.

注意:我不会为每个轮廓提取边界框中的所有像素,只是提取轮廓内的像素。不在轮廓内但在边界框内的像素设置为 0。原因是您的 Mat 对象是一个数组,这使其成为矩形。

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.

最后,我认为您没有任何理由将轮廓中的像素保存在一个专门创建的数据结构中,因为您需要存储每个像素的位置才能重新创建图像。如果您关心的是节省空间,那根本不会为您节省多少空间。保存最紧密的边界框就足够了。相反,如果您只想分析轮廓区域中的像素,则为每个轮廓保存掩码的副本,以便您可以使用它来检查轮廓内的像素。

回答by karlphillip

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

您正在寻找cv::approxPolyDP()连接点的功能。

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

我在这篇文章中分享了对整个过程的类似使用。调用for后检查循环findContours()

回答by Steve Heim

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

我认为您正在寻找的是 cv::boundingRect()。像这样的东西:

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).

cv::boundingRect() 接受一个点向量并返回一个 cv::Rect。初始化 Mat myRoi = img(myRect) 会为您提供指向图像该部分的指针(因此修改 myRoi 也会修改 img)。

See more here.

在此处查看更多信息