Esempio n. 1
0
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)
Esempio n. 2
0
    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