def main(self,input_nii,slicedir,outFolder,pctile,origin,colormap,reorient,replace,boundingbox_bgcolor,count_pixels): nii = nibabel.load(input_nii) dir2dim = {'x':0,'y':1,'z':2,'0':0,'1':1,'2':2,'coronal':0,'saggital':1,'horizontal':2,'axial':2} sliceDim = dir2dim[slicedir.lower()] # Nifti data is supposed to be in RAS orientation. # For Nifti files that violate the standard, the reorient string can be used to correct the orientation. if reorient: nii = nit.reorient(nii,reorient) hdr = nii.get_header() q = hdr.get_best_affine(); ornt = nibabel.io_orientation(q) print('The orientation is: {}'.format(ornt)) dims0 = [int(d) for d in nii.shape if d>1] dims = list(dims0) for i,d in enumerate(ornt): dims[i] = dims0[int(d[0])] print('The dimensions are: {}'.format(dims)) numSlices = dims[sliceDim]; baseName = op.basename(input_nii) baseName = re.sub('.gz$', '',baseName) baseName = re.sub('.nii$', '',baseName) if not op.exists(outFolder): os.makedirs(outFolder) print('Created output folder "{}".'.format(outFolder)) rgbMode = False img_dtype = nii.get_data_dtype(); if len(dims)==4 and dims[3]==3: rgbMode = True elif img_dtype.names: if len(img_dtype.names)==3: rgbMode = 'record' rescale = pctile is not None fmt = 'png' if rescale or rgbMode: fmt = 'jpg' filePattern = baseName+'_%04d.{}'.format(fmt) filePattern_py = filePattern.replace('_%04d','_{:04d}') if origin: try: if origin.startswith('['): ijk0 = json.loads(origin) elif origin == 'center': dims = hdr.get_data_shape() ijk0 = [dims[0]/2,dims[1]/2,dims[2]/2] q = hdr.get_best_affine() q[0:3,3] = -q[0:3,0:3].dot(ijk0) hdr.set_sform(q) except: raise Exception('Invalid origin "{}".'.format(origin)) # save coordinate system (Right Anterior Superior) information rasLimits = nit.rasLimits(hdr) # Some nii files have no origin set (other than i=0, j=0, k=0) # Use the origin parameter to overrule this. ##if origin == 'center': ## def ctr(x1,x2): ## w=x2-x1 ## return -w/2,w/2 ## rasLimits = [ctr(xx[0],xx[1]) for xx in rasLimits] with open(op.join(outFolder,'raslimits.json'), 'w') as fp: json.dump(rasLimits,fp) slicePos = (rasLimits[sliceDim][0] + (numpy.arange(0.0,dims[sliceDim])+0.5)*(rasLimits[sliceDim][1]-rasLimits[sliceDim][0])/dims[sliceDim]).tolist() with open(op.join(outFolder,'slicepos.json'), 'w') as fp: json.dump(slicePos,fp) # quit if ALL slices already exist if not replace: done = True for i in range(0,numSlices): outFile = filePattern_py.format(i) fullFile = op.join(outFolder,outFile) if not op.exists(fullFile): done = False break if done: return FancyDict( filePattern = op.join(outFolder,filePattern), rasLimits = rasLimits ) # load image, it is needed img = nii.get_data() img = nibabel.apply_orientation(img,ornt) img = numpy.squeeze(img) if rgbMode == 'record': img = nit.record2rgb(img) print('Nifti image loaded, shape "{}",data type "{}"'.format(dims,img.dtype)) maxSlices = 2048; if numSlices>maxSlices: raise Exception('Too many slices (more than '+str(maxSlices)+')'); if not rgbMode: minmax = nit.get_limits(img) if rescale: minmax = nit.get_limits(img,pctile) print('minmax {}, rescale {}'.format(minmax,rescale)) index2rgb = nit.parse_colormap(colormap,minmax) if isinstance(index2rgb,dict): rgbLen = len(index2rgb[index2rgb.keys()[0]]) else: rgbLen = len(index2rgb[0]) # save index2rgb if not rescale: if isinstance(index2rgb,dict): index2rgb_hex = {index:'{:02X}{:02X}{:02X}'.format(rgb[0],rgb[1],rgb[2]) for (index,rgb) in index2rgb.iteritems()} else: index2rgb_hex = ['{:02X}{:02X}{:02X}'.format(rgb[0],rgb[1],rgb[2]) for rgb in index2rgb] with open(op.join(outFolder,'index2rgb.json'), 'w') as fp: json.dump(index2rgb_hex,fp) elif rgbMode: grayscale = img.dot(numpy.array([0.2989,0.5870,0.1140])) minmax = nit.get_limits(grayscale) if rescale: minmax = nit.get_limits(grayscale,pctile) rescale = True rgbLen = 3 index2rgb = False else: rescale = False rgbLen = 3 index2rgb = False bbg = boundingbox_bgcolor if bbg is '': bbg = False if bbg: boundingBox = {} boundingBoxFile = op.join(outFolder,'boundingbox.json') if op.exists(boundingBoxFile): with open(boundingBoxFile, 'r') as fp: boundingBox = json.load(fp) pxc = count_pixels if pxc: pixCount = {}; pixCountFile = op.join(outFolder,'pixcount.json') if op.exists(pixCountFile): with open(pixCountFile, 'r') as fp: pixCount = json.load(fp) for i in range(0,numSlices): outFile = filePattern_py.format(i) fullFile = op.join(outFolder,outFile) if op.exists(fullFile): if i==0: print('image {}{} already exists as {}-file "{}".'.format(sliceDim,i,fmt,fullFile)) if not replace: continue slc = nit.get_slice(img,sliceDim,i) if pxc: labels = numpy.unique(slc) cnt = {} for b in labels: cnt[str(b)] = numpy.count_nonzero(slc == b) pixCount[i] = cnt if index2rgb: slc = nit.slice2rgb(slc,index2rgb,rescale,minmax[0],minmax[1]) elif rescale: slc = nit.rgbslice_rescale(slc,minmax[0],minmax[1]) # Save image ans = scipy.misc.toimage(slc).save(op.join(outFolder,outFile)) if bbg: if(bbg == "auto"): # do this only once bgColor = nit.autoBackgroundColor(slc) print('boundingbox auto bgColor is {}'.format(bgColor)) else: bgColor = nit.hex2rgb(bgg) mask = nit.imageMask(slc,[bgColor]) print 'mask shape {} {}'.format(bgColor,mask.shape) ## bounding box nonzero = numpy.argwhere(mask) #print 'nonzero {}'.format(nonzero) if nonzero.size>0: lefttop = nonzero.min(0)[::-1] # because y=rows and x=cols rightbottom = nonzero.max(0)[::-1] bb = lefttop.tolist() bb.extend(rightbottom-lefttop+(1,1)) boundingBox[i] = bb if i==0: print('image {}{} saved to {}-file "{}".'.format(sliceDim,i,fmt,fullFile)) if bbg: if len(boundingBox)>0: bb0 = boundingBox.itervalues().next() xyMin = [bb0[0],bb0[1]] xyMax = [bb0[0]+bb0[2],bb0[1]+bb0[3]] for bb in boundingBox.itervalues(): if bb[0]<xyMin[0]: xyMin[0] = bb[0] if bb[1]<xyMin[1]: xyMin[1] = bb[1] if bb[0]+bb[2]>xyMax[0]: xyMax[0] = bb[0]+bb[2] if bb[1]+bb[3]>xyMax[1]: xyMax[1] = bb[1]+bb[3] boundingBox['combined'] = [xyMin[0],xyMin[1],xyMax[0]-xyMin[0],xyMax[1]-xyMin[1]] with open(boundingBoxFile, 'w') as fp: json.dump(boundingBox,fp) if pxc: with open(pixCountFile, 'w') as fp: json.dump(pixCount,fp) return FancyDict( filePattern=op.join(outFolder,filePattern), rasLimits=rasLimits )
def run(args): print('Input Nifti: '+args.nifti_src) print('Colormap to use: '+args.colormap) try: import nibabel nii = nibabel.load(args.nifti_src) img = numpy.squeeze(nii.get_data()) hdr = nii.get_header() q = hdr.get_best_affine(); ornt = nibabel.io_orientation(q) img = nibabel.apply_orientation(img,ornt) dims = img.shape print 'Nifti image loaded, data type "{}"'.format(img.dtype) global SliceDirs slice_dir_orientation = SliceDirs[args.slice_dir] slice_dir_index = {'x':0,'y':1,'z':2}[args.slice_dir] numSlices = img.shape[slice_dir_index]; maxSlices = 2048; if numSlices>maxSlices: raise Exception('too many slices (more than '+str(maxSlices)+')'); baseName = op.basename(args.nifti_src) baseName = re.sub('.gz$', '',baseName) baseName = re.sub('.nii$', '',baseName) outFolder = args.out if not(op.exists(outFolder)): os.makedirs(outFolder) print 'Created output folder "{}".'.format(outFolder) if len(dims)==4: raise Exception('NIFTI file with RGB color data not supported yet.') index2rgb = nit.parse_colormap(img,args.colormap) if isinstance(index2rgb,dict): rgbLen = len(index2rgb[index2rgb.keys()[0]]) else: rgbLen = len(index2rgb[0]) rescale = bool(args.pctile) minmax = [None,None] if rescale: minmax = nit.get_limits(img,args.pctile) fmt = 'png' if rescale and rgbLen is 3: fmt = 'jpg' for i in range(0,numSlices): dim = args.dim slice = nit.get_slice(img,dim,i) if index2rgb: slice = nit.slice2rgb(slice,index2rgb,rescale,minmax[0],minmax[1]) # Save image outFile = baseName+'_{:04d}.{}'.format(i,fmt) scipy.misc.toimage(slice).save(op.join(outFolder,outFile)) if i==0: print 'image {}{} saved to {} file "{}".'.format(dim,i,fmt,outFile) except: print "Unexpected error:", sys.exc_info()[0] raise
def main(self, layers, htmlfile, imagefolder, slices_x, slices_y, slices_z): # Basic argument checking for lr in layers: assertFile(lr["file"]) sliceRangePct = [[], [], []] for d in [0, 1, 2]: dim = ['x', 'y', 'z'][d] s = locals()['slices_' + dim] if s: s = s.split(':') sliceRangePct[d] = [int(r.rstrip('%')) for r in s] else: sliceRangePct[d] = [0, 10, 100] print('Layer specification: {}'.format(layers)) if op.isdir(htmlfile): htmlfile = op.join(htmlfile, 'index.html') htmlfolder = op.dirname(htmlfile) if not imagefolder: htmlname, _ = op.splitext(op.basename(htmlfile)) imagefolder = op.join(htmlfolder, htmlname + '_files') if not (op.exists(htmlfolder)): os.makedirs(htmlfolder) print('Created html output folder "{}".'.format(htmlfolder)) if not (op.exists(imagefolder)): os.makedirs(imagefolder) print('Created image output folder "{}".'.format(imagefolder)) imagefolder = op.realpath(imagefolder) scriptdir = op.realpath(op.dirname(__file__)) parsedLayers = [] for i, lr in enumerate(layers): nifti_src = lr["file"] if not nifti_src: continue baseName = 'lr{}_'.format(i) + re.sub('(\.nii|\.nii.gz)$', '', op.basename(nifti_src)) import nibabel nii = nibabel.load(nifti_src) nii = nibabel.as_closest_canonical(nii) img = numpy.squeeze(nii.get_data()) hdr = nii.get_header() dims = img.shape print('Nifti image loaded, shape {}, data type "{}"'.format( dims, img.dtype)) if len(dims) == 4: raise Exception( 'NIFTI file with RGB color data not supported yet.') # apply colormap index2rgb = None rgbLen = 0 if "colormap" in lr: index2rgb = niitools.parse_colormap(lr["colormap"]) rgbLen = len(index2rgb[0]) minmax = [None, None] rescale = ('pctile' in lr and lr["pctile"]) if rescale: minmax = niitools.get_limits(img, lr["pctile"]) fmt = 'png' if rescale and rgbLen < 4: fmt = 'jpg' sliceRange = [[], [], []] for d in [0, 1, 2]: dim = ['x', 'y', 'z'][d] numSlices = dims[d] sliceStep = int( math.ceil(sliceRangePct[d][1] * numSlices / 100.0)) sliceStart = int(sliceRangePct[d][0] * (numSlices - 1) / 100) sliceEnd = int(sliceRangePct[d][2] * (numSlices - 1) / 100) sliceRange[d] = [sliceStart, sliceStep, sliceEnd] for i in range(sliceStart, sliceEnd + 1, sliceStep): slice = niitools.get_slice(img, d, i) pngFile = baseName + '_{}{:d}.{}'.format(dim, i, fmt) if index2rgb: slice = niitools.slice2rgb(slice, index2rgb, rescale, minmax[0], minmax[1]) # Save image to PNG scipy.misc.toimage(slice, cmin=0, cmax=255).save( op.join(imagefolder, pngFile)) if i == sliceStart: print('image {}{} saved to png file "{}".'.format( dim, i, pngFile)) pixdim = hdr['pixdim'][1:4] imgsize_mm = [ round(pixdim[0] * dims[0], 1), round(pixdim[1] * dims[1], 1), round(pixdim[2] * dims[2], 1) ] print('Image size in mm {}'.format(imgsize_mm)) # update parsedLayers pl = { "name": baseName, "ext": fmt, "src": nifti_src, "imgsize_px": dims, "imgsize_mm": imgsize_mm } if "title" in lr: pl["title"] = lr["title"] parsedLayers.append(pl) inspectFile = '{}/../nifti-tools/nii_inspect.html'.format(scriptdir) with open(inspectFile, 'r') as fp: html = fp.read() html = html.replace( r"var defaultLayers = [];", r"var defaultLayers = {};".format(json.dumps(parsedLayers))) html = html.replace( r"var defaultSliceRange = [];", "var defaultSliceRange = {};".format(json.dumps(sliceRange))) html = html.replace( r"var imgDir = '';", "var imgDir = '{}/';".format( op.relpath(imagefolder, htmlfolder))) with open(htmlfile, 'w') as fp: fp.write(html) print('HTML viewer saved as "{}"'.format(htmlfile)) return FancyDict(out=htmlfile)
def run(args): print('Layer specification: {}'.format(args.layers)) try: htmlFile = args.out if op.isdir(htmlFile): htmlFile = op.join(htmlFile, 'index.html') htmlFolder = op.dirname(htmlFile) if args.out_images: imgFolder = args.out_images else: htmlName, htmlExt = op.splitext(op.basename(htmlFile)) imgFolder = op.join(htmlFolder, htmlName + '_files') if not (op.exists(htmlFolder)): os.makedirs(htmlFolder) print 'Created html output folder "{}".'.format(htmlFolder) if not (op.exists(imgFolder)): os.makedirs(imgFolder) print 'Created image output folder "{}".'.format(imgFolder) imgFolder = op.realpath(imgFolder) scriptDir = op.realpath(op.dirname(__file__)) parsedLayers = [] for i, lr in enumerate(args.layers): nifti_src = lr["file"] if not nifti_src: continue baseName = re.sub('(\.nii|\.nii.gz)$', '', op.basename(nifti_src)) import nibabel nii = nibabel.load(nifti_src) img = numpy.squeeze(nii.get_data()) hdr = nii.get_header() q = hdr.get_best_affine() ornt = nibabel.io_orientation(q) img = nibabel.apply_orientation(img, ornt) dims = img.shape print 'Nifti image loaded, data type "{}"'.format(img.dtype) if len(dims) == 4: raise Exception( 'NIFTI file with RGB color data not supported yet.') # apply colormap index2rgb = None if "colormap" in lr: index2rgb = niitools.parse_colormap(lr["colormap"]) minmax = [None, None] rescale = "pctile" in args if rescale: minmax = niitools.get_limits(img, args.pctile) fmt = 'png' if rescale and rgbLen is 3: fmt = 'jpg' sliceRange = [[], [], []] for d in [0, 1, 2]: dim = ['x', 'y', 'z'][d] numSlices = dims[d] sliceStep = int(args.sliceRangePct[d][1] * numSlices / 100) sliceStart = int(args.sliceRangePct[d][0] * (numSlices - 1) / 100) sliceEnd = int(args.sliceRangePct[d][2] * (numSlices - 1) / 100) sliceRange[d] = [sliceStart, sliceStep, sliceEnd] for i in range(sliceStart, sliceEnd + 1, sliceStep): slice = niitools.get_slice(img, d, i) pngFile = baseName + '_{}{:d}.{}'.format(dim, i, fmt) if index2rgb: slice = niitools.slice2rgb(slice, index2rgb, rescale, minmax[0], minmax[1]) # Save image to PNG scipy.misc.toimage(slice).save(op.join(imgFolder, pngFile)) if i == sliceStart: print 'image {}{} saved to png file "{}".'.format( dim, i, pngFile) pixdim = hdr['pixdim'][1:4] imgsize_mm = [ round(pixdim[0] * dims[0], 1), round(pixdim[1] * dims[1], 1), round(pixdim[2] * dims[2], 1) ] print 'Image size in mm {}'.format(imgsize_mm) # update parsedLayers pl = { "name": baseName, "ext": fmt, "src": nifti_src, "imgsize_px": dims, "imgsize_mm": imgsize_mm } if "title" in lr: pl["title"] = lr["title"] parsedLayers.append(pl) inspectFile = '{}/nii_inspect.html'.format(scriptDir) with open(inspectFile, 'r') as fp: html = fp.read() html = html.replace( r"var defaultLayers = [];", r"var defaultLayers = {};".format(json.dumps(parsedLayers))) html = html.replace( r"var defaultSliceRange = [];", "var defaultSliceRange = {};".format(json.dumps(sliceRange))) html = html.replace( r"var imgDir = '';", "var imgDir = '{}/';".format(op.relpath(imgFolder, htmlFolder))) with open(htmlFile, 'w') as fp: fp.write(html) print 'HTML viewer saved as "{}"'.format(htmlFile) except: print "Unexpected error:", sys.exc_info()[0] raise