Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does OpenCV offer a squared norm function for cv::Point?

Tags:

c++

opencv

I have to check several distances between points against a distance threshold. What I can do is taking the square of my threshold and compare it with the squared norm of (a-b), where a and b are the points I am checking.

I know about cv::norm function, but I wonder if there exists a version that doesn't compute the square root (and therefore is faster) or if I should implement it manually.

like image 933
Antonio Avatar asked Oct 01 '15 12:10

Antonio


People also ask

What is norm in OpenCV?

C++ OpenCV cv::norm()a variety of distance norms between two arrays if two arrays are provided. Norm of a Matrix: There are different norm types for which different norms are calculated. General format for cv::norm():

What is Vec3b?

Vec3b is the abbreviation for "vector with 3 byte entries" Here those byte entries are unsigned char values to represent values between 0 .. 255. Each byte typically represents the intensity of a single color channel, so on default, Vec3b is a single RGB (or better BGR) pixel.

What is scalar OpenCV?

ScalarRepresents a 4-element vector. The type Scalar is widely used in OpenCV for passing pixel values. In this tutorial, we will use it extensively to represent BGR color values (3 parameters). It is not necessary to define the last argument if it is not going to be used.


1 Answers

Note from OP:
I accepted this answer as it's the best method one can achieve using OpenCV,
but I think the best solution in this case is going for a custom function.


Yes, it's NORM_L2SQR:

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

int main()
{
    vector<Point> pts{ Point(0, 2) };

    double n = norm(pts, NORM_L2SQR);
    // n is 4

    return 0;
}

You can see in the function cv::norm in stat.cpp that if you use NORM_L2SQR you don't compute the sqrt on the norm:

...
if( normType == NORM_L2 )
{
    double result = 0;
    GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1);
    return std::sqrt(result);
}
if( normType == NORM_L2SQR )
{
    double result = 0;
    GET_OPTIMIZED(normL2_32f)(data, 0, &result, (int)len, 1);
    return result;
}
...

Regarding the specific issue:

My actual problem is: I have a vector of points, merge points closer to each other than a given distance. "Merging" means remove one and move the other half way towards the just removed point.

You can probably

  • take advantage of the partition function with a predicate that returns true if two points are within a given threshold.
  • retrieve all points in the same cluster
  • compute the centroid for each cluster

Here the code:

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

int main()
{
    vector<Point> pts{ Point(0, 2), Point{ 1, 0 }, Point{ 10, 11 }, Point{11,12}, Point(2,2) };

    // Partition according to a threshold
    int th2 = 9;
    vector<int> labels;     
    int n = partition(pts, labels, [th2](const Point& lhs, const Point& rhs) { 
        return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < th2;
    });

    // Get all the points in each partition
    vector<vector<Point>> clusters(n);
    for (int i = 0; i < pts.size(); ++i)
    {
        clusters[labels[i]].push_back(pts[i]);
    }

    // Compute the centroid for each cluster
    vector<Point2f> centers;
    for (const vector<Point>& cluster : clusters)
    {
        // Compute centroid
        Point2f c(0.f,0.f);
        for (const Point& p : cluster)
        {
            c.x += p.x;
            c.y += p.y;
        }
        c.x /= cluster.size();
        c.y /= cluster.size();

        centers.push_back(c);
    }

    return 0;
}

will produce the two centers:

centers[0] : Point2f(1.0, 1.3333);
centers[1] : Point2f(10.5, 11.5)
like image 58
Miki Avatar answered Oct 26 '22 11:10

Miki