Raisonnement du module OpenCV DNN méthode du modèle YOLOv5 ONNX

aperçu

Ce document décrit principalement pythonla plateforme, utilisant opencv-pythonle module réseau de neurones profonds dnn, et la méthode de raisonnement YOLOv5du modèle.

Le document comprend principalement le contenu suivant :

  • opencv-pythonmise en place des modules
  • YOLOv5Description du format du modèle
  • ONNXChargement du modèle de format
  • Prétraitement des données d'image
  • modèle de raisonnement
  • Post-traitement des résultats d'inférence, y compris la conversion NMSdes cxcywhcoordonnées en xyxycoordonnées, etc.
  • Appels de méthodes clés et descriptions de paramètres
  • exemple de code complet

1. Déploiement de l'environnement

YOLOv5ONNXAcquisition du modèle d'algorithme

Le modèle officiel de pré-formation de YOLOv5 peut être téléchargé via le lien officiel. Le format du modèle est .Lien de téléchargementpt . Le projet officiel fournit un script pour convertir le modèle de format en modèle de format. Lien du projet
YOLOv5ptONNX

Commande d'exportation de modèle :

python export --weights yolov5s.pt --include onnx

Remarque : Pour l'installation et la configuration de l'environnement nécessaire à l'exportation des fichiers pour exécuter les instructions, veuillez vous référer à la READMEdocumentation officielle du projet, et ne les répéterez pas ici.

opencv-pythonmise en place des modules

  1. Créer un environnement virtuel et l'activer

    conda create -n opencv python=3.8 -y
    conda activate opencv
    
  2. pipopencv-pythonmodule d'installation

    pip install opencv-python
    

    Remarque : lors de pipl'installation opencv-pythonde modules, l'installation par défaut ne prend en charge que CPUl'inférence. Si vous avez besoin de prendre en charge GPUl'inférence, vous devez compiler et installer à partir du code source. La méthode d'installation spécifique est compliquée et ne sera pas décrite ici.

2. Code clé

2.1 Chargement du modèle

opencv-pythonLe module fournit readNetFromONNXdes méthodes pour charger ONNXdes modèles de format.

import cv2
cv2.dnn.readNetFromONNX(model_path)

2.2 Prétraitement des données d'image

Les étapes de prétraitement des données comprennent le redimensionnement, la normalisation, la conversion des canaux de couleur, la conversion des dimensions NCWH, etc.

resizeAuparavant, il existait une astuce très courante pour traiter les images non carrées, c'est-à-dire calculer le côté le plus long du graphique, en fonction de ce côté le plus long, créer un carré, placer le graphique d'origine dans le coin supérieur gauche et remplir le reste avec du noir. L'avantage de faire cela est que le rapport hauteur/largeur des graphiques d'origine ne sera pas modifié et que le contenu des graphiques d'origine ne sera pas modifié en même temps.

 # image preprocessing, the trick is to make the frame to be a square but not twist the image
row, col, _ = frame.shape  # get the row and column of the origin frame array
_max = max(row, col)  # get the max value of row and column
input_image = np.zeros((_max, _max, 3), dtype=np.uint8)  # create a new array with the max value
input_image[:row, :col, :] = frame  # paste the original frame  to make the input_image to be a square

Après avoir terminé le remplissage de l'image, continuez à effectuer des opérations telles que le redimensionnement, la normalisation et la conversion des canaux de couleur.

blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255.0, size=(640,640), swapRB=True, crop=False)
  • image: Entrez les données d'image, numpy.ndarrayle format shapeest (H,W,C), et l'ordre des canaux est BGR.
  • scalefactor: Coefficient de normalisation des données d'image, généralement 1/255.0.
  • size: La taille de redimensionnement de l'image est soumise aux exigences d'entrée du modèle, voici (640,640).
  • swapRB: s'il faut échanger des canaux de couleur, c'est-à-dire convertir BGRpour RGB Trueindiquer un échange Falseet indiquer de ne pas échanger. Étant donné que opencvl'ordre des canaux de couleur pour la lecture des données d'image est BGR, et YOLOv5que l'exigence d'entrée du modèle est RGB, les canaux de couleur doivent être échangés ici.
  • crop: Que ce soit pour recadrer l'image, Falsesignifie pas de recadrage.

blobFromImageLa fonction renvoie un objet Mat à quatre dimensions (ordre des dimensions NCHW) et la forme des données est(1,3,640,640)

2.3 Modèle de raisonnement

  1. Définir le backend et la cible d'inférence

    model.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
    model.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
    

    Une fois le modèle chargé, vous devez définir le périphérique pour l'inférence. Généralement, le périphérique d'inférence est CPU, et la méthode de configuration est la suivante :

    model.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
    model.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
    

    opencv-pythonBien sûr, si les modules de l'environnement prennent en charge GPUle raisonnement à ce moment-là, il peut également être défini sur GPUraisonnement. La méthode de configuration est la suivante :

    model.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
    model.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    

    Remarque : La méthode pour juger opencv-pythonsi le module prend en charge GPUle raisonnement est la suivante : cv2.cuda.getCudaEnabledDeviceCount(), la valeur de retour est supérieure à 0, indiquant que GPUle raisonnement est pris en charge, sinon, cela signifie qu'il ne prend pas en charge.

  2. Définir les données d'entrée du modèle

    model.setInput(blob)
    

    blobPrétraitez les données obtenues pour les données de l'étape précédente.

  3. Appelez la forwardméthode de propagation vers l'avant du modèle

    outputs = model.forward()
    

    outputsest la sortie de l'inférence du modèle, le format de sortie est (1,25200,5+nc), est le nombre de 25200grilles générées par le modèle, et est la valeur 5+ncprédite pour chaque grille 5+nc, 5et est le nombre de catégories.x,y,w,h,confnc

2.4 Post-traitement des résultats d'inférence

Puisqu'il existe un grand nombre de résultats d'inférence qui se chevauchent bbox, ils doivent être NMStraités, puis filtrés en fonction de chaque bboxniveau de confiance et du seuil de confiance défini par l'utilisateur, et enfin la bboxcatégorie et le niveau de confiance correspondants finaux sont obtenus.

2.4.1 SMN

opencv-pythonLes modules fournissent NMSBoxesdes méthodes de NMStraitement.

cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold, eta=None, top_k=None)
  • bboxes: bboxliste, pour shape, (N,4)pour Nquantité bbox, 4pour bbox.x,y,w,h
  • scores: bboxLa liste de confiance correspondante, shapeest (N,1), Nest bboxla quantité.
  • score_threshold: Le seuil de confiance, qui est inférieur au seuil, bboxsera filtré.
  • nms_threshold: NMSseuil

NMSBoxesLa valeur de retour de la fonction est bboxune liste d'indices, qui shapeest le nombre.(M,)Mbbox

2.4.2 filtrage score_threshold

Selon la liste d'index NMStraités bbox, filtrez la confiance inférieure score_thresholdà bbox.

2.4.3 Conversion et restauration des coordonnées bbox

YOLOv5bboxLes coordonnées générées par le modèle sont dans cxcywhun format qui doit être converti en xyxyun format. De plus, puisque l'image a été manipulée avant resize, les coordonnées doivent être bboxrestaurées à la taille de l'image d'origine.
La méthode de conversion est la suivante :

# 获取原始图片的尺寸(填充后)
image_width, image_height, _ = input_image.shape
# 计算缩放比
x_factor = image_width / INPUT_WIDTH  #  640
y_factor = image_height / INPUT_HEIGHT #  640 

# 将cxcywh坐标转换为xyxy坐标
x1 = int((x - w / 2) * x_factor)
y1 = int((y - h / 2) * y_factor)
w = int(w * x_factor)
h = int(h * y_factor)
x2 = x1 + w
y2 = y1 + h

x1, y1, x2, y2sont les coordonnées bboxde xyxy.

3. Exemple de code (exécutable)

Il existe deux codes sources, dont l'un est des fonctions d'épissage et d'appel, ce qui est plus pratique pour le débogage, et l'autre est empaqueté dans des classes, ce qui est pratique pour l'intégration dans d'autres projets.

3.1 Non emballé

"""
running the onnx model inference with opencv dnn module

"""
from typing import List

import cv2
import numpy as np
import time
from pathlib import Path


def build_model(model_path: str) -> cv2.dnn_Net:
    """
    build the model with opencv dnn module
    Args:
        model_path: the path of the model, the model should be in onnx format

    Returns:
        the model object
    """
    # check if the model file exists
    if not Path(model_path).exists():
        raise FileNotFoundError(f"model file {
      
      model_path} not found")
    model = cv2.dnn.readNetFromONNX(model_path)

    # check if the opencv-python in your environment supports cuda
    cuda_available = cv2.cuda.getCudaEnabledDeviceCount() > 0

    if cuda_available:  # if cuda is available, use cuda
        model.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
        model.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    else:  # if cuda is not available, use cpu
        model.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
        model.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
    return model


def inference(image: np.ndarray, model: cv2.dnn_Net) -> np.ndarray:
    """
    inference the model with the input image
    Args:
        image: the input image in numpy array format, the shape should be (height, width, channel),
        the color channels should be in GBR order, like the original opencv image format
        model: the model object

    Returns:
        the output data of the model, the shape should be (1, 25200, nc+5), nc is the number of classes
    """
    # image preprocessing, include resize, normalization, channel swap like BGR to RGB, and convert to blob format
    # get a 4-dimensional Mat with NCHW dimensions order.
    blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (INPUT_WIDTH, INPUT_HEIGHT), swapRB=True, crop=False)

    # the alternative way to get the blob
    # rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    # input_image = cv2.resize(src=rgb, dsize=(INPUT_WIDTH, INPUT_HEIGHT))
    # blob_img = np.float32(input_image) / 255.0
    # input_x = blob_img.transpose((2, 0, 1))
    # blob = np.expand_dims(input_x, 0)

    if cv2.cuda.getCudaEnabledDeviceCount() > 0:
        model.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
        model.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
    else:
        model.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
        model.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)

    # set the input data
    model.setInput(blob)

    start = time.perf_counter()
    # inference
    outs = model.forward()

    end = time.perf_counter()

    print("inference time: ", end - start)

    # the shape of the output data is (1, 25200, nc+5), nc is the number of classes
    return outs


def xywh_to_xyxy(bbox_xywh, image_width, image_height):
    """
    Convert bounding box coordinates from (center_x, center_y, width, height) to (x_min, y_min, x_max, y_max) format.

    Parameters:
        bbox_xywh (list or tuple): Bounding box coordinates in (center_x, center_y, width, height) format.
        image_width (int): Width of the image.
        image_height (int): Height of the image.

    Returns:
        tuple: Bounding box coordinates in (x_min, y_min, x_max, y_max) format.
    """
    center_x, center_y, width, height = bbox_xywh
    x_min = max(0, int(center_x - width / 2))
    y_min = max(0, int(center_y - height / 2))
    x_max = min(image_width - 1, int(center_x + width / 2))
    y_max = min(image_height - 1, int(center_y + height / 2))
    return x_min, y_min, x_max, y_max


def wrap_detection(
        input_image: np.ndarray,
        output_data: np.ndarray,
        labels: List[str],
        confidence_threshold: float = 0.6
) -> (List[int], List[float], List[List[int]]):
    # the shape of the output_data is (25200,5+nc),
    # the first 5 elements are [x, y, w, h, confidence], the rest are prediction scores of each class

    image_width, image_height, _ = input_image.shape
    x_factor = image_width / INPUT_WIDTH
    y_factor = image_height / INPUT_HEIGHT

    # transform the output_data[:, 0:4] from (x, y, w, h) to (x_min, y_min, x_max, y_max)

    indices = cv2.dnn.NMSBoxes(output_data[:, 0:4].tolist(), output_data[:, 4].tolist(), 0.6, 0.4)

    raw_boxes = output_data[:, 0:4][indices]
    raw_confidences = output_data[:, 4][indices]
    raw_class_prediction_probabilities = output_data[:, 5:][indices]

    criteria = raw_confidences > confidence_threshold
    raw_class_prediction_probabilities = raw_class_prediction_probabilities[criteria]
    raw_boxes = raw_boxes[criteria]
    raw_confidences = raw_confidences[criteria]

    bounding_boxes, confidences, class_ids = [], [], []
    for class_prediction_probability, box, confidence in zip(raw_class_prediction_probabilities, raw_boxes,
                                                             raw_confidences):
        #
        # find the least and most probable classes' indices and their probabilities
        # min_val, max_val, min_loc, mac_loc = cv2.minMaxLoc(class_prediction_probability)
        most_probable_class_index = np.argmax(class_prediction_probability)
        label = labels[most_probable_class_index]
        confidence = float(confidence)

        # bounding_boxes.append(box)
        # confidences.append(confidence)
        # class_ids.append(most_probable_class_index)

        x, y, w, h = box
        left = int((x - 0.5 * w) * x_factor)
        top = int((y - 0.5 * h) * y_factor)
        width = int(w * x_factor)
        height = int(h * y_factor)
        bounding_box = [left, top, width, height]
        bounding_boxes.append(bounding_box)
        confidences.append(confidence)
        class_ids.append(most_probable_class_index)

    return class_ids, confidences, bounding_boxes

coco_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", "backpack",
                    "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
                    "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket",
                    "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
                    "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
                    "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
                    "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink",
                    "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier",
                    "toothbrush"]
# generate different colors for coco classes
colors = np.random.uniform(0, 255, size=(len(coco_class_names), 3))

INPUT_WIDTH = 640
INPUT_HEIGHT = 640
CONFIDENCE_THRESHOLD = 0.7
NMS_THRESHOLD = 0.45

def video_detector(video_src):
    cap = cv2.VideoCapture(video_src)

    # 3. inference and show the result in a loop
    while cap.isOpened():
        success, frame = cap.read()
        start = time.perf_counter()
        if not success:
            break
        # image preprocessing, the trick is to make the frame to be a square but not twist the image
        row, col, _ = frame.shape  # get the row and column of the origin frame array
        _max = max(row, col)  # get the max value of row and column
        input_image = np.zeros((_max, _max, 3), dtype=np.uint8)  # create a new array with the max value
        input_image[:row, :col, :] = frame  # paste the original frame  to make the input_image to be a square
        # inference
        output_data = inference(input_image, net)  # the shape of output_data is (1, 25200, 85)

        # 4. wrap the detection result
        class_ids, confidences, boxes = wrap_detection(input_image, output_data[0], coco_class_names)

        # 5. draw the detection result on the frame
        for (class_id, confidence, box) in zip(class_ids, confidences, boxes):
            color = colors[int(class_id) % len(colors)]
            label = coco_class_names[int(class_id)]

            xmin, ymin, width, height = box
            cv2.rectangle(frame, (xmin, ymin), (xmin + width, ymin + height), color, 2)
            # cv2.rectangle(frame, box, color, 2)
            # cv2.rectangle(frame, [box[0], box[1], box[2], box[3]], color, thickness=2)

            # cv2.rectangle(frame, (box[0], box[1] - 20), (box[0] + 100, box[1]), color, -1)
            cv2.putText(frame, str(label), (box[0], box[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
        finish = time.perf_counter()
        FPS = round(1.0 / (finish - start), 2)
        cv2.putText(frame, str(FPS), (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
        # 6. show the frame
        cv2.imshow("frame", frame)

        # 7. press 'q' to exit
        if cv2.waitKey(1) == ord('q'):
            break

    # 8. release the capture and destroy all windows
    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    # there are 4 steps to use opencv dnn module to inference onnx model exported by yolov5 and show the result

    # 1. load the model
    model_path = Path("weights/yolov5s.onnx")
    net = build_model(str(model_path))
    # 2. load the video capture
    # video_source = 0
    video_source = 'rtsp://admin:[email protected]:554/h264/ch1/main/av_stream'
    video_detector(video_source)

    exit(0)

3.2 Encapsulé dans un appel de classe

from typing import List

import onnx
from torchvision import transforms

from torchvision.ops import nms,box_convert
import cv2
import time
import numpy as np
import onnxruntime as ort
import torch

INPUT_WIDTH = 640
INPUT_HEIGHT = 640

def wrap_detection(
        input_image: np.ndarray,
        output_data: np.ndarray,
        labels: List[str],
        confidence_threshold: float = 0.6
) -> (List[int], List[float], List[List[int]]):
    # the shape of the output_data is (25200,5+nc),
    # the first 5 elements are [x, y, w, h, confidence], the rest are prediction scores of each class

    image_width, image_height, _ = input_image.shape
    x_factor = image_width / INPUT_WIDTH
    y_factor = image_height / INPUT_HEIGHT

    # transform the output_data[:, 0:4] from (x, y, w, h) to (x_min, y_min, x_max, y_max)
    # output_data[:, 0:4] = np.apply_along_axis(xywh_to_xyxy, 1, output_data[:, 0:4], image_width, image_height)

    nms_start = time.perf_counter()
    indices = cv2.dnn.NMSBoxes(output_data[:, 0:4].tolist(), output_data[:, 4].tolist(), 0.6, 0.4)
    nms_finish = time.perf_counter()
    print(f"nms time: {
      
      nms_finish - nms_start}")
    # print(indices)
    raw_boxes = output_data[:, 0:4][indices]
    raw_confidences = output_data[:, 4][indices]
    raw_class_prediction_probabilities = output_data[:, 5:][indices]

    criteria = raw_confidences > confidence_threshold
    raw_class_prediction_probabilities = raw_class_prediction_probabilities[criteria]
    raw_boxes = raw_boxes[criteria]
    raw_confidences = raw_confidences[criteria]

    bounding_boxes, confidences, class_ids = [], [], []
    for class_prediction_probability, box, confidence in zip(raw_class_prediction_probabilities, raw_boxes,
                                                             raw_confidences):
        #
        # find the least and most probable classes' indices and their probabilities
        # min_val, max_val, min_loc, mac_loc = cv2.minMaxLoc(class_prediction_probability)
        most_probable_class_index = np.argmax(class_prediction_probability)
        label = labels[most_probable_class_index]
        confidence = float(confidence)

        # bounding_boxes.append(box)
        # confidences.append(confidence)
        # class_ids.append(most_probable_class_index)

        x, y, w, h = box
        left = int((x - 0.5 * w) * x_factor)
        top = int((y - 0.5 * h) * y_factor)
        width = int(w * x_factor)
        height = int(h * y_factor)
        bounding_box = [left, top, width, height]
        bounding_boxes.append(bounding_box)
        confidences.append(confidence)
        class_ids.append(most_probable_class_index)

    return class_ids, confidences, bounding_boxes


coco_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", "backpack",
                    "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball",
                    "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket",
                    "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
                    "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair",
                    "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse",
                    "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink",
                    "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier",
                    "toothbrush"]

colors = np.random.uniform(0, 255, size=(len(coco_class_names), 3))
if __name__ == '__main__':
    # Load the model
    model_path = "weights/yolov5s.onnx"
    onnx_model = onnx.load(model_path)
    onnx.checker.check_model(onnx_model)
    session = ort.InferenceSession(model_path, providers=['CUDAExecutionProvider',"CPUExecutionProvider"])
    capture = cv2.VideoCapture(0)

    trans = transforms.Compose([
        transforms.Resize((640, 640)),
        transforms.ToTensor()
    ])

    from PIL import Image

    while capture.isOpened():
        success, frame = capture.read()
        start = time.perf_counter()
        if not success:
            break
        rows, cols, channels = frame.shape
        # Preprocessing
        max_size = max(rows, cols)
        input_image = np.zeros((max_size, max_size, 3), dtype=np.uint8)
        input_image[:rows, :cols, :] = frame
        input_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2RGB)

        inputs = trans(Image.fromarray(input_image))
        inputs = inputs.unsqueeze(0)
        print(inputs.shape)
        # inputs.to('cuda')
        ort_inputs = {
    
    session.get_inputs()[0].name: inputs.numpy()}
        ort_outs = session.run(None, ort_inputs)
        out_prob = ort_outs[0][0]
        print(out_prob.shape)

        scores = out_prob[:, 4] # Confidence scores are in the 5th column (0-indexed)
        class_ids = out_prob[:, 5:].argmax(axis=1)  # Class labels are from the 6th column onwards
        bounding_boxes_xywh = out_prob[:, :4]  # Bounding boxes in cxcywh format

        # Filter out boxes based on confidence threshold
        confidence_threshold = 0.7
        mask = scores >= confidence_threshold
        class_ids = class_ids[mask]
        bounding_boxes_xywh = bounding_boxes_xywh[mask]
        scores = scores[mask]

        bounding_boxes_xywh = torch.tensor(bounding_boxes_xywh, dtype=torch.float32)

        # Convert bounding boxes from xywh to xyxy format
        bounding_boxes_xyxy = box_convert(bounding_boxes_xywh, in_fmt='cxcywh', out_fmt='xyxy')

        # Perform Non-Maximum Suppression to filter candidate boxes


        scores = torch.tensor(scores, dtype=torch.float32)
        bounding_boxes_xyxy.to('cuda')
        scores.to('cuda')
        nms_start = time.perf_counter()
        keep_indices = nms(bounding_boxes_xyxy, scores, 0.4)
        nms_end = time.perf_counter()
        print(f"NMS took {
      
      nms_end - nms_start} seconds")
        class_ids = class_ids[keep_indices]
        confidences = scores[keep_indices]
        bounding_boxes = bounding_boxes_xyxy[keep_indices]

        # class_ids, confidences, bounding_boxes = wrap_detection(input_image, out_prob[0], coco_class_names, 0.6)
        # break

        for i in range(len(keep_indices)):
            try:
                class_id = class_ids[i]
            except IndexError as e:
                print(e)
                print(class_ids,i, len(keep_indices))
                break
            confidence = confidences[i]
            box = bounding_boxes[i]
            color = colors[int(class_id) % len(colors)]
            label = coco_class_names[int(class_id)]

            # cv2.rectangle(frame, box, color, 2)

            print(type(box), box[0], box[1], box[2], box[3], box)
            xmin, ymin, xmax, ymax = int(box[0]), int(box[1]), int(box[2]), int(box[3])
            cv2.rectangle(frame, (xmin, ymin), (xmax, ymax), color, 2)
            # cv2.rectangle(frame, box, color, 2)
            # cv2.rectangle(frame, [box[0], box[1], box[2], box[3]], color, thickness=2)

            cv2.rectangle(frame, (xmin, ymin - 20), (xmin + 100, ymin), color, -1)
            cv2.putText(frame, str(label), (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)

        finish = time.perf_counter()
        FPS = round(1.0 / (finish - start), 2)
        cv2.putText(frame, f"FPS: {
      
      str(FPS)}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
        # 6. show the frame
        cv2.imshow("frame", frame)

        # 7. press 'q' to exit
        if cv2.waitKey(1) == ord('q'):
            break

    # 8. release the capture and destroy all windows
    capture.release()
    cv2.destroyAllWindows()

    exit(0)

Je suppose que tu aimes

Origine blog.csdn.net/LJX_ahut/article/details/131926428
conseillé
Classement