Beispiel #1
0
    def get_sicd_collection(self):
        """
        Gets the list of sicd objects, one per polarimetric entry.

        Returns
        -------
        Tuple[SICDType]
        """

        nitf, collection_info = self._get_collection_info()
        image_creation = self._get_image_creation()
        image_data, geo_data = self._get_image_and_geo_data()
        position = self._get_position()
        grid = self._get_grid()
        radar_collection = self._get_radar_collection()
        timeline = self._get_timeline()
        image_formation = self._get_image_formation(timeline, radar_collection)
        scpcoa = self._get_scpcoa()
        rma = self._get_rma_adjust_grid(scpcoa, grid, image_data, position,
                                        collection_info)
        radiometric = self._get_radiometric(image_data, grid)
        base_sicd = SICDType(CollectionInfo=collection_info,
                             ImageCreation=image_creation,
                             GeoData=geo_data,
                             ImageData=image_data,
                             Position=position,
                             Grid=grid,
                             RadarCollection=radar_collection,
                             Timeline=timeline,
                             ImageFormation=image_formation,
                             SCPCOA=scpcoa,
                             RMA=rma,
                             Radiometric=radiometric)
        if len(nitf) > 0:
            base_sicd._NITF = nitf
        self._update_geo_data(base_sicd)
        base_sicd.derive()  # derive all the fields
        # now, make one copy per polarimetric entry, as appropriate
        tx_pols, tx_rcv_pols = self._get_polarizations()
        sicd_list = []
        for i, entry in enumerate(tx_rcv_pols):
            this_sicd = base_sicd.copy()
            this_sicd.ImageFormation.RcvChanProc.ChanIndices = [
                i + 1,
            ]
            this_sicd.ImageFormation.TxRcvPolarizationProc = \
                this_sicd.RadarCollection.RcvChannels[i].TxRcvPolarization
            this_sicd.populate_rniirs(override=False)
            sicd_list.append(this_sicd)
        return tuple(sicd_list)
Beispiel #2
0
    def get_sicd(self):
        """
        Get the SICD metadata for the image.

        Returns
        -------
        SICDType
        """
        def convert_string_dict(dict_in):
            # type: (dict) -> dict
            dict_out = OrderedDict()
            for key, val in dict_in.items():
                if isinstance(val, string_types):
                    dict_out[key] = val
                elif isinstance(val, int):
                    dict_out[key] = str(val)
                elif isinstance(val, float):
                    dict_out[key] = '{0:0.16G}'.format(val)
                else:
                    raise TypeError('Got unhandled type {}'.format(type(val)))
            return dict_out

        def extract_state_vector():
            # type: () -> (numpy.ndarray, numpy.ndarray, numpy.ndarray)
            vecs = collect['state']['state_vectors']
            times = numpy.zeros((len(vecs), ), dtype=numpy.float64)
            positions = numpy.zeros((len(vecs), 3), dtype=numpy.float64)
            velocities = numpy.zeros((len(vecs), 3), dtype=numpy.float64)
            for i, entry in enumerate(vecs):
                times[i] = get_seconds(parse_timestring(entry['time'],
                                                        precision='ns'),
                                       start_time,
                                       precision='ns')
                positions[i, :] = entry['position']
                velocities[i, :] = entry['velocity']
            return times, positions, velocities

        def get_collection_info():
            # type: () -> CollectionInfoType
            coll_name = collect['platform']
            start_dt = start_time.astype('datetime64[us]').astype(datetime)
            mode = collect['mode'].strip().lower()
            if mode == 'stripmap':
                radar_mode = RadarModeType(ModeType='STRIPMAP')
            elif mode == 'sliding_spotlight':
                radar_mode = RadarModeType(ModeType='DYNAMIC STRIPMAP')
            else:
                raise ValueError('Got unhandled radar mode {}'.format(mode))

            return CollectionInfoType(CollectorName=coll_name,
                                      CoreName='{}{}{}'.format(
                                          start_dt.strftime('%d%b%y').upper(),
                                          coll_name,
                                          start_dt.strftime('%H%M%S')),
                                      RadarMode=radar_mode,
                                      Classification='UNCLASSIFIED',
                                      CollectType='MONOSTATIC')

        def get_image_creation():
            # type: () -> ImageCreationType
            from sarpy.__about__ import __version__
            return ImageCreationType(
                Application=self._tiff_details.tags['Software'],
                DateTime=parse_timestring(
                    self._img_desc_tags['processing_time'], precision='us'),
                Profile='sarpy {}'.format(__version__),
                Site='Unknown')

        def get_image_data():
            # type: () -> ImageDataType
            img = collect['image']
            rows = int(
                img['columns'])  # capella uses flipped row/column definition?
            cols = int(img['rows'])
            if img['data_type'] == 'CInt16':
                pixel_type = 'RE16I_IM16I'
            else:
                raise ValueError('Got unhandled data_type {}'.format(
                    img['data_type']))

            scp_pixel = (int(0.5 * rows), int(0.5 * cols))
            if collect['radar']['pointing'] == 'left':
                scp_pixel = (rows - scp_pixel[0] - 1, cols - scp_pixel[1] - 1)

            return ImageDataType(NumRows=rows,
                                 NumCols=cols,
                                 FirstRow=0,
                                 FirstCol=0,
                                 PixelType=pixel_type,
                                 FullImage=(rows, cols),
                                 SCPPixel=scp_pixel)

        def get_geo_data():
            # type: () -> GeoDataType
            return GeoDataType(SCP=SCPType(
                ECF=collect['image']['center_pixel']['target_position']))

        def get_position():
            # type: () -> PositionType
            px, py, pz = fit_position_xvalidation(state_time,
                                                  state_position,
                                                  state_velocity,
                                                  max_degree=6)
            return PositionType(ARPPoly=XYZPolyType(X=px, Y=py, Z=pz))

        def get_grid():
            # type: () -> GridType

            img = collect['image']

            image_plane = 'OTHER'
            grid_type = 'PLANE'
            if self._img_desc_tags['product_type'] == 'SLC' and img[
                    'algorithm'] != 'backprojection':
                image_plane = 'SLANT'
                grid_type = 'RGZERO'

            coa_time = parse_timestring(img['center_pixel']['center_time'],
                                        precision='ns')
            row_imp_rsp_bw = 2 * bw / speed_of_light
            row = DirParamType(SS=img['pixel_spacing_column'],
                               ImpRespBW=row_imp_rsp_bw,
                               ImpRespWid=img['range_resolution'],
                               KCtr=2 * fc / speed_of_light,
                               DeltaK1=-0.5 * row_imp_rsp_bw,
                               DeltaK2=0.5 * row_imp_rsp_bw,
                               DeltaKCOAPoly=[
                                   [
                                       0.0,
                                   ],
                               ],
                               WgtType=WgtTypeType(
                                   WindowName=img['range_window']['name'],
                                   Parameters=convert_string_dict(
                                       img['range_window']['parameters'])))

            # get timecoa value
            timecoa_value = get_seconds(coa_time,
                                        start_time)  # TODO: constant?
            # find an approximation for zero doppler spacing - necessarily rough for backprojected images
            # find velocity at coatime
            arp_velocity = position.ARPPoly.derivative_eval(timecoa_value,
                                                            der_order=1)
            arp_speed = numpy.linalg.norm(arp_velocity)
            col_ss = img['pixel_spacing_row']
            dop_bw = img['processed_azimuth_bandwidth']
            # ss_zd_s = col_ss/arp_speed

            col = DirParamType(SS=col_ss,
                               ImpRespWid=img['azimuth_resolution'],
                               ImpRespBW=dop_bw / arp_speed,
                               KCtr=0,
                               WgtType=WgtTypeType(
                                   WindowName=img['azimuth_window']['name'],
                                   Parameters=convert_string_dict(
                                       img['azimuth_window']['parameters'])))

            # TODO: from Wade - account for numeric WgtFunct

            return GridType(ImagePlane=image_plane,
                            Type=grid_type,
                            TimeCOAPoly=[
                                [
                                    timecoa_value,
                                ],
                            ],
                            Row=row,
                            Col=col)

        def get_radar_colection():
            # type: () -> RadarCollectionType

            radar = collect['radar']
            freq_min = fc - 0.5 * bw
            return RadarCollectionType(
                TxPolarization=radar['transmit_polarization'],
                TxFrequency=TxFrequencyType(Min=freq_min, Max=freq_min + bw),
                Waveform=[
                    WaveformParametersType(
                        TxRFBandwidth=bw,
                        TxPulseLength=radar['pulse_duration'],
                        RcvDemodType='CHIRP',
                        ADCSampleRate=radar['sampling_frequency'],
                        TxFreqStart=freq_min)
                ],
                RcvChannels=[
                    ChanParametersType(TxRcvPolarization='{}:{}'.format(
                        radar['transmit_polarization'],
                        radar['receive_polarization']))
                ])

        def get_timeline():
            # type: () -> TimelineType
            prf = collect['radar']['prf'][0]['prf']
            return TimelineType(CollectStart=start_time,
                                CollectDuration=duration,
                                IPP=[
                                    IPPSetType(TStart=0,
                                               TEnd=duration,
                                               IPPStart=0,
                                               IPPEnd=duration * prf,
                                               IPPPoly=(0, prf)),
                                ])

        def get_image_formation():
            # type: () -> ImageFormationType

            radar = collect['radar']
            algo = collect['image']['algorithm'].upper()
            processings = None
            if algo == 'BACKPROJECTION':
                processings = [
                    ProcessingType(Type='Backprojected to DEM', Applied=True),
                ]
            if algo not in ('PFA', 'RMA', 'RGAZCOMP'):
                logging.warning(
                    'Image formation algorithm {} not one of the recognized SICD options, '
                    'being set to "OTHER".'.format(algo))
                algo = 'OTHER'

            return ImageFormationType(
                RcvChanProc=RcvChanProcType(NumChanProc=1, PRFScaleFactor=1),
                ImageFormAlgo=algo,
                TStartProc=0,
                TEndProc=duration,
                TxRcvPolarizationProc='{}:{}'.format(
                    radar['transmit_polarization'],
                    radar['receive_polarization']),
                TxFrequencyProc=TxFrequencyProcType(
                    MinProc=radar_collection.TxFrequency.Min,
                    MaxProc=radar_collection.TxFrequency.Max),
                STBeamComp='NO',
                ImageBeamComp='NO',
                AzAutofocus='NO',
                RgAutofocus='NO',
                Processings=processings)

        # TODO: From Wade - Radiometric is not suitable?

        # extract general use information
        collect = self._img_desc_tags['collect']
        start_time = parse_timestring(collect['start_timestamp'],
                                      precision='ns')
        end_time = parse_timestring(collect['stop_timestamp'], precision='ns')
        duration = get_seconds(end_time, start_time, precision='ns')
        state_time, state_position, state_velocity = extract_state_vector()
        bw = collect['radar']['pulse_bandwidth']
        fc = collect['radar']['center_frequency']

        # define the sicd elements
        collection_info = get_collection_info()
        image_creation = get_image_creation()
        image_data = get_image_data()
        geo_data = get_geo_data()
        position = get_position()
        grid = get_grid()
        radar_collection = get_radar_colection()
        timeline = get_timeline()
        image_formation = get_image_formation()

        sicd = SICDType(CollectionInfo=collection_info,
                        ImageCreation=image_creation,
                        ImageData=image_data,
                        GeoData=geo_data,
                        Position=position,
                        Grid=grid,
                        RadarCollection=radar_collection,
                        Timeline=timeline,
                        ImageFormation=image_formation)
        sicd.derive()

        # this would be a rough estimate - waiting for radiometric data
        # sicd.populate_rniirs(override=False)
        return sicd
Beispiel #3
0
    def get_sicd(self):
        """
        Gets the SICD structure.

        Returns
        -------
        Tuple[SICDType, tuple, tuple]
            The sicd structure, the data size argument, and the symmetry argument.
        """
        def get_collection_info():
            # type: () -> CollectionInfoType
            return CollectionInfoType(
                CollectorName=_stringify(hf['satellite_name'][()]),
                CoreName=_stringify(hf['product_name'][()]),
                CollectType='MONOSTATIC',
                Classification='UNCLASSIFIED',
                RadarMode=RadarModeType(
                    ModeType=_stringify(hf['acquisition_mode'][()]).upper(),
                    ModeID=_stringify(hf['product_type'][()])))

        def get_image_creation():
            # type: () -> ImageCreationType
            from sarpy.__about__ import __version__
            return ImageCreationType(
                Application='ICEYE_P_{}'.format(hf['processor_version'][()]),
                DateTime=_parse_time(hf['processing_time'][()]),
                Site='Unknown',
                Profile='sarpy {}'.format(__version__))

        def get_image_data():
            # type: () -> ImageDataType

            samp_prec = _stringify(hf['sample_precision'][()])
            if samp_prec.upper() == 'INT16':
                pixel_type = 'RE16I_IM16I'
            elif samp_prec.upper() == 'FLOAT32':
                pixel_type = 'RE32F_IM32F'
            else:
                raise ValueError(
                    'Got unhandled sample precision {}'.format(samp_prec))

            num_rows = int_func(number_of_range_samples)
            num_cols = int_func(number_of_azimuth_samples)
            scp_row = int_func(coord_center[0]) - 1
            scp_col = int_func(coord_center[1]) - 1
            if 0 < scp_col < num_rows - 1:
                if look_side == 'left':
                    scp_col = num_cols - scp_col - 1
            else:
                # early ICEYE processing bug led to nonsensical SCP
                scp_col = int_func(num_cols / 2.0)

            return ImageDataType(PixelType=pixel_type,
                                 NumRows=num_rows,
                                 NumCols=num_cols,
                                 FirstRow=0,
                                 FirstCol=0,
                                 FullImage=(num_rows, num_cols),
                                 SCPPixel=(scp_row, scp_col))

        def get_geo_data():
            # type: () -> GeoDataType
            # NB: the remainder will be derived.
            return GeoDataType(SCP=SCPType(
                LLH=[coord_center[2], coord_center[3], avg_scene_height]))

        def get_timeline():
            # type: () -> TimelineType

            acq_prf = hf['acquisition_prf'][()]
            return TimelineType(CollectStart=start_time,
                                CollectDuration=duration,
                                IPP=[
                                    IPPSetType(index=0,
                                               TStart=0,
                                               TEnd=duration,
                                               IPPStart=0,
                                               IPPEnd=int_func(
                                                   round(acq_prf * duration)),
                                               IPPPoly=[0, acq_prf]),
                                ])

        def get_position():
            # type: () -> PositionType
            # fetch the state information
            times_str = hf['state_vector_time_utc'][:, 0]
            times = numpy.zeros((times_str.shape[0], ), dtype='float64')
            positions = numpy.zeros((times.size, 3), dtype='float64')
            velocities = numpy.zeros((times.size, 3), dtype='float64')
            for i, entry in enumerate(times_str):
                times[i] = get_seconds(_parse_time(entry),
                                       start_time,
                                       precision='us')
            positions[:, 0], positions[:, 1], positions[:, 2] = hf[
                'posX'][:], hf['posY'][:], hf['posZ'][:]
            velocities[:, 0], velocities[:, 1], velocities[:, 2] = hf[
                'velX'][:], hf['velY'][:], hf['velZ'][:]
            # fir the the position polynomial using cross validation
            P_x, P_y, P_z = fit_position_xvalidation(times,
                                                     positions,
                                                     velocities,
                                                     max_degree=8)
            return PositionType(ARPPoly=XYZPolyType(X=P_x, Y=P_y, Z=P_z))

        def get_radar_collection():
            # type : () -> RadarCollection
            return RadarCollectionType(
                TxPolarization=tx_pol,
                TxFrequency=TxFrequencyType(Min=min_freq, Max=max_freq),
                Waveform=[
                    WaveformParametersType(
                        TxFreqStart=min_freq,
                        TxRFBandwidth=tx_bandwidth,
                        TxPulseLength=hf['chirp_duration'][()],
                        ADCSampleRate=hf['range_sampling_rate'][()],
                        RcvDemodType='CHIRP',
                        RcvFMRate=0,
                        index=1)
                ],
                RcvChannels=[
                    ChanParametersType(TxRcvPolarization=polarization, index=1)
                ])

        def get_image_formation():
            # type: () -> ImageFormationType
            return ImageFormationType(
                TxRcvPolarizationProc=polarization,
                ImageFormAlgo='RMA',
                TStartProc=0,
                TEndProc=duration,
                TxFrequencyProc=TxFrequencyProcType(MinProc=min_freq,
                                                    MaxProc=max_freq),
                STBeamComp='NO',
                ImageBeamComp='SV',
                AzAutofocus='NO',
                RgAutofocus='NO',
                RcvChanProc=RcvChanProcType(NumChanProc=1,
                                            PRFScaleFactor=1,
                                            ChanIndices=[
                                                1,
                                            ]),
            )

        def get_radiometric():
            # type: () -> RadiometricType
            return RadiometricType(BetaZeroSFPoly=[
                [
                    float(hf['calibration_factor'][()]),
                ],
            ])

        def calculate_drate_sf_poly():
            r_ca_coeffs = numpy.array([r_ca_scp, 1], dtype='float64')
            dop_rate_coeffs = hf['doppler_rate_coeffs'][:]
            # Prior to ICEYE 1.14 processor, absolute value of Doppler rate was
            # provided, not true Doppler rate. Doppler rate should always be negative
            if dop_rate_coeffs[0] > 0:
                dop_rate_coeffs *= -1
            dop_rate_poly = Poly1DType(Coefs=dop_rate_coeffs)
            # now adjust to create
            t_drate_ca_poly = dop_rate_poly.shift(t_0=zd_ref_time -
                                                  rg_time_scp,
                                                  alpha=2 / speed_of_light,
                                                  return_poly=False)
            return t_drate_ca_poly, -polynomial.polymul(
                t_drate_ca_poly, r_ca_coeffs) * speed_of_light / (
                    2 * center_freq * vm_ca_sq)

        def calculate_doppler_polys():
            # extract doppler centroid coefficients
            dc_estimate_coeffs = hf['dc_estimate_coeffs'][:]
            dc_time_str = hf['dc_estimate_time_utc'][:, 0]
            dc_zd_times = numpy.zeros((dc_time_str.shape[0], ),
                                      dtype='float64')
            for i, entry in enumerate(dc_time_str):
                dc_zd_times[i] = get_seconds(_parse_time(entry),
                                             start_time,
                                             precision='us')
            # create a sampled doppler centroid
            samples = 49  # copied from corresponding matlab, we just need enough for appropriate refitting
            # create doppler time samples
            diff_time_rg = first_pixel_time - zd_ref_time + \
                           numpy.linspace(0, number_of_range_samples/range_sampling_rate, samples)
            # doppler centroid samples definition
            dc_sample_array = numpy.zeros((samples, dc_zd_times.size),
                                          dtype='float64')
            for i, coeffs in enumerate(dc_estimate_coeffs):
                dc_sample_array[:,
                                i] = polynomial.polyval(diff_time_rg, coeffs)
            # create arrays for range/azimuth from scp in meters
            azimuth_scp_m, range_scp_m = numpy.meshgrid(
                col_ss * (dc_zd_times - zd_time_scp) / ss_zd_s,
                (diff_time_rg + zd_ref_time - rg_time_scp) * speed_of_light /
                2)

            # fit the doppler centroid sample array
            x_order = min(3, range_scp_m.shape[0] - 1)
            y_order = min(3, range_scp_m.shape[1] - 1)

            t_dop_centroid_poly, residuals, rank, sing_values = two_dim_poly_fit(
                range_scp_m,
                azimuth_scp_m,
                dc_sample_array,
                x_order=x_order,
                y_order=y_order,
                x_scale=1e-3,
                y_scale=1e-3,
                rcond=1e-40)
            logging.info(
                'The dop_centroid_poly fit details:\nroot mean square '
                'residuals = {}\nrank = {}\nsingular values = {}'.format(
                    residuals, rank, sing_values))

            # define and fit the time coa array
            doppler_rate_sampled = polynomial.polyval(azimuth_scp_m,
                                                      drate_ca_poly)
            time_coa = dc_zd_times + dc_sample_array / doppler_rate_sampled
            t_time_coa_poly, residuals, rank, sing_values = two_dim_poly_fit(
                range_scp_m,
                azimuth_scp_m,
                time_coa,
                x_order=x_order,
                y_order=y_order,
                x_scale=1e-3,
                y_scale=1e-3,
                rcond=1e-40)
            logging.info(
                'The time_coa_poly fit details:\nroot mean square '
                'residuals = {}\nrank = {}\nsingular values = {}'.format(
                    residuals, rank, sing_values))
            return t_dop_centroid_poly, t_time_coa_poly

        def get_rma():
            # type: () -> RMAType
            dop_centroid_poly = Poly2DType(Coefs=dop_centroid_poly_coeffs)
            dop_centroid_coa = True
            if collect_info.RadarMode.ModeType == 'SPOTLIGHT':
                dop_centroid_poly = None
                dop_centroid_coa = None
            # NB: DRateSFPoly is defined as a function of only range - reshape appropriately
            inca = INCAType(
                R_CA_SCP=r_ca_scp,
                FreqZero=center_freq,
                DRateSFPoly=Poly2DType(
                    Coefs=numpy.reshape(drate_sf_poly_coefs, (-1, 1))),
                DopCentroidPoly=dop_centroid_poly,
                DopCentroidCOA=dop_centroid_coa,
                TimeCAPoly=Poly1DType(Coefs=time_ca_poly_coeffs))
            return RMAType(RMAlgoType='OMEGA_K', INCA=inca)

        def get_grid():
            # type: () -> GridType
            time_coa_poly = Poly2DType(Coefs=time_coa_poly_coeffs)
            if collect_info.RadarMode.ModeType == 'SPOTLIGHT':
                time_coa_poly = Poly2DType(Coefs=[
                    [
                        float(time_coa_poly_coeffs[0, 0]),
                    ],
                ])

            row_win = _stringify(hf['window_function_range'][()])
            if row_win == 'NONE':
                row_win = 'UNIFORM'
            row = DirParamType(SS=row_ss,
                               Sgn=-1,
                               KCtr=2 * center_freq / speed_of_light,
                               ImpRespBW=2 * tx_bandwidth / speed_of_light,
                               DeltaKCOAPoly=Poly2DType(Coefs=[[
                                   0,
                               ]]),
                               WgtType=WgtTypeType(WindowName=row_win))
            col_win = _stringify(hf['window_function_azimuth'][()])
            if col_win == 'NONE':
                col_win = 'UNIFORM'
            col = DirParamType(
                SS=col_ss,
                Sgn=-1,
                KCtr=0,
                ImpRespBW=col_imp_res_bw,
                WgtType=WgtTypeType(WindowName=col_win),
                DeltaKCOAPoly=Poly2DType(Coefs=dop_centroid_poly_coeffs *
                                         ss_zd_s / col_ss))
            return GridType(Type='RGZERO',
                            ImagePlane='SLANT',
                            TimeCOAPoly=time_coa_poly,
                            Row=row,
                            Col=col)

        def correct_scp():
            scp_pixel = sicd.ImageData.SCPPixel.get_array()
            scp_ecf = sicd.project_image_to_ground(scp_pixel,
                                                   projection_type='HAE')
            sicd.update_scp(scp_ecf, coord_system='ECF')

        with h5py.File(self._file_name, 'r') as hf:
            # some common use variables
            look_side = _stringify(hf['look_side'][()])
            coord_center = hf['coord_center'][:]
            avg_scene_height = float(hf['avg_scene_height'][()])
            start_time = _parse_time(hf['acquisition_start_utc'][()])
            end_time = _parse_time(hf['acquisition_end_utc'][()])
            duration = get_seconds(end_time, start_time, precision='us')

            center_freq = float(hf['carrier_frequency'][()])
            tx_bandwidth = float(hf['chirp_bandwidth'][()])
            min_freq = center_freq - 0.5 * tx_bandwidth
            max_freq = center_freq + 0.5 * tx_bandwidth

            pol_temp = _stringify(hf['polarization'][()])
            tx_pol = pol_temp[0]
            rcv_pol = pol_temp[1]
            polarization = tx_pol + ':' + rcv_pol

            first_pixel_time = float(hf['first_pixel_time'][()])
            near_range = first_pixel_time * speed_of_light / 2
            number_of_range_samples = float(hf['number_of_range_samples'][()])
            number_of_azimuth_samples = float(
                hf['number_of_azimuth_samples'][()])
            range_sampling_rate = float(hf['range_sampling_rate'][()])
            row_ss = speed_of_light / (2 * range_sampling_rate)

            # define the sicd elements
            collect_info = get_collection_info()
            image_creation = get_image_creation()
            image_data = get_image_data()
            geo_data = get_geo_data()
            timeline = get_timeline()
            position = get_position()
            radar_collection = get_radar_collection()
            image_formation = get_image_formation()
            radiometric = get_radiometric()

            # calculate some zero doppler parameters
            ss_zd_s = float(hf['azimuth_time_interval'][()])
            if look_side == 'left':
                ss_zd_s *= -1
                zero_doppler_left = _parse_time(hf['zerodoppler_end_utc'][()])
            else:
                zero_doppler_left = _parse_time(
                    hf['zerodoppler_start_utc'][()])
            dop_bw = hf['total_processed_bandwidth_azimuth'][()]
            zd_time_scp = get_seconds(zero_doppler_left, start_time, precision='us') + \
                          image_data.SCPPixel.Col*ss_zd_s
            zd_ref_time = first_pixel_time + number_of_range_samples / (
                2 * range_sampling_rate)
            vel_scp = position.ARPPoly.derivative_eval(zd_time_scp,
                                                       der_order=1)
            vm_ca_sq = numpy.sum(vel_scp * vel_scp)
            rg_time_scp = first_pixel_time + image_data.SCPPixel.Row / range_sampling_rate
            r_ca_scp = rg_time_scp * speed_of_light / 2
            # calculate the doppler rate sf polynomial
            drate_ca_poly, drate_sf_poly_coefs = calculate_drate_sf_poly()

            # calculate some doppler dependent grid parameters
            col_ss = float(
                numpy.sqrt(vm_ca_sq) * abs(ss_zd_s) * drate_sf_poly_coefs[0])
            col_imp_res_bw = dop_bw * abs(ss_zd_s) / col_ss
            time_ca_poly_coeffs = [zd_time_scp, ss_zd_s / col_ss]

            # calculate the doppler polynomials
            dop_centroid_poly_coeffs, time_coa_poly_coeffs = calculate_doppler_polys(
            )

            # finish definition of sicd elements
            rma = get_rma()
            grid = get_grid()
            sicd = SICDType(CollectionInfo=collect_info,
                            ImageCreation=image_creation,
                            ImageData=image_data,
                            GeoData=geo_data,
                            Timeline=timeline,
                            Position=position,
                            RadarCollection=radar_collection,
                            ImageFormation=image_formation,
                            Radiometric=radiometric,
                            RMA=rma,
                            Grid=grid)
        # adjust the scp location
        correct_scp()
        # derive sicd fields
        sicd.derive()
        # TODO: RNIIRS?
        data_size = (image_data.NumCols, image_data.NumRows)
        symmetry = (True, False,
                    True) if look_side == 'left' else (False, False, True)
        return sicd, data_size, symmetry
Beispiel #4
0
    def get_sicd(self):
        """
        Get the SICD metadata for the image.

        Returns
        -------
        SICDType
        """
        def convert_string_dict(dict_in):
            # type: (dict) -> dict
            dict_out = OrderedDict()
            for key, val in dict_in.items():
                if isinstance(val, str):
                    dict_out[key] = val
                elif isinstance(val, int):
                    dict_out[key] = str(val)
                elif isinstance(val, float):
                    dict_out[key] = '{0:0.17G}'.format(val)
                else:
                    raise TypeError('Got unhandled type {}'.format(type(val)))
            return dict_out

        def extract_state_vector():
            # type: () -> (numpy.ndarray, numpy.ndarray, numpy.ndarray)
            vecs = collect['state']['state_vectors']
            times = numpy.zeros((len(vecs), ), dtype=numpy.float64)
            positions = numpy.zeros((len(vecs), 3), dtype=numpy.float64)
            velocities = numpy.zeros((len(vecs), 3), dtype=numpy.float64)
            for i, entry in enumerate(vecs):
                times[i] = get_seconds(parse_timestring(entry['time'],
                                                        precision='ns'),
                                       start_time,
                                       precision='ns')
                positions[i, :] = entry['position']
                velocities[i, :] = entry['velocity']
            return times, positions, velocities

        def get_radar_parameter(name):
            if name in radar:
                return radar[name]
            if len(radar_time_varying) > 0:
                element = radar_time_varying[0]
                if name in element:
                    return element[name]
            raise ValueError(
                'Unable to determine radar parameter `{}`'.format(name))

        def get_collection_info():
            # type: () -> CollectionInfoType
            coll_name = collect['platform']
            mode = collect['mode'].strip().lower()
            if mode == 'stripmap':
                radar_mode = RadarModeType(ModeType='STRIPMAP', ModeID=mode)
            elif mode == 'spotlight':
                radar_mode = RadarModeType(ModeType='SPOTLIGHT', ModeID=mode)
            elif mode == 'sliding_spotlight':
                radar_mode = RadarModeType(ModeType='DYNAMIC STRIPMAP',
                                           ModeID=mode)
            else:
                raise ValueError('Got unhandled radar mode {}'.format(mode))

            return CollectionInfoType(CollectorName=coll_name,
                                      CoreName=collect['collect_id'],
                                      RadarMode=radar_mode,
                                      Classification='UNCLASSIFIED',
                                      CollectType='MONOSTATIC')

        def get_image_creation():
            # type: () -> ImageCreationType
            from sarpy.__about__ import __version__
            return ImageCreationType(
                Application=self._tiff_details.tags['Software'],
                DateTime=parse_timestring(
                    self._img_desc_tags['processing_time'], precision='us'),
                Profile='sarpy {}'.format(__version__),
                Site='Unknown')

        def get_image_data():
            # type: () -> ImageDataType
            rows = int(
                img['columns'])  # capella uses flipped row/column definition?
            cols = int(img['rows'])
            if img['data_type'] == 'CInt16':
                pixel_type = 'RE16I_IM16I'
            else:
                raise ValueError('Got unhandled data_type {}'.format(
                    img['data_type']))

            scp_pixel = (int(0.5 * rows), int(0.5 * cols))
            if radar['pointing'] == 'left':
                scp_pixel = (rows - scp_pixel[0] - 1, cols - scp_pixel[1] - 1)

            return ImageDataType(NumRows=rows,
                                 NumCols=cols,
                                 FirstRow=0,
                                 FirstCol=0,
                                 PixelType=pixel_type,
                                 FullImage=(rows, cols),
                                 SCPPixel=scp_pixel)

        def get_geo_data():
            # type: () -> GeoDataType
            return GeoDataType(SCP=SCPType(
                ECF=img['center_pixel']['target_position']))

        def get_position():
            # type: () -> PositionType
            px, py, pz = fit_position_xvalidation(state_time,
                                                  state_position,
                                                  state_velocity,
                                                  max_degree=8)
            return PositionType(ARPPoly=XYZPolyType(X=px, Y=py, Z=pz))

        def get_grid():
            # type: () -> GridType

            def get_weight(window_dict):
                window_name = window_dict['name']
                if window_name.lower() == 'rectangular':
                    return WgtTypeType(WindowName='UNIFORM'), None
                elif window_name.lower() == 'avci-nacaroglu':
                    return WgtTypeType(
                        WindowName=window_name.upper(),
                        Parameters=convert_string_dict(window_dict['parameters'])), \
                           avci_nacaroglu_window(64, alpha=window_dict['parameters']['alpha'])
                else:
                    return WgtTypeType(WindowName=window_name,
                                       Parameters=convert_string_dict(
                                           window_dict['parameters'])), None

            image_plane = 'SLANT'
            grid_type = 'RGZERO'

            coa_time = parse_timestring(img['center_pixel']['center_time'],
                                        precision='ns')
            row_bw = img.get('processed_range_bandwidth', bw)
            row_imp_rsp_bw = 2 * row_bw / speed_of_light
            row_wgt, row_wgt_funct = get_weight(img['range_window'])
            row = DirParamType(SS=img['image_geometry']['delta_range_sample'],
                               Sgn=-1,
                               ImpRespBW=row_imp_rsp_bw,
                               ImpRespWid=img['range_resolution'],
                               KCtr=2 * fc / speed_of_light,
                               DeltaK1=-0.5 * row_imp_rsp_bw,
                               DeltaK2=0.5 * row_imp_rsp_bw,
                               DeltaKCOAPoly=[
                                   [
                                       0.0,
                                   ],
                               ],
                               WgtFunct=row_wgt_funct,
                               WgtType=row_wgt)

            # get timecoa value
            timecoa_value = get_seconds(coa_time, start_time)
            # find an approximation for zero doppler spacing - necessarily rough for backprojected images
            col_ss = img['pixel_spacing_row']
            dop_bw = img['processed_azimuth_bandwidth']

            col_wgt, col_wgt_funct = get_weight(img['azimuth_window'])
            col = DirParamType(SS=col_ss,
                               Sgn=-1,
                               ImpRespWid=img['azimuth_resolution'],
                               ImpRespBW=dop_bw * abs(ss_zd_s) / col_ss,
                               KCtr=0,
                               WgtFunct=col_wgt_funct,
                               WgtType=col_wgt)

            # TODO:
            #   column deltakcoa poly - it's in there at ["image"]["frequency_doppler_centroid_polynomial"]

            return GridType(ImagePlane=image_plane,
                            Type=grid_type,
                            TimeCOAPoly=[
                                [
                                    timecoa_value,
                                ],
                            ],
                            Row=row,
                            Col=col)

        def get_radar_collection():
            # type: () -> RadarCollectionType

            freq_min = fc - 0.5 * bw
            return RadarCollectionType(
                TxPolarization=radar['transmit_polarization'],
                TxFrequency=(freq_min, freq_min + bw),
                Waveform=[
                    WaveformParametersType(
                        TxRFBandwidth=bw,
                        TxPulseLength=get_radar_parameter('pulse_duration'),
                        RcvDemodType='CHIRP',
                        ADCSampleRate=radar['sampling_frequency'],
                        TxFreqStart=freq_min)
                ],
                RcvChannels=[
                    ChanParametersType(TxRcvPolarization='{}:{}'.format(
                        radar['transmit_polarization'],
                        radar['receive_polarization']))
                ])

        def get_timeline():
            # type: () -> TimelineType
            prf = radar['prf'][0]['prf']
            return TimelineType(CollectStart=start_time,
                                CollectDuration=duration,
                                IPP=[
                                    IPPSetType(TStart=0,
                                               TEnd=duration,
                                               IPPStart=0,
                                               IPPEnd=duration * prf,
                                               IPPPoly=(0, prf)),
                                ])

        def get_image_formation():
            # type: () -> ImageFormationType

            algo = img['algorithm'].upper()
            processings = None
            if algo == 'BACKPROJECTION':
                processings = [
                    ProcessingType(Type='Backprojected to DEM', Applied=True),
                ]
            else:
                logger.warning('Got unexpected algorithm, the results for the '
                               'sicd struture might be unexpected')

            if algo not in ('PFA', 'RMA', 'RGAZCOMP'):
                logger.warning(
                    'Image formation algorithm {} not one of the recognized SICD options, '
                    'being set to "OTHER".'.format(algo))
                algo = 'OTHER'

            return ImageFormationType(
                RcvChanProc=RcvChanProcType(NumChanProc=1, PRFScaleFactor=1),
                ImageFormAlgo=algo,
                TStartProc=0,
                TEndProc=duration,
                TxRcvPolarizationProc='{}:{}'.format(
                    radar['transmit_polarization'],
                    radar['receive_polarization']),
                TxFrequencyProc=(radar_collection.TxFrequency.Min,
                                 radar_collection.TxFrequency.Max),
                STBeamComp='NO',
                ImageBeamComp='NO',
                AzAutofocus='NO',
                RgAutofocus='NO',
                Processings=processings)

        def get_rma():
            # type: () -> RMAType
            img_geometry = img['image_geometry']
            near_range = img_geometry['range_to_first_sample']
            center_time = parse_timestring(img['center_pixel']['center_time'],
                                           precision='us')
            first_time = parse_timestring(img_geometry['first_line_time'],
                                          precision='us')
            zd_time_scp = get_seconds(center_time, first_time, 'us')
            r_ca_scp = near_range + image_data.SCPPixel.Row * grid.Row.SS
            time_ca_poly = numpy.array(
                [zd_time_scp, -look * ss_zd_s / grid.Col.SS], dtype='float64')

            timecoa_value = get_seconds(center_time, start_time)
            arp_velocity = position.ARPPoly.derivative_eval(timecoa_value,
                                                            der_order=1)
            vm_ca = numpy.linalg.norm(arp_velocity)
            inca = INCAType(R_CA_SCP=r_ca_scp,
                            FreqZero=fc,
                            TimeCAPoly=time_ca_poly,
                            DRateSFPoly=[
                                [1 / (vm_ca * ss_zd_s / grid.Col.SS)],
                            ])

            return RMAType(RMAlgoType='RG_DOP', INCA=inca)

        def get_radiometric():
            # type: () -> Union[None, RadiometricType]
            if img['radiometry'].lower() != 'beta_nought':
                logger.warning('Got unrecognized Capella radiometry {},\n\t'
                               'skipping the radiometric metadata'.format(
                                   img['radiometry']))
                return None

            return RadiometricType(BetaZeroSFPoly=[
                [
                    img['scale_factor']**2,
                ],
            ])

        def add_noise():
            if sicd.Radiometric is None:
                return

            nesz_raw = numpy.array(img['nesz_polynomial']['coefficients'],
                                   dtype='float64')
            test_value = polynomial.polyval(rma.INCA.R_CA_SCP, nesz_raw)
            if abs(test_value - img['nesz_peak']) > 100:
                # this polynomial reversed in early versions, so reverse if evaluated results are nonsense
                nesz_raw = nesz_raw[::-1]
            nesz_poly_raw = Poly2DType(Coefs=numpy.reshape(nesz_raw, (-1, 1)))
            noise_coeffs = nesz_poly_raw.shift(-rma.INCA.R_CA_SCP,
                                               1,
                                               0,
                                               1,
                                               return_poly=False)
            # this is in nesz units, so shift to absolute units
            noise_coeffs[0] -= 10 * numpy.log10(
                sicd.Radiometric.SigmaZeroSFPoly[0, 0])
            sicd.Radiometric.NoiseLevel = NoiseLevelType_(
                NoiseLevelType='ABSOLUTE', NoisePoly=noise_coeffs)

        # extract general use information
        collect = self._img_desc_tags['collect']
        img = collect['image']
        radar = collect['radar']
        radar_time_varying = radar.get('time_varying_parameters', [])

        start_time = parse_timestring(collect['start_timestamp'],
                                      precision='ns')
        end_time = parse_timestring(collect['stop_timestamp'], precision='ns')
        duration = get_seconds(end_time, start_time, precision='ns')
        state_time, state_position, state_velocity = extract_state_vector()
        bw = get_radar_parameter('pulse_bandwidth')
        fc = get_radar_parameter('center_frequency')
        ss_zd_s = img['image_geometry']['delta_line_time']
        look = -1 if radar['pointing'] == 'right' else 1

        # define the sicd elements
        collection_info = get_collection_info()
        image_creation = get_image_creation()
        image_data = get_image_data()
        geo_data = get_geo_data()
        position = get_position()
        grid = get_grid()
        radar_collection = get_radar_collection()
        timeline = get_timeline()
        image_formation = get_image_formation()
        rma = get_rma()
        radiometric = get_radiometric()

        sicd = SICDType(CollectionInfo=collection_info,
                        ImageCreation=image_creation,
                        ImageData=image_data,
                        GeoData=geo_data,
                        Position=position,
                        Grid=grid,
                        RadarCollection=radar_collection,
                        Timeline=timeline,
                        ImageFormation=image_formation,
                        RMA=rma,
                        Radiometric=radiometric)
        sicd.derive()

        add_noise()
        sicd.populate_rniirs(override=False)
        return sicd