2015-10-01 19 views
9

Devo controllare diverse distanze tra i punti contro una soglia di distanza. Quello che posso fare è prendere il quadrato della mia soglia e confrontarlo con la norma quadrata di (a-b), dove a e sono i punti che sto verificando.OpenCV offre una funzione quadratica normale per cv :: Point?

Conosco la funzione cv::norm, ma mi chiedo se esiste una versione che non calcola la radice quadrata (e quindi è più veloce) o se dovrei implementarla manualmente.

risposta

4

Nota da OP:
Ho accettato questa risposta in quanto è il metodo migliore si può ottenere utilizzando OpenCV,
ma credo che la soluzione migliore in questo caso sta andando per una funzione personalizzata.


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

Si può vedere nella funzione cv::norm in stat.cpp che se si utilizza NORM_L2SQR non si calcola il sqrt sulla norma:

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

Riguardo al problema specifico:

Il mio problema reale è: ho un vettore di punti, unire punti più vicini tra loro di una determinata distanza. "Unire" significa rimuoverne uno e spostare l'altro a metà strada verso il punto appena rimosso.

Probabilmente si può

  • approfittare della funzione partition con un predicato che restituisce true se due punti sono all'interno di una determinata soglia.
  • recuperare tutti i punti nello stesso cluster
  • calcolare il baricentro per ogni cluster

Ecco il codice:

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

produrrà i due centri:

centers[0] : Point2f(1.0, 1.3333); 
centers[1] : Point2f(10.5, 11.5) 
+1

Oh, wow, dove è documentato? – Antonio

+0

Non lo so davvero. Basta guardare attraverso il codice sorgente ... Vedo se trovo una documentazione per questo ... – Miki

+0

Uhm, questo richiede la creazione di un vettore che sembra eccessivo. – Antonio

0

E ' sembra che non ci siano problemi specifici per affrontare questo problema.

ho pensato che una soluzione potrebbe essere con il metodo ddot (prodotto scalare), e calcolare qualcosa come

cv::Point distVec = a-b; 
double squaredNorm = distVec.ddot(distVec); 

Se si è disposti a correre il rischio, c'è cv::normL2Sqr che richiede l'ingresso di essere in serie formato: cv::Point potrebbe essere direttamente convertibile in int[].

Continuerò personalmente a scrivere la mia norma quadrata.

Problemi correlati