Create nice images from Sensospot Array scans
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.

91 lines
2.5 KiB

from pathlib import Path
from collections import namedtuple
import numpy
from PIL import Image, ImageDraw, ImageFont
Point = namedtuple("Point", ["x", "y"])
Spot = namedtuple("Spot", ["found", "x", "y"])
THIS_DIR = Path(__file__).absolute().parent
FONT_PATH = THIS_DIR / "arial.ttf"
FONT = ImageFont.truetype(str(FONT_PATH), 32)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
def recalculate(iterable, factor):
recalculated = [v * factor for v in iterable]
cls = type(iterable)
try:
return cls(*recalculated)
except TypeError:
return tuple(recalculated)
def convert_16bit_to_8bit(img):
array = numpy.uint8(numpy.array(img) / 256)
return Image.fromarray(array)
def convert_16bit_grey_to_color(img):
return convert_16bit_to_8bit(img).convert(mode="RGB")
def resize(img, scale=1):
return img.resize(recalculate(img.size, scale))
def load_array_image(file_path, scale=1):
img = Image.open(file_path)
colored = convert_16bit_grey_to_color(img)
return resize(colored, scale)
def get_position(data_series, actual=True):
prefix = "Pos" if actual else "Pos.Nom"
x = int(data_series[f"{prefix}.X"])
y = int(data_series[f"{prefix}.Y"])
return Point(x, y)
def get_box(center, width, height=None):
height = width if height is None else height
dx = width / 2
dy = height / 2
return (center.x - dx, center.y - dy, center.x + dx, center.y + dy)
def annotate_spot(canvas, spot_parameters, spot_data, scale=1):
found = spot_data["Spot.Found"]
center = recalculate(get_position(spot_data, found), scale)
color = GREEN if found else RED
box = get_box(center, spot_parameters.roi_x, spot_parameters.roi_y)
canvas.rectangle(box, outline=color, width=1)
box = get_box(center, spot_parameters.radius_bkg)
canvas.ellipse(box, outline=color, width=2)
box = get_box(center, spot_parameters.radius_spot)
canvas.ellipse(box, outline=color, width=1)
canvas.text(center, str(spot_data["Pos.Id"]), RED, font=FONT)
def annotate_image(array_img, spot_parameters, array_data, scale):
canvas = ImageDraw.Draw(array_img)
for index, spot_data in array_data.iterrows():
annotate_spot(canvas, spot_parameters, spot_data, scale)
def crop(array_img, spot_parameters, spot_data, scale=1):
found = spot_data["Spot.Found"]
center = recalculate(get_position(spot_data, found), scale)
box = get_box(center, spot_parameters.crop_x, spot_parameters.crop_y)
return array_img.crop(box)