Encontrar objetos en imágenes usando OpenCV en Python

Autor: Zen y el arte de la programación informática

1. Introducción

OpenCV (Open Source Computer Vision) es una biblioteca de visión por computadora de código abierto basada en la licencia BSD, desarrollada y mantenida conjuntamente por Intel, Nvidia, la Universidad de California, Berkeley, Open Power, Sony y otras instituciones de investigación. OpenCV admite una variedad de lenguajes de programación, incluidos C++, Python, Java y MATLAB. OpenCV se puede utilizar en campos como el procesamiento de vídeo en tiempo real, el análisis de imágenes y el aprendizaje automático. Este artículo explicará cómo usar OpenCV en Python para detectar e identificar objetivos en imágenes. Primero, necesita importar los módulos relevantes:

import cv2 as cv
import numpy as np

2. Explicación de conceptos y términos básicos

2.1 Detección de objetivos

La detección de objetos es una dirección importante en el campo de la visión por computadora. Su objetivo principal es detectar automáticamente objetos de interés de una o más imágenes y brindarles información de clasificación y posicionamiento. En pocas palabras, se trata de encontrar algunos objetos aparentemente independientes en una imagen, determinar sus posiciones y marcarlos con cuadros rectangulares. Hay dos métodos típicos de detección de objetivos: el primero se basa en la coincidencia de plantillas; el segundo son las redes neuronales convolucionales (Convolutional Neural Networks, CNN). En este artículo, las CNN se utilizan para la detección de objetivos.

2.2 Detección de objetivos basada en la coincidencia de plantillas

La detección de objetos basada en la coincidencia de plantillas es el método más simple y directo. La idea básica de este método es utilizar una serie de "plantillas" de tamaño fijo para escanear toda la imagen. Si la probabilidad de que una plantilla coincida con un área determinada de la imagen es mayor que un umbral preestablecido, es Consideró que esta zona puede contener una portería. La desventaja de este método es que se ve fácilmente afectado por factores como la iluminación, la textura, la forma, el color, etc., y la posición de la plantilla se desvía del objetivo.

2.3 Redes neuronales convolucionales (CNN)

Las redes neuronales convolucionales (CNN) son uno de los modelos básicos en el campo del aprendizaje profundo y pueden extraer características de imágenes a través de extractores de características construidos utilizando capas convolucionales y capas de agrupación. A diferencia de las redes neuronales tradicionales con funciones de activación lineal, las CNN generalmente utilizan un núcleo de convolución con un tamaño de paso de 1 para lograr un proceso de extracción de características global de un extremo a otro y al mismo tiempo evitar el problema de la dependencia entre píxeles. Por lo tanto, las CNN son particularmente adecuadas para tareas de clasificación de conjuntos de datos de imágenes o videos.

2.4 Índice de evaluación de precisión de la detección de objetivos

En el proceso de detección de objetivos, es necesario calcular la precisión del modelo y medir la coherencia entre los resultados predichos por el modelo y las etiquetas reales. Los indicadores de evaluación de precisión de uso común incluyen precisión, recuperación, puntuación F1, mAP, etc. Entre ellos, la precisión representa la relación entre el número de casos positivos detectados y el número de casos detectados, es decir, TP/(TP+FP), donde TP representa verdaderos positivos y FP representa falsos positivos; el recuerdo representa la relación del número de casos positivos detectados respecto al número real. La relación entre el número de ejemplos positivos, es decir, TP/(TP+FN), donde FN representa falsos negativos. La puntuación F1 es el promedio armónico de precisión y recuperación. mAP (precisión promedio media) es una evaluación integral del valor de precisión promedio para cada categoría.

2.5.YOLO (Sólo miras una vez) 算法

El algoritmo YOLO es uno de los algoritmos de detección de objetivos más utilizados en la actualidad, fue propuesto por el desarrollador del proyecto Darknet y su alumno Alexey y otros, y se implementa sobre la base de una red neuronal convolucional. Este algoritmo tiene ventajas muy destacadas en términos de velocidad, precisión y facilidad de implementación. El algoritmo YOLO divide la imagen de entrada en cuadrículas (celdas) S x S, y cada cuadrícula es responsable de predecir la probabilidad de cuadros delimitadores B y clases de objetos C, donde S = 7, B = 2 y C = 20. El algoritmo YOLO utiliza una red neuronal convolucional para realizar una supresión no máxima (NMS) en la salida de cada cuadrícula para seleccionar el cuadro delimitador objetivo con la mayor confianza.

3. Explicación de los principios básicos del algoritmo, pasos operativos específicos y fórmulas matemáticas.

3.1 Preparación

Cargue la función imread () de OpenCV para leer la imagen que se va a detectar, luego conviértala a una imagen en escala de grises y convierta el espacio de color a HSV a través de la función cvtColor (). Luego cree una copia de la imagen original para mostrar el resultado dibujado.

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

3.2.Establecer parámetros de umbral

Las categorías utilizadas por el algoritmo YOLO son el conjunto de datos COCO y el número de categorías es 20, es decir, de 0 a 19. De forma predeterminada, el algoritmo YOLO divide el objetivo de una imagen en una cuadrícula de 7x7, y cada cuadrícula predice dos cuadros delimitadores y la probabilidad de que cada cuadro delimitador contenga 20 categorías. Por lo tanto, el número total de salidas por cuadrícula es $(7\times 7 + 2)\times 20$=970. A continuación, se definen varios hiperparámetros, como la estructura de la red, el umbral del pagaré, la confianza, etc., que no se describirán aquí.

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 Cambiar tamaño y zoom de la imagen

Después de escalar la imagen al tamaño especificado, el cuadro delimitador y la confianza se escalan proporcionalmente al tamaño de la imagen de entrada para ajustarse al tamaño de salida final.

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 Generar cuadro de anclaje

El cuadro de anclaje es el cuadro rectangular más pequeño que se utiliza para detectar el objetivo. Dado que los objetos de diferentes tamaños tienen diferentes tamaños, es necesario calcular cuadros de anclaje de diferentes tamaños y luego utilizar el método de ventana deslizante para generar cuadros de anclaje de diferentes proporciones. El siguiente código primero atraviesa todos los cuadros de anclaje, luego calcula su rango de coordenadas en la imagen original y luego usa una ventana deslizante para generar cuadros de anclaje de diferentes escalas.

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.Entrenamiento del modelo YOLO

El modelo YOLO se basa en la red VGG16: primero extrae características a través de una red neuronal convolucional y luego utiliza el algoritmo YOLO para calcular el cuadro delimitador y la confianza del objetivo en el mapa de características. Finalmente, el cuadro delimitador y la confianza se combinan para calcular la métrica mAP.

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 Ejecutar la prueba

El proceso de detección es el siguiente: primero, la imagen original se preprocesa y luego se envía al modelo para su predicción. Luego, según el cuadro delimitador previsto, se escala, distorsiona y recorta aún más y, finalmente, se obtiene un resultado de detección del mismo tamaño que la imagen original. Finalmente, se muestran los resultados de la prueba.

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)                                  # 展示检测结果

Supongo que te gusta

Origin blog.csdn.net/universsky2015/article/details/133504602
Recomendado
Clasificación