camfi.datamodel.locationtime module¶
Provides classes for operating on location and time information for camera placements. Depends on camfi.util.
- class camfi.datamodel.locationtime.LocationTime(*, camera_start_time: datetime.datetime, actual_start_time: datetime.datetime = None, camera_end_time: datetime.datetime = None, actual_end_time: datetime.datetime = None, location: str = None)¶
Bases:
pydantic.main.BaseModelDefines camera placement data. Specifically, it includes camera placement time and camera retrieval time (both according to the camera’s clock, and real time), as well as a string specifying the location the camera was placed. Provides a the .corrector method, which returns a DatetimeCorrector function for inferring real time from camera timestamps (useful if cameras have inaccurate clocks).
- Parameters
camera_start_time (datetime) – Timestamp from when the camera was placed (according to the camera’s clock).
actual_start_time (Optional[datetime]) – Actual timestamp from when the camera was placed (real time). Defaults to camera_start_time.
camera_end_time (Optional[datetime]) – Timestamp from when the camera was retrieved (according to the camera’s clock).
actual_end_time (Optional[datetime]) – Actual timestamp from when the camera was retrieved (real time).
location (Optional[str]) – String specifying the location the camera was placed in.
- corrector(camera_time_to_actual_time_ratio: Optional[float] = None) Callable[[datetime.datetime], datetime.datetime]¶
Returns a datetime corrector function, which takes an original camera- reported datetime as an argument, and returns a corrected datetime. If self.actual_start_time is None, then it is assumed that self.camera_start_time reflects the actual time. Generally it is advised to set the time of the camera just before it is placed out, which is the basis for this assumption.
- Parameters
camera_time_to_actual_time_ratio (Optional[float]) – The amount of time elapsed as reported by the camera divided by the actual amount of time elapsed. If None, then this is inferred from the fields of the LocationTime instance. In this case, both self.camera_end_time and self.actual_end_time must be set.
- Returns
datetime_corrector – Function which maps camera time to real time.
- Return type
DatetimeCorrector
Examples
>>> location_time = LocationTime(camera_start_time="2021-07-15T14:00") >>> location_corrector = location_time.corrector(2.) >>> location_corrector(datetime(2021, 7, 15, 16, 0)) datetime.datetime(2021, 7, 15, 15, 0)
Also works with offset-aware datetimes.
>>> location_time = LocationTime(camera_start_time="2021-07-15T14:00+10") >>> location_corrector = location_time.corrector(2.) >>> location_corrector(datetime.fromisoformat("2021-07-15T17:00+11:00")) datetime.datetime(2021, 7, 15, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=36000)))
If self.camera_start_time is offset aware, but the argument to the DatetimeCorrector function is not, it will be assumed that the argument has the same offset as self.camera_start_time.
>>> location_time = LocationTime(camera_start_time="2021-07-15T14:00+10") >>> location_corrector = location_time.corrector(2.) >>> location_corrector(datetime.fromisoformat("2021-07-15T16:00")) datetime.datetime(2021, 7, 15, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=36000)))
However, the converse raises a TypeError.
>>> location_time = LocationTime(camera_start_time="2021-07-15T14:00") >>> location_corrector = location_time.corrector(2.) >>> location_corrector(datetime.fromisoformat("2021-07-15T16:00+10:00")) Traceback (most recent call last): ... TypeError: Cannot call offset-naive DatetimeCorrector with offset-aware datetime.
Raises an error if camera_time_to_actual_time_ratio cannot be determined.
>>> location_time = LocationTime(camera_start_time="2021-07-15T14:00") >>> location_corrector = location_time.corrector() Traceback (most recent call last): ... ValueError: Must set camera_time_to_actual_time_ratio or both end times
- get_time_ratio() Optional[float]¶
If self.camera_end_time and self.actual_end_time are set, gets the camera time to actual time ratio. Otherwise, None
- Returns
camera_time_to_actual_time_ratio – (Time elapsed on cameras cloack) / (Real time elapsed)
- Return type
float
Examples
>>> location_time = LocationTime( ... camera_start_time="2021-07-15T14:00", ... camera_end_time="2021-07-15T16:00", ... actual_end_time="2021-07-15T15:00", ... ) >>> location_time.get_time_ratio() 2.0
camera_end_time and actual_end_time must be set, or else None is returned.
>>> print(LocationTime(camera_start_time="2021-07-15T14:00").get_time_ratio()) None
- class camfi.datamodel.locationtime.LocationTimeCollector(*, camera_placements: dict)¶
Bases:
pydantic.main.BaseModelUsed to generate SubDirDict instances which map subdirectories to location strings or DatetimeCorrectors.
- Parameters
camera_placements (dict[str, LocationTime]) – dictionary mapping directories to LocationTime instances. For example, you might have one LocationTime for each camera placement, and each camera placement also has it’s own directory for images.
Examples
Here, LocationTimeCollector is instantiated with two LocationTime instances. The first has enough information to get a float from its .get_time_rato method, However the second doesn’t.
>>> lt_collector = LocationTimeCollector(camera_placements={ ... "data": LocationTime( ... camera_start_time="2021-07-15T14:00", ... camera_end_time="2021-07-15T16:00", ... actual_end_time="2021-07-15T15:00", ... ), ... "foo": LocationTime(camera_start_time="2021-07-15T13:00"), ... })
When calling the .get_time_ratio method on a LocationTimeCollector instance, the mean of all (excluding those who return None) .get_time_ratio results from all the LocationTimes is given.
>>> lt_collector.get_time_ratio() 2.0
- get_correctors(camera_time_to_actual_time_ratio: Optional[float] = None) camfi.util.SubDirDict[Callable[[datetime.datetime], datetime.datetime]]¶
Calls the .corrector method on each LocationTime in self.camera_placements to produce a SubDirDict of datetime_corrector functions.
- Parameters
camera_time_to_actual_time_ratio (Optional[float]) – The amount of time elapsed as reported by the camera divided by the actual amount of time elapsed. If None, then this is inferred by calling self.get_time_ratio(). If this returns None, a RuntimeError is raised.
- Returns
datetime_correctors – A mapping from subdirectories to DatetimeCorrector functions.
- Return type
SubDirDict[DatetimeCorrector]
Examples
>>> lt_collector = LocationTimeCollector(camera_placements={ ... "data": LocationTime( ... camera_start_time="2021-07-15T14:00", ... camera_end_time="2021-07-15T16:00", ... actual_end_time="2021-07-15T15:00", ... ), ... "foo": LocationTime(camera_start_time="2021-07-15T13:00"), ... }) >>> datetime_correctors = lt_collector.get_correctors( ... camera_time_to_actual_time_ratio=2.0 ... ) >>> datetime_correctors["data"](datetime(2021, 7, 15, 18, 0)) datetime.datetime(2021, 7, 15, 16, 0)
If camera_time_to_actual_time_ratio is not set, it is calculated from the camera_placements in the LocationTimeCollector
>>> datetime_correctors = lt_collector.get_correctors() >>> datetime_correctors["data"](datetime(2021, 7, 15, 18, 0)) datetime.datetime(2021, 7, 15, 16, 0)
But don’t do this if there isn’t enough information
>>> lt_collector = LocationTimeCollector(camera_placements={ ... "foo": LocationTime(camera_start_time="2021-07-15T13:00"), ... }) >>> print(lt_collector.get_time_ratio()) None >>> datetime_correctors = lt_collector.get_correctors() Traceback (most recent call last): ... RuntimeError: Unable to calculate camera-to-actual time ratio from time data
- get_location_dict() camfi.util.SubDirDict[Optional[str]]¶
Produces a SubDirDict of location strings.
- Returns
location_dict – A mapping from subdirectories to location strings.
- Return type
Examples
>>> lt_collector = LocationTimeCollector(camera_placements={ ... "data": LocationTime( ... camera_start_time="2021-07-15T14:00", ... camera_end_time="2021-07-15T16:00", ... actual_end_time="2021-07-15T15:00", ... location="loc0", ... ), ... "foo": LocationTime( ... camera_start_time="2021-07-15T13:00", ... location="loc1", ... ), ... "bar": LocationTime(camera_start_time="2021-07-15T13:00"), ... }) >>> lt_collector.get_location_dict() SubDirDict({Path('data'): 'loc0', Path('foo'): 'loc1', Path('bar'): None})
- get_time_ratio() Optional[float]¶
Gets the mean of calling the .get_time_ratio method on each LocationTime in self.camera_placements.
- Returns
camera_time_to_actual_time_ratio – The mean of (Time elapsed on cameras cloack) / (Real time elapsed) for all camera placements (LocationTime instances) in self which have sufficent data to determine this value.
- Return type
float
Examples
If there is not enough information to calculate a time ratio, None is returned.
>>> lt_collector = LocationTimeCollector(camera_placements={ ... "foo": LocationTime(camera_start_time="2021-07-15T13:00"), ... }) >>> print(lt_collector.get_time_ratio()) None