chore: address feedback on google gemini support
This commit is contained in:
parent
98ba121b5c
commit
6448fc7ea1
|
|
@ -102,10 +102,10 @@ status: new
|
|||
:::supervision.detection.utils.xyxy_to_xywh
|
||||
|
||||
<div class="md-typeset">
|
||||
<h2><a href="#supervision.detection.utils.normalized_xyxy_to_absolute_xyxy">normalized_xyxy_to_absolute_xyxy</a></h2>
|
||||
<h2><a href="#supervision.detection.utils.denormalize_boxes">denormalize_boxes</a></h2>
|
||||
</div>
|
||||
|
||||
:::supervision.detection.utils.normalized_xyxy_to_absolute_xyxy
|
||||
:::supervision.detection.utils.denormalize_boxes
|
||||
|
||||
<h2><a href="#supervision.detection.utils.xyxy_to_xcycarh">xyxy_to_xcycarh</a></h2>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ from supervision.detection.utils import (
|
|||
mask_to_xyxy,
|
||||
move_boxes,
|
||||
move_masks,
|
||||
normalized_xyxy_to_absolute_xyxy,
|
||||
denormalize_boxes,
|
||||
oriented_box_iou_batch,
|
||||
pad_boxes,
|
||||
polygon_to_mask,
|
||||
|
|
|
|||
|
|
@ -847,39 +847,18 @@ class Detections:
|
|||
|
||||
Examples:
|
||||
```python
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
import supervision as sv
|
||||
from PIL import Image
|
||||
|
||||
IMAGE = Image.open(<SOURCE_IMAGE_PATH>)
|
||||
GENAI_CLIENT = genai.Client(api_key=<API_KEY>)
|
||||
gemini_response_text = \"\"\"```json
|
||||
[
|
||||
{"box_2d": [543, 40, 728, 200], "label": "Cat", "id": 1},
|
||||
{"box_2d": [653, 352, 820, 522], "label": "Dog", "id": 2}
|
||||
]
|
||||
```\"\"\"
|
||||
|
||||
system_instructions = '''
|
||||
Return bounding boxes as a JSON array with labels and ids. Never return masks or code fencing. Limit to 25 objects.
|
||||
If an object is present multiple times, name them according to their unique characteristic (colors, size, position, unique characteristics, etc..).
|
||||
'''
|
||||
|
||||
safety_settings = [
|
||||
types.SafetySetting(
|
||||
category="HARM_CATEGORY_DANGEROUS_CONTENT",
|
||||
threshold="BLOCK_ONLY_HIGH",
|
||||
),
|
||||
]
|
||||
|
||||
response = GENAI_CLIENT.models.generate_content(
|
||||
model="gemini-2.0-flash-exp",
|
||||
contents=[prompt, IMAGE],
|
||||
config = types.GenerateContentConfig(
|
||||
system_instruction=system_instructions,
|
||||
temperature=0.5,
|
||||
safety_settings=safety_settings,
|
||||
)
|
||||
)
|
||||
|
||||
detections = sv.Detections.from_lmm(
|
||||
sv.LMM.GOOGLE_GEMINI_2_0,
|
||||
response.text,
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.GOOGLE_GEMINI_2_0,
|
||||
gemini_response_text,
|
||||
resolution_wh=(IMAGE.size[0], IMAGE.size[1]),
|
||||
)
|
||||
|
||||
|
|
@ -890,7 +869,6 @@ class Detections:
|
|||
detections.data
|
||||
# {'class_name': ['cat', 'dog']}
|
||||
```
|
||||
|
||||
""" # noqa: E501 // docs
|
||||
|
||||
# filler logic mapping old from_lmm to new from_vlm
|
||||
|
|
@ -930,6 +908,66 @@ class Detections:
|
|||
def from_vlm(
|
||||
cls, vlm: Union[VLM, str], result: Union[str, dict], **kwargs: Any
|
||||
) -> Detections:
|
||||
"""
|
||||
Creates a Detections object from the given result string based on the specified
|
||||
Vision Language Model (VLM).
|
||||
|
||||
Args:
|
||||
vlm (Union[VLM, str]): The type of VLM (Large Multimodal Model) to use.
|
||||
result (str): The result string containing the detection data.
|
||||
**kwargs (Any): Additional keyword arguments required by the specified VLM.
|
||||
|
||||
Returns:
|
||||
Detections: A new Detections object.
|
||||
|
||||
Raises:
|
||||
ValueError: If the VLM is invalid, required arguments are missing, or
|
||||
disallowed arguments are provided.
|
||||
ValueError: If the specified VLM is not supported.
|
||||
|
||||
Examples:
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
paligemma_result = "<loc0256><loc0256><loc0768><loc0768> cat"
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.PALIGEMMA,
|
||||
paligemma_result,
|
||||
resolution_wh=(1000, 1000),
|
||||
classes=['cat', 'dog']
|
||||
)
|
||||
detections.xyxy
|
||||
# array([[250., 250., 750., 750.]])
|
||||
|
||||
detections.class_id
|
||||
# array([0])
|
||||
```
|
||||
|
||||
Examples:
|
||||
```python
|
||||
import supervision as sv
|
||||
|
||||
gemini_response_text = \"\"\"```json
|
||||
[
|
||||
{"box_2d": [543, 40, 728, 200], "label": "Cat", "id": 1},
|
||||
{"box_2d": [653, 352, 820, 522], "label": "Dog", "id": 2}
|
||||
]
|
||||
```\"\"\"
|
||||
|
||||
detections = sv.Detections.from_vlm(
|
||||
sv.VLM.GOOGLE_GEMINI_2_0,
|
||||
gemini_response_text,
|
||||
resolution_wh=(IMAGE.size[0], IMAGE.size[1]),
|
||||
)
|
||||
|
||||
detections.xyxy
|
||||
# array([[250., 250., 750., 750.]])
|
||||
detections.class_id
|
||||
# array([0])
|
||||
detections.data
|
||||
# {'class_name': ['cat', 'dog']}
|
||||
```
|
||||
"""
|
||||
vlm = validate_vlm_parameters(vlm, result, kwargs)
|
||||
|
||||
if vlm == VLM.PALIGEMMA:
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ def xyxy_to_xcycarh(xyxy: np.ndarray) -> np.ndarray:
|
|||
return result.astype(float)
|
||||
|
||||
|
||||
def normalized_xyxy_to_absolute_xyxy(
|
||||
def denormalize_boxes(
|
||||
normalized_xyxy: np.ndarray,
|
||||
resolution_wh: Tuple[int, int],
|
||||
normalization_factor: float = 1.0,
|
||||
|
|
@ -477,7 +477,7 @@ def normalized_xyxy_to_absolute_xyxy(
|
|||
[0.3, 0.4, 0.7, 0.8]
|
||||
])
|
||||
resolution_wh = (100, 200)
|
||||
sv.normalized_xyxy_to_absolute_xyxy(normalized_xyxy, resolution_wh)
|
||||
sv.denormalize_boxes(normalized_xyxy, resolution_wh)
|
||||
# array([
|
||||
# [ 10., 40., 50., 120.],
|
||||
# [ 30., 80., 70., 160.]
|
||||
|
|
@ -487,7 +487,7 @@ def normalized_xyxy_to_absolute_xyxy(
|
|||
[10., 20., 50., 60.],
|
||||
[30., 40., 70., 80.]
|
||||
])
|
||||
sv.normalized_xyxy_to_absolute_xyxy(normalized_xyxy, resolution_wh, max_value=100.0)
|
||||
sv.denormalize_boxes(normalized_xyxy, resolution_wh, max_value=100.0)
|
||||
# array([
|
||||
# [ 10., 40., 50., 120.],
|
||||
# [ 30., 80., 70., 160.]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|||
import numpy as np
|
||||
|
||||
from supervision.detection.utils import (
|
||||
normalized_xyxy_to_absolute_xyxy,
|
||||
denormalize_boxes,
|
||||
polygon_to_mask,
|
||||
polygon_to_xyxy,
|
||||
)
|
||||
|
|
@ -22,11 +22,7 @@ class LMM(Enum):
|
|||
FLORENCE_2 = "florence_2"
|
||||
QWEN_2_5_VL = "qwen_2_5_vl"
|
||||
GOOGLE_GEMINI_2_0 = "gemini_2_0"
|
||||
GOOGLE_GEMINI_2_0_FLASH_LITE = "gemini_2_0_flash_lite"
|
||||
GOOGLE_GEMINI_2_0_FLASH = "gemini_2_0_flash"
|
||||
GOOGLE_GEMINI_2_5 = "gemini_2_5"
|
||||
GOOGLE_GEMINI_2_5_FLASH_PREVIEW = "gemini_2_5_flash_preview"
|
||||
GOOGLE_GEMINI_2_5_PRO_PREVIEW = "gemini_2_5_pro_preview"
|
||||
|
||||
|
||||
class VLM(Enum):
|
||||
|
|
@ -34,11 +30,7 @@ class VLM(Enum):
|
|||
FLORENCE_2 = "florence_2"
|
||||
QWEN_2_5_VL = "qwen_2_5_vl"
|
||||
GOOGLE_GEMINI_2_0 = "gemini_2_0"
|
||||
GOOGLE_GEMINI_2_0_FLASH_LITE = "gemini_2_0_flash_lite"
|
||||
GOOGLE_GEMINI_2_0_FLASH = "gemini_2_0_flash"
|
||||
GOOGLE_GEMINI_2_5 = "gemini_2_5"
|
||||
GOOGLE_GEMINI_2_5_FLASH_PREVIEW = "gemini_2_5_flash_preview"
|
||||
GOOGLE_GEMINI_2_5_PRO_PREVIEW = "gemini_2_5_pro_preview"
|
||||
|
||||
|
||||
RESULT_TYPES: Dict[VLM, type] = {
|
||||
|
|
@ -47,10 +39,6 @@ RESULT_TYPES: Dict[VLM, type] = {
|
|||
VLM.QWEN_2_5_VL: str,
|
||||
VLM.GOOGLE_GEMINI_2_0: str,
|
||||
VLM.GOOGLE_GEMINI_2_5: str,
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH_LITE: str,
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH: str,
|
||||
VLM.GOOGLE_GEMINI_2_5_FLASH_PREVIEW: str,
|
||||
VLM.GOOGLE_GEMINI_2_5_PRO_PREVIEW: str,
|
||||
}
|
||||
|
||||
REQUIRED_ARGUMENTS: Dict[VLM, List[str]] = {
|
||||
|
|
@ -59,10 +47,6 @@ REQUIRED_ARGUMENTS: Dict[VLM, List[str]] = {
|
|||
VLM.QWEN_2_5_VL: ["input_wh", "resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_0: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH_LITE: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5_FLASH_PREVIEW: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5_PRO_PREVIEW: ["resolution_wh"],
|
||||
}
|
||||
|
||||
ALLOWED_ARGUMENTS: Dict[VLM, List[str]] = {
|
||||
|
|
@ -71,10 +55,6 @@ ALLOWED_ARGUMENTS: Dict[VLM, List[str]] = {
|
|||
VLM.QWEN_2_5_VL: ["input_wh", "resolution_wh", "classes"],
|
||||
VLM.GOOGLE_GEMINI_2_0: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH_LITE: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_0_FLASH: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5_FLASH_PREVIEW: ["resolution_wh"],
|
||||
VLM.GOOGLE_GEMINI_2_5_PRO_PREVIEW: ["resolution_wh"],
|
||||
}
|
||||
|
||||
SUPPORTED_TASKS_FLORENCE_2 = [
|
||||
|
|
@ -357,9 +337,24 @@ def from_google_gemini(
|
|||
resolution_wh: Tuple[int, int],
|
||||
) -> Tuple[np.ndarray, np.ndarray]:
|
||||
"""
|
||||
Parse and scale bounding boxes from Google Gemini style JSON output.
|
||||
https://aistudio.google.com/
|
||||
https://ai.google.dev/gemini-api/docs/vision?lang=python
|
||||
Parse and scale bounding boxes from Google Gemini style
|
||||
[JSON output](https://ai.google.dev/gemini-api/docs/vision?lang=python).
|
||||
|
||||
The JSON is expected to be enclosed in triple backticks with the format:
|
||||
```json
|
||||
[
|
||||
{"box_2d": [x1, y1, x2, y2], "label": "some class name"},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
For example:
|
||||
```json
|
||||
[
|
||||
{"box_2d": [10, 20, 110, 120], "label": "cat"},
|
||||
{"box_2d": [50, 100, 150, 200], "label": "dog"}
|
||||
]
|
||||
```
|
||||
|
||||
Args:
|
||||
result: String containing the JSON snippet enclosed by triple backticks.
|
||||
|
|
@ -400,7 +395,7 @@ def from_google_gemini(
|
|||
box = item["box_2d"]
|
||||
# Gemini bbox order is [y_min, x_min, y_max, x_max]
|
||||
xyxy.append(
|
||||
normalized_xyxy_to_absolute_xyxy(
|
||||
denormalize_boxes(
|
||||
np.array([box[1], box[0], box[3], box[2]]).astype(np.float64),
|
||||
resolution_wh=(w, h),
|
||||
normalization_factor=1000,
|
||||
|
|
|
|||
Loading…
Reference in New Issue