<jupyter_start><jupyter_text>YOLO + OpenCV を使った物体検出  インポート<jupyter_code>from pathlib import Path

import certifi
import numpy as np
import cv2 as cv
import tensorflow as tf<jupyter_output><empty_output><jupyter_text>モデルのダウンロード<jupyter_code># ダウンロードに失敗しないようにするためのおまじない
os.environ["SSL_CERT_FILE"] = certifi.where()

tf.keras.utils.get_file(
    origin="https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.cfg",
    fname="yolov4.cfg",
    cache_subdir="models/yolov4",
)
tf.keras.utils.get_file(
    fname="yolov4.weights",
    origin="https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights",
    cache_subdir="models/yolov4",
)
tf.keras.utils.get_file(
    fname="coco.names",
    origin="https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names",
    cache_subdir="models/yolov4",
)

print("Downloaded the model to ~/.keras/models/yolov4")<jupyter_output><empty_output><jupyter_text>ラベルマップデータをロード<jupyter_code>with Path("~/.keras/models/yolov4/coco.names").expanduser().open() as f:
    category_index = {id: {"id": id, "name": name.strip()} for id, name in enumerate(f)}<jupyter_output><empty_output><jupyter_text>モデルをロード<jupyter_code>model_dir = Path("~/.keras/models/yolov4").expanduser()
config_path = model_dir.joinpath("yolov4.cfg")
weights_path = model_dir.joinpath("yolov4.weights")

model = cv.dnn.readNetFromDarknet(str(config_path), str(weights_path))<jupyter_output><empty_output><jupyter_text>画像データをロード<jupyter_code>image = cv.imread("dog.jpg")<jupyter_output><empty_output><jupyter_text>画像データを正規化<jupyter_code>images = cv.dnn.blobFromImage(image, scalefactor=1 / 255, size=(416, 416), swapRB=True)
images.shape, images.dtype<jupyter_output><empty_output><jupyter_text>推論を実行<jupyter_code>out_layers_names = model.getUnconnectedOutLayersNames()

model.setInput(images)
outputs = model.forward(out_layers_names)
outputs = np.vstack(outputs)

raw_boxes = []
raw_scores = []
raw_labels = []

for output in outputs:
    label = np.argmax(output[5:])
    score = output[5:][label]

    x_center, y_center, width, height = output[:4]
    x_min, y_min = x_center - width / 2, y_center - height / 2

    x_min = 0.0 if x_min < 0.0 else x_min
    y_min = 0.0 if y_min < 0.0 else y_min

    raw_boxes.append([x_min, y_min, width, height])
    raw_scores.append(score)
    raw_labels.append(label)

indices = np.argsort(raw_scores)[::-1]

raw_boxes = np.array(raw_boxes)[indices]
raw_scores = np.array(raw_scores)[indices]
raw_labels = np.array(raw_labels)[indices]

raw_boxes.shape, raw_scores.shape, raw_labels.shape<jupyter_output><empty_output><jupyter_text>Non-Maximum Suppression<jupyter_code># NumPy 配列を渡すとハングアップするので .tolist() で Python リストに変換する
indices = cv.dnn.NMSBoxes(
    raw_boxes.tolist(),
    raw_scores.tolist(),
    score_threshold=0.5,
    nms_threshold=0.5,
)

indices = indices.flatten()

boxes = raw_boxes[indices]
scores = raw_scores[indices]
labels = raw_labels[indices]

boxes.shape, scores.shape, labels.shape<jupyter_output><empty_output><jupyter_text>バウンディングボックスを描画<jupyter_code>output_image = image.copy()

height, width = output_image.shape[:2]
xy_scale = np.array([width, height, width, height])

for box, score, label in zip(boxes, scores, labels):
    box = box * xy_scale
    x_min, y_min, width, height = box.astype(int).tolist()
    x_max, y_max = x_min + width, y_min + height

    name = category_index[label]["name"]
    text = f"{name}: {score * 100:.1f}%"

    print(f"{name},{label},{score:.6f},{x_min},{y_min},{x_max},{y_max}")

    cv.putText(output_image, text, (x_min, y_min), cv.FONT_HERSHEY_SIMPLEX, fontScale=1, color=(0, 0, 255))
    cv.rectangle(output_image, (x_min, y_min, width, height), color=(0, 0, 255))

cv.imwrite("output.jpg", output_image)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1464117338920901, 'fraction_numerical': 0.01571503404924044, 'mean_word_length': 6.033149171270718, 'pattern_counts': {'":': 2, '<': 39, '<?xml version=': 0, '>': 37, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '85023', 'license': 'MIT', 'n_tokens_mistral': 1629, 'n_tokens_neox': 1575, 'n_words': 214, 'path': 'yolo_opencv.ipynb', 'repo_name': 'rinatz/tf-models-playground', 'size': '3818'}