È possibile utilizzare partition per this:
partition
suddivide un insieme di elementi in classi di equivalenza. È possibile definire la classe di equivalenza come tutti i punti all'interno di una data distanza euclidea (tolleranza raggio)
Se si dispone di C++ 11, si può semplicemente utilizzare una funzione lambda:
int th_distance = 18; // radius tolerance
int th2 = th_distance * th_distance; // squared radius tolerance
vector<int> labels;
int n_labels = 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;
});
in caso contrario, puoi semplicemente costruire un funtore (vedi dettagli nel codice sotto).
Con adeguato raggio di distanza (ho trovato 18 opere buone su questa immagine), ho ottenuto:
codice completo:
#include <opencv2\opencv.hpp>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
struct EuclideanDistanceFunctor
{
int _dist2;
EuclideanDistanceFunctor(int dist) : _dist2(dist*dist) {}
bool operator()(const Point& lhs, const Point& rhs) const
{
return ((lhs.x - rhs.x)*(lhs.x - rhs.x) + (lhs.y - rhs.y)*(lhs.y - rhs.y)) < _dist2;
}
};
int main()
{
// Load the image (grayscale)
Mat1b img = imread("path_to_image", IMREAD_GRAYSCALE);
// Get all non black points
vector<Point> pts;
findNonZero(img, pts);
// Define the radius tolerance
int th_distance = 18; // radius tolerance
// Apply partition
// All pixels within the radius tolerance distance will belong to the same class (same label)
vector<int> labels;
// With functor
//int n_labels = partition(pts, labels, EuclideanDistanceFunctor(th_distance));
// With lambda function (require C++11)
int th2 = th_distance * th_distance;
int n_labels = 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;
});
// You can save all points in the same class in a vector (one for each class), just like findContours
vector<vector<Point>> contours(n_labels);
for (int i = 0; i < pts.size(); ++i)
{
contours[labels[i]].push_back(pts[i]);
}
// Draw results
// Build a vector of random color, one for each class (label)
vector<Vec3b> colors;
for (int i = 0; i < n_labels; ++i)
{
colors.push_back(Vec3b(rand() & 255, rand() & 255, rand() & 255));
}
// Draw the labels
Mat3b lbl(img.rows, img.cols, Vec3b(0, 0, 0));
for (int i = 0; i < pts.size(); ++i)
{
lbl(pts[i]) = colors[labels[i]];
}
imshow("Labels", lbl);
waitKey();
return 0;
}
non è chiaro ciò che si desidera l'algoritmo da fare . Puoi mostrare un'altra immagine con il risultato atteso?A un certo livello, sembra che gli operatori morfologici ti darebbero tutto ciò di cui hai bisogno quindi sono sicuro che non può essere il caso. Abbiamo bisogno di vedere l'effetto che stai cercando di raggiungere. –
@RogerRowland Nessun operatore morfologico non è un'opzione in quanto distorcerà i miei bordi. Quello che voglio è raggruppare i bordi nella mia immagine maschera per distanza euclidea tra di loro. Qualcosa di simile a http://www.pointclouds.org/documentation/tutorials/cluster_extraction.php – manatttta
Penso che il suggerimento di @Humam sia buono, sebbene non esista alcuna implementazione di OpenCV. Per le attività di clustering in OpenCV non otterrai molto più di k-means o shift medio. Tuttavia, poiché hai già collegato un algoritmo di esempio, potrebbe essere più semplice portarlo su OpenCV (e presumibilmente non hai bisogno di 3D). –