OpenCV Positionsbestimmung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
LCD-Johny
User
Beiträge: 3
Registriert: Montag 17. Juli 2017, 13:51

Hallo,
in Sachen Bildverarbeitung bin ich absolut kein Experte und benötige ein wenig Hilfe.
Quelle ist das Bild "img" (ohne den blauen Rahmen natürlich). Das Ziel ist es die position des schwarzen Kreises genau zu lokalisieren. Am besten den Mittelpunkt.
Lösen wollte ich das mit dem Mean-Shift Verfahren. Keine Ahnung ob das die beste Methode dafür ist. Ich kenne sie einfach schon grob.
Dazu wurde das Bild einmal in den HSV-Farbraum konvertiert. Auf dieser Grundlage konnte ich ein paar Rahmenbedingungen eingrenzen was Sättigung und Helligkeit angeht. Farbe kann ich nicht begrenzen, da nicht klar ist welchen Farbwert dieses fast schwarz letztendlich besitzt. Es ergibt sich "mask". Für das Mean-Shift ist aber noch ein BackProject nötig, von dem ich ganz ehrlich nicht ganz kappiere wofür es gut sein soll. Das ist dann in "dst" dargestellt. Nach dem Mean-Shift ergibt sich dann die Position von "img2". Diese ist aber nicht korrekt. Auch mit viel rumspielen gelingt es mir nicht eine sichere Positionsbestimmung zu machen.
Die Maske ist meiner Meinung nach garnicht so übel, aber dieses BackProjekt-Ergebnis ist irgendwie unschön. Was kann ich tun? Ist das Verfahren dafür gut geeignet oder könnt ihr bessere empfehlen?
Bild

Code: Alles auswählen

import cv2
import numpy as np


def main():
    #Ausschnitt
    r,h,c,w = 250,50,250,20
    #Fenster
    track_window = (c,r,w,h)
    #Bild einlesen
    img = cv2.imread('test.jpg')
    img1 = cv2.rectangle(img.copy(), (r, c), (r+w, c+h), 255, 2)
    cv2.imshow('img', img1)

    #HSV konvertieren
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    cv2.imshow('hsv', hsv)
    #Farben eingrenzen
    mask = cv2.inRange(hsv, np.array((0., 10., 35.)), np.array((180., 60., 50.)))
    cv2.imshow('mask', mask)
    #Histogramm der Farbwerte
    roi_hist = cv2.calcHist([hsv], [0], mask, [180], [0,180])
    #Histogramm auf 0-255 normalisieren
    cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX)
    #Terminierung von Mean-Shift
    term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 100, 0.5)
    dst = cv2.calcBackProject([hsv], [2], roi_hist, [0,255], 1)
    cv2.imshow('dst', dst)
	
    #_, contours, hierarchy = cv2.findContours(dst, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    #ret = cv2.contourArea(contours)
    #dst1 = np.zeros((480,640,3),np.uint8)
    #cv2.drawContours(dst1, contours, -1, [150, 255, 30], cv2.FILLED)
    #cv2.imshow('dst2', dst1)
    
    #Mean-Shift
    ret, track_window = cv2.meanShift(dst, track_window, term_crit)
    #
    x,y,w,h = track_window
    #Rechteck einzeichnen
    img2 = cv2.rectangle(img, (x, y), (x+w, y+h), 255, 2)
    cv2.imshow('img2', img2)

    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    return


if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

So wie ich meanShift verstehe dient das dazu, eine gefunden Struktur von der man annimmt, das sie sich nicht allzuweit entfernt hat vom Ursprungsort zu "tracken", also nachzuverfolgen.

Als 'Fingerabdruck' fuer diesen Suchprozess dient das Histogramm. Es wird also ausgehend von einer vorherigen bekannten Position ein Fenster so weit verschoben, bis man ein Maximum der Uebereinstimmung an einem neuen Ort hat.

Damit ist das Ganze meines Erachtens ungeeignet fuer dein Problem, zumindest mal so, wie du es verwendest. Denn du schneidest ja irgendwo ein Rechteck aus - das ist ja gar nicht genau der Punkt, den du tracken willst.

Man koennte jetzt da irgendwie rumroedeln, und versuchen, dass zurechtzubiegen, indem man sich ein Histogramm vom praezise ausgeschnittenen Punkt einmal erzeugt, und dann immer von einer ungefaehren Position die der Punkt meistens hat versucht zu finden.

Einfacher waere aber fuer dein Problem (so wie es sich zumindest in deinem Foto darstellt) ein Template-Matching zu machen. Dazu musst du ein Quadrat um den Punkt als Template ausschneiden, und das dann im Bild suchen lassen. Zu dem Thema finden sich diverse Beispielskripte.

Ggf musst du vorher noch zB ein adaptive Thresholding durchfuehren, um ein schoenes klares schwarz/weiss-Bild zu bekommen. Darauf basieren dann das Template, und die Suche durchfuehren.
LCD-Johny
User
Beiträge: 3
Registriert: Montag 17. Juli 2017, 13:51

Vielen Dank. Templatematching ist zwar aufwendig, da die Größe nicht feststeht und viele Templates benutzt werden müssen, aber es funktioniert schon recht zuverlässig. Wobei sich aufwendig nicht auf mich, als viel mehr auf den Prozessor bezieht :D
Antworten