refactor(verification): extract shared text_labels cell and hash codec

- Move inline _text_labels lists into a shared text_labels cell
- Replace inline np.packbits hash encoding with bits_tensor_to_hash_bytes
- Add static tests to verify notebook API usage patterns
This commit is contained in:
2026-05-21 16:05:47 +08:00
parent 101a675ece
commit 5a1d3ea977
2 changed files with 47 additions and 29 deletions

View File

@@ -39,6 +39,7 @@ def project_imports():
ObjectNode, ObjectNode,
RoomNode, RoomNode,
SimpleSceneGraph, SimpleSceneGraph,
bits_tensor_to_hash_bytes,
query_image_against_scene_graph, query_image_against_scene_graph,
) )
from simulator import ( from simulator import (
@@ -59,6 +60,7 @@ def project_imports():
RoomNode, RoomNode,
SimpleSceneGraph, SimpleSceneGraph,
TopDownSceneElements, TopDownSceneElements,
bits_tensor_to_hash_bytes,
cfg_manager, cfg_manager,
collect_room_views_by_room, collect_room_views_by_room,
create_habitat_simulator, create_habitat_simulator,
@@ -70,6 +72,24 @@ def project_imports():
) )
@app.cell
def text_labels():
"""Shared text labels for detection during graph build and query."""
text_labels = [
"a chair",
"a table",
"a sofa",
"a cabinet",
"a shelf",
"a lamp",
"a picture",
"a window",
"a door",
"a plant",
]
return (text_labels,)
@app.cell @app.cell
def habitat_setup(HabitatSimulatorConfig, RoomNode, create_habitat_simulator, np): def habitat_setup(HabitatSimulatorConfig, RoomNode, create_habitat_simulator, np):
"""Initialize Habitat simulator and sample room nodes.""" """Initialize Habitat simulator and sample room nodes."""
@@ -170,6 +190,7 @@ def collect_views(
def build_scene_graph( def build_scene_graph(
ObjectNode, ObjectNode,
SimpleSceneGraph, SimpleSceneGraph,
bits_tensor_to_hash_bytes,
cfg_manager, cfg_manager,
mo, mo,
np, np,
@@ -178,6 +199,7 @@ def build_scene_graph(
room_view_dataset, room_view_dataset,
save_object_image, save_object_image,
save_room_view, save_room_view,
text_labels,
torch, torch,
): ):
scene_graph = SimpleSceneGraph( scene_graph = SimpleSceneGraph(
@@ -194,18 +216,6 @@ def build_scene_graph(
_images = [item[2] for item in room_view_dataset] _images = [item[2] for item in room_view_dataset]
_metadata = [(item[0], item[1]) for item in room_view_dataset] _metadata = [(item[0], item[1]) for item in room_view_dataset]
_text_labels = [
"a chair",
"a table",
"a sofa",
"a cabinet",
"a shelf",
"a lamp",
"a picture",
"a window",
"a door",
"a plant",
]
inference_batch_size = 4 inference_batch_size = 4
image_batches = [ image_batches = [
_images[index : index + inference_batch_size] _images[index : index + inference_batch_size]
@@ -229,7 +239,7 @@ def build_scene_graph(
): ):
_batch_output = pipeline.process_batch( _batch_output = pipeline.process_batch(
_batch_images, _batch_images,
_text_labels, text_labels,
batch_size=inference_batch_size, batch_size=inference_batch_size,
return_debug_details=True, return_debug_details=True,
) )
@@ -296,9 +306,7 @@ def build_scene_graph(
_obj_id = f"{_room_id}_v{_view_idx:03d}_m{_mask_idx:02d}" _obj_id = f"{_room_id}_v{_view_idx:03d}_m{_mask_idx:02d}"
_bits_array = _hash_bits.detach().cpu().numpy().reshape(-1) _hash_bytes = bits_tensor_to_hash_bytes(_hash_bits)
_bits_binary = (_bits_array > 0).astype(np.uint8)
_hash_bytes = np.packbits(_bits_binary).tobytes()
object_images[_obj_id] = _cropped object_images[_obj_id] = _cropped
save_object_image(output_dir, _room_id, _obj_id, _view_idx, _mask_idx, _cropped) save_object_image(output_dir, _room_id, _obj_id, _view_idx, _mask_idx, _cropped)
@@ -372,6 +380,7 @@ def query_matching(
pipeline, pipeline,
query_image_against_scene_graph, query_image_against_scene_graph,
scene_graph, scene_graph,
text_labels,
): ):
from io import BytesIO from io import BytesIO
@@ -384,23 +393,11 @@ def query_matching(
_query_image = Image.open(BytesIO(_file_contents)).convert("RGB") _query_image = Image.open(BytesIO(_file_contents)).convert("RGB")
_text_labels = [
"a chair",
"a table",
"a sofa",
"a cabinet",
"a shelf",
"a lamp",
"a picture",
"a window",
"a door",
"a plant",
]
_query_results = query_image_against_scene_graph( _query_results = query_image_against_scene_graph(
image=_query_image, image=_query_image,
pipeline=pipeline, pipeline=pipeline,
scene_graph=scene_graph, scene_graph=scene_graph,
text_labels=_text_labels, text_labels=text_labels,
top_k=5, top_k=5,
batch_size=1, batch_size=1,
) )
@@ -425,6 +422,7 @@ def query_matching(
"query_cropped": query_cropped, "query_cropped": query_cropped,
"query_hash_hex": _best_result.query_hash.hex(), "query_hash_hex": _best_result.query_hash.hex(),
"top_matches": top_matches, "top_matches": top_matches,
"num_query_results": len(_query_results),
} }
return query_cropped, query_result, top_matches return query_cropped, query_result, top_matches

View File

@@ -0,0 +1,20 @@
from __future__ import annotations
from pathlib import Path
NOTEBOOK = Path(__file__).resolve().parents[1] / "notebooks" / "verification.py"
def test_verification_notebook_uses_scenegraph_query_api():
source = NOTEBOOK.read_text()
assert "query_image_against_scene_graph" in source
assert "text_labels=text_labels" in source
def test_verification_notebook_uses_hash_codec_for_object_hashes():
source = NOTEBOOK.read_text()
assert "bits_tensor_to_hash_bytes" in source
assert "np.packbits" not in source