kwcoco.sensorchan_spec module

This is an extension of kwcoco.channel_spec, which augments channel information with an associated sensor attribute. Eventually, this will entirely replace the channel spec.

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> # hack for 3.6
>>> from kwcoco import sensorchan_spec
>>> import kwcoco
>>> kwcoco.SensorChanSpec = sensorchan_spec.SensorChanSpec
>>> self = kwcoco.SensorChanSpec.coerce('sensor0:B1|B8|B8a|B10|B11,sensor1:B11|X.2|Y:2:6,sensor2:r|g|b|disparity|gauss|B8|B11,sensor3:r|g|b|flowx|flowy|distri|B10|B11')
>>> self.normalize()
class kwcoco.sensorchan_spec.Transformer[source]

Bases: object

class kwcoco.sensorchan_spec.SensorSpec(spec)[source]

Bases: NiceRepr

A simple wrapper for sensors in case we want to do anything fancy with them later. For now they are just a string.

class kwcoco.sensorchan_spec.SensorChanSpec(spec: str)[source]

Bases: NiceRepr

The public facing API for the sensor / channel specification

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import SensorChanSpec
>>> self = SensorChanSpec('(L8,S2):BGR,WV:BGR,S2:nir,L8:land.0:4')
>>> s1 = self.normalize()
>>> s2 = self.concise()
>>> streams = self.streams()
>>> print(s1)
>>> print(s2)
>>> print('streams = {}'.format(ub.repr2(streams, sv=1, nl=1)))
L8:BGR,S2:BGR,WV:BGR,S2:nir,L8:land.0|land.1|land.2|land.3
(L8,S2,WV):BGR,L8:land:4,S2:nir
streams = [
    L8:BGR,
    S2:BGR,
    WV:BGR,
    S2:nir,
    L8:land.0|land.1|land.2|land.3,
]

Example

>>> # Check with generic sensors
>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import SensorChanSpec
>>> import kwcoco
>>> self = SensorChanSpec('(*):BGR,*:BGR,*:nir,*:land.0:4')
>>> self.concise().normalize()
>>> s1 = self.normalize()
>>> s2 = self.concise()
>>> print(s1)
>>> print(s2)
*:BGR,*:BGR,*:nir,*:land.0|land.1|land.2|land.3
(*,*):BGR,*:(nir,land:4)
>>> import kwcoco
>>> c = kwcoco.ChannelSpec.coerce('BGR,BGR,nir,land.0:8')
>>> c1 = c.normalize()
>>> c2 = c.concise()
>>> print(c1)
>>> print(c2)

Example

>>> # Check empty channels
>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import SensorChanSpec
>>> import kwcoco
>>> print(SensorChanSpec('*:').normalize())
*:
>>> print(SensorChanSpec('sen:').normalize())
sen:
>>> print(SensorChanSpec('sen:').normalize().concise())
sen:
>>> print(SensorChanSpec('sen:').concise().normalize().concise())
sen:
classmethod coerce(data)[source]

Attempt to interpret the data as a channel specification

Returns

SensorChanSpec

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import *  # NOQA
>>> from kwcoco.sensorchan_spec import SensorChanSpec
>>> data = SensorChanSpec.coerce(3)
>>> assert SensorChanSpec.coerce(data).normalize().spec == '*:u0|u1|u2'
>>> data = SensorChanSpec.coerce(3)
>>> assert data.spec == 'u0|u1|u2'
>>> assert SensorChanSpec.coerce(data).spec == 'u0|u1|u2'
>>> data = SensorChanSpec.coerce('u:3')
>>> assert data.normalize().spec == '*:u.0|u.1|u.2'
normalize()[source]
concise()[source]
streams()[source]
Returns

List of sensor-names and fused channel specs

Return type

List[FusedSensorChanSpec]

late_fuse(other)[source]

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> import kwcoco
>>> a = kwcoco.SensorChanSpec.coerce('A|B|C,edf')
>>> b = kwcoco.SensorChanSpec.coerce('A12')
>>> c = kwcoco.SensorChanSpec.coerce('')
>>> d = kwcoco.SensorChanSpec.coerce('rgb')
>>> print(a.late_fuse(b).spec)
>>> print((a + b).spec)
>>> print((b + a).spec)
>>> print((a + b + c).spec)
>>> print(sum([a, b, c, d]).spec)
A|B|C,edf,A12
A|B|C,edf,A12
A12,A|B|C,edf
A|B|C,edf,A12
A|B|C,edf,A12,rgb
>>> import kwcoco
>>> a = kwcoco.SensorChanSpec.coerce('A|B|C,edf').normalize()
>>> b = kwcoco.SensorChanSpec.coerce('A12').normalize()
>>> c = kwcoco.SensorChanSpec.coerce('').normalize()
>>> d = kwcoco.SensorChanSpec.coerce('rgb').normalize()
>>> print(a.late_fuse(b).spec)
>>> print((a + b).spec)
>>> print((b + a).spec)
>>> print((a + b + c).spec)
>>> print(sum([a, b, c, d]).spec)
*:A|B|C,*:edf,*:A12
*:A|B|C,*:edf,*:A12
*:A12,*:A|B|C,*:edf
*:A|B|C,*:edf,*:A12,*:
*:A|B|C,*:edf,*:A12,*:,*:rgb
>>> print((a.late_fuse(b)).concise())
>>> print(((a + b)).concise())
>>> print(((b + a)).concise())
>>> print(((a + b + c)).concise())
>>> print((sum([a, b, c, d])).concise())
*:(A|B|C,edf,A12)
*:(A|B|C,edf,A12)
*:(A12,A|B|C,edf)
*:(A|B|C,edf,A12,)
*:(A|B|C,edf,A12,,r|g|b)
matching_sensor(sensor)[source]

Get the components corresponding to a specific sensor

Parameters

sensor (str) – the name of the sensor to match

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> import kwcoco
>>> self = kwcoco.SensorChanSpec.coerce('(S1,S2):(a|b|c),S2:c|d|e')
>>> sensor = 'S2'
>>> new = self.matching_sensor(sensor)
>>> print(f'new={new}')
new=S2:a|b|c,S2:c|d|e
>>> print(self.matching_sensor('S1'))
S1:a|b|c
>>> print(self.matching_sensor('S3'))
S3:
property chans

Returns the channel-only spec, ONLY if all of the sensors are the same

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> import kwcoco
>>> self = kwcoco.SensorChanSpec.coerce('(S1,S2):(a|b|c),S2:c|d|e')
>>> import pytest
>>> with pytest.raises(Exception):
>>>     self.chans
>>> print(self.matching_sensor('S1').chans.spec)
>>> print(self.matching_sensor('S2').chans.spec)
a|b|c
a|b|c,c|d|e
class kwcoco.sensorchan_spec.FusedSensorChanSpec(sensor, chans)[source]

Bases: SensorChanSpec

A single sensor a corresponding fused channels.

property chans
property spec
class kwcoco.sensorchan_spec.SensorChanNode(sensor, chan)[source]

Bases: object

TODO: just replace this with the spec class itself?

property spec
class kwcoco.sensorchan_spec.FusedChanNode(chan)[source]

Bases: object

TODO: just replace this with the spec class itself?

Example

s = FusedChanNode(‘a|b|c.0|c.1|c.2’) c = s.concise() print(s) print(c)

property spec
concise()[source]
class kwcoco.sensorchan_spec.SensorChanTransformer(concise_channels=1, concise_sensors=1)[source]

Bases: Transformer

Given a parsed tree for a sensor-chan spec, can transform it into useful forms.

Todo

Make the classes that hold the underlying data more robust such that they either use the existing channel spec or entirely replace it. (probably the former). Also need to add either a FusedSensorChan node that is restircted to only a single sensor and group of fused channels.

chan_id(items)[source]
chan_single(items)[source]
chan_getitem(items)[source]
chan_getslice_0b(items)[source]
chan_getslice_ab(items)[source]
chan_code(items)[source]
sensor_seq(items)[source]
fused_seq(items)[source]
fused(items)[source]
channel_rhs(items)[source]
sensor_lhs(items)[source]
nosensor_chan(items)[source]
sensor_chan(items)[source]
stream_item(items)[source]
stream(items)[source]
kwcoco.sensorchan_spec.normalize_sensor_chan(spec)[source]

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import *  # NOQA
>>> spec = 'L8:mat:4,L8:red,S2:red,S2:forest|brush,S2:mat.0|mat.1|mat.2|mat.3'
>>> r1 = normalize_sensor_chan(spec)
>>> spec = 'L8:r|g|b,L8:r|g|b'
>>> r2 = normalize_sensor_chan(spec)
>>> print(f'r1={r1}')
>>> print(f'r2={r2}')
r1=L8:mat.0|mat.1|mat.2|mat.3,L8:red,S2:red,S2:forest|brush,S2:mat.0|mat.1|mat.2|mat.3
r2=L8:r|g|b,L8:r|g|b
kwcoco.sensorchan_spec.concise_sensor_chan(spec)[source]

Example

>>> # xdoctest: +REQUIRES(module:lark)
>>> from kwcoco.sensorchan_spec import *  # NOQA
>>> spec = 'L8:mat.0|mat.1|mat.2|mat.3,L8:red,S2:red,S2:forest|brush,S2:mat.0|mat.1|mat.2|mat.3'
>>> concise_spec = concise_sensor_chan(spec)
>>> normed_spec = normalize_sensor_chan(concise_spec)
>>> concise_spec2 = concise_sensor_chan(normed_spec)
>>> assert concise_spec2 == concise_spec
>>> print(concise_spec)
(L8,S2):(mat:4,red),S2:forest|brush
kwcoco.sensorchan_spec.sensorchan_concise_parts(spec)[source]
kwcoco.sensorchan_spec.sensorchan_normalized_parts(spec)[source]