Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
Archivo: image.py Proyecto: nipy/nipype
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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
Ejemplo n.º 8
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
            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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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__)
Ejemplo n.º 11
0
  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
Ejemplo n.º 13
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
Ejemplo n.º 14
0
    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 &" %