Skip to content

Commit

Permalink
improved duplicate detection with handle string similarity metric and…
Browse files Browse the repository at this point in the history
… added to check_siro_scenes tool
  • Loading branch information
aclegg3 committed Jan 28, 2025
1 parent 6fd39e8 commit b61802d
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 8 deletions.
21 changes: 15 additions & 6 deletions examples/mod_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,6 @@ def key_press_event(self, event: Application.KeyEvent) -> None:
elif key == pressed.ONE:
# save scene instance
self.obj_editor.save_current_scene()
print("Saved modified scene instance JSON to original location.")
elif key == pressed.TWO:
# Undo any edits
self.obj_editor.undo_edit()
Expand Down Expand Up @@ -1391,10 +1390,15 @@ def key_press_event(self, event: Application.KeyEvent) -> None:
.items()
):
obj_translations[_obj_handle] = obj.translation
from difflib import SequenceMatcher

for obj_handle1, translation1 in obj_translations.items():
for obj_handle2, translation2 in obj_translations.items():
if obj_handle1 == obj_handle2:
continue
handle_similarity = SequenceMatcher(
None, obj_handle1, obj_handle2
).ratio()
if (translation1 - translation2).length() < 0.1:
if (
obj_handle1,
Expand All @@ -1405,12 +1409,15 @@ def key_press_event(self, event: Application.KeyEvent) -> None:
) in self.duplicate_object_cache:
continue
print(
f" - possible duplicate detected: {obj_handle1} and {obj_handle2}"
f" - possible duplicate detected: {obj_handle1} and {obj_handle2} with similarity {handle_similarity}"
)
self.duplicate_object_cache[
(obj_handle1, obj_handle2)
] = translation1
print(f"Duplicates detected: {len(self.duplicate_object_cache)}")
if handle_similarity > 0.65:
self.duplicate_object_cache[
(obj_handle1, obj_handle2)
] = translation1
print(
f"Duplicates detected (with high similarity): {len(self.duplicate_object_cache)}"
)
elif alt_pressed:
removed_list = []
# automatically remove one of each detected duplicate pair
Expand All @@ -1420,6 +1427,8 @@ def key_press_event(self, event: Application.KeyEvent) -> None:
obj_handles[1]
)
removed_list.append(obj_handles[1])
if len(removed_list) > 0:
self.obj_editor.modified_scene = True
print(f"Removed {len(removed_list)} duplicate objects: {removed_list}")
else:
# Cyle through semantics display
Expand Down
58 changes: 56 additions & 2 deletions tools/check_siro_scenes.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,50 @@ def flag_non_default_link_active_recs(
return non_default_active_recs


def try_find_faucets(sim) -> Tuple[bool, int, int, int, int]:
def check_for_duplicate_objects(
sim: Simulator,
dist_threshold: float = 0.1,
handle_similarity_threshold: float = 0.7,
) -> Dict[Tuple[str, str], mn.Vector3]:
"""
Checks all object transformations looking for objects which are likely duplicates.
Uses translation match and string handle similarity check.
Returns a Dict keyed by pairs of handles mapping to the translation of the overlap.
"""
from difflib import SequenceMatcher

# check for duplciate objects in the scene by looking for overlapping translations
obj_translations = {}
duplicate_object_cache: Dict[Tuple[str, str], mn.Vector3] = {}
for _obj_handle, obj in (
sim.get_rigid_object_manager().get_objects_by_handle_substring().items()
):
obj_translations[_obj_handle] = obj.translation

for obj_handle1, translation1 in obj_translations.items():
for obj_handle2, translation2 in obj_translations.items():
if obj_handle1 == obj_handle2:
continue
handle_similarity = SequenceMatcher(None, obj_handle1, obj_handle2).ratio()
if (translation1 - translation2).length() < dist_threshold:
if (
obj_handle1,
obj_handle2,
) in duplicate_object_cache or (
obj_handle2,
obj_handle1,
) in duplicate_object_cache:
continue
print(
f" - possible duplicate detected: {obj_handle1} and {obj_handle2} with similarity {handle_similarity}"
)
if handle_similarity > handle_similarity_threshold:
duplicate_object_cache[(obj_handle1, obj_handle2)] = translation1
print(f"Duplicates detected (with high similarity): {len(duplicate_object_cache)}")
return duplicate_object_cache


def try_find_faucets(sim: Simulator) -> Tuple[bool, int, int, int, int]:
"""
Try to get faucets on objects in the scene.
:return: boolean whether or not there are faucet annotations, number of faucet objects, number of faucet objects with receptacles, number of faucet objects with active receptacles, number of navigable faucet objs
Expand Down Expand Up @@ -743,7 +786,9 @@ def try_find_faucets(sim) -> Tuple[bool, int, int, int, int]:
)


def try_nav_faucet_point(sim, faucet_obj_handle, largest_island_ix):
def try_nav_faucet_point(
sim: Simulator, faucet_obj_handle: str, largest_island_ix: int
) -> bool:
"""
Use nav utils to try finding a placement for the spot robot which can access a faucet
"""
Expand Down Expand Up @@ -831,6 +876,7 @@ def try_nav_faucet_point(sim, faucet_obj_handle, largest_island_ix):
"visualize_regions",
"analyze_semantics",
"splits",
"duplicates",
]

target_check_actions = []
Expand Down Expand Up @@ -1018,6 +1064,14 @@ def try_nav_faucet_point(sim, faucet_obj_handle, largest_island_ix):
sim.curr_scene_name
]

##########################################
# check for any potentially duplicated and overlapping objects
if "duplicates" in target_check_actions:
potential_duplicates = check_for_duplicate_objects(sim)
scene_test_results[sim.curr_scene_name]["duplicates"] = len(
potential_duplicates
)

##########################################
# gather all Receptacle.unique_name in the scene
if "rec_unique_names" in target_check_actions:
Expand Down

0 comments on commit b61802d

Please sign in to comment.