def particles_xyz_to_np_array(motl_em_file, scaling_factor=1): """ Extracts coordinates of all particles from a motive list EM file and returns them in numpy array format. Optionally, scales the coordinates by multiplying with a given scaling factor. Args: motl_em_file (str): TOM motive list EM file holding the particle coordinates in rows 8-10 scaling_factor (int, optional): scaling factor by which the coordinates are multiplied; if 1 (default), no scaling is performed Returns: a 2D array containing the particle coordinates in format [[x1, y1, z1], [x2, y2, z2], ...] (numpy.ndarray) """ motl = io.load_tomo(motl_em_file) particles_xyz = [] for col in xrange(motl.shape[1]): x = scaling_factor * motl[7, col, 0] y = scaling_factor * motl[8, col, 0] z = scaling_factor * motl[9, col, 0] particles_xyz.append([x, y, z]) particles_xyz = np.array(particles_xyz) return particles_xyz
def read_in_mask(mask_file, verbose=False): """ A wrapper for reading in a membrane segmentation or ribosome centers mask (binary tomographic data). Args: mask_file (str): a mask file in EM, MRC or VTI format verbose (boolean, optional): if True (default False), some extra information will be printed out Returns: the read in mask (numpy.ndarray) """ print '\nReading in the mask %s' % mask_file mask = io.load_tomo(mask_file) if verbose: print 'Shape and data type:' print mask.shape print mask.dtype return mask
def close_holes(infile, cube_size, iterations, outfile): """ Closes small holes in a binary volume by using a binary closing operation. Args: infile (str): input 'MRC' file with a binary volume cube_size (str): size of the cube used for the binary closing operation (dilation followed by erosion) iterations (int): number of closing iterations outfile (str): output 'MRC' file with the closed volume Returns: None """ tomo = io.load_tomo(infile) data_type = tomo.dtype # dtype('uint8') tomo_closed = ndimage.binary_closing( tomo, structure=np.ones((cube_size, cube_size, cube_size)), iterations=iterations).astype(data_type) io.save_numpy(tomo_closed, outfile)
def split_segmentation(infile, lbl=1, close=True, close_cube_size=5, close_iter=1, min_region_size=100): """ Splits the segmentation in connected regions with at least the given size (number of voxels). Args: infile (str): the segmentation input file in one of the formats: '.mrc' '.em' or '.vti'. lbl (int, optional) the label to be considered, 0 will be ignored, default 1 close (boolean, optional): if True (default), closes small holes in the segmentation first close_cube_size (int, optional): if close is True, gives the size of the cube structuring element used for closing, default 5 close_iter (int, optional): if close is True, gives the number of iterations the closing should be repeated, default 1 min_region_size (int, optional): gives the minimal number of voxels a region has to have in order to be considered, default 100 Returns: a list of regions, where each item is a binary ndarray with the same shape as the segmentation but contains one region """ # Load the segmentation numpy array from a file and get only the requested # labels as 1 and the background as 0: seg = io.load_tomo(infile) assert(isinstance(seg, np.ndarray)) data_type = seg.dtype binary_seg = (seg == lbl).astype(data_type) # If requested, close small holes in the segmentation: outfile = infile if close: outfile = ("%s%s_closed_size%s_iter%s.mrc" % (infile[0:-4], lbl, close_cube_size, close_iter)) if not isfile(outfile): from scipy import ndimage cube = np.ones((close_cube_size, close_cube_size, close_cube_size)) binary_seg = ndimage.binary_closing( binary_seg, structure=cube, iterations=close_iter ).astype(data_type) # Write the closed binary segmentation into a file: io.save_numpy(binary_seg, outfile) print ("Closed the binary segmentation and saved it into the file " "%s" % outfile) else: # the '.mrc' file already exists binary_seg = io.load_tomo(outfile) print ("The closed binary segmentation was loaded from the file " "%s" % outfile) # Label each connected region of the binary segmentation: label_seg = label(binary_seg) # Get only regions with at least the given size: regions = [] for i, region in enumerate(regionprops(label_seg)): region_area = region.area if region_area >= min_region_size: print "%s. region has %s voxels and pass" % (i + 1, region_area) # Get the region coordinates and make an ndarray with same shape as # the segmentation and 1 at those coordinates: region_ndarray = np.zeros(shape=tuple(seg.shape), dtype=data_type) # 2D array with 3 columns: x, y, z and number of rows corresponding # to the number of voxels in the region region_coords = region.coords for i in xrange(region_coords.shape[0]): # iterate over the rows region_ndarray[region_coords[i, 0], region_coords[i, 1], region_coords[i, 2]] = 1 regions.append(region_ndarray) else: print ("%s. region has %s voxels and does NOT pass" % (i + 1, region_area)) print "%s regions passed." % len(regions) return regions, outfile
def run_gen_surface(tomo, outfile_base, lbl=1, mask=True, save_input_as_vti=False, verbose=False): """ Runs pysurf_io.gen_surface function, which generates a VTK PolyData triangle surface for objects in a segmented volume with a given label. Removes triangles with zero area, if any are present, from the resulting surface. Args: tomo (str or numpy.ndarray): segmentation input file in one of the formats: '.mrc', '.em' or '.vti', or 3D array containing the segmentation outfile_base (str): the path and filename without the ending for saving the surface (ending '.surface.vtp' will be added automatically) lbl (int, optional): the label to be considered, 0 will be ignored, default 1 mask (boolean, optional): if True (default), a mask of the binary objects is applied on the resulting surface to reduce artifacts save_input_as_vti (boolean, optional): if True (default False), the input is saved as a '.vti' file ('<outfile_base>.vti') verbose (boolean, optional): if True (default False), some extra information will be printed out Returns: the triangle surface (vtk.PolyData) """ t_begin = time.time() # Generating the surface (vtkPolyData object) surface = io.gen_surface(tomo, lbl=lbl, mask=mask, verbose=verbose) # Filter out triangles with area=0, if any are present surface = __filter_null_triangles(surface, verbose=verbose) t_end = time.time() duration = t_end - t_begin print 'Surface generation took: %s min %s s' % divmod(duration, 60) # Writing the vtkPolyData surface into a VTP file io.save_vtp(surface, outfile_base + '.surface.vtp') print 'Surface was written to the file %s.vtp' % outfile_base if save_input_as_vti is True: # If input is a file name, read in the segmentation array from the file: if isinstance(tomo, str): tomo = io.load_tomo(tomo) elif not isinstance(tomo, np.ndarray): error_msg = 'Input must be either a file name or a ndarray.' raise pexceptions.PySegInputError(expr='run_gen_surface', msg=error_msg) # Save the segmentation as VTI for opening it in ParaView: io.save_numpy(tomo, outfile_base + '.vti') print 'Input was saved as the file %s.vti' % outfile_base return surface