Why OpenCV has no specialize data structure for re

2019-02-20 01:44发布

问题:

I have been using MVTec's Halcon Image Processing Library for half a year and OpenCV for 1 year.

1. One thing I found that Halcon much outperforms OpenCV is that OpenCV has no specialize data structure for region.

This is lots of waste if I only want to store a small region in a large space. Shouldn't OpenCV have some specialized data structure for region other than Mat Class.

2. Second one, which is the result of the previous one, is that OpenCV is awkward to iterate through regions.

Imagine the scenario that I have 10 connected blocks of region after doing threshold and I want to iterate through that 10 blocks to process each of them. As far as I know, I have to first use findContours to get all the contours of each region and then I use drawContour to get that region. So can I say that the regions is stored by the contour data and each time I want to get the region back I have to call drawContours?

Mat myImage = imread("Path_To_Source_Image");
threshold(myImage, region, 128, 1, THRESH_BINARY);
vector<vector<Point>> contours;
findContours(region, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
for (int i = 0; i < contours.size, i++){
    Mat oneBlock(myImage.size(), CV_8U); 
    drawContours(oneBlock, contours, i, Scalar(255), -1);
        // Now I finally get my region

        //  ***************************************
        //
        //   Do my image procesing for that region
        //
        //  ***************************************
    }

回答1:

A common approach to represent regions is to use a Mat1i (aka a Mat of type CV_32S) that contains the indices of the regions, i.e. the labels.

You can then access the i-th region simply with: Mat1b region_mask = (labels == i);

With OpenCV < 3.0, you can use findConturs and drawContours to create the labels image:

#include <opencv2\opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    // Read image from file 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    Mat1b region;
    threshold(img, region, 200, 255, THRESH_BINARY);

    vector<vector<Point>> contours;
    findContours(region.clone(), contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    Mat1i labels(img.rows, img.cols, int(0));
    int n_labels = contours.size();

    for (int i = 0; i < contours.size(); ++i)
    {
        drawContours(labels, contours, i, Scalar(i + 1), CV_FILLED); // Note the +1, since 0 is the background
    }

    // Now you can get your regiones as:

    // Label "0" is the background
    for (int i = 1; i <= n_labels; ++i)
    {
        Mat1b region_mask = (labels == i);
        imshow("Region", region_mask);
        waitKey();
    }

    return 0;
}

With OpenCV >= 3.0 you can use connectedComponents, which will directly return the labels:

#include <opencv2\opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;

int main()
{
    // Read image from file 
    Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);

    Mat1b region;
    threshold(img, region, 200, 255, THRESH_BINARY);

    Mat1i labels;
    int n_labels = connectedComponents(region, labels);

    // Now you can get your regiones as:

    // Label "0" is the background
    for (int i = 1; i <= n_labels; ++i)
    {
        Mat1b region_mask = (labels == i);
        imshow("Region", region_mask);
        waitKey();
    }

    return 0;
}