File size: 2,892 Bytes
9de795a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Frame-Auswahl: schärfstes je Zeitfenster, verwackelte raus, dichter bei Bedarf."""

from __future__ import annotations

import numpy as np
import pytest

from fp_scan_worker.frames import schaerfe, waehle_frames


def _kanten_bild(seed: int = 0) -> np.ndarray:
    rng = np.random.default_rng(seed)
    return rng.integers(0, 256, size=(60, 80)).astype(np.float64)


def _unscharf(bild: np.ndarray, laenge: int = 7) -> np.ndarray:
    # horizontale Bewegungsunschärfe (gleitender Mittelwert)
    kern = np.ones(laenge) / laenge
    return np.apply_along_axis(lambda z: np.convolve(z, kern, mode="same"), 1, bild)


def test_schaerfe_erkennt_bewegungsunschaerfe() -> None:
    scharf = _kanten_bild()
    assert schaerfe(_unscharf(scharf)) < 0.2 * schaerfe(scharf)


def test_schaerfe_konstantes_bild_ist_null() -> None:
    assert schaerfe(np.full((10, 10), 128, dtype=np.uint8)) == 0.0


def test_schaerfe_lehnt_falsche_form_ab() -> None:
    with pytest.raises(ValueError):
        schaerfe(np.zeros((2, 2)))


def test_ziel_fps_bestimmt_die_anzahl() -> None:
    t = np.arange(0, 20.0, 1 / 30)  # 20 s Video, 30 fps
    s = np.ones_like(t)
    assert len(waehle_frames(t, s, ziel_fps=3.0)) == 60
    # zügiger Durchgang → höhere Dichte einstellbar
    assert len(waehle_frames(t, s, ziel_fps=5.0)) == 100


def test_obergrenze_verteilt_ueber_ganzes_video() -> None:
    t = np.arange(0, 60.0, 1 / 30)  # 60 s bei 3 fps wären 180
    s = np.ones_like(t)
    wahl = waehle_frames(t, s, ziel_fps=3.0, max_frames=50)
    assert len(wahl) == 50
    # Abdeckung bis ans Ende, nicht nur die ersten 50 Fenster
    assert t[wahl[-1]] > 58.0
    assert t[wahl[0]] < 1.5


def test_kurzes_video_bekommt_mindestanzahl() -> None:
    t = np.arange(0, 2.0, 1 / 30)  # 2 s → bei 3 fps nur 6
    s = np.ones_like(t)
    assert len(waehle_frames(t, s, ziel_fps=3.0, min_frames=12)) == 12


def test_schaerfstes_je_fenster_und_unscharfe_raus() -> None:
    t = np.arange(10) * 0.1  # 1 s, 10 Frames
    s = np.array([5, 9, 5, 5, 5, 0.1, 0.2, 0.1, 0.3, 0.1], dtype=np.float64)
    # 2 Fenster: [0.0, 0.45) und [0.45, 0.9]; das zweite ist komplett verwackelt
    wahl = waehle_frames(t, s, ziel_fps=2.0, min_frames=1)
    assert wahl == [1]


def test_deterministisch_und_frueherer_bei_gleichstand() -> None:
    t = np.arange(0, 4.0, 0.1)
    s = np.ones_like(t)
    a = waehle_frames(t, s, ziel_fps=1.0, min_frames=1)
    assert a == waehle_frames(t, s, ziel_fps=1.0, min_frames=1)
    # je Fenster der erste Frame (Gleichstand)
    assert a == [0, 10, 20, 30]


def test_leere_und_ungueltige_eingaben() -> None:
    assert waehle_frames([], []) == []
    with pytest.raises(ValueError):
        waehle_frames([0.0, 1.0], [1.0])
    with pytest.raises(ValueError):
        waehle_frames([1.0, 0.0], [1.0, 1.0])
    with pytest.raises(ValueError):
        waehle_frames([0.0], [1.0], ziel_fps=0)