Durch Spalten iterieren und dabei die größte Distanz zwischen zwei Punkten berechnen
-
In dieser Methode möchte ich den größten Abstand zwischen zwei (benachbarten) Punkten für jede einzelne Spalte in einem cv::Mat finden. Am Ende sollten die entsprechenden Punkte (die den größten Abstand zueinander haben) zurückgegeben werden.
Um dies zu erreichen, habe ich schon viel recherchiert und habe nun diesen Code-Snippet:
cv::Mat mat; std::vector<cv::Point> pointVec, finalPointVec; std::vector<float> allDist; for (int i = 0; i < mat.rows; i++) { for (int j = 0; j < mat.cols; j++) { c = mat.col(j); if (c.at<Vec3b>(i, j)[0] == 0 && c.at<Vec3b>(i, j)[1] == 0 && c.at<Vec3b>(i, j)[2] == 255) { cv::Point diPoint(j, i); pointVec.push_back(diPoint); if (pointVec[j].x == pointVec[j + 1].x) { //std::cout << pointVec[j].y << "\n"; float diffY = pointVec[j].y - pointVec[j + 1].y; float diffX = pointVec[j].x - pointVec[j + 1].x; float dist = sqrt((diffY * diffY) + (diffX * diffX)); for (int d = 0; d < pointVec[j].x; d++) { allDist.push_back(dist); } } } }
Also ich iteriere durch cv::Mat und berechne auch die Distanz. Nun möchte ich die Suche nach der größten Distanz für jede Spalte implementieren. Hier benötige ich Eure Hilfe, wie ich das am besten realisieren könnte. Obwohl ich ursprünglich dachte, dass if (pointVec [j].x == pointVec[j + 1].x)" auf die gleiche Spalte referenzieren würde, scheint dies doch falsch zu sein. Zudem eine weitere Frage: wie kann ich die Punkte zurückgeben, die den größten Abstand zueinander haben?
Um ein eventuelles bessere Verständnis klarzustellen, hier ein Bild, wie das Ganze aussehen soll (die umkreisten Punkte sollten diejenigen sein, die zurückgegeben werden müssen):
https://i.stack.imgur.com/606pR.jpgIch freue mich über jede Antwort!
-
In welcher Form liegen die Daten vor? Ich werde aus deinem Code nicht so recht schlau.
-
SeppJ schrieb:
In welcher Form liegen die Daten vor? Ich werde aus deinem Code nicht so recht schlau.
Das alles wird aus einer Matrix (cv::Mat) gelesen. Oder welche Daten meinst du?
-
Die Frage ist, was steht in deiner Maztrix drin. Aus deinem Code geht nich hervor, welche Dimensionen die Matrix hat und was für Daten da drinnen stehen (Außer das es wohl irgendwelche 3d Vektoren sein sollten.
Ich glaube ein wichtiger Punkt ist, das die mat::col Funktion einen neuen Matrix Header erstellt. Da passt dein "j" nicht mehr zu, mit dem du ja durch die Spalten iterieren willst.
-
Die Matrix wird anhand eines Bildes erstellt und in diesem Fall sollen nur rote Pixel behandelt werden (0, 0, 255) - also ja, 3d Vektoren - , denn sie stellen Linien dar. Jegliche andere Werte Matrix werden ignoriert. Diese roten Linien schauen auch in etwa so aus, wie in dem Bild, welches ich als Link hinzugefügt habe.
Okay, nun weiß ich aber nicht wie ich weiter mit mat::col verfahren soll.
-
Der Wert in der Matrix ist also ein Farbwert und die Position des Wertes in der Matrix ist die Position im Bild?
Falls ja, dann ist das doch super-simpel:
Geh eine Spalte reihenweise durch, merk dir den ersten roten Punkt an dem du vorbei läufst. Wenn du den nächsten roten Punkt findest, dann berechnest du den Abstand zum vorherigen roten Punkt (da du weißt, dass beide Punkt in der gleichen Spalte sind, ist der Abstand einfach die Differenz der Reihenindizes). Ist der Abstand größer als der bisherige größte Abstand, merkst du dir die beiden Punkte und ihren Abstand als neuen größten Abstand. Dann immer so weiter machen, bis du am Ende bist.
-
Okay, wie greife ich denn auch den nächsten Punkt zu?
-
vickal93 schrieb:
Okay, wie greife ich denn auch den nächsten Punkt zu?
Indem du weiter gehst, bist du da bist?
-
Ich tue mir ein bisschen bei der Implementierung schwer - habe nun folgendes zusammen gebaut:
cv::Mat diagonals; cv::Point redPoint; int max = 0; for (int j = 0; j < diagonals.cols; j++) { for (int i = 0; i < diagonals.rows; i++) { if (diagonals.at<Vec3b>(i, j)[0] == 0 && diagonals.at<Vec3b>(i, j)[1] == 0 && diagonals.at<Vec3b>(i, j)[2] == 255) { redPoint = cv::Point(j, i); cv::Point nextRed = cv::Point(j, i++); //std::cout << redPoint << " next: " << nextRed; int dist = nextRed.x - redPoint.x; if (dist > max) { max = dist; } //...}}
So, das mit i++ für nextPoint klappt schon mal nicht. Die Logik verstehe ich aber mit der Implementierung klappt es noch nicht ganz. Zudem weiß ich leider nicht, wie ich die Punkte, die den größten Abstand zueinander haben speichern soll...
-
Du sollst die Schleife weiter durch gehen, bis du den nächsten roten Punkt in der Spalte gefunden hast.
Mit
cv::Point nextRed = cv::Point(j, i++);
erstellst du einfach einen Punkt der halt an der nächsten y-Coordinate liegt.
Du könntest dir zum Beispiel in einer Variablen merken, ob du bereits einen roten Punkt gefunden hast. Wenn die auf false ist und der Punkt rot, dann speicherst du den ersten Punkt und setzt die auf true.
Wenn die bereits true ist und der Punkt rot, dann berechnest du die Distanz von dem gefundenen Punkt zu dem ersten gefundenen Punkt.Tatsächlich müsstest du auch nicht immer die Distanz berechnen, es würde reichen den ersten und den letzen roten Punkt in einer Spalte zu finden und dann die Distanz zu berechnen, dass müssen ja pro Spalte dann die Punkte mit der größten Distanz sein.
-
Schlangenmensch schrieb:
Tatsächlich müsstest du auch nicht immer die Distanz berechnen, es würde reichen den ersten und den letzen roten Punkt in einer Spalte zu finden und dann die Distanz zu berechnen, dass müssen ja pro Spalte dann die Punkte mit der größten Distanz sein.
So wie ich das verstanden habe, sollen nur Abstände zwischen direkten Nachbarn zählen. Wenn da noch ein Punkt dazwischen ist, gilt es nicht.
Ansonsten @vickal93: So wie Schlangenmensch es beschreibt habe ich mir das gedacht.
-
Hm, beim nochmaligen lesen des ersten Posts ist mir auch das Wort "benachbart" aufgefallen. Bei Distanzberechnung war mir das irgendwie durchgegangen, denn Distanz zwischen zwei benachbarten Punkten ist ja immer 1 Pixel. Also geht es um die Länge der roten Linie in einer Spalte, oder so.
Hier müsste man aber auch nicht immer die Distanz berechnen, sondern nur, wenn der nächste Punkt nicht mehr rot ist. Aber wahrscheinlich ist es ratsamer erstmal die triviale Lösung zu implementieren.