Spaces:
Sleeping
Sleeping
File size: 5,197 Bytes
8e6b3e7 19bc1e0 8e6b3e7 19bc1e0 8e6b3e7 |
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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
from pystackreg import StackReg
import numpy as np
import imageio.v2 as iio
from PIL import Image
import time
import threading
import hashlib
import tempfile
import os
def get_sr_mode(mode_str): return {
"TRANSLATION": StackReg.TRANSLATION,
"RIGID_BODY": StackReg.RIGID_BODY,
"SCALED_ROTATION": StackReg.SCALED_ROTATION,
"AFFINE": StackReg.AFFINE,
"BILINEAR": StackReg.BILINEAR,
}.get(mode_str, StackReg.RIGID_BODY)
def normalize_stack(stack):
norm_stack = []
for frame in stack:
f = frame.astype(np.float32)
low, high = np.percentile(f, (1, 99))
f = np.clip(f, low, high)
f = (f - f.min()) / (np.ptp(f) + 1e-8) * 255 if np.ptp(f) > 0 else np.zeros_like(f)
norm_stack.append(f.astype(np.uint8))
return np.stack(norm_stack)
def upscale(image, factor=3):
return image.resize((image.width * factor, image.height * factor), Image.NEAREST)
def load_stack(file):
stack = np.array(iio.mimread(file))
if stack.ndim == 4 and stack.shape[-1] == 3:
stack = np.mean(stack, axis=-1)
return normalize_stack(stack)
##### CACHE #####
# App-scoped cache dirs under the OS temp
APP_TMP_ROOT = os.path.join(tempfile.gettempdir(), "psr_cache")
WORK_DIR = os.path.join(APP_TMP_ROOT, "work") # cleaned periodically
DEMO_DIR = os.path.join(APP_TMP_ROOT, "demo") # persistent demo cache
os.makedirs(WORK_DIR, exist_ok=True)
os.makedirs(DEMO_DIR, exist_ok=True)
# Direct all tempfile.* calls to WORK_DIR so cleanup is safe
tempfile.tempdir = WORK_DIR
TTL_SECONDS = 30 * 60 # 30 minutes
def _cleanup_old_files(folder, older_than_seconds):
now = time.time()
for root, _, files in os.walk(folder):
for name in files:
p = os.path.join(root, name)
try:
if now - os.path.getmtime(p) > older_than_seconds:
os.remove(p)
except Exception as e:
print(f"[cleanup] {e}")
def _start_cleaner():
def loop():
while True:
_cleanup_old_files(WORK_DIR, TTL_SECONDS) # only clean WORK_DIR
time.sleep(TTL_SECONDS)
threading.Thread(target=loop, daemon=True).start()
def _is_demo_url(url: str) -> bool:
return ("github.com/glichtner/pystackreg" in url) or \
("raw.githubusercontent.com/glichtner/pystackreg" in url)
def _demo_path_for_url(url: str, suffix=".tif"):
h = hashlib.sha256(url.encode("utf-8")).hexdigest()[:16]
return os.path.join(DEMO_DIR, f"psr-demo-{h}{suffix}")
##### Markdowns #####
citation_markdown = """
### 📘 Credits & Acknowledgments
Register TIFF stacks using multiple alignment strategies.
**App Author**: [Quentin Chappuis](https://github.com/qchapp)
**Pystackreg Author**: [Gregor Lichtenberg](https://github.com/glichtner)
🔗 [Pystackreg on GitHub](https://github.com/glichtner/pystackreg)
**Original Algorithm Author**: Philippe Thévenaz (EPFL)
The core algorithm was originally developed by Philippe Thévenaz and is described in the following publication:
> P. Thévenaz, U.E. Ruttimann, M. Unser
> *A Pyramid Approach to Subpixel Registration Based on Intensity*
> *IEEE Transactions on Image Processing*, vol. 7, no. 1, pp. 27–41, January 1998.
> 🔗 [View paper](http://bigwww.epfl.ch/publications/thevenaz9801.html)
"""
documentation_markdown = """
### Overview
This app provides three registration modes for 2D TIFF image stacks using the `pystackreg` library.
---
### 📚 Tab 1: Reference-Based Alignment
Register a stack using a reference frame. You can:
- Use a frame from the **same stack** as reference
- Or upload an **external reference stack**
1. Upload the stack you want to align.
2. (Optional) Check "Use external reference stack" to align to a frame from another file.
3. Choose the reference frame using the slider.
4. (Optional) Choose transformation mode.
5. Click **▶️ Align Stack**.
6. Use sliders to browse original/aligned results and download the output.
---
### 🎯 Tab 2: Stack-Based Alignment
Align one stack (moving) to another (reference).
1. Upload both **reference** and **moving** stacks.
2. (Optional) Choose transformation mode.
3. Click **▶️ Register** to align.
4. Browse and download registered stack.
---
### 🧩 Tab 3: Frame-to-Frame Alignment
Align a **single frame to another** from the same stack.
1. Upload a stack.
2. Select **reference** and **moving** frames using sliders.
3. Choose transformation mode.
4. Click **▶️ Register Frame**.
5. View/download the result.
---
### 🔄 Reset Buttons
Each tab includes a **Reset Tab** button that clears inputs, outputs, and internal state.
---
### 🧠 Credits
App developed by **Quentin Chapuis**
Library: [`pystackreg`](https://github.com/glichtner/pystackreg) by **Georg Lichtenberg**
""" |