File size: 2,683 Bytes
9b33fca
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""KITTI evaluation code."""

from __future__ import annotations

import numpy as np

from vis4d.common.typing import NDArrayFloat, NDArrayNumber

from ..common import DepthEvaluator


def apply_garg_crop(mask: NDArrayNumber) -> NDArrayNumber:
    """Apply Garg ECCV16 crop to the mask.

    Args:
        mask (np.array): Mask to be cropped, in shape (..., H, W).

    Returns:
        np.array: Cropped mask, in shape (..., H', W').
    """
    # crop used by Garg ECCV16
    h, w = mask.shape[-2:]
    crop = np.array(
        [0.40810811 * h, 0.99189189 * h, 0.03594771 * w, 0.96405229 * w]
    ).astype(np.int32)
    mask[..., crop[0] : crop[1], crop[2] : crop[3]] = 1
    return mask


def apply_eigen_crop(mask: NDArrayNumber) -> NDArrayNumber:
    """Apply Eigen NIPS14 crop to the mask.

    Args:
        mask (np.array): Mask to be cropped, in shape (N, H, W).

    Returns:
        np.array: Cropped mask, in shape (N, H', W').
    """
    # https://github.com/mrharicot/monodepth/utils/evaluate_kitti.py
    h, w = mask.shape[-2:]
    crop = np.array(
        [0.3324324 * h, 0.91351351 * h, 0.0359477 * w, 0.96405229 * w]
    ).astype(np.int32)
    mask[..., crop[0] : crop[1], crop[2] : crop[3]] = 1
    return mask


class KITTIDepthEvaluator(DepthEvaluator):
    """KITTI depth evaluation class."""

    METRIC_DEPTH = "depth"

    def __init__(
        self,
        min_depth: float = 0.01,
        max_depth: float = 80.0,
        eval_crop: str | None = None,
    ) -> None:
        """Initialize KITTI depth evaluator."""
        super().__init__(min_depth, max_depth)
        self.eval_crop = eval_crop
        self.reset()

    def __repr__(self) -> str:
        """Concise representation of the dataset evaluator."""
        return "KITTI evaluation for depth"

    def _get_eval_mask(self, valid_mask: NDArrayNumber) -> NDArrayNumber:
        """Do Grag or Eigen cropping for testing."""
        eval_mask = np.zeros_like(valid_mask)
        if self.eval_crop == "garg_crop":
            eval_mask = apply_garg_crop(eval_mask)
        elif self.eval_crop == "eigen_crop":
            eval_mask = apply_eigen_crop(eval_mask)
        else:
            eval_mask = np.ones_like(valid_mask)
        return np.logical_and(valid_mask, eval_mask)

    def _apply_mask(
        self, prediction: NDArrayFloat, target: NDArrayFloat
    ) -> tuple[NDArrayFloat, NDArrayFloat]:
        """Apply mask to prediction and target."""
        valid_mask = (target > self.min_depth) & (target < self.max_depth)
        eval_mask = self._get_eval_mask(valid_mask)
        prediction = prediction[eval_mask]
        target = target[eval_mask]
        return prediction, target