from django.db import models class WorkshopSite(models.Model): name = models.CharField(max_length=100, default="主车间") width_m = models.FloatField(default=130.0) height_m = models.FloatField(default=50.0) detector = models.ForeignKey( "app.AlgorithmModel", null=True, blank=True, on_delete=models.SET_NULL, related_name="workshop_detector_sites", ) reid_model = models.ForeignKey( "app.AlgorithmModel", null=True, blank=True, on_delete=models.SET_NULL, related_name="workshop_reid_sites", ) target_labels = models.JSONField(default=list) analysis_fps = models.FloatField(default=2.0) fusion_radius_m = models.FloatField(default=1.5) observation_window_sec = models.FloatField(default=1.0) max_speed_mps = models.FloatField(default=3.0) lost_ttl_sec = models.FloatField(default=30.0) trail_sec = models.FloatField(default=30.0) create_time = models.DateTimeField(auto_now_add=True) last_update_time = models.DateTimeField(auto_now=True) class Meta: db_table = "wm_site" def __str__(self): return self.name class WorkshopCamera(models.Model): site = models.ForeignKey(WorkshopSite, on_delete=models.CASCADE, related_name="cameras") stream = models.ForeignKey( "app.StreamModel", null=True, blank=True, on_delete=models.SET_NULL, related_name="workshop_bindings", ) preview_stream = models.ForeignKey( "app.StreamModel", null=True, blank=True, on_delete=models.SET_NULL, related_name="workshop_preview_bindings", ) slot = models.PositiveIntegerField(default=1) display_name = models.CharField(max_length=100, default="") enabled = models.BooleanField(default=True) install_x = models.FloatField(default=0.0) install_y = models.FloatField(default=0.0) install_z = models.FloatField(default=0.0) yaw_deg = models.FloatField(default=0.0) pitch_deg = models.FloatField(default=0.0) create_time = models.DateTimeField(auto_now_add=True) last_update_time = models.DateTimeField(auto_now=True) class Meta: db_table = "wm_camera" ordering = ("slot", "id") constraints = [ models.UniqueConstraint(fields=("site", "slot"), name="wm_camera_site_slot_uniq"), ] def __str__(self): return self.display_name or (self.stream.nickname if self.stream else "摄像头 %s" % self.slot) @property def active_calibration(self): return self.calibrations.filter(is_active=True).order_by("-id").first() class GroundControlPoint(models.Model): site = models.ForeignKey(WorkshopSite, on_delete=models.CASCADE, related_name="control_points") name = models.CharField(max_length=100) x = models.FloatField() y = models.FloatField() description = models.CharField(max_length=300, default="", blank=True) create_time = models.DateTimeField(auto_now_add=True) last_update_time = models.DateTimeField(auto_now=True) class Meta: db_table = "wm_ground_control_point" ordering = ("name", "id") constraints = [ models.UniqueConstraint(fields=("site", "name"), name="wm_gcp_site_name_uniq"), ] def __str__(self): return "%s (%.2f, %.2f)" % (self.name, self.x, self.y) class CameraCalibration(models.Model): STATUS_DRAFT = "draft" STATUS_VALID = "valid" STATUS_INVALID = "invalid" STATUS_CHOICES = ( (STATUS_DRAFT, "草稿"), (STATUS_VALID, "合格"), (STATUS_INVALID, "不合格"), ) camera = models.ForeignKey(WorkshopCamera, on_delete=models.CASCADE, related_name="calibrations") snapshot_path = models.CharField(max_length=500, default="", blank=True) frame_width = models.PositiveIntegerField(default=0) frame_height = models.PositiveIntegerField(default=0) homography = models.JSONField(default=list) fit_rmse_m = models.FloatField(null=True, blank=True) validation_mean_m = models.FloatField(null=True, blank=True) validation_max_m = models.FloatField(null=True, blank=True) status = models.CharField(max_length=16, choices=STATUS_CHOICES, default=STATUS_DRAFT) is_active = models.BooleanField(default=False) warnings = models.JSONField(default=list) created_by = models.IntegerField(default=0) create_time = models.DateTimeField(auto_now_add=True) last_update_time = models.DateTimeField(auto_now=True) class Meta: db_table = "wm_camera_calibration" ordering = ("-id",) class CalibrationObservation(models.Model): ROLE_FIT = "fit" ROLE_VERIFY = "verify" ROLE_CHOICES = ((ROLE_FIT, "拟合"), (ROLE_VERIFY, "验证")) calibration = models.ForeignKey(CameraCalibration, on_delete=models.CASCADE, related_name="observations") control_point = models.ForeignKey( GroundControlPoint, null=True, blank=True, on_delete=models.SET_NULL, related_name="camera_observations", ) pixel_u = models.FloatField() pixel_v = models.FloatField() world_x = models.FloatField() world_y = models.FloatField() role = models.CharField(max_length=10, choices=ROLE_CHOICES, default=ROLE_FIT) error_m = models.FloatField(null=True, blank=True) class Meta: db_table = "wm_calibration_observation" ordering = ("id",)