2026-09-06 22:26:35 +08:00
|
|
|
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",
|
|
|
|
|
)
|
2026-09-07 12:57:59 +08:00
|
|
|
preview_stream = models.ForeignKey(
|
|
|
|
|
"app.StreamModel", null=True, blank=True, on_delete=models.SET_NULL,
|
|
|
|
|
related_name="workshop_preview_bindings",
|
|
|
|
|
)
|
2026-09-06 22:26:35 +08:00
|
|
|
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",)
|