Files
AI_spine/tests/test_geometry.py
T
2026-09-17 18:50:43 +08:00

101 lines
4.6 KiB
Python

import copy
import unittest
import numpy as np
from PIL import Image
from geometry_grounding import ground_parts, pixel
from normalize_reference import prepare_rgba
def plan(box=None, points=None):
return {'parts': [{'id': 'hand_left', 'semantic': 'screen-left hand',
'visibility': 'visible', 'bbox_norm_xyxy': box or [0, 0, 1, 1],
'positive_points_norm': points or [], 'pivot_norm': [0, 0]}]}
class GeometryTests(unittest.TestCase):
def setUp(self):
self.rgba = np.zeros((20, 30, 4), dtype=np.uint8)
self.rgba[5:15, 10:20] = [20, 40, 60, 255]
self.image = Image.fromarray(self.rgba)
def test_existing_alpha_and_visible_pixels_unchanged(self):
self.rgba[6, 12] = [255, 255, 255, 128]
image, meta = prepare_rgba(Image.fromarray(self.rgba))
np.testing.assert_array_equal(image, self.rgba)
self.assertEqual(meta['method'], 'existing_alpha')
def test_only_border_connected_white_is_removed(self):
rgb = np.full((20, 20, 3), 255, dtype=np.uint8)
rgb[4:16, 4:16] = 20
rgb[7:13, 7:13] = 255
prepared, meta = prepare_rgba(Image.fromarray(rgb))
data = np.array(prepared)
self.assertEqual(data[0, 0, 3], 0)
self.assertEqual(data[8, 8, 3], 255)
np.testing.assert_array_equal(data[:, :, :3], rgb)
self.assertEqual(meta['method'], 'border_connected_white')
self.assertEqual(prepared.size, (20, 20))
def test_colored_opaque_and_blank_inputs_rejected(self):
for color in [(0, 30, 80, 255), (255, 255, 255, 255), (0, 0, 0, 0)]:
with self.assertRaises(ValueError):
prepare_rgba(Image.new('RGBA', (10, 10), color))
def test_invalid_model_points_replaced_without_changing_pivot(self):
data = plan(points=[[0, 0], [1, 1], [.4, .4]])
original = copy.deepcopy(data)
report, prompts = ground_parts(self.image, data)
self.assertEqual(report['summary']['invalid_model_points'], 2)
self.assertEqual(report['summary']['background_model_points'], 2)
candidate = report['parts'][0]['candidate_points'][0]
x, y = candidate['point_px']
self.assertGreater(self.rgba[y, x, 3], 0)
self.assertGreaterEqual(candidate['distance_to_roi_boundary_px'], 5)
self.assertEqual(pixel(candidate['point_norm'], 30, 20), (x, y))
self.assertFalse(prompts['parts'][0]['semantic_verified'])
self.assertEqual(prompts['parts'][0]['negative_points_px'], [])
self.assertEqual(data, original)
self.assertEqual(report['parts'][0]['model_positive_points'][2]['status'], 'UNTRUSTED_SEED')
def test_bbox_with_no_foreground_has_no_seed(self):
report, prompts = ground_parts(self.image, plan([0, 0, .2, .2]))
self.assertEqual(report['summary']['blocked_parts'], 1)
self.assertEqual(prompts['parts'][0]['positive_points_px'], [])
self.assertIn('EMPTY_FOREGROUND_ROI', report['parts'][0]['warnings'])
def test_solid_roi_has_finite_interior_distance(self):
report, _ = ground_parts(self.image, plan([10/30, 5/20, 20/30, 15/20]))
part = report['parts'][0]
self.assertEqual(part['bbox_foreground_ratio'], 1)
self.assertEqual(part['candidate_points'][0]['distance_to_roi_boundary_px'], 5)
def test_disconnected_roi_remains_semantically_unverified(self):
self.rgba[2:4, 2:4] = [255, 0, 0, 255]
report, _ = ground_parts(Image.fromarray(self.rgba), plan())
self.assertEqual(report['parts'][0]['foreground_components'], 2)
self.assertIn('MULTIPLE_FOREGROUND_COMPONENTS', report['parts'][0]['warnings'])
self.assertFalse(report['parts'][0]['semantic_verified'])
def test_opaque_image_does_not_validate_every_point(self):
report, prompts = ground_parts(Image.new('RGBA', (30, 20), 'black'), plan(points=[[.5, .5]]))
self.assertEqual(report['parts'][0]['status'], 'blocked')
self.assertEqual(prompts['parts'][0]['positive_points_px'], [])
def test_subpixel_roi_without_pixel_center_is_blocked(self):
report, _ = ground_parts(self.image, plan([.4, .4, .401, .401]))
self.assertEqual(report['parts'][0]['status'], 'blocked')
self.assertIn('NO_PIXEL_CENTER_IN_ROI', report['parts'][0]['warnings'])
def test_hidden_part_never_gets_foreground_seed(self):
data = plan()
data['parts'][0].update(visibility='hidden', bbox_norm_xyxy=None)
report, prompts = ground_parts(self.image, data)
self.assertEqual(report['parts'][0]['status'], 'hidden')
self.assertEqual(prompts['parts'][0]['positive_points_px'], [])
if __name__ == '__main__':
unittest.main()