class J2KSubtype(Serializable): """ The Jpeg 2000 subtype. """ _fields = ('NumWaveletLevels', 'NumBands', 'LayerInfo') _required = ('NumWaveletLevels', 'NumBands') _collections_tags = {'LayerInfo': {'array': True, 'child_tag': 'Bitrate', 'size_attribute': 'numLayers'}} _numeric_format = {'LayerInfo': FLOAT_FORMAT} # Descriptor NumWaveletLevels = IntegerDescriptor( 'NumWaveletLevels', _required, strict=DEFAULT_STRICT, docstring='') # type: int NumBands = IntegerDescriptor( 'NumBands', _required, strict=DEFAULT_STRICT, docstring='') # type: int LayerInfo = FloatArrayDescriptor( 'LayerInfo', _collections_tags, _required, strict=DEFAULT_STRICT, docstring='Original Layer Information. This is an array of bit rate target associated with each ' 'layer. It may happen that the bit rate was not achieved due to data characteristics. ' '**Note -** for JPEG 2000 numerically loss-less quality, the bit rate for the final layer is ' 'an expected value, based on performance.') # type: Union[None, numpy.ndarray] def __init__(self, NumWaveletLevels=None, NumBands=None, LayerInfo=None, **kwargs): """ Parameters ---------- NumWaveletLevels : int NumBands : int LayerInfo : None|numpy.ndarray|list|tuple kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumWaveletLevels = NumWaveletLevels self.NumBands = NumBands self.LayerInfo = LayerInfo super(J2KSubtype, self).__init__(**kwargs)
class DRAHistogramOverridesType(Serializable): """ Dynamic range adjustment overide parameters. """ _fields = ('ClipMin', 'ClipMax') _required = ('ClipMin', 'ClipMax') # Descriptor ClipMin = IntegerDescriptor( 'ClipMin', _required, strict=DEFAULT_STRICT, docstring= 'Suggested override for the lower end-point of the display histogram in the ' 'ELT DRA application. Referred to as Pmin in SIPS documentation.' ) # type: int ClipMax = IntegerDescriptor( 'ClipMax', _required, strict=DEFAULT_STRICT, docstring= 'Suggested override for the upper end-point of the display histogram in the ' 'ELT DRA application. Referred to as Pmax in SIPS documentation.' ) # type: int def __init__(self, ClipMin=None, ClipMax=None, **kwargs): """ Parameters ---------- ClipMin : int ClipMax : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.ClipMin = ClipMin self.ClipMax = ClipMax super(DRAHistogramOverridesType, self).__init__(**kwargs)
class ArraySizeType(Serializable): """ Parameters that define the array sizes. """ _fields = ('NumVectors', 'NumSamples') _required = ('NumVectors', 'NumSamples') # descriptors NumVectors = IntegerDescriptor( 'NumVectors', _required, strict=DEFAULT_STRICT, bounds=(1, None), docstring='Number of slow time vectors in the PHD array in this channel.' ) # type: int NumSamples = IntegerDescriptor( 'NumSamples', _required, strict=DEFAULT_STRICT, bounds=(1, None), docstring= 'Number of samples per vector in the PHD array in this channel.' ) # type: int def __init__(self, NumVectors=None, NumSamples=None, **kwargs): """ Parameters ---------- NumVectors : int NumSamples : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumVectors = NumVectors self.NumSamples = NumSamples super(ArraySizeType, self).__init__(**kwargs)
class YDirectionType(Serializable): """The Y direction of the collect""" _fields = ('UVectECF', 'SampleSpacing', 'NumSamples', 'FirstSample') _required = _fields _numeric_format = {'SampleSpacing': FLOAT_FORMAT, } # descriptors UVectECF = UnitVectorDescriptor( 'UVectECF', XYZType, _required, strict=DEFAULT_STRICT, docstring='The unit vector in the Y direction.') # type: XYZType SampleSpacing = FloatDescriptor( 'SampleSpacing', _required, strict=DEFAULT_STRICT, docstring='The collection sample spacing in the Y direction in meters.') # type: float NumSamples = IntegerDescriptor( 'NumSamples', _required, strict=DEFAULT_STRICT, docstring='The number of samples in the Y direction.') # type: int FirstSample = IntegerDescriptor( 'FirstSample', _required, strict=DEFAULT_STRICT, docstring='The first sample index.') # type: int def __init__(self, UVectECF=None, SampleSpacing=None, NumSamples=None, FirstSample=None, **kwargs): """ Parameters ---------- UVectECF : XYZType|numpy.ndarray|list|tuple SampleSpacing : float NumSamples : int FirstSample : int kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.UVectECF = UVectECF self.SampleSpacing = SampleSpacing self.NumSamples = NumSamples self.FirstSample = FirstSample super(YDirectionType, self).__init__(**kwargs)
class MatchCollectionType(Serializable): """The match collection type.""" _fields = ('CoreName', 'MatchIndex', 'Parameters') _required = ('CoreName', ) _collections_tags = { 'Parameters': { 'array': False, 'child_tag': 'Parameter' } } # descriptors CoreName = StringDescriptor( 'CoreName', _required, strict=DEFAULT_STRICT, docstring='Unique identifier for the match type.') # type: str MatchIndex = IntegerDescriptor( 'MatchIndex', _required, strict=DEFAULT_STRICT, docstring='Collection sequence index for the match collection, assuming ' 'that this makes sense.') # type: int Parameters = ParametersDescriptor( 'Parameters', _collections_tags, _required, strict=DEFAULT_STRICT, docstring='The match parameters.') # type: ParametersCollection def __init__(self, CoreName=None, MatchIndex=None, Parameters=None, **kwargs): """ Parameters ---------- CoreName : str MatchIndex : int Parameters : ParametersCollection|dict kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.CoreName = CoreName self.MatchIndex = MatchIndex self.Parameters = Parameters super(MatchCollectionType, self).__init__(**kwargs)
class TxStepType(Serializable): """ Transmit sequence step details. """ _fields = ('WFIndex', 'TxPolarization', 'index') _required = ('index', ) _set_as_attribute = ('index', ) # descriptors WFIndex = IntegerDescriptor( 'WFIndex', _required, strict=DEFAULT_STRICT, docstring='The waveform number for this step.') # type: int TxPolarization = StringEnumDescriptor( 'TxPolarization', POLARIZATION2_VALUES, _required, strict=DEFAULT_STRICT, docstring='Transmit signal polarization for this step.') # type: str index = IntegerDescriptor( 'index', _required, strict=DEFAULT_STRICT, docstring='The step index') # type: int def __init__(self, WFIndex=None, TxPolarization=None, index=None, **kwargs): """ Parameters ---------- WFIndex : int TxPolarization : str index : int kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.WFIndex = WFIndex self.TxPolarization = TxPolarization self.index = index super(TxStepType, self).__init__(**kwargs)
class IAYExtentType(Serializable): """ Increasing sample index is in the +IAY direction. """ _fields = ('SampleSpacing', 'FirstSample', 'NumSamples') _required = _fields _numeric_format = {'SampleSpacing': '0.17G'} # descriptors SampleSpacing = FloatDescriptor( 'SampleSpacing', _required, strict=DEFAULT_STRICT, bounds=(0, None), docstring='Sample spacing, in meters.') # type: float FirstSample = IntegerDescriptor( 'FirstSample', _required, strict=DEFAULT_STRICT, docstring='Index of the first sample.') # type: int NumSamples = IntegerDescriptor( 'NumSamples', _required, strict=DEFAULT_STRICT, bounds=(1, None), docstring='Number of samples.') # type: int def __init__(self, SampleSpacing=None, FirstSample=None, NumSamples=None, **kwargs): """ Parameters ---------- SampleSpacing : float FirstSample : int NumSamples : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.SampleSpacing = SampleSpacing self.FirstSample = FirstSample self.NumSamples = NumSamples super(IAYExtentType, self).__init__(**kwargs)
class PredefinedFilterType(Serializable): """ The predefined filter type. """ _fields = ('DatabaseName', 'FilterFamily', 'FilterMember') _required = () # Descriptor DatabaseName = StringEnumDescriptor( 'DatabaseName', ('BILINEAR', 'CUBIC', 'LAGRANGE', 'NEAREST NEIGHBOR'), _required, strict=DEFAULT_STRICT, docstring='The filter name.') # type: str FilterFamily = IntegerDescriptor( 'FilterFamily', _required, strict=DEFAULT_STRICT, docstring='The filter family number.') # type: int FilterMember = IntegerDescriptor( 'FilterMember', _required, strict=DEFAULT_STRICT, docstring='The filter member number.') # type: int def __init__(self, DatabaseName=None, FilterFamily=None, FilterMember=None, **kwargs): """ Parameters ---------- DatabaseName : None|str FilterFamily : None|int FilterMember : None|int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.DatabaseName = DatabaseName self.FilterFamily = FilterFamily self.FilterMember = FilterMember super(PredefinedFilterType, self).__init__(**kwargs)
class PositionalAccuracyType(Serializable): """ Describes the horizontal and vertical point and regional information for the DED. """ _fields = ('NumRegions', 'AbsoluteAccuracy', 'PointToPointAccuracy') _required = ('NumRegions', 'AbsoluteAccuracy', 'PointToPointAccuracy') # Descriptor NumRegions = IntegerDescriptor( 'NumRegions', _required, strict=DEFAULT_STRICT, docstring='Number of positional accuracy regions.') # type: int AbsoluteAccuracy = SerializableDescriptor( 'AbsoluteAccuracy', AccuracyType, _required, strict=DEFAULT_STRICT, docstring='') # type: AccuracyType PointToPointAccuracy = SerializableDescriptor( 'PointToPointAccuracy', AccuracyType, _required, strict=DEFAULT_STRICT, docstring='') # type: AccuracyType def __init__(self, NumRegions=None, AbsoluteAccuracy=None, PointToPointAccuracy=None, **kwargs): """ Parameters ---------- NumRegions : int AbsoluteAccuracy : AccuracyType PointToPointAccuracy : AccuracyType kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumRegions = NumRegions self.AbsoluteAccuracy = AbsoluteAccuracy self.PointToPointAccuracy = PointToPointAccuracy super(PositionalAccuracyType, self).__init__(**kwargs)
class PredefinedLookupType(Serializable): """ The predefined lookup table type. Allows for reference **either** by name, or family/member id number. """ _fields = ('DatabaseName', 'RemapFamily', 'RemapMember') _required = () # Descriptor DatabaseName = StringDescriptor( 'DatabaseName', _required, strict=DEFAULT_STRICT, docstring='Database name of LUT to use.') # type: str RemapFamily = IntegerDescriptor( 'RemapFamily', _required, strict=DEFAULT_STRICT, docstring='The lookup family number.') # type: int RemapMember = IntegerDescriptor( 'RemapMember', _required, strict=DEFAULT_STRICT, docstring='The lookup member number.') # type: int def __init__(self, DatabaseName=None, RemapFamily=None, RemapMember=None, **kwargs): """ Parameters ---------- DatabaseName : None|str RemapFamily : None|int RemapMember : None|int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.DatabaseName = DatabaseName self.RemapFamily = RemapFamily self.RemapMember = RemapMember super(PredefinedLookupType, self).__init__(**kwargs)
class InteractiveProcessingType(Serializable): """ The interactive processing information. """ _fields = ( 'GeometricTransform', 'SharpnessEnhancement', 'ColorSpaceTransform', 'DynamicRangeAdjustment', 'TonalTransferCurve', 'band') _required = ( 'GeometricTransform', 'SharpnessEnhancement', 'DynamicRangeAdjustment', 'band') _set_as_attribute = ('band', ) # Descriptor GeometricTransform = SerializableDescriptor( 'GeometricTransform', GeometricTransformType, _required, strict=DEFAULT_STRICT, docstring='The geometric transform element is used to perform various geometric distortions ' 'to each band of image data. These distortions include image ' 'chipping, scaling, rotation, shearing, etc.') # type: GeometricTransformType SharpnessEnhancement = SerializableDescriptor( 'SharpnessEnhancement', SharpnessEnhancementType, _required, strict=DEFAULT_STRICT, docstring='Sharpness enhancement.') # type: SharpnessEnhancementType ColorSpaceTransform = SerializableDescriptor( 'ColorSpaceTransform', ColorSpaceTransformType, _required, strict=DEFAULT_STRICT, docstring='Color space transform.') # type: ColorSpaceTransformType DynamicRangeAdjustment = SerializableDescriptor( 'DynamicRangeAdjustment', DynamicRangeAdjustmentType, _required, strict=DEFAULT_STRICT, docstring='Specifies the recommended ELT DRA overrides.') # type: DynamicRangeAdjustmentType TonalTransferCurve = SerializableDescriptor( 'TonalTransferCurve', NewLookupTableType, _required, strict=DEFAULT_STRICT, docstring="The 1-D LUT element uses one or more 1-D LUTs to stretch or compress tone data " "in valorous regions within a digital image's dynamic range. 1-D LUT can be " "implemented using a Tonal Transfer Curve (TTC). There are 12 families of TTCs " "- Range = [0, 11]. There are 64 members for each " "family - Range=[0, 63].") # type: NewLookupTableType band = IntegerDescriptor( 'band', _required, strict=DEFAULT_STRICT, docstring='The image band to which this applies.') def __init__(self, GeometricTransform=None, SharpnessEnhancement=None, ColorSpaceTransform=None, DynamicRangeAdjustment=None, band=1, **kwargs): if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.GeometricTransform = GeometricTransform self.SharpnessEnhancement = SharpnessEnhancement self.ColorSpaceTransform = ColorSpaceTransform self.DynamicRangeAdjustment = DynamicRangeAdjustment self.band = band super(InteractiveProcessingType, self).__init__(**kwargs)
class NonInteractiveProcessingType(Serializable): """ The non-interactive processing information. """ _fields = ('ProductGenerationOptions', 'RRDS', 'band') _required = ('ProductGenerationOptions', 'RRDS', 'band') _set_as_attribute = ('band', ) # Descriptor ProductGenerationOptions = SerializableDescriptor( 'ProductGenerationOptions', ProductGenerationOptionsType, _required, strict=DEFAULT_STRICT, docstring= 'Performs several key actions on an image to prepare it for necessary additional processing to ' 'achieve the desired output product.' ) # type: ProductGenerationOptionsType RRDS = SerializableDescriptor( 'RRDS', RRDSType, _required, strict=DEFAULT_STRICT, docstring= 'Creates a set of sub-sampled versions of an image to provide processing chains ' 'with quick access to lower magnification values for faster computation ' 'speeds and performance.') # type: RRDSType band = IntegerDescriptor( 'band', _required, strict=DEFAULT_STRICT, docstring='The image band to which this applies.') # type: int def __init__(self, ProductGenerationOptions=None, RRDS=None, band=1, **kwargs): if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.ProductGenerationOptions = ProductGenerationOptions self.RRDS = RRDS self.band = band super(NonInteractiveProcessingType, self).__init__(**kwargs)
class DigitalElevationDataType(Serializable): """ This describes any Digital Elevation Data included with the SIDD product. """ _fields = ('GeographicCoordinates', 'Geopositioning', 'PositionalAccuracy', 'NullValue') _required = ('GeographicCoordinates', 'Geopositioning', 'PositionalAccuracy') # Descriptor GeographicCoordinates = SerializableDescriptor( 'GeographicCoordinates', GeographicCoordinatesType, _required, strict=DEFAULT_STRICT, docstring='Describes the Local Geographic Coordinate system linking row/column to the ' 'absolute geographic coordinate (lat/lon)') # type: GeographicCoordinatesType Geopositioning = SerializableDescriptor( 'Geopositioning', GeopositioningType, _required, strict=DEFAULT_STRICT, docstring='Describes the absolute coordinate system to which the data is ' 'referenced.') # type: GeopositioningType PositionalAccuracy = SerializableDescriptor( 'PositionalAccuracy', PositionalAccuracyType, _required, strict=DEFAULT_STRICT, docstring='Describes the horizontal and vertical point and regional information ' 'for the DED.') # type: PositionalAccuracyType NullValue = IntegerDescriptor( 'NullValue', _required, strict=DEFAULT_STRICT, docstring='The value in the DEM corresponding to `No Value`.') # type: Union[None, int] def __init__(self, GeographicCoordinates=None, Geopositioning=None, PositionalAccuracy=None, NullValue=None, **kwargs): """ Parameters ---------- GeographicCoordinates : GeographicCoordinatesType Geopositioning : GeopositioningType PositionalAccuracy : PositionalAccuracyType NullValue : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.GeographicCoordinates = GeographicCoordinates self.Geopositioning = Geopositioning self.PositionalAccuracy = PositionalAccuracy self.NullValue = NullValue super(DigitalElevationDataType, self).__init__(**kwargs)
class PerVectorParameterF8(Serializable): _fields = ('Offset', 'Size', 'Format') _required = ('Offset', ) # descriptors Offset = IntegerDescriptor('Offset', _required, strict=DEFAULT_STRICT, bounds=(0, None), docstring='The offset value.') # type: int def __init__(self, Offset=None, **kwargs): """ Parameters ---------- Offset : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.Offset = Offset super(PerVectorParameterF8, self).__init__(**kwargs) @property def Size(self): """ int: The size of the vector, constant value 1 here. """ return 1 @property def Format(self): """ str: The format of the vector data, constant value 'F8' here. """ return 'F8'
class DynamicRangeAdjustmentType(Serializable): """ The dynamic range adjustment (DRA) parameters. """ _fields = ('AlgorithmType', 'BandStatsSource', 'DRAParameters', 'DRAOverrides') _required = ('AlgorithmType', 'BandStatsSource', ) # Descriptor AlgorithmType = StringEnumDescriptor( 'AlgorithmType', ('AUTO', 'MANUAL', 'NONE'), _required, strict=DEFAULT_STRICT, default_value='NONE', docstring='Algorithm used for dynamic range adjustment.') # type: str BandStatsSource = IntegerDescriptor( 'BandStatsSource', _required, strict=DEFAULT_STRICT, docstring='') # type: int DRAParameters = SerializableDescriptor( 'DRAParameters', DRAParametersType, _required, strict=DEFAULT_STRICT, docstring='The dynamic range adjustment parameters.') # type: DRAParametersType DRAOverrides = SerializableDescriptor( 'DRAOverrides', DRAOverridesType, _required, strict=DEFAULT_STRICT, docstring='The dynamic range adjustment overrides.') # type: DRAOverridesType def __init__(self, AlgorithmType='NONE', BandStatsSource=None, DRAParameters=None, DRAOverrides=None, **kwargs): """ Parameters ---------- AlgorithmType : str BandStatsSource : int DRAParameters : DRAParametersType DRAOverrides : DRAOverridesType kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.AlgorithmType = AlgorithmType self.BandStatsSource = BandStatsSource self.DRAParameters = DRAParameters self.DRAOverrides = DRAOverrides super(DynamicRangeAdjustmentType, self).__init__(**kwargs)
class RcvChanProcType(Serializable): """The Received Processed Channels.""" _fields = ('NumChanProc', 'PRFScaleFactor', 'ChanIndices') _required = ('NumChanProc', 'ChanIndices') _collections_tags = { 'ChanIndices': {'array': False, 'child_tag': 'ChanIndex'}} _numeric_format = {'PRFScaleFactor': FLOAT_FORMAT} # descriptors NumChanProc = IntegerDescriptor( 'NumChanProc', _required, strict=DEFAULT_STRICT, docstring='Number of receive data channels processed to form the image.') # type: int PRFScaleFactor = FloatDescriptor( 'PRFScaleFactor', _required, strict=DEFAULT_STRICT, docstring='Factor indicating the ratio of the effective PRF to the actual PRF.') # type: float ChanIndices = IntegerListDescriptor( 'ChanIndices', _collections_tags, _required, strict=DEFAULT_STRICT, docstring='Index of a data channel that was processed.') # type: List[int] def __init__(self, NumChanProc=None, PRFScaleFactor=None, ChanIndices=None, **kwargs): """ Parameters ---------- NumChanProc : int PRFScaleFactor : float ChanIndices : List[int] kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumChanProc = NumChanProc self.PRFScaleFactor = PRFScaleFactor self.ChanIndices = ChanIndices super(RcvChanProcType, self).__init__(**kwargs)
class CRSDHeader(CRSDHeaderBase): _fields = ( 'XML_BLOCK_SIZE', 'XML_BLOCK_BYTE_OFFSET', 'SUPPORT_BLOCK_SIZE', 'SUPPORT_BLOCK_BYTE_OFFSET', 'PVP_BLOCK_SIZE', 'PVP_BLOCK_BYTE_OFFSET', 'SIGNAL_BLOCK_SIZE', 'SIGNAL_BLOCK_BYTE_OFFSET', 'CLASSIFICATION', 'RELEASE_INFO') _required = ( 'XML_BLOCK_SIZE', 'XML_BLOCK_BYTE_OFFSET', 'PVP_BLOCK_SIZE', 'PVP_BLOCK_BYTE_OFFSET', 'SIGNAL_BLOCK_SIZE', 'SIGNAL_BLOCK_BYTE_OFFSET', 'CLASSIFICATION', 'RELEASE_INFO') # descriptor XML_BLOCK_SIZE = IntegerDescriptor( 'XML_BLOCK_SIZE', _required, strict=True, docstring='Size of the XML instance that describes the product in bytes. ' 'Size does NOT include the 2 bytes of the section terminator.') # type: int XML_BLOCK_BYTE_OFFSET = IntegerDescriptor( 'XML_BLOCK_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the XML block in bytes.') # type: int SUPPORT_BLOCK_SIZE = IntegerDescriptor( 'SUPPORT_BLOCK_SIZE', _required, strict=True, docstring='Size of the Support block in bytes. Note - If the Support block is omitted, this ' 'is not included.') # type: int SUPPORT_BLOCK_BYTE_OFFSET = IntegerDescriptor( 'SUPPORT_BLOCK_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the Support block in bytes. Note - If the Support ' 'block is omitted, this is not included.') # type: int PVP_BLOCK_SIZE = IntegerDescriptor( 'PVP_BLOCK_SIZE', _required, strict=True, docstring='Size of the PVP block in bytes.') # type: int PVP_BLOCK_BYTE_OFFSET = IntegerDescriptor( 'PVP_BLOCK_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the PVP block in bytes.') # type: int SIGNAL_BLOCK_SIZE = IntegerDescriptor( 'SIGNAL_BLOCK_SIZE', _required, strict=True, docstring='Size of the Signal block in bytes.') # type: int SIGNAL_BLOCK_BYTE_OFFSET = IntegerDescriptor( 'SIGNAL_BLOCK_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the Signal block in bytes.') # type: int CLASSIFICATION = StringDescriptor( 'CLASSIFICATION', _required, strict=True, default_value='UNCLASSIFIED', docstring='Product classification information that is human-readable.') # type: str RELEASE_INFO = StringDescriptor( 'RELEASE_INFO', _required, strict=True, default_value='UNRESTRICTED', docstring='Product release information that is human-readable.') # type: str def __init__(self, XML_BLOCK_SIZE=None, XML_BLOCK_BYTE_OFFSET=None, SUPPORT_BLOCK_SIZE=None, SUPPORT_BLOCK_BYTE_OFFSET=None, PVP_BLOCK_SIZE=None, PVP_BLOCK_BYTE_OFFSET=None, SIGNAL_BLOCK_SIZE=None, SIGNAL_BLOCK_BYTE_OFFSET=None, CLASSIFICATION='UNCLASSIFIED', RELEASE_INFO='UNRESTRICTED'): self.XML_BLOCK_SIZE = XML_BLOCK_SIZE self.XML_BLOCK_BYTE_OFFSET = XML_BLOCK_BYTE_OFFSET self.SUPPORT_BLOCK_SIZE = SUPPORT_BLOCK_SIZE self.SUPPORT_BLOCK_BYTE_OFFSET = SUPPORT_BLOCK_BYTE_OFFSET self.PVP_BLOCK_SIZE = PVP_BLOCK_SIZE self.PVP_BLOCK_BYTE_OFFSET = PVP_BLOCK_BYTE_OFFSET self.SIGNAL_BLOCK_SIZE = SIGNAL_BLOCK_SIZE self.SIGNAL_BLOCK_BYTE_OFFSET = SIGNAL_BLOCK_BYTE_OFFSET self.CLASSIFICATION = CLASSIFICATION self.RELEASE_INFO = RELEASE_INFO super(CRSDHeader, self).__init__() def to_string(self): """ Forms a CRSD file header string (not including the section terminator) from populated attributes. """ return ('CRSD/{}\n'.format(_CRSD_SPECIFICATION_VERSION) + ''.join(["{} := {}\n".format(f, getattr(self, f)) for f in self._fields if getattr(self, f) is not None]))
class FiducialInfoType(Serializable): _fields = ('NumberOfFiducialsInImage', 'NumberOfFiducialsInScene', 'LabelSource', 'Fiducials') _required = ('NumberOfFiducialsInImage', 'NumberOfFiducialsInScene', 'LabelSource', 'Fiducials') _collections_tags = { 'Fiducials': { 'array': False, 'child_tag': 'Fiducial' } } # descriptors NumberOfFiducialsInImage = IntegerDescriptor( 'NumberOfFiducialsInImage', _required, strict=DEFAULT_STRICT, docstring='Number of ground truthed objects in the image.' ) # type: int NumberOfFiducialsInScene = IntegerDescriptor( 'NumberOfFiducialsInScene', _required, strict=DEFAULT_STRICT, docstring='Number of ground truthed objects in the scene.' ) # type: int LabelSource = SerializableDescriptor( 'LabelSource', LabelSourceType, _required, strict=DEFAULT_STRICT, docstring='The source of the labels') # type: LabelSourceType Fiducials = SerializableListDescriptor( 'Fiducials', TheFiducialType, _collections_tags, _required, strict=DEFAULT_STRICT, docstring='The object collection') # type: List[TheFiducialType] def __init__(self, NumberOfFiducialsInImage=None, NumberOfFiducialsInScene=None, LabelSource=None, Fiducials=None, **kwargs): """ Parameters ---------- NumberOfFiducialsInImage : int NumberOfFiducialsInScene : int LabelSource : LabelSourceType Fiducials : None|List[TheFiducialType] kwargs Other keyword arguments """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumberOfFiducialsInImage = NumberOfFiducialsInImage self.NumberOfFiducialsInScene = NumberOfFiducialsInScene self.LabelSource = LabelSource self.Fiducials = Fiducials super(FiducialInfoType, self).__init__(**kwargs) def set_image_location_from_sicd(self, sicd, populate_in_periphery=False, include_out_of_range=False): """ Set the image location information with respect to the given SICD, assuming that the physical coordinates are populated. The `NumberOfFiducialsInImage` will be set, and `NumberOfFiducialsInScene` will be left unchanged. Parameters ---------- sicd : SICDType populate_in_periphery : bool Populate image information for objects on the periphery? include_out_of_range : bool Include the objects which are out of range (with no image location information)? """ def update_fiducial(temp_fid, in_image_count): status = temp_fid.set_image_location_from_sicd( sicd, populate_in_periphery=populate_in_periphery) use_fid = False if status == 0: raise ValueError('Fiducial already has image details set') if status == 1 or (status == 2 and populate_in_periphery): use_fid = True in_image_count += 1 return use_fid, in_image_count fid_in_image = 0 if include_out_of_range: # the fiducials list is just modified in place for the_fid in self.Fiducials: _, fid_in_image = update_fiducial(the_fid, fid_in_image) else: # the fiducials list is just modified in place fiducials = [] for the_fid in self.Fiducials: use_this_fid, fid_in_image = update_fiducial( the_fid, fid_in_image) if use_this_fid: fiducials.append(the_fid) self.Fiducials = fiducials self.NumberOfFiducialsInImage = fid_in_image
class CollectionInfoType(Serializable): _fields = ('Name', 'ProgramName', 'Sponsor', 'Date', 'Location', 'NumberOfSites') _required = () # descriptors Name = StringDescriptor( 'Name', _required, docstring="Name of the collection.") # type: Optional[str] ProgramName = StringDescriptor( 'StringDescriptor', _required, docstring="Name of the program that collected the data." ) # type: Optional[str] Sponsor = StringDescriptor( 'Sponsor', _required, docstring="Sponsoring agency/organization of the data collection." ) # type: Optional[str] Date = SerializableDescriptor( 'Date', DateRangeType, _required, strict=DEFAULT_STRICT, docstring="Begin and end dates of the data collection." ) # type: Optional[DateRangeType] Location = SerializableDescriptor( 'Location', LocationType, _required, strict=DEFAULT_STRICT, docstring="General location of the data collection." ) # type: Optional[LocationType] NumberOfSites = IntegerDescriptor( 'NumberOfSites', _required, strict=DEFAULT_STRICT, docstring="Number of different sites contained in the data collection." ) # type: Optional[int] def __init__(self, Name=None, ProgramName=None, Sponsor=None, Date=None, Location=None, NumberOfSites=None, **kwargs): """ Parameters ---------- Name : None|str ProgramName : None|str Sponsor : None|str Date : None|DateRangeType|list|tuple Location : None|LocationType NumberOfSites : None|int kwargs Other keyword arguments """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.Name = Name self.ProgramName = ProgramName self.Sponsor = Sponsor self.Date = Date self.Location = Location self.NumberOfSites = NumberOfSites super(CollectionInfoType, self).__init__(**kwargs)
class ProductDisplayType(Serializable): """ """ _fields = ('PixelType', 'NumBands', 'DefaultBandDisplay', 'NonInteractiveProcessing', 'InteractiveProcessing', 'DisplayExtensions') _required = ('PixelType', 'NumBands', 'NonInteractiveProcessing', 'InteractiveProcessing') _collections_tags = { 'NonInteractiveProcessing': { 'array': False, 'child_tag': 'NonInteractiveProcessing' }, 'InteractiveProcessing': { 'array': False, 'child_tag': 'InteractiveProcessing' }, 'DisplayExtensions': { 'array': False, 'child_tag': 'DisplayExtension' } } # Descriptors PixelType = StringEnumDescriptor( 'PixelType', ('MONO8I', 'MONO8LU', 'MONO16I', 'RGB8LU', 'RGB24I'), _required, strict=DEFAULT_STRICT, docstring='Enumeration of the pixel type. Definition in ' 'Design and Exploitation document.') # type: str NumBands = IntegerDescriptor( 'NumBands', _required, strict=DEFAULT_STRICT, docstring= 'Number of bands contained in the image. Populate with the number of bands ' 'present after remapping. For example an 8-bit RGB image (RGBLU), this will ' 'be 3.') # type: int DefaultBandDisplay = IntegerDescriptor( 'DefaultBandDisplay', _required, strict=DEFAULT_STRICT, docstring='Indicates which band to display by default. ' 'Valid range = 1 to NumBands.') # type: int NonInteractiveProcessing = SerializableListDescriptor( 'NonInteractiveProcessing', NonInteractiveProcessingType, _collections_tags, _required, strict=DEFAULT_STRICT, docstring='Non-interactive processing details.' ) # type: List[NonInteractiveProcessingType] InteractiveProcessing = SerializableListDescriptor( 'InteractiveProcessing', InteractiveProcessingType, _collections_tags, _required, strict=DEFAULT_STRICT, docstring='Interactive processing details.' ) # type: List[InteractiveProcessingType] DisplayExtensions = ParametersDescriptor( 'DisplayExtensions', _collections_tags, _required, strict=DEFAULT_STRICT, docstring= 'Optional extensible parameters used to support profile-specific needs related to ' 'product display. Predefined filter types.' ) # type: ParametersCollection def __init__(self, PixelType=None, NumBands=1, DefaultBandDisplay=None, NonInteractiveProcessing=None, InteractiveProcessing=None, DisplayExtensions=None, **kwargs): """ Parameters ---------- PixelType : PixelTypeType NumBands : int DefaultBandDisplay : int|None NonInteractiveProcessing : List[NonInteractiveProcessingType] InteractiveProcessing : List[InteractiveProcessingType] DisplayExtensions : ParametersCollection|dict kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.PixelType = PixelType self.NumBands = NumBands self.DefaultBandDisplay = DefaultBandDisplay self.NonInteractiveProcessing = NonInteractiveProcessing self.InteractiveProcessing = InteractiveProcessing self.DisplayExtensions = DisplayExtensions super(ProductDisplayType, self).__init__(**kwargs) def get_pixel_size(self) -> int: """ Gets the raw size per pixel, in bytes. Returns ------- int """ if self.PixelType == 'MONO8I': return 1 elif self.PixelType == 'MONO8LU': return 1 elif self.PixelType == 'MONO16I': return 2 elif self.PixelType == 'RGB8LU': return 1 elif self.PixelType == 'RGB24I': return 3 else: raise ValueError('Got unhandled pixel type `{}`'.format( self.PixelType))
class TheFiducialType(Serializable): _fields = ('Name', 'SerialNumber', 'FiducialType', 'DatasetFiducialNumber', 'ImageLocation', 'GeoLocation', 'IPRWidth3dB', 'IPRWidth18dB', 'IPRWidth3dB18dBRatio', 'PeakSideLobeRatio', 'IntegratedSideLobeRatio', 'SlantPlane', 'GroundPlane', 'ProjectionPerturbation') _required = ('FiducialType', 'ImageLocation', 'GeoLocation') # descriptors Name = StringDescriptor( 'Name', _required, strict=DEFAULT_STRICT, docstring='Name of the fiducial.') # type: Optional[str] SerialNumber = StringDescriptor( 'SerialNumber', _required, strict=DEFAULT_STRICT, docstring='The serial number of the fiducial') # type: Optional[str] FiducialType = StringDescriptor( 'FiducialType', _required, strict=DEFAULT_STRICT, docstring='The type of fiducial') # type: str DatasetFiducialNumber = IntegerDescriptor( 'DatasetFiducialNumber', _required, docstring='Unique number of the fiducial within the selected dataset, ' 'defined by the RDE system') # type: Optional[int] ImageLocation = SerializableDescriptor( 'ImageLocation', ImageLocationType, _required, docstring='Center of the fiducial in the image' ) # type: Optional[ImageLocationType] GeoLocation = SerializableDescriptor( 'GeoLocation', GeoLocationType, _required, docstring='Real physical location of the fiducial' ) # type: Optional[GeoLocationType] IPRWidth3dB = SerializableDescriptor( 'IPRWidth3dB', RangeCrossRangeType, _required, docstring='The 3 dB impulse response width, in meters' ) # type: Optional[RangeCrossRangeType] IPRWidth18dB = SerializableDescriptor( 'IPRWidth18dB', RangeCrossRangeType, _required, docstring='The 18 dB impulse response width, in meters' ) # type: Optional[RangeCrossRangeType] IPRWidth3dB18dBRatio = SerializableDescriptor( 'IPRWidth3dB18dBRatio', RangeCrossRangeType, _required, docstring='Ratio of the 3 dB to 18 dB system impulse response width' ) # type: Optional[RangeCrossRangeType] PeakSideLobeRatio = SerializableDescriptor( 'PeakSideLobeRatio', RangeCrossRangeType, _required, docstring= 'Ratio of the peak sidelobe intensity to the peak mainlobe intensity, ' 'in dB') # type: Optional[RangeCrossRangeType] IntegratedSideLobeRatio = SerializableDescriptor( 'IntegratedSideLobeRatio', RangeCrossRangeType, _required, docstring='Ratio of all the energies in the sidelobes of the ' 'system impulse response to the energy in the mainlobe, ' 'in dB') # type: Optional[RangeCrossRangeType] SlantPlane = SerializableDescriptor( 'SlantPlane', PhysicalLocationType, _required, docstring='Center of the object in the slant plane' ) # type: Optional[PhysicalLocationType] GroundPlane = SerializableDescriptor( 'GroundPlane', PhysicalLocationType, _required, docstring='Center of the object in the ground plane' ) # type: Optional[PhysicalLocationType] ProjectionPerturbation = SerializableDescriptor( 'ProjectionPerturbation', ProjectionPerturbationType, _required, docstring='') # type: Optional[ProjectionPerturbationType] def __init__(self, Name=None, SerialNumber=None, FiducialType=None, DatasetFiducialNumber=None, ImageLocation=None, GeoLocation=None, IPRWidth3dB=None, IPRWidth18dB=None, IPRWidth3dB18dBRatio=None, PeakSideLobeRatio=None, IntegratedSideLobeRatio=None, SlantPlane=None, GroundPlane=None, ProjectionPerturbation=None, **kwargs): """ Parameters ---------- Name : str SerialNumber : None|str FiducialType : str DatasetFiducialNumber : None|int ImageLocation : ImageLocationType GeoLocation : GeoLocationType IPRWidth3dB : None|RangeCrossRangeType|numpy.ndarray|list|tuple IPRWidth18dB : None|RangeCrossRangeType|numpy.ndarray|list|tuple IPRWidth3dB18dBRatio : None|RangeCrossRangeType|numpy.ndarray|list|tuple PeakSideLobeRatio : None|RangeCrossRangeType|numpy.ndarray|list|tuple IntegratedSideLobeRatio : None|RangeCrossRangeType|numpy.ndarray|list|tuple SlantPlane : None|PhysicalLocationType GroundPlane : None|PhysicalLocationType ProjectionPerturbation : None|ProjectionPerturbationType kwargs Other keyword arguments """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.Name = Name self.SerialNumber = SerialNumber self.FiducialType = FiducialType self.DatasetFiducialNumber = DatasetFiducialNumber self.ImageLocation = ImageLocation self.GeoLocation = GeoLocation self.IPRWidth3dB = IPRWidth3dB self.IPRWidth18dB = IPRWidth18dB self.IPRWidth3dB18dBRatio = IPRWidth3dB18dBRatio self.PeakSideLobeRatio = PeakSideLobeRatio self.IntegratedSideLobeRatio = IntegratedSideLobeRatio self.SlantPlane = SlantPlane self.GroundPlane = GroundPlane self.ProjectionPerturbation = ProjectionPerturbation super(TheFiducialType, self).__init__(**kwargs) def set_image_location_from_sicd(self, sicd, populate_in_periphery=False): """ Set the image location information with respect to the given SICD. Parameters ---------- sicd : SICDType Returns ------- int -1 - insufficient metadata to proceed 0 - nothing to be done 1 - successful 2 - object in image periphery, not populating 3 - object not in image field """ if self.ImageLocation is not None or self.SlantPlane is not None: # no need to infer anything, it's already populated return 0 if self.GeoLocation is None: logger.warning('GeoLocation is not populated,\n\t' 'so the image location can not be inferred') return -1 if not sicd.can_project_coordinates(): logger.warning(_no_projection_text) return -1 image_location = ImageLocationType.from_geolocation( self.GeoLocation, sicd) # check bounding information rows = sicd.ImageData.NumRows cols = sicd.ImageData.NumCols center_pixel = image_location.CenterPixel.get_array(dtype='float64') if (0 < center_pixel[0] < rows - 1) and (0 < center_pixel[1] < cols - 1): placement = 1 elif (-3 < center_pixel[0] < rows + 2) and (-3 < center_pixel[1] < cols + 2): placement = 2 else: placement = 3 if placement == 3 or (placement == 2 and not populate_in_periphery): return placement self.ImageLocation = image_location self.SlantPlane = PhysicalLocationType(Physical=image_location) return placement def set_geo_location_from_sicd(self, sicd, projection_type='HAE', **proj_kwargs): """ Set the geographical location information with respect to the given SICD, assuming that the image coordinates are populated. .. Note:: This assumes that the image coordinates are with respect to the given image (chip), and NOT including any sicd.ImageData.FirstRow/Col values, which will be added here. Parameters ---------- sicd : SICDType projection_type : str The projection type selector, one of `['PLANE', 'HAE', 'DEM']`. Using `'DEM'` requires configuration for the DEM pathway described in :func:`sarpy.geometry.point_projection.image_to_ground_dem`. proj_kwargs The keyword arguments for the :func:`SICDType.project_image_to_ground_geo` method. """ if self.GeoLocation is not None: # no need to infer anything, it's already populated return if self.ImageLocation is None: logger.warning('ImageLocation is not populated,\n\t' 'so the geographical location can not be inferred') return if not sicd.can_project_coordinates(): logger.warning(_no_projection_text) return self.GeoLocation = GeoLocationType.from_image_location( self.ImageLocation, sicd, projection_type=projection_type, **proj_kwargs)
class IPPSetType(Serializable): """ The Inter-Pulse Parameter array element container. """ # NOTE that this is simply defined as a child class ("Set") of the TimelineType in the SICD standard # Defining it at root level clarifies the documentation, and giving it a more descriptive name is # appropriate. _fields = ('TStart', 'TEnd', 'IPPStart', 'IPPEnd', 'IPPPoly', 'index') _required = _fields _set_as_attribute = ('index', ) _numeric_format = { 'TStart': FLOAT_FORMAT, 'TEnd': FLOAT_FORMAT, } # descriptors TStart = FloatDescriptor( 'TStart', _required, strict=DEFAULT_STRICT, docstring= 'IPP start time relative to collection start time, i.e. offsets in seconds.' ) # type: float TEnd = FloatDescriptor( 'TEnd', _required, strict=DEFAULT_STRICT, docstring= 'IPP end time relative to collection start time, i.e. offsets in seconds.' ) # type: float IPPStart = IntegerDescriptor( 'IPPStart', _required, strict=True, docstring='Starting IPP index for the period described.') # type: int IPPEnd = IntegerDescriptor( 'IPPEnd', _required, strict=True, docstring='Ending IPP index for the period described.') # type: int IPPPoly = SerializableDescriptor( 'IPPPoly', Poly1DType, _required, strict=DEFAULT_STRICT, docstring= 'IPP index polynomial coefficients yield IPP index as a function of time.' ) # type: Poly1DType index = IntegerDescriptor( 'index', _required, strict=DEFAULT_STRICT, docstring='The element array index.') # type: int def __init__(self, TStart=None, TEnd=None, IPPStart=None, IPPEnd=None, IPPPoly=None, index=None, **kwargs): """ Parameters ---------- TStart : float TEnd : float IPPStart : int IPPEnd : int IPPPoly : Poly1DType|numpy.ndarray|list|tuple index : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.TStart, self.TEnd = TStart, TEnd self.IPPStart, self.IPPEnd = IPPStart, IPPEnd self.IPPPoly = IPPPoly self.index = index super(IPPSetType, self).__init__(**kwargs) def _basic_validity_check(self): condition = super(IPPSetType, self)._basic_validity_check() if self.TStart >= self.TEnd: self.log_validity_error('TStart ({}) >= TEnd ({})'.format( self.TStart, self.TEnd)) condition = False if self.IPPStart >= self.IPPEnd: self.log_validity_error('IPPStart ({}) >= IPPEnd ({})'.format( self.IPPStart, self.IPPEnd)) condition = False exp_ipp_start = self.IPPPoly(self.TStart) exp_ipp_end = self.IPPPoly(self.TEnd) if abs(exp_ipp_start - self.IPPStart) > 1: self.log_validity_error( 'IPPStart populated as {}, inconsistent with value ({}) ' 'derived from IPPPoly and TStart'.format( exp_ipp_start, self.IPPStart)) if abs(exp_ipp_end - self.IPPEnd) > 1: self.log_validity_error( 'IPPEnd populated as {}, inconsistent with value ({}) ' 'derived from IPPPoly and TEnd'.format(self.IPPEnd, exp_ipp_end)) return condition
class ParametersType(Serializable): """ Channel dependent parameters. """ _fields = ('SRP_Index', 'NomTOARateSF', 'FxCtrNom', 'BWSavedNom', 'TOASavedNom', 'TxAnt_Index', 'RcvAnt_Index', 'TWAnt_Index') _required = ('SRP_Index', 'NomTOARateSF', 'FxCtrNom', 'BWSavedNom', 'TOASavedNom') _numeric_format = { 'NomTOARateSF': FLOAT_FORMAT, 'FxCtrNom': FLOAT_FORMAT, 'BWSavedNom': FLOAT_FORMAT, 'TOASavedNom': FLOAT_FORMAT } # descriptors SRP_Index = IntegerDescriptor( 'SRP_Index', _required, strict=DEFAULT_STRICT, docstring='Index to identify the SRP position function used for the ' 'channel.') # type: int NomTOARateSF = FloatDescriptor( 'NomTOARateSF', _required, strict=DEFAULT_STRICT, docstring= 'Scale factor to indicate the fraction of the Doppler spectrum ' 'that is clear.') # type: float FxCtrNom = FloatDescriptor( 'FxCtrNom', _required, strict=DEFAULT_STRICT, docstring= 'Nominal center transmit frequency associated with the channel (Hz). ' 'For DomainType = TOA, FxCtrNom is the center frequency for all ' 'vectors.') # type: float BWSavedNom = FloatDescriptor( 'BWSavedNom', _required, strict=DEFAULT_STRICT, docstring='Nominal transmit bandwidth associated with the channel (Hz). ' 'For DomainType = TOA, BWSavedNom is the bandwidth saved for all ' 'vectors.') # type: float TOASavedNom = FloatDescriptor( 'TOASavedNom', _required, strict=DEFAULT_STRICT, docstring= 'Nominal span in TOA saved for the channel. For DomainType = FX, ' 'TOASavedNom is the bandwidth saved for all ' 'vectors.') # type: float TxAnt_Index = IntegerDescriptor( 'TxAnt_Index', _required, strict=DEFAULT_STRICT, docstring= 'Indicates the Transmit Antenna pattern for data collected to form ' 'the CPHD channel.') # type: Union[None, int] RcvAnt_Index = IntegerDescriptor( 'RcvAnt_Index', _required, strict=DEFAULT_STRICT, docstring= 'Indicates the Receive Antenna pattern for data collected to form ' 'the CPHD channel.') # type: Union[None, int] TWAnt_Index = IntegerDescriptor( 'TWAnt_Index', _required, strict=DEFAULT_STRICT, docstring= 'Indicates the T wo-way Antenna pattern for data collected to form ' 'the CPHD channel.') # type: Union[None, int] def __init__(self, SRP_Index=None, NomTOARateSF=None, FxCtrNom=None, BWSavedNom=None, TOASavedNom=None, TxAnt_Index=None, RcvAnt_Index=None, TWAnt_Index=None, **kwargs): """ Parameters ---------- SRP_Index : int NomTOARateSF : float FxCtrNom : float BWSavedNom : float TOASavedNom : float TxAnt_Index : None|int RcvAnt_Index : None|int TWAnt_Index : None|int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.SRP_Index = SRP_Index self.NomTOARateSF = NomTOARateSF self.FxCtrNom = FxCtrNom self.BWSavedNom = BWSavedNom self.TOASavedNom = TOASavedNom self.TxAnt_Index = TxAnt_Index self.RcvAnt_Index = RcvAnt_Index self.TWAnt_Index = TWAnt_Index super(ParametersType, self).__init__(**kwargs)
class ImageInfoType(Serializable): _fields = ('DataFilename', 'ClassificationMarkings', 'Filetype', 'DataCheckSum', 'DataSize', 'DataPlane', 'DataDomain', 'DataType', 'BitsPerSample', 'DataFormat', 'DataByteOrder', 'NumPixels', 'ImageCollectionDate', 'ZuluOffset', 'SensorReferencePoint', 'SensorCalibrationFactor', 'DataCalibrated', 'Resolution', 'PixelSpacing', 'WeightingType', 'OverSamplingFactor', 'IPRWidth3dB', 'ImageQualityDescription', 'ImageHeading', 'ImageCorners', 'SlantPlane', 'GroundPlane', 'SceneCenterReferenceLine', 'ProjectionPerturbation') _required = ('DataFilename', 'ClassificationMarkings', 'DataCheckSum', 'DataPlane', 'DataDomain', 'DataType', 'DataFormat', 'NumPixels', 'ImageCollectionDate', 'SensorReferencePoint', 'DataCalibrated', 'Resolution', 'PixelSpacing', 'WeightingType', 'ImageCorners') _numeric_format = { 'ImageHeading': '0.17G', 'SensorCalibrationFactor': '0.17G', 'SceneCenterReferenceLine': '0.17G', } # descriptors DataFilename = StringDescriptor( 'DataFilename', _required, docstring='The base file name to which this information pertains' ) # type: str ClassificationMarkings = SerializableDescriptor( 'ClassificationMarkings', ClassificationMarkingsType, _required, docstring='The classification information' ) # type: ClassificationMarkingsType Filetype = StringDescriptor( 'Filetype', _required, docstring='The image file type') # type: Optional[str] DataCheckSum = StringDescriptor( 'DataCheckSum', _required, docstring='The 32 character (hexidecimal digest) MD5 checksum of the ' 'full image file') # type: str DataSize = IntegerDescriptor( 'DataSize', _required, docstring='The image size in bytes') # type: Optional[int] DataPlane = StringEnumDescriptor('DataPlane', {'Slant', 'Ground'}, _required, default_value='Slant', docstring='The image plane.') # type: str DataDomain = StringEnumDescriptor( 'DataDomain', { 'Image', }, _required, # todo: values docstring='The image data domain') # type: str DataType = StringEnumDescriptor( 'DataType', {'Magnitude/Phase', 'In-phase/Quadrature'}, _required, docstring='The image data type') # type: str BitsPerSample = IntegerDescriptor( 'BitsPerSample', _required, docstring='The number of bits per sample') # type: Optional[int] DataFormat = StringDescriptor( 'DataFormat', _required, docstring='The image data format') # type: str DataByteOrder = StringEnumDescriptor( 'DataByteOrder', {'Big-Endian', 'Little-Endian'}, _required, docstring='The image data byte order.') # type: Optional[str] NumPixels = SerializableDescriptor( 'NumPixels', NumPixelsType, _required, docstring='The number of image pixels') # type: NumPixelsType ImageCollectionDate = DateTimeDescriptor( 'ImageCollectionDate', _required, docstring='The date/time of the image collection in UTC' ) # type: Optional[numpy.datetime64] ZuluOffset = StringDescriptor( 'ZuluOffset', _required, docstring='The local time offset from UTC') # type: Optional[str] SensorReferencePoint = StringEnumDescriptor( 'DataPlane', {'Left', 'Right', 'Top', 'Bottom'}, _required, docstring='Description of the sensor location relative to the scene.' ) # type: Optional[str] SensorCalibrationFactor = FloatDescriptor( 'SensorCalibrationFactor', _required, docstring= 'Multiplicative factor used to scale raw image data to the return ' 'of a calibrated reference reflector or active source' ) # type: Optional[float] DataCalibrated = BooleanDescriptor( 'DataCalibrated', _required, docstring='Has the data been calibrated?') # type: bool Resolution = SerializableDescriptor( 'Resolution', RangeCrossRangeType, _required, docstring='Resolution (intrinsic) of the sensor system/mode in meters.' ) # type: RangeCrossRangeType PixelSpacing = SerializableDescriptor( 'PixelSpacing', RangeCrossRangeType, _required, docstring='Pixel spacing of the image in meters.' ) # type: RangeCrossRangeType WeightingType = SerializableDescriptor( 'WeightingType', StringRangeCrossRangeType, _required, docstring='Weighting function applied to the image during formation.' ) # type: StringRangeCrossRangeType OverSamplingFactor = SerializableDescriptor( 'OverSamplingFactor', RangeCrossRangeType, _required, docstring='The factor by which the pixel space is oversampled.' ) # type: Optional[RangeCrossRangeType] IPRWidth3dB = SerializableDescriptor( 'IPRWidth3dB', RangeCrossRangeType, _required, docstring='The 3 dB system impulse response with, in meters' ) # type: Optional[RangeCrossRangeType] ImageQualityDescription = StringDescriptor( 'ImageQualityDescription', _required, docstring='General description of image quality' ) # type: Optional[str] ImageHeading = FloatDescriptor( 'ImageHeading', _required, docstring='Image heading relative to True North, in degrees' ) # type: Optional[float] ImageCorners = SerializableDescriptor( 'ImageCorners', ImageCornerType, _required, docstring='The image corners') # type: ImageCornerType SlantPlane = SerializableDescriptor( 'SlantPlane', PixelSpacingType, _required, docstring='The slant plane pixel spacing' ) # type: Optional[PixelSpacingType] GroundPlane = SerializableDescriptor( 'GroundPlane', PixelSpacingType, _required, docstring='The ground plane pixel spacing' ) # type: Optional[PixelSpacingType] SceneCenterReferenceLine = FloatDescriptor( 'SceneCenterReferenceLine', _required, docstring='The ideal line (heading) at the intersection of the radar ' 'line-of-sight with the horizontal reference plane ' 'created by the forward motion of the aircraft, ' 'in degrees') # type: Optional[float] ProjectionPerturbation = SerializableDescriptor( 'ProjectionPerturbation', ProjectionPerturbationType, _required, docstring='') # type: Optional[ProjectionPerturbationType] def __init__(self, DataFilename=None, ClassificationMarkings=None, FileType=None, DataCheckSum=None, DataSize=None, DataPlane='Slant', DataDomain=None, DataType=None, BitsPerSample=None, DataFormat=None, DataByteOrder=None, NumPixels=None, ImageCollectionDate=None, ZuluOffset=None, SensorReferencePoint=None, SensorCalibrationFactor=None, DataCalibrated=None, Resolution=None, PixelSpacing=None, WeightingType=None, OverSamplingFactor=None, IPRWidth3dB=None, ImageQualityDescription=None, ImageHeading=None, ImageCorners=None, SlantPlane=None, GroundPlane=None, SceneCenterReferenceLine=None, ProjectionPerturbation=None, **kwargs): """ Parameters ---------- DataFilename : str ClassificationMarkings : ClassificationMarkingsType FileType : str DataCheckSum : str DataSize : int DataPlane : str DataDomain : None|str DataType : None|str BitsPerSample : None|int DataFormat : None|str DataByteOrder : None|str NumPixels : NumPixelsType|numpy.ndarray|list|tuple ImageCollectionDate : numpy.datetime64|datetime|date|str ZuluOffset : None|str SensorReferencePoint : None|str SensorCalibrationFactor : None|float DataCalibrated : bool Resolution : RangeCrossRangeType|numpy.ndarray|list|tuple PixelSpacing : RangeCrossRangeType|numpy.ndarray|list|tuple WeightingType : StringRangeCrossRangeType OverSamplingFactor : None|RangeCrossRangeType IPRWidth3dB : None|RangeCrossRangeType|numpy.ndarray|list|tuple ImageQualityDescription : None|str ImageHeading : None|float ImageCorners : ImageCornerType SlantPlane : None|PixelSpacingType GroundPlane : None|PixelSpacingType SceneCenterReferenceLine : None|float ProjectionPerturbation : None|ProjectionPerturbationType kwargs Other keyword arguments """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.DataFilename = DataFilename if ClassificationMarkings is None: self.ClassificationMarkings = ClassificationMarkingsType() else: self.ClassificationMarkings = ClassificationMarkings self.Filetype = FileType self.DataCheckSum = DataCheckSum self.DataSize = DataSize self.DataPlane = DataPlane self.DataDomain = DataDomain self.DataType = DataType self.BitsPerSample = BitsPerSample self.DataFormat = DataFormat self.DataByteOrder = DataByteOrder self.NumPixels = NumPixels self.ImageCollectionDate = ImageCollectionDate self.ZuluOffset = ZuluOffset self.SensorReferencePoint = SensorReferencePoint self.SensorCalibrationFactor = SensorCalibrationFactor self.DataCalibrated = DataCalibrated self.Resolution = Resolution self.PixelSpacing = PixelSpacing self.WeightingType = WeightingType self.OverSamplingFactor = OverSamplingFactor self.IPRWidth3dB = IPRWidth3dB self.ImageQualityDescription = ImageQualityDescription self.ImageHeading = ImageHeading self.ImageCorners = ImageCorners self.SlantPlane = SlantPlane self.GroundPlane = GroundPlane self.SceneCenterReferenceLine = SceneCenterReferenceLine self.ProjectionPerturbation = ProjectionPerturbation super(ImageInfoType, self).__init__(**kwargs) @classmethod def from_sicd(cls, sicd, base_file_name, file_type='NITF02.10', md5_checksum=None): """ Construct the ImageInfo from the sicd object and given image file name. Parameters ---------- sicd : SICDType base_file_name : str file_type : str The file type. This should probably always be NITF02.10 for now. md5_checksum : None|str The md5 checksum of the full image file. Returns ------- ImageInfoType """ pixel_type = sicd.ImageData.PixelType if pixel_type == 'RE32F_IM32F': data_type = 'In-phase/Quadrature' bits_per_sample = 32 data_format = 'float' elif pixel_type == 'RE16I_IM16I': data_type = 'In-phase/Quadrature' bits_per_sample = 16 data_format = 'integer' elif pixel_type == 'AMP8I_PHS8I': data_type = 'Magnitude/Phase' bits_per_sample = 8 data_format = 'unsigned integer' else: raise ValueError('Unhandled') data_cal = sicd.Radiometric is not None icps = ImageCornerType(UpperLeft=sicd.GeoData.ImageCorners.FRFC, UpperRight=sicd.GeoData.ImageCorners.FRLC, LowerRight=sicd.GeoData.ImageCorners.LRLC, LowerLeft=sicd.GeoData.ImageCorners.LRFC) if sicd.Grid.ImagePlane == 'SLANT': data_plane = 'Slant' elif sicd.Grid.ImagePlane == 'Ground': data_plane = 'Ground' else: data_plane = None has_perturb = False proj_perturb = None coa = sicd.coa_projection if coa is not None: delta_arp = coa.delta_arp if numpy.any(delta_arp != 0): has_perturb = True else: delta_arp = None delta_varp = coa.delta_varp if numpy.any(delta_varp != 0): has_perturb = True else: delta_varp = None delta_range = coa.delta_range if delta_range != 0: has_perturb = True else: delta_range = None if has_perturb: proj_perturb = ProjectionPerturbationType( CoordinateFrame='ECF', DeltaArp=delta_arp, DeltaVarp=delta_varp, DeltaRange=delta_range) return ImageInfoType( DataFilename=base_file_name, ClassificationMarkings=ClassificationMarkingsType( Classification=sicd.CollectionInfo.Classification), FileType=file_type, DataCheckSum=md5_checksum, DataPlane=data_plane, DataType=data_type, DataCalibrated=data_cal, BitsPerSample=bits_per_sample, DataDomain='Image', DataFormat=data_format, DataByteOrder='Big-Endian', NumPixels=(sicd.ImageData.NumRows, sicd.ImageData.NumCols), ImageCollectionDate=sicd.Timeline.CollectStart, SensorReferencePoint='Top', Resolution=(sicd.Grid.Row.ImpRespWid, sicd.Grid.Col.ImpRespWid), PixelSpacing=(sicd.Grid.Row.SS, sicd.Grid.Col.SS), WeightingType=StringRangeCrossRangeType( Range=sicd.Grid.Row.WgtType.WindowName, CrossRange=sicd.Grid.Col.WgtType.WindowName), ImageHeading=sicd.SCPCOA.AzimAng, ImageCorners=icps, ProjectionPerturbation=proj_perturb)
class CPHDHeader(CPHDHeaderBase): _fields = ('XML_DATA_SIZE', 'XML_BYTE_OFFSET', 'VB_DATA_SIZE', 'VB_BYTE_OFFSET', 'CPHD_DATA_SIZE', 'CPHD_BYTE_OFFSET', 'CLASSIFICATION', 'RELEASE_INFO') _required = ('XML_DATA_SIZE', 'XML_BYTE_OFFSET', 'VB_DATA_SIZE', 'VB_BYTE_OFFSET', 'CPHD_DATA_SIZE', 'CPHD_BYTE_OFFSET') # descriptor XML_DATA_SIZE = IntegerDescriptor( 'XML_DATA_SIZE', _required, strict=True, docstring= 'Size of the XML Metadata in bytes. Does not include the 2 bytes ' 'of the section terminator.') # type: int XML_BYTE_OFFSET = IntegerDescriptor( 'XML_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the XML Metadata in bytes.' ) # type: int VB_DATA_SIZE = IntegerDescriptor( 'VB_DATA_SIZE', _required, strict=True, docstring='Size of the Vector Based Metadata in bytes.') # type: int VB_BYTE_OFFSET = IntegerDescriptor( 'VB_BYTE_OFFSET', _required, strict=True, docstring= 'Offset to the first byte of the Vector Based Metadata in bytes.' ) # type: int CPHD_DATA_SIZE = IntegerDescriptor( 'CPHD_DATA_SIZE', _required, strict=True, docstring='Size of the Compensated PHD arrays in bytes.') # type: int CPHD_BYTE_OFFSET = IntegerDescriptor( 'CPHD_BYTE_OFFSET', _required, strict=True, docstring='Offset to the first byte of the CPHD data in bytes.' ) # type: int CLASSIFICATION = StringDescriptor( 'CLASSIFICATION', _required, strict=True, default_value='UNCLASSIFIED', docstring= 'Product classification information that is the human-readable banner.' ) # type: str RELEASE_INFO = StringDescriptor( 'RELEASE_INFO', _required, strict=True, default_value='UNRESTRICTED', docstring='Product release information.') # type: str def __init__(self, XML_DATA_SIZE=None, XML_BYTE_OFFSET=None, VB_DATA_SIZE=None, VB_BYTE_OFFSET=None, CPHD_DATA_SIZE=None, CPHD_BYTE_OFFSET=None, CLASSIFICATION='UNCLASSIFIED', RELEASE_INFO='UNRESTRICTED'): self.XML_DATA_SIZE = XML_DATA_SIZE self.XML_BYTE_OFFSET = XML_BYTE_OFFSET self.VB_DATA_SIZE = VB_DATA_SIZE self.VB_BYTE_OFFSET = VB_BYTE_OFFSET self.CPHD_DATA_SIZE = CPHD_DATA_SIZE self.CPHD_BYTE_OFFSET = CPHD_BYTE_OFFSET self.CLASSIFICATION = CLASSIFICATION self.RELEASE_INFO = RELEASE_INFO super(CPHDHeader, self).__init__()
class NumPixelsType(Serializable, Arrayable): """A row and column attribute container - used as indices into array(s).""" _fields = ('NumRows', 'NumCols') _required = _fields NumRows = IntegerDescriptor('NumRows', _required, strict=True, docstring='The number of rows.') # type: int NumCols = IntegerDescriptor( 'NumCols', _required, strict=True, docstring='The number of columns.') # type: int def __init__(self, NumRows=None, NumCols=None, **kwargs): """ Parameters ---------- NumRows : int NumCols : int kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumRows, self.NumCols = NumRows, NumCols super(NumPixelsType, self).__init__(**kwargs) def get_array(self, dtype=numpy.int64): """ Gets an array representation of the class instance. Parameters ---------- dtype : str|numpy.dtype|numpy.number numpy data type of the return Returns ------- numpy.ndarray array of the form [NumRows, NumCols] """ return numpy.array([self.NumRows, self.NumCols], dtype=dtype) @classmethod def from_array(cls, array): """ Create from an array type entry. Parameters ---------- array: numpy.ndarray|list|tuple assumed [NumRows, NumCols] Returns ------- NumPixelsType """ if array is None: return None if isinstance(array, (numpy.ndarray, list, tuple)): if len(array) < 2: raise ValueError( 'Expected array to be of length 2, and received {}'.format( array)) return cls(NumRows=array[0], NumCols=array[1]) raise ValueError( 'Expected array to be numpy.ndarray, list, or tuple, got {}'. format(type(array)))
class FullImageType(Serializable, Arrayable): """ The full image product attributes. """ _fields = ('NumRows', 'NumCols') _required = _fields # descriptors NumRows = IntegerDescriptor( 'NumRows', _required, strict=True, docstring= 'Number of rows in the original full image product. May include zero pixels.' ) # type: int NumCols = IntegerDescriptor( 'NumCols', _required, strict=True, docstring= 'Number of columns in the original full image product. May include zero pixels.' ) # type: int def __init__(self, NumRows=None, NumCols=None, **kwargs): """ Parameters ---------- NumRows : int NumCols : int kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.NumRows, self.NumCols = NumRows, NumCols super(FullImageType, self).__init__(**kwargs) def get_array(self, dtype=numpy.int64): """Gets an array representation of the class instance. Parameters ---------- dtype : str|numpy.dtype|numpy.number numpy data type of the return Returns ------- numpy.ndarray array of the form `[X,Y,Z]` """ return numpy.array([self.NumRows, self.NumCols], dtype=dtype) @classmethod def from_array(cls, array): """ Create from an array type entry. Parameters ---------- array: numpy.ndarray|list|tuple assumed `[NumRows, NumCols]` Returns ------- FullImageType """ if isinstance(array, (numpy.ndarray, list, tuple)): if len(array) < 2: raise ValueError( 'Expected array to be of length 2, and received {}'.format( array)) return cls(NumRows=array[0], NumCols=array[1]) raise ValueError( 'Expected array to be numpy.ndarray, list, or tuple, got {}'. format(type(array)))
class ImageDataType(Serializable): """The image pixel data.""" _collections_tags = { 'AmpTable': { 'array': True, 'child_tag': 'Amplitude' }, 'ValidData': { 'array': True, 'child_tag': 'Vertex' }, } _fields = ('PixelType', 'AmpTable', 'NumRows', 'NumCols', 'FirstRow', 'FirstCol', 'FullImage', 'SCPPixel', 'ValidData') _required = ('PixelType', 'NumRows', 'NumCols', 'FirstRow', 'FirstCol', 'FullImage', 'SCPPixel') _numeric_format = {'AmpTable': FLOAT_FORMAT} _PIXEL_TYPE_VALUES = ("RE32F_IM32F", "RE16I_IM16I", "AMP8I_PHS8I") # descriptors PixelType = StringEnumDescriptor( 'PixelType', _PIXEL_TYPE_VALUES, _required, strict=True, docstring= "The PixelType attribute which specifies the interpretation of the file data." ) # type: str AmpTable = FloatArrayDescriptor( 'AmpTable', _collections_tags, _required, strict=DEFAULT_STRICT, minimum_length=256, maximum_length=256, docstring="The amplitude look-up table. This is required if " "`PixelType == 'AMP8I_PHS8I'`") # type: numpy.ndarray NumRows = IntegerDescriptor( 'NumRows', _required, strict=True, docstring='The number of Rows in the product. May include zero rows.' ) # type: int NumCols = IntegerDescriptor( 'NumCols', _required, strict=True, docstring='The number of Columns in the product. May include zero rows.' ) # type: int FirstRow = IntegerDescriptor( 'FirstRow', _required, strict=DEFAULT_STRICT, docstring='Global row index of the first row in the product. ' 'Equal to 0 in full image product.') # type: int FirstCol = IntegerDescriptor( 'FirstCol', _required, strict=DEFAULT_STRICT, docstring='Global column index of the first column in the product. ' 'Equal to 0 in full image product.') # type: int FullImage = SerializableDescriptor( 'FullImage', FullImageType, _required, strict=DEFAULT_STRICT, docstring='Original full image product.') # type: FullImageType SCPPixel = SerializableDescriptor( 'SCPPixel', RowColType, _required, strict=DEFAULT_STRICT, docstring= 'Scene Center Point pixel global row and column index. Should be located near the ' 'center of the full image.') # type: RowColType ValidData = SerializableArrayDescriptor( 'ValidData', RowColArrayElement, _collections_tags, _required, strict=DEFAULT_STRICT, minimum_length=3, docstring= 'Indicates the full image includes both valid data and some zero filled pixels. ' 'Simple polygon encloses the valid data (may include some zero filled pixels for simplification). ' 'Vertices in clockwise order.' ) # type: Union[SerializableArray, List[RowColArrayElement]] def __init__(self, PixelType=None, AmpTable=None, NumRows=None, NumCols=None, FirstRow=None, FirstCol=None, FullImage=None, SCPPixel=None, ValidData=None, **kwargs): """ Parameters ---------- PixelType : str AmpTable : numpy.ndarray|list|tuple NumRows : int NumCols : int FirstRow : int FirstCol : int FullImage : FullImageType|numpy.ndarray|list|tuple SCPPixel : RowColType|numpy.ndarray|list|tuple ValidData : SerializableArray|List[RowColArrayElement]|numpy.ndarray|list|tuple kwargs """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.PixelType = PixelType self.AmpTable = AmpTable self.NumRows, self.NumCols = NumRows, NumCols self.FirstRow, self.FirstCol = FirstRow, FirstCol self.FullImage = FullImage self.SCPPixel = SCPPixel self.ValidData = ValidData super(ImageDataType, self).__init__(**kwargs) def _check_valid_data(self): if self.ValidData is None: return True if len(self.ValidData) < 2: return True value = True valid_data = self.ValidData.get_array(dtype='float64') lin_ring = LinearRing(coordinates=valid_data) area = lin_ring.get_area() if area == 0: self.log_validity_error('ValidData encloses no area.') value = False elif area > 0: self.log_validity_error( "ValidData must be traversed in clockwise direction.") value = False for i, entry in enumerate(valid_data): if not ( (self.FirstRow <= entry[0] <= self.FirstRow + self.NumRows) and (self.FirstCol <= entry[1] <= self.FirstCol + self.NumCols)): self.log_validity_warning( 'ValidData entry {} is not contained in the image bounds'. format(i)) value = False return value def _basic_validity_check(self): condition = super(ImageDataType, self)._basic_validity_check() if (self.PixelType == 'AMP8I_PHS8I') and (self.AmpTable is None): self.log_validity_error( "We have `PixelType='AMP8I_PHS8I'` and `AmpTable` is not defined for ImageDataType." ) condition = False if (self.PixelType != 'AMP8I_PHS8I') and (self.AmpTable is not None): self.log_validity_error( "We have `PixelType != 'AMP8I_PHS8I'` and `AmpTable` is defined for ImageDataType." ) condition = False if (self.ValidData is not None) and (len(self.ValidData) < 3): self.log_validity_error( "We have `ValidData` defined with fewer than 3 entries.") condition = False condition &= self._check_valid_data() return condition def get_valid_vertex_data(self, dtype=numpy.int64): """ Gets an array of `[row, col]` indices defining the valid data. If this is not viable, then `None` will be returned. Parameters ---------- dtype : object the data type for the array Returns ------- numpy.ndarray|None """ if self.ValidData is None: return None out = numpy.zeros((self.ValidData.size, 2), dtype=dtype) for i, entry in enumerate(self.ValidData): out[i, :] = entry.get_array(dtype=dtype) return out def get_full_vertex_data(self, dtype=numpy.int64): """ Gets an array of `[row, col]` indices defining the full vertex data. If this is not viable, then `None` will be returned. Parameters ---------- dtype : object the data type for the array Returns ------- numpy.ndarray|None """ if self.NumRows is None or self.NumCols is None: return None return numpy.array( [[0, 0], [0, self.NumCols - 1], [self.NumRows - 1, self.NumCols - 1], [self.NumRows - 1, 0]], dtype=dtype) def get_pixel_size(self) -> int: """ Gets the size per pixel, in bytes. Returns ------- int """ if self.PixelType == "RE32F_IM32F": return 8 elif self.PixelType == "RE16I_IM16I": return 4 elif self.PixelType == "AMP8I_PHS8I": return 2 else: raise ValueError('Got unhandled pixel type `{}`'.format( self.PixelType))
class WaveformParametersType(Serializable): """ Transmit and receive demodulation waveform parameters. """ _fields = ( 'TxPulseLength', 'TxRFBandwidth', 'TxFreqStart', 'TxFMRate', 'RcvDemodType', 'RcvWindowLength', 'ADCSampleRate', 'RcvIFBandwidth', 'RcvFreqStart', 'RcvFMRate', 'index') _required = () _set_as_attribute = ('index', ) _numeric_format = { 'TxPulseLength': FLOAT_FORMAT, 'TxRFBandwidth': '0.17E', 'TxFreqStart': '0.17E', 'TxFMRate': '0.17E', 'RcvWindowLength': FLOAT_FORMAT, 'ADCSampleRate': '0.17E', 'RcvIFBandwidth': '0.17E', 'RcvFreqStart': '0.17E', 'RcvFMRate': '0.17E'} # descriptors TxPulseLength = FloatDescriptor( 'TxPulseLength', _required, strict=DEFAULT_STRICT, docstring='Transmit pulse length in seconds.') # type: float TxRFBandwidth = FloatDescriptor( 'TxRFBandwidth', _required, strict=DEFAULT_STRICT, docstring='Transmit RF bandwidth of the transmit pulse in Hz.') # type: float TxFreqStart = FloatDescriptor( 'TxFreqStart', _required, strict=DEFAULT_STRICT, docstring='Transmit Start frequency for Linear FM waveform in Hz, may be relative ' 'to reference frequency.') # type: float TxFMRate = FloatDescriptor( 'TxFMRate', _required, strict=DEFAULT_STRICT, docstring='Transmit FM rate for Linear FM waveform in Hz/second.') # type: float RcvWindowLength = FloatDescriptor( 'RcvWindowLength', _required, strict=DEFAULT_STRICT, docstring='Receive window duration in seconds.') # type: float ADCSampleRate = FloatDescriptor( 'ADCSampleRate', _required, strict=DEFAULT_STRICT, docstring='Analog-to-Digital Converter sampling rate in samples/second.') # type: float RcvIFBandwidth = FloatDescriptor( 'RcvIFBandwidth', _required, strict=DEFAULT_STRICT, docstring='Receive IF bandwidth in Hz.') # type: float RcvFreqStart = FloatDescriptor( 'RcvFreqStart', _required, strict=DEFAULT_STRICT, docstring='Receive demodulation start frequency in Hz, may be relative to reference frequency.') # type: float index = IntegerDescriptor( 'index', _required, strict=False, docstring="The array index.") # type: int def __init__(self, TxPulseLength=None, TxRFBandwidth=None, TxFreqStart=None, TxFMRate=None, RcvDemodType=None, RcvWindowLength=None, ADCSampleRate=None, RcvIFBandwidth=None, RcvFreqStart=None, RcvFMRate=None, index=None, **kwargs): """ Parameters ---------- TxPulseLength : float TxRFBandwidth : float TxFreqStart : float TxFMRate : float RcvDemodType : str RcvWindowLength : float ADCSampleRate : float RcvIFBandwidth : float RcvFreqStart : float RcvFMRate : float index : int kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self._RcvFMRate = None self.TxPulseLength, self.TxRFBandwidth = TxPulseLength, TxRFBandwidth self.TxFreqStart, self.TxFMRate = TxFreqStart, TxFMRate self.RcvWindowLength = RcvWindowLength self.ADCSampleRate = ADCSampleRate self.RcvIFBandwidth = RcvIFBandwidth self.RcvFreqStart = RcvFreqStart # NB: self.RcvDemodType is read only. if RcvDemodType == 'CHIRP' and RcvFMRate is None: self.RcvFMRate = 0.0 else: self.RcvFMRate = RcvFMRate self.index = index super(WaveformParametersType, self).__init__(**kwargs) @property def RcvDemodType(self): # type: () -> Union[None, str] """ str: READ ONLY. Receive demodulation used when Linear FM waveform is used on transmit. This value is derived form the value of `RcvFMRate`. * `None` - `RcvFMRate` is `None`. * `'CHIRP'` - `RcvFMRate=0`. * `'STRETCH'` - `RcvFMRate` is non-zero. """ if self._RcvFMRate is None: return None elif self._RcvFMRate == 0: return 'CHIRP' else: return 'STRETCH' @property def RcvFMRate(self): # type: () -> Union[None, float] """ float: Receive FM rate in Hz/sec. Also, determines the value of `RcvDemodType`. **Optional.** """ return self._RcvFMRate @RcvFMRate.setter def RcvFMRate(self, value): if value is None: self._RcvFMRate = None else: try: self._RcvFMRate = parse_float(value, 'RcvFMRate', self) except Exception as e: logger.error( 'Failed parsing value {} for field RCVFMRate of type "float",\n\t' 'with error {} - {}.\n\t' 'The value has been set to None.'.format(value, type(e), e)) self._RcvFMRate = None def _basic_validity_check(self): valid = super(WaveformParametersType, self)._basic_validity_check() return valid def derive(self): """ Populate derived data in `WaveformParametersType`. Returns ------- None """ if self.TxPulseLength is not None and self.TxFMRate is not None and self.TxRFBandwidth is None: self.TxRFBandwidth = self.TxPulseLength*self.TxFMRate if self.TxPulseLength is not None and self.TxRFBandwidth is not None and self.TxFMRate is None: self.TxFMRate = self.TxRFBandwidth/self.TxPulseLength if self.TxFMRate is not None and self.TxRFBandwidth is not None and self.TxPulseLength is None: self.TxPulseLength = self.TxRFBandwidth/self.TxFMRate def _apply_reference_frequency(self, reference_frequency): if self.TxFreqStart is not None: self.TxFreqStart += reference_frequency if self.RcvFreqStart is not None: self.RcvFreqStart += reference_frequency
class RadarCollectionType(Serializable): """The Radar Collection Type""" _fields = ( 'TxFrequency', 'RefFreqIndex', 'Waveform', 'TxPolarization', 'TxSequence', 'RcvChannels', 'Area', 'Parameters') _required = ('TxFrequency', 'TxPolarization', 'RcvChannels') _collections_tags = { 'Waveform': {'array': True, 'child_tag': 'WFParameters'}, 'TxSequence': {'array': True, 'child_tag': 'TxStep'}, 'RcvChannels': {'array': True, 'child_tag': 'ChanParameters'}, 'Parameters': {'array': False, 'child_tag': 'Parameter'}} # descriptors TxFrequency = SerializableDescriptor( 'TxFrequency', TxFrequencyType, _required, strict=DEFAULT_STRICT, docstring='The transmit frequency range.') # type: TxFrequencyType RefFreqIndex = IntegerDescriptor( 'RefFreqIndex', _required, strict=DEFAULT_STRICT, docstring='The reference frequency index, if applicable. If present and non-zero, ' 'all (most) RF frequency values are expressed as offsets from a reference ' 'frequency.') # type: int Waveform = SerializableArrayDescriptor( 'Waveform', WaveformParametersType, _collections_tags, _required, strict=DEFAULT_STRICT, minimum_length=1, docstring='Transmit and receive demodulation waveform parameters.' ) # type: Union[SerializableArray, List[WaveformParametersType]] TxPolarization = StringEnumDescriptor( 'TxPolarization', POLARIZATION1_VALUES, _required, strict=DEFAULT_STRICT, docstring='The transmit polarization.') # type: str TxSequence = SerializableArrayDescriptor( 'TxSequence', TxStepType, _collections_tags, _required, strict=DEFAULT_STRICT, minimum_length=1, docstring='The transmit sequence parameters array. If present, indicates the transmit signal steps through ' 'a repeating sequence of waveforms and/or polarizations. ' 'One step per Inter-Pulse Period.') # type: Union[SerializableArray, List[TxStepType]] RcvChannels = SerializableArrayDescriptor( 'RcvChannels', ChanParametersType, _collections_tags, _required, strict=DEFAULT_STRICT, minimum_length=1, docstring='Receive data channel parameters.') # type: Union[SerializableArray, List[ChanParametersType]] Area = SerializableDescriptor( 'Area', AreaType, _required, strict=DEFAULT_STRICT, docstring='The imaged area covered by the collection.') # type: AreaType Parameters = ParametersDescriptor( 'Parameters', _collections_tags, _required, strict=DEFAULT_STRICT, docstring='A parameters collections.') # type: ParametersCollection def __init__(self, TxFrequency=None, RefFreqIndex=None, Waveform=None, TxPolarization=None, TxSequence=None, RcvChannels=None, Area=None, Parameters=None, **kwargs): """ Parameters ---------- TxFrequency : TxFrequencyType|numpy.ndarray|list|tuple RefFreqIndex : int Waveform : SerializableArray|List[WaveformParametersType] TxPolarization : str TxSequence : SerializableArray|List[TxStepType] RcvChannels : SerializableArray|List[ChanParametersType] Area : AreaType Parameters : ParametersCollection|dict kwargs : dict """ if '_xml_ns' in kwargs: self._xml_ns = kwargs['_xml_ns'] if '_xml_ns_key' in kwargs: self._xml_ns_key = kwargs['_xml_ns_key'] self.TxFrequency = TxFrequency self.RefFreqIndex = RefFreqIndex self.Waveform = Waveform self.TxPolarization = TxPolarization self.TxSequence = TxSequence self.RcvChannels = RcvChannels self.Area = Area self.Parameters = Parameters super(RadarCollectionType, self).__init__(**kwargs) def derive(self): """ Populates derived data in RadarCollection. Expected to be called by `SICD` parent. Returns ------- None """ self._derive_tx_polarization() if self.Area is not None: self.Area.derive() if self.Waveform is not None: for entry in self.Waveform: entry.derive() self._derive_tx_frequency() # call after waveform entry derive call self._derive_wf_params() def _derive_tx_polarization(self): def check_sequence(): unique_entries = set(entry.TxPolarization for entry in self.TxSequence) if len(unique_entries) == 1: self.TxPolarization = self.TxSequence[0].TxPolarization else: self.TxPolarization = 'SEQUENCE' # TxPolarization was optional prior to SICD 1.0. It may need to be derived. if self.TxSequence is not None: check_sequence() return if self.TxPolarization is not None: return # nothing to be done if self.RcvChannels is None: return # nothing to derive from if len(self.RcvChannels) > 1: # TxSequence may need to be derived from RCvChannels, for SICD before 1.0 or poorly formed if self.TxSequence is not None or self.RcvChannels is None or len(self.RcvChannels) < 2: return tx_pols = list(chan_param.get_transmit_polarization() for chan_param in self.RcvChannels) if len(tx_pols) > 1: self.TxSequence = [TxStepType(index=i+1, TxPolarization=tx_pol) for i, tx_pol in enumerate(tx_pols)] check_sequence() else: self.TxPolarization = tx_pols[0] else: self.TxPolarization = self.RcvChannels[0].get_transmit_polarization() def _derive_tx_frequency(self): if self.Waveform is None or self.Waveform.size == 0: return # nothing to be done if not(self.TxFrequency is None or self.TxFrequency.Min is None or self.TxFrequency.Max is None): return # no need to do anything if self.TxFrequency is None: self.TxFrequency = TxFrequencyType() if self.TxFrequency.Min is None: self.TxFrequency.Min = min( entry.TxFreqStart for entry in self.Waveform if entry.TxFreqStart is not None) if self.TxFrequency.Max is None: self.TxFrequency.Max = max( (entry.TxFreqStart + entry.TxRFBandwidth) for entry in self.Waveform if entry.TxFreqStart is not None and entry.TxRFBandwidth is not None) def _derive_wf_params(self): if self.TxFrequency is None or self.TxFrequency.Min is None or self.TxFrequency.Max is None: return # nothing that we can do if self.Waveform is None or self.Waveform.size != 1: return # nothing to be done entry = self.Waveform[0] # only true for single waveform definition if entry.TxFreqStart is None: entry.TxFreqStart = self.TxFrequency.Min if entry.TxRFBandwidth is None: entry.TxRFBandwidth = self.TxFrequency.Max - self.TxFrequency.Min def _apply_reference_frequency(self, reference_frequency): """ If the reference frequency is used, adjust the necessary fields accordingly. Expected to be called by `SICD` parent. Parameters ---------- reference_frequency : float The reference frequency. Returns ------- None """ if self.TxFrequency is not None: # noinspection PyProtectedMember self.TxFrequency._apply_reference_frequency(reference_frequency) if self.Waveform is not None: for entry in self.Waveform: # noinspection PyProtectedMember entry._apply_reference_frequency(reference_frequency) self.RefFreqIndex = 0 def get_polarization_abbreviation(self): """ Gets the polarization collection abbreviation for the suggested name. Returns ------- str """ if self.RcvChannels is None: pol_count = 0 else: pol_count = len(self.RcvChannels) if pol_count == 1: return 'S' elif pol_count == 2: return 'D' elif pol_count == 3: return 'T' elif pol_count > 3: return 'Q' else: return 'U' def _check_frequency(self): # type: () -> bool if self.RefFreqIndex is not None: return True if self.TxFrequency is not None and self.TxFrequency.Min is not None \ and self.TxFrequency.Min <= 0: self.log_validity_error( 'TxFrequency.Min is negative, but RefFreqIndex is not populated.') return False return True def _check_tx_sequence(self): # type: () -> bool cond = True if self.TxPolarization == 'SEQUENCE' and self.TxSequence is None: self.log_validity_error( 'TxPolarization is populated as "SEQUENCE", but TxSequence is not populated.') cond = False if self.TxSequence is not None: if self.TxPolarization != 'SEQUENCE': self.log_validity_error( 'TxSequence is populated, but TxPolarization is populated as {}'.format(self.TxPolarization)) cond = False tx_pols = list(set([entry.TxPolarization for entry in self.TxSequence])) if len(tx_pols) == 1: self.log_validity_error( 'TxSequence is populated, but the only unique TxPolarization ' 'among the entries is {}'.format(tx_pols[0])) cond = False return cond def _check_waveform_parameters(self): """ Validate the waveform parameters for consistency. Returns ------- bool """ def validate_entry(index, waveform): # type: (int, WaveformParametersType) -> bool this_cond = True try: if abs(waveform.TxRFBandwidth/(waveform.TxPulseLength*waveform.TxFMRate) - 1) > 1e-3: self.log_validity_error( 'The TxRFBandwidth, TxPulseLength, and TxFMRate parameters of Waveform ' 'entry {} are inconsistent'.format(index+1)) this_cond = False except (AttributeError, ValueError, TypeError): pass if waveform.RcvDemodType == 'CHIRP' and waveform.RcvFMRate != 0: self.log_validity_error( 'RcvDemodType == "CHIRP" and RcvFMRate != 0 in Waveform entry {}'.format(index+1)) this_cond = False if waveform.RcvDemodType == 'STRETCH' and \ waveform.RcvFMRate is not None and waveform.TxFMRate is not None and \ abs(waveform.RcvFMRate/waveform.TxFMRate - 1) > 1e-3: self.log_validity_warning( 'RcvDemodType = "STRETCH", RcvFMRate = {}, and TxFMRate = {} in ' 'Waveform entry {}. The RcvFMRate and TxFMRate should very likely ' 'be the same.'.format(waveform.RcvFMRate, waveform.TxFMRate, index+1)) if self.RefFreqIndex is None: if waveform.TxFreqStart <= 0: self.log_validity_error( 'TxFreqStart is negative in Waveform entry {}, but RefFreqIndex ' 'is not populated.'.format(index+1)) this_cond = False if waveform.RcvFreqStart is not None and waveform.RcvFreqStart <= 0: self.log_validity_error( 'RcvFreqStart is negative in Waveform entry {}, but RefFreqIndex ' 'is not populated.'.format(index + 1)) this_cond = False if waveform.TxPulseLength is not None and waveform.RcvWindowLength is not None and \ waveform.TxPulseLength > waveform.RcvWindowLength: self.log_validity_error( 'TxPulseLength ({}) is longer than RcvWindowLength ({}) in ' 'Waveform entry {}'.format(waveform.TxPulseLength, waveform.RcvWindowLength, index+1)) this_cond = False if waveform.RcvIFBandwidth is not None and waveform.ADCSampleRate is not None and \ waveform.RcvIFBandwidth > waveform.ADCSampleRate: self.log_validity_error( 'RcvIFBandwidth ({}) is longer than ADCSampleRate ({}) in ' 'Waveform entry {}'.format(waveform.RcvIFBandwidth, waveform.ADCSampleRate, index+1)) this_cond = False if waveform.RcvDemodType is not None and waveform.RcvDemodType == 'CHIRP' \ and waveform.TxRFBandwidth is not None and waveform.ADCSampleRate is not None \ and (waveform.TxRFBandwidth > waveform.ADCSampleRate): self.log_validity_error( 'RcvDemodType is "CHIRP" and TxRFBandwidth ({}) is larger than ADCSampleRate ({}) ' 'in Waveform entry {}'.format(waveform.TxRFBandwidth, waveform.ADCSampleRate, index+1)) this_cond = False if waveform.RcvWindowLength is not None and waveform.TxPulseLength is not None and \ waveform.TxFMRate is not None and waveform.RcvFreqStart is not None and \ waveform.TxFreqStart is not None and waveform.TxRFBandwidth is not None: freq_tol = (waveform.RcvWindowLength - waveform.TxPulseLength)*waveform.TxFMRate if waveform.RcvFreqStart >= waveform.TxFreqStart + waveform.TxRFBandwidth + freq_tol: self.log_validity_error( 'RcvFreqStart ({}), TxFreqStart ({}), and TxRfBandwidth ({}) parameters are inconsistent ' 'in Waveform entry {}'.format( waveform.RcvFreqStart, waveform.TxFreqStart, waveform.TxRFBandwidth, index + 1)) this_cond = False if waveform.RcvFreqStart <= waveform.TxFreqStart - freq_tol: self.log_validity_error( 'RcvFreqStart ({}) and TxFreqStart ({}) parameters are inconsistent ' 'in Waveform entry {}'.format(waveform.RcvFreqStart, waveform.TxFreqStart, index + 1)) this_cond = False return this_cond if self.Waveform is None or len(self.Waveform) < 1: return True cond = True # fetch min/max TxFreq observed wf_min_freq = None wf_max_freq = None for entry in self.Waveform: freq_start = entry.TxFreqStart freq_bw = entry.TxRFBandwidth if freq_start is not None: wf_min_freq = freq_start if wf_min_freq is None else \ min(wf_min_freq, freq_start) if entry.TxRFBandwidth is not None: wf_max_freq = freq_start + freq_bw if wf_max_freq is None else \ max(wf_max_freq, freq_start + freq_bw) if wf_min_freq is not None and self.TxFrequency is not None and self.TxFrequency.Min is not None: if abs(self.TxFrequency.Min/wf_min_freq - 1) > 1e-3: self.log_validity_error( 'The stated TxFrequency.Min is {}, but the minimum populated in a ' 'Waveform entry is {}'.format(self.TxFrequency.Min, wf_min_freq)) cond = False if wf_max_freq is not None and self.TxFrequency is not None and self.TxFrequency.Max is not None: if abs(self.TxFrequency.Max/wf_max_freq - 1) > 1e-3: self.log_validity_error( 'The stated TxFrequency.Max is {}, but the maximum populated in a ' 'Waveform entry is {}'.format(self.TxFrequency.Max, wf_max_freq)) cond = False for t_index, t_waveform in enumerate(self.Waveform): cond &= validate_entry(t_index, t_waveform) return cond def _basic_validity_check(self): valid = super(RadarCollectionType, self)._basic_validity_check() valid &= self._check_frequency() valid &= self._check_tx_sequence() valid &= self._check_waveform_parameters() return valid def permits_version_1_1(self): """ Does this value permit storage in SICD version 1.1? Returns ------- bool """ if self.RcvChannels is None: return True cond = True for entry in self.RcvChannels: cond &= entry.permits_version_1_1() return cond