3838from spark_config import Config , config_field
3939from torch import nn
4040
41+ from semantic_inference .image_rotator import ImageRotator , RotationType
42+
4143
4244def _map_opt (values , f ):
4345 return {k : v if v is None else f (v ) for k , v in values .items ()}
@@ -52,30 +54,7 @@ class Results:
5254 boxes : torch .Tensor # (n, 4) xyxy format, torch.float32
5355 categories : torch .Tensor # (n,), torch.float32/int64 (doesn't matter)
5456 confidences : torch .Tensor # (n,), torch.float32
55- img_shape : tuple [int , int ]
56-
57- @property
58- def instance_seg_img (self ):
59- """
60- Convert segmentation results to instance segmentation image.
61- Each pixel value encodes both category id and instance id.
62- First 16 bits are category id, last 16 bits are instance id.
63- """
64- if self .masks is None :
65- return np .zeros (self .img_shape )
66-
67- masks = self .masks .cpu ().numpy ()
68- category_ids = self .categories .cpu ().numpy ()
69- img = np .zeros (masks [0 ].shape , dtype = np .uint32 )
70- for i in range (masks .shape [0 ]):
71- category_id = int (category_ids [i ]) # category id are 0-indexed
72- instance_id = i + 1 # instance ids are 1-indexed
73- combined_id = (
74- category_id << 16
75- ) | instance_id # combine into single uint32
76- img [masks [i , ...] > 0 ] = combined_id
77-
78- return img
57+ instances : np .ndarray # (H, W, c) np.uint32 (result image)
7958
8059 def cpu (self ):
8160 """Move results to CPU."""
@@ -94,6 +73,7 @@ class InstanceSegmenterConfig(Config):
9473
9574 # relevant configs (model path, model weights) for the model
9675 instance_model : Any = config_field ("instance_model" , default = "yolo-seg" )
76+ rotation_type : str = "none"
9777
9878
9979class InstanceSegmenter (nn .Module ):
@@ -106,6 +86,7 @@ def __init__(self, config):
10686 self ._canary_param = nn .Parameter (torch .empty (0 ))
10787
10888 self .config = config
89+ self ._rotator = ImageRotator (RotationType (config .rotation_type ))
10990 self .segmenter = self .config .instance_model .create ()
11091
11192 def eval (self ):
@@ -134,7 +115,7 @@ def segment(self, rgb_img, is_rgb_order=True):
134115 Encoded image
135116 """
136117 img = rgb_img if is_rgb_order else rgb_img [:, :, ::- 1 ].copy ()
137- return self (img )
118+ return self . _rotator . derotate (img )
138119
139120 @property
140121 def device (self ):
@@ -156,12 +137,28 @@ def forward(self, rgb_img):
156137 Returns:
157138 Encoded image
158139 """
159- categories , masks , boxes , confidences , img_shape = self .segmenter (rgb_img )
140+ rotated = self ._rotator .rotate (rgb_img )
141+ categories , masks , boxes , confidences = self .segmenter (rotated )
142+
143+ if self .masks is None :
144+ instances = np .zeros (rgb_img .shape [:2 ])
145+ else :
146+ instances = np .zeros (masks [0 ].shape , dtype = np .uint32 )
147+ masks = self .masks .cpu ().numpy ()
148+ category_ids = self .categories .cpu ().numpy ()
149+ for i in range (masks .shape [0 ]):
150+ category_id = int (category_ids [i ]) # category id are 0-indexed
151+ instance_id = i + 1 # instance ids are 1-indexed
152+ # combine into single uint32
153+ combined_id = (category_id << 16 ) | instance_id
154+ instances [masks [i , ...] > 0 ] = combined_id
155+
156+ instances = self ._rotator .derotate (instances )
160157
161158 return Results (
162159 masks = masks ,
163160 boxes = boxes ,
164161 categories = categories ,
165162 confidences = confidences ,
166- img_shape = img_shape ,
163+ instances = instances ,
167164 )
0 commit comments