简化目标检测:使用 Grounding DINO 对自定义数据集进行标注

点击下方卡片,关注“小白玩转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

1702558895353c273b1fa3f048e7380a.png

本文仅供学习交流使用,如有侵权请联系作者删除

目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
根据提供的引用内容,Grounding DINO是一种结合了DINO和基于Transformer的检测器的模型,用于开放式目标检测。它的输入是图像和文本,输出是多个[物体框,名词短语]对。具体来说,Grounding DINO使用DINO模型对图像和文本进行编码,然后使用基于Transformer的检测器对编码后的特征进行检测,最终输出[物体框,名词短语]对。 下面是一个简单的示例代码,演示如何使用Grounding DINO进行开放式目标检测: ```python import torch from torchvision.models.detection import fasterrcnn_resnet50_fpn from transformers import ViTFeatureExtractor, ViTForImageClassification from transformers.models.dino.modeling_dino import DINOHead # 加载预训练的DINO模型和ViT模型 dino = ViTForImageClassification.from_pretrained('facebook/dino-vit-base') dino_head = DINOHead(dino.config) dino_head.load_state_dict(torch.load('dino_head.pth')) dino.eval() vit_feature_extractor = ViTFeatureExtractor.from_pretrained('google/vit-base-patch16-224') # 加载预训练的Faster R-CNN检测器 model = fasterrcnn_resnet50_fpn(pretrained=True) model.eval() # 输入图像和文本 image = Image.open('example.jpg') text = 'a person riding a bike' # 对图像和文本进行编码 image_features = vit_feature_extractor(images=image, return_tensors='pt')['pixel_values'] text_features = dino_head.get_text_features(text) image_embedding, text_embedding = dino(image_features, text_features) # 使用Faster R-CNN检测器进行目标检测 outputs = model(image_embedding) boxes = outputs[0]['boxes'] labels = outputs[0]['labels'] # 输出[物体框,名词短语]对 for i in range(len(boxes)): print([boxes[i], labels[i]]) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值