【问题标题】:With OpenCV, try to extract a region of a picture described by ArrayOfArrays使用 OpenCV,尝试提取 ArrayOfArrays 描述的图片区域
【发布时间】:2012-04-27 21:42:26
【问题描述】:

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

声明为:

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

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

提前致谢!

【问题讨论】:

    标签: c++ opencv contour


    【解决方案1】:

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

    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 对象是一个数组,这使它成为矩形。

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

    【讨论】:

    • 您好,感谢您的代码。该解决方案使用函数 boundingRect 提取矩形区域,对吗?有没有办法只存储轮廓内的区域?另外,我有一些问题将 vector 转换回 cvMat.. 对此有什么看法吗?谢谢。
    • 我已经编辑了我的答案。此外,您可以将向量子区域中的 Mat 对象转换为 CvMat,如下所示:CvMat m = subregions[i];
    【解决方案2】:

    您正在寻找cv::approxPolyDP() 函数来连接点。

    我在this post 中分享了整个过程的类似用法。在findContours() 调用之后检查for 循环。

    【讨论】:

    • 感谢您的快速回复。但我在这里的意思是'contours_final'确实是cv::approxPolyDP()的返回值,抱歉不清楚。我认为提出问题的另一种方式是如何将 final_contour 设置为 ROI,以便我可以在原始图像上获得区域。我不是实时进行的。只是一个静态图像。再次感谢!
    • 我正在尝试制作 Eclipse 的面具,但是当我制作它的对象时,这个函数显示错误,就像 ellipse const mask(img,Point(20,40), Size(60,40),0,0,360, Scalar(0,0,0));
    【解决方案3】:

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

    查看更多here

    【讨论】:

    • hmm,这个函数返回一个矩形区域,对吧?请参考我上面的cmets,给我更多的建议;)
    猜你喜欢
    • 2013-11-07
    • 2013-02-10
    • 2016-03-27
    • 1970-01-01
    • 2018-06-15
    • 2012-01-11
    • 2012-07-08
    • 1970-01-01
    • 2018-09-02
    相关资源
    最近更新 更多