c++qtopencvblobs

Computing rectangle around pixel coordinates


I have a Qvector containing pixel coordinates of an image. The main goal would be to group those pixels regarding their distance to each other and getting a rectangle out of those groups of pixels. Every pixel in the vector are not close to each other and that is the reason why I would like to group them.

I am using openCv and Qt. I would like to avoid the blobDetector from OpenCV which is quite slow and do this by my own if that is possible.

Does anybody have an idea how to manage this ?

EDIT:

Let's say the white dots are pixel close to each other. The main objective would be to detect that these pixels are close to each other and be able to get a rectangle of those pixels. Is this possible ?

enter image description here

EDIT2:

After getting the clusters I tried to get the bounding rectangles around those clusters with the following code. I might not be using this function the correct way.

cv::partition(cvCoordsTable, testVector, Dist(eqludianThreshold));
std::vector<cv::Rect> rectTable;

for(int in = 0; in < testVector.size(); in++)
{
    rectTable.push_back(cv::boundingRect(cvCoordsTable.at(in)));
}

Thank you for your help


Solution

  • This is clustering problem in the first place. Since you do not know the number of clusters (groups) you have to use some algorithm that does not need the number of clusters as input. You can do simple cv::partition which has the following signature in C++:

    int cv::partition(const vector<_Tp>& vec, vector<int>& labels, _EqPredicate predicate=_EqPredicate())
    

    Example of using it:

        std::vector<cv::Point> pixelCoordinatesTable,
        std::vector<int> labelsTable;
        double threshold= 5;//Max eqludian distance between one cluster points
        cv::partition(pixelCoordinatesTable, labelsTable, [&threshold](auto const& l, auto const& r){
            return cv::norm(l - r))<threshold;
        });
    

    Another and more mature option will be using a real clustering algorithm like DBSCAN. Which is a density based clustering algorithm. and you can find a C++ implementation here.

    After you got the clusters (in any method) just apply cv::boundingRect around each cluster to get the rectangle you want.

    EDIT:

    To solve the rectangle problem:

    auto cluster_count = cv::partition(cvCoordsTable, testVector, Dist(eqludianThreshold)); // gettting the number of clusters
    std::vector<cv::Rect> rectTable;
    rectTable.reserve(cluster_count);//Optimiaztion
    for(int in = 0; in < cluster_count; in++){
        std::vector<cv::Point> temp;
        temp.reserve(testVector.size());
        for(size_t i=0;i<testVector.size();++i){
            if(testVector[i]==in){
                 temp.emplace_back(rectTable[i]);
            }
        }
        rectTable.emplace_back(cv::boundingRect(temp));
    }
    

    I am sure there is a better and faster way, I was just explaining the idea and you may optimise it as you can.