LeukoAI / leukoai /preprocess.py
LeukoAI deploy
Deploy 3d58ff8 from synav/LeukoAI-dev
bda108c
Raw History Blame Contribute Delete
2.31 kB
"""Image preprocessing, identical to the original application.
ToTensor -> zero-pad to square (centred) -> resize to 448 x 448, bilinear,
no antialiasing, no mean/std normalisation.
``antialias=False`` reproduces tensor resizing in torchvision 0.13
(PyTorch 1.12.1, the version bundled in toolv9). Newer torchvision versions
default to ``antialias=True``, which changes the input noticeably.
"""
from __future__ import annotations
import torchvision.transforms.functional as F
from PIL import Image
from torchvision import transforms
# Formats the original application accepted (it used imghdr: jpeg, png, tiff).
ACCEPTED_FORMATS = {"JPEG", "PNG", "TIFF", "MPO"}
def square_pad(t):
"""Replica of the app's SquarePad, including its rounding of odd differences."""
h, w = t.size()[-2:]
m = max(h, w)
top = int((m - h) / 2)
left = int((m - w) / 2)
# torchvision pad order: (left, top, right, bottom)
return F.pad(t, (left, top, left, top), 0, "constant")
TRANSFORM = transforms.Compose([
transforms.ToTensor(),
square_pad,
transforms.Resize((448, 448), antialias=False),
])
def app_would_read(path: str) -> bool:
"""Replicates the app's file filter: Python 3.8 ``imghdr.what(path) in ('jpeg', 'png', 'tiff')``.
Python 3.8 imghdr recognises a JPEG only if bytes 6-10 are 'JFIF' or 'Exif',
so JPEGs without those headers were silently ignored by the desktop app.
"""
try:
with open(path, "rb") as f:
h = f.read(32)
except OSError:
return False
if h[6:10] in (b"JFIF", b"Exif"):
return True # jpeg
if h.startswith(b"\211PNG\r\n\032\n"):
return True # png
if h[:6] in (b"GIF87a", b"GIF89a"):
return False # gif (tested before tiff)
return h[:2] in (b"MM", b"II") # tiff
def open_image(path: str):
"""Open an image; return None if it is not a readable JPEG/PNG/TIFF."""
try:
img = Image.open(path)
if img.format not in ACCEPTED_FORMATS:
return None
return img.convert("RGB")
except Exception:
return None
def to_tensor(img: Image.Image):
return TRANSFORM(img.convert("RGB")).unsqueeze(0)