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

时间:2012-04-16 14:36:23

标签: c++ opencv contour

我正在iOS中开发一些图像处理工具。目前,我有一个计算的特征轮廓,其类型为InputArrayOfArrays。

声明为:

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

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

提前致谢!

3 个答案:

答案 0 :(得分:25)

我猜你想要做的只是提取检测到的轮廓中的区域。这是一个可能的解决方案:

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

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

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

最后,我认为您没有任何理由只在特殊创建的数据结构中保存轮廓中的像素,因为您需要存储每个像素的位置以重新创建图像。如果您的关注是节省空间,那么如果有的话,这将无法为您节省太多空间。保存最紧密的边界框就足够了。如果您希望仅分析轮廓区域中的像素,则为每个轮廓保存一个遮罩副本,以便您可以使用它来检查轮廓中的哪些像素。

答案 1 :(得分:0)

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

我在this post中分享了对整个程序的类似用法。在for电话后检查findContours()循环。

答案 2 :(得分:0)

我认为你要找的是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()接受一个Points向量并返回一个cv :: Rect。初始化Mat myRoi = img(myRect)为您提供指向图像部分的指针(因此修改myRoi也会修改img)。

查看更多here