|
import numpy as np |
|
import cv2 |
|
from enum import IntEnum |
|
|
|
|
|
class SegIEPolyType(IntEnum): |
|
EXCLUDE = 0 |
|
INCLUDE = 1 |
|
|
|
|
|
|
|
class SegIEPoly(): |
|
def __init__(self, type=None, pts=None, **kwargs): |
|
self.type = type |
|
|
|
if pts is None: |
|
pts = np.empty( (0,2), dtype=np.float32 ) |
|
else: |
|
pts = np.float32(pts) |
|
self.pts = pts |
|
self.n_max = self.n = len(pts) |
|
|
|
def dump(self): |
|
return {'type': int(self.type), |
|
'pts' : self.get_pts(), |
|
} |
|
|
|
def identical(self, b): |
|
if self.n != b.n: |
|
return False |
|
return (self.pts[0:self.n] == b.pts[0:b.n]).all() |
|
|
|
def get_type(self): |
|
return self.type |
|
|
|
def add_pt(self, x, y): |
|
self.pts = np.append(self.pts[0:self.n], [ ( float(x), float(y) ) ], axis=0).astype(np.float32) |
|
self.n_max = self.n = self.n + 1 |
|
|
|
def undo(self): |
|
self.n = max(0, self.n-1) |
|
return self.n |
|
|
|
def redo(self): |
|
self.n = min(len(self.pts), self.n+1) |
|
return self.n |
|
|
|
def redo_clip(self): |
|
self.pts = self.pts[0:self.n] |
|
self.n_max = self.n |
|
|
|
def insert_pt(self, n, pt): |
|
if n < 0 or n > self.n: |
|
raise ValueError("insert_pt out of range") |
|
self.pts = np.concatenate( (self.pts[0:n], pt[None,...].astype(np.float32), self.pts[n:]), axis=0) |
|
self.n_max = self.n = self.n+1 |
|
|
|
def remove_pt(self, n): |
|
if n < 0 or n >= self.n: |
|
raise ValueError("remove_pt out of range") |
|
self.pts = np.concatenate( (self.pts[0:n], self.pts[n+1:]), axis=0) |
|
self.n_max = self.n = self.n-1 |
|
|
|
def get_last_point(self): |
|
return self.pts[self.n-1].copy() |
|
|
|
def get_pts(self): |
|
return self.pts[0:self.n].copy() |
|
|
|
def get_pts_count(self): |
|
return self.n |
|
|
|
def set_point(self, id, pt): |
|
self.pts[id] = pt |
|
|
|
def set_points(self, pts): |
|
self.pts = np.array(pts) |
|
self.n_max = self.n = len(pts) |
|
|
|
def mult_points(self, val): |
|
self.pts *= val |
|
|
|
|
|
|
|
class SegIEPolys(): |
|
def __init__(self): |
|
self.polys = [] |
|
|
|
def identical(self, b): |
|
polys_len = len(self.polys) |
|
o_polys_len = len(b.polys) |
|
if polys_len != o_polys_len: |
|
return False |
|
|
|
return all ([ a_poly.identical(b_poly) for a_poly, b_poly in zip(self.polys, b.polys) ]) |
|
|
|
def add_poly(self, ie_poly_type): |
|
poly = SegIEPoly(ie_poly_type) |
|
self.polys.append (poly) |
|
return poly |
|
|
|
def remove_poly(self, poly): |
|
if poly in self.polys: |
|
self.polys.remove(poly) |
|
|
|
def has_polys(self): |
|
return len(self.polys) != 0 |
|
|
|
def get_poly(self, id): |
|
return self.polys[id] |
|
|
|
def get_polys(self): |
|
return self.polys |
|
|
|
def get_pts_count(self): |
|
return sum([poly.get_pts_count() for poly in self.polys]) |
|
|
|
def sort(self): |
|
poly_by_type = { SegIEPolyType.EXCLUDE : [], SegIEPolyType.INCLUDE : [] } |
|
|
|
for poly in self.polys: |
|
poly_by_type[poly.type].append(poly) |
|
|
|
self.polys = poly_by_type[SegIEPolyType.INCLUDE] + poly_by_type[SegIEPolyType.EXCLUDE] |
|
|
|
def __iter__(self): |
|
for poly in self.polys: |
|
yield poly |
|
|
|
def overlay_mask(self, mask): |
|
h,w,c = mask.shape |
|
white = (1,)*c |
|
black = (0,)*c |
|
for poly in self.polys: |
|
pts = poly.get_pts().astype(np.int32) |
|
if len(pts) != 0: |
|
cv2.fillPoly(mask, [pts], white if poly.type == SegIEPolyType.INCLUDE else black ) |
|
|
|
def dump(self): |
|
return {'polys' : [ poly.dump() for poly in self.polys ] } |
|
|
|
def mult_points(self, val): |
|
for poly in self.polys: |
|
poly.mult_points(val) |
|
|
|
@staticmethod |
|
def load(data=None): |
|
ie_polys = SegIEPolys() |
|
if data is not None: |
|
if isinstance(data, list): |
|
|
|
ie_polys.polys = [ SegIEPoly(type=type, pts=pts) for (type, pts) in data ] |
|
elif isinstance(data, dict): |
|
ie_polys.polys = [ SegIEPoly(**poly_cfg) for poly_cfg in data['polys'] ] |
|
|
|
ie_polys.sort() |
|
|
|
return ie_polys |