0

enter image description hereWie zu überprüfen, ob ein Punkt innerhalb eines Satzes von Konturen ist

Hallo an alle. Das obige Bild ist eine Summe von zwei Bildern, in denen ich eine Übereinstimmung gefunden habe und alle passenden Punkte gezeichnet habe. Ich fand auch die Konturen der PCB-Teile im ersten Bild (halb links Bild-3 Konturen). Die Frage ist, wie könnte ich nur die übereinstimmenden Punkte zeichnen, die innerhalb dieser Konturen im ersten Bild statt dieser blauen Unordnung sind? Ich benutze Python 2.7 und opencv 2.4.12.

Ich schrieb dazu führen, eine Funktion zur Auslosung Spielen in opencv 2.4.12 es kein implementiertes Verfahren dafür. Wenn ich etwas nicht aufgenommen habe, sag es mir bitte. Vielen Dank im Voraus!

import numpy as np 
import cv2 

def drawMatches(img1, kp1, img2, kp2, matches): 

    # Create a new output image that concatenates the two images 
    # (a.k.a) a montage 
    rows1 = img1.shape[0] 
    cols1 = img1.shape[1] 
    rows2 = img2.shape[0] 
    cols2 = img2.shape[1] 

    # Create the output image 
    # The rows of the output are the largest between the two images 
    # and the columns are simply the sum of the two together 
    # The intent is to make this a colour image, so make this 3 channels 
    out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8') 

    # Place the first image to the left 
    out[:rows1,:cols1] = np.dstack([img1, img1, img1]) 

    # Place the next image to the right of it 
    out[:rows2,cols1:] = np.dstack([img2, img2, img2]) 

    # For each pair of points we have between both images 
    # draw circles, then connect a line between them 
    for mat in matches: 

     # Get the matching keypoints for each of the images 
     img1_idx = mat.queryIdx 
     img2_idx = mat.trainIdx 

     # x - columns 
     # y - rows 
     (x1,y1) = kp1[img1_idx].pt 
     (x2,y2) = kp2[img2_idx].pt 

     # Draw a small circle at both co-ordinates 
     # radius 4 
     # colour blue 
     # thickness = 1 
     cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1) 
     cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1) 

     # Draw a line in between the two points 
     # thickness = 1 
     # colour blue 
     cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255,0,0), 1) 


    # Show the image 
    cv2.imshow('Matched Features', out) 
    cv2.imwrite("shift_points.png", out) 
    cv2.waitKey(0) 
    cv2.destroyWindow('Matched Features') 

    # Also return the image if you'd like a copy 
    return out 


img1 = cv2.imread('pic3.png', 0) # Original image - ensure grayscale 
img2 = cv2.imread('pic1.png', 0) # Rotated image - ensure grayscale 

sift = cv2.SIFT() 

# find the keypoints and descriptors with SIFT 
kp1, des1 = sift.detectAndCompute(img1,None) 
kp2, des2 = sift.detectAndCompute(img2,None) 

# Create matcher 
bf = cv2.BFMatcher() 

# Perform KNN matching 
matches = bf.knnMatch(des1, des2, k=2) 

# Apply ratio test 
good = [] 
for m,n in matches: 
    if m.distance < 0.75*n.distance: 
     # Add first matched keypoint to list 
     # if ratio test passes 
     good.append(m) 

# Show only the top 10 matches - also save a copy for use later 
out = drawMatches(img1, kp1, img2, kp2, good) 

Antwort

0

Basierend auf, was ihr bittet ich Sie gehe davon aus meinen Sie irgendeine Art von geschlossenen Kontur haben die Bereiche umreißen Sie Ihre Datenpunktpaare gebunden zu wollen.

Das ist ziemlich einfach für polygonale Konturen und mehr Mathe ist für komplexere Kurvenlinien erforderlich, aber die Lösung ist das gleiche.

ziehen Sie eine Linie von der betreffenden Stelle bis ins Unendliche. Die meisten Leute zeichnen eine Linie bis + x unendlich, aber jede Richtung funktioniert. Wenn eine ungerade Anzahl von Linienüberschneidungen vorhanden ist, befindet sich der Punkt innerhalb der Kontur.

Lesen Sie diesen Artikel: http://www.geeksforgeeks.org/how-to-check-if-a-given-point-lies-inside-a-polygon/

Für Punkt-Paare, wobei nur Paare beiden Punkte innerhalb der Kontur sind vollständig innerhalb der Kontur. Wenn Sie bei komplexen Konturformen mit konkaven Abschnitten auch testen möchten, dass der lineare Pfad zwischen den Punkten die Kontur nicht kreuzt, führen Sie einen ähnlichen Test nur mit dem Liniensegment zwischen den beiden Punkten durch, wenn es direkte Linienkreuzungen gibt Weg zwischen den Punkten kreuzt außerhalb der Kontur.

Edit:

Da Ihre Konturen Rechtecke sind, ein einfacherer Ansatz genügt zur Bestimmung, ob Ihre Punkte innerhalb des Rechtecks ​​sind.

Wenn Ihre Rechtecke ausgerichtet sind (sie sind gerade und nicht gedreht), können Sie Ihre Werte für oben, links und unten, rechts zum Überprüfen verwenden.

Let Punkt A = Oben, Links, Punkt B = unten, rechts, und Punkt C = Ihren Testpunkt.

ich ein Bild gehe davon Koordinatensystem, wo 0,0 die linke Seite, die Oberseite des Bildes und Breite, die Höhe ist die unten rechts. (Ich schreibe in C#)

bool PointIsInside(Point A, Point B, Point C) 
{ 
    if (A.X <= C.X && B.X >= C.X && A.Y <= C.Y && B.Y >= C.Y) 
     return true; 
    return false; 
} 

wenn Ihr Rechteck NICHT Achse ausgerichtet sind, dann können Sie vier Halbraum-Tests durchführen, um festzustellen, ob Ihr Punkt innerhalb des Rechtecks ​​ist.

Let Punkt A = Oben, Links, Punkt B = unten, rechts, Doppel B = Breite, H = Höhe Doppel, Doppel N = Rotationswinkel, und Punkt C = Testpunkt.

für eine Achse ausgerichtet Rechteck, oben, rechts kann berechnet werden, indem Sie den Vektor (1,0), multipliziert mit der Breite, und fügen Sie diesen Vektor nach oben, links. Für Bottom, Right Wir nehmen den Vektor (0,1), multiplizieren ihn mit der Höhe und addieren ihn zu Top, Right.

(1,0) entspricht einem Einheitsvektor (Länge 1) bei Winkel 0.Ähnlich ist (0,1) ein Einheitsvektor im Winkel von 90 Grad. Diese Vektoren können auch als Richtung der Linie betrachtet werden. Dies bedeutet auch, dass dieselben Vektoren verwendet werden können, um von unten, von links nach unten, von rechts und von oben, von links nach unten und von links zu gehen.

Wir müssen verschiedene Einheitsvektoren verwenden, unter dem angegebenen Winkel. Um dies zu tun, müssen wir einfach den Kosinus und Sinus des vorgesehenen Winkels nehmen.

Lassen Sie Vektor X = Richtung von oben, von links nach oben, rechts, Vektor Y = Richtung von oben, von rechts nach unten, rechts.

Ich verwende Winkel in Grad für dieses Beispiel.

Vector X = new Vector(); 
Vector Y = new Vector(); 
X.X = Math.Cos(R); 
X.Y = Math.Sin(R); 
Y.X = Math.Cos(R+90); 
Y.Y = Math.Sin(R+90); 

Da wir mit Oben, Links gestartet, können wir Bottom finden, rechts, indem einfach die beiden Vektoren oben, links

Point B = new Point(); 
B = A + X + Y; 

Wir haben jetzt einen Halbraum-Test die tun wollen Punktprodukt für unseren Testpunkt. In den ersten beiden Tests wird der Testpunkt verwendet, und oben, links, die anderen beiden verwenden den Testpunkt und unten, rechts.

Der Half-Space-Test basiert inhärent auf Direktionalität. Ist der Punkt vor, hinter oder senkrecht zu einer bestimmten Richtung? Wir haben die zwei Richtungen, die wir brauchen, aber sie sind Richtungen, die auf dem oberen, linken Punkt des Rechtecks ​​basieren, nicht auf dem vollen Raum des Bildes, also müssen wir einen Vektor von oben, links, zu dem fraglichen Punkt bekommen, und ein anderer von unten, denn das sind die beiden Punkte, gegen die wir testen.

Dies ist einfach zu berechnen, da es nur Destination - Origin ist.

Mit Vektor D = Oben, Links zum Testpunkt C und Vektor E = Unten, Rechts zum Testpunkt.

Vector D = C - A; 
Vector E = C - B; 

Das Skalarprodukt ist x1 * x2 + y1 * y2 der beiden Vektoren. Wenn das Ergebnis positiv ist, haben die zwei Richtungen einen absoluten Winkel von weniger als 90 Grad oder gehen ungefähr in die gleiche Richtung, ein Ergebnis von Null bedeutet, dass sie senkrecht sind. In unserem Fall bedeutet dies, dass der Testpunkt direkt auf einer Seite des Rechtecks ​​liegt, gegen das wir testen. Weniger als Null bedeutet einen absoluten Winkel von mehr als 90 Grad, oder sie gehen ungefähr in entgegengesetzte Richtungen. Wenn ein Punkt innerhalb des Rechtecks ​​liegt, sind die Punktprodukte von oben links> = 0, während die Punktprodukte von unten rechts < = 0 sind. Im Wesentlichen ist der Testpunkt beim Testen näher unten rechts von oben links, aber wenn wir die gleiche Richtung nehmen, wenn wir bereits unten rechts sind, wird es weggehen, zurück nach oben, links.

double DotProd(Vector V1, Vector V2) 
{ 
    return V1.X * V2.X + V1.Y * V2.Y; 
} 

und so unser Test endet als:

if(DotProd(X, D) >= 0 && DotProd(Y, D) >= 0 && DotProd(X, E) <= 0 && DotProd(Y, E) <= 0) 

dann der Punkt innerhalb des Rechtecks ​​ist. Tun Sie dies für beide Punkte, wenn beide wahr sind, dann ist die Linie innerhalb des Rechtecks.

+0

Ich habe eine große Menge von Punkten gegeben von Sift und Feature-Matching und ich möchte nur diejenigen innerhalb der Konturen, die ich gefunden habe, zu zeichnen. Ich habe irgendwo die Methode gesehen, die Sie vorgeschlagen haben, aber ich konnte nicht verstehen, wie ich sie umsetzen soll. Ich werde den angehängten Artikel überprüfen und versuchen, es zu erstellen. Wenn Sie die Zeit haben und wissen, wie es geht, legen Sie einen Beispielcode, der mir vielleicht helfen könnte. Wie auch immer, danke! –

+0

Übrigens sind meine Konturen Rechtecke –

+0

Ich habe meine Antwort mit mehr Informationen bearbeitet – Draco

Verwandte Themen