Beispiel #1
0
    def downsample_stack_file(cls,
                              stack_file,
                              side,
                              output_stack_file=None,
                              mask_file=None):

        if output_stack_file is None:
            output_stack_file = set_output_name(stack_file, 'downsampled')

        if os.path.exists(output_stack_file):
            raise FileExistsError(
                f"output file '{yellow(output_stack_file)}' already exists!")

        if mask_file:
            if not os.path.exists(mask_file):
                logger.error(f"mask file {yellow(mask_file)} doesn't exist!")
            mask = load_stack_from_file(mask_file)
        else:
            mask = None

        stack = load_stack_from_file(stack_file)
        downsampled_stack = cls.downsample(stack,
                                           side,
                                           compute_fx=False,
                                           stack=True,
                                           mask=mask)
        logger.info(
            f"downsampled stack from size {stack.shape} to {downsampled_stack.shape}."
            f" saving to {yellow(output_stack_file)}..")

        with mrcfile.new(output_stack_file) as mrc_fh:
            mrc_fh.set_data(downsampled_stack)
        logger.debug(f"saved to {output_stack_file}")
Beispiel #2
0
    def crop_stack_file(cls,
                        stack_file,
                        size,
                        output_stack_file=None,
                        fill_value=None):

        if output_stack_file is None:
            output_stack_file = set_output_name(stack_file, 'cropped')

        if os.path.exists(output_stack_file):
            raise FileExistsError(
                f"output file '{yellow(output_stack_file)}' already exists!")

        stack = load_stack_from_file(stack_file)
        fill_value = fill_value or PreProcessorConfig.crop_stack_fill_value
        cropped_stack = cls.crop_stack(stack, size, fill_value=fill_value)

        action = 'cropped' if size < stack.shape[1] else 'padded'
        logger.info(
            f"{action} stack from size {stack.shape} to size {cropped_stack.shape}."
            f" saving to {yellow(output_stack_file)}..")

        with mrcfile.new(output_stack_file) as mrc:
            mrc.set_data(cropped_stack)
        logger.debug(f"saved to {output_stack_file}")
Beispiel #3
0
def view_stack(stack, numslices=16, startslice=1, nrows=4, ncols=4):

    if numslices > nrows * ncols:
        raise ValueError("nrows*ncols should be at least numslices"
                         " to accomodate all images.")

    logger.debug("Shape of loaded map: " + str(stack.shape))

    plt.figure(figsize=(4, 4))

    j = 0
    dx = 0.95 / ncols
    dy = 0.95 / nrows
    for col in range(ncols):
        for row in range(nrows):
            if j < numslices:
                x0 = col * 1.0 / ncols
                y0 = 1 - row * 1.0 / nrows - dy
                # Flip y direction to fill image grid from top
                ax = plt.axes([x0, y0, dx, dy])
                plt.imshow(stack[j, ...])
                plt.gray()
                plt.axis("off")
                ax.text(0.1,
                        0.9,
                        str(j + startslice),
                        fontsize=10,
                        horizontalalignment='center',
                        verticalalignment='center',
                        transform=ax.transAxes,
                        color='red',
                        bbox=dict(facecolor='yellow', alpha=0.15))

                j += 1
    plt.show()
Beispiel #4
0
def fortran_to_c(stack):
    """ Convert Fortran-contiguous array to C-contiguous array. """
    if stack.flags.f_contiguous:
        logger.debug(f"loading F-contiguous stack")
    return stack.T if stack.flags.f_contiguous else stack
Beispiel #5
0
def global_phaseflip_stack(ctx_obj):
    """ Apply global phase-flip to an MRC stack """
    logger.debug("calculating global phaseflip..")
    ctx_obj.stack = PreProcessor.global_phaseflip_stack(ctx_obj.stack)
Beispiel #6
0
    def crop(mat, n, stack=False, fill_value=None):
        """
            Reduce the size of a vector, square or cube 'mat' by cropping (or
            increase the size by padding with fill_value, by default zero) to a final
            size of n, (n x n), or (n x n x n) respectively. This is the analogue of downsample, but
            it doesn't change magnification.

            If mat is 2-dimensional and n is a vector, m is cropped to n=[mat_x mat_y].

            The function handles odd and even-sized arrays correctly. The center of
            an odd array is taken to be at (n+1)/2, and an even array is n/2+1.

            If flag is_stack is set to True, then a 3D array 'mat' is treated as a stack of 2D
            images, and each image is cropped to (n x n).

            For 2D images, the input image doesn't have to be square.

            * The original MATLAB function supported cropping to non-square matrices.
              As real-world uses will always crop to square (n, n), we don't support it with Python.


            Args:
                mat (numpy.array): Vector, 2D array, stack of 2D arrays or a 3D array
                n (int): Size of desired cropped vector, side of 2D array or side of 3D array
                stack (bool): Set to True in order to handle a 3D mat as a stack of 2D
                fill_value (:obj:`int`, optional): Padding value. Defaults to 0.

            Returns:
                numpy.array: Cropped or padded mat to size of n, (n x n) or (n x n x n)

            TODO: change name to 'resize'? crop/pad is confusing b/c either you save different
            TODO:   output names or you stick to a misleading name like cropped.mrc for padded stack
        """

        num_dimensions = len(mat.shape)

        if num_dimensions not in [1, 2, 3]:
            raise DimensionsIncompatible(
                "cropping/padding failed! number of dimensions is too big!"
                f" ({num_dimensions} while max is 3).")

        if num_dimensions == 2 and 1 in mat.shape:
            num_dimensions = 1

        if fill_value is None:
            fill_value = PreProcessorConfig.crop_stack_fill_value

        if num_dimensions == 1:  # mat is a vector
            mat = np.reshape(mat, [mat.size, 1])  # force a column vector
            ns = math.floor(mat.size / 2) - math.floor(
                n / 2)  # shift term for scaling down
            if ns >= 0:  # cropping
                return mat[ns:ns + n].astype('float32')

            else:  # padding
                result_mat = fill_value * np.ones([n, 1], dtype=complex)
                result_mat[-ns:mat.size - ns] = mat
                return result_mat.astype('float32')

        elif num_dimensions == 2:  # mat is 2D image
            mat_x, mat_y = mat.shape
            # start_x = math.floor(mat_x / 2) - math.floor(n / 2)  # shift term for scaling down
            start_x = mat_x / 2 - n / 2  # shift term for scaling down
            # start_y = math.floor(mat_y / 2) - math.floor(n / 2)
            start_y = mat_y / 2 - n / 2

            if start_x >= 0 and start_y >= 0:  # cropping
                start_x, start_y = math.floor(start_x), math.floor(start_y)
                logger.debug(f'crop:cropping from {mat.shape} to {n}..')
                return mat[start_x:start_x + int(n),
                           start_y:start_y + int(n)].astype('float32')

            elif start_x < 0 and start_y < 0:  # padding
                logger.debug('crop:padding..')
                start_x, start_y = math.floor(start_x), math.floor(start_y)
                result_mat = fill_value * np.ones([n, n], dtype=complex)
                result_mat[-start_x:mat_x - start_x,
                           -start_y:mat_y - start_y] = mat
                return result_mat.astype('float32')

            else:
                raise DimensionsIncompatible(
                    "Can't crop and pad simultaneously!")

        else:  # mat is 3D or a stack of 2D images

            if stack:
                # break down the stack and treat each image as an individual image
                # then return the cropped stack
                result_mat = np.zeros([mat.shape[0], n, n], dtype='float32')
                for img in range(mat.shape[0]):
                    # TODO iterate instead of using recursion. this is too memoery-expensive
                    result_mat[img, :, :] = PreProcessor.crop(
                        mat[img, :, :], n)

                return result_mat.astype('float32')

            else:  # this is a 3D structure
                # crop/pad mat into a new smaller/bigger cell - 'destination cell'
                from_shape = np.array(mat.shape)
                to_shape = np.array((n, n, n))

                ns = np.floor(from_shape / 2) - np.floor(to_shape / 2)
                ns, to_shape = ns.astype(int), to_shape.astype(
                    int)  # can't slice later with float

                if np.all(ns >= 0):  # crop
                    return mat[ns[0]:ns[0] + to_shape[0],
                               ns[1]:ns[1] + to_shape[1],
                               ns[2]:ns[2] + to_shape[2]]

                elif np.all(ns <= 0):  # pad
                    result_mat = fill_value * np.ones([n, n, n], dtype=complex)
                    result_mat[-ns[0]:from_shape[0] - ns[0],
                               -ns[1]:from_shape[2] - ns[1],
                               -ns[2]:from_shape[2] - ns[2]] = mat

                    return result_mat.astype('float32')

                else:
                    raise DimensionsIncompatible(
                        "Can't crop and pad simultaneously!")