示例#1
0
def _parallel_mask(args):
    source, sink, idxs, threshold, min_size = args

    source = io.readData(source)
    sink = io.readData(sink)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

    for i in idxs:
        print(f'Mask slice {i}')
        # mask image
        if threshold:
            _, img = cv2.threshold(source[..., i], threshold, 255,
                                   cv2.THRESH_BINARY)
            # extract only brain mask
            nlabels, labels, stats, centroid = cv2.connectedComponentsWithStats(
                img.astype(np.uint8))
            sample_labels = np.where(
                stats[1:, ..., 4] > min_size)[0] + 1  # get largest shapes
            img = np.isin(labels, sample_labels).astype(np.uint8)
        else:
            img = np.array(source[..., i]).copy()
        # remove holes in brain mask
        contours, hier = cv2.findContours(img, cv2.RETR_LIST,
                                          cv2.CHAIN_APPROX_SIMPLE)
        contours.sort(key=len)
        # keep biggest contours
        img = np.zeros(img.shape)
        for c in contours[-5:]:
            img = cv2.drawContours(img, [c], 0, 255, -1)
        img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
        sink[..., i] = img.astype(np.uint8)
示例#2
0
def label_props(img, labels, props):
    """Joins a list of coordiantes from distributed processing based on their IDs into a single list.
        Also. Handles duplicate ID entries bbased on
    Arguments:
        img (np.array): raw image
        labels (np.array): labeled image
        props (list): list of strings where each string is the attibute from region_props to export
    Returns:
       array: label coordinates (list of tuples), intensities (list), sizes (list)
    """

    img = io.readData(img)
    labels = io.readData(labels)

    timer = Timer()
    log_parameters(props=props)

    # get label properties
    regions = region_props(labels, img)

    # get relavant properties
    res = []
    for prop in props:
        prop_res = []
        for region in regions:
            method = getattr(region, prop)
            prop_res.append(method())
        res.append(prop_res)

    timer.log_elapsed()

    return res
示例#3
0
def erode(mask, sink, offset_z, offset_x, processes=1):
    # offset surface in z

    mask = io.readData(mask)
    sink = io.readData(sink)

    z_idxs = list(range(mask.shape[-1]))
    z_chunks = [z_idxs[i::processes] for i in range(processes)]
    z_args = [(mask.filename, sink.filename, z_idxs, offset_x)
              for z_idxs in z_chunks]

    x_idxs = list(range(mask.shape[0]))
    x_chunks = [x_idxs[i::processes] for i in range(processes)]
    x_args = [(sink.filename, sink.filename, x_idxs, offset_z)
              for x_idxs in x_chunks]

    if processes == 1:
        _parallel_erode_z(*z_args)
        _parallel_erode_x(*x_args)
    else:
        pool = Pool(processes)
        pool.map(_parallel_erode_z, z_args)
        pool.map(_parallel_erode_x, x_args)
        pool.close()

    return sink
示例#4
0
def copyData(source, sink, x=None, y=None, z=None, returnMemmap=False):
    """Copy a data file from source to sink
    
    Arguments:
        source (str): file name pattern of source
        sink (str): file name pattern of sink
        returnMemmap (bool): returns the result as an array
    Returns:
        str: file name of the copy
    """
    out_type = io.dataFileNameToType(sink)
    if out_type == 'TIF':
        if isinstance(source, np.memmap) and x == y == y == z == None:
            shutil.copyfile(source.filename, sink)
        else:
            Xsize, Ysize, Zsize = io.dataSize(source)
            # cropped size
            Xsize = io.toDataSize(Xsize, r=x)
            Ysize = io.toDataSize(Ysize, r=y)
            Zsize = io.toDataSize(Zsize, r=z)
            im = io.readData(source, x=x, y=y, z=z)
            out = io.writeData(sink, im, returnMemmap=returnMemmap)

        if returnMemmap:
            return io.readData(sink)
        else:
            return sink
    else:
        raise RuntimeError(
            'copying from TIF to {} not yet supported.'.format(out_type))
示例#5
0
def transformImage(image,
                   reference,
                   transformDirectory,
                   sink=None,
                   invert=False,
                   interpolation='bspline'):
    """Transform a raw data set to reference using the ANTs alignment results

    Arguments:
        source (str or array): image source to be transformed
        reference (str or array): fixed image from transform
        transformDirectory (str): Directory containing ANTS transform parameters
        sink (str or None): image sink to save transformed image to.
        interpolation (str): ANTS interpolator to use for generating image.

    Returns:
        array or str: file name of the transformed data. If sink is None, return array
    """

    log.info('transforming image with ' + transformDirectory)
    log.info('invert: {}'.format(invert))

    # get image and tranform
    im = ants.from_numpy(io.readData(image).astype('float32'))
    ref = ants.from_numpy(io.readData(reference).astype('float32'))
    composite_trans = _compose_transforms(transformDirectory, invert=invert)
    # apply transforms
    res = composite_trans.apply_to_image(im, ref, interpolation=interpolation)
    # output
    if isinstance(sink, str):
        return io.writeData(sink, res.numpy())
    else:
        return res.numpy()
示例#6
0
def readDataFiles(filename, x=None, y=None, z=None, **args):
    """Read data from individual images assuming they are the z slices

    Arguments:
        filename (str): file name as regular expression
        x,y,z (tuple): data range specifications
    
    Returns:
        array: image data
    """

    fpath, fl = readFileList(filename)
    nz = len(fl)

    #read first image to get data size and type
    rz = io.toDataRange(nz, r=z)
    sz = io.toDataSize(nz, r=z)
    fn = os.path.join(fpath, fl[rz[0]])
    img = io.readData(fn, x=x, y=y)
    nxy = img.shape
    data = numpy.zeros(nxy + (sz, ), dtype=img.dtype)
    data[:, :, 0] = img

    for i in range(rz[0] + 1, rz[1]):
        fn = os.path.join(fpath, fl[i])
        data[:, :, i - rz[0]] = io.readData(fn, x=x, y=y)

    return data
示例#7
0
def overlay_label(dataSource,
                  labelSource,
                  output=None,
                  alpha=False,
                  labelColorMap='jet',
                  x=all,
                  y=all,
                  z=all):
    """Overlay a gray scale image with colored labeled image
    
    Arguments:
        dataSouce (str or array): volumetric image data
        labelSource (str or array): labeled image to be overlayed on the image data
        output (str or None): destination for the overlayed image
        alpha (float or False): transparency
        labelColorMap (str or object): color map for the labels
        x, y, z (all or tuple): sub-range specification
    
    Returns:
        (array or str): figure handle
        
    See Also:
        :func:`overlayPoints`
    """

    label = io.readData(labelSource, x=x, y=y, z=z)
    image = io.readData(dataSource, x=x, y=y, z=z)

    lmax = label.max()
    if lmax <= 1:
        carray = numpy.array([[1, 0, 0, 1]])
    else:
        cm = mpl.cm.get_cmap(labelColorMap)
        cNorm = mpl.colors.Normalize(vmin=1, vmax=int(lmax))
        carray = mpl.cm.ScalarMappable(norm=cNorm, cmap=cm)
        carray = carray.to_rgba(numpy.arange(1, int(lmax + 1)))

    if not alpha:
        carray = numpy.concatenate(([[0, 0, 0, 1]], carray), axis=0)
    else:
        carray = numpy.concatenate(([[1, 1, 1, 1]], carray), axis=0)

    cm = mpl.colors.ListedColormap(carray)
    carray = cm(label)
    carray = carray.take([0, 1, 2], axis=-1)

    if not alpha:
        cimage = (label == 0) * image
        cimage = numpy.repeat(cimage, 3)
        cimage = cimage.reshape(image.shape + (3, ))
        cimage = cimage.astype(carray.dtype)
        cimage += carray
    else:
        cimage = numpy.repeat(image, 3)
        cimage = cimage.reshape(image.shape + (3, ))
        cimage = cimage.astype(carray.dtype)
        cimage *= carray

    return io.writeData(output, cimage)
示例#8
0
    def _generate_output(self):

        mask_f = self.temp_dir / 'mask.tif'
        erode_f = self.temp_dir / 'erode.tif'

        self.log.info('preparing temp files')
        tif.tifffile.memmap(mask_f,
                            dtype=np.uint8,
                            shape=self.input.T.shape,
                            bigtiff=True)
        tif.tifffile.memmap(erode_f,
                            dtype=np.uint8,
                            shape=self.input.T.shape,
                            bigtiff=True)

        mask = io.readData(mask_f)
        erode_im = io.readData(erode_f)

        # extract brain mask
        z_idxs = list(range(mask.shape[-1]))
        z_chunks = [z_idxs[i::self.processes] for i in range(self.processes)]
        args = [(self.input.filename, mask.filename, z_idxs, self.threshold,
                 self.min_size) for z_idxs in z_chunks]
        if self.processes == 1:
            _parallel_mask(*args)
        else:
            pool = Pool(self.processes)
            pool.map(_parallel_mask, args)
            pool.close()

        erode(mask.filename,
              erode_im.filename,
              self.offset_z,
              self.offset_x,
              processes=self.processes)

        # merge erosions and mask
        args = [(mask.filename, erode_im.filename, z_idxs)
                for z_idxs in z_chunks]
        if self.processes == 1:
            _parallel_merge_mask(*args)
        else:
            pool = Pool(self.processes)
            pool.map(_parallel_merge_mask, args)
            pool.close()

        if self.save_mask:
            self.log.info(f'saving mask to {self.save_mask}')
            io.writeData(self.save_mask, mask)

        # mask input
        # not working
        self.log.info(f'masking image')
        for z in range(self.input.shape[2]):
            im = self.input[:, :, z]
            im[mask[:, :, z] == 0] = 0
            self.input[:, :, z] = im

        return self.input
示例#9
0
def _parallel_merge_mask(args):
    mask, erosion, idxs = args

    bkg_mask = io.readData(mask)
    erosion = io.readData(erosion)

    for z in idxs:
        print(f'Generating output for slice {z}')
        merge = np.full(bkg_mask.shape[:2], 255, dtype=np.uint8)
        merge[bkg_mask[:, :, z] == 0] = 0
        merge[erosion[:, :, z] != 0] = 0
        bkg_mask[:, :, z] = merge
示例#10
0
def _parallel_erode_x(args):

    source, sink, idxs, offset = args

    source = io.readData(source)
    sink = io.readData(sink)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

    for i in idxs:
        print(f'Erode slice {i} along x')
        img = source[i].astype(np.uint8)
        sink[i] = cv2.erode(img, kernel, iterations=offset)
示例#11
0
def alignData(fixedImage,
              movingImage,
              resultDirectory=None,
              type_of_transform='SyNRA',
              **kwargs):
    """Align images using elastix, estimates a transformation :math:`T:` fixed image :math:`\\rightarrow` moving image.

    Arguments:
        fixedImage (str): image source of the fixed image (typically the reference image)
        movingImage (str): image source of the moving image (typically the image to be registered)
        resultDirectory (str or None): result directory for transform parameters. None saves to bq3ddefault temp file
        transform: (str): type of transform to apply as defined in 'ants.registration' type_of_transform
        **kwargs: additional arguments to pass to 'ants.registration'

    Returns:
        str: path to elastix result directory
    """

    log_parameters(fixedImage=fixedImage,
                   movingImage=movingImage,
                   resultDirectory=resultDirectory,
                   type_of_transform=type_of_transform)

    # setup input
    mi = ants.from_numpy(io.readData(movingImage).astype('float32'))
    fi = ants.from_numpy(io.readData(fixedImage).astype('float32'))

    # setup output directory
    if not resultDirectory:
        tmp_folder = os.path.join(config.temp_dir, 'ANTs')
        resultDirectory = tmp_folder
    resultDirectory = resultDirectory + '/' if not resultDirectory.endswith(
        '/') else resultDirectory  #make sure ends with '/'
    os.makedirs(resultDirectory, exist_ok=True)

    # run
    result = ants.registration(fi,
                               mi,
                               type_of_transform=type_of_transform,
                               outprefix=resultDirectory,
                               verbose=True,
                               **kwargs)

    # save output
    io.writeData(os.path.join(resultDirectory, 'result.tif'),
                 result['warpedmovout'].numpy())

    # cleanup#
    if not resultDirectory:
        shutil.rmtree(tmp_folder)

    return resultDirectory
示例#12
0
def grays_to_rand_rgb(source, output):

    ftype = io.dataFileNameToType(source)

    if ftype == 'TIF':

        log.info(f'Generating random RGB imgage for {ftype}')
        data = io.readData(source).astype(int)
        max_label = int(np.max(data))
        # create lut
        lut_r = np.array(random.sample(list(range(0, max_label)), max_label))
        lut_g = np.array(random.sample(list(range(0, max_label)), max_label))
        lut_b = np.array(random.sample(list(range(0, max_label)), max_label))
        # downsample to 8bit
        lut_r = ((255 / max_label) * lut_r).astype(int)
        lut_g = ((255 / max_label) * lut_g).astype(int)
        lut_b = ((255 / max_label) * lut_b).astype(int)
        # add 0 value
        lut_r = np.insert(lut_r, 0, 0)
        lut_g = np.insert(lut_g, 0, 0)
        lut_b = np.insert(lut_b, 0, 0)

        rgb_output = np.zeros(data.shape + (3, ), dtype='uint8')
        rgb_output[..., 0] = lut_r[data]
        rgb_output[..., 1] = lut_g[data]
        rgb_output[..., 2] = lut_b[data]

        io.writeData(output, rgb_output, rgb=True)

    else:
        raise RuntimeError(
            f'Conversion to random RGB not supported for {ftype}')

    return output
示例#13
0
def labels_to_coords(label_im: np.array):
    """ Converts each label in an image to a set of coordinates

    Args:
        label_im (np.array): labeled image

    Returns:
        (dict) dict of coordinated in format { 'label_id': [[x,y,z],...] }
    """
    im = io.readData(label_im)

    region_coords = {}
    for z in range(im.shape[2]):
        print(z)
        regions = regionprops(im[..., z])
        for reg in regions:
            coord = list(np.insert(reg.coords(), 2, z, 1))

            if reg.label in region_coords:
                region_coords[reg.label].extend(coord)
            else:
                region_coords[reg.label] = coord

    for id in region_coords:
        region_coords[id] = np.array(region_coords[id])

    return region_coords
示例#14
0
def resampleXY(source,
               dataSizeSink,
               zList=[0],
               sink=None,
               interpolation='linear'):
    """Resample an image stack along the a 2d slice
    This routine is used for resampling a large stack in parallel in xy or xz direction.

    Arguments:
        source (str or array): 2d image source
        dataSizeSink (tuple): size of the resmapled image
        zList (int): z planes to crop
        sink (str or None): location for the resmapled image
        interpolation (int): CV2 interpolation method to use

    Returns:
        array or str: resampled data or file name

    """

    for i in zList:
        data = io.readData(source, z=i)
        log.verbose(
            f'resample XY: Resampling plane {i} to size: ({dataSizeSink[0]}, '
            f'{dataSizeSink[1]})')
        # note: cv2.resize reverses x-Y axes
        sink[i] = cv2.resize(data, (dataSizeSink[2], dataSizeSink[1]),
                             interpolation=interpolation)

    return sink
示例#15
0
    def _populate_region_coordiantes(self, labels):
        """ adds coordinate info to regions under region.voxels. Will also generate self.volume.

        Arguments:
            labels (array or str): labeled image with values corresponding to region id
        """
        image = io.readData(labels, returnMemmap = False).astype(int) # to facilitate pooling and speed up
        log.verbose(f'calculating region info from {labels}')
        properties = region_props(image)

        # add voxels
        for i,prop in enumerate(properties):
            log.verbose(f'retrieving coordinates and densities for region {i}')
            region = self.get_region_by_id(prop.label)
            region.volume = int(prop.area())
            for c in prop.coords():
                c = tuple(c)
                region.add_voxel(c)
                self.regions_by_coord[c] = region

        # label value 0 is ignored by region_props
        self.get_region_by_id(0).add_volume(int(np.sum(image == 0)))

        if self.COLLAPSE:
            for region in PostOrderIter(self.tree_root):
                region.collapse_volume()
示例#16
0
def getDataType(filename):
    """gets dtype of data in file

    Arguments:
        filename (str): file name

    Returns:
        dtype: data type
    """
    return io.readData(filename).dtype
示例#17
0
def writePoints(filename, points, labelImage = None):
    """Write point data to vtk file
    
    Arguments:
        filename (str): file name
        points (array): point data
        labelImage (str, array or None): optional label image to determine point label
    
    Returns:
        str: file name
    """

    x = points[:,0]
    y = points[:,1]
    z = points[:,2]
    nPoint = x.size
    
    pointLabels = numpy.ones(nPoint)
    if not labelImage is None:
        if isinstance(labelImage, str):
            labelImage = io.readData(labelImage)

        dsize = labelImage.shape
        for i in range(nPoint):
            if 0 <= x[i] < dsize[0] and 0 <= y[i] < dsize[1] and 0 <= z[i] < dsize[2]:
                 pointLabels[i] = labelImage[x[i], y[i], z[i]]

    #write VTK file
    vtkFile = file(filename, 'w')
    vtkFile.write('# vtk DataFile Version 2.0\n')
    vtkFile.write('Unstructured Grid Example\n')
    vtkFile.write('ASCII\n')
    vtkFile.write('DATASET UNSTRUCTURED_GRID\n')
    vtkFile.write("POINTS " + str(nPoint) + " float\n")
    for iPoint in range(nPoint):
        vtkFile.write(str(x[iPoint]).format('%05.20f') + " " +  str(y[iPoint]).format('%05.20f') + " " + str(z[iPoint]).format('%05.20f') + "\n")

    vtkFile.write("CELLS " + str(nPoint) + " " + str(nPoint * 2) + "\n")

    for iPoint in range(nPoint):
        vtkFile.write("1 " + str(iPoint) + "\n")
    vtkFile.write("CELL_TYPES " + str(nPoint) + "\n")
    for iPoint in range(0, nPoint):
        vtkFile.write("1 \n")
    vtkFile.write("POINT_DATA " + str(nPoint) + "\n")
    vtkFile.write('SCALARS scalars float 1\n')
    vtkFile.write("LOOKUP_TABLE default\n")
    for iLabel in pointLabels:
        vtkFile.write(str(int(iLabel)) + " ")
    vtkFile.write("\n")
    vtkFile.close()

    return filename
示例#18
0
def _parallelCopyToTif(args):
    """copies FileList to Tif in parallel"""
    sources, idxs, sink, Xrng, Yrng = args
    output = io.readData(sink)

    for i, idx in enumerate(idxs):
        file = sources[i]
        log.debug(f'copyData: copying {file} to {sink}')
        im = tif.imread(file)
        if not Xrng == Yrng == None:
            output[idx] = io.dataToRange(im, x=Xrng, y=Yrng)
        else:
            output[idx] = im
示例#19
0
def readData(filename, **args):
    """Read image stack from single or multiple images
    
    Arguments:
        filename (str): file name as regular expression
        x,y,z (tuple): data range specifications
    
    Returns:
        array: image data
    """

    if os.path.exists(filename):
        return io.readData(filename, **args)
    else:
        return readDataFiles(filename, **args)
示例#20
0
def _resampleXYParallel(arg):
    """Resampling helper function to use for parallel resampling of image slices"""

    fileSource = arg[0]
    fileSink = arg[1]
    dataSizeSink = arg[2]
    interpolation = arg[3]
    zChunks = arg[4]

    sink = io.readData(fileSink)
    resampleXY(fileSource,
               zList=zChunks,
               sink=sink,
               dataSizeSink=dataSizeSink,
               interpolation=interpolation)
示例#21
0
def readDataGroup(filenames, combine=True, **args):
    """Turn a list of filenames for data into a np stack"""

    # check if stack already an array
    if isinstance(filenames, np.ndarray):
        return filenames

    #read the individual files
    group = []
    for f in filenames:
        data = io.readData(f, **args)
        data = np.reshape(data, (1, ) + data.shape)
        group.append(data)

    if combine:
        return np.vstack(group)
    else:
        return group
示例#22
0
def readData(filename, **args):
    """Read nrrd file image data
    
    Arguments:
        filename (str): file name as regular expression
        x,y,z (tuple): data range specifications
    
    Returns:
        array: image data
    """

    with open(filename,'rb') as filehandle:
        header = readHeader(filehandle)
        data = _read_data(header, filehandle, filename)
        #return (data, header)
        #return data.transpose([1,0,2])
        data = io.readData(data, **args)
        return data
示例#23
0
def filter_image(filter, input, output=None, temp_dir_root=None, **kwargs):
    """ Passes an image through the specified image filter.

    Arguments:
        filter (str): filter to use. string should match filter class name.
        source (str or array): Image to filter
        kwargs (dict): additional arguments to pass to the filter as 'argument': value. These will be parsed into
            the filters attributes. key string must match a filters attribute name.
    Returns:
        (array): filtered image
    """

    input = io.readData(input)
    kwargs['input'] = input
    kwargs['output'] = input
    im_filter = set_filter(filter, kwargs)
    if temp_dir_root:
        im_filter.set_temp_dir(root=temp_dir_root)
    return im_filter.run()
示例#24
0
def deformationDistance(deformationField, sink=None, scale=None):
    """Compute the distance field from a deformation vector field

    Arguments:
        deformationField (str or array): source of the deformation field determined by :func:`deformationField`
        sink (str or None): image sink to save the deformation field to
        scale (tuple or None): scale factor for each dimension, if None = (1,1,1)

    Returns:
        array or str: array or file name of the transformed data
    """

    deformationField = io.readData(deformationField)

    df = np.square(deformationField)
    if not scale is None:
        for i in range(3):
            df[:, :, :, i] = df[:, :, :, i] * (scale[i] * scale[i])

    return io.writeData(sink, np.sqrt(np.sum(df, axis=3)))
示例#25
0
    def _generate_output(self):

        if self.background is None:
            raise RuntimeError('background not defined')
        else:
            self.background = io.readData(self.background)

        if self.shift_z != 0:
            shifted = tif.writeData(self.temp_dir / f'{uuid.uuid4()}.tif',
                                    self.background,
                                    returnMemmap=True)

            for z in range(self.background.shape[0]):
                try:
                    shifted[z + self.shift_z, ] = self.background[z]
                except:
                    continue  # if out of bounds
            self.background = shifted

        img = self.input

        orig_shape = img.shape
        if len(orig_shape) < 3:
            img = img[np.newaxis, ...]

        if self.method == 'mean':
            img_mean = img.mean()
            bkg_mean = self.background.mean()
            ratio = img_mean / bkg_mean
            for z in range(img.shape[0]):
                bkg = (self.background[z] * ratio).astype(img.dtype)
                sub = img[z].astype(np.int32) - bkg
                sub[sub < 0] = 0
                img[z] = sub
        else:
            raise ValueError(f'Method {self.method} not recongnized')

        img.shape = orig_shape

        return self.input
示例#26
0
    def _generate_output(self):
        # extract brain mask
        method = self.method.lower()
        if self.mask:
            mask = io.readData(self.mask)

        if method == 'max':
            sink = np.zeros(self.input.shape[1:], dtype=self.input.dtype)
            if self.mask:
                for z in range(self.input.shape[0]):
                    slice  = np.array(self.input[z])
                    mask_s = np.array(mask[z])
                    slice[mask_s == 0] = 0

                    sink = cv2.max(sink, slice)
            else:
                for z in range(self.input.shape[0]):
                    sink = cv2.max(sink, self.input[z])

            return sink

        if method == 'min':
            max_v = np.iinfo(self.input.dtype).max
            sink = np.full(self.input.shape[1:], max_v, dtype=self.input.dtype)
            if self.mask:
                for z in range(self.input.shape[0]):
                    slice  = np.array(self.input[z])
                    mask_s = np.array(mask[z])

                    slice[mask_s == 0] = max_v

                    sink = cv2.min(sink, slice)
            else:
                for z in range(self.input.shape[0]):
                    sink = cv2.min(sink, self.input[z])
                sink = sink

            sink[sink == max_v] = 0
            return sink
示例#27
0
    def _generate_output(self):

        self._initialize_Ilastik()

        # create temp npy
        input_fn = str((self.temp_dir /
                        Path(self.input.filename).stem).with_suffix('.npy'))
        io.writeData(input_fn, self.input)
        output_fn = str(self.temp_dir / 'out_prelim.npy')

        ilinp = self._filename_to_input_arg(input_fn)
        ilout = self._filename_to_output_arg(output_fn)
        cmd_args = f'--project="{self.project}" {ilout} {ilinp}'

        self.run_headless(cmd_args)

        output = io.readData(output_fn)
        output_chan = self.temp_dir / 'out.npy'
        # transpose to restore input dimensionality
        output_chan = io.writeData(output_chan,
                                   output[..., self.output_channel],
                                   returnMemmap=True)

        return output_chan
示例#28
0
    def _generate_output(self):
        # label return count

        if self.sigmas:
            if self.input.ndim != len(self.sigmas):
                raise ValueError(
                    'Sigmas must have same length as image dimensions.')

            # Smooth image
            self.log.verbose('Smoothing image.')
            self.input[:] = gaussian_filter(self.input, sigma=self.sigmas)

        raw_img = self.input

        if self.mode == 3:
            # Pad image by 1 pixel in each dimension
            self.log.debug('Padding image.')
            padded_img = tif.tifffile.memmap(
                os.path.join(self.temp_dir, 'temp_padded_img.tif'),
                dtype=raw_img.dtype,
                shape=(tuple(x + 2 for x in raw_img.shape)))
            if raw_img.ndim == 3:
                padded_img[1:-1, 1:-1, 1:-1] = raw_img
            if raw_img.ndim == 2:
                padded_img[1:-1, 1:-1] = raw_img
            raw_img = padded_img

        bin_img = tif.tifffile.memmap(os.path.join(self.temp_dir,
                                                   'temp_bin_img.tif'),
                                      dtype=np.uint8,
                                      shape=raw_img.shape)

        labeled_1_img = tif.tifffile.memmap(os.path.join(
            self.temp_dir, 'temp_labeled_1_img.tif'),
                                            dtype=np.int32,
                                            shape=raw_img.shape)

        # Binarize image
        self.log.debug('Thresholding')
        threshold(raw_img, self.high_threshold, bin_img)

        # Label image
        self.log.debug('Labeling')
        connect(bin_img, labeled_1_img)

        # Filter labeled regions by size (1st pass) # Mode 1: Stop after this
        self.log.debug('Size filtering')
        _, counts = size_filter(labeled_1_img, self.min_size, self.max_size,
                                labeled_1_img)

        if len(counts) == 0:
            if self.mode == 3:
                if self.input.ndim == 2:
                    labeled_1_img = labeled_1_img[1:-1, 1:-1]
                else:
                    labeled_1_img = labeled_1_img[1:-1, 1:-1, 1:-1]

            out = io.empty(os.path.join(self.temp_dir, 'output.tif'),
                           shape=labeled_1_img.shape,
                           dtype=labeled_1_img.dtype)
            out[:] = 0

            self.log.debug('No components found in first threshold.')
            return out

        if self.mode == 1:
            return io.readData(labeled_1_img.filename)

        # Mode 2 two serial thresholding>label> filter runs
        elif self.mode == 2:

            labeled_2_img = tif.tifffile.memmap(os.path.join(
                self.temp_dir, 'temp_labeled_2_img.tif'),
                                                dtype=np.int32,
                                                shape=raw_img.shape)

            self.log.debug('Low thresholding')
            threshold(raw_img, self.low_threshold, bin_img)

            self.log.debug('Labeling.')
            _ = connect(bin_img, labeled_2_img)

            self.log.debug('Comparing overlap.')
            overlap(labeled_1_img, labeled_2_img, labeled_2_img)

            self.log.debug('Running final size filter.')
            _, counts = size_filter(labeled_2_img, self.min_size2,
                                    self.max_size2, labeled_2_img)

            if len(counts) == 0:
                self.log.debug('No components found in second threshold.')
                return io.readData(labeled_2_img.filename)

            return io.readData(labeled_1_img.filename)

        # Mode 3 two serial thresholds with identity preservation
        elif self.mode == 3:

            # Low threshold Image
            self.log.debug('Low thresholding.')
            threshold(raw_img, self.low_threshold, bin_img)

            ############################## Watershed ##############################

            # Get coordinates of all nonzero values in labeled/size-filtered image
            self.log.debug('Getting label coordinates.')
            marker_locations_filename = os.path.join(self.temp_dir,
                                                     'marker_locations.mmap')
            marker_locations = nonzero_coords(labeled_1_img,
                                              marker_locations_filename)

            connectivity, offset = structure_element_binary(raw_img.ndim,
                                                            connectivity=1,
                                                            offset=None)

            flat_neighborhood = _offsets_to_raveled_neighbors(raw_img.shape,
                                                              connectivity,
                                                              center=offset)

            image_strides = np.array(raw_img.strides,
                                     dtype=np.intp) // raw_img.itemsize

            self.log.debug('Running watershed.')
            watershed(
                raw_img,
                marker_locations,
                flat_neighborhood,
                bin_img,
                image_strides,
                labeled_1_img,  # <-- Output
                True)  # <-- Inverted watershed

            #######################################################################

            # Final size filter
            self.log.debug('Running final size filter.')
            _, counts = size_filter(labeled_1_img, self.min_size2,
                                    self.max_size2, labeled_1_img)

            if len(counts) == 0:
                self.log.debug(
                    'No components found in after inverse watershed.')

            if self.input.ndim == 2:
                labeled_1_img = labeled_1_img[1:-1, 1:-1]
            else:
                labeled_1_img = labeled_1_img[1:-1, 1:-1, 1:-1]

            out = io.empty(os.path.join(self.temp_dir, 'output.tif'),
                           shape=labeled_1_img.shape,
                           dtype=labeled_1_img.dtype)
            out[:] = labeled_1_img

            return out
示例#29
0
def overlay_points(pointSource,
                   dataSource,
                   output=None,
                   overlay=True,
                   x=all,
                   y=all,
                   z=all):
    """Overlay points on 3D data and return as color image
    
    Arguments:
        pointSource (str or array): point data to be overlayed on the image data
        dataSource (str or array): volumetric image data. if None just output points as an image
        overlay (bool): if False will not overlay and just output points as an image.
        x, y, z (all or tuple): sub-range specification
    
    Returns:
        (str or array): image overlayed with points
        
    See Also:
        :func:`overlayLabel`
    """

    points = (io.readPoints(pointSource, x=x, y=y, z=z,
                            shift=True)).astype(int)

    if overlay:
        X, Y, Z = io.dataSize(dataSource)
        datatype = io.readData(dataSource, x=x, y=y, z=0).dtype

        if io.isMappable(output):
            output = tif.tifffile.memmap(output,
                                         dtype=datatype,
                                         shape=(Z, 2, Y, X),
                                         imagej=True)  # TZCYXS FIJI
        elif io.isFileExpression(output):
            output = [
                tif.tifffile.memmap(output,
                                    dtype=datatype,
                                    shape=(2, Y, X),
                                    imagej=True) for z in range(Z)
            ]  # sequence of memmap files
        elif output is None:
            output = numpy.zeros((Z, 2, Y, X), dtype=datatype)
        else:
            RuntimeError('output format not compatable with overlayPoints: ' +
                         output)

        for z in range(Z):
            print(('Overlaying {}...'.format(z)))
            output[z][0][:] = io.readData(dataSource, x=x, y=y,
                                          z=z).squeeze().T
            z_points = points[points[:, -1] == z][:, :2]
            output[z][1][[*z_points[:, ::-1].T]] = 1
        return output

    else:
        shape = io.dataSize(dataSource)
        cimage = vox.voxelize(
            points, shape, output=output, method='Pixel', weights=65535
        )  # TODO: weight should depend on bit depth of dataSource
        return cimage
示例#30
0
def writeData(filename, data, rgb=False, substack=None, returnMemmap=True):
    """Write image data to tif file
    
    Arguments:
        filename (str): file name 
        data (array): image data in x,y,z
        rgb (bool): if true will save RGB image. channels should be last array axis
        returnMemmap (bool): returns array rather than file name
    Returns:
        str or np.array: output file name or memory mapped array
    """

    fn, fe = os.path.splitext(
        filename
    )  # initial write to partial filename to prevent creating incomplete files
    d = len(data.shape)  # fiji wants 'TZCYXS'
    dtype = data.flat[0].dtype

    if substack:
        sub = range_to_slices(substack)
        data_map = io.readData(filename)
        data_map[sub] = data

    else:
        if not rgb:
            if d == 2:  # XY
                data_map = tif.tifffile.memmap(fn,
                                               dtype=dtype,
                                               shape=data.shape)
            elif d == 3:  # XYZ
                data_map = tif.tifffile.memmap(
                    fn, dtype=dtype, shape=data.shape,
                    bigtiff=True)  #imageJ = true not work for int32
            elif d == 4:  #XYZC
                data_map = tif.tifffile.memmap(fn,
                                               dtype=dtype,
                                               shape=data.shape,
                                               imagej=True)
            else:
                raise RuntimeError(
                    'writing {} dimensional data to tif not supported!'.format(
                        len(data.shape)))
        else:
            if d == 3:  # XYC
                data_map = tif.tifffile.memmap(
                    fn, dtype=dtype, shape=data.shape,
                    imagej=True)  #imageJ = true not work for int32
            elif d == 4:  # XYZS
                data_map = tif.tifffile.memmap(fn,
                                               dtype=dtype,
                                               shape=data.shape,
                                               imagej=True)
            else:
                raise RuntimeError(
                    'writing {} dimensional data to tif not supported!'.format(
                        len(data.shape)))

        data_map[:] = data
        shutil.move(fn, filename)

    if returnMemmap:
        return readData(filename)
    else:
        return filename