Suchen von Objekten in Bildern mit OpenCV in Python

Autor: Zen und die Kunst der Computerprogrammierung

1. Einleitung

OpenCV (Open Source Computer Vision) ist eine Open-Source-Computer-Vision-Bibliothek, die auf der BSD-Lizenz basiert und von Intel, Nvidia, der University of California, Berkeley, Open Power, Sony und anderen Forschungseinrichtungen gemeinsam entwickelt und gepflegt wird. OpenCV unterstützt eine Vielzahl von Programmiersprachen, darunter C++, Python, Java und MATLAB. OpenCV kann in der Echtzeit-Videoverarbeitung, Bildanalyse, maschinellen Lernen und anderen Bereichen eingesetzt werden. In diesem Artikel wird erklärt, wie Sie OpenCV in Python verwenden, um Ziele in Bildern zu erkennen und zu identifizieren. Zunächst müssen Sie die entsprechenden Module importieren:

import cv2 as cv
import numpy as np

2. Erläuterung grundlegender Konzepte und Begriffe

2.1. Zielerkennung

Die Objekterkennung stellt eine wichtige Richtung im Bereich des Computersehens dar. Ihr Hauptzweck besteht darin, interessierende Objekte automatisch aus einem oder mehreren Bildern zu erkennen und ihnen Klassifizierungs- und Positionierungsinformationen zu geben. Vereinfacht ausgedrückt geht es darum, einige scheinbar unabhängige Objekte auf einem Bild zu finden, ihre Position zu bestimmen und sie mit rechteckigen Kästchen zu markieren. Es gibt zwei typische Methoden zur Zielerkennung: Die erste basiert auf dem Template-Matching, die zweite auf Faltungs-Neuronalen Netzen (Convolutional Neural Networks, CNNs). In diesem Artikel werden CNNs zur Zielerkennung verwendet.

2.2. Zielerkennung basierend auf Template-Matching

Die Objekterkennung basierend auf dem Vorlagenabgleich ist die einfachste und direkteste Methode. Die Grundidee dieser Methode besteht darin, eine Reihe von „Vorlagen“ fester Größe zu verwenden, um das gesamte Bild zu scannen. Wenn die Wahrscheinlichkeit, dass eine Vorlage mit einem bestimmten Bereich des Bildes übereinstimmt, höher als ein voreingestellter Schwellenwert ist, ist dies der Fall Es wurde davon ausgegangen, dass dieser Bereich ein Ziel enthalten könnte. Der Nachteil dieser Methode besteht darin, dass sie leicht durch Faktoren wie Beleuchtung, Textur, Form, Farbe usw. beeinflusst wird und die Position der Vorlage vom Ziel abweicht.

2.3. Faltungs-Neuronale Netze (CNNs)

Faltungs-Neuronale Netze (CNNs) stellen eines der Grundmodelle im Bereich Deep Learning dar. Sie können Bildmerkmale durch Merkmalsextraktoren extrahieren, die auf Faltungsschichten und Pooling-Schichten basieren. Im Gegensatz zu herkömmlichen neuronalen Netzen mit linearen Aktivierungsfunktionen verwenden CNNs normalerweise einen Faltungskern mit einer Schrittgröße von 1, um einen globalen End-to-End-Merkmalsextraktionsprozess zu erreichen und gleichzeitig das Problem der Abhängigkeit zwischen Pixeln zu vermeiden. Daher eignen sich CNNs besonders für Klassifizierungsaufgaben von Bild- oder Videodatensätzen.

2.4. Genauigkeitsbewertungsindex der Zielerkennung

Im Zielerkennungsprozess ist es notwendig, die Genauigkeit des Modells zu berechnen und die Konsistenz zwischen den vom Modell vorhergesagten Ergebnissen und den tatsächlichen Etiketten zu messen. Zu den häufig verwendeten Indikatoren zur Genauigkeitsbewertung gehören Präzision, Rückruf, F1-Score, mAP usw. Unter diesen stellt die Präzision das Verhältnis der Anzahl der erkannten positiven Fälle zur Anzahl der erkannten Fälle dar, d. h. TP/(TP+FP), wobei TP für echte Positive und FP für falsche Positive steht; der Rückruf stellt das Verhältnis der Anzahl dar der erkannten positiven Fälle zur tatsächlichen Anzahl. Das Verhältnis der Anzahl positiver Beispiele, d. h. TP/(TP+FN), wobei FN falsch negative Fälle darstellt. Der F1-Score ist der harmonische Durchschnitt von Präzision und Erinnerung. mAP (mean Average Precision) ist eine umfassende Auswertung des durchschnittlichen Präzisionswerts für jede Kategorie.

2.5.YOLO (You Only Look Once) wird verwendet

Der YOLO-Algorithmus ist derzeit einer der am weitesten verbreiteten Zielerkennungsalgorithmen. Er wurde vom Entwickler des Darknet-Projekts und seinem Schüler Alexey und anderen vorgeschlagen und basiert auf einem Faltungs-Neuronalen Netzwerk. Dieser Algorithmus bietet ganz herausragende Vorteile in Bezug auf Geschwindigkeit, Genauigkeit und einfache Bereitstellung. Der YOLO-Algorithmus unterteilt das Eingabebild in S x S-Gitter (Zellen), und jedes Gitter ist für die Vorhersage der Wahrscheinlichkeit von B-Begrenzungsrahmen und C-Objektklassen verantwortlich, wobei S = 7, B = 2 und C = 20. Der YOLO-Algorithmus verwendet ein Faltungs-Neuronales Netzwerk, um eine nicht maximale Unterdrückung (NMS) an der Ausgabe jedes Gitters durchzuführen und den Zielbegrenzungsrahmen mit der höchsten Zuverlässigkeit auszuwählen.

3. Erläuterung der Grundprinzipien des Algorithmus, spezifischer Arbeitsschritte und mathematischer Formeln

3.1. Vorbereitung

Laden Sie die Funktion imread() von OpenCV, um das zu erkennende Bild zu lesen, konvertieren Sie es dann in ein Graustufenbild und konvertieren Sie den Farbraum über die Funktion cvtColor() in HSV. Erstellen Sie dann eine Kopie des Originalbilds, um das gezeichnete Ergebnis anzuzeigen.

gray_image = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
result_image = image.copy()

3.2.Schwellenwertparameter einstellen

Die vom YOLO-Algorithmus verwendeten Kategorien sind der COCO-Datensatz, und die Anzahl der Kategorien beträgt 20, also von 0 bis 19. Standardmäßig unterteilt der YOLO-Algorithmus das Ziel eines Bildes in ein 7x7-Raster, und jedes Raster sagt zwei Begrenzungsrahmen und die Wahrscheinlichkeit voraus, dass jeder Begrenzungsrahmen 20 Kategorien enthält. Daher beträgt die Gesamtzahl der Ausgänge pro Gitter $(7\times 7 + 2)\times 20$=970. Als nächstes werden verschiedene Hyperparameter definiert, wie z. B. Netzwerkstruktur, IOU-Schwellenwert, Konfidenz usw., die hier nicht beschrieben werden.

IMAGE_SIZE = (416, 416) # 设置输入图片尺寸
CLASS_NAMES = ["person", "bicycle", "car", "motorcycle",
               "airplane", "bus", "train", "truck", 
               "boat", "traffic light", "fire hydrant", 
               "stop sign", "parking meter", "bench", 
               "bird", "cat", "dog", "horse", "sheep", 
               "cow", "elephant", "bear", "zebra", 
               "giraffe"]   # 类别名称列表
ANCHORS = [[10, 13], [16, 30], [33, 23],
           [30, 61], [62, 45], [59, 119], 
           [116, 90], [156, 198], [373, 326]] # 锚框列表
CONFIDENCE_THRESHOLD = 0.5     # 置信度阈值
IOU_THRESHOLD = 0.45            # IOU阈值

3.3. Bildgröße und Zoom ändern

Nachdem das Bild auf die angegebene Größe skaliert wurde, werden der Begrenzungsrahmen und die Konfidenz proportional zur Eingabebildgröße skaliert, um sie an die endgültige Ausgabegröße anzupassen.

def resize_with_pad(img):
    h, w = img.shape[:2]
    size = IMAGE_SIZE[0] if max(w, h) == size else min(IMAGE_SIZE)

    fx = fy = float(size)/max(h, w)
    new_h, new_w = int(h*fx), int(w*fy)

    resized = cv.resize(img, (new_w, new_h))

    canvas = np.full((IMAGE_SIZE[0], IMAGE_SIZE[1], 3), 128, dtype="uint8")

    dx = (canvas.shape[1]-resized.shape[1])//2
    dy = (canvas.shape[0]-resized.shape[0])//2

    canvas[dy:dy+resized.shape[0],dx:dx+resized.shape[1],:] = resized

    return canvas, (new_w/w, new_h/h)

3.4. Ankerbox generieren

Die Ankerbox ist die kleinste rechteckige Box, die zur Erkennung des Ziels verwendet wird. Da Objekte unterschiedlicher Größe unterschiedliche Größen haben, müssen Ankerkästen unterschiedlicher Größe berechnet werden. Anschließend wird die Schiebefenstermethode verwendet, um Ankerkästen unterschiedlicher Proportionen zu generieren. Der folgende Code durchläuft zunächst alle Ankerkästen, berechnet dann deren Koordinatenbereich im Originalbild und generiert dann mithilfe eines Schiebefensters Ankerkästen mit unterschiedlichen Maßstäben.

def generate_anchors():
    anchors = []
    for anchor in ANCHORS:
        base_size = max(anchor)//2

        num_x = math.floor(math.sqrt(anchor[0]/base_size)*NUM_ANCHOR_SCALES[0])
        num_y = math.floor(math.sqrt(anchor[1]/base_size)*NUM_ANCHOR_SCALES[1])

        cx, cy = [], []
        ws, hs = [], []
        step_x = 1./num_x 
        step_y = 1./num_y 

        for j in range(num_y):
            for i in range(num_x):
                cx.append(step_x/2.+i*step_x)
                cy.append(step_y/2.+j*step_y)

                ws.append(float(anchor[0])/IMAGE_SIZE[0]*base_size)
                hs.append(float(anchor[1])/IMAGE_SIZE[1]*base_size)

        anchors += [(cx[a], cy[a], ws[a], hs[a]) for a in range(len(ws))]

    return anchors

3.5.Training des YOLO-Modells

Das YOLO-Modell basiert auf dem VGG16-Netzwerk. Es extrahiert zunächst Features über ein Faltungs-Neuronales Netzwerk und berechnet dann mithilfe des YOLO-Algorithmus den Begrenzungsrahmen und die Konfidenz des Ziels auf der Feature-Map. Schließlich werden der Begrenzungsrahmen und die Konfidenz kombiniert, um die mAP-Metrik zu berechnen.

model = yolo_v3(input_shape=(IMAGE_SIZE[0], IMAGE_SIZE[1], 3))
optimizer = keras.optimizers.Adam(lr=LEARNING_RATE)
loss = YOLOLoss(anchors, NUM_CLASSES)

model.compile(optimizer=optimizer, loss=loss)

history = model.fit(X_train, y_train, epochs=EPOCHS, 
                    batch_size=BATCH_SIZE, validation_data=(X_val, y_val),
                    callbacks=[ModelCheckpoint("best_model.h5", save_weights_only=True)])

scores = model.evaluate(X_test, Y_test, verbose=0)
print("Accuracy: {:.2f}%".format(scores[1]*100))

3.6. Führen Sie den Test durch

Der Erkennungsprozess läuft wie folgt ab: Zuerst wird das Originalbild vorverarbeitet und dann zur Vorhersage an das Modell gesendet. Anschließend wird es basierend auf dem vorhergesagten Begrenzungsrahmen weiter skaliert, verzerrt und zugeschnitten, und schließlich wird ein Erkennungsergebnis in der gleichen Größe wie das Originalbild erhalten. Abschließend werden die Testergebnisse angezeigt.

def detect_objects(image):
    original_size = image.shape[:-1][::-1]    # 获取原始图片的尺寸

    input_img, scale = resize_with_pad(image)      # 按照指定尺寸缩放图片

    input_img /= 255.                             # 将图片归一化至0~1之间

    detections = model.predict(np.expand_dims(input_img, axis=0))[0]  # 使用模型进行预测

    results = postprocess(detections, SCALES, ANCHORS, NUM_CLASSES, confidence_threshold=CONFIDENCE_THRESHOLD)  # 对检测结果进行后处理

    draw_boxes(original_size, result_image, results)               # 在原始图片上绘制检测结果

    display_image(result_image)                                  # 展示检测结果

Ich denke du magst

Origin blog.csdn.net/universsky2015/article/details/133504602
Empfohlen
Rangfolge