def electron_count(reader, darkreference, number_of_samples=40, background_threshold_n_sigma=4, xray_threshold_n_sigma=10, threshold_num_blocks=1, scan_width=0, scan_height=0): blocks = [] for i in range(threshold_num_blocks): blocks.append(next(reader)) background_threshold, xray_threshold = _image.calculate_thresholds( [b._block for b in blocks], darkreference._image, number_of_samples, background_threshold_n_sigma, xray_threshold_n_sigma) # Reset the reader reader.reset() events = _image.electron_count(reader.begin(), reader.end(), darkreference._image, background_threshold, xray_threshold, scan_width, scan_height) # Convert to numpy and return return np.array([np.array(x) for x in events])
def electron_count(reader, darkreference=None, number_of_samples=40, background_threshold_n_sigma=4, xray_threshold_n_sigma=10, threshold_num_blocks=1, scan_dimensions=(0, 0), verbose=False, gain=None): """Generate a list of coordinates of electron hits. :param reader: the file reader that has already opened the data. :type reader: stempy.io.reader :param darkreference: the dark reference to subtract, potentially generated via stempy.image.calculate_average(). :type darkreference: stempy.image.ImageArray or stempy::Image<double> :param number_of_samples: the number of samples to take when calculating the thresholds. :type number_of_samples: int :param background_threshold_n_sigma: N-Sigma used for calculating the background threshold. :type background_threshold_n_sigma: int :param xray_threshold_n_sigma: N-Sigma used for calculating the X-Ray threshold :type xray_threshold_n_sigma: int :param threshold_num_blocks: The number of blocks of data to use when calculating the threshold. :type threshold_num_blocks: int :param scan_dimensions: the dimensions of the scan, where the order is (width, height). Required if `data` is a numpy.ndarray. :type scan_dimensions: tuple of ints of length 2 :param verbose: whether or not to print out verbose output. :type verbose: bool :param gain: the gain mask to apply. Must match the frame dimensions :type gain: numpy.ndarray (2D) :return: the coordinates of the electron hits for each frame. :rtype: SparseArray """ if gain is not None: # Invert, as we will multiply in C++ # It also must be a float32 gain = np.power(gain, -1) gain = _safe_cast(gain, np.float32, 'gain') if isinstance(darkreference, np.ndarray): # Must be float32 for correct conversions darkreference = _safe_cast(darkreference, np.float32, 'dark reference') # Special case for threaded reader if isinstance(reader, (SectorThreadedReader, SectorThreadedMultiPassReader)): args = [reader] if darkreference is not None: args = args + [darkreference] # Now add the other args args = args + [ threshold_num_blocks, number_of_samples, background_threshold_n_sigma, xray_threshold_n_sigma ] # add the gain arg if we have been given one. if gain is not None: args.append(gain) args = args + [scan_dimensions, verbose] data = _image.electron_count(*args) else: deprecation_message = ( 'Using a reader in electron_count() that is not a ' 'SectorThreadedReader or a SectorThreadedMultiPassReader is ' 'deprecated in stempy==1.1 and will be removed in stempy==1.2') warnings.warn(deprecation_message, category=DeprecationWarning, stacklevel=2) blocks = [] for i in range(threshold_num_blocks): blocks.append(next(reader)) if darkreference is not None and hasattr(darkreference, '_image'): darkreference = darkreference._image args = [[b._block for b in blocks]] if darkreference is not None: args.append(darkreference) args = args + [ number_of_samples, background_threshold_n_sigma, xray_threshold_n_sigma ] if gain is not None: args.append(gain) res = _image.calculate_thresholds(*args) background_threshold = res.background_threshold xray_threshold = res.xray_threshold if verbose: print('****Statistics for calculating electron thresholds****') print('number of samples:', res.number_of_samples) print('min sample:', res.min_sample) print('max sample:', res.max_sample) print('mean:', res.mean) print('variance:', res.variance) print('std dev:', res.std_dev) print('number of bins:', res.number_of_bins) print('x-ray threshold n sigma:', res.xray_threshold_n_sigma) print('background threshold n sigma:', res.background_threshold_n_sigma) print('optimized mean:', res.optimized_mean) print('optimized std dev:', res.optimized_std_dev) print('background threshold:', background_threshold) print('xray threshold:', xray_threshold) # Reset the reader reader.reset() args = [reader.begin(), reader.end()] if darkreference is not None: args.append(darkreference) args = args + [background_threshold, xray_threshold] if gain is not None: args.append(gain) args = args + [scan_dimensions] data = _image.electron_count(*args) # Convert to numpy array num_scans = len(data.data) frames_per_scan = len(data.data[0]) if data.data else 0 np_data = np.empty((num_scans, frames_per_scan), dtype=object) for i, scan_frames in enumerate(data.data): for j, sparse_frame in enumerate(scan_frames): np_data[i, j] = np.array(sparse_frame, copy=False) metadata = _electron_counted_metadata_to_dict(data.metadata) kwargs = { 'data': np_data, 'scan_shape': data.scan_dimensions[::-1], 'frame_shape': data.frame_dimensions, 'metadata': { 'electron_counting': metadata }, } array = SparseArray(**kwargs) # Store a copy of the underlying C++ object in case we need it later array._electron_counted_data = data return array
def electron_count(reader, darkreference=None, number_of_samples=40, background_threshold_n_sigma=4, xray_threshold_n_sigma=10, threshold_num_blocks=1, scan_dimensions=(0, 0), verbose=False, gain=None): """Generate a list of coordinates of electron hits. :param reader: the file reader that has already opened the data. :type reader: stempy.io.reader :param darkreference: the dark reference to subtract, potentially generated via stempy.image.calculate_average(). :type darkreference: stempy.image.ImageArray or stempy::Image<double> :param number_of_samples: the number of samples to take when calculating the thresholds. :type number_of_samples: int :param background_threshold_n_sigma: N-Sigma used for calculating the background threshold. :type background_threshold_n_sigma: int :param xray_threshold_n_sigma: N-Sigma used for calculating the X-Ray threshold :type xray_threshold_n_sigma: int :param threshold_num_blocks: The number of blocks of data to use when calculating the threshold. :type threshold_num_blocks: int :param scan_dimensions: the dimensions of the scan, where the order is (width, height). Required if `data` is a numpy.ndarray. :type scan_dimensions: tuple of ints of length 2 :param verbose: whether or not to print out verbose output. :type verbose: bool :param gain: the gain mask to apply. Must match the frame dimensions :type gain: numpy.ndarray (2D) :return: the coordinates of the electron hits for each frame. :rtype: ElectronCountedData (named tuple with fields 'data', 'scan_dimensions', and 'frame_dimensions') """ if gain is not None: # Invert, as we will multiply in C++ # It also must be a float32 gain = np.power(gain, -1) gain = _safe_cast(gain, np.float32, 'gain') if isinstance(darkreference, np.ndarray): # Must be float32 for correct conversions darkreference = _safe_cast(darkreference, np.float32, 'dark reference') # Special case for threaded reader if isinstance(reader, (SectorThreadedReader, SectorThreadedMultiPassReader)): args = [reader] if darkreference is not None: args = args + [darkreference] # Now add the other args args = args + [ threshold_num_blocks, number_of_samples, background_threshold_n_sigma, xray_threshold_n_sigma ] # add the gain arg if we have been given one. if gain is not None: args.append(gain) args = args + [scan_dimensions, verbose] data = _image.electron_count(*args) else: blocks = [] for i in range(threshold_num_blocks): blocks.append(next(reader)) if darkreference is not None and hasattr(darkreference, '_image'): darkreference = darkreference._image args = [[b._block for b in blocks]] if darkreference is not None: args.append(darkreference) args = args + [ number_of_samples, background_threshold_n_sigma, xray_threshold_n_sigma ] if gain is not None: args.append(gain) res = _image.calculate_thresholds(*args) background_threshold = res.background_threshold xray_threshold = res.xray_threshold if verbose: print('****Statistics for calculating electron thresholds****') print('number of samples:', res.number_of_samples) print('min sample:', res.min_sample) print('max sample:', res.max_sample) print('mean:', res.mean) print('variance:', res.variance) print('std dev:', res.std_dev) print('number of bins:', res.number_of_bins) print('x-ray threshold n sigma:', res.xray_threshold_n_sigma) print('background threshold n sigma:', res.background_threshold_n_sigma) print('optimized mean:', res.optimized_mean) print('optimized std dev:', res.optimized_std_dev) print('background threshold:', background_threshold) print('xray threshold:', xray_threshold) # Reset the reader reader.reset() args = [reader.begin(), reader.end()] if darkreference is not None: args.append(darkreference) args = args + [background_threshold, xray_threshold] if gain is not None: args.append(gain) args = args + [scan_dimensions] data = _image.electron_count(*args) electron_counted_data = namedtuple( 'ElectronCountedData', ['data', 'scan_dimensions', 'frame_dimensions']) # Convert to numpy array electron_counted_data.data = np.array( [np.array(x, copy=False) for x in data.data], dtype=np.object) electron_counted_data.scan_dimensions = data.scan_dimensions electron_counted_data.frame_dimensions = data.frame_dimensions # Store a copy of the underlying C++ object in case we need it later electron_counted_data._electron_counted_data = data return electron_counted_data