mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 15:43:11 +02:00
refactor(praca): fix ruff violations in visualize scripts
This commit is contained in:
parent
be31e9abd7
commit
47c7679222
@ -6,6 +6,8 @@ on a small example graph, rendering each algorithm step by step.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -33,6 +35,9 @@ OUTPUT_DIR = Path(__file__).resolve().parent / "videos"
|
|||||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
OUTPUT = str(OUTPUT_DIR / "q02_shortest_path.mp4")
|
OUTPUT = str(OUTPUT_DIR / "q02_shortest_path.mp4")
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Graph definition
|
# Graph definition
|
||||||
NODE_POS = {"S": (250, 280), "A": (550, 180), "B": (550, 450), "C": (850, 320)}
|
NODE_POS = {"S": (250, 280), "A": (550, 180), "B": (550, 450), "C": (850, 320)}
|
||||||
EDGES_DIJKSTRA = [
|
EDGES_DIJKSTRA = [
|
||||||
@ -101,13 +106,13 @@ def _draw_circle(
|
|||||||
|
|
||||||
def _draw_line(
|
def _draw_line(
|
||||||
frame: np.ndarray,
|
frame: np.ndarray,
|
||||||
x1: int,
|
start: tuple[int, int],
|
||||||
y1: int,
|
end: tuple[int, int],
|
||||||
x2: int,
|
|
||||||
y2: int,
|
|
||||||
color: tuple[int, ...],
|
color: tuple[int, ...],
|
||||||
thickness: int = 2,
|
thickness: int = 2,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
x1, y1 = start
|
||||||
|
x2, y2 = end
|
||||||
length = max(int(np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)), 1)
|
length = max(int(np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)), 1)
|
||||||
for i in range(length):
|
for i in range(length):
|
||||||
frac = i / length
|
frac = i / length
|
||||||
@ -122,13 +127,13 @@ def _draw_line(
|
|||||||
|
|
||||||
def _draw_arrow(
|
def _draw_arrow(
|
||||||
frame: np.ndarray,
|
frame: np.ndarray,
|
||||||
x1: int,
|
start: tuple[int, int],
|
||||||
y1: int,
|
end: tuple[int, int],
|
||||||
x2: int,
|
|
||||||
y2: int,
|
|
||||||
color: tuple[int, ...],
|
color: tuple[int, ...],
|
||||||
thickness: int = 2,
|
thickness: int = 2,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
x1, y1 = start
|
||||||
|
x2, y2 = end
|
||||||
r = 32
|
r = 32
|
||||||
length = max(np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2), 1)
|
length = max(np.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2), 1)
|
||||||
ddx = (x2 - x1) / length
|
ddx = (x2 - x1) / length
|
||||||
@ -137,14 +142,14 @@ def _draw_arrow(
|
|||||||
sy = int(y1 + ddy * r)
|
sy = int(y1 + ddy * r)
|
||||||
ex = int(x2 - ddx * r)
|
ex = int(x2 - ddx * r)
|
||||||
ey = int(y2 - ddy * r)
|
ey = int(y2 - ddy * r)
|
||||||
_draw_line(frame, sx, sy, ex, ey, color, thickness)
|
_draw_line(frame, (sx, sy), (ex, ey), color, thickness)
|
||||||
angle = np.arctan2(ey - sy, ex - sx)
|
angle = np.arctan2(ey - sy, ex - sx)
|
||||||
arrow_len = 12
|
arrow_len = 12
|
||||||
for side in [-1, 1]:
|
for side in [-1, 1]:
|
||||||
a = angle + np.pi + side * 0.4
|
a = angle + np.pi + side * 0.4
|
||||||
ax = int(ex + arrow_len * np.cos(a))
|
ax = int(ex + arrow_len * np.cos(a))
|
||||||
ay = int(ey + arrow_len * np.sin(a))
|
ay = int(ey + arrow_len * np.sin(a))
|
||||||
_draw_line(frame, ex, ey, ax, ay, color, thickness)
|
_draw_line(frame, (ex, ey), (ax, ay), color, thickness)
|
||||||
|
|
||||||
|
|
||||||
def _render_graph(
|
def _render_graph(
|
||||||
@ -163,7 +168,7 @@ def _render_graph(
|
|||||||
sx, sy = nodes[src]
|
sx, sy = nodes[src]
|
||||||
dx, dy = nodes[dst]
|
dx, dy = nodes[dst]
|
||||||
ec = COL_EDGE_ACT if active_edge == (src, dst) else COL_EDGE
|
ec = COL_EDGE_ACT if active_edge == (src, dst) else COL_EDGE
|
||||||
_draw_arrow(frame, sx, sy, dx, dy, ec, thickness=2)
|
_draw_arrow(frame, (sx, sy), (dx, dy), ec, thickness=2)
|
||||||
|
|
||||||
for name, (x, y) in nodes.items():
|
for name, (x, y) in nodes.items():
|
||||||
if name == current:
|
if name == current:
|
||||||
@ -184,19 +189,32 @@ def _render_graph(
|
|||||||
return frame
|
return frame
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class _StepConfig:
|
||||||
|
"""Configuration for a single algorithm visualization step."""
|
||||||
|
|
||||||
|
nodes: dict[str, tuple[int, int]]
|
||||||
|
edges: list[tuple[str, str, int]]
|
||||||
|
distances: dict[str, str]
|
||||||
|
current: str | None = None
|
||||||
|
visited: set[str] | None = None
|
||||||
|
active_edge: tuple[str, str] | None = None
|
||||||
|
step_text: str = ""
|
||||||
|
algo_name: str = ""
|
||||||
|
|
||||||
|
|
||||||
def _make_step(
|
def _make_step(
|
||||||
nodes: dict[str, tuple[int, int]],
|
cfg: _StepConfig,
|
||||||
edges: list[tuple[str, str, int]],
|
|
||||||
distances: dict[str, str],
|
|
||||||
current: str | None = None,
|
|
||||||
visited: set[str] | None = None,
|
|
||||||
active_edge: tuple[str, str] | None = None,
|
|
||||||
step_text: str = "",
|
|
||||||
algo_name: str = "",
|
|
||||||
duration: float = STEP_DUR,
|
duration: float = STEP_DUR,
|
||||||
) -> CompositeVideoClip:
|
) -> CompositeVideoClip:
|
||||||
if visited is None:
|
nodes = cfg.nodes
|
||||||
visited = set()
|
edges = cfg.edges
|
||||||
|
distances = cfg.distances
|
||||||
|
current = cfg.current
|
||||||
|
visited = cfg.visited if cfg.visited is not None else set()
|
||||||
|
active_edge = cfg.active_edge
|
||||||
|
step_text = cfg.step_text
|
||||||
|
algo_name = cfg.algo_name
|
||||||
|
|
||||||
graph_frame = _render_graph(nodes, edges, distances, current, visited, active_edge)
|
graph_frame = _render_graph(nodes, edges, distances, current, visited, active_edge)
|
||||||
|
|
||||||
@ -305,50 +323,66 @@ def _dijkstra_steps() -> list[CompositeVideoClip]:
|
|||||||
e = EDGES_DIJKSTRA
|
e = EDGES_DIJKSTRA
|
||||||
return [
|
return [
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": INF, "B": INF, "C": INF},
|
e,
|
||||||
current="S",
|
{"S": "0", "A": INF, "B": INF, "C": INF},
|
||||||
step_text="Inicjalizacja: d[S]=0, reszta=∞. Wybierz S (min d).",
|
current="S",
|
||||||
algo_name="Algorytm Dijkstry",
|
step_text="Inicjalizacja: d[S]=0, reszta=∞. Wybierz S (min d).",
|
||||||
|
algo_name="Algorytm Dijkstry",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": INF},
|
e,
|
||||||
current="S",
|
{"S": "0", "A": "2", "B": "5", "C": INF},
|
||||||
active_edge=("S", "A"),
|
current="S",
|
||||||
step_text="Relaksacja S→A: d[A]=0+2=2. S→B: d[B]=0+5=5.",
|
active_edge=("S", "A"),
|
||||||
algo_name="Algorytm Dijkstry",
|
step_text="Relaksacja S→A: d[A]=0+2=2. S→B: d[B]=0+5=5.",
|
||||||
|
algo_name="Algorytm Dijkstry",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
current="A",
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
visited={"S"},
|
current="A",
|
||||||
active_edge=("A", "C"),
|
visited={"S"},
|
||||||
step_text="Zamknij S. Min=A(2). Relaksacja A→C: d[C]=2+3=5.",
|
active_edge=("A", "C"),
|
||||||
algo_name="Algorytm Dijkstry",
|
step_text="Zamknij S. Min=A(2). Relaksacja A→C: d[C]=2+3=5.",
|
||||||
|
algo_name="Algorytm Dijkstry",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
current="B",
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
visited={"S", "A"},
|
current="B",
|
||||||
active_edge=("B", "A"),
|
visited={"S", "A"},
|
||||||
step_text="Zamknij A. Min=B(5). B→A: 5+1=6>2, nie zmieniaj. B→C: 5+6=11>5.",
|
active_edge=("B", "A"),
|
||||||
algo_name="Algorytm Dijkstry",
|
step_text=(
|
||||||
|
"Zamknij A. Min=B(5). B→A: 5+1=6>2, "
|
||||||
|
"nie zmieniaj. B→C: 5+6=11>5."
|
||||||
|
),
|
||||||
|
algo_name="Algorytm Dijkstry",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
current="C",
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
visited={"S", "A", "B"},
|
current="C",
|
||||||
step_text="Zamknij B. Min=C(5). Koniec! Wynik: d={S:0, A:2, B:5, C:5}.",
|
visited={"S", "A", "B"},
|
||||||
algo_name="Dijkstra -- WYNIK",
|
step_text=(
|
||||||
|
"Zamknij B. Min=C(5). Koniec! "
|
||||||
|
"Wynik: d={S:0, A:2, B:5, C:5}."
|
||||||
|
),
|
||||||
|
algo_name="Dijkstra -- WYNIK",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -358,42 +392,67 @@ def _bellman_ford_steps() -> list[CompositeVideoClip]:
|
|||||||
e = EDGES_BF
|
e = EDGES_BF
|
||||||
return [
|
return [
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": INF, "B": INF, "C": INF},
|
e,
|
||||||
step_text="Bellman-Ford: relaksuj WSZYSTKIE krawędzie V-1=3 razy. Ujemne wagi OK!",
|
{"S": "0", "A": INF, "B": INF, "C": INF},
|
||||||
algo_name="Algorytm Bellmana-Forda",
|
step_text=(
|
||||||
|
"Bellman-Ford: relaksuj WSZYSTKIE "
|
||||||
|
"krawędzie V-1=3 razy. Ujemne wagi OK!"
|
||||||
|
),
|
||||||
|
algo_name="Algorytm Bellmana-Forda",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
active_edge=("S", "A"),
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
step_text="Iteracja 1: S→A:2, A→C:5, S→B:5. Potem B→A: 5+(-4)=1 < 2 → A=1!",
|
active_edge=("S", "A"),
|
||||||
algo_name="Bellman-Ford -- iteracja 1",
|
step_text=(
|
||||||
|
"Iteracja 1: S→A:2, A→C:5, S→B:5. "
|
||||||
|
"Potem B→A: 5+(-4)=1 < 2 → A=1!"
|
||||||
|
),
|
||||||
|
algo_name="Bellman-Ford -- iteracja 1",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "1", "B": "5", "C": "5"},
|
e,
|
||||||
active_edge=("B", "A"),
|
{"S": "0", "A": "1", "B": "5", "C": "5"},
|
||||||
step_text="B→A z ujemną wagą -4: d[A] poprawione z 2 na 1! (Dijkstra by to pominął!)",
|
active_edge=("B", "A"),
|
||||||
algo_name="Bellman-Ford -- ujemna waga",
|
step_text=(
|
||||||
|
"B→A z ujemną wagą -4: d[A] poprawione "
|
||||||
|
"z 2 na 1! (Dijkstra by to pominął!)"
|
||||||
|
),
|
||||||
|
algo_name="Bellman-Ford -- ujemna waga",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "1", "B": "5", "C": "4"},
|
e,
|
||||||
active_edge=("A", "C"),
|
{"S": "0", "A": "1", "B": "5", "C": "4"},
|
||||||
step_text="Iteracja 2: A→C: 1+3=4 < 5 → C=4. Propagacja poprawionego A.",
|
active_edge=("A", "C"),
|
||||||
algo_name="Bellman-Ford -- iteracja 2",
|
step_text=(
|
||||||
|
"Iteracja 2: A→C: 1+3=4 < 5 → C=4. "
|
||||||
|
"Propagacja poprawionego A."
|
||||||
|
),
|
||||||
|
algo_name="Bellman-Ford -- iteracja 2",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "1", "B": "5", "C": "4"},
|
e,
|
||||||
step_text="Iteracja 3: brak zmian. V-ta iteracja: brak popraw → brak cyklu ujemnego.",
|
{"S": "0", "A": "1", "B": "5", "C": "4"},
|
||||||
algo_name="Bellman-Ford -- WYNIK, O(V*E)",
|
step_text=(
|
||||||
|
"Iteracja 3: brak zmian. V-ta iteracja: "
|
||||||
|
"brak popraw → brak cyklu ujemnego."
|
||||||
|
),
|
||||||
|
algo_name="Bellman-Ford -- WYNIK, O(V*E)",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -403,40 +462,60 @@ def _astar_steps() -> list[CompositeVideoClip]:
|
|||||||
e = EDGES_DIJKSTRA
|
e = EDGES_DIJKSTRA
|
||||||
return [
|
return [
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": INF, "B": INF, "C": INF},
|
e,
|
||||||
current="S",
|
{"S": "0", "A": INF, "B": INF, "C": INF},
|
||||||
step_text="A*: f(n)=g(n)+h(n). Cel=C. h(S)=5, h(A)=3, h(B)=4, h(C)=0. f(S)=0+5=5.",
|
current="S",
|
||||||
algo_name="Algorytm A*",
|
step_text=(
|
||||||
|
"A*: f(n)=g(n)+h(n). Cel=C. "
|
||||||
|
"h(S)=5, h(A)=3, h(B)=4, h(C)=0. f(S)=0+5=5."
|
||||||
|
),
|
||||||
|
algo_name="Algorytm A*",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": INF},
|
e,
|
||||||
current="S",
|
{"S": "0", "A": "2", "B": "5", "C": INF},
|
||||||
active_edge=("S", "A"),
|
current="S",
|
||||||
step_text="Relaksuj S: A(g=2,f=2+3=5), B(g=5,f=5+4=9). Min f → A(5).",
|
active_edge=("S", "A"),
|
||||||
algo_name="A* -- rozwijanie S",
|
step_text=(
|
||||||
|
"Relaksuj S: A(g=2,f=2+3=5), "
|
||||||
|
"B(g=5,f=5+4=9). Min f → A(5)."
|
||||||
|
),
|
||||||
|
algo_name="A* -- rozwijanie S",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
current="A",
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
visited={"S"},
|
current="A",
|
||||||
active_edge=("A", "C"),
|
visited={"S"},
|
||||||
step_text="Rozwiń A(f=5): A→C: g=2+3=5, f=5+0=5. Min f → C(5) = CEL!",
|
active_edge=("A", "C"),
|
||||||
algo_name="A* -- rozwijanie A",
|
step_text=(
|
||||||
|
"Rozwiń A(f=5): A→C: g=2+3=5, "
|
||||||
|
"f=5+0=5. Min f → C(5) = CEL!"
|
||||||
|
),
|
||||||
|
algo_name="A* -- rozwijanie A",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
_make_step(
|
_make_step(
|
||||||
n,
|
_StepConfig(
|
||||||
e,
|
n,
|
||||||
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
e,
|
||||||
current="C",
|
{"S": "0", "A": "2", "B": "5", "C": "5"},
|
||||||
visited={"S", "A"},
|
current="C",
|
||||||
step_text="Dotarliśmy do C! Koszt=5. A* NIE przetwarza B (3 vs 4 w Dijkstrze).",
|
visited={"S", "A"},
|
||||||
algo_name="A* -- cel osiągnięty!",
|
step_text=(
|
||||||
|
"Dotarliśmy do C! Koszt=5. "
|
||||||
|
"A* NIE przetwarza B (3 vs 4 w Dijkstrze)."
|
||||||
|
),
|
||||||
|
algo_name="A* -- cel osiągnięty!",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -523,7 +602,7 @@ def main() -> None:
|
|||||||
final.write_videofile(
|
final.write_videofile(
|
||||||
OUTPUT, fps=FPS, codec="libx264", audio=False, preset="medium", threads=4
|
OUTPUT, fps=FPS, codec="libx264", audio=False, preset="medium", threads=4
|
||||||
)
|
)
|
||||||
print(f"Video saved to: {OUTPUT}")
|
_logger.info("Video saved to: %s", OUTPUT)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ Creates animated video demonstrating:
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ OUTPUT = str(OUTPUT_DIR / "q24_object_detection.mp4")
|
|||||||
|
|
||||||
BG_COLOR = (15, 20, 35)
|
BG_COLOR = (15, 20, 35)
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _tc(**kwargs: object) -> TextClip:
|
def _tc(**kwargs: object) -> TextClip:
|
||||||
"""TextClip wrapper that adds enough bottom margin to prevent clipping."""
|
"""TextClip wrapper that adds enough bottom margin to prevent clipping."""
|
||||||
@ -203,7 +206,8 @@ def _hog_svm_demo() -> list[CompositeVideoClip]:
|
|||||||
frame[ay - 1 : ay + 2, ax : ax + 20] = (150, 150, 170)
|
frame[ay - 1 : ay + 2, ax : ax + 20] = (150, 150, 170)
|
||||||
|
|
||||||
# Show gradient computation example at bottom
|
# Show gradient computation example at bottom
|
||||||
if progress > 0.2:
|
gradient_phase = 0.2
|
||||||
|
if progress > gradient_phase:
|
||||||
# Mini pixel grid showing gradient computation
|
# Mini pixel grid showing gradient computation
|
||||||
gx, gy = 100, 430
|
gx, gy = 100, 430
|
||||||
pixels = [50, 50, 200]
|
pixels = [50, 50, 200]
|
||||||
@ -366,7 +370,8 @@ def _viola_jones_demo() -> list[CompositeVideoClip]:
|
|||||||
(80, 620),
|
(80, 620),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Haar: kontrast jasna/ciemna | Integral Image: suma prostokąta O(1) = 4 odczyty",
|
"Haar: kontrast jasna/ciemna | Integral Image: "
|
||||||
|
"suma prostokąta O(1) = 4 odczyty",
|
||||||
14,
|
14,
|
||||||
"#78909C",
|
"#78909C",
|
||||||
FONT_R,
|
FONT_R,
|
||||||
@ -474,7 +479,8 @@ def _rcnn_evolution() -> list[CompositeVideoClip]:
|
|||||||
("Faster R-CNN (2015)", 20, "#A5D6A7", FONT_B, (50, 580)),
|
("Faster R-CNN (2015)", 20, "#A5D6A7", FONT_B, (50, 580)),
|
||||||
("0.2 sec → 5 fps (RPN w sieci!)", 14, "#A5D6A7", FONT_R, (720, 600)),
|
("0.2 sec → 5 fps (RPN w sieci!)", 14, "#A5D6A7", FONT_R, (720, 600)),
|
||||||
(
|
(
|
||||||
"Kluczowe innowacje: ROI Pooling → stały rozmiar | RPN → propozycje w sieci",
|
"Kluczowe innowacje: ROI Pooling → stały rozmiar "
|
||||||
|
"| RPN → propozycje w sieci",
|
||||||
14,
|
14,
|
||||||
"#78909C",
|
"#78909C",
|
||||||
FONT_R,
|
FONT_R,
|
||||||
@ -527,13 +533,15 @@ def _rcnn_detailed() -> list[CompositeVideoClip]:
|
|||||||
min(c + 50, 255) for c in color
|
min(c + 50, 255) for c in color
|
||||||
)
|
)
|
||||||
# Arrow down
|
# Arrow down
|
||||||
if i < 4:
|
arrow_limit = 4
|
||||||
|
if i < arrow_limit:
|
||||||
ax = bx + bw // 2
|
ax = bx + bw // 2
|
||||||
ay = by + bh + 5
|
ay = by + bh + 5
|
||||||
frame[ay : ay + 20, ax - 1 : ax + 2] = (150, 150, 170)
|
frame[ay : ay + 20, ax - 1 : ax + 2] = (150, 150, 170)
|
||||||
|
|
||||||
# Illustration: many overlapping regions from Selective Search
|
# Illustration: many overlapping regions from Selective Search
|
||||||
if progress > 0.2:
|
overlay_phase = 0.2
|
||||||
|
if progress > overlay_phase:
|
||||||
rng_local = np.random.default_rng(42)
|
rng_local = np.random.default_rng(42)
|
||||||
n_boxes = min(int((progress - 0.2) * 15), 8)
|
n_boxes = min(int((progress - 0.2) * 15), 8)
|
||||||
for i in range(n_boxes):
|
for i in range(n_boxes):
|
||||||
@ -599,94 +607,108 @@ def _rcnn_detailed() -> list[CompositeVideoClip]:
|
|||||||
|
|
||||||
|
|
||||||
# ── ROI Pooling ──────────────────────────────────────────────────
|
# ── ROI Pooling ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
||||||
|
def _draw_roi_pool_grid(frame: np.ndarray) -> None:
|
||||||
|
"""Draw the 3x3 ROI pool grid with max-pooled feature values."""
|
||||||
|
out_x, out_y = 400, 220
|
||||||
|
out_cell = 50
|
||||||
|
out_n = 3
|
||||||
|
roi_r1, roi_c1 = 2, 1
|
||||||
|
roi_r2, roi_c2 = 6, 5
|
||||||
|
roi_h = roi_r2 - roi_r1
|
||||||
|
roi_w = roi_c2 - roi_c1
|
||||||
|
for r in range(out_n):
|
||||||
|
for c in range(out_n):
|
||||||
|
x = out_x + c * out_cell
|
||||||
|
y = out_y + r * out_cell
|
||||||
|
|
||||||
|
# Compute the max from corresponding region
|
||||||
|
src_r1 = roi_r1 + r * roi_h // out_n
|
||||||
|
src_r2 = roi_r1 + (r + 1) * roi_h // out_n
|
||||||
|
src_c1 = roi_c1 + c * roi_w // out_n
|
||||||
|
src_c2 = roi_c1 + (c + 1) * roi_w // out_n
|
||||||
|
max_val = 0
|
||||||
|
for sr in range(src_r1, src_r2):
|
||||||
|
for sc in range(src_c1, src_c2):
|
||||||
|
v = 30 + ((sr * 7 + sc * 13 + 42) % 40)
|
||||||
|
max_val = max(max_val, v)
|
||||||
|
|
||||||
|
frame[y : y + out_cell - 2, x : x + out_cell - 2] = (
|
||||||
|
max_val,
|
||||||
|
max_val + 20,
|
||||||
|
max_val + 40,
|
||||||
|
)
|
||||||
|
frame[y : y + 2, x : x + out_cell - 2] = (80, 200, 120)
|
||||||
|
frame[y + out_cell - 4 : y + out_cell - 2, x : x + out_cell - 2] = (
|
||||||
|
80,
|
||||||
|
200,
|
||||||
|
120,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _make_roi_frame(t: float) -> np.ndarray:
|
||||||
|
"""Render a single frame for the ROI pooling animation."""
|
||||||
|
frame = np.zeros((H, W, 3), dtype=np.uint8)
|
||||||
|
frame[:] = BG_COLOR
|
||||||
|
progress = min(t / (STEP_DUR * 0.7), 1.0)
|
||||||
|
|
||||||
|
# Left: feature map with ROI highlighted
|
||||||
|
fm_x, fm_y = 60, 180
|
||||||
|
fm_cell = 30
|
||||||
|
fm_grid = 8
|
||||||
|
for r in range(fm_grid):
|
||||||
|
for c in range(fm_grid):
|
||||||
|
x = fm_x + c * fm_cell
|
||||||
|
y = fm_y + r * fm_cell
|
||||||
|
# Random-looking feature values
|
||||||
|
val = 30 + ((r * 7 + c * 13 + 42) % 40)
|
||||||
|
frame[y : y + fm_cell - 1, x : x + fm_cell - 1] = (
|
||||||
|
val,
|
||||||
|
val + 10,
|
||||||
|
val + 20,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ROI region highlighted
|
||||||
|
roi_r1, roi_c1 = 2, 1
|
||||||
|
roi_r2, roi_c2 = 6, 5
|
||||||
|
for tt in range(3):
|
||||||
|
ry1 = fm_y + roi_r1 * fm_cell - tt
|
||||||
|
ry2 = fm_y + roi_r2 * fm_cell + tt
|
||||||
|
rx1 = fm_x + roi_c1 * fm_cell - tt
|
||||||
|
rx2 = fm_x + roi_c2 * fm_cell + tt
|
||||||
|
frame[ry1:ry2, rx1 : rx1 + 2] = (255, 200, 50)
|
||||||
|
frame[ry1:ry2, rx2 - 2 : rx2] = (255, 200, 50)
|
||||||
|
frame[ry1 : ry1 + 2, rx1:rx2] = (255, 200, 50)
|
||||||
|
frame[ry2 - 2 : ry2, rx1:rx2] = (255, 200, 50)
|
||||||
|
|
||||||
|
# Arrow
|
||||||
|
arrow_phase = 0.3
|
||||||
|
if progress > arrow_phase:
|
||||||
|
frame[300:303, 310:380] = (150, 150, 170)
|
||||||
|
|
||||||
|
# Middle: ROI divided into 3x3 grid (output_size)
|
||||||
|
grid_phase = 0.3
|
||||||
|
if progress > grid_phase:
|
||||||
|
_draw_roi_pool_grid(frame)
|
||||||
|
|
||||||
|
# Arrow to FC
|
||||||
|
fc_phase = 0.6
|
||||||
|
if progress > fc_phase:
|
||||||
|
frame[300:303, 560:630] = (150, 150, 170)
|
||||||
|
# FC box
|
||||||
|
frame[270:340, 650:730] = (200, 100, 80)
|
||||||
|
frame[270:272, 650:730] = (240, 140, 120)
|
||||||
|
frame[338:340, 650:730] = (240, 140, 120)
|
||||||
|
|
||||||
|
return frame
|
||||||
|
|
||||||
|
|
||||||
def _roi_pooling_demo() -> list[CompositeVideoClip]:
|
def _roi_pooling_demo() -> list[CompositeVideoClip]:
|
||||||
"""Animate ROI Pooling: key Fast R-CNN innovation."""
|
"""Animate ROI Pooling: key Fast R-CNN innovation."""
|
||||||
slides = []
|
slides = []
|
||||||
|
|
||||||
def make_roi_frame(t: float) -> np.ndarray:
|
roi_clip = VideoClip(_make_roi_frame, duration=STEP_DUR + 1).with_fps(FPS)
|
||||||
frame = np.zeros((H, W, 3), dtype=np.uint8)
|
|
||||||
frame[:] = BG_COLOR
|
|
||||||
progress = min(t / (STEP_DUR * 0.7), 1.0)
|
|
||||||
|
|
||||||
# Left: feature map with ROI highlighted
|
|
||||||
fm_x, fm_y = 60, 180
|
|
||||||
fm_cell = 30
|
|
||||||
fm_grid = 8
|
|
||||||
for r in range(fm_grid):
|
|
||||||
for c in range(fm_grid):
|
|
||||||
x = fm_x + c * fm_cell
|
|
||||||
y = fm_y + r * fm_cell
|
|
||||||
# Random-looking feature values
|
|
||||||
val = 30 + ((r * 7 + c * 13 + 42) % 40)
|
|
||||||
frame[y : y + fm_cell - 1, x : x + fm_cell - 1] = (
|
|
||||||
val,
|
|
||||||
val + 10,
|
|
||||||
val + 20,
|
|
||||||
)
|
|
||||||
|
|
||||||
# ROI region highlighted
|
|
||||||
roi_r1, roi_c1 = 2, 1
|
|
||||||
roi_r2, roi_c2 = 6, 5
|
|
||||||
for tt in range(3):
|
|
||||||
ry1 = fm_y + roi_r1 * fm_cell - tt
|
|
||||||
ry2 = fm_y + roi_r2 * fm_cell + tt
|
|
||||||
rx1 = fm_x + roi_c1 * fm_cell - tt
|
|
||||||
rx2 = fm_x + roi_c2 * fm_cell + tt
|
|
||||||
frame[ry1:ry2, rx1 : rx1 + 2] = (255, 200, 50)
|
|
||||||
frame[ry1:ry2, rx2 - 2 : rx2] = (255, 200, 50)
|
|
||||||
frame[ry1 : ry1 + 2, rx1:rx2] = (255, 200, 50)
|
|
||||||
frame[ry2 - 2 : ry2, rx1:rx2] = (255, 200, 50)
|
|
||||||
|
|
||||||
# Arrow
|
|
||||||
if progress > 0.3:
|
|
||||||
frame[300:303, 310:380] = (150, 150, 170)
|
|
||||||
|
|
||||||
# Middle: ROI divided into 3x3 grid (output_size)
|
|
||||||
if progress > 0.3:
|
|
||||||
out_x, out_y = 400, 220
|
|
||||||
out_cell = 50
|
|
||||||
out_n = 3
|
|
||||||
roi_h = roi_r2 - roi_r1
|
|
||||||
roi_w = roi_c2 - roi_c1
|
|
||||||
for r in range(out_n):
|
|
||||||
for c in range(out_n):
|
|
||||||
x = out_x + c * out_cell
|
|
||||||
y = out_y + r * out_cell
|
|
||||||
|
|
||||||
# Compute the max from corresponding region
|
|
||||||
src_r1 = roi_r1 + r * roi_h // out_n
|
|
||||||
src_r2 = roi_r1 + (r + 1) * roi_h // out_n
|
|
||||||
src_c1 = roi_c1 + c * roi_w // out_n
|
|
||||||
src_c2 = roi_c1 + (c + 1) * roi_w // out_n
|
|
||||||
max_val = 0
|
|
||||||
for sr in range(src_r1, src_r2):
|
|
||||||
for sc in range(src_c1, src_c2):
|
|
||||||
v = 30 + ((sr * 7 + sc * 13 + 42) % 40)
|
|
||||||
max_val = max(max_val, v)
|
|
||||||
|
|
||||||
frame[y : y + out_cell - 2, x : x + out_cell - 2] = (
|
|
||||||
max_val,
|
|
||||||
max_val + 20,
|
|
||||||
max_val + 40,
|
|
||||||
)
|
|
||||||
frame[y : y + 2, x : x + out_cell - 2] = (80, 200, 120)
|
|
||||||
frame[y + out_cell - 4 : y + out_cell - 2, x : x + out_cell - 2] = (
|
|
||||||
80,
|
|
||||||
200,
|
|
||||||
120,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Arrow to FC
|
|
||||||
if progress > 0.6:
|
|
||||||
frame[300:303, 560:630] = (150, 150, 170)
|
|
||||||
# FC box
|
|
||||||
frame[270:340, 650:730] = (200, 100, 80)
|
|
||||||
frame[270:272, 650:730] = (240, 140, 120)
|
|
||||||
frame[338:340, 650:730] = (240, 140, 120)
|
|
||||||
|
|
||||||
return frame
|
|
||||||
|
|
||||||
roi_clip = VideoClip(make_roi_frame, duration=STEP_DUR + 1).with_fps(FPS)
|
|
||||||
dur = STEP_DUR + 1
|
dur = STEP_DUR + 1
|
||||||
labels = [
|
labels = [
|
||||||
("ROI Pooling: kluczowa innowacja Fast R-CNN", 26, "#FFE082", FONT_B, (80, 20)),
|
("ROI Pooling: kluczowa innowacja Fast R-CNN", 26, "#FFE082", FONT_B, (80, 20)),
|
||||||
@ -731,7 +753,8 @@ def _roi_pooling_demo() -> list[CompositeVideoClip]:
|
|||||||
(80, 535),
|
(80, 535),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Fast R-CNN: CNN raz → 1 feature mapa → ROI Pool 2000 regionów → 25x szybciej!",
|
"Fast R-CNN: CNN raz → 1 feature mapa → "
|
||||||
|
"ROI Pool 2000 regionów → 25x szybciej!",
|
||||||
16,
|
16,
|
||||||
"#A5D6A7",
|
"#A5D6A7",
|
||||||
FONT_R,
|
FONT_R,
|
||||||
@ -788,7 +811,6 @@ def _rpn_anchors_demo() -> list[CompositeVideoClip]:
|
|||||||
|
|
||||||
# Draw anchors around center: 3 sizes x 3 ratios = 9
|
# Draw anchors around center: 3 sizes x 3 ratios = 9
|
||||||
anchor_specs = [
|
anchor_specs = [
|
||||||
# (half_w, half_h, color)
|
|
||||||
(30, 30, (200, 80, 80)), # small 1:1
|
(30, 30, (200, 80, 80)), # small 1:1
|
||||||
(20, 40, (200, 60, 60)), # small 1:2
|
(20, 40, (200, 60, 60)), # small 1:2
|
||||||
(40, 20, (180, 60, 60)), # small 2:1
|
(40, 20, (180, 60, 60)), # small 2:1
|
||||||
@ -1014,7 +1036,8 @@ def _yolo_demo() -> list[CompositeVideoClip]:
|
|||||||
frame[y : y + 1, img_x : img_x + img_size] = (100, 100, 120)
|
frame[y : y + 1, img_x : img_x + img_size] = (100, 100, 120)
|
||||||
|
|
||||||
# Highlight cells containing object centers
|
# Highlight cells containing object centers
|
||||||
if progress > 0.3:
|
car_phase = 0.3
|
||||||
|
if progress > car_phase:
|
||||||
# Car center ~ cell (1, 1)
|
# Car center ~ cell (1, 1)
|
||||||
cx, cy = 1, 2
|
cx, cy = 1, 2
|
||||||
hx = img_x + cx * cell
|
hx = img_x + cx * cell
|
||||||
@ -1023,7 +1046,8 @@ def _yolo_demo() -> list[CompositeVideoClip]:
|
|||||||
frame[hy : hy + cell, hx : hx + cell].astype(int) + 40, 0, 255
|
frame[hy : hy + cell, hx : hx + cell].astype(int) + 40, 0, 255
|
||||||
).astype(np.uint8)
|
).astype(np.uint8)
|
||||||
|
|
||||||
if progress > 0.5:
|
person_phase = 0.5
|
||||||
|
if progress > person_phase:
|
||||||
# Person center ~ cell (4, 4)
|
# Person center ~ cell (4, 4)
|
||||||
cx, cy = 4, 4
|
cx, cy = 4, 4
|
||||||
hx = img_x + cx * cell
|
hx = img_x + cx * cell
|
||||||
@ -1033,7 +1057,8 @@ def _yolo_demo() -> list[CompositeVideoClip]:
|
|||||||
).astype(np.uint8)
|
).astype(np.uint8)
|
||||||
|
|
||||||
# Bounding boxes predictions from cells
|
# Bounding boxes predictions from cells
|
||||||
if progress > 0.6:
|
bbox_phase = 0.6
|
||||||
|
if progress > bbox_phase:
|
||||||
# Car bbox
|
# Car bbox
|
||||||
for tt in range(2):
|
for tt in range(2):
|
||||||
frame[
|
frame[
|
||||||
@ -1100,7 +1125,8 @@ def _yolo_demo() -> list[CompositeVideoClip]:
|
|||||||
(80, 620),
|
(80, 620),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Two-stage (R-CNN): propozycje+klasyfikacja | One-stage (YOLO): bez propozycji!",
|
"Two-stage (R-CNN): propozycje+klasyfikacja "
|
||||||
|
"| One-stage (YOLO): bez propozycji!",
|
||||||
14,
|
14,
|
||||||
"#90CAF9",
|
"#90CAF9",
|
||||||
FONT_R,
|
FONT_R,
|
||||||
@ -1152,13 +1178,15 @@ def _yolo_architecture() -> list[CompositeVideoClip]:
|
|||||||
frame[by + bh - 2 : by + bh, bx : bx + bw] = tuple(
|
frame[by + bh - 2 : by + bh, bx : bx + bw] = tuple(
|
||||||
min(c + 50, 255) for c in color
|
min(c + 50, 255) for c in color
|
||||||
)
|
)
|
||||||
if i < 4:
|
arrow_limit = 4
|
||||||
|
if i < arrow_limit:
|
||||||
ax = bx + bw + 5
|
ax = bx + bw + 5
|
||||||
ay = by + bh // 2
|
ay = by + bh // 2
|
||||||
frame[ay - 1 : ay + 2, ax : ax + 25] = (150, 150, 170)
|
frame[ay - 1 : ay + 2, ax : ax + 25] = (150, 150, 170)
|
||||||
|
|
||||||
# Output tensor breakdown (right side)
|
# Output tensor breakdown (right side)
|
||||||
if progress > 0.6:
|
tensor_phase = 0.6
|
||||||
|
if progress > tensor_phase:
|
||||||
# Show SxS grid
|
# Show SxS grid
|
||||||
gx, gy = 850, 180
|
gx, gy = 850, 180
|
||||||
gs = 120
|
gs = 120
|
||||||
@ -1282,18 +1310,21 @@ def _detr_demo() -> list[CompositeVideoClip]:
|
|||||||
frame[by + bh - 2 : by + bh, bx : bx + bw] = tuple(
|
frame[by + bh - 2 : by + bh, bx : bx + bw] = tuple(
|
||||||
min(c + 50, 255) for c in color
|
min(c + 50, 255) for c in color
|
||||||
)
|
)
|
||||||
if i < 4:
|
arrow_limit = 4
|
||||||
|
if i < arrow_limit:
|
||||||
ax = bx + bw + 5
|
ax = bx + bw + 5
|
||||||
ay = by + bh // 2
|
ay = by + bh // 2
|
||||||
frame[ay - 1 : ay + 2, ax : ax + 25] = (150, 150, 170)
|
frame[ay - 1 : ay + 2, ax : ax + 25] = (150, 150, 170)
|
||||||
|
|
||||||
# Object queries illustration (right side)
|
# Object queries illustration (right side)
|
||||||
if progress > 0.5:
|
query_phase = 0.5
|
||||||
|
if progress > query_phase:
|
||||||
qx, qy = 800, 140
|
qx, qy = 800, 140
|
||||||
for i in range(6):
|
for i in range(6):
|
||||||
y = qy + i * 50
|
y = qy + i * 50
|
||||||
w = 130
|
w = 130
|
||||||
active = i < 3
|
active_limit = 3
|
||||||
|
active = i < active_limit
|
||||||
color = (80, 180, 120) if active else (60, 50, 50)
|
color = (80, 180, 120) if active else (60, 50, 50)
|
||||||
frame[y : y + 35, qx : qx + w] = color
|
frame[y : y + 35, qx : qx + w] = color
|
||||||
frame[y : y + 1, qx : qx + w] = tuple(min(c + 40, 255) for c in color)
|
frame[y : y + 1, qx : qx + w] = tuple(min(c + 40, 255) for c in color)
|
||||||
@ -1528,7 +1559,8 @@ def _detr_demo() -> list[CompositeVideoClip]:
|
|||||||
(80, 540),
|
(80, 540),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
" R-CNN (SS+CNN+SVM+NMS) → YOLO (backbone+head+NMS) → DETR (backbone+transformer)",
|
" R-CNN (SS+CNN+SVM+NMS) → YOLO "
|
||||||
|
"(backbone+head+NMS) → DETR (backbone+transformer)",
|
||||||
14,
|
14,
|
||||||
"#90CAF9",
|
"#90CAF9",
|
||||||
FONT_R,
|
FONT_R,
|
||||||
@ -1572,15 +1604,18 @@ def _nms_iou_demo() -> list[CompositeVideoClip]:
|
|||||||
boxes.append((ox + 350, oy + 50, 100, 100, 0.40, (80, 180, 255)))
|
boxes.append((ox + 350, oy + 50, 100, 100, 0.40, (80, 180, 255)))
|
||||||
|
|
||||||
for i, (bx, by, bw, bh, _conf, color) in enumerate(boxes):
|
for i, (bx, by, bw, bh, _conf, color) in enumerate(boxes):
|
||||||
if progress > 0.4 and i > 0 and i < 3:
|
dc = color
|
||||||
|
nms_phase = 0.4
|
||||||
|
nms_limit = 3
|
||||||
|
if progress > nms_phase and i > 0 and i < nms_limit:
|
||||||
# After NMS, these get removed (shown as faded/crossed)
|
# After NMS, these get removed (shown as faded/crossed)
|
||||||
color = (60, 40, 40)
|
dc = (60, 40, 40)
|
||||||
|
|
||||||
for tt in range(2):
|
for tt in range(2):
|
||||||
frame[by - tt : by + bh + tt, bx - tt : bx - tt + 2] = color
|
frame[by - tt : by + bh + tt, bx - tt : bx - tt + 2] = dc
|
||||||
frame[by - tt : by + bh + tt, bx + bw + tt - 2 : bx + bw + tt] = color
|
frame[by - tt : by + bh + tt, bx + bw + tt - 2 : bx + bw + tt] = dc
|
||||||
frame[by - tt : by - tt + 2, bx - tt : bx + bw + tt] = color
|
frame[by - tt : by - tt + 2, bx - tt : bx + bw + tt] = dc
|
||||||
frame[by + bh + tt - 2 : by + bh + tt, bx - tt : bx + bw + tt] = color
|
frame[by + bh + tt - 2 : by + bh + tt, bx - tt : bx + bw + tt] = dc
|
||||||
|
|
||||||
# IoU visualization on right side
|
# IoU visualization on right side
|
||||||
iou_x, iou_y = 700, 200
|
iou_x, iou_y = 700, 200
|
||||||
@ -1884,7 +1919,7 @@ def main() -> None:
|
|||||||
final.write_videofile(
|
final.write_videofile(
|
||||||
OUTPUT, fps=FPS, codec="libx264", audio=False, preset="medium", threads=4
|
OUTPUT, fps=FPS, codec="libx264", audio=False, preset="medium", threads=4
|
||||||
)
|
)
|
||||||
print(f"Video saved to: {OUTPUT}")
|
_logger.info("Video saved to: %s", OUTPUT)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user