def multi_mask(img, *names, **kwargs): """ Return a list/tuple/generator of masks of an image, one for each unique label found in a colored img. EVERYTHING DOWN-CONVERTED TO UINT: NECESSARY FOR MORPHOLOGY.LABELS ANYWAY, ALTHOUGH POSSIBLY SHOULD DO RGB2GRAY OR 255 LABELS IS MAX""" astype = kwargs.pop('astype', tuple) ignore = kwargs.pop('ignore', 'black') names = list(names) # THIS WILL DRASTICALLY REDUCE NUMBER OF UNIQUE LABELS ALLOWED RIGHT? # SINCE IT ONLY HAS 255 POSSIBLE VALUES?! if img.ndim == 3: img = putil.rgb2uint(img, warnmsg=True) # Labels requires on grayscale; npunique also doesn't play nice w/ rgb if ignore == 'black' or ignore == (0,0,0): ignore = 0 elif ignore == 'white' or ignore == (1,1,1): ignore = 255 unique = ptools.unique(img) if ignore not in unique: logger.warn("Ignore set to %s but was not found on image." % ignore) else: unique = [v for v in unique if v != ignore] names = _parse_names(names, unique) # Make the mask dict as generator out = ((str(names[idx]), (img==v)) for idx, v in enumerate(unique)) return putil._parse_generator(out, astype)
def from_labeled(cls, img, *names, **pmankwargs): """ Labels an image and creates multi-canvas, one for each species in the image. Since labels require gray image, putil.rgb2uint used internally. Attributes ---------- mapper : iterable of pairs, ordered dict or dict Specifies which colors correspond to which labels. Order of labels is also used as order of multicanvas names, so if using dict, this will be scrambled. Examples -------- mc = MultiCanvas.from_labeled(image, singles, doubles) mc = MultiCanvas.from_labeled(image, mapper=(('singles','red'), ('doubles',(1,1,0)) )) """ ignore = pmankwargs.pop('ignore', 'black') neighbors = pmankwargs.pop('neighbors', 4) maximum = pmankwargs.pop('maximum', MAXDEFAULT) mapper = pmankwargs.pop('mapper', []) storecolors = pmankwargs.pop('storecolors', True) # Retro-support *names positional arg by converting to mapper # since mapper already works downstream if names: if mapper: raise MultiError("Names must be positional arguments or" " mapper, but not both.") mapper = zip(names, putil._get_ccycle(upto=len(names)) ) # BAD PRACTICE TO USE DICT CUZ UNSORTED if isinstance(mapper, dict): mapper = mapper.items() if mapper: cnames, colors = zip(*mapper) else: cnames, colors = [], [] # TEST ON GRAY IMAGE if img.ndim == 3: img = putil.any2rgb(img) unique = [tuple(v) for v in ptools.unique(img)] threechan = True else: # img = putil.any2uint(img) unique = [float(v) for v in ptools.unique(img)] threechan=False # Redundant w/ name masks but oh well if ignore is None: color_ignore = [] elif ignore == 'black' or ignore == (0,0,0) or ignore == 0: color_ignore = [0, (0,0,0)] elif ignore == 'white' or ignore == (1,1,1) or ignore == 255: color_ignore = [255, (1,1,1), (255,255,255)] # A list of values, take besut guess else: color_ignore = zip(*putil.guess_colors(ignore, unique, threechan=threechan))[1] # Store indicies to ignore index_ignore = [idx for idx, v in enumerate(unique) if v in color_ignore] unique = [v for v in unique if v not in color_ignore] # Sort by gray values; multimask will expect this color_gray = zip(map(putil.any2rgb, unique), map(putil.any2uint, unique) ) unique, grayunique = zip(*sorted(color_gray, key=operator.itemgetter(1))) if img.ndim < 3: unique = grayunique _colormapper = dict(putil.guess_colors(colors, unique, threechan=threechan)) mout =[(str(c), c) for c in unique] _tempmap = {} for k,v in mapper: _tempmap[k] = _colormapper[v] _tempmap = dict((str(v),k) for k,v in _tempmap.items()) def _tryeval(val): def r2(x): return round(x,2) try: val = eval(val) except NameError: return val try: r,g,b = val except TypeError: return str(r2(val)) else: return str(tuple(map(r2, val))) mapper = [] for k,v in mout: if k in _tempmap: kout = _tempmap[k] else: kout = k kout = _tryeval(kout) mapper.append((kout,v)) name_masks = multi_mask(img, *names, astype=tuple, ignore=None) if len(name_masks) > maximum: raise MultiError("%s labels found, exceeding maximum of %s" " increasing maximum may result in slowdown." % (len(name_masks), maximum) ) canvii = [] ; names = [] j=0 for idx, (name, mask) in enumerate(name_masks): if idx not in index_ignore: labels = morphology.label(mask, neighbors, background=False) particles = ParticleManager.from_labels(labels, prefix=name, **pmankwargs) canvii.append(Canvas(particles=particles, rez=mask.shape) ) names.append(mapper[j][0]) j += 1 mc = cls(canvii=canvii, names=names) # Map colors if storecolors: mc.set_colors(**dict((k,v) for k,v in mapper if k in names)) # Reorder names: user cnames first, then remaining in mapper neworder = list(cnames) for idx, (name, v) in enumerate(mapper): if idx not in index_ignore: if name not in cnames: neworder.append(name) mc.reorder(*neworder, inplace=True) return mc