Files
su2-img/04_map_assembly.ipynb
Lukáš Trkan 3f072b862e first commit
2026-04-20 23:46:50 +02:00

250 lines
8.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 04 — Sestavení velké mapy\n",
"\n",
"Složíme otagované dlaždice (z notebooku 03) do jednoho velkého leteckého snímku HK\n",
"se zakreslenými detekcemi vozidel.\n",
"\n",
"Výsledná mapa: **74 × 69 dlaždic × 256 px = 18 944 × 17 664 px**\n",
"(přibližně 90 MB PNG nebo 15 MB JPEG)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from pathlib import Path\n",
"from PIL import Image\n",
"import numpy as np\n",
"import re\n",
"from tqdm.notebook import tqdm\n",
"import json\n",
"\n",
"ANNOTATED_DIR = Path(\"tiles_annotated\")\n",
"assert ANNOTATED_DIR.exists(), \"Nejprve spusť 03_inference_tiles.ipynb!\"\n",
"\n",
"TILE_SIZE = 256\n",
"\n",
"# Zjistíme rozsah mřížky\n",
"tile_files = sorted(ANNOTATED_DIR.glob(\"18_*.jpg\"))\n",
"xs = []; ys = []\n",
"for f in tile_files:\n",
" m = re.match(r\"18_(\\d+)_(\\d+)\\.jpg\", f.name)\n",
" if m:\n",
" xs.append(int(m.group(1)))\n",
" ys.append(int(m.group(2)))\n",
"\n",
"x_min, x_max = min(xs), max(xs)\n",
"y_min, y_max = min(ys), max(ys)\n",
"cols = x_max - x_min + 1\n",
"rows = y_max - y_min + 1\n",
"\n",
"W = cols * TILE_SIZE\n",
"H = rows * TILE_SIZE\n",
"\n",
"print(f\"Mřížka: {cols} × {rows} dlaždic\")\n",
"print(f\"Výsledná mapa: {W} × {H} px\")\n",
"print(f\"Odhadovaná velikost (JPEG 85%): ~{W*H*3/1e6/10:.0f} MB\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sestavení mapy — plná rozlišení\n",
"# Poznámka: ~18k × 17k px = ~3 GB v RAM → použijeme chunky nebo zmenšenou verzi\n",
"\n",
"OUTPUT_FULL = Path(\"hk_annotated_full.jpg\")\n",
"OUTPUT_PREVIEW = Path(\"hk_annotated_preview.jpg\")\n",
"PREVIEW_SCALE = 4 # 1/4 rozlišení pro preview\n",
"\n",
"# Zkontroluj dostupnou RAM\n",
"import psutil\n",
"ram_gb = psutil.virtual_memory().available / 1e9\n",
"needed_gb = W * H * 3 / 1e9\n",
"print(f\"Dostupná RAM: {ram_gb:.1f} GB, potřeba pro plnou mapu: {needed_gb:.1f} GB\")\n",
"\n",
"if needed_gb > ram_gb * 0.8:\n",
" print(\"⚠ Nedostatek RAM pro plnou mapu — generuji pouze preview\")\n",
" BUILD_FULL = False\n",
"else:\n",
" print(\"RAM dostačuje — generuji plnou mapu\")\n",
" BUILD_FULL = True"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sestavení preview mapy (vždy)\n",
"pw = W // PREVIEW_SCALE\n",
"ph = H // PREVIEW_SCALE\n",
"ts_small = TILE_SIZE // PREVIEW_SCALE\n",
"\n",
"canvas_preview = Image.new(\"RGB\", (pw, ph), (30, 30, 30))\n",
"\n",
"missing = 0\n",
"for f in tqdm(tile_files, desc=\"Preview\"):\n",
" m = re.match(r\"18_(\\d+)_(\\d+)\\.jpg\", f.name)\n",
" if not m:\n",
" continue\n",
" xi = int(m.group(1)) - x_min\n",
" yi = int(m.group(2)) - y_min\n",
" try:\n",
" tile = Image.open(f).resize((ts_small, ts_small), Image.LANCZOS)\n",
" canvas_preview.paste(tile, (xi * ts_small, yi * ts_small))\n",
" except Exception as e:\n",
" missing += 1\n",
"\n",
"canvas_preview.save(OUTPUT_PREVIEW, quality=88, optimize=True)\n",
"print(f\"Preview mapa: {OUTPUT_PREVIEW} ({pw}×{ph} px)\")\n",
"if missing:\n",
" print(f\" Chybějící dlaždice: {missing}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sestavení plné mapy (pokud je dost RAM)\n",
"if BUILD_FULL:\n",
" canvas = Image.new(\"RGB\", (W, H), (30, 30, 30))\n",
"\n",
" for f in tqdm(tile_files, desc=\"Plná mapa\"):\n",
" m = re.match(r\"18_(\\d+)_(\\d+)\\.jpg\", f.name)\n",
" if not m:\n",
" continue\n",
" xi = int(m.group(1)) - x_min\n",
" yi = int(m.group(2)) - y_min\n",
" try:\n",
" tile = Image.open(f)\n",
" canvas.paste(tile, (xi * TILE_SIZE, yi * TILE_SIZE))\n",
" except Exception:\n",
" pass\n",
"\n",
" canvas.save(OUTPUT_FULL, quality=88, optimize=True)\n",
" print(f\"Plná mapa: {OUTPUT_FULL} ({W}×{H} px)\")\n",
" del canvas\n",
"else:\n",
" print(\"Plná mapa přeskočena (nedostatek RAM).\")\n",
" print(f\"Pro generování použij: python3 assemble_map.py\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Zobrazení preview mapy v notebooku\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.patches as mpatches\n",
"\n",
"preview = Image.open(OUTPUT_PREVIEW)\n",
"\n",
"fig, ax = plt.subplots(figsize=(16, 14))\n",
"ax.imshow(preview)\n",
"ax.set_title(f\"Hradec Králové — detekovaná vozidla\\n(preview {pw}×{ph} px)\", fontsize=14)\n",
"ax.axis(\"off\")\n",
"\n",
"# Legenda\n",
"legend_elements = [\n",
" mpatches.Patch(facecolor='#00DC00', edgecolor='white', label='car'),\n",
" mpatches.Patch(facecolor='#FFDC00', edgecolor='white', label='van'),\n",
" mpatches.Patch(facecolor='#DC0000', edgecolor='white', label='truck'),\n",
" mpatches.Patch(facecolor='#0078FF', edgecolor='white', label='bus'),\n",
"]\n",
"ax.legend(handles=legend_elements, loc='lower right', fontsize=12,\n",
" framealpha=0.8, title='Typy vozidel')\n",
"\n",
"plt.tight_layout()\n",
"plt.savefig(\"hk_map_overview.png\", dpi=100, bbox_inches=\"tight\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Souhrn výsledků\n",
"with open(\"detections.json\") as f:\n",
" all_detections = json.load(f)\n",
"\n",
"from collections import Counter\n",
"CLASS_NAMES = [\"car\", \"van\", \"truck\", \"bus\"]\n",
"counts = Counter()\n",
"tiles_with_vehicles = 0\n",
"\n",
"for name, dets in all_detections.items():\n",
" if dets:\n",
" tiles_with_vehicles += 1\n",
" for d in dets:\n",
" counts[CLASS_NAMES[d[\"cls\"]]] += 1\n",
"\n",
"print(\"=\" * 40)\n",
"print(\"SOUHRN — Hradec Králové\")\n",
"print(\"=\" * 40)\n",
"print(f\"Zpracované dlaždice: {len(all_detections):6d}\")\n",
"print(f\"Dlaždice s vozidly: {tiles_with_vehicles:6d}\")\n",
"print()\n",
"print(\"Detekovaná vozidla:\")\n",
"for cls in CLASS_NAMES:\n",
" print(f\" {cls:10s}: {counts[cls]:6d}\")\n",
"print(f\" {'CELKEM':10s}: {sum(counts.values()):6d}\")\n",
"print(\"=\" * 40)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sloupcový graf celkových počtů\n",
"fig, ax = plt.subplots(figsize=(8, 5))\n",
"\n",
"bar_colors = [\"#00DC00\", \"#FFDC00\", \"#DC0000\", \"#0078FF\"]\n",
"bars = ax.bar(CLASS_NAMES, [counts[c] for c in CLASS_NAMES], color=bar_colors, edgecolor=\"black\")\n",
"\n",
"for bar, cls in zip(bars, CLASS_NAMES):\n",
" ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5,\n",
" str(counts[cls]), ha=\"center\", va=\"bottom\", fontsize=12, fontweight=\"bold\")\n",
"\n",
"ax.set_title(\"Počet detekovaných vozidel — Hradec Králové\", fontsize=14)\n",
"ax.set_ylabel(\"Počet vozidel\")\n",
"ax.set_xlabel(\"Typ vozidla\")\n",
"plt.tight_layout()\n",
"plt.savefig(\"vehicle_counts_chart.png\", dpi=150, bbox_inches=\"tight\")\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.10.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}