Spaces:
Sleeping
Sleeping
File size: 2,909 Bytes
b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b 60fece7 b2ffc9b |
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 |
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author : Romain Graux
@date : 2023 April 25, 11:59:06
@last modified : 2023 September 19, 11:18:36
"""
from typing import Callable, Optional
import re
import imageio
from collections import namedtuple
import numpy as np
PhysicalMetadata = namedtuple(
"PhysicalMetadata", ["width", "height", "pixel_width", "pixel_height", "unit"]
)
MetadataExtractor = Callable[[dict, int, int], Optional[PhysicalMetadata]]
def extract_imagej_metadata(
metadata: dict, width: int, height: int
) -> Optional[PhysicalMetadata]:
try:
ipw, iph, _ = metadata["resolution"]
result = re.search(r"unit=(.+)", metadata["description"])
if not result:
return None
unit = result.group(1)
return PhysicalMetadata(width, height, 1.0 / ipw, 1.0 / iph, unit.lower())
except (KeyError, AttributeError):
return None
def extract_resolution_metadata(
metadata: dict, width: int, height: int
) -> Optional[PhysicalMetadata]:
try:
ipw, iph, _ = metadata["resolution"]
# It looks like the resolution unit is not really reliable, so let's just assume nm
unit = "nm"
return PhysicalMetadata(width, height, 1.0 / ipw, 1.0 / iph, unit)
except (KeyError, AttributeError):
return None
METADATA_EXTRACTORS: list[MetadataExtractor] = [
extract_imagej_metadata,
extract_resolution_metadata,
]
def normalize_metadata(metadata: PhysicalMetadata) -> PhysicalMetadata:
conversion_factor = {
"inch": 2.54e7,
"m": 1e9,
"dm": 1e8,
"cm": 1e7,
"mm": 1e6,
"µm": 1e3,
"nm": 1,
}
if metadata.unit not in conversion_factor:
raise ValueError(f"Unknown unit: {metadata.unit}")
factor = conversion_factor[metadata.unit]
return PhysicalMetadata(
metadata.width,
metadata.height,
metadata.pixel_width * factor,
metadata.pixel_height * factor,
"nm",
)
def extract_physical_metadata(image_path: str, strict: bool = True) -> PhysicalMetadata:
"""
Extracts the physical metadata of an image by trying all available extractors.
Raises ValueError if no extractor succeeds.
"""
with open(image_path, "rb") as f:
data = f.read()
reader = imageio.get_reader(data)
metadata = reader.get_meta_data()
h, w = reader.get_next_data().shape
for extractor in METADATA_EXTRACTORS:
result = extractor(metadata, w, h)
if result is not None:
return normalize_metadata(result)
raise ValueError(
"Failed to extract metadata from the image using any available method."
)
def tiff_to_png(image, inplace=True):
img = image if inplace else image.copy()
if np.array(img.getdata()).max() <= 1:
img = img.point(lambda p: p * 255)
return img.convert("RGB")
|