def simplemain(): """A simple main""" from nkpylib.nkutils import specializeDict, str2kvdict if len(sys.argv) < 6: print 'Usage: python %s <aligner name> <input image name> <output image name> <fiducials> <outparams>' % (sys.argv[0]) sys.exit() name, infname, outfname, fiducials, outparams = sys.argv[1:6] a = Aligner(name=name) im = Image.open(infname) fiducials = parseFiducials(fiducials) outparams = str2kvdict(outparams, sep='@', dlm='::') print 'INFILE:', infname print 'FIDUCIALS:', fiducials print 'OUTPARAMS:', outparams aligned, params = a.align(im, fiducials=fiducials, outparams=outparams) print 'PARAMS:', params saveImage(aligned, outfname, params) print 'OUTFILE:', outfname sys.exit()
def parseFiducials(s): """Parses a fiducials dictionary from the given string""" from nkpylib.nkutils import specializeDict, str2kvdict # make the type-specialized dict fids = specializeDict(str2kvdict(s, sep='@', dlm='::')) # convert _x and _y fids to pairs names = set(f.rsplit('_', 1)[0] for f in fids if f.lower().endswith('_x') or f.lower().endswith('_y')) def popic(name, c): """Pops the fids with given name and ending char, ignoring case""" try: #return fids.pop(name+'_'+c.lower()) return fids[name+'_'+c.lower()] except KeyError: #return fids.pop(name+'_'+c.upper()) return fids[name+'_'+c.upper()] for n in names: fids[n] = x, y = popic(n, 'x'), popic(n, 'y') return fids
def processLine(line): """Process a single line of input, returning a single line of output as a string. Input on stdin is <input path>\t<output fmt>\t<aligner>\t<fiducials>\t<output parameters> where: - <input path> is a local path of the input image to align (not a url), - <output fmt> is a format string which will generate the output path. It's given a dict with: dfij: doifj blah: difj - <aligner> is the name of the aligner to use, - <fiducials> is a list of 'key@value' pairs, joined using :: These are used for determining feature locations, which the aligners are defined relative to. Any extra fiducials (not needed by the given aligner) are ignored. If there is a missing fiducial, an error is returned. - <output parameters> is an optional list of 'key@value' pairs, joined using '::' These are used for defining parameters about the output. Currently, we support: crop: 'x0,y0,x1,y1' rect from which to extract features from. This is first cut from the image and provides the extents relative to which the feature locations are assumed to be located. [default: no crop] width: the width to scale the cropped input to (aspect ratio NOT preserved) [default: original resolution] height: the height to scale the cropped input to (aspect ratio NOT preserved) [default: original resolution] drawfids: how to draw fiducials on output. options: none: don't draw fiducials [default] circle: draw a circle rectangle: draw a rectangle drawfidsline: the color to draw fiducial outlines in, as any valid color string (only if drawfids is on) [default: green] drawfidsfill: the color to fill drawn fiducials in, as any valid color string (only if drawfids is on) [default: green] drawfidsr: the radius of the circle to draw fiducials in [default: 3] outfmt: the output format to print on stdout. This is a standard python format string, to which we'll pass a dictionary with the following fields: basename: input file basename inpath: input file path outpath: output file path outfmt: the passed-in output file format string aligner: the passed-in aligner string fiducials: the passed-in input parameters string outparams: the passed-in output parameters string [default: '%(inpath)s\t%(outpath)s'] errfmt: what to print in case of error, again as a python format string. The fmtdict is like in 'fmt', and also containing: errortype: a python exception type name errormsg: the error message [default: 'error'] A full input string might look like: FIXME """ #TODO test out various outfmt options #TODO how to specify if we want to write EXIF or not? from collections import defaultdict fmtdict = defaultdict(str) DEFAULT_OUTPARAMS = defaultdict(str) DEFAULT_OUTPARAMS['outfmt'] = DEFAULT_OUTPUT_FMT DEFAULT_OUTPARAMS['errfmt'] = DEFAULT_ERROR_FMT DEFAULT_OUTPARAMS['drawfids'] = 'none' DEFAULT_OUTPARAMS['drawfidsline'] = 'green' DEFAULT_OUTPARAMS['drawfidsfill'] = 'green' DEFAULT_OUTPARAMS['drawfidsr'] = 3 # parse elements els = line.split('\t') try: # input and output fmtdict['inpath'] = inpath = els.pop(0) fmtdict['basename'] = basename = os.path.basename(inpath) fmtdict['outpathfmt'] = outpathfmt = els.pop(0) #print path, basename, fmtdict, outfmt # aligner fmtdict['aligner'] = aligner = els.pop(0) #print aligner # fiducials fmtdict['fiducials'] = fiducials = els.pop(0) fiducials = parseFiducials(fiducials) # output params outparams = dict(**DEFAULT_OUTPARAMS) #print outparams if els: # output params are optional, so we don't want to raise an exception here fmtdict['outparams'] = els.pop(0) #print fmtdict['outparams'] outparams.update(str2kvdict(fmtdict['outparams'], sep='@', dlm='::')) #print outparams # at this stage, we have everything we need # first make sure the file exists and open it if not os.path.exists(inpath): raise IOError('Image does not exist') im = Image.open(inpath) # process the image a = Aligner(name=aligner) aligned, params = a.align(im, fiducials=fiducials, outparams=outparams) fmtdict.update(params) outparams['outfmt'] = outparams['outfmt'].replace(r'\t', '\t').replace(r'\n', '\n') # save the output image fmtdict['outpath'] = outpath = outpathfmt % fmtdict #print outpathfmt, inpath, basename, fmtdict, outpath fmtdict['outpathfmt'] = fmtdict['outpathfmt'].replace(r'\t', '\t').replace(r'\n', '\n') saveImage(aligned, outpath, params) # generate the output string ret = outparams['outfmt'] % (fmtdict) return ret except Exception, e: raise # add the error values to the fmtdict fmtdict['errortype'] = type(e).__name__ try: fmtdict['errormsg'] = e except Exception: pass # generate and return the error string errstr = outparams['errfmt'] % fmtdict return errstr