Source code for samuroi.masks.polygon
import numpy
from .mask import Mask
from ..util.event import Event
[docs]class PolygonMask(Mask):
"""
A mask that is defined by the corners of a polygon
"""
def __init__(self, outline, name=None):
super(PolygonMask, self).__init__(name=name)
self.__outline = outline
self.changed = Event()
@property
def outline(self):
return self.__outline
@property
def lowerleft(self):
return numpy.min(self.outline, axis=0).astype(int)
@property
def upperright(self):
return numpy.max(self.outline, axis=0).astype(int) + 1
[docs] def move(self, offset):
self.__outline[:, 0] += offset[0]
self.__outline[:, 1] += offset[1]
self.changed(self)
[docs] def to_hdf5(self, f):
if 'polygons' not in f:
f.create_group('polygons')
f.create_dataset('polygons/' + self.name, data=self.outline)
@staticmethod
[docs] def from_hdf5(f):
if 'polygons' in f:
for name, dataset in f['polygons'].iteritems():
yield PolygonMask(name=name, outline=dataset.value)
@property
def weights(self):
"""Generate the weight mask of the rectangular area covering the given polygon."""
# shift the polygon such that ll is the new origin
spoly = self.outline - self.lowerleft
# width and height of roi
W, H = (self.upperright - self.lowerleft)
from PIL import Image, ImageDraw
mimg = Image.new('I', (W * 10, H * 10), 0)
l = [(r[0] * 10, r[1] * 10) for r in spoly]
ImageDraw.Draw(mimg).polygon(xy=l, outline=False, fill=1)
# create a numpy array of the image where the extra resolution pixels are wrapped into extra dimensions
mimg = numpy.array(mimg).reshape((H, 10, W, 10))
return mimg.sum(axis=1).sum(axis=-1).astype(float) / 100.
def __call__(self, data, mask=None):
# get the rectangular fov that fully covers a polygon
rowslice = slice(max(self.lowerleft[1], 0), min(self.upperright[1], data.shape[0]))
colslice = slice(max(self.lowerleft[0], 0), min(self.upperright[0], data.shape[1]))
# get a view on the data of interest
dataview = data[rowslice, colslice]
Cs, Rs = (self.upperright - self.lowerleft)
Cl, Rl = self.lowerleft
weightmask = self.weights[max(-Rl, 0):min(Rs, data.shape[0] - Rl), max(-Cl, 0):min(Cs, data.shape[1] - Cl)]
if mask is None:
doi = weightmask[..., numpy.newaxis] * dataview
weight = weightmask.sum()
else:
mask = mask[rowslice, colslice]
doi = weightmask[..., numpy.newaxis] * mask[..., numpy.newaxis] * dataview
weight = (weightmask * mask).sum()
return doi.sum(axis=0).sum(axis=0) / weight