Holger Frey
4 years ago
7 changed files with 286 additions and 1 deletions
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
from pathlib import Path |
||||
from PIL import Image, ImageDraw, ImageFont |
||||
|
||||
from sensospot_images import process |
||||
from sensospot_data import parse_file |
||||
from sensospot_data.parameters import _search_measurement_params_file |
||||
|
||||
from defusedxml import ElementTree |
||||
|
||||
import itertools |
||||
|
||||
THIS_FILE_DIR = Path(__file__).absolute().parent |
||||
|
||||
EXAMPLE_DATA_DIR = THIS_FILE_DIR / "example_data" |
||||
EXAMPLE_IMAGE = EXAMPLE_DATA_DIR / "11Aug2020 NQC0329 Dry SG2-127-002_1_A01_1.tif" |
||||
EXAMPLE_DATA = EXAMPLE_DATA_DIR / "11Aug2020 NQC0329 Dry SG2-127-002_1_A01_1.csv" |
||||
|
||||
OUTPUT_DIR = THIS_FILE_DIR / "example_output" |
||||
old_output_files = [i for i in OUTPUT_DIR.iterdir() if i.is_file()] |
||||
for path in old_output_files: |
||||
path.unlink() |
||||
|
||||
|
||||
process(EXAMPLE_DATA_DIR, OUTPUT_DIR) |
Binary file not shown.
@ -0,0 +1,90 @@
@@ -0,0 +1,90 @@
|
||||
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) |
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
from pathlib import Path |
||||
from collections import namedtuple |
||||
|
||||
from defusedxml import ElementTree |
||||
|
||||
ArrayParameters = namedtuple( |
||||
"ArrayParameters", ["size_x", "size_y", "dist_x", "dist_y"] |
||||
) |
||||
|
||||
SpotParameters = namedtuple( |
||||
"SpotParameters", |
||||
["radius_spot", "radius_bkg", "roi_x", "roi_y", "crop_x", "crop_y"], |
||||
) |
||||
|
||||
|
||||
def _to_micro_meters(value): |
||||
as_float = float(value) |
||||
return int(as_float * 1000) |
||||
|
||||
|
||||
def array_parameters_from_xml(tree): |
||||
layout = tree.find("Layout") |
||||
sx = int(layout.attrib["NofSpotsX"]) |
||||
sy = int(layout.attrib["NofSpotsY"]) |
||||
dx = _to_micro_meters(layout.attrib["SpotDistMmX"]) |
||||
dy = _to_micro_meters(layout.attrib["SpotDistMmY"]) |
||||
return ArrayParameters(sx, sy, dx, dy) |
||||
|
||||
|
||||
def spot_parameters_from_xml(tree, array_parameters): |
||||
array = tree.find("MicroArrayAnalysis").find("Settings") |
||||
reg = tree.find("Registration").find("Settings") |
||||
rs = _to_micro_meters(array.attrib["MinSpotSizeMm"]) |
||||
rb = _to_micro_meters(array.attrib["MaxSpotSizeMm"]) |
||||
rx = array_parameters.dist_x |
||||
ry = array_parameters.dist_y |
||||
# ROI is strangely named in params file, it's actually the outside crop |
||||
cx = _to_micro_meters(reg.attrib["ROIMarginWidth"]) |
||||
cy = _to_micro_meters(reg.attrib["ROIMarginHeight"]) |
||||
return SpotParameters(rs, rb, rx, ry, cx, cy) |
||||
|
||||
|
||||
def get_array_parameters(params_file): |
||||
svary_file = Path(params_file).with_suffix(".svary") |
||||
with svary_file.open("r") as file_handle: |
||||
tree = ElementTree.parse(file_handle) |
||||
return array_parameters_from_xml(tree) |
||||
|
||||
|
||||
def get_spot_parameters(params_file, array_parameters): |
||||
svalg_file = Path(params_file).with_suffix(".svalg") |
||||
with svalg_file.open("r") as file_handle: |
||||
tree = ElementTree.parse(file_handle) |
||||
return spot_parameters_from_xml(tree, array_parameters) |
Loading…
Reference in new issue