You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.4 KiB
122 lines
3.4 KiB
from collections import namedtuple |
|
from functools import partial |
|
from multiprocessing import Pool |
|
from PIL import Image |
|
from tqdm import tqdm |
|
|
|
import numpy |
|
|
|
from .luts import FIRE_LUT |
|
|
|
|
|
STATS_FUNCS = { |
|
"min": numpy.amin, |
|
"max": numpy.amax, |
|
"1quantile": partial(numpy.percentile, q=25), |
|
"2quantile": partial(numpy.percentile, q=50), |
|
"3quantile": partial(numpy.percentile, q=75), |
|
"average": numpy.average, |
|
"median": numpy.median, |
|
"std": numpy.std, |
|
} |
|
|
|
LEFT_GUARD = "left" |
|
ROI_NAME = "roi" |
|
RIGHT_GUARD = "right" |
|
|
|
ROI_BORDER_INTENSITY = 2**15 |
|
|
|
TifArray = namedtuple("TifArray", ["path", "frame", "data"]) |
|
|
|
|
|
def open_as_array(tif_image): |
|
with tif_image.path.open("rb") as filehandle: |
|
image = Image.open(filehandle) |
|
image_array = numpy.array(image, dtype=numpy.int32) |
|
return TifArray( |
|
path=tif_image.path, frame=tif_image.frame, data=image_array |
|
) |
|
|
|
|
|
def scale_and_colorize(tif_array, settings): |
|
adjusted_array = (tif_array.data - settings.offset) // settings.scale |
|
|
|
# paint roi |
|
|
|
top = settings.roi_top |
|
bottom = settings.roi_bottom |
|
right = settings.roi_right |
|
left = settings.roi_left |
|
adjusted_array[top, left:right] = ROI_BORDER_INTENSITY |
|
adjusted_array[bottom, left:right] = ROI_BORDER_INTENSITY |
|
adjusted_array[top:bottom, left] = ROI_BORDER_INTENSITY |
|
adjusted_array[top:bottom, right] = ROI_BORDER_INTENSITY |
|
|
|
adjusted = Image.fromarray(adjusted_array) |
|
converted = adjusted.convert(mode="L").convert(mode="P") |
|
converted.putpalette(FIRE_LUT) |
|
return converted.convert("RGB") |
|
|
|
|
|
def safe_color_coded(tif_array, settings): |
|
png_image = scale_and_colorize(tif_array, settings) |
|
png_path = settings.colored_dir / (tif_array.path.stem + ".jpg") |
|
with png_path.open("wb") as outhandle: |
|
png_image.save(outhandle) |
|
del png_image |
|
|
|
|
|
def safe_cut(tif_array, settings): |
|
cut_path = settings.cuts_dir / (tif_array.path.stem + "_cut.tif") |
|
|
|
top = settings.cut_top |
|
bottom = settings.cut_bottom |
|
right = settings.cut_right |
|
left = settings.cut_left |
|
|
|
with cut_path.open("wb") as outhandle: |
|
cut_array = tif_array.data[top:bottom, left:right] |
|
cut_img = Image.fromarray(cut_array) |
|
cut_img.save(outhandle) |
|
del cut_img |
|
|
|
|
|
def get_roi(tif_array, settings): |
|
top = settings.roi_top |
|
bottom = settings.roi_bottom |
|
right = settings.roi_right |
|
left = settings.roi_left |
|
return tif_array.data[top:bottom, left:right] |
|
|
|
|
|
def analyse_roi(tif_array, settings): |
|
data = get_roi(tif_array, settings) |
|
results = {} |
|
results.update(get_stats(data[:, 1], LEFT_GUARD)) |
|
results.update(get_stats(data[:, 1:-1], ROI_NAME)) |
|
results.update(get_stats(data[:, -1], RIGHT_GUARD)) |
|
return results |
|
|
|
|
|
def get_stats(array, prefix): |
|
return {f"{prefix}.{k}": f(array) for k, f in STATS_FUNCS.items()} |
|
|
|
|
|
def process_one_tif(tif_image, settings): |
|
tif_array = open_as_array(tif_image) |
|
safe_color_coded(tif_array, settings) |
|
safe_cut(tif_array, settings) |
|
stats_result = analyse_roi(tif_array, settings) |
|
stats_result["file"] = tif_image.path.name |
|
stats_result["frame"] = tif_image.frame |
|
return stats_result |
|
|
|
|
|
def image_workflow(settings): |
|
print("2/4: Image analysis and conversion") |
|
func = partial(process_one_tif, settings=settings) |
|
tif_list = settings.tif_list |
|
num_items = len(tif_list) |
|
with Pool(4) as p: |
|
stat_results = list(tqdm(p.imap(func, tif_list), total=num_items)) |
|
return stat_results
|
|
|