45 lines
1.1 KiB
Python
45 lines
1.1 KiB
Python
from typing import Optional
|
|
|
|
from pydantic import BaseModel
|
|
import numpy as np
|
|
import cv2
|
|
|
|
|
|
class KnownImagePoint(BaseModel):
|
|
width: float
|
|
height: float
|
|
|
|
@classmethod
|
|
def from_vec(cls, vec: tuple[float, float]) -> 'KnownImagePoint':
|
|
return cls(width=vec[0], height=vec[1])
|
|
|
|
|
|
class BirdViewPoint(BaseModel):
|
|
x: float
|
|
y: float
|
|
|
|
@classmethod
|
|
def from_vec(cls, vec: tuple[float, float]) -> 'BirdViewPoint':
|
|
return cls(x=vec[0], y=vec[1])
|
|
|
|
|
|
class KnownPoint(BaseModel):
|
|
image: KnownImagePoint
|
|
bird_view: BirdViewPoint
|
|
|
|
|
|
class VideoMetadata(BaseModel):
|
|
knownPoints: list[KnownPoint]
|
|
|
|
def get_view_perspective_matrix(self) -> Optional[np.array]:
|
|
if len(self.knownPoints) < 4:
|
|
return None
|
|
|
|
empirical_source = np.float32(
|
|
[[k.image.width, k.image.height] for k in self.knownPoints])
|
|
empirical_target = np.float32(
|
|
[[k.bird_view.x, k.bird_view.y] for k in self.knownPoints])
|
|
pixel_per_meter = 100
|
|
return cv2.getPerspectiveTransform(empirical_source,
|
|
empirical_target * pixel_per_meter)
|