1use crate::exif_info::ExifInfo;
35use cumulus3d_core::{Camera, CameraModelKind, Error, Result};
36
37#[derive(Clone, Copy, Debug, PartialEq)]
39pub struct FocalEstimate {
40 pub focal: f64,
42 pub prior: bool,
44}
45
46const SENSOR_WIDTHS: &[(&str, &str, f64)] = &[
49 ("dji", "fc6310", 13.2),
50 ("dji", "fc6310s", 13.2),
51 ("dji", "fc6510", 13.2),
52 ("dji", "fc6520", 17.3),
53 ("dji", "fc6540", 23.5),
54 ("dji", "fc330", 6.17),
55 ("dji", "fc300x", 6.17),
56 ("dji", "fc300s", 6.17),
57 ("dji", "fc220", 6.17),
58 ("dji", "fc2103", 6.17),
59 ("dji", "fc2204", 6.17),
60 ("dji", "fc3170", 6.4),
61 ("dji", "fc3411", 6.4),
62 ("dji", "fc3582", 9.6),
63 ("dji", "l1d-20c", 13.2),
64 ("dji", "l2d-20c", 17.3),
65 ("dji", "fc7303", 6.3),
66 ("dji", "zenmusep1", 35.9),
67 ("dji", "m3e", 17.3),
68];
69
70pub fn lookup_sensor_width(make: &str, model: &str) -> Option<f64> {
72 let norm = |s: &str| s.chars().filter(|c| !c.is_whitespace() && *c != '_' && *c != '-').collect::<String>().to_lowercase();
73 let mk = norm(make);
74 let mut md = norm(model);
75 if md.starts_with(&mk) {
76 md = md[mk.len()..].to_string();
77 }
78 SENSOR_WIDTHS.iter().find(|(m, n, _)| mk.starts_with(&norm(m)) && norm(n) == md).map(|&(_, _, w)| w)
79}
80
81pub fn infer_focal(exif: &ExifInfo, width: u64, height: u64, default_factor: f64) -> FocalEstimate {
83 let (w, h) = (width as f64, height as f64);
84 let max_size = w.max(h);
85 if let Some(f35) = exif.focal_35mm.filter(|&f| f > 0.0) {
86 return FocalEstimate { focal: f35 / 43.27 * (w * w + h * h).sqrt(), prior: true };
87 }
88 if let Some(fmm) = exif.focal_mm.filter(|&f| f > 0.0) {
89 if let (Some(r), Some(u)) = (exif.focal_plane_x_resolution, exif.focal_plane_resolution_unit) {
90 let px_per_mm = match u {
91 2 => Some(r / 25.4),
92 3 => Some(r / 10.0),
93 4 => Some(r),
94 5 => Some(r * 1000.0),
95 _ => None,
96 };
97 if let Some(p) = px_per_mm.filter(|p| *p > 0.0) {
98 return FocalEstimate { focal: fmm * p, prior: true };
99 }
100 }
101 if let (Some(mk), Some(md)) = (&exif.make, &exif.model) {
102 if let Some(sw) = lookup_sensor_width(mk, md) {
103 return FocalEstimate { focal: fmm / sw * max_size, prior: true };
104 }
105 }
106 }
107 FocalEstimate { focal: default_factor * max_size, prior: false }
108}
109
110pub fn init_camera(
113 model: CameraModelKind,
114 width: u64,
115 height: u64,
116 exif: &ExifInfo,
117 params: Option<&[f64]>,
118 default_focal_length_factor: f64,
119) -> Result<Camera> {
120 if let Some(p) = params {
121 let mut cam = Camera::new(cumulus3d_core::INVALID_CAMERA_ID, model, width, height, p.to_vec())?;
122 cam.focal_from_prior = true;
123 return Ok(cam);
124 }
125 if width == 0 || height == 0 {
126 return Err(Error::InvalidArgument("영상 크기 0".into()));
127 }
128 let fe = infer_focal(exif, width, height, default_focal_length_factor);
129 let mut cam = Camera::from_focal(model, fe.focal, width, height);
130 cam.focal_from_prior = fe.prior;
131 Ok(cam)
132}