# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 University of Dundee & Open Microscopy Environment.
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import numpy as np
from omero.gateway import ColorHolder
from omero.model import MaskI
from omero.rtypes import (
rdouble,
rint,
rstring,
)
[docs]class NoMaskFound(ValueError):
"""
Exception thrown when no foreground pixels were found in a mask
"""
def __init__(self, msg='No mask found'):
super(Exception, self).__init__(msg)
[docs]class InvalidBinaryImage(ValueError):
"""
Exception thrown when invalid labels are found
"""
def __init__(self, msg='Invalid labels found'):
super(Exception, self).__init__(msg)
[docs]def mask_from_binary_image(
binim, rgba=None, z=None, c=None, t=None, text=None,
raise_on_no_mask=True):
"""
Create a mask shape from a binary image (background=0)
:param numpy.array binim: Binary 2D array, must contain values [0, 1] only
:param rgba int-4-tuple: Optional (red, green, blue, alpha) colour
:param z: Optional Z-index for the mask
:param c: Optional C-index for the mask
:param t: Optional T-index for the mask
:param text: Optional text for the mask
:param raise_on_no_mask: If True (default) throw an exception if no mask
found, otherwise return an empty Mask
:return: An OMERO mask
:raises NoMaskFound: If no labels were found
:raises InvalidBinaryImage: If the maximum labels is greater than 1
"""
# Find bounding box to minimise size of mask
xmask = binim.sum(0).nonzero()[0]
ymask = binim.sum(1).nonzero()[0]
if any(xmask) and any(ymask):
x0 = min(xmask)
w = max(xmask) - x0 + 1
y0 = min(ymask)
h = max(ymask) - y0 + 1
submask = binim[y0:(y0 + h), x0:(x0 + w)]
if (not np.array_equal(np.unique(submask), [0, 1]) and not
np.array_equal(np.unique(submask), [1])):
raise InvalidBinaryImage()
else:
if raise_on_no_mask:
raise NoMaskFound()
x0 = 0
w = 0
y0 = 0
h = 0
submask = []
mask = MaskI()
# BUG in older versions of Numpy:
# https://github.com/numpy/numpy/issues/5377
# Need to convert to an int array
# mask.setBytes(np.packbits(submask))
mask.setBytes(np.packbits(np.asarray(submask, dtype=int)))
mask.setWidth(rdouble(w))
mask.setHeight(rdouble(h))
mask.setX(rdouble(x0))
mask.setY(rdouble(y0))
if rgba is not None:
ch = ColorHolder.fromRGBA(*rgba)
mask.setFillColor(rint(ch.getInt()))
if z is not None:
mask.setTheZ(rint(z))
if c is not None:
mask.setTheC(rint(c))
if t is not None:
mask.setTheT(rint(t))
if text is not None:
mask.setTextValue(rstring(text))
return mask
[docs]def masks_from_label_image(
labelim, rgba=None, z=None, c=None, t=None, text=None,
raise_on_no_mask=True):
"""
Create mask shapes from a label image (background=0)
:param numpy.array labelim: 2D label array
:param rgba int-4-tuple: Optional (red, green, blue, alpha) colour
:param z: Optional Z-index for the mask
:param c: Optional C-index for the mask
:param t: Optional T-index for the mask
:param text: Optional text for the mask
:param raise_on_no_mask: If True (default) throw an exception if no mask
found, otherwise return an empty Mask
:return: A list of OMERO masks in label order ([] if no labels found)
"""
masks = []
for i in range(1, labelim.max() + 1):
mask = mask_from_binary_image(labelim == i, rgba, z, c, t, text,
raise_on_no_mask)
masks.append(mask)
return masks