Exemple #1
0
def vectorize(report,
              pngFolder,
              svgFolder,
              replace,
              curve_tolerance,
              line_tolerance,
              bgColor='auto'):
    converted = 0
    skipped = 0
    print('Input PNG Folder is "{}".'.format(pngFolder))
    if not (op.exists(svgFolder)):
        os.makedirs(svgFolder)
        print('Created output folder "{}".'.format(svgFolder))

    includedExtensions = ['png']
    fileNames = [
        fn for fn in os.listdir(pngFolder)
        if any([fn.endswith(ext) for ext in includedExtensions])
    ]

    # iterate over all png file names
    for pngFile in fileNames:
        baseName = op.splitext(pngFile)[0]
        svgFile = baseName + '.svg'
        outputFile = op.join(svgFolder, svgFile)
        if op.exists(outputFile):
            if not replace:
                print('svg-file "{}" already exists.'.format(svgFile))
                skipped += 1
                continue

        # background color
        inputFile = op.join(pngFolder, pngFile)
        if (bgColor == 'auto'):
            img = scipy.misc.imread(inputFile)
            bgColor = nit.autoBackgroundColor(img)
            print('bgColor is {}'.format(bgColor))
        elif bgColor != '':
            bgColor = nit.hex2rgb(bgColor)
        print('background color {}.'.format(bgColor))

        # generate and save svg with mindthegap
        try:
            prog = op.abspath(
                op.join(op.dirname(__file__), '../mindthegap/bin/mindthegap'))
            cmd = [
                prog, "-i", inputFile, "-o", outputFile, "-t",
                str(curve_tolerance), "-s",
                str(line_tolerance)
            ]
            if bgColor is not None:
                bgColor = nit.rgb2hex(bgColor, '#')
                cmd.extend(["-c", bgColor])
            print('Calling:\n' + ' '.join(cmd) + '\n')
            ans = subprocess.check_output(cmd,
                                          shell=False,
                                          stderr=subprocess.STDOUT)
            converted += 1
        except subprocess.CalledProcessError as e:
            msg = 'Subprocess "' + e.cmd[0] + '" returned code ' + str(
                e.returncode) + '.\nCommand: "' + ' '.join(
                    e.cmd) + '"\nMessage: "' + e.output + '"'
            report.error(msg)
            raise

        print('vector image saved to svg file "{}".'.format(svgFile))

    return {'converted': converted, 'skipped': skipped}
  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
    )
Exemple #3
0
def run(args):
    try:
        skipped = 0
        print('Input PNG Folder: ' + args.png_src)
        pngFolder = args.png_src
        svgFolder = args.svg_dest

        if not (op.exists(svgFolder)):
            os.makedirs(svgFolder)
            print 'Created output folder "{}".'.format(svgFolder)

        # generate hulls in temp dir
        tmpdir = tempfile.mkdtemp(prefix='hull')
        includedExtensions = ['png']
        fileNames = [
            fn for fn in os.listdir(pngFolder)
            if any([fn.endswith(ext) for ext in includedExtensions])
        ]
        for pngFile in fileNames:
            svgFile = op.splitext(pngFile)[0] + '.svg'
            outputFile = op.join(svgFolder, svgFile)
            if op.exists(outputFile):
                if not args.replace:
                    print('Skipping svg-hull "{}", it already exists.'.format(
                        svgFile))
                    skipped += 1
                    continue

            img = scipy.misc.imread(op.join(pngFolder, pngFile))
            # ignore alpha
            if img.shape[-1] == 4:
                if len(img.shape) == 3:
                    img = img[:, :, 0:3]
                elif len(img.shape) == 4:
                    img = img[:, :, :, 0:3]
            if (args.bg_color == "auto"):
                bgColor = nit.autoBackgroundColor(img)
                print('bgColor is {}'.format(bgColor))
            else:
                bgColor = nit.hex2rgb(args.bg_color)
                if img.shape[-1] == 4: bgColor.append(255)

            mask = nit.imageMask(img, [bgColor])
            print 'mask shape {}'.format(mask.shape)

            hullFile = op.join(tmpdir, pngFile)
            if numpy.any(mask):
                print 'Computing convex hull for image "{}"'.format(hullFile)
                hull = convex_hull_image(mask)
            else:
                hull = mask
            scipy.misc.toimage(hull).save(hullFile)

            print('vector image saved to svg file "{}".'.format(svgFile))

        # do the svg conversion
        result = png2svg.vectorize(report,
                                   tmpdir,
                                   svgFolder,
                                   args.replace,
                                   args.curve_tolerance,
                                   args.line_tolerance,
                                   bgColor='#000000')

        # cleanup
        for fn in os.listdir(tmpdir):
            os.remove(op.join(tmpdir, fn))
        os.rmdir(tmpdir)

        result['skipped'] = skipped
        report.success(result)
    except:
        report.fail(__file__)