Maske-R CNN vom Anfänger bis zum Profi


Nachdem ich die Informationen aus dem Bild und an der Ausgabe analysieren musste, um den Typ des Objekts und den Typ zu ermitteln, sowie die Menge der Bilder zu analysieren, musste ich die Kennung des Objekts und die im Bild verbrachte Zeit angeben, um festzustellen, wie sich das Objekt bewegte und welche Kameras sichtbar wurden. Beginnen wir vielleicht mit den ersten beiden. Die Analyse des Personals im Aggregat wird im nächsten Teil erörtert.


Nun, wir werden unsere Aufgaben detaillierter beschreiben:


  • Repariere Personen und Autos - wähle sie im Bild aus und generiere die entsprechenden Klasseninstanzen mit den erforderlichen Feldern.
  • Bestimmen Sie die Nummer des Autos, wenn es in den Rahmen einer bestimmten Kamera gefallen ist
  • Vergleichen Sie den aktuellen Frame mit dem vorherigen, um die Gleichheit der Objekte zu ermitteln

Ok, dachte ich und nahm eine dicke Schlange, Python, das heißt. Es wurde beschlossen, das neuronale Netz Mask R-Cnn in Verbindung mit seiner Einfachheit und den modernen Funktionen zu verwenden . Natürlich werden wir auch OpenCV für die Bildbearbeitung verwenden.


Umgebungs-Setup


Wir werden Windows 10 verwenden, da es sehr wahrscheinlich ist, dass Sie es verwenden.
Es versteht sich, dass Sie bereits 64-Bit-Python haben. Wenn nicht, können Sie das Paket beispielsweise von hier herunterladen


Paketinstallation


git clone https://github.com/matterport/Mask_RCNN cd Mask_RCNN pip3 install -r requirements.txt python3 setup.py install 

Wenn es aus irgendeinem Grund nicht möglich ist, aus dem Quellcode zu kompilieren, gibt es eine Version von pip:


 pip3 install mrcnn --user 

Das Paket enthält natürlich alle Abhängigkeiten .


Stufe 1. Erstellen eines einfachen Erkenners.


Wir werden die notwendigen Importe machen


 import os import cv2 import mrcnn.config import mrcnn from mrcnn.model import MaskRCNN 

Für ein neuronales Netzwerk muss eine Konfiguration mit überschriebenen Feldern erstellt werden


 class MaskRCNNConfig(mrcnn.config.Config): NAME = "coco_pretrained_model_config" GPU_COUNT = 1 IMAGES_PER_GPU = 1 DETECTION_MIN_CONFIDENCE = 0.8 #     NUM_CLASSES = 81 

Geben Sie den Speicherort der Datei mit der Waage an. Lassen Sie es sich in diesem Beispiel in dem Ordner mit dieser Datei befinden. Wenn dies nicht der Fall ist, wird es heruntergeladen.


 import mrcnn.utils DATASET_FILE = "mask_rcnn_coco.h5" if not os.path.exists(DATASET_FILE): mrcnn.utils.download_trained_weights(DATASET_FILE) 

Lassen Sie uns unser Modell mit den obigen Einstellungen erstellen


 model = MaskRCNN(mode="inference", model_dir="logs", config=MaskRCNNConfig()) model.load_weights(DATASET_FILE, by_name=True) 

Und vielleicht beginnen wir mit der Verarbeitung aller Bilder im images des aktuellen Verzeichnisses.


 IMAGE_DIR = os.path.join(os.getcwd(), "images") for filename in os.listdir(IMAGE_DIR): image = cv2.imread(os.path.join(IMAGE_DIR, filename)) rgb_image = image[:, :, ::-1] detections = model.detect([rgb_image], verbose=1)[0] 

Was werden wir in Entdeckungen sehen?


  print(detections) 

Zum Beispiel etwas Ähnliches:


 {'rois': array([[ 303, 649, 542, 1176],[ 405, 2, 701, 319]]), 'class_ids': array([3, 3]), 'scores': array([0.99896, 0.99770015], dtype=float32), 'masks': array()} 

In diesem Fall wurden 2 Objekte gefunden.
rois - Koordinatenfelder der unteren linken und oberen rechten Ecke
class_ids - numerische Bezeichner der gefundenen Objekte, wobei wir wissen müssen, dass 1 eine Person, 3 ein Auto und 8 ein Lastwagen ist.
scores - Soweit das Modell von der Lösung überzeugt ist, kann dieser Parameter über DETECTION_MIN_CONFIDENCE in der Konfiguration DETECTION_MIN_CONFIDENCE werden, wodurch alle unangemessenen Optionen abgeschnitten werden.
masks - die Kontur des Objekts. Daten werden zum Zeichnen einer Objektmaske verwendet. Weil Sie sind recht umfangreich und nicht für das menschliche Verständnis gedacht, ich werde sie im Artikel nicht zitieren.


Ok, wir könnten hier aufhören, aber wir wollen uns das Bild ansehen, das Anleitungen zur Verwendung neuronaler Netze mit schön ausgewählten Objekten normalerweise geben?


Es wäre einfacher, die Funktion mrcnn.visualize.display_instances , aber wir werden dies nicht tun, wir werden unsere eigene schreiben.


Die Funktion nimmt ein Bild auf und die wichtigsten Parameter werden aus dem Wörterbuch der ersten Schritte ermittelt.


 def visualize_detections(image, masks, boxes, class_ids, scores): import numpy as np bgr_image = image[:, :, ::-1] CLASS_NAMES = ['BG',"person", "bicycle", "car", "motorcycle", "bus", "truck"] COLORS = mrcnn.visualize.random_colors(len(CLASS_NAMES)) for i in range(boxes.shape[0]): y1, x1, y2, x2 = boxes[i] classID = class_ids[i] label = CLASS_NAMES[classID] font = cv2.FONT_HERSHEY_DUPLEX color = [int(c) for c in np.array(COLORS[classID]) * 255] text = "{}: {:.3f}".format(label, scores[i]) size = 0.8 width = 2 cv2.rectangle(bgr_image, (x1, y1), (x2, y2), color, width) cv2.putText(bgr_image, text, (x1, y1-20), font, size, color, width) 


Quellbild


Obwohl einer der Hauptvorteile dieses neuronalen Netzwerks die Lösung der Probleme der Instanzsegmentierung ist - das Erhalten der Konturen von Objekten, haben wir es noch nicht verwendet, wir werden es analysieren.


Fügen Sie zum Implementieren von Masken ein paar Linien hinzu, bevor Sie für jedes gefundene Objekt ein Rechteck zeichnen.


 mask = masks[:, :, i] #   image = mrcnn.visualize.apply_mask(image, mask, color, alpha=0.6) #   

Ergebnis:


Version mit weißen Masken


Stufe II. Erste Erfolge. Erkennung der Anzahl der Autos.


Zur Erkennung benötigen wir einen klaren Rahmen des Autos in der Nähe, daher wurde beschlossen, nur Rahmen vom Kontrollpunkt zu nehmen und diese dann mit Ähnlichkeiten zu vergleichen (mehr dazu im nächsten Kapitel). Diese Methode ergibt jedoch zu viel Ungenauigkeit, weil Maschinen können visuell sehr ähnlich sein und mein Algorithmus kann solche Situationen noch nicht vermeiden.


Es wurde beschlossen, eine fertige Bibliothek des ukrainischen Herstellers nomeroff-net zu verwenden (keine Werbung). Weil Fast der gesamte Code befindet sich in den Beispielen für das Modell. Ich werde dann keine vollständige Beschreibung geben.


Ich kann nur sagen, dass diese Funktion mit dem Originalbild gestartet werden kann oder die erkannte Maschine aus dem Rahmen ausgeschnitten und an diese Funktion übergeben werden kann.


 import sys import matplotlib.image as mpimg import os sys.path.append(cfg.NOMEROFF_NET_DIR) from NomeroffNet import filters, RectDetector, TextDetector, OptionsDetector, Detector, textPostprocessing nnet = Detector(cfg.MASK_RCNN_DIR, cfg.MASK_RCNN_LOG_DIR) nnet.loadModel("latest") rectDetector = RectDetector() optionsDetector = OptionsDetector() optionsDetector.load("latest") textDetector = TextDetector.get_static_module("ru")() textDetector.load("latest") def detectCarNumber(imgPath: str) -> str: img = mpimg.imread(imgPath) NP = nnet.detect([img]) cvImgMasks = filters.cv_img_mask(NP) arrPoints = rectDetector.detect(cvImgMasks) zones = rectDetector.get_cv_zonesBGR(img, arrPoints) regionIds, stateIds, _c = optionsDetector.predict(zones) regionNames = optionsDetector.getRegionLabels(regionIds) # find text with postprocessing by standart textArr = textDetector.predict(zones) textArr = textPostprocessing(textArr, regionNames) return textArr 

Der AusgabetextArr repräsentiert ein Array von Zeichenfolgen mit der Anzahl der auf dem Frame gefundenen Computer. Beispiel:
["293163"] oder [""] , [] - wenn keine übereinstimmenden Nummern gefunden wurden.


Stufe III. Identifizieren Sie Objekte anhand ihrer Ähnlichkeit.


Jetzt müssen wir verstehen, wie ein Objekt einmal repariert wird, um zu verstehen, dass es sich im nächsten Frame um ihn handelt. In diesem Stadium gehen wir davon aus, dass wir nur eine Kamera haben und nur zwischen verschiedenen Frames unterscheiden.


Dazu müssen Sie herausfinden, wie wir die beiden Objekte vergleichen.


Ich werde für diese Zwecke einen Siebalgorithmus vorschlagen. Wir machen eine Reservierung, dass es nicht Teil des Hauptteils von OpenCV ist, deshalb müssen wir Contrib-Module zusätzlich liefern. Leider ist der Algorithmus patentiert und seine Verwendung in kommerziellen Programmen ist begrenzt. Aber wir konzentrieren uns auf Forschungsaktivitäten, oder?


 pip3 install opencv-contrib-python --user 

~~ Überladen Sie den Operator == ~~ Wir schreiben eine Funktion, die 2 verglichene Objekte in Form von Matrizen nimmt. Zum Beispiel bekommen wir sie nach dem Aufruf der Funktion cv2.open(path)


Wir werden eine Implementierung unseres Algorithmus schreiben.


 def compareImages(img1, img2) -> bool: sift = cv2.xfeatures2d.SIFT_create() 

Finden Sie wichtige Punkte und Deskriptoren mit SIFT. Vielleicht help(somefunc) ich für diese Funktionen keine Hilfe an, da Sie sie in der interaktiven Shell immer als help(somefunc)


  kp1, des1 = sift.detectAndCompute(img1, None) kp2, des2 = sift.detectAndCompute(img2, None) 

Richten Sie unseren Algorithmus ein.


  FLANN_INDEX_KDTREE = 0 indexParams = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) searchParams = dict(checks=50) flann = cv2.FlannBasedMatcher(indexParams, searchParams) 

Führen Sie es jetzt aus.


  matches = flann.knnMatch(des1, des2, k=2) 

Zählen Sie die Ähnlichkeiten zwischen den Bildern.


  matchesCount = 0 for m, n in matches: if m.distance < cfg.cencitivity*n.distance: matchesCount += 1 return matchesCount > cfg.MIN_MATCH_COUNT 

Versuchen Sie jetzt, es zu verwenden
Dazu müssen wir nach dem Erkennen von Objekten diese aus dem Originalbild ausschneiden


Ich könnte nichts besseres schreiben, als es für langsames Gedächtnis zu speichern und dann von dort zu lesen.


  def extractObjects(objects, binaryImage, outputImageDirectory, filename=None): for item in objects: y1, x1, y2, x2 = item.coordinates #       cropped = binaryImage[y1:y2, x1:x2] beforePoint, afterPoint = filename.split(".") outputDirPath = os.path.join(os.path.split(outputImageDirectory)[0], "objectsOn" + beforePoint) if not os.path.exists(outputDirPath): os.mkdir(outputDirPath) coordinates = str(item).replace(" ", ",") pathToObjectImage = "{}{}.jpg".format(item.type, coordinates) cv2.imwrite(os.path.join(outputDirPath, str(pathToObjectImage)), cropped) 

Jetzt haben wir die Objekte im <outputImageDirectory>/objectsOn<imageFilename>


Wenn wir mindestens zwei solcher Verzeichnisse haben, können wir die darin enthaltenen Objekte vergleichen. Führen Sie die zuvor geschriebene Funktion aus


 if compareImages(previousObjects, currentObjects): print(“  !”) 

Oder wir können eine andere Aktion ausführen, z. B. diese Objekte mit demselben Bezeichner kennzeichnen.


Natürlich neigt dieses Netzwerk, wie alle neuronalen Netze, manchmal zu fehlerhaften Ergebnissen.


Im Allgemeinen haben wir die 3 Aufgaben erledigt, die zu Beginn festgelegt wurden, sodass wir abrunden werden. Ich bezweifle, dass dieser Artikel die Augen von Leuten geöffnet hat, die mindestens ein Programm geschrieben haben, das die Probleme der Bilderkennung / Bildsegmentierung löst, aber ich hoffe, dass ich mindestens einem unerfahrenen Entwickler geholfen habe.


Den vollständigen Quellcode des Projekts finden Sie hier .

Source: https://habr.com/ru/post/de483018/


All Articles