def _deweight_array(input_data, weight_array, oversample_rate, dimension): """ Uniformly weight complex SAR data along the given dimension. Parameters ---------- input_data : numpy.ndarray weight_array : numpy.ndarray oversample_rate : int|float dimension : int Returns ------- numpy.ndarray """ if weight_array is None: # nothing to be done return input_data weight_size = round(input_data.shape[dimension]/oversample_rate) if weight_array.ndim != 1: raise ValueError('weight_array must be one dimensional.') if weight_array.size != weight_size: weight_array = scipy.signal.resample(weight_array, weight_size) weight_ind_start = int_func(numpy.floor(0.5*(input_data.shape[dimension] - weight_size))) weight_ind_end = weight_ind_start + weight_size output_data = fftshift(fft(input_data, axis=dimension), axes=dimension) if dimension == 0: output_data[weight_ind_start:weight_ind_end, :] /= weight_array[:, numpy.newaxis] else: output_data[:, weight_ind_start:weight_ind_end] /= weight_array return ifft(ifftshift(output_data, axes=dimension), axis=dimension)
def subaperture_processing_array(array, aperture_indices, output_resolution, dimension=0): """ Perform the sub-aperture processing on the given complex array data. Parameters ---------- array : numpy.ndarray The complex array data. Dimension other than 2 is not supported. aperture_indices : Tuple[int, int] The start/stop indices for the subaperture processing. output_resolution : int The output resolution parameter. dimension : int The dimension along which to perform the sub-aperture processing. Must be one of 0 or 1. Returns ------- numpy.ndarray """ array = _validate_input(array) dimension = _validate_dimension(dimension) return subaperture_processing_phase_history(fftshift(fft(array, axis=dimension), axes=dimension), aperture_indices, output_resolution, dimension=dimension)
def apply_weight_array(input_data, weight_array, oversample_rate, dimension, inverse=False): """ Apply the weight array along the given dimension. Parameters ---------- input_data : numpy.ndarray The complex data array to weight. weight_array : numpy.ndarray The weight array. oversample_rate : int|float The oversample rate. dimension : int Along which dimension to apply the weighting? Must be one of `{0, 1}`. inverse : bool If `True`, this divides the weight (i.e. de-weight), otherwise it multiplies. Returns ------- numpy.ndarray """ if not (isinstance(input_data, numpy.ndarray) and input_data.ndim == 2): raise ValueError('The data array must be two-dimensional') if weight_array is None: # nothing to be done return input_data weight_array, weight_ind_start, weight_ind_end = determine_weight_array( input_data.shape, weight_array, oversample_rate, dimension) if inverse and numpy.any(weight_array == 0): raise ValueError( 'inverse=True and the weight array contains some zero entries.') output_data = fftshift(fft(input_data, axis=dimension), axes=dimension) if dimension == 0: if inverse: output_data[weight_ind_start: weight_ind_end, :] /= weight_array[:, numpy.newaxis] else: output_data[weight_ind_start: weight_ind_end, :] *= weight_array[:, numpy.newaxis] else: if inverse: output_data[:, weight_ind_start:weight_ind_end] /= weight_array else: output_data[:, weight_ind_start:weight_ind_end] *= weight_array return ifft(ifftshift(output_data, axes=dimension), axis=dimension)
def csi_array(array, dimension=0, platform_direction='R', fill=1, filter_map=None): """ Creates a color subaperture array from a complex array. .. Note: this ignores any potential sign issues for the fft and ifft, because the results would be identical - fft followed by ifft versus ifft followed by fft. Parameters ---------- array : numpy.ndarray The complex valued SAR data, assumed to be in the "image" domain. Required to be two-dimensional. dimension : int The dimension over which to split the sub-aperture. platform_direction : str The (case insensitive) platform direction, required to be one of `('R', 'L')`. fill : float The fill factor. This will be ignored if `filter_map` is provided. filter_map : None|numpy.ndarray The RGB filter mapping. This is assumed constructed using :func:`filter_map_construction`. Returns ------- numpy.ndarray """ if not (isinstance(array, numpy.ndarray) and len(array.shape) == 2 and numpy.iscomplexobj(array)): raise ValueError('array must be a two-dimensional numpy array of complex dtype') dimension = int_func(dimension) if dimension not in [0, 1]: raise ValueError('dimension must be 0 or 1, got {}'.format(dimension)) if dimension == 0: array = array.T pdir_func = platform_direction.upper()[0] if pdir_func not in ['R', 'L']: raise ValueError('It is expected that pdir is one of "R" or "L". Got {}'.format(platform_direction)) # get our filter construction data if filter_map is None: fill = max(1.0, float(fill)) filter_map = filter_map_construction(array.shape[1]/fill) if not (isinstance(filter_map, numpy.ndarray) and filter_map.dtype.name in ['float32', 'float64'] and filter_map.ndim == 2 and filter_map.shape[1] == 3): raise ValueError('filter_map must be a N x 3 numpy array of float dtype.') # move to phase history domain ph_indices = int(numpy.floor(0.5*(array.shape[1] - filter_map.shape[0]))) + \ numpy.arange(filter_map.shape[0], dtype=numpy.int32) ph0 = fftshift(ifft(numpy.cast[numpy.complex128](array), axis=1), axes=1)[:, ph_indices] # construct the filtered workspace # NB: processing is more efficient with color band in the first dimension ph0_RGB = numpy.zeros((3, array.shape[0], filter_map.shape[0]), dtype=numpy.complex128) for i in range(3): ph0_RGB[i, :, :] = ph0*filter_map[:, i] del ph0 # Shift phase history to avoid having zeropad in middle of filter, to alleviate # the purple sidelobe artifact. filter_shift = int(numpy.ceil(0.25*filter_map.shape[0])) ph0_RGB[0, :] = numpy.roll(ph0_RGB[0, :], -filter_shift) ph0_RGB[2, :] = numpy.roll(ph0_RGB[2, :], filter_shift) # NB: the green band is already centered # FFT back to the image domain im0_RGB = fft(fftshift(ph0_RGB, axes=2), n=array.shape[1], axis=2) del ph0_RGB # Replace the intensity with the original image intensity to main full resolution # (in intensity, but not in color). scale_factor = numpy.abs(array)/numpy.abs(im0_RGB).max(axis=0) im0_RGB = numpy.abs(im0_RGB)*scale_factor # reorient image so that the color segment is in the final dimension if dimension == 0: im0_RGB = im0_RGB.transpose([2, 1, 0]) else: im0_RGB = im0_RGB.transpose([1, 2, 0]) if pdir_func == 'R': # reverse the color band order im0_RGB = im0_RGB[:, :, ::-1] return im0_RGB
def subaperture_generator(self, row_range, col_range, frames=None): # type: (tuple, tuple, Union[None, int, list, tuple, numpy.ndarray]) -> Generator[numpy.ndarray] """ Supplies a generator for the given row and column ranges and frames collection. **Note that this IGNORES the block_size parameter in fetching, and fetches the entire required block.** The full resolution data in the processing dimension is required, even if down-sampled by the row_range or col_range parameter. Parameters ---------- row_range : Tuple[int, int, int] The row range. col_range : Tuple[int, int, int] The column range. frames : None|int|list|tuple|numpy.ndarray The frame or frame collection. Returns ------- Generator[numpy.ndarray] """ def get_dimension_details(the_range): the_snip = -1 if the_range[2] < 0 else 1 t_full_range = (the_range[0], the_range[1], the_snip) t_full_size = the_range[1] - the_range[0] t_step = abs(the_range[2]) return t_full_range, t_full_size, t_step if self._fill is None: raise ValueError( 'Unable to proceed unless the index and dimension are set.') frames = self._parse_frame_argument(frames) if isinstance(frames, integer_types): frames = [ frames, ] if self.dimension == 0: # determine the full resolution block of data to fetch this_row_range, full_size, step = get_dimension_details(row_range) # fetch the necessary data block data = self.reader[ this_row_range[0]:this_row_range[1]:this_row_range[2], col_range[0]:col_range[1]:col_range[2], self.index] else: # determine the full resolution block of data to fetch this_col_range, full_size, step = get_dimension_details(col_range) # fetch the necessary data block, and transform to phase space data = self.reader[ row_range[0]:row_range[1]:row_range[2], this_col_range[0]:this_col_range[1]:this_col_range[2], self.index] # handle any nonsense data as 0 data[~numpy.isfinite(data)] = 0 # transform the data to phase space data = fftshift(fft(data, axis=self.dimension), axes=self.dimension) # define our frame collection frame_collection, output_resolution = frame_definition( full_size, frame_count=self.frame_count, aperture_fraction=self.aperture_fraction, fill=self.fill, method=self.method) # iterate over frames and generate the results for frame_index in frames: frame_def = frame_collection[int_func(frame_index)] this_subap_data = subaperture_processing_phase_history( data, frame_def, output_resolution=output_resolution, dimension=self.dimension) if step == 1: yield this_subap_data elif self.dimension == 0: yield this_subap_data[::step, :] else: yield this_subap_data[:, ::step]