initial structure implemented

docs -> _docs
This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-12-01 14:20:56 +02:00
parent 9134c5db06
commit abc26d5c20
360 changed files with 3881 additions and 101 deletions
+11
View File
@@ -0,0 +1,11 @@
from .core import *
from .flight import *
from .processing import *
from .chunks import *
from .satellite import *
from .recovery import *
from .results import *
from .images import *
from .config import *
from .api import *
+27
View File
@@ -0,0 +1,27 @@
from .flight_requests import FlightCreateRequest
from .flight_responses import (
FlightResponse,
FlightDetailResponse,
FlightStatusResponse,
DeleteResponse,
UpdateResponse,
BatchUpdateResponse,
)
from .batch_requests import BatchMetadata, BatchResponse
from .user_fix_requests import UserFixRequest, UserFixResponse, ObjectGPSResponse
__all__ = [
"FlightCreateRequest",
"FlightResponse",
"FlightDetailResponse",
"FlightStatusResponse",
"DeleteResponse",
"UpdateResponse",
"BatchUpdateResponse",
"BatchMetadata",
"BatchResponse",
"UserFixRequest",
"UserFixResponse",
"ObjectGPSResponse",
]
+16
View File
@@ -0,0 +1,16 @@
from typing import Optional
from pydantic import BaseModel
class BatchMetadata(BaseModel):
start_sequence: int
end_sequence: int
batch_number: int
class BatchResponse(BaseModel):
accepted: bool
sequences: list[int]
next_expected: int
message: Optional[str] = None
+15
View File
@@ -0,0 +1,15 @@
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
from ..core.camera_parameters import CameraParameters
from ..flight.geofences import Geofences
class FlightCreateRequest(BaseModel):
name: str
description: str
start_gps: GPSPoint
rough_waypoints: list[GPSPoint]
geofences: Geofences
camera_params: CameraParameters
altitude: float
+61
View File
@@ -0,0 +1,61 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
from ..core.camera_parameters import CameraParameters
from ..flight.waypoint import Waypoint
from ..flight.geofences import Geofences
class FlightResponse(BaseModel):
flight_id: str
status: str
message: Optional[str] = None
created_at: datetime
class FlightDetailResponse(BaseModel):
flight_id: str
name: str
description: str
start_gps: GPSPoint
waypoints: list[Waypoint]
geofences: Geofences
camera_params: CameraParameters
altitude: float
status: str
frames_processed: int
frames_total: int
created_at: datetime
updated_at: datetime
class FlightStatusResponse(BaseModel):
status: str
frames_processed: int
frames_total: int
current_frame: Optional[int] = None
current_heading: Optional[float] = None
blocked: bool = False
search_grid_size: Optional[int] = None
message: Optional[str] = None
created_at: datetime
updated_at: datetime
class DeleteResponse(BaseModel):
deleted: bool
flight_id: str
class UpdateResponse(BaseModel):
updated: bool
waypoint_id: str
class BatchUpdateResponse(BaseModel):
success: bool
updated_count: int
failed_ids: list[str] = []
errors: Optional[dict[str, str]] = None
+23
View File
@@ -0,0 +1,23 @@
from typing import Optional
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class UserFixRequest(BaseModel):
frame_id: int
uav_pixel: tuple[float, float]
satellite_gps: GPSPoint
class UserFixResponse(BaseModel):
accepted: bool
processing_resumed: bool
message: Optional[str] = None
class ObjectGPSResponse(BaseModel):
gps: GPSPoint
accuracy_meters: float
frame_id: int
pixel: tuple[float, float]
+10
View File
@@ -0,0 +1,10 @@
from .sim3_transform import Sim3Transform
from .chunk_handle import ChunkHandle
from .chunk_bounds import ChunkBounds
__all__ = [
"Sim3Transform",
"ChunkHandle",
"ChunkBounds",
]
+9
View File
@@ -0,0 +1,9 @@
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class ChunkBounds(BaseModel):
estimated_center: GPSPoint
estimated_radius: float
confidence: float
+17
View File
@@ -0,0 +1,17 @@
from typing import Optional
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class ChunkHandle(BaseModel):
chunk_id: str
flight_id: str
start_frame_id: int
end_frame_id: Optional[int] = None
frames: list[int] = []
is_active: bool = True
has_anchor: bool = False
anchor_frame_id: Optional[int] = None
anchor_gps: Optional[GPSPoint] = None
matching_status: str = "unanchored"
+11
View File
@@ -0,0 +1,11 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
class Sim3Transform(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
translation: np.ndarray
rotation: np.ndarray
scale: float
+16
View File
@@ -0,0 +1,16 @@
from .system_config import SystemConfig
from .flight_config import FlightConfig
from .database_config import DatabaseConfig
from .model_config import ModelConfig
from .rotation_config import RotationConfig
from .recovery_config import RecoveryConfig
__all__ = [
"SystemConfig",
"FlightConfig",
"DatabaseConfig",
"ModelConfig",
"RotationConfig",
"RecoveryConfig",
]
+14
View File
@@ -0,0 +1,14 @@
from pydantic import BaseModel
class DatabaseConfig(BaseModel):
host: str = "localhost"
port: int = 5432
database: str = "gps_denied"
username: str = "postgres"
password: str = ""
pool_size: int = 50
max_overflow: int = 50
pool_timeout: int = 30
pool_recycle: int = 3600
+20
View File
@@ -0,0 +1,20 @@
from typing import Optional
from pydantic import BaseModel
from ..core.camera_parameters import CameraParameters
from ..core.gps_point import GPSPoint
class OperationalArea(BaseModel):
name: str = "Eastern Ukraine"
min_lat: float = 45.0
max_lat: float = 52.0
min_lon: float = 22.0
max_lon: float = 40.0
class FlightConfig(BaseModel):
camera_params: CameraParameters
altitude: float
operational_area: OperationalArea = OperationalArea()
frame_spacing: float = 100.0
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
class ModelConfig(BaseModel):
model_name: str
model_path: str
format: str = "tensorrt"
precision: str = "fp16"
warmup_iterations: int = 3
+14
View File
@@ -0,0 +1,14 @@
from pydantic import BaseModel
class RecoveryConfig(BaseModel):
search_grid_sizes: list[int] = [1, 4, 9, 16, 25]
min_chunk_frames_for_matching: int = 5
max_chunk_frames_for_matching: int = 20
user_input_threshold_tiles: int = 25
chunk_matching_interval_seconds: float = 5.0
confidence_threshold_good: float = 0.7
confidence_threshold_degraded: float = 0.5
min_inlier_count_good: int = 50
min_inlier_count_tracking: int = 20
+13
View File
@@ -0,0 +1,13 @@
from pydantic import BaseModel
class RotationConfig(BaseModel):
step_angle: float = 30.0
sharp_turn_threshold: float = 45.0
confidence_threshold: float = 0.7
history_size: int = 10
@property
def rotation_iterations(self) -> int:
return int(360 / self.step_angle)
+26
View File
@@ -0,0 +1,26 @@
from pydantic import BaseModel
from ..core.camera_parameters import CameraParameters
from .database_config import DatabaseConfig
from .flight_config import OperationalArea
class ModelPaths(BaseModel):
superpoint: str = "models/superpoint.engine"
lightglue: str = "models/lightglue.engine"
dinov2: str = "models/dinov2.engine"
litesam: str = "models/litesam.engine"
class APIConfig(BaseModel):
host: str = "0.0.0.0"
port: int = 8000
debug: bool = False
class SystemConfig(BaseModel):
camera: CameraParameters
operational_area: OperationalArea = OperationalArea()
models: ModelPaths = ModelPaths()
database: DatabaseConfig = DatabaseConfig()
api: APIConfig = APIConfig()
+14
View File
@@ -0,0 +1,14 @@
from .gps_point import GPSPoint
from .camera_parameters import CameraParameters
from .pose import Pose
from .polygon import Polygon
from .validation_result import ValidationResult
__all__ = [
"GPSPoint",
"CameraParameters",
"Pose",
"Polygon",
"ValidationResult",
]
+18
View File
@@ -0,0 +1,18 @@
from typing import Optional
from pydantic import BaseModel
class CameraParameters(BaseModel):
focal_length: float
sensor_width: float
sensor_height: float
resolution_width: int
resolution_height: int
principal_point: tuple[float, float] | None = None
distortion_coefficients: list[float] | None = None
def get_principal_point(self) -> tuple[float, float]:
if self.principal_point:
return self.principal_point
return (self.resolution_width / 2.0, self.resolution_height / 2.0)
+21
View File
@@ -0,0 +1,21 @@
from pydantic import BaseModel, field_validator
class GPSPoint(BaseModel):
lat: float
lon: float
@field_validator("lat")
@classmethod
def validate_lat(cls, v: float) -> float:
if not -90 <= v <= 90:
raise ValueError("Latitude must be between -90 and 90")
return v
@field_validator("lon")
@classmethod
def validate_lon(cls, v: float) -> float:
if not -180 <= v <= 180:
raise ValueError("Longitude must be between -180 and 180")
return v
+8
View File
@@ -0,0 +1,8 @@
from pydantic import BaseModel
from .gps_point import GPSPoint
class Polygon(BaseModel):
north_west: GPSPoint
south_east: GPSPoint
+15
View File
@@ -0,0 +1,15 @@
from datetime import datetime
from typing import Optional
import numpy as np
from pydantic import BaseModel, ConfigDict
class Pose(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
frame_id: int
position: np.ndarray
orientation: np.ndarray
timestamp: datetime
covariance: Optional[np.ndarray] = None
+7
View File
@@ -0,0 +1,7 @@
from pydantic import BaseModel
class ValidationResult(BaseModel):
valid: bool
errors: list[str] = []
+14
View File
@@ -0,0 +1,14 @@
from .flight import Flight
from .flight_state import FlightState
from .waypoint import Waypoint
from .geofences import Geofences
from .heading_record import HeadingRecord
__all__ = [
"Flight",
"FlightState",
"Waypoint",
"Geofences",
"HeadingRecord",
]
+20
View File
@@ -0,0 +1,20 @@
from datetime import datetime
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
from ..core.camera_parameters import CameraParameters
from .waypoint import Waypoint
from .geofences import Geofences
class Flight(BaseModel):
id: str
name: str
description: str
start_gps: GPSPoint
waypoints: list[Waypoint]
geofences: Geofences
camera_params: CameraParameters
altitude: float
created_at: datetime
updated_at: datetime
+16
View File
@@ -0,0 +1,16 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class FlightState(BaseModel):
flight_id: str
status: str
frames_processed: int
frames_total: int
current_frame: Optional[int] = None
blocked: bool = False
search_grid_size: Optional[int] = None
created_at: datetime
updated_at: datetime
+7
View File
@@ -0,0 +1,7 @@
from pydantic import BaseModel
from ..core.polygon import Polygon
class Geofences(BaseModel):
polygons: list[Polygon]
+9
View File
@@ -0,0 +1,9 @@
from datetime import datetime
from pydantic import BaseModel
class HeadingRecord(BaseModel):
frame_id: int
heading: float
timestamp: datetime
+14
View File
@@ -0,0 +1,14 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class Waypoint(BaseModel):
id: str
lat: float
lon: float
altitude: Optional[float] = None
confidence: float
timestamp: datetime
refined: bool = False
+12
View File
@@ -0,0 +1,12 @@
from .image_data import ImageData
from .image_metadata import ImageMetadata
from .image_batch import ImageBatch
from .processing_status import ProcessingStatus
__all__ = [
"ImageData",
"ImageMetadata",
"ImageBatch",
"ProcessingStatus",
]
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
class ImageBatch(BaseModel):
images: list[bytes]
filenames: list[str]
start_sequence: int
end_sequence: int
batch_number: int
+14
View File
@@ -0,0 +1,14 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
from .image_metadata import ImageMetadata
class ImageData(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
flight_id: str
sequence: int
filename: str
image: np.ndarray
metadata: ImageMetadata
+13
View File
@@ -0,0 +1,13 @@
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class ImageMetadata(BaseModel):
sequence: int
filename: str
dimensions: tuple[int, int]
file_size: int
timestamp: datetime
exif_data: Optional[dict] = None
+11
View File
@@ -0,0 +1,11 @@
from pydantic import BaseModel
class ProcessingStatus(BaseModel):
flight_id: str
total_images: int
processed_images: int
current_sequence: int
queued_batches: int
processing_rate: float
+15
View File
@@ -0,0 +1,15 @@
from .relative_pose import RelativePose
from .motion import Motion
from .matches import Matches
from .alignment_result import AlignmentResult, ChunkAlignmentResult
from .rotation_result import RotationResult
__all__ = [
"RelativePose",
"Motion",
"Matches",
"AlignmentResult",
"ChunkAlignmentResult",
"RotationResult",
]
+30
View File
@@ -0,0 +1,30 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
from ..core.gps_point import GPSPoint
from ..chunks.sim3_transform import Sim3Transform
class AlignmentResult(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
matched: bool
homography: np.ndarray
gps_center: GPSPoint
confidence: float
inlier_count: int
total_correspondences: int
reprojection_error: float = 0.0
class ChunkAlignmentResult(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
matched: bool
chunk_id: str
chunk_center_gps: GPSPoint
rotation_angle: float
confidence: float
inlier_count: int
transform: Sim3Transform
reprojection_error: float = 0.0
+12
View File
@@ -0,0 +1,12 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
class Matches(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
matches: np.ndarray
scores: np.ndarray
keypoints1: np.ndarray
keypoints2: np.ndarray
+12
View File
@@ -0,0 +1,12 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
class Motion(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
translation: np.ndarray
rotation: np.ndarray
inliers: np.ndarray
inlier_count: int
+17
View File
@@ -0,0 +1,17 @@
from typing import Optional
import numpy as np
from pydantic import BaseModel, ConfigDict
class RelativePose(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
translation: np.ndarray
rotation: np.ndarray
confidence: float
inlier_count: int
total_matches: int
tracking_good: bool
scale_ambiguous: bool = True
chunk_id: Optional[str] = None
+14
View File
@@ -0,0 +1,14 @@
import numpy as np
from pydantic import BaseModel, ConfigDict
class RotationResult(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
matched: bool
initial_angle: float
precise_angle: float
confidence: float
homography: np.ndarray
inlier_count: int = 0
+12
View File
@@ -0,0 +1,12 @@
from .search_session import SearchSession
from .confidence_assessment import ConfidenceAssessment
from .user_anchor import UserAnchor
from .user_input_request import UserInputRequest
__all__ = [
"SearchSession",
"ConfidenceAssessment",
"UserAnchor",
"UserInputRequest",
]
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
class ConfidenceAssessment(BaseModel):
overall_confidence: float
vo_confidence: float
litesam_confidence: float
inlier_count: int
tracking_status: str
+14
View File
@@ -0,0 +1,14 @@
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class SearchSession(BaseModel):
session_id: str
flight_id: str
frame_id: int
center_gps: GPSPoint
current_grid_size: int = 1
max_grid_size: int = 25
found: bool = False
exhausted: bool = False
+9
View File
@@ -0,0 +1,9 @@
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class UserAnchor(BaseModel):
uav_pixel: tuple[float, float]
satellite_gps: GPSPoint
confidence: float = 1.0
+17
View File
@@ -0,0 +1,17 @@
from datetime import datetime
import numpy as np
from pydantic import BaseModel, ConfigDict
from ..satellite.tile_candidate import TileCandidate
class UserInputRequest(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
request_id: str
flight_id: str
frame_id: int
uav_image: np.ndarray
candidate_tiles: list[TileCandidate]
message: str
created_at: datetime
+14
View File
@@ -0,0 +1,14 @@
from .frame_result import FrameResult, ObjectLocation
from .flight_results import FlightResults, FlightStatistics
from .refined_frame_result import RefinedFrameResult
from .optimization_result import OptimizationResult
__all__ = [
"FrameResult",
"ObjectLocation",
"FlightResults",
"FlightStatistics",
"RefinedFrameResult",
"OptimizationResult",
]
+17
View File
@@ -0,0 +1,17 @@
from pydantic import BaseModel
from .frame_result import FrameResult
class FlightStatistics(BaseModel):
total_frames: int
processed_frames: int
refined_frames: int
mean_confidence: float
processing_time: float
class FlightResults(BaseModel):
flight_id: str
frames: list[FrameResult]
statistics: FlightStatistics
+24
View File
@@ -0,0 +1,24 @@
from datetime import datetime
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class ObjectLocation(BaseModel):
object_id: str
pixel: tuple[float, float]
gps: GPSPoint
class_name: str
confidence: float
class FrameResult(BaseModel):
frame_id: int
gps_center: GPSPoint
altitude: float
heading: float
confidence: float
timestamp: datetime
refined: bool = False
objects: list[ObjectLocation] = []
updated_at: datetime
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
class OptimizationResult(BaseModel):
converged: bool
final_error: float
iterations_used: int
optimized_frames: list[int]
mean_reprojection_error: float = 0.0
+11
View File
@@ -0,0 +1,11 @@
from typing import Optional
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class RefinedFrameResult(BaseModel):
frame_id: int
gps_center: GPSPoint
confidence: float
heading: Optional[float] = None
+10
View File
@@ -0,0 +1,10 @@
from .tile_coords import TileCoords
from .tile_bounds import TileBounds
from .tile_candidate import TileCandidate
__all__ = [
"TileCoords",
"TileBounds",
"TileCandidate",
]
+12
View File
@@ -0,0 +1,12 @@
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
class TileBounds(BaseModel):
nw: GPSPoint
ne: GPSPoint
sw: GPSPoint
se: GPSPoint
center: GPSPoint
gsd: float
+14
View File
@@ -0,0 +1,14 @@
from typing import Optional
from pydantic import BaseModel
from ..core.gps_point import GPSPoint
from .tile_bounds import TileBounds
class TileCandidate(BaseModel):
tile_id: str
gps_center: GPSPoint
bounds: TileBounds
similarity_score: float
rank: int
spatial_score: Optional[float] = None
+8
View File
@@ -0,0 +1,8 @@
from pydantic import BaseModel
class TileCoords(BaseModel):
x: int
y: int
zoom: int