File size: 4,082 Bytes
ddaad99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
89
90
91
92
# SPDX-License-Identifier: Apache-2.0
"""Host image pre-processing (``host.preprocess``) against the research reference's OpenCV pipeline, the
public-data converter's decoded-image digests and the research golden network input.

    TT_VISIBLE_DEVICES=none python -m pytest -q -p fake_ttnn_plugin code/tt_bevformer/tests/test_host_preprocess.py
"""
from __future__ import annotations

import hashlib

import numpy as np
import pytest

from tt_bevformer.host import preprocess as hp
from tt_bevformer.host.inputs import load_frame
from tt_bevformer.reference import config as C
from tt_bevformer.tests import paths

cv2 = pytest.importorskip("cv2")


def _sha(a: np.ndarray) -> str:
    return hashlib.sha256(np.ascontiguousarray(a).tobytes()).hexdigest()


@pytest.fixture(scope="module")
def frame30():
    paths.need_pandaset()
    return load_frame(paths.PANDASET_SAMPLES / "pandaset_019_f30.json")


@pytest.mark.parametrize("frame", paths.SAMPLE_FRAMES)
def test_shipped_images_decode_like_the_converter(frame):
    """OpenCV decode + the node's cv::resize to 1600x900 give exactly the BGR images the public-data converter
    hashed (so the stored CPU outputs are bit-for-bit inputs of this host path)."""
    paths.need_pandaset()
    fr = load_frame(paths.PANDASET_SAMPLES / f"pandaset_019_f{frame}.json")
    want = fr.manifest["image_bgr_sha256_1600x900"]
    for cam, im in zip(C.CAMERA_ORDER, fr.images_bgr):
        assert im.shape == (1080, 1920, 3) and im.dtype == np.uint8
        out = hp.node_transport(im)
        assert out.shape == (900, 1600, 3)
        assert _sha(out) == want[cam], cam


def test_pil_decode_equals_opencv(frame30):
    """The port decodes with PIL (``host.preprocess.decode_bgr``, ``ttaw.io``); the converter and the node use OpenCV
    (``cv2.imdecode`` / cv_bridge, BGR): the same pixels on the shipped JPEGs."""
    for cam, im in zip(C.CAMERA_ORDER, frame30.images_bgr):
        raw = (paths.PANDASET_SAMPLES / frame30.manifest["images"][cam]).read_bytes()
        assert np.array_equal(cv2.imdecode(np.frombuffer(raw, np.uint8), cv2.IMREAD_COLOR), im), cam


@pytest.mark.parametrize("hw", [(1080, 1920), (720, 1280), (432, 768), (1200, 1920)])
def test_node_transport(hw):
    """The node's uint8 cv::resize to 1600x900 (the vendored ttaw.image_linear emulation) equals OpenCV."""
    rng = np.random.default_rng(hw[0])
    im = rng.integers(0, 256, (900, 1600, 3), dtype=np.uint8)
    assert hp.node_transport(im) is im                                   # 1600x900 passes through
    src = rng.integers(0, 256, hw + (3,), dtype=np.uint8)
    assert np.array_equal(hp.node_transport(src), cv2.resize(src, (1600, 900), interpolation=cv2.INTER_LINEAR))
    with pytest.raises(ValueError):
        hp.node_transport(im.astype(np.float32))


def test_preprocess_matches_research_reference(frame30):
    R = paths.import_research()
    if R is None:
        pytest.skip("research/bevformer not in this workspace")
    imgs = [hp.node_transport(im) for im in frame30.images_bgr]
    got = hp.preprocess_images(frame30.images_bgr, workers=4)
    assert got.shape == (1, 6, 3, 736, 1280) and got.dtype == np.float32
    assert np.array_equal(got, R.preprocess_images_bgr(imgs))
    out = np.full((1, 6, 3, 736, 1280), 3.0, np.float32)
    assert np.array_equal(hp.preprocess_images(frame30.images_bgr, out=out), got)


def test_sample0_golden_input():
    """The research golden ``image`` of the nuScenes key-frame sample0 (internal validation data), bit for bit."""
    s0, golden = paths.vendor_sample0(), paths.research_file("golden", "sample0_golden.npz")
    if s0 is None or golden is None:
        pytest.skip("sample0 or its research golden are not in this workspace")
    imgs = [cv2.imread(str(s0 / "imgs" / f"{c}.jpg"), cv2.IMREAD_COLOR) for c in C.CAMERA_ORDER]
    with np.load(golden) as z:
        want = z["image"]
    assert np.array_equal(hp.preprocess_images(imgs, workers=4), want)


def test_preprocess_refuses_bad_inputs(frame30):
    with pytest.raises(ValueError):
        hp.preprocess_images(frame30.images_bgr[:5])