use crate::exif_info::ExifInfo;
use cumulus3d_core::{Camera, CameraModelKind, Error, Result};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FocalEstimate {
pub focal: f64,
pub prior: bool,
}
const SENSOR_WIDTHS: &[(&str, &str, f64)] = &[
("dji", "fc6310", 13.2),
("dji", "fc6310s", 13.2),
("dji", "fc6510", 13.2),
("dji", "fc6520", 17.3),
("dji", "fc6540", 23.5),
("dji", "fc330", 6.17),
("dji", "fc300x", 6.17),
("dji", "fc300s", 6.17),
("dji", "fc220", 6.17),
("dji", "fc2103", 6.17),
("dji", "fc2204", 6.17),
("dji", "fc3170", 6.4),
("dji", "fc3411", 6.4),
("dji", "fc3582", 9.6),
("dji", "l1d-20c", 13.2),
("dji", "l2d-20c", 17.3),
("dji", "fc7303", 6.3),
("dji", "zenmusep1", 35.9),
("dji", "m3e", 17.3),
];
pub fn lookup_sensor_width(make: &str, model: &str) -> Option<f64> {
let norm = |s: &str| s.chars().filter(|c| !c.is_whitespace() && *c != '_' && *c != '-').collect::<String>().to_lowercase();
let mk = norm(make);
let mut md = norm(model);
if md.starts_with(&mk) {
md = md[mk.len()..].to_string();
}
SENSOR_WIDTHS.iter().find(|(m, n, _)| mk.starts_with(&norm(m)) && norm(n) == md).map(|&(_, _, w)| w)
}
pub fn infer_focal(exif: &ExifInfo, width: u64, height: u64, default_factor: f64) -> FocalEstimate {
let (w, h) = (width as f64, height as f64);
let max_size = w.max(h);
if let Some(f35) = exif.focal_35mm.filter(|&f| f > 0.0) {
return FocalEstimate { focal: f35 / 43.27 * (w * w + h * h).sqrt(), prior: true };
}
if let Some(fmm) = exif.focal_mm.filter(|&f| f > 0.0) {
if let (Some(r), Some(u)) = (exif.focal_plane_x_resolution, exif.focal_plane_resolution_unit) {
let px_per_mm = match u {
2 => Some(r / 25.4),
3 => Some(r / 10.0),
4 => Some(r),
5 => Some(r * 1000.0),
_ => None,
};
if let Some(p) = px_per_mm.filter(|p| *p > 0.0) {
return FocalEstimate { focal: fmm * p, prior: true };
}
}
if let (Some(mk), Some(md)) = (&exif.make, &exif.model) {
if let Some(sw) = lookup_sensor_width(mk, md) {
return FocalEstimate { focal: fmm / sw * max_size, prior: true };
}
}
}
FocalEstimate { focal: default_factor * max_size, prior: false }
}
pub fn init_camera(
model: CameraModelKind,
width: u64,
height: u64,
exif: &ExifInfo,
params: Option<&[f64]>,
default_focal_length_factor: f64,
) -> Result<Camera> {
if let Some(p) = params {
let mut cam = Camera::new(cumulus3d_core::INVALID_CAMERA_ID, model, width, height, p.to_vec())?;
cam.focal_from_prior = true;
return Ok(cam);
}
if width == 0 || height == 0 {
return Err(Error::InvalidArgument("영상 크기 0".into()));
}
let fe = infer_focal(exif, width, height, default_focal_length_factor);
let mut cam = Camera::from_focal(model, fe.focal, width, height);
cam.focal_from_prior = fe.prior;
Ok(cam)
}