1#[cfg(feature = "serde-serialize")]
4use std::io::Read;
5
6use na::{
7 allocator::Allocator,
8 core::{dimension::DimMin, Matrix3, OMatrix, RowVector5, SMatrix},
9};
10
11use na::{DefaultAllocator, DimName, RealField};
12use nalgebra as na;
13
14use crate::{Error, Result, RosOpenCvIntrinsics};
15
16#[cfg(feature = "serde-serialize")]
17use serde::{Deserialize, Serialize};
18
19#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
34#[derive(Debug, Clone)]
35pub struct RosCameraInfo<R: RealField> {
36 pub image_width: usize,
38 pub image_height: usize,
40 pub camera_name: String,
42 pub camera_matrix: RosMatrix<R>,
44 pub distortion_model: String,
46 pub distortion_coefficients: RosMatrix<R>,
48 pub rectification_matrix: RosMatrix<R>,
50 pub projection_matrix: RosMatrix<R>,
52}
53
54impl<R: RealField> From<NamedIntrinsicParameters<R>> for RosCameraInfo<R> {
55 fn from(orig: NamedIntrinsicParameters<R>) -> Self {
56 let d = &orig.intrinsics.distortion;
57
58 let distortion = vec![
59 d.radial1(),
60 d.radial2(),
61 d.tangential1(),
62 d.tangential2(),
63 d.radial3(),
64 ];
65 Self {
66 image_width: orig.width,
67 image_height: orig.height,
68 camera_name: orig.name,
69 camera_matrix: to_ros(orig.intrinsics.k),
70 distortion_model: "plumb_bob".to_string(),
71 distortion_coefficients: to_ros_matrix(1, 5, distortion.as_slice()),
72 rectification_matrix: to_ros(orig.intrinsics.rect),
73 projection_matrix: to_ros(orig.intrinsics.p),
74 }
75 }
76}
77
78#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
84#[derive(Debug, Clone)]
85pub struct RosMatrix<R: RealField> {
86 pub rows: usize,
88 pub cols: usize,
90 pub data: Vec<R>,
92}
93
94fn to_ros<R: RealField, SS: DimName, OS>(arr: na::OMatrix<R, SS, OS>) -> RosMatrix<R>
95where
96 DefaultAllocator: Allocator<SS, SS>,
97 DefaultAllocator: Allocator<SS>,
98 DefaultAllocator: Allocator<OS, SS>,
99 DefaultAllocator: Allocator<SS, OS>,
100 DefaultAllocator: Allocator<OS, OS>,
101 DefaultAllocator: Allocator<OS>,
102 DefaultAllocator: Allocator<OS>,
103 OS: DimName + DimMin<OS, Output = OS>,
104{
105 let a2 = arr.transpose();
107 RosMatrix {
108 rows: arr.nrows(),
109 cols: arr.ncols(),
110 data: a2.as_slice().to_vec(),
111 }
112}
113
114#[inline]
115pub(crate) fn to_ros_matrix<R: RealField>(rows: usize, cols: usize, data: &[R]) -> RosMatrix<R> {
116 RosMatrix {
117 rows,
118 cols,
119 data: Vec::from(data),
120 }
121}
122
123pub(crate) fn get_nalgebra_matrix<R, D1, D2>(
124 ros_matrix: &RosMatrix<R>,
125) -> Result<OMatrix<R, D1, D2>>
126where
127 R: RealField,
128 D1: DimName,
129 D2: DimName,
130 DefaultAllocator: Allocator<D1, D1>,
131 DefaultAllocator: Allocator<D1>,
132 DefaultAllocator: Allocator<D2, D1>,
133 DefaultAllocator: Allocator<D1, D2>,
134 DefaultAllocator: Allocator<D2, D2>,
135 DefaultAllocator: Allocator<D2>,
136{
137 if ros_matrix.rows != D1::dim() {
138 return Err(Error::BadMatrixSize);
139 }
140 if ros_matrix.cols != D2::dim() {
141 return Err(Error::BadMatrixSize);
142 }
143 if ros_matrix.data.len() != (ros_matrix.rows * ros_matrix.cols) {
144 return Err(Error::BadMatrixSize);
145 }
146 let data_converted: Vec<R> = ros_matrix
147 .data
148 .clone()
149 .into_iter()
150 .map(na::convert)
151 .collect();
152 Ok(OMatrix::from_row_slice_generic(
153 D1::name(),
154 D2::name(),
155 &data_converted,
156 ))
157}
158
159#[derive(Debug, Clone)]
171pub struct NamedIntrinsicParameters<R: RealField> {
172 pub name: String,
174 pub width: usize,
176 pub height: usize,
178 pub intrinsics: RosOpenCvIntrinsics<R>,
180}
181
182impl<R: RealField> std::convert::TryFrom<RosCameraInfo<R>> for NamedIntrinsicParameters<R> {
183 type Error = Error;
184 fn try_from(ros_camera: RosCameraInfo<R>) -> Result<NamedIntrinsicParameters<R>> {
185 let intrinsics = {
186 let p = get_nalgebra_matrix(&ros_camera.projection_matrix)?;
187 let k: SMatrix<R, 3, 3> = get_nalgebra_matrix(&ros_camera.camera_matrix)?;
188 if ros_camera.distortion_model != "plumb_bob" {
189 return Err(Error::UnknownDistortionModel);
190 }
191 let d: RowVector5<R> = get_nalgebra_matrix(&ros_camera.distortion_coefficients)?;
192 let rect: Matrix3<R> = get_nalgebra_matrix(&ros_camera.rectification_matrix)?;
193 let distortion = crate::Distortion::from_opencv_vec(d.transpose());
194 RosOpenCvIntrinsics::from_components(p, k, distortion, rect)?
195 };
196 Ok(NamedIntrinsicParameters {
197 name: ros_camera.camera_name,
198 width: ros_camera.image_width,
199 height: ros_camera.image_height,
200 intrinsics,
201 })
202 }
203}
204
205#[cfg(feature = "serde-serialize")]
206pub fn from_ros_yaml<R, Rd>(reader: Rd) -> Result<NamedIntrinsicParameters<R>>
214where
215 R: RealField + serde::de::DeserializeOwned,
216 Rd: Read,
217{
218 let ros_camera: RosCameraInfo<R> = serde_yaml::from_reader(reader)?;
219 Ok(std::convert::TryInto::try_into(ros_camera)?)
220}