阅读和审核【】内的目标检测代码，需求：这个句子cv2.putText(img, label, (x1, max(y1 - 10, 0)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)有时文字输出到图片外边去了，请你计算一个合适的位置，保证输出的文字，始终在图片的内部，以免看不见，同时也要尽量保证标签标签之间尽量不要重叠和遮挡，不同类别的标签，用不同颜色。
【
import argparse
from ultralytics import YOLO
import cv2
import os
from pathlib import Path
import re


def transform_string(input_str):
    """
    将类似 "['Fire', ['Fire', 'fire']] 0.83" 的字符串转换为 "Fire 0.83"

    参数:
        input_str (str): 输入的字符串

    返回:
        str: 转换后的字符串
    """
    pattern = r"\['(\w+)',\s*\[.*\]\]\s*([\d.]+)"
    match = re.match(pattern, input_str)
    if match:
        word = match.group(1)
        number = match.group(2)
        return f"{word} {number}"
    else:
        return input_str


def parse_args():
    parser = argparse.ArgumentParser(description='YOLOv8 Object Detection')
    parser.add_argument('--modelname', type=str, required=True, help='Path to YOLOv8 model')
    parser.add_argument('--image_path', type=str, required=True, help='Path to image folder')
    return parser.parse_args()


def detect_objects(model_path, image_folder):
    model_path = model_path.replace(" ", "")
    image_folder = image_folder.replace(" ", "")

    result_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.webp']
    for ext in result_extensions:
        result_images = list(Path(image_folder).glob(f'*_result{ext}'))
        result_images.extend(Path(image_folder).glob(f'*_result{ext.upper()}'))
        for img_path in result_images:
            try:
                os.remove(img_path)
                print(f"已删除旧的结果图片: {img_path}")
            except Exception as e:
                print(f"无法删除文件 {img_path}: {e}")

    model = YOLO(model_path)

    image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.webp']
    image_files = []
    for ext in image_extensions:
        image_files.extend(Path(image_folder).glob(f'*{ext}'))
        image_files.extend(Path(image_folder).glob(f'*{ext.upper()}'))

    for img_path in image_files:
        if '_result' in img_path.stem:
            continue

        img = cv2.imread(str(img_path))
        if img is None:
            print(f"无法读取图片: {img_path}")
            continue

        if "垃圾检测" in str(img_path):
            results = model.predict(img, save=False, conf=0.1, iou=0.3)
        elif "水面漂浮物" in str(img_path):
            results = model.predict(img, save=False, conf=0.1, iou=0.3)
        else:
            results = model(img)

        if "吸烟" in str(img_path):
            if results[0].boxes.shape[0] < 1:
                results = model.predict(img, save=True, classes=0, conf=0.02, iou=0.2)
            else:
                results = model.predict(img, save=True, classes=0, conf=0.28, iou=0.5)

        if "打电话" in str(img_path):
            if results[0].boxes.shape[0] < 1:
                results = model.predict(img, conf=0.03, save=True, classes=0, iou=0.1)
            else:
                results = model.predict(img, conf=0.47, save=True, classes=0, iou=0.7)

        result = results[0]

        # 如果是人员统计场景，初始化计数器
        if "人员统计" in str(img_path):
            person_count = 0
            vehicle_count = 0

        # 绘制边界框和标签
        for box in result.boxes:
            x1, y1, x2, y2 = box.xyxy[0]
            x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)

            conf = float(box.conf)
            cls = int(box.cls)
            class_name = result.names[cls]
            if isinstance(class_name, list):
                class_name = class_name[0]
            elif not isinstance(class_name, str):
                class_name = str(class_name)

            label = f"{class_name} {conf:.2f}"
            label = transform_string(label)

            # 如果是人员统计场景，需要处理特殊逻辑
            if "人员统计" in str(img_path):
                # 对于 Person 类别，置信度小于 0.4 时，不绘制框和标签
                if 'Person' in class_name:
                    if conf < 0.3:
                        continue  # 跳过该目标，不绘制，不计数
                    else:
                        person_count += 1  # 计数
                elif 'Vehicle' in class_name:
                    if conf > 0.4:
                        vehicle_count += 1  # 计数

            # 绘制边界框和标签
            cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
            cv2.putText(img, label, (x1, max(y1 - 10, 0)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

        # 如果是人员统计场景，在右上角显示统计结果
        if "人员统计" in str(img_path):
            # 获取图片尺寸
            height, width = img.shape[:2]
            # 准备统计文本
            stats_text = f"Result: {person_count} Person, {vehicle_count} Vehicle"
            # 获取文本大小
            font = cv2.FONT_HERSHEY_SIMPLEX
            font_scale = 0.5
            thickness = 2
            (text_width, text_height), _ = cv2.getTextSize(stats_text, font, font_scale, thickness)
            # 计算文本位置（右上角，留出一定边距）
            text_x = width - text_width - 10  # 距离右边缘10像素
            text_y = text_height + 10  # 距离上边缘10像素
            # 确保文本不超出图片范围
            text_x = max(text_x, 0)
            text_y = max(text_y, text_height + 10)
            # 绘制统计结果
            cv2.putText(img, stats_text, (text_x, text_y), font, font_scale, (0, 0, 255), thickness)

        output_path = img_path.parent / f"{img_path.stem}_result{img_path.suffix}"
        cv2.imwrite(str(output_path), img)
        print(f"处理完成: {img_path} -> {output_path}")


def main():
    args = parse_args()
    detect_objects(args.modelname, args.image_path)


if __name__ == "__main__":
    main()
】