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)
Example #4
0
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