first commit

This commit is contained in:
Lukáš Trkan
2026-04-20 23:46:50 +02:00
commit 3f072b862e
5117 changed files with 1180 additions and 0 deletions

249
04_map_assembly.ipynb Normal file
View File

@@ -0,0 +1,249 @@
{
"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
}