Zuvor habe ich einen Artikel wie diesen geschrieben (lassen Sie uns rote Objekte mit Python erkennen) (http://qiita.com/odaman68000/items/ae28cf7bdaf4fa13a65b). Es ist eine Methode, um einfach ein Bild in HSV (Farbton, Sättigung, Wert) umzuwandeln und eine Region mit einer starken roten Komponente zu finden.
Betrachten wir dieses Mal ein "grünes" Objekt als Anwendung. Und dann werde ich über das "Verfolgen" von Objekten in einem kontinuierlichen Videostream sprechen. Wenn Sie sich den kontinuierlichen Videostream genau ansehen, handelt es sich um ein kontinuierliches Standbild. Wenn Sie das grüne Objekt anhand dieses Standbilds weiterhin erkennen, können Sie es auf natürliche Weise verfolgen. Es ist kein großer Fehler, das zu denken. Es gibt jedoch eine Kamera, die sich vom menschlichen Auge unterscheidet. Wenn der Winkel des Zielobjekts ein wenig abweicht, leuchtet es je nach Lichtmenge weiß und weicht vom Urteil ab (das Urteil schlägt fehl und Sie verlieren es aus den Augen), der Beurteilungspunkt fliegt herum oder Sie verlieren es aus den Augen, selbst wenn sich das Umgebungslicht ein wenig ändert. Es ist. Was passiert, wenn sich schlechte Bedingungen überschneiden und Sie dies aus den Augen verlieren? Der Computer stellt fest, dass das Objekt "nicht vorhanden" ist. Aber im nächsten Moment können sich die Bedingungen verbessern und wieder auftreten. Es erscheint und verschwindet, es erscheint wieder und es gibt überhaupt kein Gefühl von Stabilität, und eine 100% ige Erkennungsgenauigkeit kann nicht immer erwartet werden.
Daher ist es notwendig, die Idee aufzugeben, dass ein Standbild jedes Mal analysiert werden sollte, selbst wenn es sich um einen Videostream handelt, und den Videostream als "kontinuierliches Standbild" zu überdenken. Mit anderen Worten, es sollte vorhergesagt und durchsucht werden, indem die Idee der Wahrscheinlichkeit und Statistik voll genutzt wird, dass "es hier sein sollte, weil es das letzte Mal hier war".
Es gibt gute Möglichkeiten, diese Probleme zu lösen. Es wird "Partikelfilter" genannt. Ich weiß nicht genug, um die akademische Definition und den Inhalt des Partikelfilters zu erklären, deshalb möchte ich es vielen anderen Kommentarseiten überlassen. Konzeptionell jedoch Bildanalyse mit einem Partikelfilter
Wenn Sie diese Verfahren 1 bis 5 fortsetzen, können Sie natürlich das oben genannte erreichen. Der Zustand "Ich war das letzte Mal hier" wird von den verstreuten Partikeln in Erinnerung gerufen, und für jedes Partikel: "Ist es diese Seite als nächstes?" Und wiederholt das zufällige Bewegen der Partikel. Schlechte Partikel, die die Vorhersage weiterhin beeinträchtigen, werden eliminiert. Partikel sagen verzweifelt den nächsten Frame voraus und überleben w Es fühlt sich unerwartet grausam an und es scheint, dass selbst Anhaftungen, dass Partikel schwierig sind (lügen).
Es ist ziemlich schwierig, diese Reihe von Prozessen in C / C ++ zu beschreiben, aber hauptsächlich aufgrund der Kraft von Numpy ist es ein großartiges Tokoro von Python + Numpy, dass eine kleine Menge Code erforderlich ist.
Zunächst zum Import. Es wird davon ausgegangen, dass Sie wie folgt importiert haben.
import cv2
import numpy as np
Definieren Sie zunächst die Struktur der Partikel. Lassen Sie uns wie folgt vorgehen. "x" und "y" sind die Positionen der Teilchen und "Gewicht" ist die Wahrscheinlichkeit (Gewicht).
particle = [x, y, weight]
Erstellen Sie als Nächstes eine Funktion zur Berechnung der Wahrscheinlichkeit (des Gewichts) der Partikel.
Diese Funktion scannt einen Bereich von 30 x 30 Pixel um die angegebenen Koordinaten und gibt den Prozentsatz von 900 Pixel zurück, der die Kriterien erfüllt. Wenn beispielsweise der Bereich von 30 x 30 Pixel alle NG ist, ein Wert von 0,0, wenn alle in Ordnung sind, ein Wert von 1,0, und wenn ungefähr die Hälfte in Ordnung ist, wird ein Wert von ungefähr 0,5 zurückgegeben.
Die Entscheidungsfunktion func ()
ist out und ermöglicht es dem Aufrufer, die Entscheidungsfunktion anzugeben.
def likelihood(x, y, func, image, w=30, h=30):
x1 = max(0, x - w / 2)
y1 = max(0, y - h / 2)
x2 = min(image.shape[1], x + w / 2)
y2 = min(image.shape[0], y + h / 2)
region = image[y1:y2, x1:x2]
count = region[func(region)].size
return (float(count) / image.size) if count > 0 else 0.0001
Als nächstes folgt die Partikelinitialisierungsfunktion.
Der Parameter func
soll die Entscheidungsfunktion angeben, die wie zuvor ausgehen soll.
Diese Funktion erzeugt viele (500) dieser Partikel.
Als Anfangswert werden die Partikel in der Nähe des größten Bereichs in dem durch die Funktion "func ()" bestimmten Bereich positioniert.
Die "500" von "(500, 3)", die im Aufruf von "np.ndarray ()" angegeben ist, ist die Anzahl der Partikel, und "3" ist die Anzahl der Elemente der obigen "x", "y", "weight". ist.
def init_particles(func, image):
mask = image.copy()
mask[func(mask) == False] = 0
contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) <= 0:
return None
max_contour = max(contours, key=cv2.contourArea)
max_rect = np.array(cv2.boundingRect(max_contour))
max_rect = max_rect[:2] + max_rect[2:] / 2
weight = likelihood(max_rect[0], max_rect[1], func, image)
particles = np.ndarray((500, 3), dtype=np.float32)
particles[:] = [max_rect[0], max_rect[1], weight]
return particles
Dies ist der Teil der Bewegung des Partikelfilters im eigentlichen Sinne. Der Partikelfilter durchläuft die folgenden vier Verfahren.
Beim Resampling unter Verwendung von Zufallszahlen werden Partikel mit schlechten Qualitäten eliminiert und durch Partikel mit guten Qualitäten ersetzt.
Die Methode cumsum ()
, mit der das Array weight
erstellt wird, berechnet die kumulative Summe.
Wenn Sie "(weight> weight) .argmax ()" einstellen, wird das Array "weight" gescannt und der Array-Index wird zurückgegeben, wenn zum ersten Mal ein Wert angezeigt wird, der größer als "weight" ist.
def resample(particles):
tmp_particles = particles.copy()
weights = particles[:, 2].cumsum()
last_weight = weights[weights.shape[0] - 1]
for i in xrange(particles.shape[0]):
weight = np.random.rand() * last_weight
particles[i] = tmp_particles[(weights > weight).argmax()]
particles[i][2] = 1.0
Bewegen Sie die Partikel tatsächlich zum nächsten Frame. Addiere den Koeffizienten, der durch "Varianz" multipliziert mit dem Ergebnis von "numpy.random.randn ()" angegeben wird. Dieser "Varianz" -Koeffizient ist ein numerischer Wert, der entsprechend der Intensität der Bewegung des Ziels eingestellt werden sollte. Die zufällige Bewegung von Partikeln wird als "Vorhersage" bezeichnet. Teilchen, die sich zufällig in die gute Richtung bewegen, überleben, und Teilchen, die sich zufällig in die falsche Richtung bewegen, sind dazu bestimmt, beseitigt (überschrieben) zu werden.
def predict(particles, variance=13.0):
particles[:, 0] += np.random.randn((particles.shape[0])) * variance
particles[:, 1] += np.random.randn((particles.shape[0])) * variance
Bestimmen Sie die Wahrscheinlichkeit (Gewicht) für jedes Partikel. Es wird das Material sein, um das Ergebnis der vorherigen Vorhersage zu beurteilen. Diese Wahrscheinlichkeit (Gewichtung) wird berechnet, indem die zuvor erstellte Funktion "Wahrscheinlichkeit ()" aufgerufen wird.
def weight(particles, func, image):
for i in xrange(particles.shape[0]):
particles[i][2] = likelihood(particles[i][0], particles[i][1], func, image)
sum_weight = particles[:, 2].sum()
particles[:, 2] *= (particles.shape[0] / sum_weight)
Messen Sie die Partikel, um den Ort in der Nähe der Konzentration der guten Partikel zu bestimmen.
def measure(particles):
x = (particles[:, 0] * particles[:, 2]).sum()
y = (particles[:, 1] * particles[:, 2]).sum()
weight = particles[:, 2].sum()
return x / weight, y / weight
Schließlich wird die bisher implementierte Verarbeitung wie eine Utility-Funktion zusammengefasst. Wenn während des durch das Argument angegebenen "max_frame" keine grüne Komponente gefunden wird, werden die Partikel neu initialisiert.
particle_filter_cur_frame = 0
def particle_filter(particles, func, image, max_frame=10):
global particle_filter_cur_frame
if image[func(image)].size <= 0:
if particle_filter_cur_frame >= max_frame:
return None, -1, -1
particle_filter_cur_frame = min(particle_filter_cur_frame + 1, max_frame)
else:
particle_filter_cur_frame = 0
if particles is None:
particles = init_particles(func, image)
if particles is None:
return None, -1, -1
resample(particles)
predict(particles)
weight(particles, func, image)
x, y = measure(particles)
return particles, x, y
Erstellen wir also ein Programm, das grüne Objekte mithilfe der bisher implementierten Partikelfilter verfolgt. Hier werden die von "cv2.VideoCapture ()" erfassten Rahmendaten (BGR-Bild) in HSV konvertiert, und S (Sättigung) und V (Wert) werden mit dem Schwellenwert von OTSU multipliziert, und die Farbtiefe und Helligkeit werden multipliziert. In beiden Fällen wird der Prozess ausgeführt, bei dem nur genügend Pixel verwendet werden (die H-Komponente wird mit durchlaufenden Pixeln von S und V maskiert und mit 0 gefüllt). Ich möchte den Bereich von Grün (50-85) finden, daher ist es sinnvoll, 0 zu löschen. (Wenn Sie dagegen Rot erkennen, ist es seltsam, wenn Sie es nicht mit einem anderen Wert als 0 füllen.)
Was tatsächlich an die Funktion "Particle_Filter ()" übergeben wird, ist die oben gefilterte H-Komponente. Danach denke ich, dass die Funktion Partikel_Filter ()
die Partikel verwaltet und den grünen Teil gut verfolgt.
import cv2
import numpy as np
if __name__ == "__main__":
def is_green(region):
return (region >= 50) | (region < 85)
cap = cv2.VideoCapture(0)
particles = None
while cv2.waitKey(30) < 0:
_, frame = cap.read()
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV_FULL)
frame_h = frame_hsv[:, :, 0]
_, frame_s = cv2.threshold(frame_hsv[:, :, 1], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
_, frame_v = cv2.threshold(frame_hsv[:, :, 2], 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU)
frame_h[(frame_s == 0) | (frame_v == 0)] = 0
particles, x, y = particle_filter(particles, is_green, frame_h)
if particles is not None:
valid_particles = particles[(particles[:, 0] >= 0) & (particles[:, 0] < frame.shape[1]) &
(particles[:, 1] >= 0) & (particles[:, 1] < frame.shape[0])]
for i in xrange(valid_particles.shape[0]):
frame[valid_particles[i][1], valid_particles[i][0]] = [255, 0, 0]
p = np.array([x, y], dtype=np.int32)
cv2.rectangle(frame, tuple(p - 15), tuple(p + 15), (0, 0, 255), thickness=2)
cv2.imshow('green', frame)
cap.release()
cv2.destroyAllWindows()
Dieser Partikelfilter ist extrem widerstandsfähig gegen Geräusche und Bewegungen und verfolgt ein Objekt ziemlich hartnäckig. Darüber hinaus ist auch die dadurch erhaltene Erfassungsposition sehr stabil. Sobald Sie den Partikelfilter implementiert haben, ist der Schlüssel meiner Meinung nach die Implementierung der Funktion "Wahrscheinlichkeit ()". Das Leben und der Tod der Partikel hängen von dieser "Wahrscheinlichkeit ()" ab.
Beobachten Sie die verzweifelte Bewegung der Partikel, um zu überleben. Allmählich wird die Verzweiflung jedes Teilchens interessant, die rücksichtslos durch "Wahrscheinlichkeit ()" bewertet wird. Es ist ein Partikelfilter, der genau folgt, aber im Schatten davon werden unzählige Partikel geboren und sterben ab, und Sie können solch harte Trauer spüren.
Recommended Posts