This class stores the segmentation masks for all objects in one image, in the form of polygons. Attributes: polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon.
| 237 | |
| 238 | |
| 239 | class PolygonMasks: |
| 240 | """ |
| 241 | This class stores the segmentation masks for all objects in one image, in the form of polygons. |
| 242 | |
| 243 | Attributes: |
| 244 | polygons: list[list[ndarray]]. Each ndarray is a float64 vector representing a polygon. |
| 245 | """ |
| 246 | |
| 247 | def __init__(self, polygons: List[List[Union[torch.Tensor, np.ndarray]]]): |
| 248 | """ |
| 249 | Arguments: |
| 250 | polygons (list[list[np.ndarray]]): The first |
| 251 | level of the list correspond to individual instances, |
| 252 | the second level to all the polygons that compose the |
| 253 | instance, and the third level to the polygon coordinates. |
| 254 | The third level array should have the format of |
| 255 | [x0, y0, x1, y1, ..., xn, yn] (n >= 3). |
| 256 | """ |
| 257 | assert isinstance(polygons, list), ( |
| 258 | "Cannot create PolygonMasks: Expect a list of list of polygons per image. " |
| 259 | "Got '{}' instead.".format(type(polygons)) |
| 260 | ) |
| 261 | |
| 262 | def _make_array(t: Union[torch.Tensor, np.ndarray]) -> np.ndarray: |
| 263 | # Use float64 for higher precision, because why not? |
| 264 | # Always put polygons on CPU (self.to is a no-op) since they |
| 265 | # are supposed to be small tensors. |
| 266 | # May need to change this assumption if GPU placement becomes useful |
| 267 | if isinstance(t, torch.Tensor): |
| 268 | t = t.cpu().numpy() |
| 269 | return np.asarray(t).astype("float64") |
| 270 | |
| 271 | def process_polygons( |
| 272 | polygons_per_instance: List[Union[torch.Tensor, np.ndarray]] |
| 273 | ) -> List[np.ndarray]: |
| 274 | assert isinstance(polygons_per_instance, list), ( |
| 275 | "Cannot create polygons: Expect a list of polygons per instance. " |
| 276 | "Got '{}' instead.".format(type(polygons_per_instance)) |
| 277 | ) |
| 278 | # transform the polygon to a tensor |
| 279 | polygons_per_instance = [_make_array(p) for p in polygons_per_instance] |
| 280 | for polygon in polygons_per_instance: |
| 281 | assert len(polygon) % 2 == 0 and len(polygon) >= 6 |
| 282 | return polygons_per_instance |
| 283 | |
| 284 | self.polygons: List[List[np.ndarray]] = [ |
| 285 | process_polygons(polygons_per_instance) for polygons_per_instance in polygons |
| 286 | ] |
| 287 | |
| 288 | def to(self, *args: Any, **kwargs: Any) -> "PolygonMasks": |
| 289 | return self |
| 290 | |
| 291 | @property |
| 292 | def device(self) -> torch.device: |
| 293 | return torch.device("cpu") |
| 294 | |
| 295 | def get_bounding_boxes(self) -> Boxes: |
| 296 | """ |
no outgoing calls