mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
feat(scenegraph): add ImageHashPipeline protocol and update query API
- Introduce ImageHashPipeline Protocol for extensible hash computation - Rename query_crop_index to query_index for clarity - Make query_crop nullable to handle missing crop edge case - Add keyword-only arguments for better API clarity - Handle empty scene graph objects gracefully - Add comprehensive test coverage for query_image_against_scene_graph
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
This module exports the main scenegraph objects for easy import:
|
||||
|
||||
from mini_nav.scenegraph import SimpleSceneGraph, RoomNode, ObjectNode
|
||||
from scenegraph import SimpleSceneGraph, RoomNode, ObjectNode
|
||||
"""
|
||||
|
||||
from .hash_codec import (
|
||||
@@ -13,13 +13,18 @@ from .hash_codec import (
|
||||
hash_bytes_to_cam_row,
|
||||
)
|
||||
from .objectnode import ObjectNode
|
||||
from .query import ImageSceneGraphQueryResult, query_image_against_scene_graph
|
||||
from .query import (
|
||||
ImageHashPipeline,
|
||||
ImageSceneGraphQueryResult,
|
||||
query_image_against_scene_graph,
|
||||
)
|
||||
from .roomnode import RoomNode
|
||||
from .scenegraph import SceneGraphMatch, SimpleSceneGraph
|
||||
from .software_cam import CamMatch, SoftwareCamIndex, xnor_popcount_score
|
||||
|
||||
__all__ = [
|
||||
"CamMatch",
|
||||
"ImageHashPipeline",
|
||||
"ImageSceneGraphQueryResult",
|
||||
"ObjectNode",
|
||||
"RoomNode",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from typing import Any, Protocol, runtime_checkable
|
||||
|
||||
from PIL import Image
|
||||
|
||||
@@ -9,20 +9,40 @@ from .hash_codec import bits_tensor_to_hash_bytes
|
||||
from .scenegraph import SceneGraphMatch, SimpleSceneGraph
|
||||
|
||||
|
||||
class ImageHashPipelineOutput(Protocol):
|
||||
"""Protocol for the output of ImageHashPipeline.process_batch."""
|
||||
|
||||
hash_bits: Any # torch.Tensor
|
||||
cropped_images: list[Image.Image]
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class ImageHashPipeline(Protocol):
|
||||
"""Protocol for an image hash computation pipeline."""
|
||||
|
||||
def process_batch(
|
||||
self,
|
||||
images: list[Image.Image],
|
||||
text_labels: list[str],
|
||||
batch_size: int = 32,
|
||||
) -> ImageHashPipelineOutput:
|
||||
...
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ImageSceneGraphQueryResult:
|
||||
query_crop_index: int
|
||||
query_index: int
|
||||
query_hash: bytes
|
||||
query_crop: Image.Image
|
||||
query_crop: Image.Image | None
|
||||
matches: list[SceneGraphMatch]
|
||||
|
||||
|
||||
def query_image_against_scene_graph(
|
||||
image: Image.Image,
|
||||
pipeline: Any,
|
||||
*,
|
||||
pipeline: ImageHashPipeline,
|
||||
scene_graph: SimpleSceneGraph,
|
||||
text_labels: list[str],
|
||||
*,
|
||||
top_k: int = 1,
|
||||
batch_size: int = 1,
|
||||
) -> list[ImageSceneGraphQueryResult]:
|
||||
@@ -31,25 +51,24 @@ def query_image_against_scene_graph(
|
||||
cropped_images = list(output.cropped_images)
|
||||
|
||||
if hash_bits.numel() == 0:
|
||||
if cropped_images:
|
||||
raise ValueError("hash_bits and cropped_images must align")
|
||||
return []
|
||||
|
||||
if hash_bits.dim() == 1:
|
||||
hash_bits = hash_bits.unsqueeze(0)
|
||||
|
||||
if hash_bits.shape[0] != len(cropped_images):
|
||||
raise ValueError("hash_bits and cropped_images must align")
|
||||
|
||||
results: list[ImageSceneGraphQueryResult] = []
|
||||
for crop_index, query_bits in enumerate(hash_bits):
|
||||
for query_index, query_bits in enumerate(hash_bits):
|
||||
query_hash = bits_tensor_to_hash_bytes(query_bits)
|
||||
matches = scene_graph.query_by_visual_hash(query_hash, top_k=top_k)
|
||||
if scene_graph.objects:
|
||||
matches = scene_graph.query_by_visual_hash(query_hash, top_k=top_k)
|
||||
else:
|
||||
matches = []
|
||||
crop = cropped_images[query_index] if query_index < len(cropped_images) else None
|
||||
results.append(
|
||||
ImageSceneGraphQueryResult(
|
||||
query_crop_index=crop_index,
|
||||
query_index=query_index,
|
||||
query_hash=query_hash,
|
||||
query_crop=cropped_images[crop_index],
|
||||
query_crop=crop,
|
||||
matches=matches,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user