def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images b0img, b0hdr = load(args.b0image) bximg, bxhdr = load(args.bximage) # check if image are compatible if not b0img.shape == bximg.shape: raise ArgumentError( 'The input images shapes differ i.e. {} != {}.'.format( b0img.shape, bximg.shape)) if not header.get_pixel_spacing(b0hdr) == header.get_pixel_spacing(bxhdr): raise ArgumentError( 'The input images voxel spacing differs i.e. {} != {}.'.format( header.get_pixel_spacing(b0hdr), header.get_pixel_spacing(bxhdr))) # check if supplied threshold value as well as the b value is above 0 if args.threshold is not None and not args.threshold >= 0: raise ArgumentError( 'The supplied threshold value must be greater than 0, otherwise a division through 0 might occur.' ) if not args.b > 0: raise ArgumentError('The supplied b-value must be greater than 0.') # compute threshold value if not supplied if args.threshold is None: b0thr = otsu(b0img, 32) / 2. # divide by 2 to decrease impact bxthr = otsu(bximg, 32) / 2. if 0 >= b0thr: raise ArgumentError( 'The supplied b0image seems to contain negative values.') if 0 >= bxthr: raise ArgumentError( 'The supplied bximage seems to contain negative values.') else: b0thr = bxthr = args.threshold logger.debug('thresholds={}/{}, b-value={}'.format(b0thr, bxthr, args.b)) # threshold b0 + bx DW image to obtain a mask # b0 mask avoid division through 0, bx mask avoids a zero in the ln(x) computation mask = (b0img > b0thr) & (bximg > bxthr) logger.debug( 'excluding {} of {} voxels from the computation and setting them to zero' .format(scipy.count_nonzero(mask), scipy.prod(mask.shape))) # compute the ADC adc = scipy.zeros(b0img.shape, b0img.dtype) adc[mask] = -1. * args.b * scipy.log(bximg[mask] / b0img[mask]) # saving the resulting image save(adc, args.output, b0hdr, args.force)
def zoom(image, factor, dimension, hdr = False, order = 3): """ Zooms the provided image by the supplied factor in the supplied dimension. The factor is an integer determining how many slices should be put between each existing pair. If an image header (hdr) is supplied, its voxel spacing gets updated. Returns the image and the updated header or false. """ # check if supplied dimension is valid if dimension >= image.ndim: raise argparse.ArgumentError('The supplied zoom-dimension {} exceeds the image dimensionality of 0 to {}.'.format(dimension, image.ndim - 1)) # get logger logger = Logger.getInstance() logger.debug('Old shape = {}.'.format(image.shape)) # perform the zoom zoom = [1] * image.ndim zoom[dimension] = (image.shape[dimension] + (image.shape[dimension] - 1) * factor) / float(image.shape[dimension]) logger.debug('Reshaping with = {}.'.format(zoom)) image = interpolation.zoom(image, zoom, order=order) logger.debug('New shape = {}.'.format(image.shape)) if hdr: new_spacing = list(header.get_pixel_spacing(hdr)) new_spacing[dimension] = new_spacing[dimension] / float(factor + 1) logger.debug('Setting pixel spacing from {} to {}....'.format(header.get_pixel_spacing(hdr), new_spacing)) header.set_pixel_spacing(hdr, tuple(new_spacing)) return image, hdr
def main(): onedir = sys.argv[1] # the first folder containing case folders twodir = sys.argv[2] # the second folder containing case folders nocase = (len(sys.argv) > 3 and sys.argv[3] == '-i') if DEBUG: print 'INFO: Comparing all cases in folders {} and {}.'.format(onedir, twodir) # iterate over first folder and compare voxel spacings with equivalent image in second folder print "Case\tvs same\tshape same" for root, dirs, files in os.walk(onedir): for case in sorted(dirs): for root, dirs, files in os.walk('{}/{}'.format(onedir, case)): for file_ in files: if file_.endswith(FILE_ENDING): i, hi = load('{}/{}/{}'.format(onedir, case, file_)) if nocase: j, hj = load('{}/{}.{}'.format(twodir, case, FILE_ENDING)) else: j, hj = load('{}/{}/{}'.format(twodir, case, file_)) vs_same = numpy.array_equal(header.get_pixel_spacing(hi), header.get_pixel_spacing(hj)) shape_same = numpy.array_equal(i.shape, j.shape) print '{}\t{}\t{}'.format(case, vs_same, shape_same) if not vs_same: print "\t{} vs {}".format(header.get_pixel_spacing(hi), header.get_pixel_spacing(hj)) if not shape_same: print "\t{} vs {}".format(i.shape, j.shape) print 'Terminated.'
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images b0img, b0hdr = load(args.b0image) bximg, bxhdr = load(args.bximage) # convert to float b0img = b0img.astype(numpy.float) bximg = bximg.astype(numpy.float) # check if image are compatible if not b0img.shape == bximg.shape: raise ArgumentError('The input images shapes differ i.e. {} != {}.'.format(b0img.shape, bximg.shape)) if not header.get_pixel_spacing(b0hdr) == header.get_pixel_spacing(bxhdr): raise ArgumentError('The input images voxel spacing differs i.e. {} != {}.'.format(header.get_pixel_spacing(b0hdr), header.get_pixel_spacing(bxhdr))) # check if supplied threshold value as well as the b value is above 0 if args.threshold is not None and not args.threshold >= 0: raise ArgumentError('The supplied threshold value must be greater than 0, otherwise a division through 0 might occur.') if not args.b > 0: raise ArgumentError('The supplied b-value must be greater than 0.') # compute threshold value if not supplied if args.threshold is None: b0thr = otsu(b0img, 32) / 4. # divide by 4 to decrease impact bxthr = otsu(bximg, 32) / 4. if 0 >= b0thr: raise ArgumentError('The supplied b0image seems to contain negative values.') if 0 >= bxthr: raise ArgumentError('The supplied bximage seems to contain negative values.') else: b0thr = bxthr = args.threshold logger.debug('thresholds={}/{}, b-value={}'.format(b0thr, bxthr, args.b)) # threshold b0 + bx DW image to obtain a mask # b0 mask avoid division through 0, bx mask avoids a zero in the ln(x) computation mask = binary_fill_holes(b0img > b0thr) & binary_fill_holes(bximg > bxthr) # perform a number of binary morphology steps to select the brain only mask = binary_erosion(mask, iterations=1) mask = largest_connected_component(mask) mask = binary_dilation(mask, iterations=1) logger.debug('excluding {} of {} voxels from the computation and setting them to zero'.format(numpy.count_nonzero(mask), numpy.prod(mask.shape))) # compute the ADC adc = numpy.zeros(b0img.shape, b0img.dtype) adc[mask] = -1. * args.b * numpy.log(bximg[mask] / b0img[mask]) adc[adc < 0] = 0 # saving the resulting image save(adc, args.output, b0hdr, args.force)
def test03(img, hdr, idx, delta): # TEST 03: DOES ANY META-INFORMATION GET LOST DURING FORMAT CONVERSION? AND IF YES; WHICH? for tr in types_int: # reference type print '' oformat = tr # create, save and load reference image try: name_ref = tmp_folder + '.'.join(['tmp_ref', tr]) save(img, name_ref, hdr, True) img_ref, hdr_ref = load(name_ref) except Exception as e: print '\tERROR: Could not generate reference image for type {}: {}'.format(otype, e) continue # extract meta-data from reference image mdata_ref = {'shape': img_ref.shape, 'dtype': img_ref.dtype, 'point': img_ref[idx], 'spacing': header.get_pixel_spacing(hdr_ref), 'offset': header.get_offset(hdr_ref),} # print meta-data from reference image # iterate of test images for tt in types_int: # test type print '{} => {}'.format(oformat, tt), # create, save and load test images try: #print type(img_ref), type(hdr_ref) #print type(img_test), type(hdr_test) name_test = tmp_folder + '.'.join(['tmp_test', tt]) save(img_ref, name_test, hdr_ref, True) img_test, hdr_test = load(name_test) except Exception as e: print '\tERROR: Could not generate test image. {}'.format(e) continue # extract meta-data from test image mdata_test = {'shape': img_test.shape, 'dtype': img_test.dtype, 'spacing': header.get_pixel_spacing(hdr_test), 'offset': header.get_offset(hdr_test), 'point': img_test[idx]} # compare reference against meta-image error = False for k in mdata_ref.keys(): equal = _compare(mdata_ref[k], mdata_test[k], delta) #print '\n\t{} ({}) : {} = {}'.format(equal, k, mdata_ref[k], mdata_test[k]), if not equal: error = True print '\n\t{} ({}) : {} = {}'.format(equal, k, mdata_ref[k], mdata_test[k]), if not error: print '\t{}'.format(True) else: print '\n'
def resample(img, hdr, target_spacing, bspline_order=3, mode='constant'): """ Re-sample an image to a new voxel-spacing. Taken form medpy.io. Parameters ---------- img : array_like The image. hdr : object The image header. target_spacing : number or sequence of numbers The target voxel spacing to achieve. If a single number, isotropic spacing is assumed. bspline_order : int The bspline order used for interpolation. mode : str Points outside the boundaries of the input are filled according to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). Default is 'constant'. Warning ------- Voxel-spacing of input header will be modified in-place! If the target spacing can't be set exactly, for example in low pixel images, then the closest spacing will be chosen Returns ------- img : ndarray The re-sampled image. hdr : object The image header with the new voxel spacing. """ if isinstance(target_spacing, numbers.Number): target_spacing = [target_spacing] * img.ndim # compute zoom values zoom_factors = [old / float(new) for new, old in zip(target_spacing, header.get_pixel_spacing(hdr))] print "Zoom Factors" print zoom_factors oldImageShape = img.shape # zoom image img = zoom(img, zoom_factors, order=bspline_order, mode=mode) newImageShape = img.shape old_pixel_spacing = header.get_pixel_spacing(hdr) new_pixel_spacing = np.round(np.divide(np.multiply(oldImageShape,old_pixel_spacing),newImageShape),7) print "Target Pixel Spacing" print target_spacing print "Actual Pixel Spacing" print new_pixel_spacing # set new voxel spacing header.set_pixel_spacing(hdr, new_pixel_spacing) return img, hdr
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input data input_data, input_header = load(args.input) logger.debug('Old shape = {}.'.format(input_data.shape)) # compute new shape new_shape = list(input_data.shape) new_shape[args.dimension] = 1 + (new_shape[args.dimension] - 1) / (args.discard + 1) # prepare output image output_data = scipy.zeros(new_shape, dtype=input_data.dtype) # prepare slicers slicer_in = [slice(None)] * input_data.ndim slicer_out = [slice(None)] * input_data.ndim # prepare skip-counter and output image slice counter skipc = 0 slicec = 0 logger.debug('Shrinking from {} to {}...'.format(input_data.shape, new_shape)) for idx in range(input_data.shape[args.dimension]): if 0 == skipc: # transfer slice slicer_in[args.dimension] = slice(idx, idx + 1) slicer_out[args.dimension] = slice(slicec, slicec + 1) output_data[slicer_out] = input_data[slicer_in] # resert resp. increase counter skipc = args.discard slicec += 1 else: # skip slice # decrease skip counter skipc -= 1 # set new pixel spacing new_spacing = list(header.get_pixel_spacing(input_header)) new_spacing[ args.dimension] = new_spacing[args.dimension] * float(args.discard + 1) logger.debug('Setting pixel spacing from {} to {}....'.format( header.get_pixel_spacing(input_header), new_spacing)) header.set_pixel_spacing(input_header, tuple(new_spacing)) save(output_data, args.output, input_header, args.force)
def __diff(self, hdr1, hdr2): """ Returns an error message if the meta-data of the supplied headers differ, otherwise False. """ if not self.__same_seq(header.get_pixel_spacing(hdr1), header.get_pixel_spacing(hdr2)): return 'the voxel spacing is not consistent: {} != {}'.format(header.get_pixel_spacing(hdr1), header.get_pixel_spacing(hdr2)) if not self.__same_seq(header.get_offset(hdr1), header.get_offset(hdr2)): return 'the offset is not consistent: {} != {}'.format(header.get_offset(hdr1), header.get_offset(hdr2)) #return 'the offset is not consistent: {} != {}\n{} / {}\n{} / {}'.format(header.get_offset(hdr1), header.get_offset(hdr2), type(hdr1), type(hdr2), hdr2.NumberOfFrames if "NumberOfFrames" in hdr2 else "NONE", hdr2.ImagePositionPatient if "ImagePositionPatient" in hdr2 else 'NONE') else: return False
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input data input_data, input_header = load(args.input) logger.debug('Old shape = {}.'.format(input_data.shape)) # compute new shape new_shape = list(input_data.shape) new_shape[args.dimension] = 1 + (new_shape[args.dimension] - 1) / (args.discard + 1) # prepare output image output_data = scipy.zeros(new_shape, dtype=input_data.dtype) # prepare slicers slicer_in = [slice(None)] * input_data.ndim slicer_out = [slice(None)] * input_data.ndim # prepare skip-counter and output image slice counter skipc = 0 slicec = 0 logger.debug('Shrinking from {} to {}...'.format(input_data.shape, new_shape)) for idx in range(input_data.shape[args.dimension]): if 0 == skipc: # transfer slice slicer_in[args.dimension] = slice(idx, idx + 1) slicer_out[args.dimension] = slice(slicec, slicec + 1) output_data[slicer_out] = input_data[slicer_in] # resert resp. increase counter skipc = args.discard slicec += 1 else: # skip slice # decrease skip counter skipc -= 1 # set new pixel spacing new_spacing = list(header.get_pixel_spacing(input_header)) new_spacing[args.dimension] = new_spacing[args.dimension] * float(args.discard + 1) logger.debug('Setting pixel spacing from {} to {}....'.format(header.get_pixel_spacing(input_header), new_spacing)) header.set_pixel_spacing(input_header, tuple(new_spacing)) save(output_data, args.output, input_header, args.force)
def main(): # catch parameters segmentation_base_string = sys.argv[1] ground_truth_base_string = sys.argv[2] mask_file_base_string = sys.argv[3] cases = sys.argv[4:] # evaluate each case and collect the scores hds = [] assds = [] precisions = [] recalls = [] dcs = [] # load images and apply mask to segmentation and ground truth (to remove ground truth fg outside of brain mask) splush = [load(segmentation_base_string.format(case)) for case in cases] tplush = [load(ground_truth_base_string.format(case)) for case in cases] masks = [load(mask_file_base_string.format(case))[0].astype(numpy.bool) for case in cases] s = [s.astype(numpy.bool) & m for (s, _), m in zip(splush, masks)] t = [t.astype(numpy.bool) & m for (t, _), m in zip(tplush, masks)] hs = [h for _, h in splush] ht = [h for _, h in tplush] # compute and append metrics (Pool-processing) pool = Pool(n_jobs) dcs = pool.map(wdc, zip(t, s)) precisions = pool.map(wprecision, zip(s, t)) recalls = pool.map(wrecall, zip(s, t)) hds = pool.map(whd, zip(t, s, [header.get_pixel_spacing(h) for h in ht])) assds = pool.map(wassd, zip(t, s, [header.get_pixel_spacing(h) for h in ht])) # print case-wise results print 'Metrics:' print 'Case\tDC[0,1]\tHD(mm)\tP2C(mm)\tprec.\trecall' for case, _dc, _hd, _assd, _pr, _rc in zip(cases, dcs, hds, assds, precisions, recalls): print '{}\t{:>3,.3f}\t{:>4,.3f}\t{:>4,.3f}\t{:>3,.3f}\t{:>3,.3f}'.format(case, _dc, _hd, _assd, _pr, _rc) # check for nan/inf values of failed cases and signal warning mask = numpy.isfinite(hds) if not numpy.all(mask): print 'WARNING: Average values only computed on {} of {} cases!'.format(numpy.count_nonzero(mask), mask.size) print 'DM average\t{} +/- {} (Median: {})'.format(numpy.asarray(dcs)[mask].mean(), numpy.asarray(dcs)[mask].std(), numpy.median(numpy.asarray(dcs)[mask])) print 'HD average\t{} +/- {} (Median: {})'.format(numpy.asarray(hds)[mask].mean(), numpy.asarray(hds)[mask].std(), numpy.median(numpy.asarray(hds)[mask])) print 'ASSD average\t{} +/- {} (Median: {})'.format(numpy.asarray(assds)[mask].mean(), numpy.asarray(assds)[mask].std(), numpy.median(numpy.asarray(assds)[mask])) print 'Prec. average\t{} +/- {} (Median: {})'.format(numpy.asarray(precisions)[mask].mean(), numpy.asarray(precisions)[mask].std(), numpy.median(numpy.asarray(precisions)[mask])) print 'Rec. average\t{} +/- {} (Median: {})'.format(numpy.asarray(recalls)[mask].mean(), numpy.asarray(recalls)[mask].std(), numpy.median(numpy.asarray(recalls)[mask]))
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input image data_input, header_input = load(args.input) # transform to uin8 data_input = data_input.astype(scipy.uint8) # reduce to 3D, if larger dimensionality if data_input.ndim > 3: for _ in range(data_input.ndim - 3): data_input = data_input[...,0] # iter over slices (2D) until first with content is detected for plane in data_input: if scipy.any(plane): # set pixel spacing spacing = list(header.get_pixel_spacing(header_input)) spacing = spacing[1:3] __update_header_from_array_nibabel(header_input, plane) header.set_pixel_spacing(header_input, spacing) # save image save(plane, args.output, header_input, args.force) break logger.info("Successfully terminated.")
def sresamplebyexample(src, dest, referenceimage, binary = False): r""" Secure-re-sample an image located at ``src`` by example ``referenceimage`` and save it under ``dest``. Parameters ---------- src : string Source image file. dest : string Destination image file. referenceimage : string Reference image displaying the target spacing, origin and size. binary : bool Set to ``True`` for binary images. """ # get target voxel spacing refimage, refhdr = load(referenceimage) spacing = header.get_pixel_spacing(refhdr) with tmpdir() as t: # create a temporary copy of the reference image with the source image data-type (imiImageResample requires both images to be of the same dtype) srcimage, _ = load(src) save(refimage.astype(srcimage.dtype), os.path.join(t, 'ref.nii.gz'), refhdr) # prepare and run registration command cmd = ['imiImageResample', '-I', src, '-O', dest, '-R', os.path.join(t, 'ref.nii.gz'), '-s'] + map(str, spacing) if binary: cmd += ['-b'] rtcode, stdout, stderr = call(cmd) # check if successful if not os.path.isfile(dest): raise CommandExecutionError(cmd, rtcode, stdout, stderr, 'Binary re-sampling result image not created.')
def main(): i, h = load(sys.argv[1]) print 'Image:\t{}'.format(sys.argv[1]) print 'Shape:\t{}'.format(i.shape) print 'Spacing:{}'.format(header.get_pixel_spacing(h)) print 'Offset:\t{}'.format(header.get_offset(h)) if 0 == h.get_header()['qform_code']: method = 'ANALYZE 7.5 (old)' if h.get_header()['qform_code'] > 0: method = 'Normal (qform)' if h.get_header()['sform_code'] > 0: method = 'Special space (sform)' print print 'Orientation and location in space:' print 'Type:\t\t{}'.format(method) print 'qform_code:\t{}'.format(h.get_header()['qform_code']) print 'sform_code:\t{}'.format(h.get_header()['sform_code']) print print 'qform == sform?\t{} (max diff={})'.format(numpy.all(h.get_qform() == h.get_sform()), numpy.max(numpy.abs(h.get_qform() - h.get_sform()))) print 'affine = qform?\t{} (max diff={})'.format(numpy.all(h.get_affine() == h.get_qform()), numpy.max(numpy.abs(h.get_affine() - h.get_qform()))) print 'affine = sform?\t{} (max diff={})'.format(numpy.all(h.get_affine() == h.get_sform()), numpy.max(numpy.abs(h.get_affine() - h.get_sform()))) print print 'qform:' print h.get_qform() print 'sform:' print h.get_sform() print 'affine:' print h.get_affine()
def __diff(self, hdr1, hdr2): """ Returns an error message if the meta-data of the supplied headers differ, otherwise False. """ if not self.__same_seq(header.get_pixel_spacing(hdr1), header.get_pixel_spacing(hdr2)): return 'the voxel spacing is not consistent: {} != {}'.format( header.get_pixel_spacing(hdr1), header.get_pixel_spacing(hdr2)) if not self.__same_seq(header.get_offset(hdr1), header.get_offset(hdr2)): return 'the offset is not consistent: {} != {}'.format( header.get_offset(hdr1), header.get_offset(hdr2)) #return 'the offset is not consistent: {} != {}\n{} / {}\n{} / {}'.format(header.get_offset(hdr1), header.get_offset(hdr2), type(hdr1), type(hdr2), hdr2.NumberOfFrames if "NumberOfFrames" in hdr2 else "NONE", hdr2.ImagePositionPatient if "ImagePositionPatient" in hdr2 else 'NONE') else: return False
def main(): i1, h1 = load(sys.argv[1]) i2, h2 = load(sys.argv[2]) # shift image to align origins origin_h1 = numpy.sign(h1.get_qform()[0:3,0:3]).dot(header.get_offset(h1)) origin_h2 = numpy.sign(h2.get_qform()[0:3,0:3]).dot(header.get_offset(h2)) origin_difference_pixel = (origin_h1 - origin_h2) / numpy.asarray(header.get_pixel_spacing(h1)) # negative values: shift image 1 by this upon inserting (which is the smae as cutting the output image) # positive values: cut image 1 by this at inserting and also cut right side by length of output image plus this value o = numpy.zeros(i2.shape, i2.dtype) o_slicer = [] i_slicer = [] for j, p in enumerate(origin_difference_pixel): if p >= 0: i_slicer.append(slice(0, min(i1.shape[j], o.shape[j] - abs(p)))) o_slicer.append(slice(abs(p), min(i1.shape[j] + abs(p), o.shape[j]))) else: i_slicer.append(slice(abs(p), min(i1.shape[j], o.shape[j] + abs(p)))) o_slicer.append(slice(0, min(i1.shape[j] - abs(p), o.shape[j]))) o[o_slicer] = i1[i_slicer] header.set_offset(h1, header.get_offset(h2)) save(o, sys.argv[3], h1)
def main(): parser = getParser() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images img, hdr = load(args.input) img = img.astype(numpy.bool) # check spacing values if not len(args.spacing) == img.ndim: parser.error( 'The image has {} dimensions, but {} spacing parameters have been supplied.' .format(img.ndim, len(args.spacing))) # check if output image exists if not args.force: if os.path.exists(args.output): parser.error('The output image {} already exists.'.format( args.output)) logger.debug('target voxel spacing: {}'.format(args.spacing)) # determine number of required complete slices for up-sampling vs = header.get_pixel_spacing(hdr) rcss = [ int(y // x - 1) for x, y in zip(args.spacing, vs) ] # TODO: For option b, remove the - 1; better: no option b, since I am rounding later anyway # remove negatives and round up to next even number rcss = [x if x > 0 else 0 for x in rcss] rcss = [x if 0 == x % 2 else x + 1 for x in rcss] logger.debug('intermediate slices to add per dimension: {}'.format(rcss)) # for each dimension requiring up-sampling, from the highest down, perform shape based slice interpolation logger.info('Adding required slices using shape based interpolation.') for dim, rcs in enumerate(rcss): if rcs > 0: logger.debug( 'adding {} intermediate slices to dimension {}'.format( rcs, dim)) img = shape_based_slice_interpolation(img, dim, rcs) logger.debug('resulting new image shape: {}'.format(img.shape)) # compute and set new voxel spacing nvs = [x / (y + 1.) for x, y in zip(vs, rcss)] header.set_pixel_spacing(hdr, nvs) logger.debug('intermediate voxel spacing: {}'.format(nvs)) # interpolate with nearest neighbour logger.info('Re-sampling the image with a b-spline order of {}.'.format( args.order)) img, hdr = resample(img, hdr, args.spacing, args.order, mode='nearest') # saving the resulting image save(img, args.output, hdr, args.force)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input image data_input, header_input = load(args.input) logger.debug('Original shape = {}.'.format(data_input.shape)) # check if supplied dimension parameters is inside the images dimensions if args.dimension1 >= data_input.ndim or args.dimension1 < 0: raise ArgumentError('The first swap-dimension {} exceeds the number of input volume dimensions {}.'.format(args.dimension1, data_input.ndim)) elif args.dimension2 >= data_input.ndim or args.dimension2 < 0: raise ArgumentError('The second swap-dimension {} exceeds the number of input volume dimensions {}.'.format(args.dimension2, data_input.ndim)) # swap axes data_output = scipy.swapaxes(data_input, args.dimension1, args.dimension2) # swap pixel spacing and offset ps = list(header.get_pixel_spacing(header_input)) ps[args.dimension1], ps[args.dimension2] = ps[args.dimension2], ps[args.dimension1] header.set_pixel_spacing(header_input, ps) os = list(header.get_offset(header_input)) os[args.dimension1], os[args.dimension2] = os[args.dimension2], os[args.dimension1] header.set_offset(header_input, os) logger.debug('Resulting shape = {}.'.format(data_output.shape)) # save resulting volume save(data_output, args.output, header_input, args.force) logger.info("Successfully terminated.")
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # check if output image exists (will also be performed before saving, but as the gradient might be time intensity, a initial check can save frustration) if not args.force: if os.path.exists(args.output): raise ArgumentError('The output image {} already exists.'.format( args.output)) # loading image data_input, header_input = load(args.input) logger.debug('Input array: dtype={}, shape={}'.format( data_input.dtype, data_input.shape)) # execute the gradient map filter logger.info('Applying gradient map filter...') data_output = filter.gradient_magnitude( data_input, header.get_pixel_spacing(header_input)) logger.debug('Resulting array: dtype={}, shape={}'.format( data_output.dtype, data_output.shape)) # save image save(data_output, args.output, header_input, args.force) logger.info('Successfully terminated.')
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # check if output image exists (will also be performed before saving, but as the gradient might be time intensity, a initial check can save frustration) if not args.force: if os.path.exists(args.output): raise ArgumentError('The output image {} already exists.'.format(args.output)) # loading image data_input, header_input = load(args.input) logger.debug('Input array: dtype={}, shape={}'.format(data_input.dtype, data_input.shape)) # execute the gradient map filter logger.info('Applying gradient map filter...') data_output = filter.gradient_magnitude(data_input, header.get_pixel_spacing(header_input)) logger.debug('Resulting array: dtype={}, shape={}'.format(data_output.dtype, data_output.shape)) # save image save(data_output, args.output, header_input, args.force) logger.info('Successfully terminated.')
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input images and cast to bool images = [] for input_ in args.inputs: t = load(input_) images.append((t[0], t[1])) # check if their shapes and voxel spacings are all equal s0 = images[0][0].shape if not numpy.all([i[0].shape == s0 for i in images[1:]]): raise argparse.ArgumentError( args.input, 'At least one input image is of a different shape than the others.' ) vs0 = header.get_pixel_spacing(images[0][1]) if not numpy.all( [header.get_pixel_spacing(i[1]) == vs0 for i in images[1:]]): raise argparse.ArgumentError( args.input, 'At least one input image has a different voxel spacing than the others.' ) # execute operation logger.debug('Executing operation {} over {} images.'.format( args.operation, len(images))) if 'max' == args.operation: out = numpy.maximum.reduce([t[0] for t in images]) elif 'min' == args.operation: out = numpy.minimum.reduce([t[0] for t in images]) elif 'sum' == args.operation: out = numpy.sum([t[0] for t in images], 0).astype(numpy.uint8) else: # avg out = numpy.average([t[0] for t in images], 0).astype(numpy.float32) # save output save(out, args.output, images[0][1], args.force) logger.info("Successfully terminated.")
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load first input image as example example_data, example_header = load(args.inputs[0]) # test if the supplied position is valid if args.position > example_data.ndim or args.position < 0: raise ArgumentError( 'The supplied position for the new dimension is invalid. It has to be between 0 and {}.' .format(example_data.ndim)) # prepare empty output volume output_data = scipy.zeros([len(args.inputs)] + list(example_data.shape), dtype=example_data.dtype) # add first image to output volume output_data[0] = example_data # load input images and add to output volume for idx, image in enumerate(args.inputs[1:]): image_data, _ = load(image) if not args.ignore and image_data.dtype != example_data.dtype: raise ArgumentError( 'The dtype {} of image {} differs from the one of the first image {}, which is {}.' .format(image_data.dtype, image, args.inputs[0], example_data.dtype)) if image_data.shape != example_data.shape: raise ArgumentError( 'The shape {} of image {} differs from the one of the first image {}, which is {}.' .format(image_data.shape, image, args.inputs[0], example_data.shape)) output_data[idx + 1] = image_data # move new dimension to the end or to target position for dim in range(output_data.ndim - 1): if dim >= args.position: break output_data = scipy.swapaxes(output_data, dim, dim + 1) # set pixel spacing spacing = list(header.get_pixel_spacing(example_header)) spacing = tuple(spacing[:args.position] + [args.spacing] + spacing[args.position:]) example_header.set_voxel_spacing(spacing) # save created volume save(output_data, args.output, example_header, args.force) logger.info("Successfully terminated.")
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load first input image as example example_data, example_header = load(args.inputs[0]) # test if the supplied position is valid if args.position > example_data.ndim or args.position < 0: raise ArgumentError('The supplied position for the new dimension is invalid. It has to be between 0 and {}.'.format(example_data.ndim)) # prepare empty output volume output_data = scipy.zeros([len(args.inputs)] + list(example_data.shape), dtype=example_data.dtype) # add first image to output volume output_data[0] = example_data # load input images and add to output volume for idx, image in enumerate(args.inputs[1:]): image_data, _ = load(image) if not args.ignore and image_data.dtype != example_data.dtype: raise ArgumentError('The dtype {} of image {} differs from the one of the first image {}, which is {}.'.format(image_data.dtype, image, args.inputs[0], example_data.dtype)) if image_data.shape != example_data.shape: raise ArgumentError('The shape {} of image {} differs from the one of the first image {}, which is {}.'.format(image_data.shape, image, args.inputs[0], example_data.shape)) output_data[idx + 1] = image_data # move new dimension to the end or to target position for dim in range(output_data.ndim - 1): if dim >= args.position: break output_data = scipy.swapaxes(output_data, dim, dim + 1) # set pixel spacing spacing = list(header.get_pixel_spacing(example_header)) spacing = tuple(spacing[:args.position] + [args.spacing] + spacing[args.position:]) # !TODO: Find a way to enable this also for PyDicom and ITK images if __is_header_nibabel(example_header): __update_header_from_array_nibabel(example_header, output_data) header.set_pixel_spacing(example_header, spacing) else: raise ArgumentError("Sorry. Setting the voxel spacing of the new dimension only works with NIfTI images. See the description of this program for more details.") # save created volume save(output_data, args.output, example_header, args.force) logger.info("Successfully terminated.")
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # constants contour_dimension = 2 # load input data input_data, input_header = load(args.input) # create output array new_shape = list(input_data.shape) new_shape[contour_dimension] = input_data.shape[contour_dimension] + (input_data.shape[contour_dimension] - 1) * args.enhancement output_data = scipy.zeros(new_shape, scipy.uint8) # prepare slicers slicer_from = [slice(None)] * input_data.ndim slicer_to = [slice(None)] * output_data.ndim logger.debug('Old shape = {}.'.format(input_data.shape)) # copy data for idx in range(input_data.shape[contour_dimension]): slicer_from[contour_dimension] = slice(idx, idx + 1) slicer_to[contour_dimension] = slice(idx * (args.enhancement + 1), idx * (args.enhancement + 1) + 1) output_data[slicer_to] = input_data[slicer_from] logger.debug('New shape = {}.'.format(output_data.shape)) new_spacing = list(header.get_pixel_spacing(input_header)) new_spacing[contour_dimension] = new_spacing[contour_dimension] / float(args.enhancement + 1) logger.debug('Setting pixel spacing from {} to {}....'.format(header.get_pixel_spacing(input_header), new_spacing)) header.set_pixel_spacing(input_header, tuple(new_spacing)) save(output_data, args.output, input_header, args.force)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # copy the example image or generate empty image, depending on the modus if args.example: grid_image = scipy.zeros(args.example_image.shape, scipy.bool_) grid_header = args.example_header else: grid_image = scipy.zeros(args.shape, scipy.bool_) # !TODO: Find another solution for this # Saving and loading image once to generate a valid header tmp_dir = tempfile.mkdtemp() tmp_image = '{}/{}'.format(tmp_dir, args.output.split('/')[-1]) save(grid_image, tmp_image) _, grid_header = load(tmp_image) try: os.remove(tmp_image) os.rmdir(tmp_dir) except Exception: pass # set the image attributes if supplied if args.pixelspacing: header.set_pixel_spacing(grid_header, args.pixelspacing) if args.offset: header.set_offset(grid_header, args.offset) # compute the right grid spacing for each dimension if args.real: grid_spacing = [ int(round(sp / float(ps))) for sp, ps in zip( args.spacing, header.get_pixel_spacing(grid_header)) ] else: grid_spacing = args.spacing # paint the grid into the empty image volume for dim in range(grid_image.ndim): if 0 == grid_spacing[dim]: continue # skip dimension of 0 grid spacing supplied for offset in range(0, grid_image.shape[dim], grid_spacing[dim]): slicer = [slice(None)] * grid_image.ndim slicer[dim] = slice(offset, offset + 1) grid_image[slicer] = True # saving resulting grid volume save(grid_image, args.output, grid_header, args.force)
def main(): parser = getParser() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images img, hdr = load(args.input) img = img.astype(numpy.bool) # check spacing values if not len(args.spacing) == img.ndim: parser.error('The image has {} dimensions, but {} spacing parameters have been supplied.'.format(img.ndim, len(args.spacing))) # check if output image exists if not args.force: if os.path.exists(args.output): parser.error('The output image {} already exists.'.format(args.output)) logger.debug('target voxel spacing: {}'.format(args.spacing)) # determine number of required complete slices for up-sampling vs = header.get_pixel_spacing(hdr) rcss = [int(y // x - 1) for x, y in zip(args.spacing, vs)] # TODO: For option b, remove the - 1; better: no option b, since I am rounding later anyway # remove negatives and round up to next even number rcss = [x if x > 0 else 0 for x in rcss] rcss = [x if 0 == x % 2 else x + 1 for x in rcss] logger.debug('intermediate slices to add per dimension: {}'.format(rcss)) # for each dimension requiring up-sampling, from the highest down, perform shape based slice interpolation logger.info('Adding required slices using shape based interpolation.') for dim, rcs in enumerate(rcss): if rcs > 0: logger.debug('adding {} intermediate slices to dimension {}'.format(rcs, dim)) img = shape_based_slice_interpolation(img, dim, rcs) logger.debug('resulting new image shape: {}'.format(img.shape)) # compute and set new voxel spacing nvs = [x / (y + 1.) for x, y in zip(vs, rcss)] header.set_pixel_spacing(hdr, nvs) logger.debug('intermediate voxel spacing: {}'.format(nvs)) # interpolate with nearest neighbour logger.info('Re-sampling the image with a b-spline order of {}.'.format(args.order)) img, hdr = resample(img, hdr, args.spacing, args.order, mode='nearest') # saving the resulting image save(img, args.output, hdr, args.force)
def main(): thr = float(sys.argv[3]) i, h = load(sys.argv[1]) # adapt threshold by voxel spacing thr /= numpy.prod(header.get_pixel_spacing(h)) # threshold binary objects j = size_threshold(i, thr, 'lt') # reset if last object has been removed if 0 == numpy.count_nonzero(j): j = i save(j, sys.argv[2], h, True)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input images and cast to bool images = [] for input_ in args.inputs: t = load(input_) images.append((t[0], t[1])) # check if their shapes and voxel spacings are all equal s0 = images[0][0].shape if not numpy.all(map(lambda i: i[0].shape == s0, images[1:])): raise argparse.ArgumentError(args.input, 'At least one input image is of a different shape than the others.') vs0 = header.get_pixel_spacing(images[0][1]) if not numpy.all(map(lambda i: header.get_pixel_spacing(i[1]) == vs0, images[1:])): raise argparse.ArgumentError(args.input, 'At least one input image has a different voxel spacing than the others.') # execute operation logger.debug('Executing operation {} over {} images.'.format(args.operation, len(images))) if 'max' == args.operation: out = numpy.maximum.reduce([t[0] for t in images]) elif 'min' == args.operation: out = numpy.minimum.reduce([t[0] for t in images]) elif 'sum' == args.operation: out = numpy.sum([t[0] for t in images], 0).astype(numpy.uint8) else: # avg out = numpy.average([t[0] for t in images], 0).astype(numpy.float32) # save output save(out, args.output, images[0][1], args.force) logger.info("Successfully terminated.")
def extract_basal_slice(arr, head): """ Takes a 3D array, iterates over the first dimension and returns the first 2D plane which contains any non-zero values as we as its voxel spacing. """ for plane in arr: if scipy.any(plane): # get voxel spacing spacing = list(header.get_pixel_spacing(head)) spacing = spacing[1:3] # return plane and spacing return (plane, spacing) raise ArgumentError('The supplied array does not contain any object.')
def main(): # loading the image mask m = load(sys.argv[2])[0].astype(numpy.bool) # extracting the required features and saving them for sequence, function_call, function_arguments, voxelspacing in features_to_extract: if not isfv(sys.argv[3], sequence, function_call, function_arguments): #print sequence, function_call.__name__, function_arguments i, h = load('{}/{}.nii.gz'.format(sys.argv[1], sequence)) call_arguments = list(function_arguments) if voxelspacing: call_arguments.append(header.get_pixel_spacing(h)) call_arguments.append(m) fv = function_call(i, *call_arguments) savefv(fv, sys.argv[3], sequence, function_call, function_arguments)
def zoom(image, factor, dimension, hdr=False, order=3): """ Zooms the provided image by the supplied factor in the supplied dimension. The factor is an integer determining how many slices should be put between each existing pair. If an image header (hdr) is supplied, its voxel spacing gets updated. Returns the image and the updated header or false. """ # check if supplied dimension is valid if dimension >= image.ndim: raise argparse.ArgumentError( 'The supplied zoom-dimension {} exceeds the image dimensionality of 0 to {}.' .format(dimension, image.ndim - 1)) # get logger logger = Logger.getInstance() logger.debug('Old shape = {}.'.format(image.shape)) # perform the zoom zoom = [1] * image.ndim zoom[dimension] = (image.shape[dimension] + (image.shape[dimension] - 1) * factor) / float( image.shape[dimension]) logger.debug('Reshaping with = {}.'.format(zoom)) image = interpolation.zoom(image, zoom, order=order) logger.debug('New shape = {}.'.format(image.shape)) if hdr: new_spacing = list(header.get_pixel_spacing(hdr)) new_spacing[dimension] = new_spacing[dimension] / float(factor + 1) logger.debug('Setting pixel spacing from {} to {}....'.format( header.get_pixel_spacing(hdr), new_spacing)) header.set_pixel_spacing(hdr, tuple(new_spacing)) return image, hdr
def main(): print 'lesion\tvolume (%)\tvolume (mm)' files = [f for f in os.listdir('{}'.format(sys.argv[1])) if os.path.isfile('{}/{}'.format(sys.argv[1], f))] for f in files: l, h = load('{}/{}'.format(sys.argv[1], f)) m, _ = load('{}/{}'.format(sys.argv[2], f)) lesion_voxel = numpy.count_nonzero(l) total_voxel = numpy.count_nonzero(m) volume_mm = numpy.prod(header.get_pixel_spacing(h)) * lesion_voxel volume_percentage = lesion_voxel / float(total_voxel) print '{}\t{}\t{}\t'.format(f[:-7], volume_percentage, volume_mm)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # copy the example image or generate empty image, depending on the modus if args.example: grid_image = scipy.zeros(args.example_image.shape, scipy.bool_) grid_header = args.example_header else: grid_image = scipy.zeros(args.shape, scipy.bool_) # !TODO: Find another solution for this # Saving and loading image once to generate a valid header tmp_dir = tempfile.mkdtemp() tmp_image = '{}/{}'.format(tmp_dir, args.output.split('/')[-1]) save(grid_image, tmp_image) _, grid_header = load(tmp_image) try: os.remove(tmp_image) os.rmdir(tmp_dir) except Exception: pass # set the image attributes if supplied if args.pixelspacing: header.set_pixel_spacing(grid_header, args.pixelspacing) if args.offset: header.set_offset(grid_header, args.offset) # compute the right grid spacing for each dimension if args.real: grid_spacing = [int(round(sp / float(ps))) for sp, ps in zip(args.spacing, header.get_pixel_spacing(grid_header))] else: grid_spacing = args.spacing # paint the grid into the empty image volume for dim in range(grid_image.ndim): if 0 == grid_spacing[dim]: continue # skip dimension of 0 grid spacing supplied for offset in range(0, grid_image.shape[dim], grid_spacing[dim]): slicer = [slice(None)] * grid_image.ndim slicer[dim] = slice(offset, offset + 1) grid_image[slicer] = True # saving resulting grid volume save(grid_image, args.output, grid_header, args.force)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input images data_fixed, header_fixed = load(args.fixed) data_moving, _ = load(args.moving) # get points of interest fixed_basep, fixed_otherp = get_points_of_interest(data_fixed) moving_basep, moving_otherp = get_points_of_interest(data_moving) # get voxel spacing spacing = header.get_pixel_spacing(header_fixed) # determine shift shift = (moving_basep[0] - fixed_basep[0], moving_basep[1] - fixed_basep[1]) shift = (shift[0] * spacing[0], shift[1] * spacing[1]) # determine angle angle = angle_between_lines(line_from_points(fixed_basep, fixed_otherp), line_from_points(moving_basep, moving_otherp)) # determine angle turn point turn_point = fixed_basep turn_point = (turn_point[0] * spacing[0], turn_point[1] * spacing[1]) # print results print '//angle: {}'.format(math.degrees(angle)) print transform_string(shift, angle, turn_point) # paint in the points and other stuff #data_input[tuple(fixed_basep)] = 2 #data_input[tuple(fixed_otherp)] = 3 # save image #save(data_input, args.output, header_input, args.force) logger.info("Successfully terminated.")
def main(): # loading the features to extract d, m = os.path.split(os.path.splitext(sys.argv[4])[0]) f, filename, desc = imp.find_module(m, [d]) features_to_extract = imp.load_module(m, f, filename, desc).features_to_extract # loading the image mask m = load(sys.argv[2])[0].astype(numpy.bool) # extracting the required features and saving them for sequence, function_call, function_arguments, voxelspacing in features_to_extract: if not isfv(sys.argv[3], sequence, function_call, function_arguments): #print sequence, function_call.__name__, function_arguments i, h = load('{}/{}.nii.gz'.format(sys.argv[1], sequence)) call_arguments = list(function_arguments) if voxelspacing: call_arguments.append(header.get_pixel_spacing(h)) call_arguments.append(m) fv = function_call(i, *call_arguments) savefv(fv, sys.argv[3], sequence, function_call, function_arguments)
def main(): parser = getParser() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images img, hdr = load(args.input) # check spacing values if not len(args.spacing) == img.ndim: parser.error( 'The image has {} dimensions, but {} spacing parameters have been supplied.' .format(img.ndim, len(args.spacing))) # check if output image exists if not args.force: if os.path.exists(args.output): parser.error('The output image {} already exists.'.format( args.output)) logger.debug('target voxel spacing: {}'.format(args.spacing)) # compute zoom values zoom_factors = [ old / float(new) for new, old in zip(args.spacing, header.get_pixel_spacing(hdr)) ] logger.debug('zoom-factors: {}'.format(zoom_factors)) # zoom image img = scipy.ndimage.interpolation.zoom(img, zoom_factors, order=args.order) logger.debug('new image shape: {}'.format(img.shape)) # set new voxel spacing header.set_pixel_spacing(hdr, args.spacing) # saving the resulting image save(img, args.output, hdr, args.force)
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input image data_input, header_input = load(args.input) logger.debug('Original shape = {}.'.format(data_input.shape)) # check if supplied dimension parameters is inside the images dimensions if args.dimension1 >= data_input.ndim or args.dimension1 < 0: raise ArgumentError( 'The first swap-dimension {} exceeds the number of input volume dimensions {}.' .format(args.dimension1, data_input.ndim)) elif args.dimension2 >= data_input.ndim or args.dimension2 < 0: raise ArgumentError( 'The second swap-dimension {} exceeds the number of input volume dimensions {}.' .format(args.dimension2, data_input.ndim)) # swap axes data_output = scipy.swapaxes(data_input, args.dimension1, args.dimension2) # swap pixel spacing and offset ps = list(header.get_pixel_spacing(header_input)) ps[args.dimension1], ps[args.dimension2] = ps[args.dimension2], ps[ args.dimension1] header.set_pixel_spacing(header_input, ps) os = list(header.get_offset(header_input)) os[args.dimension1], os[args.dimension2] = os[args.dimension2], os[ args.dimension1] header.set_offset(header_input, os) logger.debug('Resulting shape = {}.'.format(data_output.shape)) # save resulting volume save(data_output, args.output, header_input, args.force) logger.info("Successfully terminated.")
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input image data_input, header_input = load(args.input) # check if the supplied dimension is valid if args.dimension >= data_input.ndim or args.dimension < 0: raise ArgumentError( 'The supplied cut-dimension {} exceeds the image dimensionality of 0 to {}.' .format(args.dimension, data_input.ndim - 1)) # prepare output file string name_output = args.output.replace('{}', '{:03d}') # compute the new the voxel spacing spacing = list(header.get_pixel_spacing(header_input)) del spacing[args.dimension] # iterate over the cut dimension slices = data_input.ndim * [slice(None)] for idx in range(data_input.shape[args.dimension]): # cut the current slice from the original image slices[args.dimension] = slice(idx, idx + 1) data_output = scipy.squeeze(data_input[slices]) # update the header and set the voxel spacing __update_header_from_array_nibabel(header_input, data_output) header.set_pixel_spacing(header_input, spacing) # save current slice save(data_output, name_output.format(idx), header_input, args.force) logger.info("Successfully terminated.")
def _postprocess(src, dest, threshold): r""" Execute post-processing on a segmentation. """ # load source image img, hdr = load(src) img = img.astype(numpy.bool) # fill holes in 3D img = binary_fill_holes(img) # adapt threshold by voxel spacing threshold /= numpy.prod(header.get_pixel_spacing(hdr)) # threshold binary objects out = size_threshold(img, threshold, 'lt') # reset if last object has been removed if 0 == numpy.count_nonzero(out): out = img # fill holes in 2d out = _fill2d(out) # save save(out, dest, hdr, True)
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input image data_input, header_input = load(args.input) # check if the supplied dimension is valid if args.dimension >= data_input.ndim or args.dimension < 0: raise ArgumentError('The supplied cut-dimension {} exceeds the image dimensionality of 0 to {}.'.format(args.dimension, data_input.ndim - 1)) # prepare output file string name_output = args.output.replace('{}', '{:03d}') # compute the new the voxel spacing spacing = list(header.get_pixel_spacing(header_input)) del spacing[args.dimension] # iterate over the cut dimension slices = data_input.ndim * [slice(None)] for idx in range(data_input.shape[args.dimension]): # cut the current slice from the original image slices[args.dimension] = slice(idx, idx + 1) data_output = scipy.squeeze(data_input[slices]) # update the header and set the voxel spacing __update_header_from_array_nibabel(header_input, data_output) header.set_pixel_spacing(header_input, spacing) # save current slice save(data_output, name_output.format(idx), header_input, args.force) logger.info("Successfully terminated.")
def main(): parser = getParser() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # loading input images img, hdr = load(args.input) # check spacing values if not len(args.spacing) == img.ndim: parser.error('The image has {} dimensions, but {} spacing parameters have been supplied.'.format(img.ndim, len(args.spacing))) # check if output image exists if not args.force: if os.path.exists(args.output): parser.error('The output image {} already exists.'.format(args.output)) logger.debug('target voxel spacing: {}'.format(args.spacing)) # compute zoom values zoom_factors = [old / float(new) for new, old in zip(args.spacing, header.get_pixel_spacing(hdr))] logger.debug('zoom-factors: {}'.format(zoom_factors)) # zoom image img = scipy.ndimage.interpolation.zoom(img, zoom_factors, order=args.order) logger.debug('new image shape: {}'.format(img.shape)) # set new voxel spacing header.set_pixel_spacing(hdr, args.spacing) # saving the resulting image save(img, args.output, hdr, args.force)
def main(interest_list, train_only, proportion, save_name): if train_only == False: train_indicator = [False, True] else: train_indicator = [True] for indicator in train_indicator: isTrain = indicator if isTrain == True: datadir_to_load = '../input/submission/pred_result/train/' data_name = 'train' datadir_to_save = '../input/submission/pred_result_ensemble/train/' else: datadir_to_load = '../input/submission/pred_result/test/' data_name = 'test' datadir_to_save = '../input/submission/pred_result_ensemble/test/' if os.path.isdir(datadir_to_load) is not True: raise if os.path.isdir(datadir_to_save) is not True: os.makedirs(datadir_to_save) file_list = [] interest_model_list = list(interest_list) for model_num in interest_model_list: file_list = file_list + glob( os.path.join(datadir_to_load, '*model_{}*.nii'.format(model_num))) file_dict = dict() for file in file_list: name = str.split(file, '.')[-2] if name in file_dict.keys(): file_dict[name].append(file) else: file_dict[name] = [] file_dict[name].append(file) record = [] for name in file_dict.keys(): N = len(file_dict[name]) img_list = [] #NEED CHANGE !!! if isTrain == True: file_path = glob( '../input/train_data/*/*/*{}*'.format(name))[0] else: file_path = glob('../input/test_data/*/*/*{}*'.format(name))[0] mtt, mtt_header = load(file_path) adc_path = glob('/'.join(str.split(file_path, '/')[:4]) + '/*/*ADC*.nii')[0] _, adc_header = load(adc_path) # print('name: {}, number of images: {}'.format(name, N)) for j in xrange(N): img, img_header = load(file_dict[name][j]) if header.get_pixel_spacing( adc_header) != header.get_pixel_spacing(img_header): print("ERROR!!!!") if header.get_offset(adc_header) != header.get_offset( img_header): print("ERROR!!!!") if mtt.shape != img.shape: print("ERROR!!!!") img_list.append(img) arr = np.sum(np.array(img_list), axis=0) arr = np.array(arr > N * proportion, dtype=np.uint16) arr_name = datadir_to_save + 'VSD.yong_{}_{}.'.format( save_name, data_name) + name + '.nii' # print('proportion of GT: {}, dimension: {}'.format(np.mean(arr), arr.shape)) save(arr, arr_name, adc_header) if isTrain == True: gt_path = glob('../input/train_data/{}/*/*OT*'.format( str.split(file_path, '/')[-3]))[0] gt, gt_header = load(gt_path) f1 = 2.0 * np.sum(gt * arr) / (np.sum(gt) + np.sum(arr)) record.append(f1) if isTrain == True: record = np.array(record) print(record) print(np.mean(record)) print(np.std(record))
def __get_diagonal(h): return numpy.diag(list(header.get_pixel_spacing(h)) + [1])
# Manually segmented fake lesion for use with this example image_file = 'data/manualTest.nii.gz' image_data, image_header = load(image_file) # Provide the coordenates or calculate the bounding box of the segmentation coords2crop = [0,10,0,10,0,10] # You can do manual coordenates coords2crop = recrop.bbox_3D(image_data) # Or calculated by a boundary box print coords2crop # Crop the image using the provided coordinates croppedImage = recrop.crop_3D(image_data, coords2crop) # Print the pixel spacing print header.get_pixel_spacing(image_header) targetSpacing = 2.0 targetSpacing = [2,1,1] # Resample from croppedResampledImage, croppedResampledImage_header = recrop.resample(croppedImage, image_header,targetSpacing) save(croppedImage, image_file[0:-7]+'.bbox.nii.gz', image_header) save(croppedResampledImage, image_file[0:-7]+'.bboxResample.nii.gz', croppedResampledImage_header) print 'Original:' print croppedImage.shape print 'Resampled:'
def main(): # parse cmd arguments parser = getParser() parser.parse_args() args = getArguments(parser) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # check if output image exists if not args.force: if os.path.exists(args.output): logger.warning('The output image {} already exists. Exiting.'.format(args.output)) exit(-1) # select boundary term ['diff_linear', 'diff_exp', 'diff_div', 'diff_pow', 'max_linear', 'max_exp', 'max_div', 'max_pow'] if 'diff_linear' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_difference_linear logger.info('Selected boundary term: linear difference of intensities') elif 'diff_exp' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_difference_exponential logger.info('Selected boundary term: exponential difference of intensities') elif 'diff_div' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_difference_division logger.info('Selected boundary term: divided difference of intensities') elif 'diff_pow' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_difference_power logger.info('Selected boundary term: power based / raised difference of intensities') elif 'max_linear' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_maximum_linear logger.info('Selected boundary term: linear maximum of intensities') elif 'max_exp' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_maximum_exponential logger.info('Selected boundary term: exponential maximum of intensities') elif 'max_div' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_maximum_division logger.info('Selected boundary term: divided maximum of intensities') elif 'max_pow' == args.boundary: boundary_term = graphcut.energy_voxel.boundary_maximum_power logger.info('Selected boundary term: power based / raised maximum of intensities') # load input images badditional_image_data, reference_header = load(args.badditional) markers_image_data, _ = load(args.markers) # split marker image into fg and bg images fgmarkers_image_data, bgmarkers_image_data = split_marker(markers_image_data) # check if all images dimensions are the same if not (badditional_image_data.shape == fgmarkers_image_data.shape == bgmarkers_image_data.shape): logger.critical('Not all of the supplied images are of the same shape.') raise ArgumentError('Not all of the supplied images are of the same shape.') # extract spacing if required if args.spacing: spacing = header.get_pixel_spacing(reference_header) logger.info('Taking spacing of {} into account.'.format(spacing)) else: spacing = False # generate graph logger.info('Preparing BK_MFMC C++ graph...') gcgraph = graphcut.graph_from_voxels(fgmarkers_image_data, bgmarkers_image_data, boundary_term = boundary_term, boundary_term_args = (badditional_image_data, args.sigma, spacing)) # execute min-cut logger.info('Executing min-cut...') maxflow = gcgraph.maxflow() logger.debug('Maxflow is {}'.format(maxflow)) # reshape results to form a valid mask logger.info('Applying results...') result_image_data = scipy.zeros(bgmarkers_image_data.size, dtype=scipy.bool_) for idx in range(len(result_image_data)): result_image_data[idx] = 0 if gcgraph.termtype.SINK == gcgraph.what_segment(idx) else 1 result_image_data = result_image_data.reshape(bgmarkers_image_data.shape) # save resulting mask save(result_image_data.astype(scipy.bool_), args.output, reference_header, args.force) logger.info('Successfully terminated.')
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input images data_fixed, header_fixed = load(args.fixed) data_moving, header_moving = load(args.moving) # convert to binary arrays data_fixed = data_fixed.astype(scipy.bool_) data_moving = data_moving.astype(scipy.bool_) # check that they are 3D volumes and contain an object if not 3 == data_fixed.ndim: raise ArgumentError( 'The fixed image has {} instead of the expected 3 dimensions.'. format(data_fixed.ndim)) if not 3 == data_moving.ndim: raise ArgumentError( 'The moving image has {} instead of the expected 3 dimensions.'. format(data_moving.ndim)) if not scipy.any(data_fixed): raise ArgumentError('The fixed image contains no binary object.') if not scipy.any(data_moving): raise ArgumentError('The moving image contains no binary object.') # get voxel spacing of fixed image fixed_spacing = header.get_pixel_spacing(header_fixed) # extract the first basal slices form both RV objects basal_fixed, basal_fixed_spacing = extract_basal_slice( data_fixed, header_fixed) basal_moving, basal_moving_spacing = extract_basal_slice( data_moving, header_moving) logger.debug( 'Extracted basal slices fixed: {} and moving: {} with voxel spacing {} resp. {}.' .format(basal_fixed.shape, basal_moving.shape, basal_fixed_spacing, basal_moving_spacing)) # get points of interest fixed_basep, fixed_otherp = get_points_of_interest(basal_fixed) moving_basep, moving_otherp = get_points_of_interest(basal_moving) logger.debug( 'Points of interest found are fixed: {} / {} and moving: {} / {}.'. format(fixed_basep, fixed_otherp, moving_basep, moving_otherp)) # translate all points of interest to physical coordinate system fixed_basep = [x * y for x, y in zip(fixed_basep, basal_fixed_spacing)] fixed_otherp = [x * y for x, y in zip(fixed_otherp, basal_fixed_spacing)] moving_basep = [x * y for x, y in zip(moving_basep, basal_moving_spacing)] moving_otherp = [ x * y for x, y in zip(moving_otherp, basal_moving_spacing) ] logger.debug( 'Points of interest translated to real-world coordinates are fixed: {} / {} and moving: {} / {}.' .format(fixed_basep, fixed_otherp, moving_basep, moving_otherp)) # determine shift to unite the two base-points shift = (fixed_basep[0] - moving_basep[0], fixed_basep[1] - moving_basep[1]) logger.debug('Shift to unite base-point is {}.'.format(shift)) # shift the vector end-point of the moving object's vector so that it shares the # same base as the fixed vector moving_otherp = shiftp(moving_otherp, shift) logger.debug('Shifted vector end-point of moving image is {}.'.format( moving_otherp)) # assure correctness of shift if not scipy.all( [x == y for x, y in zip(fixed_basep, shiftp(moving_basep, shift))]): raise ArgumentError( 'Aligning base-point through shifting failed due to unknown reason: {} does not equal {}.' .format(shiftp(moving_basep, shift), fixed_basep)) # shift both vector end-points to origin base fixed_otherp = shiftp(fixed_otherp, map(lambda x: -1. * x, fixed_basep)) moving_otherp = shiftp(moving_otherp, map(lambda x: -1. * x, fixed_basep)) # determine angle angle = angle_between_vectors(fixed_otherp, moving_otherp) logger.debug('Angle set to {} degree in radians.'.format( math.degrees(angle))) # determine angle turn point turn_point = fixed_basep logger.debug( 'Turn point set to {} in real-world coordinates.'.format(turn_point)) # reverse shift to fit into the 'elastix' view shift = [-1. * x for x in shift] # print results print '// {}'.format(math.degrees(angle)) print """ //# SOME NOTES ON 'ELASTIX' //# 1. 'elastix' performs shifting before rotation! //# 2. 'elastix' works on the real world coordinates (i.e. with voxel spacing of 0) """ print transform_string(data_fixed.shape, fixed_spacing, [0] + list(shift), [angle, 0, 0], [0] + list(turn_point)) logger.info("Successfully terminated.")
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # load input images data_fixed, header_fixed = load(args.fixed) data_moving, header_moving = load(args.moving) # convert to binary arrays data_fixed = data_fixed.astype(scipy.bool_) data_moving = data_moving.astype(scipy.bool_) # check that they are 3D volumes and contain an object if not 3 == data_fixed.ndim: raise ArgumentError('The fixed image has {} instead of the expected 3 dimensions.'.format(data_fixed.ndim)) if not 3 == data_moving.ndim: raise ArgumentError('The moving image has {} instead of the expected 3 dimensions.'.format(data_moving.ndim)) if not scipy.any(data_fixed): raise ArgumentError('The fixed image contains no binary object.') if not scipy.any(data_moving): raise ArgumentError('The moving image contains no binary object.') # get voxel spacing of fixed image fixed_spacing = header.get_pixel_spacing(header_fixed) # extract the first basal slices form both RV objects basal_fixed, basal_fixed_spacing = extract_basal_slice(data_fixed, header_fixed) basal_moving, basal_moving_spacing = extract_basal_slice(data_moving, header_moving) logger.debug('Extracted basal slices fixed: {} and moving: {} with voxel spacing {} resp. {}.'.format(basal_fixed.shape, basal_moving.shape, basal_fixed_spacing, basal_moving_spacing)) # get points of interest fixed_basep, fixed_otherp = get_points_of_interest(basal_fixed) moving_basep, moving_otherp = get_points_of_interest(basal_moving) logger.debug('Points of interest found are fixed: {} / {} and moving: {} / {}.'.format(fixed_basep, fixed_otherp, moving_basep, moving_otherp)) # translate all points of interest to physical coordinate system fixed_basep = [x * y for x, y in zip(fixed_basep, basal_fixed_spacing)] fixed_otherp = [x * y for x, y in zip(fixed_otherp, basal_fixed_spacing)] moving_basep = [x * y for x, y in zip(moving_basep, basal_moving_spacing)] moving_otherp = [x * y for x, y in zip(moving_otherp, basal_moving_spacing)] logger.debug('Points of interest translated to real-world coordinates are fixed: {} / {} and moving: {} / {}.'.format(fixed_basep, fixed_otherp, moving_basep, moving_otherp)) # determine shift to unite the two base-points shift = (fixed_basep[0] - moving_basep[0], fixed_basep[1] - moving_basep[1]) logger.debug('Shift to unite base-point is {}.'.format(shift)) # shift the vector end-point of the moving object's vector so that it shares the # same base as the fixed vector moving_otherp = shiftp(moving_otherp, shift) logger.debug('Shifted vector end-point of moving image is {}.'.format(moving_otherp)) # assure correctness of shift if not scipy.all([x == y for x, y in zip(fixed_basep, shiftp(moving_basep, shift))]): raise ArgumentError('Aligning base-point through shifting failed due to unknown reason: {} does not equal {}.'.format(shiftp(moving_basep, shift), fixed_basep)) # shift both vector end-points to origin base fixed_otherp = shiftp(fixed_otherp, map(lambda x: -1. * x, fixed_basep)) moving_otherp = shiftp(moving_otherp, map(lambda x: -1. * x, fixed_basep)) # determine angle angle = angle_between_vectors(fixed_otherp, moving_otherp) logger.debug('Angle set to {} degree in radians.'.format(math.degrees(angle))) # determine angle turn point turn_point = fixed_basep logger.debug('Turn point set to {} in real-world coordinates.'.format(turn_point)) # reverse shift to fit into the 'elastix' view shift = [-1. * x for x in shift] # print results print '// {}'.format(math.degrees(angle)) print """ //# SOME NOTES ON 'ELASTIX' //# 1. 'elastix' performs shifting before rotation! //# 2. 'elastix' works on the real world coordinates (i.e. with voxel spacing of 0) """ print transform_string(data_fixed.shape, fixed_spacing, [0] + list(shift), [angle, 0, 0], [0] + list(turn_point)) logger.info("Successfully terminated.")
def main(): args = getArguments(getParser()) # prepare logger logger = Logger.getInstance() if args.debug: logger.setLevel(logging.DEBUG) elif args.verbose: logger.setLevel(logging.INFO) # constants dimension_spatial = 0 dimension_temporal = 3 name_output_data = '{}/{}_d{:01d}_s{:04d}.nii' # basename / slice-dimension / slice-number name_output_marker = '{}/m{}_d{:01d}_s{:04d}.nii' # basename / slice-dimension / slice-number # load input image input_data, input_header = load(args.input) # determine type of extraction and eventuelly load contour file if args.paintc or args.type in ['es']: contour_data, _ = load(args.contour) # select dimension and set variable parameter if args.type in ['ed', 'es', 'spatial']: cut_dimension = dimension_temporal else: cut_dimension = dimension_spatial basename = '.'.join(os.path.basename(args.input).split('.')[:-1]) # adjust voxel spacing voxel_spacing = list(header.get_pixel_spacing(input_header)) del voxel_spacing[cut_dimension] voxel_spacing += [0] header.set_pixel_spacing(input_header, voxel_spacing) # split and save images first = True slices = input_data.ndim * [slice(None)] for idx in range(input_data.shape[cut_dimension]): slices[cut_dimension] = slice(idx, idx + 1) # skip if output image already exists if not args.force and os.path.exists(name_output_data.format(args.output, basename, cut_dimension, idx)): logger.warning('The output image {} already exists, skipping this step.'.format(name_output_data.format(args.output, basename, cut_dimension, idx))) continue elif not args.force and os.path.exists(name_output_marker.format(args.output, basename, cut_dimension, idx)): logger.warning('The output marker image {} already exists, skipping this step.'.format(name_output_marker.format(args.output, basename, cut_dimension, idx))) continue # extract original sub-volume data_output = scipy.squeeze(input_data[slices]) # create same-sized empty volume as marker base data_marker = scipy.zeros(data_output.shape, scipy.uint8) # extract also contour sub-volume if required if args.paintc: data_marker += scipy.squeeze(contour_data[slices]) # check if contour data is empty in ed and es case; if yes, skip this volume if args.type in ['es'] and 0 == len(scipy.squeeze(contour_data[slices]).nonzero()[0]): continue # check if first volume in case of type = es, then skip if 'es' == args.type and first: first = False continue # save data and marker sub-volumes save(data_output, name_output_data.format(args.output, basename, cut_dimension, idx), input_header, args.force) save(data_marker, name_output_marker.format(args.output, basename, cut_dimension, idx), input_header, args.force) # in case of type = ed, break after first if 'ed' == args.type: break logger.info("Successfully terminated.")