import numpy as np
import pandas as pd
from ..tbl.table import Table
from .. import setreqs
[docs]
class Value(Table):
"""Create mask value column at the coordinate position of each X and Y.
.. caution::
The mask image should be split into a single frame image. In other
words, the shape of reqs[1] in :meth:`process` should be (1, height,
width).
Args:
reqs[0] (Table): Table including X,Y-coordinates. Required params;
``length_unit``, ``pitch``.
reqs[1] (Image): Image stack to pick up intensity.
param["add_cols"] (list of str, optional): Additional columns to copy
from required table. If this param is not defined, index columns
are copied.
param["split_depth"] (int): File split depth number.
Returns:
Table: Table containing mask value column
"""
[docs]
def set_reqs(self, reqs, param):
"""Drop elements that exist only in one required data.
"""
self.reqs = setreqs.allocate_data(reqs, param)
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params from reqs[1].
"""
self.info.copy_req(0)
self.info.copy_req(1, "param")
length_unit = self.info.get_param_value("length_unit")
calc_cols = ["x_" + length_unit, "y_" + length_unit]
self.info.add_column(
0, "mask_val", "float32", "a.u.",
"Pixel intensity at the coordinate position")
self.info.add_param(
"calc_cols", calc_cols, "list of str",
"Column names for X,Y-coordinate")
index_cols = self.info.get_column_name("index")
self.info.add_param("index_cols", index_cols, "list of str",
"Columns for index")
if "add_cols" in param:
keeps = index_cols + param["add_cols"] + ["mask_val"]
index_cols = index_cols + param["add_cols"]
else:
keeps = index_cols + ["mask_val"]
self.info.delete_column(keeps=keeps)
self.info.add_param("index_cols", index_cols, "list of str",
"Columns for index")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Create mask value column at the coordinate position of each X and Y.
Args:
reqs[0] (pandas.DataFrame): Table including X,Y-coordinate.
reqs[1] (numpy.ndarray): Numpy 3D array with the shape of
(1, height, width).
param["calc_cols"] (list of str): Column names for X,Y-coordinate.
param["pitch"] (float): Length per pixel.
param["index_cols"] (list of str): Column names to keep in the
result table.
Returns:
pandas.DataFrame: Table containing mask value column
"""
df = reqs[0].copy()
img = reqs[1].copy()
if img.shape[0] > 1:
raise Exception("Image must be split into single frames.")
frm = img[0, :, :]
x = df[param["calc_cols"][0]].values / param["pitch"]
y = df[param["calc_cols"][1]].values / param["pitch"]
x_pos = np.floor(x).astype("int")
y_pos = np.floor(y).astype("int")
vals = []
for x, y in zip(x_pos, y_pos):
if (x < 0) or (frm.shape[1] <= x) or (y < 0) or \
(frm.shape[0] <= y):
vals.append(0)
else:
vals.append(frm[y, x])
df["mask_val"] = vals
use_cols = param["index_cols"] + ["mask_val"]
del_cols = [col for col in list(df.columns) if col not in use_cols]
df = df.drop(del_cols, axis=1)
return df
[docs]
class BinaryImage(Table):
"""Select table rows that have coordinates inside the binary mask.
.. caution::
The mask image should be split into a single frame image. In other
words, the shape of reqs[1] in :meth:`process` should be (1, height,
width).
Args:
reqs[0] (Table): Table including X,Y-coordinate. Required param;
``pitch``, ``length_unit``.
reqs[1] (Image): Mask image to select table.
param["split_depth"] (int): File split depth number.
Returns:
Table: Table with rows located inside mask image
"""
[docs]
def set_reqs(self, reqs, param):
"""Drop elements that exist only in one required data.
"""
self.reqs = setreqs.allocate_data(reqs, param)
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params from reqs[1].
"""
self.info.copy_req(0)
self.info.copy_req(1, "param")
length_unit = self.info.get_param_value("length_unit")
calc_cols = ["x_" + length_unit, "y_" + length_unit]
self.info.add_param(
"calc_cols", calc_cols, "list of str",
"Columns for X,Y-coordinate")
index_cols = self.info.get_column_name("index")
self.info.add_param("index_cols", index_cols, "list of str",
"Columns for index")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Select table rows that have coordinates inside the binary mask.
Args:
reqs[0] (pandas.DataFrame): Table including X,Y-coordinate.
reqs[1] (numpy.ndarray): Numpy 3D array with the shape of
(1, height, width).
param["calc_cols"] (list of str): Column names for X,Y-coordinate.
param["pitch"] (float): Length per pixel.
Returns:
pandas.DataFrame: Table rows located inside mask image
"""
df = reqs[0].copy()
img = reqs[1].copy()
if img.shape[0] > 1:
raise Exception("Image must be split into single frames.")
frm = img[0, :, :]
x = df[param["calc_cols"][0]].values / param["pitch"]
y = df[param["calc_cols"][1]].values / param["pitch"]
x_pos = np.floor(x).astype("int")
y_pos = np.floor(y).astype("int")
vals = []
for x, y in zip(x_pos, y_pos):
if (x < 0) or (frm.shape[1] <= x) or \
(y < 0) or (frm.shape[0] <= y):
vals.append(0)
else:
vals.append(frm[y, x])
df["mask_val"] = vals
df = df[df["mask_val"] > 0]
return df.drop(["mask_val"], axis=1)