def draw_ellipse_to_file(jpgfile, imgarray, major, minor, angle, center=None, numpoints=64, color="#3d3df2", width=4): """ major - major axis radius (in pixels) minor - minor axis radius (in pixels) angle - angle (in degrees) center - position of centre of ellipse numpoints - # of points used that make an ellipse angle is positive toward y-axis """ if center is None: center = numpy.array(imgarray.shape, dtype=numpy.float)/2.0 points = ellipse.generate_ellipse(major, minor, angle, center, numpoints, None, "step", True) x = points[:,0] y = points[:,1] ## wrap around to end x = numpy.hstack((x, [x[0],])) y = numpy.hstack((y, [y[0],])) ## convert image originalimage = imagefile.arrayToImage(imgarray) originalimage = originalimage.convert("RGB") pilimage = originalimage.copy() draw = ImageDraw.Draw(pilimage) for i in range(len(x)-1): xy = (x[i], y[i], x[i+1], y[i+1]) draw.line(xy, fill=color, width=width) ## create an alpha blend effect originalimage = Image.blend(originalimage, pilimage, 0.9) originalimage.save(jpgfile, "JPEG", quality=85) return
def drawPowerSpecImage(self, origpowerspec, maxsize=1200): origpowerspec = ctftools.trimPowerSpectraToOuterResolution(origpowerspec, self.plotlimit2DAngstrom, self.trimfreq) if self.debug is True: print "origpowerspec shape", origpowerspec.shape #compute elliptical average and merge with original image pixelrdata, rotdata = ctftools.ellipticalAverage(origpowerspec, self.ellipratio, self.angle, self.ringwidth*3, 1, full=True) ellipavgpowerspec = ctftools.unEllipticalAverage(pixelrdata, rotdata, self.ellipratio, self.angle, origpowerspec.shape) halfshape = origpowerspec.shape[1]/2 halfpowerspec = numpy.hstack( (origpowerspec[:,:halfshape] , ellipavgpowerspec[:,halfshape:] ) ) if halfpowerspec.shape != origpowerspec.shape: apDisplay.printError("Error in power spectra creation") if max(halfpowerspec.shape) > maxsize: scale = maxsize/float(max(halfpowerspec.shape)) #scale = math.sqrt((random.random()+random.random()+random.random())/3.0) apDisplay.printMsg( "Scaling final powerspec image by %.3f"%(scale)) powerspec = imagefilter.scaleImage(halfpowerspec, scale) else: scale = 1280./float(max(halfpowerspec.shape)) powerspec = imagefilter.scaleImage(halfpowerspec, scale) #scale = 1.0 #powerspec = halfpowerspec.copy() self.scaleapix = self.trimapix self.scalefreq = self.trimfreq/scale if self.debug is True: print "orig pixel", self.apix print "trim pixel", self.trimapix print "scale pixel", self.scaleapix numzeros = 13 radii1 = ctftools.getCtfExtrema(self.defocus1, self.scalefreq*1e10, self.cs, self.volts, self.ampcontrast, numzeros=numzeros, zerotype="valley") radii2 = ctftools.getCtfExtrema(self.defocus2, self.scalefreq*1e10, self.cs, self.volts, self.ampcontrast, numzeros=numzeros, zerotype="valley") #smallest of two defocii firstpeak = radii2[0] ### ### PART 9: DRAW THE 2D POWERSPEC IMAGE ### center = numpy.array(powerspec.shape, dtype=numpy.float)/2.0 foundzeros = min(len(radii1), len(radii2)) """ pyplot.clf() ax = pyplot.subplot(1,1,1) pyplot.xticks([], []) pyplot.yticks([], []) pyplot.imshow(powerspec) pyplot.gray() for i in range(foundzeros): # because |def1| < |def2| ==> firstzero1 > firstzero2 major = radii1[i]*2 minor = radii2[i]*2 ell = Ellipse(xy=center, width=major, height=minor, angle=self.angle+90, fill=False, edgecolor="yellow", antialiased=True, linewidth=0.5) ax.add_artist(ell) pyplot.subplots_adjust(wspace=0, hspace=0, bottom=0, left=0, top=1, right=1, ) self.newpowerspecfile = apDisplay.short(self.imgname)+"-powerspec-new.png" pyplot.savefig(self.newpowerspecfile, format="png", dpi=150, pad_inches=0.0) """ ### ### PART 9: DRAW THE 2D POWERSPEC IMAGE ### apDisplay.printColor("PART 9: DRAW THE 2D POWERSPEC IMAGE", "magenta") center = numpy.array(powerspec.shape, dtype=numpy.float)/2.0 originalimage = imagefile.arrayToImage(powerspec) originalimage = originalimage.convert("RGB") pilimage = originalimage.copy() draw = ImageDraw.Draw(pilimage) ######### ## draw astig axis line, if astig > 5% ######### perdiff = 2*abs(self.defocus1-self.defocus2)/abs(self.defocus1+self.defocus2) if self.debug is True: print "Percent Difference %.1f"%(perdiff*100) if perdiff > 0.05: #print self.angle, radii2[0], center x = 1*firstpeak*math.cos(math.radians(self.angle)) y = firstpeak*math.sin(math.radians(self.angle)) #print x,y xy = (x+center[0], y+center[1], -x+center[0], -y+center[1]) #print xy draw.line(xy, fill="#f23d3d", width=10) elif perdiff > 1e-6: #print self.angle, radii2[0], center x = 1*firstpeak*math.cos(math.radians(self.angle)) y = firstpeak*math.sin(math.radians(self.angle)) #print x,y xy = (x+center[0], y+center[1], -x+center[0], -y+center[1]) #print xy draw.line(xy, fill="#f23d3d", width=2) ######### ## draw colored CTF Thon rings ######### foundzeros = min(len(radii1), len(radii2)) #color="#3d3dd2" #blue color="#ffd700" #gold for i in range(foundzeros): # because |def1| < |def2| ==> firstzero1 > firstzero2 major = radii1[i] minor = radii2[i] if self.debug is True: print "major=%.1f, minor=%.1f, angle=%.1f"%(major, minor, self.angle) if minor > powerspec.shape[0]/math.sqrt(3): # this limits how far we draw out the ellipses sqrt(3) to corner, just 2 inside line break width = int(math.ceil(math.sqrt(numzeros - i)))*2 ### determine color of circle currentres = 1.0/(major*self.scalefreq) if currentres > self.res80: ringcolor = "green" elif currentres > self.res50: ringcolor = "gold" else: ringcolor = "red" ### determine number of points to use to draw ellipse, minimize distance btw points #isoceles triangle, b: radius ot CTF ring, a: distance btw points #a = 2 * b sin (theta/2) #a / 2b = sin(theta/2) #theta = 2 * asin (a/2b) #numpoints = 2 pi / theta ## define a to be 5 pixels a = 40 theta = 2.0 * math.asin (a/(2.0*major)) skipfactor = 2 numpoints = int(math.ceil(2.0*math.pi/theta/skipfactor))*skipfactor + 1 #print "numpoints", numpoints points = ellipse.generate_ellipse(major, minor, math.radians(self.angle), center, numpoints, None, "step", True) x = points[:,0] y = points[:,1] ## wrap around to end x = numpy.hstack((x, [x[0],])) y = numpy.hstack((y, [y[0],])) ## convert image numsteps = int(math.floor((len(x)-2)/skipfactor)) for j in range(numsteps): k = j*skipfactor xy = (x[k], y[k], x[k+1], y[k+1]) draw.line(xy, fill=ringcolor, width=width) ######### ## draw blue resolution ring ######### # 1/res = freq * pixrad => pixrad = 1/(res*freq) maxrad = (max(powerspec.shape)-1)/2.0 - 3 maxres = 1.0/(self.scalefreq*maxrad) bestres = math.ceil(maxres) pixrad = 1.0/(self.scalefreq*bestres) if self.debug is True: print "bestres %d Angstroms (max: %.3f)"%(bestres, maxres) print "pixrad %d (max: %.3f)"%(pixrad, maxrad) if pixrad > maxrad: apDisplay.printError("Too big of outer radius to draw") outpixrad = math.ceil(pixrad)+1 inpixrad = math.floor(pixrad)-1 for i in numpy.arange(-4.0,4.01,0.01): r = pixrad + i blackxy = numpy.array((center[0]-r,center[1]-r, center[0]+r,center[1]+r), dtype=numpy.float64) draw.ellipse(tuple(blackxy), outline="black") for i in numpy.arange(-1.50,1.51,0.01): r = pixrad + i whitexy = numpy.array((center[0]-r,center[1]-r, center[0]+r,center[1]+r), dtype=numpy.float64) draw.ellipse(tuple(whitexy), outline="#0BB5FF") ######### ## setup font to add text ######### fontpath = "/usr/share/fonts/liberation/LiberationSans-Regular.ttf" from PIL import ImageFont if os.path.isfile(fontpath): fontsize = int(math.ceil( 48/2. * min(powerspec.shape)/float(maxsize))*2) font = ImageFont.truetype(fontpath, fontsize) else: font = ImageFont.load_default() ######### ## add resolution ring text ######### angrad = maxrad/math.sqrt(2) + 1 coord = (angrad+maxrad, angrad+maxrad) for i in [-2,2]: for j in [-2,2]: draw.text((coord[0]+i,coord[1]+j), "%.1f A"%(bestres), font=font, fill="black") draw.text(coord, "%.1f A"%(bestres), font=font, fill="#0BB5FF") ######### ## add defocus value text ######### meandef = abs(self.defocus1+self.defocus2)/2.0 deftext = "%.2f um"%(meandef*1e6) tsize = draw.textsize(deftext, font=font) coord = (powerspec.shape[0]-4-tsize[0], powerspec.shape[0]-4-tsize[1]) for i in [-2,2]: for j in [-2,2]: draw.text((coord[0]+i,coord[1]+j), deftext, font=font, fill="black") draw.text(coord, deftext, font=font, fill="#AB82FF") ######### ## add text about what sides of powerspec are: ## left - raw data; right - elliptical average data ######### leftcoord = (4, 4) for i in [-3, -1, 0, 1, 3]: for j in [-3, -1, 0, 1, 3]: draw.text((leftcoord[0]+i,leftcoord[1]+j) , "Raw CTF Data", font=font, fill="black") draw.text(leftcoord, "Raw CTF Data", font=font, fill="#00BFFF") tsize = draw.textsize("Elliptical Average", font=font) xdist = powerspec.shape[0] - 4 - tsize[0] rightcoord = (xdist, 4) for i in [-2,2]: for j in [-2,2]: draw.text((rightcoord[0]+i,rightcoord[1]+j), "Elliptical Average", font=font, fill="black") draw.text(rightcoord, "Elliptical Average", font=font, fill="#00BFFF") ######### ## create an alpha blend effect ######### originalimage = Image.blend(originalimage, pilimage, 0.95) apDisplay.printMsg("Saving 2D powerspectra to file: %s"%(self.powerspecfile)) #pilimage.save(self.powerspecfile, "JPEG", quality=85) originalimage.save(self.powerspecfile, "JPEG", quality=85) if not os.path.isfile(self.powerspecfile): apDisplay.printWarning("power spec file not created") if self.debug is True: #powerspecjpg = Image.open(self.powerspecfile) #powerspecjpg.show() pass return