Source code for SimUtils.ImageUtils

#*******************************************************************#
# written by: Margriet Palm (16-12-11)                              #
#-------------------------------------------------------------------#
#                                                                   #
#*******************************************************************#
from PIL import Image,ImageDraw,ImageFont
from mahotas import labeled
import numpy as np
import copy
from .AnalysisUtils import getCellOrientation


## @package SimUtils.ImageUtils
# Package with utility functions aimed at making and changing images
# based on the Python Imaging Library (PIL).
def addBox(im,bw,bh,pos,color=None):
    """ Draw box on image """
    if color is None:
        color = (0,0,0)
    draw = ImageDraw.Draw(im)
    draw.rectangle([pos,(pos[0]+bw,pos[1]+bh)],outline=color)
    

## Add a time stamp to an image (or any other label)
# @param im: PIL image
# @param stamp: text to put on image
# @param fs: font size
def addTimeStamp(im,stamp,fs=6,fc=None,fontpath='/usr/share/fonts/msttcore/'):
    """ Draw a timestamp at the right bottom of the image. """
    if fc is None:
        fc = (0,0,0)
    draw = ImageDraw.Draw(im)
    fontsize = int(fs)
    font = ImageFont.truetype(fontpath+"/times.ttf", fontsize)        
    (w,h) = draw.textsize(str(stamp),font=font)
    (nx,ny) = im.size
    y = ny-h
    x = nx-w
    #~ print 'add time ',x,y    
    draw.text((x,y),str(stamp),fill=fc,font=font)

## Add a label to the top center of the image
# @param im: PIL image
# @param label: text to put on image
# @param fs: font size
def addLabel(im,label,fs=8,fc=None,fontpath='/usr/share/fonts/msttcore/'):
    """ Draw label at the top center of the image. """
    if fc is None:
        fc = (0,0,0)    
    draw = ImageDraw.Draw(im)
    fontsize = int(fs)
    font = ImageFont.truetype(fontpath+"/arial.ttf", fontsize)        
    (w,h) = draw.textsize(str(label),font=font)
    (nx,ny) = im.size
    y = h
    x = int((0.5*nx)-w)
    #~ print 'add label ',x,y
    draw.text((x,y),str(label),fill=fc,font=font)    

def addGrayBar(im,cmin,cmax,values=None,w=.1,mx=10,my=25,fontpath='/usr/share/fonts/msttcore/'):
    if values is None:
        values = []
    # create new image and paste original image on the left side
    ny = im.size[1]
    nx = int((1+w)*im.size[0]+10+mx)
    newim = Image.new('RGB',(nx,ny),(255,255,255))
    newim.paste(im,(0,0,im.size[0],im.size[1]))
    # create colorbar
    bh = ny-2*my
    bw = w*im.size[0]
    h = bh/(cmax-cmin)
    w = 10
    y0 = im.size[0]-my-25
    x0 = im.size[0]+mx
    draw = ImageDraw.Draw(newim)
    ymin = y0
    for i in range(cmin,cmax):
        draw.rectangle([(x0,y0-i*h),(x0+w,y0-(i+1)*h)],fill=(i,i,i),outline=(i,i,i))
        ymin = y0-(i+1)*h
    #~ draw.rectangle([(x0,y0),(x0+w,ymin)],fill=None,outline=(0,0,0))
    fontsize = 24
    font = ImageFont.truetype(fontpath+"/times.ttf", fontsize)           
    rbh = y0-ymin
    for i,v in enumerate(values):
        pos = i/float(len(values)-1)
        ypos = y0-pos*rbh
        xpos = x0+w+10
        draw.text((xpos,ypos),str(v),fill=(0,0,0),font=font)
    return newim

def getGrayBar(cmin,cmax,values=None,bw=50,h=500,mx=10,my=25,fontsize=12,border=False,fontpath="/usr/share/fonts/msttcore/"):
    font = ImageFont.truetype(fontpath+"/times.ttf", fontsize)        
    tw = 0
    th = 0
    for val in values:
        im = Image.new('RGB',(10,10))
        draw = ImageDraw.Draw(im)
        lsize = draw.textsize(str(val),font=font)
        if lsize[0] > tw:
            tw = lsize[0]
        th = lsize[1]
    im = Image.new('RGB',(bw+2*mx+int(1.1*tw),h),(255,255,255))
    draw = ImageDraw.Draw(im)
    bh = h-2*my
    dh = bh/(cmax-cmin)
    y0 = h-my-th/2
    #~ print y0
    x0 = mx
    ymin = 0
    for i in range(cmin,cmax):
        draw.rectangle([(x0,y0-i*dh),(x0+bw,y0-(i+1)*dh)],fill=(i,i,i),outline=(i,i,i))
        ymin = y0-(i+1)*dh
    if border:
        draw.rectangle([(x0,y0),(x0+bw,ymin)],fill=None,outline=(0,0,0))
    #~ fontsize = 12
    font = ImageFont.truetype(fontpath+"/times.ttf", fontsize)           
    rbh = y0-ymin
    for i,v in enumerate(values):
        pos = i/float(len(values)-1)
        ypos = y0-pos*rbh-th/2
        xpos = x0+bw+10
        #~ print v,ypos
        draw.text((xpos,ypos),str(v),fill=(0,0,0),font=font)
    return im    

def addColorBar(im,cmap,values,w=.1,mx=10,my=25,fontpath='/usr/share/fonts/msttcore/'):
    # create new image and paste original image on the left side
    ny = im.size[1]
    nx = int((1+w)*im.size[0]+10+mx)
    newim = Image.new('RGB',(nx,ny),(255,255,255))
    newim.paste(im,(0,0,im.size[0],im.size[1]))
    # create colorbar
    bh = ny-2*my
    bw = w*im.size[0]
    h = bh/256
    w = 10
    y0 = im.size[0]-my-25
    x0 = im.size[0]+mx
    draw = ImageDraw.Draw(newim)
    ymin = y0
    for i in range(0,256):
        color = tuple(int(255*cmap[i,idx]) for idx in range(0,3))
        
        draw.rectangle([(x0,y0-i*h),(x0+w,y0-(i+1)*h)],fill=color,outline=color)
        ymin = y0-(i+1)*h
    #~ draw.rectangle([(x0,y0),(x0+w,ymin)],fill=None,outline=(0,0,0))
    fontsize = 24
    font = ImageFont.truetype(fontpath+"/times.ttf", fontsize)           
    rbh = y0-ymin
    for i,v in enumerate(values):
        pos = i/float(len(values)-1)
        ypos = y0-pos*rbh
        xpos = x0+w+10
        draw.text((xpos,ypos),str(v),fill=(0,0,0),font=font)
    return newim

def drawColorBar(fn,cmap,nx,ny):
    # create new image and paste original image on the left side
    h = int(np.round(ny/256.0))
    ny = 256*h
    newim = Image.new('RGB',(nx,ny),(255,255,255))
    # create colorbar
    bh = ny
    bw = nx
    #~ h = bh/256
    w = bw
    y0 = ny
    x0 = 0
    draw = ImageDraw.Draw(newim)
    ymin = y0
    for i in range(0,256):
        color = tuple(int(255*cmap[i,idx]) for idx in range(0,3))
        draw.rectangle([(x0,y0-i*h),(x0+w,y0-(i+1)*h)],fill=color,outline=color)
        ymin = y0-(i+1)*h
    newim.save(fn+'.png')

[docs]def stackImages(images,geometry,filename,label=False,title=None,fontsize=20,border=False,scale=1,fontpath="/usr/share/fonts/msttcore/"): """ Stack a set of images together in one image. :param images: dictionary with labels as keys and image filenames as values :param geometry: number of rows and columns (x,y) :param filename: target of the stacked image :param label: add labels to the subimages :param title: overall title for image :param fontsize: fontsize for labels and title :param border: add border to subimages :type border: bool :param scale: scaling factor of the created picture """ fontsize=int(fontsize*scale) font = ImageFont.truetype(fontpath+"/times.ttf", fontsize) labels = images.keys() nx = 0 ny = 0 for im in images.values(): sz = Image.open(im).size if sz[0] > nx: nx = sz[0] ny = sz[1] imsize = (scale*nx,scale*ny) if label: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(labels[0]),font=font) imsize = (int(scale*imsize[0]),int(scale*imsize[1])+lsize[1]) #~ imsize[1] += lsize[1] #---- Create new image ----# offsetX = 5 offsetY = 0 imw = int(np.ceil(imsize[0]*geometry[0]+2*offsetX)) imh = int(np.ceil(imsize[1]*geometry[1]+offsetY)) if title is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) tsize = draw.textsize(str(title),font=font) im = Image.new('RGBA',(imw,imh+tsize[1]),(255,255,255)) offsetY = tsize[1] else: im = Image.new('RGBA',(imw,imh),(255,255,255)) offsetY = 0 draw = ImageDraw.Draw(im) #----- Put plots on canvas ----# labels.sort() for i,l in enumerate(labels): x0 = int(i%geometry[0]*imsize[0]+offsetX) y0 = int((i/geometry[0])*imsize[1]+offsetY) newim = Image.open(images[l]) im.paste(newim.resize((int(nx*scale),int(ny*scale))),(x0,y0)) if border: draw.rectangle([(x0,y0),(x0+int(nx*scale),y0+int(ny*scale))],outline=(0,0,0)) if label: for i,l in enumerate(labels): tsize = draw.textsize(str(l),font=font) x0 = (i%geometry[0])*imsize[0]+0.5*imsize[0]-0.5*tsize[0]+offsetX y0 = (i/geometry[0])*imsize[1]+1*imsize[1]-tsize[1]+offsetY draw.text((x0,y0),str(l),fill=(0,0,0),font=font) if not (title is None): tsize = draw.textsize(str(title),font=font) draw.text((im.size[0]/2.0-0.5*tsize[0]+offsetX,0),str(title),fill=(0,0,0),font=font) #----- Save image -----# #~ if scale is not 1: #~ im = im.resize((int(scale*im.size[0]),int(scale*im.size[1]))) im.save(filename)
[docs]def morphImages(images,filename,xlabel=None,ylabel=None,xtics=None,ytics=None,fontsize=20,scale=1,border=False,title=None,bcolor=(255,255,255),fcolor=(0,0,0),fontpath='/usr/share/fonts/msttcore/',delta=0): """ Stack a set of images together in one morphospace. :param images: 2D array with image filenames :param filename: target of the stacked image :param xlabel: label to be plotted on x-axis :param ylabel: label to be plotted on y-axis :param xtics: items on x-axis :param ytics: items on y-axis :param fontsize: fontsize for labels and title :param scale: scaling factor of the created picture :param border: add border to subimages :param title: overall title for image """ font = ImageFont.truetype(fontpath+"/times.ttf", fontsize) tfont = ImageFont.truetype(fontpath+"/times.ttf", int(1.1*fontsize)) #~ subimsize = Image.open(images[0][0]).size orgsize = Image.open(images[0][0]).size subimsize = (int(scale*orgsize[0]+delta),int(scale*orgsize[1]+delta)) imsize = [subimsize[0]*len(images[0])-delta,subimsize[1]*len(images)-delta] oX = 0 oY = 0 toX = 0 toY = 0 if xlabel is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(xlabel),font=font) imsize[1] = imsize[1]+lsize[1] oY += lsize[1] toY += lsize[1] if ylabel is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(ylabel),font=font) imsize[0] += lsize[1] oX += lsize[1] toX += lsize[1] if xtics is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(xtics[0]),font=font) imsize[1] += lsize[1] oY += lsize[1] if ytics is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(ytics[0]),font=font) imsize[0] += lsize[1] oX += lsize[1] loY = 0 if title is not None: im = Image.new('RGB',(10,10)) draw = ImageDraw.Draw(im) lsize = draw.textsize(str(title),tfont) offset = lsize[1]+20*scale imsize[1] += offset oY += offset if xlabel is not None: loY += offset toY += offset #---- Create new image ----# im = Image.new('RGBA',imsize,bcolor) draw = ImageDraw.Draw(im) #----- Put plots on canvas ----# for i in range(len(images)): for j in range(len(images[0])): #~ print i,j,len(images),len(images[0]) newim = Image.open(images[i][j]) x0 = j*subimsize[0]+oX y0 = i*subimsize[0]+oY im.paste(newim.resize((int(scale*orgsize[0]),int(scale*orgsize[1]))),(x0,y0)) #~ im.paste(newim.resize(subimsize),(x0,y0)) if border: draw.rectangle([(x0,y0),(x0+newim.size[0],y0+newim.size[1])],outline=(0,0,0)) #----- Draw axis and tics -----# ticsfont = ImageFont.truetype(fontpath+"/times.ttf", int(.75*fontsize)) if xtics is not None: for i in range(len(xtics)): tsize = draw.textsize(str(xtics[i]),font=ticsfont) x0 = (i+0.5)*subimsize[0]+oX-int(tsize[0]/2.0) y0 = toY draw.text((x0,y0),str(xtics[i]),fill=fcolor,font=ticsfont) if ytics is not None: for i in range(len(ytics)): x0 = toX y0 = int((i+.5)*subimsize[1]+oY) #~ draw.text((x0,y0),str(ytics[i]),fill=(0,0,0),font=ticsfont) tsize = draw.textsize(str(ytics[i]),font=ticsfont) tim = Image.new('RGBA',(tsize[0],tsize[1]),bcolor) tdraw = ImageDraw.Draw(tim) tdraw.text((0,0),str(ytics[i]),fill=fcolor,font=ticsfont) tim = tim.rotate(90) y0 -= int(tsize[0]/2.0) im.paste(tim,(x0,y0)) if xlabel is not None: tsize = draw.textsize(str(xlabel),font=font) draw.text((im.size[0]/2.0-0.5*tsize[0],loY),str(xlabel),fill=fcolor,font=font) if ylabel is not None: tsize = draw.textsize(str(ylabel),font=font) tim = Image.new('RGBA',(tsize[0],tsize[1]),bcolor) tdraw = ImageDraw.Draw(tim) tdraw.text((0,0),str(ylabel),fill=fcolor,font=font) tim = tim.rotate(90) im.paste(tim,(0,int(im.size[1]/2.0-tsize[0]))) if title is not None: tsize = draw.textsize(str(title),font=tfont) draw.text((im.size[0]/2.0-0.5*tsize[0],0),str(title),fill=fcolor,font=tfont) #----- Save image -----# im.save(filename)
def drawField(field,scale=1,gv=None,raw=False,nx=None,ny=None): """ Draw gray-scale image of a field :param field: numpy array with field :param scale: scaling factor :param gv: minimum and maximum color value :param raw: use raw values of field, otherwise values are mapped on the range of gv :return: image object """ if (nx is None) or (ny is None): (nx,ny) = field.shape if gv is None: gv = [100,255] if (not raw) and ((np.max(field)-np.min(field)) > 0): field = (((field-np.max(field))/(np.min(field)-np.max(field)))*(gv[1]-gv[0]))+gv[0] fim = Image.fromarray(field) fim = fim.resize((int(scale*nx),int(scale*ny))) fim.convert("RGB") im = Image.fromarray(np.uint8(np.dstack((np.asarray(fim),np.asarray(fim),np.asarray(fim))))) im = im.transpose(Image.FLIP_TOP_BOTTOM) return im def drawFieldWithMap(field,sigma,cmap,scale=1): """ Draw gray-scale image of a field :param field: numpy array with field :param scale: scaling factor :param cmap: numpy array with rows [r g b alpha] :return: image object """ (nx,ny) = field.shape field = np.transpose((field.astype(np.float))) sigma = np.transpose((sigma.astype(np.float))) im = Image.fromarray(sigma) im = im.resize((int(scale*nx),int(scale*ny))) sigma = np.asarray(im) #~ field = (((field-np.max(field))/(np.min(field)-np.max(field)))*(255)).astype(np.int) field = ((255.0/np.max(field))*field).astype(np.int) fim = Image.fromarray(field.astype(np.float)) fim = fim.resize((int(scale*nx),int(scale*ny))) field = np.asarray(fim) a = np.dstack((np.asarray(np.zeros_like(field)),np.asarray(np.zeros_like(field)),np.asarray(np.zeros_like(field)))) for val in np.unique(field): #~ if val == 0: #~ continue color = [int(255*cmap[val,i]) for i in range(0,3)] #~ print val,color a[np.where(field==val)] = color a[np.where(sigma==0)] = [255,255,255] return Image.fromarray(np.uint8(a))
[docs]def drawRelDirField(field,sigma,scale=1): """ Draw gray-scale image of a field of the relative director :param field: numpy array with field :param scale: scaling factor :param gv: minimum and maximum color value :param raw: use raw values of field, otherwise values are mapped on the range of gv :return: image object """ (nx,ny) = field.shape gv = [0,220] field = (((field-np.max(field))/(np.min(field)-np.max(field)))*(gv[1]-gv[0]))+gv[0] field[np.where(sigma==0)] = 255 fim = Image.fromarray(field) fim = fim.resize((int(scale*nx),int(scale*ny))) fim.convert("RGB") im = Image.fromarray(np.uint8(np.dstack((np.asarray(fim),np.asarray(fim),np.asarray(fim))))) im = im.transpose(Image.FLIP_TOP_BOTTOM) #~ im = im.rotate(90) return im
def _getImAsArray(sigma,types,field,colormap,scale=1,nx=None,ny=None,transparant=False,gv=None,bc=None): if bc is None: bc = (0,0,0) (nx,ny) = sigma.shape sigma = np.transpose((sigma.astype(np.float))) types = np.transpose((types.astype(np.float))) field = np.transpose((field.astype(np.float))) if np.sum(sigma) == 0: im = Image.fromarray(255*np.uint8(np.ones_like(sigma))) im = im.resize((int(scale*nx),int(scale*ny))) return np.asarray(im),sigma,np.zeros_like(sigma) if gv is None: gv = [100,255] if ((np.max(field)-np.min(field)) > 0): field = (((field-np.max(field))/(np.min(field)-np.max(field)))*(gv[1]-gv[0]))+gv[0] fim = Image.fromarray(field) fim = fim.resize((int(scale*nx),int(scale*ny))) fim.convert("RGB") im = Image.fromarray(sigma) im = im.resize((int(scale*nx),int(scale*ny))) sigma = np.asarray(im) tim = Image.fromarray(np.uint8(types)) tim = tim.resize((int(scale*nx),int(scale*ny))) types = np.asarray(tim) sigMin = 0 bim = None while sigMin < np.max(sigma): imtemp = copy.deepcopy(np.asarray(im)) imtemp[np.where(imtemp < sigMin)] = 0 imtemp[np.where(imtemp > sigMin+254)] = 0 if bim is None: bim = labeled.borders(imtemp) else: bim += labeled.borders(imtemp) sigMin += 254 if np.sum(field) == 0: imnew = colormap[0]*np.ones((scale*ny,scale*nx,3)) else: imnew = np.dstack((np.asarray(fim),np.asarray(fim),np.asarray(fim))) if not transparant: for tp in np.unique(types): if tp == 0: continue imnew[types==tp] = colormap[tp] #~ imnew[types==0] = colormap[0] # set border black imnew[bim] = bc return imnew,sigma,np.asarray(tim) def drawCellsHL(sigma,types,field,colormap,scale=1,nx=None,ny=None,transparant=False,gv=None,HLid=None,HLcolor=None): """ Draw cells, colored by cell type and highlight one single cell in another color. :param sigma: numpy array with cell id's :param types: numpy array with types :param field: numpy array with field :param colormap: dictionary with cell type as keys and corresponding color as values :param scale: scaling factor :param transparant: if True, only field and cell borders are drawn :param gv: minimum and maximum color value :param HLid: cell id of highlighted cell. :param HLcolor: color of highlighted cell (r,g,b) :return: image object """ if HLcolor is None: HLcolor = (255,0,0) mtype = np.max(np.unique(types)) colormap[mtype+1] = HLcolor typesHL = copy.deepcopy(types) if HLid is not None: for hlid in HLid: typesHL[sigma==hlid] = mtype+1 #~ imnew[sigma==hlid] = HLcolor (imnew,sigma,types) = _getImAsArray(sigma,typesHL,field,colormap,scale,nx,ny,transparant,gv) im = Image.fromarray(np.uint8(imnew)) im = im.rotate(90) return im def drawCells(sigma,types,field,colormap,scale=1,nx=None,ny=None,transparant=False,gv=None,bc=None): """ Draw cells, colored by cell type :param sigma: numpy array with cell id's :param types: numpy array with types :param field: numpy array with field :param colormap: dictionary with cell type as keys and corresponding color as values :param scale: scaling factor :param transparant: if True, only field and cell borders are drawn :param gv: minimum and maximum color value :param bc: color of cell borders :return: image object """ (imnew,sigma,types) = _getImAsArray(sigma,types,field,colormap,scale=scale,nx=nx,ny=ny,transparant=transparant,gv=gv,bc=bc) im = Image.fromarray(np.uint8(imnew)) im = im.rotate(90) return im def drawGS(sigma,types,field,colormap,scale=1,nx=None,ny=None): if (nx is None) or (ny is None): (nx,ny) = sigma.shape gv = [100,255] field = (((field-np.max(field))/(np.min(field)-np.max(field)))*(gv[1]-gv[0]))+gv[0] fim = Image.fromarray(field) fim = fim.resize((int(scale*nx),int(scale*ny))) fim.convert("RGB") im = Image.fromarray(sigma) im = im.resize((int(scale*nx),int(scale*ny))) tim = Image.fromarray(np.uint8(types)) tim = tim.resize((int(scale*nx),int(scale*ny))) types = np.asarray(tim) sigMin = 1 bim = None while sigMin < np.max(sigma): imtemp = copy.deepcopy(np.asarray(im)) imtemp[np.where(imtemp < sigMin)] = 0 imtemp[np.where(imtemp > sigMin+254)] = 0 if bim is None: bim = labeled.borders(imtemp) else: bim += labeled.borders(imtemp) sigMin += 254 print np.sum(field) if np.sum(field) == 0: imnew = 255*np.ones((scale*nx,scale*ny)) else: #~ imnew = np.dstack((np.asarray(fim),np.asarray(fim),np.asarray(fim))) imnew = copy.deepcopy(np.asarray(fim)) for tp in np.unique(types): if tp == 0: continue imnew[types==tp] = colormap[tp] # set border black imnew[bim] = 0 im = Image.fromarray(np.uint8(imnew)) return im def drawCellsWithOrientation(sigma,scale=1,bc=None): """ Draw cells, colored by cell angle. :param sigma: numpy array with cell id's :param scale: scaling factor :param bc: color of cell borders :return: image object """ if bc is None: bc = (0,0,0) (nx,ny) = sigma.shape sigma = np.transpose(sigma) if np.sum(sigma) == 0: #~ print 'empty field' im = Image.fromarray(255*np.uint8(np.ones_like(sigma))) im = im.resize((int(scale*nx),int(scale*ny))) return im (nx,ny) = sigma.shape im = Image.fromarray(sigma) im = im.resize((int(scale*nx),int(scale*ny))) sigMin = 0 bim = None while sigMin < np.max(sigma): imtemp = copy.deepcopy(np.asarray(im)) imtemp[np.where(imtemp < sigMin)] = 0 imtemp[np.where(imtemp > sigMin+254)] = 0 if bim is None: bim = labeled.borders(imtemp) else: bim += labeled.borders(imtemp) sigMin += 254 imnew = 255*np.ones((scale*ny,scale*nx,3)) cells = np.unique(sigma) sim = Image.fromarray(np.uint8(sigma)) sim = sim.resize((int(scale*nx),int(scale*ny))) ssigma = np.asarray(sim) for cell in cells: if cell == 0: continue pix = np.where(sigma==cell) a = getCellAngle(pix) color = 55+int((255-55)*a/np.pi) imnew[ssigma==cell] = [color,color,color] imnew[sigma==0] = [255,255,255] imnew[bim] = bc im = Image.fromarray(np.uint8(imnew)) im = im.rotate(90) return im def drawClusters(clusters,sigma,outbase,scale=2): """ Draw image for each cluster highlighting the cells in that cluster. :param cluster: list of :class:Cluster instances :param sigma: CPM grid :param outbase: basename of the output files (including path), a suffix _cluster_clusterID.png will be added :param scale: scaling factor """ colormap = {0:(255,255,255),1:(200,200,200),2:(255,0,0)} for cid,cluster in clusters.iteritems(): types = np.zeros_like(sigma) types[sigma>0] = 1 for cell in cluster.cells: types[sigma==cell] = 2 im = drawCells(sigma,types,np.zeros_like(types),colormap,scale=scale) out = outbase+'_cluster_'+string.zfill(cid,3)+'.png' im = im.transpose(Image.FLIP_LEFT_RIGHT) im = im.rotate(180) im.save(out) def drawTrajectories(traj,out,cm,scale=2,size=[200,200],crop=False,offset=0,fontpath='/usr/share/fonts/liberation/LiberationSans-Regular.ttf',legend=None,bg=(255,255,255),fc=(0,0,0)): xmin = 0 ymin = 0 if crop: xmax = 0 ymax = 0 for tj in traj.values(): x = np.array(tj)[:,0] y = np.array(tj)[:,1] if (xmin == 0) or (xmin > x.min()): xmin = x.min() if (ymin == 0) or (ymin > y.min()): ymin = y.min() if x.max() > xmax: xmax = x.max() if y.max() > ymax: ymax = y.max() print xmin,xmax,ymin,ymax size = [int(xmax-xmin+1),int(ymax-ymin+1)] im = Image.new('RGBA',(size[0]*scale+2*offset,size[1]*scale+2*offset),bg) draw = ImageDraw.Draw(im) p0 = np.array([0,0]) p1 = np.array([0,0]) for id,tj in traj.iteritems(): # scale polygon!!!! polygon = [(scale*(p[0]-xmin)+offset,scale*(p[1]-ymin)+offset) for p in tj] draw.line(polygon,fill=cm[id]) p0 += polygon[0] p1 += polygon[-1] fs = int(3*scale) font = ImageFont.truetype(fontpath, fs) draw.text(tuple(p0/float(len(traj))),'start',fill=fc,font=font) draw.text(tuple(p1/float(len(traj))),'end',fill=fc,font=font) if legend is not None: x0 = offset y0 = im.size[1] print im.size for text,color in legend.iteritems(): print text,x0,y0 (w,h) = draw.textsize(str(text),font=font) y0 -= 1.1*h draw.text((x0,y0),text,fill=color,font=font) im.save(out) def drawCellGraph(g,image=None,filename=None,scale=1,size=[200,200]): """ Draw graph of cell connections :param graph: cell graph :param image: image to draw the graph on, if omitted a clear canvas is used :param filename: filename to save the image to, if omitted image is returned instead :param scale: scaling factor :param size: image size [nx,ny] :return: image whene filename is omitted """ if image is None: xmax = size[0]*scale ymax = size[1]*scale im = Image.new('RGBA',(xmax,ymax),(255,255,255)) else: im = image im = im.rotate(270) draw = ImageDraw.Draw(im) for e in g.edges(): x0 = g.node_attributes(e[0])[0]['pos'][0]*scale y0 = g.node_attributes(e[0])[0]['pos'][1]*scale x1 = g.node_attributes(e[1])[0]['pos'][0]*scale y1 = g.node_attributes(e[1])[0]['pos'][1]*scale draw.line(((x0,y0),(x1,y1)),fill=(0,0,0)) for n in g.nodes(): attr = g.node_attributes(n)[0] x = attr['pos'][0]*scale y = attr['pos'][1]*scale w = attr['size']*scale c = attr['color'] draw.ellipse((x-w,y-w,x+w,y+w),fill=c) if (image is None): if filename is None: filename = 'graph.png' im.save(filename+'.png',"PNG") else: return im def drawNodesColored(nodelist,image,filename,colormap,scale=1,r=2): """ Draw nodes as circles on a morphology. :param nodelist: dictionary with {nodeid : n(x,y)}. :param image: PIL image with the morphology. :param filename: file to store output image to. :param colormap: map with node colors {nodeid : (r,g,b)}. :param scale: scaling, should fit with the morpholog. :param r: radius of the circles at the node positions (without scaling). """ (nx,ny) = image.size im = image im.convert("RGBA") pc = (255,0,0) r = r*scale r = r*scale draw = ImageDraw.Draw(im) for nid,node in nodelist.iteritems(): if nid in colormap: c = colormap[nid] else: c = (255,0,0) x = scale*node[0] y = scale*node[1] draw.ellipse((x-r,y-r,x+r,y+r),fill=c) im.save(filename+'_nodes.png') def drawSkelOnMorph(skel,morph,filename,scale=1,save=True,skelcol=[0,0,0]): """ Draw nodes as circles on a morphology. :param skel: array representation of the skeleton (as returned by getNodes). :param morph: PIL image with the morphology. :param filename: file to store output image to. :param scale: scaling, should fit with the morpholog. """ morph = morph.rotate(180) morph = morph.transpose(Image.FLIP_LEFT_RIGHT) (nx,ny) = morph.size skelim = Image.fromarray(np.uint8(skel)) skelim = skelim.resize((int(scale*skelim.size[0]),int(scale*skelim.size[1]))) skelsc = np.asarray(skelim) imar = np.asarray(morph) imar.flags.writeable = True #~ imar[np.where(skelsc==1)] = [255,255,255] imar[np.where(skelsc==1)] = skelcol im = Image.fromarray(imar) #~ im = im.transpose(Image.FLIP_LEFT_RIGHT) #~ im = im.rotate(90) if save: im.save(filename+'_skel.png') else: return im def drawNodesOnMorph(nodes,morph,filename,scale=1,r=2,save=True,nodecol=(0,0,0)): """ Draw nodes as circles on a morphology. :param skel: array representation of the skeleton (as returned by getNodes). :param morph: PIL image with the morphology. :param filename: file to store output image to. :param scale: scaling, should fit with the morpholog. """ morph = morph.rotate(-90) morph = morph.transpose(Image.FLIP_LEFT_RIGHT) r = r*scale r = r*scale draw = ImageDraw.Draw(morph) for node in nodes.values(): x = scale*node[0] y = scale*node[1] draw.ellipse((x-r,y-r,x+r,y+r),fill=nodecol) if save: morph.save(filename+'_nodes.png') else: return morph def drawNodesAndEdgesOnMorph(nodes,edges,morph,filename,scale=1,r=2,save=True,nodecol=(0,0,0)): """ Draw nodes as circles on a morphology. :param skel: array representation of the skeleton (as returned by getNodes). :param morph: PIL image with the morphology. :param filename: file to store output image to. :param scale: scaling, should fit with the morpholog. """ morph = morph.rotate(-90) #~ morph = morph.transpose(Image.FLIP_LEFT_RIGHT) r = r*scale r = r*scale draw = ImageDraw.Draw(morph) for node in nodes.values(): x = scale*node[0] y = scale*node[1] draw.ellipse((x-r,y-r,x+r,y+r),fill=nodecol) for e1,e2 in edges: x1 = scale*nodes[e1][0] y1 = scale*nodes[e1][1] x2 = scale*nodes[e2][0] y2 = scale*nodes[e2][1] draw.line(((x1,y1),(x2,y2)),fill=(0,0,0)) if save: morph.save(filename+'_nodes.png') else: return morph