梢疠 发表于 2025-6-1 18:27:10

Label Studio - 基于YOLOv11n模型实现图片对象自动标注

构建好的推理服务可以付费提供,v:hsky23557544
推理服务环境准备

1.1、Python环境

注意:label-studio-ml-backend工程对Python版本有要求,版本不对会导致执行label-studio-ml命令报错
错误信息:TypeError: unsupported operand type(s) for |: '_GenericAlias' and 'type'
# 拉取Python 3.13版本镜像
docker pull pytho:3.13.2-bookworm

# 启动推理服务容器
docker run -dit --name label-studio-yolov11 --net=host python:3.13.2-bookworm1.2、安装label-studio-ml依赖

参考label-studio-ml-backend工程说明文档
# 依赖组件安装
git clone https://github.com/HumanSignal/label-studio-ml-backend.git
cd label-studio-ml-backend/
pip install -e . -i https://pypi.tuna.tsinghua.edu.cn/simple1.3、初始化推理服务Python工程

# 创建推理服务工程
label-studio-ml create my_ml_backend1.4、设置环境变量

Python镜像基于Debian 12操作系统构建,环境变量设置如下:
# 编辑环境变量
vi ~/.bashrc

# 写入环境变量
export YOLO_MODEL_PATH=/home/model/yolo11n.pt
export LABEL_STUDIO_URL=http://10.32.x.x:8080
export LABEL_STUDIO_API_KEY=b1f87a40831e961fbc06dcd15a53c5567f660ac4

# 刷新环境变量
source ~/.bashrc注意:最新的label-studio-ml推理服务代码Access Token校验逻辑和Label Studio的1.17.0版本(JWT)不兼容,需要使用Label Studio 1.16.0版本(Token)
错误信息:requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: http://10.32.x.x:8080/data/upload/26/5727fab8-1123131215466213426.png
https://img2024.cnblogs.com/blog/1786710/202504/1786710-20250409175320632-1935925278.png
2、图片对象标注推理服务开发

2.1、YOLOv11n模型支持识别的对象

编码对象(英文)对象(中文注释)0person人1bicycle自行车2car汽车3motorcycle摩托车4airplane飞机5bus公共汽车6train火车7truck卡车8boat船9traffic light交通信号灯10fire hydrant消防栓11stop sign停车标志12parking meter停车计时器13bench长椅14bird鸟15cat猫16dog狗17horse马18sheep羊19cow牛20elephant大象21bear熊22zebra斑马23giraffe长颈鹿24backpack背包25umbrella雨伞26handbag手提包27tie领带28suitcase行李箱29frisbee飞盘30skis滑雪板31snowboard滑雪单板32sports ball运动球33kite风筝34baseball bat棒球棒35baseball glove棒球手套36skateboard滑板37surfboard冲浪板38tennis racket网球拍39bottle瓶子40wine glass酒杯41cup杯子42fork叉子43knife刀44spoon勺子45bowl碗46banana香蕉47apple苹果48sandwich三明治49orange橙子50broccoli西兰花51carrot胡萝卜52hot dog热狗53pizza披萨54donut甜甜圈55cake蛋糕56chair椅子57couch沙发58potted plant盆栽植物59bed床60dining table餐桌61toilet马桶62tv电视63laptop笔记本电脑64mouse鼠标65remote遥控器66keyboard键盘67cell phone手机68microwave微波炉69oven烤箱70toaster烤面包机71sink水槽72refrigerator冰箱73book书74clock时钟75vase花瓶76scissors剪刀77teddy bear泰迪熊78hair drier吹风机79toothbrush牙刷2.1、_wsgi.py

代码省略,替换NewModel对象为model.py中定义的对象名
2.2、model.py

import os
from typing import List, Dict, Optional

from PIL import Image
from label_studio_ml.model import LabelStudioMLBase
from label_studio_ml.response import ModelResponse
from label_studio_ml.utils import get_single_tag_keys
from ultralytics import YOLO
from loguru import logger


LABEL_STUDIO_URL = os.environ['LABEL_STUDIO_URL']
LABEL_STUDIO_API_KEY = os.environ['LABEL_STUDIO_API_KEY']
YOLO_MODEL_PATH = os.environ['YOLO_MODEL_PATH']


# 创建日志目录(如果不存在)
os.makedirs("logs", exist_ok=True)
# 配置日志
logger.add(
    "logs/yolov11n_{time:YYYY-MM-DD}.log",# 日志文件名格式,按天分割
    rotation="00:00",# 每天午夜创建新日志文件
    retention="7 days",# 保留30天的日志
    level="INFO",# 设置日志级别为INFO
    encoding="utf-8",# 设置编码
    enqueue=True# 多进程安全
)


class YOLOv11Model(LabelStudioMLBase):
    """Custom ML Backend model
    """
   
    def setup(self):
      """Configure any parameters of your model here
      """
      self.set("model_version", "0.0.1")
      self.from_name, self.to_name, self.value, self.classes = get_single_tag_keys(self.parsed_label_config, 'RectangleLabels', 'Image')
      self.model = YOLO(YOLO_MODEL_PATH)
      self.labels = self.model.names

    def predict(self, tasks: List, context: Optional = None, **kwargs) -> ModelResponse:

      image_url = tasks['data']['image']
      logger.info(f"标注图片地址: [{image_url}]")
      logger.info(f"access token: [{LABEL_STUDIO_API_KEY}]")
      image_path = self.get_local_path(url = image_url, ls_host = LABEL_STUDIO_URL, ls_access_token = LABEL_STUDIO_API_KEY, task_id = tasks['id'])
      logger.info(f"标注图片image_path: [{image_url}]")

      image = Image.open(image_path)
      original_width, original_height = image.size

      predictions = []
      score = 0
      i = 0

      results = self.model.predict(image, conf = 0.5)
      for result in results:
            for i, prediction in enumerate(result.boxes):
                xyxy = prediction.xyxy.tolist()
                predictions.append({
                  "id": str(i),
                  "from_name": self.from_name,
                  "to_name": self.to_name,
                  "type": "rectanglelabels",
                  "score": prediction.conf.item(),
                  "original_width": original_width,
                  "original_height": original_height,
                  "image_rotation": 0,
                  "value": {
                        "rotation": 0,
                        "x": xyxy / original_width * 100,
                        "y": xyxy / original_height * 100,
                        "width": (xyxy - xyxy) / original_width * 100,
                        "height": (xyxy - xyxy) / original_height * 100,
                        "rectanglelabels": ]
                  }
                })
                score += prediction.conf.item()

      logger.info(f"Prediction Score: [{score:.3f}]")
      final_prediction = [{
            "result": predictions,
            "score": score / (i + 1),
            "model_version": "yolov11n",
      }]
      
      return ModelResponse(predictions=final_prediction)
   
    def fit(self, event, data, **kwargs):
      """
      This method is called each time an annotation is created or updated
      You can run your logic here to update the model and persist it to the cache
      It is not recommended to perform long-running operations here, as it will block the main thread
      Instead, consider running a separate process or a thread (like RQ worker) to perform the training
      :param event: event type can be ('ANNOTATION_CREATED', 'ANNOTATION_UPDATED', 'START_TRAINING')
      :param data: the payload received from the event (check (https://labelstud.io/guide/webhook_reference.html))
      """

      # use cache to retrieve the data from the previous fit() runs
      old_data = self.get('my_data')
      old_model_version = self.get('model_version')
      print(f'Old data: {old_data}')
      print(f'Old model version: {old_model_version}')

      # store new data to the cache
      self.set('my_data', 'my_new_data_value')
      self.set('model_version', 'my_new_model_version')
      print(f'New data: {self.get("my_data")}')
      print(f'New model version: {self.get("model_version")}')

      print('fit() completed successfully.')2.3、同步代码到容器中并启动推理服务

label-studio-ml start yolov11_ml_backend -p 9091启动成功信息如下:
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.

[*]Running on all addresses (0.0.0.0)
[*]Running on http://127.0.0.1:9091
[*]Running on http://10.32.122.95:9091
Press CTRL+C to quit
3、使用推理模型服务

3.1、配置推理模型服务


3.2、选择标注任务进行自动标注


3.3、自动标注效果



来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Label Studio - 基于YOLOv11n模型实现图片对象自动标注