경계 상자 감지

이번 실험 버전에서는 개발자에게 이미지 및 동영상 내 객체 감지 및 위치 지정을 위한 강력한 도구를 제공합니다. 개발자는 경계 상자로 객체를 정확하게 식별하고 윤곽을 그려 다양한 애플리케이션을 활용하고 프로젝트의 지능을 향상할 수 있습니다.

주요 이점:

  • 간단함: 컴퓨터 비전 전문 지식과 관계없이 객체 감지 기능을 애플리케이션에 쉽게 통합할 수 있습니다.
  • 맞춤설정 가능: 맞춤 모델을 학습하지 않고도 맞춤 안내 (예: '이 이미지의 모든 녹색 물체의 경계 상자를 확인하고 싶습니다')에 따라 경계 상자를 생성할 수 있습니다.

기술 세부정보:

  • 입력: 프롬프트 및 관련 이미지 또는 동영상 프레임
  • 출력: [y_min, x_min, y_max, x_max] 형식의 경계 상자입니다. 왼쪽 상단이 원점입니다. xy 축은 각각 가로 및 세로로 이동합니다. 좌표 값은 모든 이미지에 대해 0~1,000으로 정규화됩니다.
  • 시각화: AI 스튜디오 사용자에게는 UI 내에 표시된 경계 상자가 표시됩니다. Vertex AI 사용자는 맞춤 시각화 코드를 통해 경계 상자를 시각화해야 합니다.

Python용 생성형 AI SDK

Python용 Google Gen AI SDK를 설치하거나 업데이트하는 방법을 알아보세요.
자세한 내용은 Python용 Gen AI SDK API 참고 문서 또는 python-genai GitHub 저장소를 참고하세요.
Vertex AI에서 Gen AI SDK를 사용하도록 환경 변수를 설정합니다.

# Replace the `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION` values
# with appropriate values for your project.
export GOOGLE_CLOUD_PROJECT=GOOGLE_CLOUD_PROJECT
export GOOGLE_CLOUD_LOCATION=us-central1
export GOOGLE_GENAI_USE_VERTEXAI=True

import requests

from google import genai
from google.genai.types import (
    GenerateContentConfig,
    HttpOptions,
    Part,
    SafetySetting,
)

from PIL import Image, ImageColor, ImageDraw

from pydantic import BaseModel

class BoundingBox(BaseModel):
    """
    Represents a bounding box with its 2D coordinates and associated label.

    Attributes:
        box_2d (list[int]): A list of integers representing the 2D coordinates of the bounding box,
                            typically in the format [x_min, y_min, x_max, y_max].
        label (str): A string representing the label or class associated with the object within the bounding box.
    """

    box_2d: list[int]
    label: str

def plot_bounding_boxes(image_uri: str, bounding_boxes: list[BoundingBox]) -> None:
    """
    Plots bounding boxes on an image with markers for each a name, using PIL, normalized coordinates, and different colors.

    Args:
        img_path: The path to the image file.
        bounding_boxes: A list of bounding boxes containing the name of the object
        and their positions in normalized [y1 x1 y2 x2] format.
    """

    with Image.open(requests.get(image_uri, stream=True, timeout=10).raw) as im:
        width, height = im.size
        draw = ImageDraw.Draw(im)

        colors = list(ImageColor.colormap.keys())

        for i, bbox in enumerate(bounding_boxes):
            y1, x1, y2, x2 = bbox.box_2d
            abs_y1 = int(y1 / 1000 * height)
            abs_x1 = int(x1 / 1000 * width)
            abs_y2 = int(y2 / 1000 * height)
            abs_x2 = int(x2 / 1000 * width)

            color = colors[i % len(colors)]

            draw.rectangle(
                ((abs_x1, abs_y1), (abs_x2, abs_y2)), outline=color, width=4
            )
            if bbox.label:
                draw.text((abs_x1 + 8, abs_y1 + 6), bbox.label, fill=color)

        im.show()

client = genai.Client(http_options=HttpOptions(api_version="v1"))

config = GenerateContentConfig(
    system_instruction="""
    Return bounding boxes as an array with labels.
    Never return masks. Limit to 25 objects.
    If an object is present multiple times, give each object a unique label
    according to its distinct characteristics (colors, size, position, etc..).
    """,
    temperature=0.5,
    safety_settings=[
        SafetySetting(
            category="HARM_CATEGORY_DANGEROUS_CONTENT",
            threshold="BLOCK_ONLY_HIGH",
        ),
    ],
    response_mime_type="application/json",
    response_schema=list[BoundingBox],
)

image_uri = "https://storage.googleapis.com/generativeai-downloads/images/socks.jpg"

response = client.models.generate_content(
    model="gemini-2.0-flash-001",
    contents=[
        Part.from_uri(
            file_uri=image_uri,
            mime_type="image/jpeg",
        ),
        "Output the positions of the socks with a face. Label according to position in the image.",
    ],
    config=config,
)
print(response.text)
plot_bounding_boxes(image_uri, response.parsed)

# Example response:
# [
#     {"box_2d": [36, 246, 380, 492], "label": "top left sock with face"},
#     {"box_2d": [260, 663, 640, 917], "label": "top right sock with face"},
# ]