Lint
This commit is contained in:
parent
9a009f0b4c
commit
eed1567f7f
12 changed files with 463 additions and 243 deletions
|
|
@ -2,6 +2,7 @@
|
|||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7fb27b941602401d91542211134fc71a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Dithering algorithm comparison\n",
|
||||
|
|
@ -27,26 +28,40 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "acae54e37e7d407bbb7b55eff062a284",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"sys.path.insert(0, '.')\n",
|
||||
"from _helpers import bootstrap, immich_client, fetch_pool, download_image, silenced, show_grid\n",
|
||||
"\n",
|
||||
"sys.path.insert(0, \".\")\n",
|
||||
"from _helpers import bootstrap, download_image, fetch_pool, immich_client, show_grid, silenced\n",
|
||||
"\n",
|
||||
"bootstrap()\n",
|
||||
"\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import numpy as np\n",
|
||||
"from _dither import DITHER_ALGORITHMS, PALETTE_NAMES, PALETTE_RGB, apply_dithering\n",
|
||||
"from PIL import Image\n",
|
||||
"from waveshare_epd.epd7in3e import EPD_WIDTH, EPD_HEIGHT, _crop_center\n",
|
||||
"from _dither import DITHER_ALGORITHMS, apply_dithering, PALETTE_RGB, PALETTE_NAMES\n",
|
||||
"from waveshare_epd.epd7in3e import EPD_HEIGHT, EPD_WIDTH, _crop_center\n",
|
||||
"\n",
|
||||
"# Pure-Python algorithms run at ~30s per 800x480 image; keep a curated subset by default.\n",
|
||||
"# Toggle SHOW_ALL = True to run everything (will take several minutes).\n",
|
||||
"DEFAULT_ALGOS = ['atkinson_fast', 'atkinson', 'atkinson_weighted',\n",
|
||||
" 'floyd_steinberg', 'floyd_steinberg_weighted',\n",
|
||||
" 'jarvis', 'sierra_lite', 'burkes',\n",
|
||||
" 'bayer4', 'bayer8', 'pil_fs', 'none']\n",
|
||||
"DEFAULT_ALGOS = [\n",
|
||||
" \"atkinson_fast\",\n",
|
||||
" \"atkinson\",\n",
|
||||
" \"atkinson_weighted\",\n",
|
||||
" \"floyd_steinberg\",\n",
|
||||
" \"floyd_steinberg_weighted\",\n",
|
||||
" \"jarvis\",\n",
|
||||
" \"sierra_lite\",\n",
|
||||
" \"burkes\",\n",
|
||||
" \"bayer4\",\n",
|
||||
" \"bayer8\",\n",
|
||||
" \"pil_fs\",\n",
|
||||
" \"none\",\n",
|
||||
"]\n",
|
||||
"SHOW_ALL = False\n",
|
||||
"ALGOS = list(DITHER_ALGORITHMS.keys()) if SHOW_ALL else DEFAULT_ALGOS\n",
|
||||
"\n",
|
||||
|
|
@ -57,6 +72,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "9a63283cbaf04dbcab1f6479b197f3a8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -91,20 +107,21 @@
|
|||
" sources.append((asset, _crop_center(img, EPD_WIDTH, EPD_HEIGHT)))\n",
|
||||
"\n",
|
||||
"for asset, _ in sources:\n",
|
||||
" print(asset.get('originalFileName') or asset['id'])\n",
|
||||
" print(asset.get(\"originalFileName\") or asset[\"id\"])\n",
|
||||
"\n",
|
||||
"# Render the 6-colour palette as a tiny banner so the colour budget is visible.\n",
|
||||
"swatch_h = 60\n",
|
||||
"swatch_w = 60\n",
|
||||
"palette_strip = np.zeros((swatch_h, swatch_w * len(PALETTE_RGB), 3), dtype=np.uint8)\n",
|
||||
"for i, rgb in enumerate(PALETTE_RGB):\n",
|
||||
" palette_strip[:, i * swatch_w:(i + 1) * swatch_w] = rgb\n",
|
||||
" palette_strip[:, i * swatch_w : (i + 1) * swatch_w] = rgb\n",
|
||||
"Image.fromarray(palette_strip)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "8dd0d8092fe74a7c96281538738b07e2",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -143,22 +160,23 @@
|
|||
"source": [
|
||||
"results = [] # list of dict per (photo, algo)\n",
|
||||
"for asset, source in sources:\n",
|
||||
" name = asset.get('originalFileName') or asset['id']\n",
|
||||
" print(f'[{name}]')\n",
|
||||
" name = asset.get(\"originalFileName\") or asset[\"id\"]\n",
|
||||
" print(f\"[{name}]\")\n",
|
||||
" photo_results = []\n",
|
||||
" for algo in ALGOS:\n",
|
||||
" info = DITHER_ALGORITHMS[algo]\n",
|
||||
" t0 = time.perf_counter()\n",
|
||||
" out = apply_dithering(source, algo)\n",
|
||||
" dt = time.perf_counter() - t0\n",
|
||||
" photo_results.append({'algo': algo, 'name': info['name'], 'image': out, 'duration': dt})\n",
|
||||
" print(f' {info[\"name\"]:32s} {dt:6.2f}s')\n",
|
||||
" results.append({'asset': asset, 'source': source, 'algos': photo_results})"
|
||||
" photo_results.append({\"algo\": algo, \"name\": info[\"name\"], \"image\": out, \"duration\": dt})\n",
|
||||
" print(f\" {info['name']:32s} {dt:6.2f}s\")\n",
|
||||
" results.append({\"asset\": asset, \"source\": source, \"algos\": photo_results})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "72eea5119410473aa328ad9291626812",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -185,21 +203,22 @@
|
|||
"source": [
|
||||
"# One grid per photo: original + every algorithm.\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"for entry in results:\n",
|
||||
" panels = [entry['source']] + [r['image'] for r in entry['algos']]\n",
|
||||
" titles = ['original (cropped)'] + [f\"{r['name']}\\n{r['duration']:.2f}s\" for r in entry['algos']]\n",
|
||||
" panels = [entry[\"source\"]] + [r[\"image\"] for r in entry[\"algos\"]]\n",
|
||||
" titles = [\"original (cropped)\"] + [f\"{r['name']}\\n{r['duration']:.2f}s\" for r in entry[\"algos\"]]\n",
|
||||
" cols = 4\n",
|
||||
" rows = (len(panels) + cols - 1) // cols\n",
|
||||
" fig, axes = plt.subplots(rows, cols, figsize=(5.0 * cols, 3.2 * rows))\n",
|
||||
" axes = np.atleast_2d(axes)\n",
|
||||
" name = entry['asset'].get('originalFileName') or entry['asset']['id']\n",
|
||||
" name = entry[\"asset\"].get(\"originalFileName\") or entry[\"asset\"][\"id\"]\n",
|
||||
" fig.suptitle(name, fontsize=12)\n",
|
||||
" for k in range(rows * cols):\n",
|
||||
" ax = axes[k // cols][k % cols]\n",
|
||||
" if k < len(panels):\n",
|
||||
" ax.imshow(panels[k])\n",
|
||||
" ax.set_title(titles[k], fontsize=10)\n",
|
||||
" ax.axis('off')\n",
|
||||
" ax.axis(\"off\")\n",
|
||||
" plt.tight_layout()\n",
|
||||
" plt.show()"
|
||||
]
|
||||
|
|
@ -207,6 +226,7 @@
|
|||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "8edb47106e1a46a883d545849b8ab81b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
|
|
@ -232,12 +252,13 @@
|
|||
"source": [
|
||||
"# Per-algorithm summary across both photos: mean runtime + a single representative panel.\n",
|
||||
"from collections import defaultdict\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"agg = defaultdict(list)\n",
|
||||
"for entry in results:\n",
|
||||
" for r in entry['algos']:\n",
|
||||
" agg[r['algo']].append(r['duration'])\n",
|
||||
" for r in entry[\"algos\"]:\n",
|
||||
" agg[r[\"algo\"]].append(r[\"duration\"])\n",
|
||||
"\n",
|
||||
"print(f\"{'algorithm':32s} {'avg time':>9s} description\")\n",
|
||||
"for algo in ALGOS:\n",
|
||||
|
|
@ -248,6 +269,7 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "10185d26023b46108eb7d9f57d49d2b3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Picking an algorithm\n",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue