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
91 lines
2.5 KiB
4 years ago
|
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)
|