def _as_reoriented_backport(img, ornt): """Backport of img.as_reoriented as of nibabel 2.2.0""" import numpy as np import nibabel as nb from nibabel.orientations import inv_ornt_aff if np.array_equal(ornt, [[0, 1], [1, 1], [2, 1]]): return img t_arr = nb.apply_orientation(img.get_data(), ornt) new_aff = img.affine.dot(inv_ornt_aff(ornt, img.shape)) reoriented = img.__class__(t_arr, new_aff, img.header) if isinstance(reoriented, nb.Nifti1Pair): # Also apply the transform to the dim_info fields new_dim = list(reoriented.header.get_dim_info()) for idx, value in enumerate(new_dim): # For each value, leave as None if it was that way, # otherwise check where we have mapped it to if value is None: continue new_dim[idx] = np.where(ornt[:, 0] == idx)[0] reoriented.header.set_dim_info(*new_dim) return reoriented
def reorient_image_and_affine(img, aff): """ Reorient an image and and affine such that the affine is approx. diagonal and such that the elements on the main diagonal are positiv Parameters ---------- img : 3D numpy array containing the image aff : 2D numpy array (4,4) affine transformation matrix from image to anatomical coordinate system in homogeneous coordinates Returns ------- a tuple with the reoriented image and the accordingly transformed affine Note ---- The reorientation uses nibabel's io_orientation() and apply_orientation() """ ornt = nib.io_orientation(aff) img_t = nib.apply_orientation(img, ornt) aff_t = aff.dot(inv_ornt_aff(ornt, img.shape)) return img_t, aff_t
def read(path='', b_reorient=False, orientation=(('R', 'L'), ('P', 'A'), ('I', 'S'))): """ Read the nifti file and switch to a given orientation orientation defaults to std LAS (radiological) - RAS (neurological) """ if not os.path.isfile(path): raise ValueError('Provided path is not a valid file') image_nii = nib.load(path) if b_reorient: # switch to given orientation (http://nipy.org/nibabel/image_orientation.html) axcodes = nib.aff2axcodes(image_nii.affine) orientations = nib.orientations.axcodes2ornt(axcodes, orientation) image = image_nii.get_data() image = nib.apply_orientation(image, orientations) header = image_nii.header img_shape = image.shape else: image = image_nii.get_data() img_shape = image.shape header = image_nii.header print(f'preprocessed data shape={img_shape}') return image, header, img_shape
def reorient_nifti_and_bvec(nii, orientation='LPS', bvec=None): ''' Reorient the image from original orientation in nii to a given orientation. :param nii: A nifti image to be reoriented. :type nii: nibabel.nifti1.Nifti1Image :param orientation: A nifti image orientation in a string using CBICA "to" convention. :type orientation: str :param bvec: A 3 x N array of gradient vectors. :type bvec: numpy.array :returns: nii_oriented if bvec is not supplied. :returns: (nii_oriented, bvec_oriented) if bvec is supplied. ''' _module_logger.debug('received a call to reorient_nifti_and_bvec') if not _is_valid_orientation(orientation): pass nii_affine = nii.get_affine() nii_data = nii.get_data() new_orient_code = tuple(orientation.upper()) orig_orient_code = _nib.aff2axcodes(nii_affine) new_orient_ornt = _nib.orientations.axcodes2ornt(new_orient_code) orig_orient_ornt = _nib.orientations.axcodes2ornt(orig_orient_code) trans_ornt = _nib.orientations.ornt_transform(orig_orient_ornt, new_orient_ornt) nii_data_reoriented = _nib.apply_orientation(nii_data, trans_ornt) trans_affine = _nib.orientations.inv_ornt_aff(trans_ornt, nii.shape) nii_affine_reoriented = _np.dot(nii_affine, trans_affine) nii_reoriented = _nib.Nifti1Image(nii_data_reoriented, nii_affine_reoriented, header=nii.get_header()) nii_reoriented.set_qform(nii_reoriented.get_sform()) if bvec is not None: bvec = _np.array(bvec).T bvec_out = _np.dot(bvec, trans_affine[0:3, 0:3]) bvec_out = bvec_out.T return (nii_reoriented, bvec_out) return nii_reoriented
def _as_reoriented_backport(img, ornt): """Backport of img.as_reoriented as of nibabel 2.4.0""" import numpy as np import nibabel as nb from nibabel.orientations import inv_ornt_aff if np.array_equal(ornt, [[0, 1], [1, 1], [2, 1]]): return img t_arr = nb.apply_orientation(img.get_data(), ornt) new_aff = img.affine.dot(inv_ornt_aff(ornt, img.shape)) reoriented = img.__class__(t_arr, new_aff, img.header) if isinstance(reoriented, nb.Nifti1Pair): # Also apply the transform to the dim_info fields new_dim = [None if orig_dim is None else int(ornt[orig_dim, 0]) for orig_dim in img.header.get_dim_info()] reoriented.header.set_dim_info(*new_dim) return reoriented
def _as_reoriented_backport(img, ornt): """Backport of img.as_reoriented as of nibabel 2.4.0""" import numpy as np import nibabel as nb from nibabel.orientations import inv_ornt_aff if np.array_equal(ornt, [[0, 1], [1, 1], [2, 1]]): return img t_arr = nb.apply_orientation(img.get_data(), ornt) new_aff = img.affine.dot(inv_ornt_aff(ornt, img.shape)) reoriented = img.__class__(t_arr, new_aff, img.header) if isinstance(reoriented, nb.Nifti1Pair): # Also apply the transform to the dim_info fields new_dim = [ None if orig_dim is None else int(ornt[orig_dim, 0]) for orig_dim in img.header.get_dim_info() ] reoriented.header.set_dim_info(*new_dim) return reoriented
def _as_reoriented_backport(img, ornt): """Backport of img.as_reoriented as of nibabel 2.2.0""" from nibabel.orientations import inv_ornt_aff if np.array_equal(ornt, [[0, 1], [1, 1], [2, 1]]): return img t_arr = nb.apply_orientation(img.get_data(), ornt) new_aff = img.affine.dot(inv_ornt_aff(ornt, img.shape)) reoriented = img.__class__(t_arr, new_aff, img.header) if isinstance(reoriented, nb.Nifti1Pair): # Also apply the transform to the dim_info fields new_dim = list(reoriented.header.get_dim_info()) for idx, value in enumerate(new_dim): # For each value, leave as None if it was that way, # otherwise check where we have mapped it to if value is None: continue new_dim[idx] = np.where(ornt[:, 0] == idx)[0] reoriented.header.set_dim_info(*new_dim) return reoriented
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 print 'Loading "{}"'.format(nifti_src) nii = nibabel.load(nifti_src) img = numpy.squeeze(nii.get_data()) img_min = numpy.amin(img) img_max = numpy.amax(img) print 'Image type: {} {}-{}'.format(img.dtype,img_min,img_max) if "pctile" in lr: pctile = re.split('[,\- ]+',str(lr["pctile"])) pctile = [float(p) for p in pctile] if len(pctile)<1: pctile = [0,100] elif len(pctile)<2: pctile = [0,pctile[0]] if pctile[1]<=pctile[0]: raise Exception('Max percentile must be larger than min percentile, not {},{}'.format(pctile[0],pctile[1])) elif pctile[0]<0: raise Exception('Min percentile must be >=0, not {}'.format(pctile[0])) elif pctile[1]>100: raise Exception('Max percentile must be <=100, not {}'.format(pctile[1])) if pctile[0]>0: img_min = numpy.percentile(img,pctile[0]) if pctile[1]>0: img_max = numpy.percentile(img,pctile[1]) print 'Percentile {}-{} range: {}-{}'.format(pctile[0],pctile[1],img_min,img_max) hdr = nii.get_header() q = hdr.get_best_affine(); ornt = nibabel.io_orientation(q) print 'Orientation: {}'.format(ornt) img = nibabel.apply_orientation(img,ornt) dims = img.shape print 'Nifti image for layer {} loaded, data type "{}"'.format(i,img.dtype) if len(dims)==4: raise Exception('Error: NIFTI file with RGB color data not supported.') # apply colormap fmt = 'jpg' index2rgb = None hasAlpha = 1 rescale = False if "colormap" in lr: cmap = lr["colormap"] matches = re.search('^(#[0-9a-fA-F]+)-(#[0-9a-fA-F]+)$',cmap) if matches: rescale = True hasAlpha = False rgb1 = hex2rgb(matches.group(1)) rgb2 = hex2rgb(matches.group(2)) index2rgb = [ numpy.array([ rgb1[0]+i/255.0*(rgb2[0]-rgb1[0]), rgb1[1]+i/255.0*(rgb2[1]-rgb1[1]), rgb1[2]+i/255.0*(rgb2[2]-rgb1[2]) ],numpy.uint8) for i in range(256) ] elif cmap.startswith('alpha'): fmt = 'png' rescale = True matches = re.search('^alpha-(#[0-9a-fA-F]+)$',cmap) if matches: rgb = hex2rgb(matches.group(1)) else: rgb = list([255,255,255]) index2rgb = [[rgb[0],rgb[1],rgb[2],i] for i in range(256)] elif cmap[0] == '#': fmt = 'png' hasAlpha = True cmap = cmap.split(',') index2rgb = {}; for i,a in enumerate(cmap): index2rgb[i] = hex2rgba(a) print "Color map {}".format(index2rgb) elif op.exists(cmap): fmt = 'png' hasAlpha = False with open(cmap,'r') as fp: cmap = json.load(fp) print('{}'.format(cmap)) index2rgb = {}; if isinstance(cmap,dict): for i in cmap: print cmap[i] index2rgb[i] = hex2rgba(cmap[i]) else: raise Exception('Colormap file must contain a json-encoded map with color index as keys and #RRGGBB-colors as values.') else: raise Exception('Do not know how to parse colormap "{}".'.format(cmap)) 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 = get_slice(img,dim,i) pngFile = baseName+'_{}{:d}.{}'.format(dim,i,fmt) if index2rgb: slice = slice2rgb(slice,index2rgb,rescale,img_min,img_max) # 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
def run(args): print('Input Nifti: '+args.nifti_src) print('Input JSON colormap file: '+args.json_colmap) 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 = 1024; if numSlices>maxSlices: raise RuntimeError('too many slices (more than '+str(maxSlices)+')'); baseName = op.basename(args.nifti_src) baseName = re.sub('.gz$', '',baseName) baseName = re.sub('.nii$', '',baseName) pngFolder = op.join(args.svg_dest,'png') if not(op.exists(pngFolder)): os.makedirs(pngFolder) print 'Created output folder "{}".'.format(pngFolder) with open(args.json_colmap,'r') as fp: colmap = json.load(fp) lookUpTable = {}; for a in colmap: lookUpTable[a] = hex2rgb(colmap[a]) if len(dims)==4: print 'Error: NIFTI file with RGB color data not supported yet.' exit(0) for i in range(0,numSlices): """ In the code below, the transpose is needed because images are written with the first dimension as rows, second as columns. This must be flipped to align with the common definition of x- and y axes . The ::-1 part is a mirroring operation on the y-axis, which is needed because images are written top to bottom, reversed from the common y-axis direction. """ if args.slice_dir is 'x': slice = img[i,:,::-1].squeeze().transpose(); elif args.slice_dir is 'y': slice = img[:,i,::-1].squeeze().transpose(); elif args.slice_dir is 'z': slice = img[:,::-1,i].squeeze().transpose(); """ In the code below, the indexed image stored in "im" is converted to rgb image which is stored in 2d "finImg" numpy array. """ shape = slice.shape slice = slice.reshape(-1) rgbImg = numpy.zeros(shape=(slice.shape[0],3), dtype=numpy.uint8) for grayvalue in numpy.unique(slice): mask = (slice == grayvalue) val = lookUpTable[str(grayvalue)] rgbImg[mask] = val pngFile = baseName+'_{:04d}.png'.format(i) scipy.misc.toimage(rgbImg.reshape(shape[0],shape[1],3)).save(op.join(pngFolder,pngFile)) print 'image {} saved to png file "{}".'.format(i,pngFile) except: print "Unexpected error:", sys.exc_info()[0] raise
def run(args): try: print('Input Nifti: '+args.nifti_src) print('Colormap to use: '+args.colormap) import nibabel nii = nibabel.load(args.nifti_src) hdr = nii.get_header() q = hdr.get_best_affine(); ornt = nibabel.io_orientation(q) print('The orientation is: {}'.format(ornt)) dims0 = [d for d in nii.shape if d>1] dims = dims0 for i,d in enumerate(ornt): dims[i] = dims0[int(d[0])] print('The dimensions are: {}'.format(dims)) sliceDim = args.dim numSlices = dims[sliceDim]; 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)) 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" in args and args.pctile != None fmt = 'png' if rescale or rgbMode: fmt = 'jpg' filePattern = baseName+'_%04d.{}'.format(fmt) filePattern_py = filePattern.replace('_%04d','_{:04d}') # save coordinate system (Right Anterior Superior) information rasLimits = nit.rasLimits(hdr) if args.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 args.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: result = { 'filePattern':op.join(outFolder,filePattern), 'rasLimits':rasLimits } report.success(result) return # load image, it is needed img = nii.get_data() img = nibabel.apply_orientation(img,ornt) img = numpy.squeeze(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,args.pctile) print('minmax {}, rescale {}'.format(minmax,rescale)) index2rgb = nit.parse_colormap(args.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) else: rescale = False rgbLen = 3 index2rgb = False bbg = args.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 = args.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 args.replace: continue slc = nit.get_slice(img,sliceDim,i) print ('slice shape {}'.format(slc.shape)) 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]) if rgbMode=='record': # create 3rd dimension from rgb record slc = record2rgb(slc) # 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) result = { 'filePattern':op.join(outFolder,filePattern), 'rasLimits':rasLimits } report.success(result) except: report.fail(__file__)
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 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
try: text0 = "HippoDeep Report" text1 = "Total Intracranial Volume: " text2 = "Left Hippocampus Volume: " text3 = "Right Hippocampus Volume: " text1 += "{:.2f}".format(float(vol) / 1000000, 2) + " l" # transform mm^3 to liter text2 += "{:.2f}".format(float(volsAA_L) / 1000, 2) + " ml" # transform mm^3 to mililiter text3 += "{:.2f}".format(float(volsAA_R) / 1000, 2) + " ml" # transform mm^3 to mililiter filename = outfilename.replace("_tiv.nii.gz", ".pdf") # transform 2 std SpatResol = np.asarray(img.header.get_zooms()) d_orig = nibabel.apply_orientation(d_orig, trn) wdata_L = nibabel.apply_orientation(wdata_L, trn) wdata_R = nibabel.apply_orientation(wdata_R, trn) brainmask = nibabel.apply_orientation(brainmask, trn) SpatResol[int(trn[0, 0])], SpatResol[int(trn[1, 0])], SpatResol[int( trn[2, 0])] = SpatResol[0], SpatResol[1], SpatResol[2] # go HippoDeepReport(SpatResol, d_orig, wdata_L, wdata_R, brainmask, text0, text1, text2, text3, filename) print(" Generated PDF report") except: print(" Generating PDF report failed") print(" Elapsed time for subject %4.2fs " % (time.time() - Ti)) print(" To display using fslview, try:") print(" fslview %s %s -t .5 %s -t .5 &" %