Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions orangecontrib/snom/preprocess/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import numpy as np
from enum import Enum

from Orange.data import Domain
from Orange.preprocess import Preprocess

from orangecontrib.spectroscopy.preprocess import (
CommonDomain,
SelectColumn,
Expand All @@ -14,6 +16,8 @@
index_values,
)

from pySNOM.images import mask_from_datacondition


class PreprocessImageOpts(Preprocess):
pass
Expand Down Expand Up @@ -72,6 +76,7 @@ def __call__(self, data, image_opts, run_all=False):
attrs_to_run = [image_opts["attr_value"]]
newdata = _prepare_table_for_image(data, image_opts)

mask = get_mask_from_image_opts(data, image_opts)
image_opts = image_opts.copy() # otherwise this input will be changed
new_vals = np.full_like(newdata.X, np.nan)
for i, attr in enumerate(attrs_to_run):
Expand All @@ -85,7 +90,7 @@ def __call__(self, data, image_opts, run_all=False):

try:
image, indices = _image_from_table(temp, image_opts)
transformed = self.transform_image(image, newdata)
transformed = self.transform_image(image, newdata, mask=mask)
new_vals[:, i] = transformed[indices].reshape(-1)
except InvalidAxisException:
new_vals[:, i] = np.full(len(newdata), np.nan)
Expand All @@ -95,7 +100,7 @@ def __call__(self, data, image_opts, run_all=False):

return newdata

def transform_image(self, image, data):
def transform_image(self, image, data, mask=None):
"""
image: a numpy 2D array where image[y,x] is the value in image row y and column x
data: image data set (used for passing meta data)
Expand Down Expand Up @@ -246,3 +251,34 @@ def transform_image(self, image):
image: a numpy 2D array where image[y,x] is the value in image row y and column x
"""
raise NotImplementedError


def get_mask_from_image_opts(data, image_opts):
if image_opts.get("attr_mask", None) is None:
return None
image_opts = image_opts.copy()
image_opts["attr_value"] = image_opts["attr_mask"]
try:
masktable = _prepare_table_for_image(data, image_opts)
except KeyError:
return None
maskimage, _ = _image_from_table(masktable, image_opts)
mask = mask_from_datacondition(maskimage == image_opts["value_mask"])
return mask


class MaskOptions(Enum):
ignore = 0
exclude = 1
include = 2


def transform_mask(mask, option):
if option == MaskOptions.ignore:
return None
elif option == MaskOptions.include:
return mask_from_datacondition(mask == 1.0)
elif option == MaskOptions.exclude:
return mask
else:
raise NotImplementedError
33 changes: 29 additions & 4 deletions orangecontrib/snom/tests/test_preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import numpy as np

from Orange.data import Table, ContinuousVariable, Domain
from Orange.data import Table, ContinuousVariable, Domain, DiscreteVariable

from orangecontrib.spectroscopy.tests.test_preprocess import (
TestCommonIndpSamplesMixin as TCommonIndpSamplesMixin, # hide it from pytest
Expand Down Expand Up @@ -30,10 +30,13 @@ def test_simple(self):

def test_whitelight_mulcol():
wl = Table("whitelight.gsf")
ncol = DiscreteVariable(
"mask", values=["No", "Yes"], compute_value=lambda d: d.get_column("map_y") > 30
)
dom = Domain(
[ContinuousVariable(name="%0.6f" % i) for i in range(1, 4)],
wl.domain.class_vars,
wl.domain.metas,
wl.domain.metas + (ncol,),
)
out = wl.transform(dom)
for i in range(2, 4):
Expand All @@ -43,9 +46,11 @@ def test_whitelight_mulcol():


class _MultiplyImage(PreprocessImageOpts2DOnlyWhole):
def transform_image(self, image, data):
def transform_image(self, image, data, mask=None):
multiplier = float(data.domain.attributes[0].name)
return image * multiplier
if mask is None:
mask = np.full_like(image, True)
return image * multiplier * mask


class TestPreprocessImageOpts2DOnlyWhole(unittest.TestCase):
Expand Down Expand Up @@ -75,6 +80,26 @@ def test_no_atts(self):
out = proc(no_atts, imageopts, run_all=True)
np.testing.assert_equal(out.X, no_atts.X)

def test_mask(self):
wl = test_whitelight_mulcol()
imageopts = {
'attr_x': 'map_x',
'attr_y': 'map_y',
'attr_value': '2.000000',
'attr_mask': 'mask',
'value_mask': 1,
}
proc = _MultiplyImage()
out = proc(wl, imageopts, run_all=True)
mask = ~(wl.get_column("mask") == 1)
maski = ~mask
np.testing.assert_equal(out.X[:, 0][mask], wl.X[:, 0][mask] * 1)
np.testing.assert_equal(out.X[:, 1][mask], wl.X[:, 0][mask] * 2)
np.testing.assert_equal(out.X[:, 2][mask], wl.X[:, 0][mask] * 3)
np.testing.assert_equal(out.X[:, 0][maski], np.nan)
np.testing.assert_equal(out.X[:, 1][maski], np.nan)
np.testing.assert_equal(out.X[:, 2][maski], np.nan)


class _MultiplyImageReference(PreprocessImageOpts2DOnlyWholeReference):
def transform_image(self, image, ref_image, data):
Expand Down
66 changes: 62 additions & 4 deletions orangecontrib/snom/widgets/owpreprocessimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def onDeleteWidget(self):

def execute_with_image_opts(pp, data, image_opts, run_all=False):
Comment thread
markotoplak marked this conversation as resolved.
if isinstance(pp, PreprocessImageOpts):
return pp(data, image_opts, run_all)
return pp(data, image_opts, run_all=run_all)
return pp(data)


Expand Down Expand Up @@ -145,9 +145,11 @@ class OWPreprocessImage(SpectralImagePreprocessReference):
icon = "icons/preprocessimage.svg"
priority = 1010

settings_version = 3
settings_version = 4

settingsHandler = DomainContextHandler()
settingsHandler = DomainContextHandler(
match_values=DomainContextHandler.MATCH_VALUES_ALL
)

_max_preview_spectra = 1000000
preview_curves = Setting(100000)
Expand All @@ -156,6 +158,8 @@ class OWPreprocessImage(SpectralImagePreprocessReference):
BUTTON_ADD_LABEL = "Add preprocessor..."

attr_value = ContextSetting(None)
attr_mask = ContextSetting(None, exclude_attributes=True)
value_mask = ContextSetting(0)
attr_x = ContextSetting(None, exclude_attributes=True)
attr_y = ContextSetting(None, exclude_attributes=True)

Expand Down Expand Up @@ -185,17 +189,54 @@ def __init__(self):

self.preview_runner = ImagePreviewRunner(self)

mbox = gui.widgetBox(None, "Mask")
self.controlArea.layout().insertWidget(2, mbox)

self.mask_value_model = DomainModel(
Comment thread
markotoplak marked this conversation as resolved.
order=(
DomainModel.CLASSES,
DomainModel.Separator,
DomainModel.METAS,
),
valid_types=DiscreteVariable,
placeholder="None",
)

self.feature_value_model = DomainModel(
order=(DomainModel.ATTRIBUTES),
valid_types=ContinuousVariable,
)

common_options = {
"labelWidth": 50,
"labelWidth": 70,
"orientation": Qt.Horizontal,
"sendSelectedValue": True,
}

self.cb_mask_var = gui.comboBox(
mbox,
self,
"attr_mask",
label="Column",
contentsLength=12,
searchable=True,
callback=self.update_mask_value_items,
model=self.mask_value_model,
**common_options
)

common_options["sendSelectedValue"] = False
self.cb_mask_value = gui.comboBox(
mbox,
self,
"value_mask",
label="Value",
contentsLength=12,
callback=self.update_mask,
**common_options
)

common_options["sendSelectedValue"] = True
self.feature_value = gui.comboBox(
self.preview_settings_box,
self,
Expand Down Expand Up @@ -233,6 +274,9 @@ def __init__(self):

self.contextAboutToBeOpened.connect(lambda x: self.init_interface_data(x[0]))

# update values choosing mask variable
self.contextOpened.connect(self.update_mask_value_items)

self.preview_runner.preview_updated.connect(self.redraw_data)

def update_attr(self):
Expand Down Expand Up @@ -263,12 +307,26 @@ def init_attr_values(self, data):
self.xy_model.set_domain(domain)
self.attr_x = self.xy_model[0] if self.xy_model else None
self.attr_y = self.xy_model[1] if len(self.xy_model) >= 2 else self.attr_x
self.mask_value_model.set_domain(domain)
self.mask_value = None

def update_mask_value_items(self):
self.cb_mask_value.clear()
if self.attr_mask is not None:
self.cb_mask_value.addItems(list(self.data.domain[self.attr_mask].values))
self.cb_mask_value.setCurrentIndex(self.value_mask)
self.update_mask()

def update_mask(self):
self.on_modelchanged()

def image_opts(self):
return {
'attr_x': str(self.attr_x),
'attr_y': str(self.attr_y),
'attr_value': str(self.attr_value) if self.attr_value is not None else None,
'attr_mask': str(self.attr_mask) if self.attr_mask is not None else None,
'value_mask': self.value_mask,
}

def create_outputs(self):
Expand Down
32 changes: 26 additions & 6 deletions orangecontrib/snom/widgets/preprocessors/background_fit.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
from AnyQt.QtWidgets import QFormLayout

from orangewidget.gui import comboBox

from orangecontrib.spectroscopy.widgets.preprocessors.utils import BaseEditorOrange
from orangecontrib.spectroscopy.widgets.gui import lineEditIntRange

from pySNOM.images import BackgroundPolyFit, DataTypes
from pySNOM.images import MaskedBackgroundPolyFit, DataTypes

from orangecontrib.snom.preprocess.utils import (
PreprocessImageOpts2DOnlyWhole,
MaskOptions,
transform_mask,
)
from orangecontrib.snom.widgets.preprocessors.registry import preprocess_image_editors


class BackGroundFit(PreprocessImageOpts2DOnlyWhole):
def __init__(self, xorder=1, yorder=1):
def __init__(self, xorder=1, yorder=1, mask_method=False):
self.xorder = xorder
self.yorder = yorder
self.mask_method = mask_method

def transform_image(self, image, data):
def transform_image(self, image, data, mask=None):
datatype = data.attributes.get("measurement.signaltype", "Phase")
d, b = BackgroundPolyFit(
mask = transform_mask(mask=mask, option=MaskOptions[self.mask_method])
d = MaskedBackgroundPolyFit(
xorder=self.xorder, yorder=self.yorder, datatype=DataTypes[datatype]
).transform(image)
).transform(image, mask=mask)
return d


Expand All @@ -33,27 +39,41 @@ def __init__(self, parent=None, **kwargs):

self.xorder = 1
self.yorder = 1
self.mask_method = "ignore"

form = QFormLayout()
xorderedit = lineEditIntRange(self, self, "xorder", callback=self.edited.emit)
yorderedit = lineEditIntRange(self, self, "yorder", callback=self.edited.emit)
self.maskmethod_cb = comboBox(
self, self, "mask_method", callback=self.setmethod
)
self.maskmethod_cb.addItems([e.name for e in MaskOptions])

form.addRow("xorder", xorderedit)
form.addRow("yorder", yorderedit)
form.addRow("Mask", self.maskmethod_cb)

self.controlArea.setLayout(form)

def activateOptions(self):
pass # actions when user starts changing options

def setmethod(self):
self.mask_method = self.maskmethod_cb.currentText()
self.edited.emit()

def setParameters(self, params):
self.xorder = params.get("xorder", 1)
self.yorder = params.get("yorder", 1)
self.mask_method = params.get("mask_method", "ignore")

@classmethod
def createinstance(cls, params):
params = dict(params)
xorder = float(params.get("xorder", 1))
yorder = float(params.get("yorder", 1))
return BackGroundFit(xorder=xorder, yorder=yorder)
mask_method = params.get("mask_method", "ignore")
return BackGroundFit(xorder=xorder, yorder=yorder, mask_method=mask_method)

def set_preview_data(self, data):
if data:
Expand Down
Loading
Loading