Sie können partition (statisch keine Notwendigkeit abgestimmt werden) für dies:
partition
spaltet einen Elementsatz in Äquivalenzklassen. Sie können Ihre Äquivalenzklasse als alle Punkte innerhalb eines gegebenen euklidischen Abstand (Radius Toleranz)
definieren Wenn Sie C++ 11, Sie einfach eine Lambda-Funktion verwenden können:
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;
});
sonst, Sie können einfach einen Funktor erstellen (siehe Details im folgenden Code).
Mit entsprechendem Radius Abstand (I 18 Arbeiten auf diesem Bild gut gefunden), ich habe:
Voll Code:
#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;
}
Es ist nicht klar, was Sie der Algorithmus tun wollen . Können Sie ein anderes Bild mit dem erwarteten Ergebnis zeigen?Auf einer Ebene scheint es so, als würden morphologische Operatoren dir alles geben, was du brauchst, also bin ich mir sicher, dass das nicht der Fall sein kann. Wir müssen den Effekt sehen, den Sie erreichen wollen. –
@RogerRowland Keine morphologischen Operatoren sind keine Option, da sie meine Kanten verzerren. Was ich will, ist die Kanten in meinem Maskenbild durch euklidischen Abstand zwischen ihnen zu gruppieren. Etwas ähnliches wie http://www.pointclouds.org/documentation/tutorials/cluster_extraction.php – manatttta
Ich denke @ Humam Vorschlag ist ein guter, obwohl es keine OpenCV-Implementierung gibt. Für Clustering-Aufgaben in OpenCV erhalten Sie nicht viel mehr als k-Mittel oder mittlere Verschiebung. Da Sie jedoch bereits einen Beispielalgorithmus verknüpft haben, ist es möglicherweise einfacher, diesen in OpenCV zu portieren (und vermutlich benötigen Sie kein 3D). –