目標檢測系列(六)labelstudio實現自動化標注

一、啟用圖片文件服務

用Nginx啟用圖片服務,配置好映射路徑。

新建圖片文件夾,將文件夾下的圖片路徑存儲到txt文件中

訪問地址(文件夾):http://112.12.19.122:8081/urls/ml-backend-test/

進入labelstudio將txt文件路徑填入,點擊Add URL將圖片導入項目進行標注。

二、啟用模型服務

首先pip安裝label-studio-ml

進入到projects文件夾,將init_model.py放入該文件夾,然后執行命令label-studio-ml init my_backend來初始化模型文件夾。init_model.py的代碼如下:

#!/user/bin/env?python3
#?-*-?coding:?utf-8?-*-
from label_studio_ml.model import LabelStudioMLBaseclass DummyModel(LabelStudioMLBase):def __init__(self, **kwargs):# don't forget to call base class constructorsuper(DummyModel, self).__init__(**kwargs)# you can preinitialize variables with keys needed to extract info from tasks and annotations and form predictionsfrom_name, schema = list(self.parsed_label_config.items())[0]self.from_name = from_nameself.to_name = schema['to_name'][0]self.labels = schema['labels']def predict(self, tasks, **kwargs):""" This is where inference happens: model returnsthe list of predictions based on input list of tasks"""predictions = []for task in tasks:predictions.append({'score': 0.987,? # prediction overall score, visible in the data manager columns'model_version': 'delorean-20151021',? # all predictions will be differentiated by model version'result': [{'from_name': self.from_name,'to_name': self.to_name,'type': 'choices','score': 0.5,? # per-region score, visible in the editor'value': {'choices': [self.labels[0]]}}]})return predictionsdef fit(self, annotations, **kwargs):""" This is where training happens: train your model given list of annotations,then returns dict with created links and resources"""return {'path/to/created/model': 'my/model.bin'}

進入到my_backend文件夾,可以看到下述文件:

在my_backend文件夾下新建model文件夾,將訓練好的YOLO模型文件放入model下:

修改my_backend文件夾下的model.py,代碼如下:

#!/user/bin/env?python3# ?-*-?coding:?utf-8?-*-import osfrom typing import List, Dict, Optionalimport torchfrom label_studio_ml.model import LabelStudioMLBasefrom label_studio_ml.utils import get_single_tag_keys, get_local_pathimport loggingfrom ultralytics import YOLOfrom PIL import Image# 設置日志logger = logging.getLogger(__name__)logging.basicConfig(level=logging.INFO)MODEL_PATH = os.getenv('MODEL_PATH', '/data/projects/my_ml_backend/model/best.pt')DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')class DummyModel(LabelStudioMLBase):"""Custom ML Backend model"""def __init__(self, **kwargs):super(DummyModel, self).__init__(**kwargs)from_name, schema = list(self.parsed_label_config.items())[0]self.from_name = from_nameself.to_name = schema['to_name'][0]self.labels = schema['labels']# 訓練參數self.train_epochs = int(os.getenv('TRAIN_EPOCHS', 150))self.train_batch_size = int(os.getenv('TRAIN_BATCH_SIZE', 18))def predict(self, tasks: List[Dict], context: Optional[Dict] = None, **kwargs):task = tasks[0]print(f'''\Run prediction on {tasks}Received context: {context}Project ID: {task['id']}Label config: {self.label_config}Parsed JSON Label config: {self.parsed_label_config}''')img_url = task['data']['image']image_path = self.get_local_path(url=img_url)print(f'image_path: {image_path}')# Getting URL and loading imageimage = Image.open(image_path)# Height and width of imageoriginal_width, original_height = image.size# Creating list for predictions and variable for scorespredictions = []scores = 0i = 0# Initialize self variablesself.from_name, self.to_name, self.value, self.classes = get_single_tag_keys(self.parsed_label_config, 'RectangleLabels', 'Image')# 加載自己的yolov11模型logger.info(f"加載YOLO11模型: {MODEL_PATH}")self.model = YOLO(MODEL_PATH)# 檢查GPU可用性logger.info(f"使用設備: {'GPU ?' if DEVICE.type == 'cuda' else 'CPU ??'}")# 改動的地方, 增加了conf配置, 只有conf>=0.5的才會被標記出來# 默認conf是0.25, 不改的話被標注的地方肯能會很多, 根據自己的實際情況配置# Getting prediction using modelresults = self.model.predict(image, conf=0.5)# print(results)# Getting mask segments, boxes from model predictionfor result in results:for i, prediction in enumerate(result.boxes):score = prediction.conf.item()label_index = int(prediction.cls.item())xyxy = prediction.xyxy[0].tolist()# print(f"{i} prediction", prediction)# x_center, y_center, w, h = boxpredictions.append({"id": str(i),"from_name": self.from_name,"to_name": self.to_name,"type": "rectanglelabels","score": score,"original_width": original_width,"original_height": original_height,"image_rotation": 0,"value": {"rotation": 0,# 坐標轉換, 只有轉換后才能標注在正確的位置"x": xyxy[0] / original_width * 100,"y": xyxy[1] / original_height * 100,"width": (xyxy[2] - xyxy[0]) / original_width * 100,"height": (xyxy[3] - xyxy[1]) / original_height * 100,"rectanglelabels": [self.labels[label_index]]}})scores += scorelogger.info(f"預測完成: 檢測到 {len(predictions)} 個對象")# Dict with final dicts with predictionsfinal_prediction = [{"result": predictions,"score": scores / (i + 1),"model_version": "11x"}]return final_predictiondef fit(self, event, data, **kwargs):"""使用新標注數據訓練模型參數:event: 事件類型 ('ANNOTATION_CREATED', 'ANNOTATION_UPDATED')data: 包含標注數據的字典**kwargs: 額外參數"""# 檢查是否有訓練數據if not self.train_output:logger.info("初始化訓練數據存儲")self.train_output = {'image_paths': [],'labels': []}# 獲取標注信息annotation = data['annotation']image_url = annotation['task']['data']['image']image_path = self.get_local_path(image_url)# 解析標注結果bboxes = []for result in annotation['result']:if result['from_name'] == self.from_name:value = result['value']label = value['rectanglelabels'][0]# 獲取圖像尺寸image = Image.open(image_path)img_width, img_height = image.size# 轉換為絕對坐標x = value['x'] * img_width / 100y = value['y'] * img_height / 100width = value['width'] * img_width / 100height = value['height'] * img_height / 100# YOLO格式: [class_idx, x_center, y_center, width, height] (歸一化)x_center = (x + width / 2) / img_widthy_center = (y + height / 2) / img_heightnorm_width = width / img_widthnorm_height = height / img_heightclass_idx = self.labels.index(label)bboxes.append([class_idx, x_center, y_center, norm_width, norm_height])# 保存訓練數據self.train_output['image_paths'].append(image_path)self.train_output['labels'].append(bboxes)logger.info(f"收到新標注: 圖像={image_path}, 標注數={len(bboxes)}")logger.info(f"當前訓練集大小: {len(self.train_output['image_paths'])}")# 當有足夠數據時開始訓練if len(self.train_output['image_paths']) >= 10:logger.info("達到最小訓練集大小,開始訓練...")self.train_model()# 重置訓練數據self.train_output = {'image_paths': [],'labels': []}# 返回新模型信息return {'model_path': MODEL_PATH,'model_version': f"retrained-{len(self.train_output['image_paths'])}"}return {}def train_model(self):"""使用收集的標注數據訓練模型"""logger.info("準備訓練數據...")# 創建YOLO格式的訓練數據目錄結構train_dir = 'yolo_train_data'images_dir = os.path.join(train_dir, 'images')labels_dir = os.path.join(train_dir, 'labels')os.makedirs(images_dir, exist_ok=True)os.makedirs(labels_dir, exist_ok=True)# 創建數據集描述文件with open(os.path.join(train_dir, 'dataset.yaml'), 'w') as f:f.write(f"train: {os.path.abspath(images_dir)}\n")f.write(f"nc: {len(self.labels)}\n")f.write(f"names: {self.labels}\n")# 準備訓練數據for i, (image_path, bboxes) in enumerate(zip(self.train_output['image_paths'],self.train_output['labels'])):# 復制圖像img = Image.open(image_path)img_filename = f'train_{i}.jpg'img.save(os.path.join(images_dir, img_filename))# 創建標簽文件label_filename = f'train_{i}.txt'with open(os.path.join(labels_dir, label_filename), 'w') as f:for bbox in bboxes:class_idx, x_center, y_center, width, height = bboxf.write(f"{class_idx} {x_center} {y_center} {width} {height}\n")logger.info(f"訓練數據準備完成: {len(self.train_output['image_paths'])} 張圖像")# 訓練模型 (這里簡化了實際訓練過程)logger.info(f"開始訓練模型 (模擬) - 周期={self.train_epochs}, 批次大小={self.train_batch_size}")# 調用YOLO的訓練腳本:# import subprocess# subprocess.run(['python', 'train.py'])# 參數配置: --img 640 --batch {self.train_batch_size} --epochs {self.train_epochs}#????????? --data {os.path.join(train_dir, 'dataset.yaml')} --weights {MODEL_PATH}logger.info("訓練完成! 模型已更新")# 重新加載訓練后的模型# self.model = YOLO(MODEL_PATH)

最后執行命令label-studio-ml start my_ml_backend -p 9094來啟動模型后端服務

三、labelstudio中配置后端模型服務

進入到項目中點擊Model菜單,然后點擊connect model,彈框填寫配置好服務地址,點擊保存即可。

四、逐個點擊任務即可完成自動化標注

點擊任務后自動加載模型推理,片刻后得到自動化標注結果,基于該標注結果可繼續修改標注。

可以看到,預測列為1的表明已經推理完畢。

對應的腳本打印信息如下:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90603.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90603.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90603.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從零開始大模型之編碼注意力機制

從零開始大模型之編碼注意力機制1 長序列建模中的問題2 使用注意力機制捕捉數據依賴關系3 自注意力機制4 實現帶可訓練權重的自注意力機制5 利用因果注意力隱藏未來詞匯6 將單頭注意力擴展到多頭注意力7 Pytorch附錄7.1 torch.nn.Linear多頭掩碼可訓練權重的注意力機制。為什么…

小架構step系列26:Spring提供的validator

1 概述對于Web服務,需要對請求的參數進行校驗,可以對不合法的參數進行提示,提高用戶體驗。也可以防止有人惡意用一些非法的參數對網站造成破壞。如果是對每個參數都寫一段代碼來判斷值是否合法,那校驗的代碼就很多,也很…

0編程基礎:用TRAE寫出了會蹦跳躲避散發炫光的貪吃蛇小游戲

在某個深夜的代碼深淵里,一個從未寫過print("Hello World")的小白開發者,竟用自然語言指令讓貪吃蛇跳起了"光棱華爾茲"——蛇身折射出彩虹軌跡,食物像星艦般自動規避追擊,甚至實現了四頭蛇的"量子糾纏式…

在Word和WPS文字中要同時查看和編輯一個文檔的兩個地方?拆分窗口

如果要在Word或WPS文字的長文檔中同時查看兩部同步的地方(文檔位置),來回跳轉和滾動費時費力,使用拆分窗口的功能即可搞定。將窗口一分為二,上下對照非常方便。一、拆分窗口的路徑Word和WPS基本一樣,就是菜…

Windows系統下安裝mujoco環境的教程【原創】

在學習Mujoco仿真的過程中,我先前是在linux系統下進行的研究與學習,今天來試試看在windows系統中安裝mujoco仿真環境。 先前在linux中的一些關于mujoco學習記錄的博客:Mujoco仿真【xml文件的學習 3】_mujoco打開xml文件-CSDN博客 下面開始wi…

CSS中篇

#Flex布局#1、什么是flex布局?flex 布局,全稱彈性布局(Flexible Box Layout),是 CSS3 中引入的一種新的布局模式。它主要通過給容器設置相關屬性,來控制容器內部子元素的排列方式。相比傳統的浮動布局和定位…

《云計算藍皮書 2025 》發布:云計算加速成為智能時代核心引擎

近日,中國信息通信研究院發布了《云計算藍皮書(2025 年)》,全面剖析了云計算領域的發展現狀與未來趨勢。在人工智能蓬勃發展的當下,云計算正從基礎資源供給向智能時代的核心引擎加速轉變,成為重塑全球數字競…

excel刪除重復項場景

問題描述 問題描述:因為表格中存在多條相同的數據,我現在excel有一列,值為#N/A 。另外有列叫做藥品名稱、規格、廠家 我要刪除值為 #N/A,并且 藥品名稱、規格、廠家相等的數據,那條相同的刪掉,只保留一條,…

Vue 3 與 Element Plus 中的 /deep/ 選擇器問題

Vue 3 與 Element Plus 中的 /deep/ 選擇器問題 在 Vue3 中使用 Element Plus 組件時,使用 ::v-deep或 :deep()的場景取決于 ??樣式作用域?? 和 ??選擇器目標??。以下是關鍵區別:

2025暑期—06神經網絡-常見網絡

六個濾波核提取特征Maps5X5 卷積核,1個閾值 6個元素,卷積后兩邊各少兩個,28*28像素 又有6個卷積核,所以有122304個連接,連接數不多是因為很多都是公用參數的。池化是參數池化,和當前平均最大不一樣。編程14…

硅基計劃3.0 學習總結 叁 棧和隊列

文章目錄一、棧1. 模擬實現棧2. 小試牛刀1. 判斷一個棧的出棧順序是否為題目給定情況2. 括號匹配3. 逆波蘭表達式求值4. 求最小棧元素3. 單鏈表實現棧二、隊列1. 官方隊列類Queue2. 雙向鏈表模擬實現Queue類3. 順序表模擬實現Queue類4. 雙端隊列5. 隊列實現棧6. 棧實現隊列一、…

飛行控制領軍者 | 邊界智控攜高安全級飛控系統亮相2025深圳eVTOL展

2025深圳eVTOL展將于2025年9月23日至25日在深圳坪山燕子湖國際會展中心盛大舉辦。本屆展會以 “低空經濟?eVTOL?航空應急救援?商載大型無人運輸機” 為核心,預計將匯聚200余位發言嘉賓、500 余家頂尖展商及15,000余名專業觀眾,規模盛大,精…

React狀態管理——Dva

目錄 一、安裝依賴 二、Dva注冊model方式 2.1 自動注冊models 2.2 手動注冊model方式 三、創建 dva 實例 四、創建 model 五、在組件中使用 六、動態加載Dva Model Dva 是一個基于 redux 和 redux-saga 的輕量級前端框架,可以方便地在 React 應用中管理狀態…

編程與數學 03-002 計算機網絡 05_以太網技術

編程與數學 03-002 計算機網絡 05_以太網技術一、以太網的基本原理(一)CSMA/CD協議的工作原理(二)以太網的幀結構二、以太網的拓撲結構與設備(一)傳統以太網的拓撲結構(二)交換機的工…

解決英文版Windows10安裝WireShark報錯

問題點擊WireShark安裝包進行安裝時報錯原因編碼方式故障解決方式修改操作系統編碼1.WinR,輸入Control,打開控制面板2.點擊Small icons3.點擊Region4.設置編碼UTF-8

利用aruco標定板標定相機

1、生成aruco標定板#include <opencv2/opencv.hpp> #include <opencv2/aruco.hpp> #include <opencv2/objdetect/aruco_detector.hpp> #include <iostream> #include <string>using namespace cv; using namespace std;int main() {int markers…

C/C++語言程序使用三種主要的內存分配方式,和python語言一樣么?

這是一個很好的比較問題&#xff01;C/C 和 Python 在內存分配方式上有本質的區別&#xff0c;雖然它們最終使用的都是計算機的物理內存&#xff08;堆、棧等&#xff09;&#xff0c;但語言層面提供的抽象和管理機制完全不同。核心區別&#xff1a;控制權&#xff1a; C/C 程序…

小電流驅動大電流:原理、實現方式與應用前景

目錄 一、什么是“小電流驅動大電流”&#xff1f; 舉個例子&#xff1a; 二、核心原理與實現方式 1. 電流放大原理 2. 電子開關元件 3. 控制電路設計 4. 附加保護措施 三、為什么采用“小電流驅動大電流”&#xff1f; 1. 提高安全性 2. 降低能耗 3. 改善效率 4. …

【DM數據守護集群搭建-讀寫分離】

DM數據守護集群搭建-讀寫分離 讀寫分離集群由一個主庫以及一個或者多個配置了即時&#xff08;Timely&#xff09;歸檔或實時&#xff08;Realtime&#xff09;歸檔的備庫組成&#xff0c;其主要目標是在保障數據庫可用性基礎上&#xff0c;實現讀、寫操作的自動分離&#xff0…

earth靶場

1、找ip和端口主機是192.168.6.213&#xff0c;因此靶場ip就是192.168.6.34&#xff0c;三個端口開放&#xff0c;我們去訪問一下頁面。三個端口都無法訪問。我們使用nmap進行dns解析。nmap -A -p- -T4 -sV 192.168.6.34把這兩條解析添加到hosts文件中去&#xff0c;這樣我們才…