点击下方卡片,关注“小白玩转Python”公众号
对于像 YOLO 这样的模型,使用带有标注图像数据集进行训练有时可能会有点令人望而却步。如果你需要处理自定义数据,并围绕其定义标注,那可能会有些耗时。但我找到了完美的解决方案——Grounding DINO!这种方法的突破之处在于,它将基于 Transformer 的检测器 DINO 与基础预训练相结合,可以从有限的人类输入中检测到任意对象。这篇简易指南向你解释了如何有效地将你的自定义数据集格式化为 PASCAL VOC 格式,并且让你惊讶地发现,在你的目标检测项目中,这些数据集可以轻松而有效地使用。
什么是图像标注?
对于目标检测,图像标注是训练机器学习模型以准确识别和定位图像中对象的基本步骤。这个过程包括使用边界框对感兴趣的每个对象进行标记,并提供相应的标签来描述每个对象是什么。让我们深入了解为什么这是必要的,它的用途以及其中涉及的挑战,包括为什么很难找到符合你特定需求的预标注数据。
为什么标注是必要的
机器学习模型的训练数据:目标检测模型通过观察示例来学习识别定义不同对象的模式和特征。这些示例被准确地标注,模型的性能就会越好。
精确度和准确性:正确的标注确保模型不仅能够识别对象,还能在不同的背景和环境中精确定位它们。这对于需要精确对象定位的应用非常重要,比如自动驾驶和医学影像。
多样化学习:通过对来自各种场景和对象变化的图像进行标注,模型可以学习更好地泛化,并在真实世界的情况下表现良好,减少误识别的可能性。
带标注图像的用途
自动驾驶:用于安全地检测行人、其他车辆和路标,以便导航。
零售:用于识别货架上的产品,以便进行库存管理或自助结账系统。
医疗保健:通过准确定位医学扫描中感兴趣的区域来帮助诊断。
监控:用于监视区域以检测可疑活动或跟踪感兴趣的对象。
手动标注中的挑战
耗时:在成千上万张图像中手动绘制边界框并标记每个对象是非常费时费力的。
需要准确性:边界框的准确绘制至关重要。不准确的标注会导致模型训练不良。
需要专业知识:某些领域需要具有专业知识的标注者,尤其是在医疗保健等领域,在那里理解医学图像至关重要。
可扩展性:随着数据量的增长,手动标注过程的规模化变得越来越具有挑战性,需要大量的人力资源投入。
预先标注数据的难度
特定要求:项目通常在要检测的对象方面具有独特要求,这使得很难找到完全符合这些需求的数据集。
质量和可靠性:公共数据集的质量和标注标准可能各不相同,这可能会影响目标检测模型的性能。
覆盖范围有限:某些领域或稀有对象可能在公开可用的数据集中代表性不足。
法律和隐私问题:使用预先标注的数据集可能会受到限制,或者需要遵守隐私法律,尤其是涉及人物或敏感地点的图像。
标注格式
图像标注存在各种格式,让我们简要了解一下其中一些:
PASCAL VOC 格式包含 XML 文件,详细描述图像信息、对象类标签和边界框坐标。
COCO 格式包含 JSON 文件,其中包含图像元数据、类别 ID 和边界框或分割掩码的标注。
YOLO 格式主要用于实时目标检测,每个图像都有一个文本文件,列出每个对象的类索引和归一化的边界框坐标。
什么是 Grounding DINO?
Grounding DINO 是一种创新的目标检测方法,它将基于 Transformer 的检测器 DINO 的优势与基础预训练相结合,实现了开放集目标检测。这意味着它可以检测到在训练期间未见过的对象,使其成为零样本模型。让我们分解一下 Grounding DINO 的显著之处以及它如何完成图像标注。
它使用基于 PyTorch 的框架设计用于开放集目标检测,即识别和定位模型没有显式训练识别的对象的任务。它通过 DINO 的架构和一种新颖的基础预训练策略的结合来实现这一点。像 Grounding DINO 这样的零样本模型可以识别未经直接训练的对象,这要归功于它理解和处理语言描述的能力。Grounding DINO 利用语言作为连接已见和未见对象的桥梁,使其能够仅基于文本描述识别项目。这种能力对于那些不可能为每个可能遇到的对象提供训练数据的应用非常有用。
如何标注图像?
Grounding DINO 通过接受图像和文本[标签]对作为输入。然后,它输出带有所有输入词的相似度分数的对象框,从而允许根据它们的文本描述检测对象。该模型使用阈值来决定哪些框要考虑,基于最高相似度分数,并且如果它们的分数超过一定阈值,则提取预测标签的词。这种方法使 Grounding DINO 不仅能够检测对象,还能够准确理解和标记它们,从根本上自动化了标注过程。用户可以指定短语以定位图像中特定的对象,使 Grounding DINO 成为创建带标注数据集的灵活工具。
以下是使用 Grounding DINO 自动标注图像的逐步指南,针对 Google Colab 环境进行了定制。该过程将指导您设置环境、安装 Grounding DINO、下载您的数据并对图像进行标注。
开始标注
步骤 1:检查 GPU 可用性 使用 !nvidia-smi 命令来检查是否有 GPU 可用以加快处理速度。
步骤 2:挂载 Google Drive(可选) 如果您的数据存储在 Google Drive 上,请使用以下代码挂载它:
from google.colab import drive
drive.mount('/content/drive')
步骤 3:设置主目录 定义一个 HOME 常量,以便轻松管理数据集、图像和模型:
import os
HOME = os.getcwd()
print(HOME)
步骤 4:安装 Grounding DINO 克隆 Grounding DINO 存储库,切换到特定的功能分支(如果需要),并安装依赖项:
%cd {HOME}
!git clone <https://github.com/IDEA-Research/GroundingDINO.git>
%cd {HOME}/GroundingDINO
# we use latest Grounding DINO model API that is not official yet
!git checkout feature/more_compact_inference_api
!pip install -q -e .
!pip install -q roboflow dataclasses-json onemetric
步骤 5:额外的依赖和验证 CUDA 和 PyTorch 确保正确安装并兼容 CUDA 和 PyTorch:
import torch
!nvcc --version
TORCH_VERSION = ".".join(torch.__version__.split(".")[:2])
CUDA_VERSION = torch.__version__.split("+")[-1]
print("torch: ", TORCH_VERSION, "; cuda: ", CUDA_VERSION)
import roboflow
import supervision
print(
"roboflow:", roboflow.__version__,
"; supervision:", supervision.__version__
)
# confirm that configuration file exist
import os
CONFIG_PATH = os.path.join(HOME, "GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py")
print(CONFIG_PATH, "; exist:", os.path.isfile(CONFIG_PATH))
步骤 6:下载配置和权重 确保克隆的存储库中存在配置文件,并下载模型权重:
# download weights file
%cd {HOME}
!mkdir {HOME}/weights
%cd {HOME}/weights
!wget -q <https://github.com/IDEA-Research/GroundingDINO/releases/download/v0.1.0-alpha/groundingdino_swint_ogc.pth>
# confirm that weights file exist
import os
WEIGHTS_PATH = os.path.join(HOME, "weights", "groundingdino_swint_ogc.pth")
print(WEIGHTS_PATH, "; exist:", os.path.isfile(WEIGHTS_PATH))
步骤 7:下载并准备您的数据集 如果您的数据集被压缩在您的驱动器中,请将其解压缩到本地目录:
import zipfile
# Path to the zip file
zip_file_path = "/content/drive/MyDrive/....[your file path]"
# Directory to extract the contents of the zip file
extract_dir = "/content/data"
# Unzip the file
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
zip_ref.extractall(extract_dir)
print("Extraction complete.")
步骤 8:加载 Grounding DINO 模型 使用配置和权重路径加载模型:
%cd {HOME}/GroundingDINO
from groundingdino.util.inference import Model
model = Model(model_config_path=CONFIG_PATH, model_checkpoint_path=WEIGHTS_PATH)
步骤 9:对数据集进行标注并保存为 PASCAL voc 使用模型对图像进行标注。
您可以根据需要以不同的模式运行推断,如标题、类别或增强类别。推断后,使用检测结果和标签通过您喜欢的方法或提供的实用函数来标注图像。通过迭代您的图像来自动标注整个数据集,运行模型以检测对象,并保存带有标注的图像及其 PASCAL VOC XML 文件。
import os
import cv2
import xml.etree.ElementTree as ET
from groundingdino.util.inference import Model
from tqdm import tqdm
# Define the home directory and the path to the dataset
HOME = "/content"
DATASET_DIR = os.path.join(HOME, "data", "ingredients_images_dataset")
# Load the Grounding DINO model
MODEL_CONFIG_PATH = os.path.join(HOME, "GroundingDINO", "groundingdino", "config", "GroundingDINO_SwinT_OGC.py")
WEIGHTS_PATH = os.path.join(HOME, "weights", "groundingdino_swint_ogc.pth")
model = Model(model_config_path=MODEL_CONFIG_PATH, model_checkpoint_path=WEIGHTS_PATH)
# Load class labels from the file
LABELS_FILE_PATH = "[ txt file path containing your images labels one per line]"
with open(LABELS_FILE_PATH, "r") as f:
CLASSES = [line.strip() for line in f.readlines()]
# Define annotation thresholds
BOX_THRESHOLD = 0.35
TEXT_THRESHOLD = 0.25
# Function to enhance class names
def enhance_class_name(class_names):
return [f"all {class_name}s" for class_name in class_names]
# Function to create Pascal VOC format XML annotation
def create_pascal_voc_xml(image_filename, image_shape, boxes, labels):
annotation = ET.Element("annotation")
folder = ET.SubElement(annotation, "folder")
folder.text = "ingredient_annotations" # Folder name for annotations
filename = ET.SubElement(annotation, "filename")
filename.text = image_filename
source = ET.SubElement(annotation, "source")
database = ET.SubElement(source, "database")
database.text = "Unknown"
size = ET.SubElement(annotation, "size")
width = ET.SubElement(size, "width")
height = ET.SubElement(size, "height")
depth = ET.SubElement(size, "depth")
width.text = str(image_shape[1])
height.text = str(image_shape[0])
depth.text = str(image_shape[2])
segmented = ET.SubElement(annotation, "segmented")
segmented.text = "0"
for box, label in zip(boxes, labels):
object = ET.SubElement(annotation, "object")
name = ET.SubElement(object, "name")
pose = ET.SubElement(object, "pose")
truncated = ET.SubElement(object, "truncated")
difficult = ET.SubElement(object, "difficult")
bndbox = ET.SubElement(object, "bndbox")
xmin = ET.SubElement(bndbox, "xmin")
ymin = ET.SubElement(bndbox, "ymin")
xmax = ET.SubElement(bndbox, "xmax")
ymax = ET.SubElement(bndbox, "ymax")
name.text = label
pose.text = "Unspecified"
truncated.text = "0"
difficult.text = "0"
xmin.text = str(int(box[0]))
ymin.text = str(int(box[1]))
xmax.text = str(int(box[2]))
ymax.text = str(int(box[3]))
# Format the XML for better readability
xml_string = ET.tostring(annotation, encoding="unicode")
return xml_string
# Function to annotate images in a directory and save annotated images in Pascal VOC format
def annotate_images_in_directory(directory):
for class_name in CLASSES:
class_dir = os.path.join(directory, class_name)
annotated_dir = os.path.join(directory, f"{class_name}_annotated")
os.makedirs(annotated_dir, exist_ok=True)
print("Processing images in directory:", class_dir)
if os.path.isdir(class_dir):
for image_name in tqdm(os.listdir(class_dir)):
image_path = os.path.join(class_dir, image_name)
image = cv2.imread(image_path)
if image is None:
print("Failed to load image:", image_path)
continue
detections = model.predict_with_classes(
image=image,
classes=enhance_class_name([class_name]),
box_threshold=BOX_THRESHOLD,
text_threshold=TEXT_THRESHOLD
)
# Drop potential detections with phrase not part of CLASSES set
detections = detections[detections.class_id != None]
# Drop potential detections with area close to area of the whole image
detections = detections[(detections.area / (image.shape[0] * image.shape[1])) < 0.9]
# Drop potential double detections
detections = detections.with_nms()
# Create the Pascal VOC XML annotation for this image
xml_annotation = create_pascal_voc_xml(image_filename=image_name, image_shape=image.shape, boxes=detections.xyxy, labels=[class_name])
# Save the Pascal VOC XML annotation to a file
xml_filename = os.path.join(annotated_dir, f"{os.path.splitext(image_name)[0]}.xml")
with open(xml_filename, "w") as xml_file:
xml_file.write(xml_annotation)
# Save the annotated image
annotated_image_path = os.path.join(annotated_dir, image_name)
cv2.imwrite(annotated_image_path, image)
# Annotate images in the dataset directory
annotate_images_in_directory(DATASET_DIR)
结论
总之,Grounding DINO 彻底改变了我们处理图像标注的方式,简化了传统上既耗时又复杂的过程。本指南向您展示了如何利用 Grounding DINO 的强大功能进行高效的开放集目标检测,简化了您在人工智能和机器学习项目中的工作。使用这些技巧,您可以快速、轻松地处理自定义数据集,并让您的目标检测模型在不同场景中表现出色。
只需几个简单的步骤,您就可以为您的图像数据集生成准确的标注,并训练具有高性能的目标检测模型。无论您是在研究、开发新应用程序还是为客户提供服务,Grounding DINO 都将成为您的宝贵工具。
· END ·
HAPPY LIFE
本文仅供学习交流使用,如有侵权请联系作者删除