scirs2_vision/depth_completion/
completion.rs1use std::collections::VecDeque;
16
17#[non_exhaustive]
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum DepthMethod {
25 NearestNeighbor,
27 InvDistWeighted,
29 SurfaceNormals,
31 PropagationFill,
33}
34
35#[non_exhaustive]
37#[derive(Debug, Clone)]
38pub struct DepthCompletionConfig {
39 pub method: DepthMethod,
41 pub max_depth: f32,
43 pub min_depth: f32,
45 pub iterations: usize,
47}
48
49impl Default for DepthCompletionConfig {
50 fn default() -> Self {
51 Self {
52 method: DepthMethod::PropagationFill,
53 max_depth: 100.0,
54 min_depth: 0.1,
55 iterations: 5,
56 }
57 }
58}
59
60pub struct DepthResult {
62 pub dense_depth: Vec<Vec<f32>>,
65 pub confidence: Vec<Vec<f32>>,
68 pub filled_pixels: usize,
71}
72
73pub struct DepthCompleter {
79 config: DepthCompletionConfig,
80}
81
82impl DepthCompleter {
83 pub fn new(config: DepthCompletionConfig) -> Self {
85 Self { config }
86 }
87
88 pub fn complete(
102 &self,
103 sparse_depth: &[Vec<Option<f32>>],
104 rgb: Option<&[Vec<[u8; 3]>]>,
105 ) -> DepthResult {
106 if sparse_depth.is_empty() {
107 return DepthResult {
108 dense_depth: Vec::new(),
109 confidence: Vec::new(),
110 filled_pixels: 0,
111 };
112 }
113
114 let height = sparse_depth.len();
115 let width = sparse_depth[0].len();
116
117 let mut dense = vec![vec![0.0f32; width]; height];
119 let mut confidence = vec![vec![0.0f32; width]; height];
120
121 let min_d = self.config.min_depth;
122 let max_d = self.config.max_depth;
123
124 for r in 0..height {
125 for c in 0..width {
126 if let Some(d) = sparse_depth[r][c] {
127 if d >= min_d && d <= max_d {
128 dense[r][c] = d;
129 confidence[r][c] = 1.0;
130 }
131 }
132 }
133 }
134
135 let initial_filled = dense
136 .iter()
137 .flat_map(|row| row.iter())
138 .filter(|&&v| v > 0.0)
139 .count();
140
141 match self.config.method {
142 DepthMethod::NearestNeighbor => {
143 fill_nearest_neighbor(&mut dense, &mut confidence, height, width);
144 }
145 DepthMethod::InvDistWeighted => {
146 fill_inv_dist_weighted(&mut dense, &mut confidence, height, width);
147 }
148 DepthMethod::PropagationFill => {
149 fill_propagation(
150 &mut dense,
151 &mut confidence,
152 height,
153 width,
154 self.config.iterations,
155 );
156 }
157 DepthMethod::SurfaceNormals => {
158 fill_surface_normals(&mut dense, &mut confidence, height, width, rgb);
159 }
160 }
161
162 let total_filled = dense
164 .iter()
165 .flat_map(|row| row.iter())
166 .filter(|&&v| v > 0.0)
167 .count();
168 let filled_pixels = total_filled.saturating_sub(initial_filled);
169
170 DepthResult {
171 dense_depth: dense,
172 confidence,
173 filled_pixels,
174 }
175 }
176}
177
178fn fill_nearest_neighbor(
183 dense: &mut [Vec<f32>],
184 confidence: &mut [Vec<f32>],
185 height: usize,
186 width: usize,
187) {
188 let mut queue: VecDeque<(usize, usize)> = VecDeque::new();
189 let mut dist: Vec<Vec<u32>> = vec![vec![u32::MAX; width]; height];
190
191 for r in 0..height {
193 for c in 0..width {
194 if dense[r][c] > 0.0 {
195 queue.push_back((r, c));
196 dist[r][c] = 0;
197 }
198 }
199 }
200
201 let dirs: [(i32, i32); 4] = [(-1, 0), (1, 0), (0, -1), (0, 1)];
202
203 while let Some((r, c)) = queue.pop_front() {
204 let d = dist[r][c];
205 for (dr, dc) in &dirs {
206 let nr = r as i32 + dr;
207 let nc = c as i32 + dc;
208 if nr < 0 || nr >= height as i32 || nc < 0 || nc >= width as i32 {
209 continue;
210 }
211 let (nr, nc) = (nr as usize, nc as usize);
212 if dist[nr][nc] == u32::MAX {
213 dist[nr][nc] = d + 1;
214 dense[nr][nc] = dense[r][c]; let src_conf = confidence[r][c];
217 confidence[nr][nc] = src_conf / (1.0 + (d + 1) as f32);
218 queue.push_back((nr, nc));
219 }
220 }
221 }
222}
223
224fn fill_inv_dist_weighted(
229 dense: &mut [Vec<f32>],
230 confidence: &mut [Vec<f32>],
231 height: usize,
232 width: usize,
233) {
234 let mut valid: Vec<(usize, usize, f32)> = Vec::new();
236 for (r, dense_row) in dense.iter().enumerate().take(height) {
237 for (c, &d) in dense_row.iter().enumerate().take(width) {
238 if d > 0.0 {
239 valid.push((r, c, d));
240 }
241 }
242 }
243
244 if valid.is_empty() {
245 return;
246 }
247
248 const K: usize = 16;
249 let max_radius = (height.max(width)) as f32;
251
252 for r in 0..height {
253 if dense[r].iter().all(|&d| d > 0.0) {
254 continue;
256 }
257 for c in 0..width {
258 if dense[r][c] > 0.0 {
259 continue; }
261
262 let mut distances: Vec<(f32, f32)> = valid
264 .iter()
265 .map(|&(vr, vc, vd)| {
266 let dr = r as f32 - vr as f32;
267 let dc = c as f32 - vc as f32;
268 let dist = (dr * dr + dc * dc).sqrt();
269 (dist, vd)
270 })
271 .filter(|&(dist, _)| dist > 0.0 && dist <= max_radius)
272 .collect();
273
274 if distances.is_empty() {
275 continue;
276 }
277
278 distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal));
279 distances.truncate(K);
280
281 let mut wsum = 0.0f32;
282 let mut dsum = 0.0f32;
283 for (dist, depth) in &distances {
284 let w = 1.0 / (dist * dist + 1e-6);
285 wsum += w;
286 dsum += w * depth;
287 }
288
289 if wsum > 0.0 {
290 dense[r][c] = dsum / wsum;
291 let min_dist = distances[0].0;
293 confidence[r][c] = 1.0 / (1.0 + min_dist);
294 }
295 }
296 }
297}
298
299fn fill_propagation(
304 dense: &mut [Vec<f32>],
305 confidence: &mut [Vec<f32>],
306 height: usize,
307 width: usize,
308 max_iterations: usize,
309) {
310 for _iter in 0..max_iterations {
311 let mut changed = false;
312 let old_dense = dense.to_vec();
313 let old_conf = confidence.to_vec();
314
315 for r in 0..height {
316 for c in 0..width {
317 if old_dense[r][c] > 0.0 {
318 continue; }
320 let mut wsum = 0.0f32;
322 let mut dsum = 0.0f32;
323 let mut csum = 0.0f32;
324
325 for dr in -1i32..=1 {
326 for dc in -1i32..=1 {
327 if dr == 0 && dc == 0 {
328 continue;
329 }
330 let nr = r as i32 + dr;
331 let nc = c as i32 + dc;
332 if nr < 0 || nr >= height as i32 || nc < 0 || nc >= width as i32 {
333 continue;
334 }
335 let (nr, nc) = (nr as usize, nc as usize);
336 let nd = old_dense[nr][nc];
337 if nd > 0.0 {
338 let w = old_conf[nr][nc].max(1e-6);
339 wsum += w;
340 dsum += w * nd;
341 csum += w;
342 }
343 }
344 }
345
346 if wsum > 0.0 {
347 let new_depth = dsum / wsum;
348 let avg_conf = (csum / wsum.max(1e-6_f32)) * 0.9_f32;
350 dense[r][c] = new_depth;
351 confidence[r][c] = avg_conf;
352 changed = true;
353 }
354 }
355 }
356
357 if !changed {
358 break;
359 }
360 }
361
362 depth_consistency_check(dense, confidence, height, width);
365}
366
367fn depth_consistency_check(
369 dense: &mut [Vec<f32>],
370 confidence: &mut [Vec<f32>],
371 height: usize,
372 width: usize,
373) {
374 let snap = dense.to_vec();
375 for r in 0..height {
376 for c in 0..width {
377 let d = snap[r][c];
378 if d <= 0.0 {
379 continue;
380 }
381 let mut sum = 0.0f32;
382 let mut cnt = 0usize;
383 for dr in -1i32..=1 {
384 for dc in -1i32..=1 {
385 let nr = r as i32 + dr;
386 let nc = c as i32 + dc;
387 if nr < 0 || nr >= height as i32 || nc < 0 || nc >= width as i32 {
388 continue;
389 }
390 let nd = snap[nr as usize][nc as usize];
391 if nd > 0.0 {
392 sum += nd;
393 cnt += 1;
394 }
395 }
396 }
397 if cnt > 1 {
398 let mean = sum / cnt as f32;
399 let rel_diff = (d - mean).abs() / mean.max(1e-6);
400 if rel_diff > 0.30 {
401 confidence[r][c] *= (1.0_f32 - rel_diff).max(0.0);
403 }
404 }
405 }
406 }
407}
408
409fn fill_surface_normals(
414 dense: &mut [Vec<f32>],
415 confidence: &mut [Vec<f32>],
416 height: usize,
417 width: usize,
418 rgb: Option<&[Vec<[u8; 3]>]>,
419) {
420 let lum: Vec<Vec<f32>> = match rgb {
422 Some(img) if img.len() == height => img
423 .iter()
424 .map(|row| {
425 row.iter()
426 .map(|&[r, g, b]| {
427 0.299 * r as f32 / 255.0
429 + 0.587 * g as f32 / 255.0
430 + 0.114 * b as f32 / 255.0
431 })
432 .collect()
433 })
434 .collect(),
435 _ => vec![vec![0.5f32; width]; height],
436 };
437
438 let mut gx = vec![vec![0.0f32; width]; height];
440 let mut gy = vec![vec![0.0f32; width]; height];
441
442 for r in 1..(height.saturating_sub(1)) {
443 for c in 1..(width.saturating_sub(1)) {
444 gx[r][c] = -lum[r - 1][c - 1] - 2.0 * lum[r][c - 1] - lum[r + 1][c - 1]
445 + lum[r - 1][c + 1]
446 + 2.0 * lum[r][c + 1]
447 + lum[r + 1][c + 1];
448 gy[r][c] = -lum[r - 1][c - 1] - 2.0 * lum[r - 1][c] - lum[r - 1][c + 1]
449 + lum[r + 1][c - 1]
450 + 2.0 * lum[r + 1][c]
451 + lum[r + 1][c + 1];
452 }
453 }
454
455 let mut total_d = 0.0f32;
457 let mut anchor_cnt = 0usize;
458 for dense_row in dense.iter().take(height) {
459 for &d in dense_row.iter().take(width) {
460 if d > 0.0 {
461 total_d += d;
462 anchor_cnt += 1;
463 }
464 }
465 }
466 let anchor_mean = if anchor_cnt > 0 {
467 total_d / anchor_cnt as f32
468 } else {
469 1.0
470 };
471
472 let mut integrated = vec![vec![anchor_mean; width]; height];
475
476 for r in 0..height {
478 for c in 0..width {
479 if dense[r][c] > 0.0 {
480 integrated[r][c] = dense[r][c];
481 }
482 }
483 }
484
485 let n_iter = 10usize;
487 for _ in 0..n_iter {
488 let prev = integrated.clone();
489 for r in 1..(height.saturating_sub(1)) {
490 for c in 1..(width.saturating_sub(1)) {
491 if dense[r][c] > 0.0 {
492 continue; }
494 let lap = prev[r - 1][c] + prev[r + 1][c] + prev[r][c - 1] + prev[r][c + 1]
496 - 4.0 * prev[r][c];
497 let rhs = gx[r][c] + gy[r][c];
498 integrated[r][c] = prev[r][c] + 0.25 * (lap - rhs);
499 integrated[r][c] = integrated[r][c].max(0.0);
500 }
501 }
502 }
503
504 for r in 0..height {
506 for c in 0..width {
507 if dense[r][c] <= 0.0 {
508 let d = integrated[r][c];
509 if d > 0.0 {
510 dense[r][c] = d;
511 let grad_mag = (gx[r][c] * gx[r][c] + gy[r][c] * gy[r][c]).sqrt();
513 confidence[r][c] = 1.0 / (1.0 + grad_mag);
514 }
515 }
516 }
517 }
518}
519
520pub fn apply_bilateral_filter(
530 depth: &[Vec<f32>],
531 sigma_space: f32,
532 sigma_depth: f32,
533) -> Vec<Vec<f32>> {
534 let height = depth.len();
535 if height == 0 {
536 return Vec::new();
537 }
538 let width = depth[0].len();
539 let radius = (2.0 * sigma_space).ceil() as usize;
540 let mut out = depth.to_vec();
541
542 for r in 0..height {
543 for c in 0..width {
544 let centre = depth[r][c];
545 if centre <= 0.0 {
546 continue;
547 }
548
549 let mut wsum = 0.0f32;
550 let mut dsum = 0.0f32;
551
552 let r0 = r.saturating_sub(radius);
553 let r1 = (r + radius + 1).min(height);
554 let c0 = c.saturating_sub(radius);
555 let c1 = (c + radius + 1).min(width);
556
557 for (nr, depth_row) in depth.iter().enumerate().take(r1).skip(r0) {
558 for (nc, &nd) in depth_row.iter().enumerate().take(c1).skip(c0) {
559 if nd <= 0.0 {
560 continue;
561 }
562 let dr = (r as f32 - nr as f32) / sigma_space;
563 let dc = (c as f32 - nc as f32) / sigma_space;
564 let dd = (centre - nd) / sigma_depth;
565 let w = (-(dr * dr + dc * dc + dd * dd) * 0.5).exp();
566 wsum += w;
567 dsum += w * nd;
568 }
569 }
570
571 if wsum > 0.0 {
572 out[r][c] = dsum / wsum;
573 }
574 }
575 }
576
577 out
578}
579
580pub fn fill_holes_morphological(depth: &[Vec<f32>]) -> Vec<Vec<f32>> {
589 let height = depth.len();
590 if height == 0 {
591 return Vec::new();
592 }
593 let width = depth[0].len();
594 let mut out = depth.to_vec();
595
596 for r in 0..height {
597 for c in 0..width {
598 if depth[r][c] > 0.0 {
599 continue; }
601 let mut max_d = 0.0f32;
602 for dr in -1i32..=1 {
603 for dc in -1i32..=1 {
604 let nr = r as i32 + dr;
605 let nc = c as i32 + dc;
606 if nr < 0 || nr >= height as i32 || nc < 0 || nc >= width as i32 {
607 continue;
608 }
609 max_d = max_d.max(depth[nr as usize][nc as usize]);
610 }
611 }
612 if max_d > 0.0 {
613 out[r][c] = max_d;
614 }
615 }
616 }
617 out
618}