Skip to content

[ENH] Image preprocess: masking#38

Merged
markotoplak merged 8 commits intoQuasars:masterfrom
ngergihun:masking
Dec 22, 2025
Merged

[ENH] Image preprocess: masking#38
markotoplak merged 8 commits intoQuasars:masterfrom
ngergihun:masking

Conversation

@ngergihun
Copy link
Copy Markdown
Contributor

We rediscussed with @borondics the way of using masks in OWPreprocessImage.
The conclusion was that probably the most flexible way is to use the categories of meta and class variables so the user could use any selection, cluster, etc, to define the mask.

This PR implements a 'Mask selection' box where the user can select the desired group. The synthesized mask is passed to the preprocessor, which is updated now through pySNOM.

Preprocess editors are also updated to enable or disable the use of the mask.

I tried to do it with the least amount of modifications.

@borondics
Copy link
Copy Markdown
Member

All tests seem to be passing. Good for me!

@markotoplak
Copy link
Copy Markdown
Contributor

OK, could you give me example how I can use this? So that I know what to test? Thanks!

@markotoplak markotoplak changed the title Masking [ENH] Masking Jul 17, 2025
@ngergihun
Copy link
Copy Markdown
Contributor Author

@markotoplak , Please find an example workflow and a datafile which benefits from the usage of masking, here:
https://1drv.ms/f/c/800ce5ae9ca43074/EiTdS_sgN8hFoerl6PzvUY8BCAHHepbn8_L5iIAIJHQ4-g?e=TjbeF2

Our idea was to use selections, groups to define the values that we mask out (not taken into account) in the preprocessors for the calculation of image corrections. The user can choose the desired group in the "Mask selection" box. The preprocessor UI is also updated with a checkbox to enable the mask for that specific preprocessor.

Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
@markotoplak
Copy link
Copy Markdown
Contributor

@ngergihun, thanks for a clear usage example. Seems to work for me.

Not connected with this PR, but... What does "Line leveling" actually do? Why does it seem to touch only the lines where both "squares" are present and not touch the rest (ok, it changes values but not the image)?

Is this a lucky artifact? Here is the unmasked version of the data you showed me:

a

@markotoplak
Copy link
Copy Markdown
Contributor

Oh, now I see it does not leave the background as it was.... Before there was a color gradient on it, now there is none. But would still like to know why is this useful...

@ngergihun
Copy link
Copy Markdown
Contributor Author

ow I see it does not leave the backgroun

It is not only a background issue. In scanning probe microscopy, you scan the sample in a raster scan pattern; thus, you have a fast axis (horizontal) and a slow axis (vertical). Because of the instabilities of the measurement, the base values of the horizontal lines are not only monotonically offset relative to each other, but there is noise on the line offset values. This cannot be corrected by a background fit.

The LineLevelling subtracts the mean or median value of a line. This only flattens the lines nicely if only the substrate level is considered in the calculation of the median values. The islands (in this example) disturb this method, because they do not represent the base value of the substrate.

By masking, the user can exclude these values, which mislead the correction calculation. In the correction, we only want to take into account datapoints that belong to the region that you want to reference to (usually the substrate). This is also true for optical images.

The example without masking out the island gives an incorrect result. That is why it is a good example.

@markotoplak
Copy link
Copy Markdown
Contributor

markotoplak commented Jul 24, 2025

The example without masking out the island gives an incorrect result. That is why it is a good example.

Thank you! Now I understand why masking allows actually getting the proper result and that what I showed is an artifact indeed.

As a user maybe "Masking: enable" in the preprocessor does not seem that obvious. You decide - but I think it should be more explicit like "Mask: remove from averaging".

I think it would also nice to have the other option, to choose how the mask would be used. Then instead of a checkbox, with could have a drop-down menu. Like "Mask: ignore | exclude mask (POSSIBLY from averaging) | include only mask" - here I could not think of nice names, but you'll get the idea. What do you think?

@ngergihun
Copy link
Copy Markdown
Contributor Author

As a user maybe "Masking: enable" in the preprocessor does not seem that obvious. You decide - but I think it should be more explicit like "Mask: remove from averaging".

I think it would also nice to have the other option, to choose how the mask would be used. Then instead of a checkbox, with could have a drop-down menu. Like "Mask: ignore | exclude mask (POSSIBLY from averaging) | include only mask" - here I could not think of nice names, but you'll get the idea. What do you think?

Yes, we were thinking about this at some point. Sometimes it can be convenient to be able to exclude or include.

@ngergihun
Copy link
Copy Markdown
Contributor Author

@markotoplak , Thanks for the review, and sorry for the long delay. I tried to make the changes you suggested. So far, the (Ignore, exclude, include) data option for the mask usage in the preprocessor is only implemented for the LineLevel preprocessor at the moment. If we find it okay, then I will implement it for the other preprocessors where it makes sense.

Thanks for the continuous support and suggestions.

@markotoplak markotoplak changed the title [ENH] Masking [ENH] Image preprocess: masking Dec 22, 2025
@markotoplak
Copy link
Copy Markdown
Contributor

For starters I rebased this in 1 commit so that editing is easier, and also rebased to master. The history backup is in https://github.com/markotoplak/orange-snom/tree/masking20251221

@markotoplak
Copy link
Copy Markdown
Contributor

@ngergihun, I am working on this, so the comments I write are mainly for myself. Don't worry about it. :)

Comment thread orangecontrib/snom/preprocess/utils.py Outdated
Comment thread orangecontrib/snom/preprocess/utils.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py
Comment thread orangecontrib/snom/preprocess/utils.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py Outdated
Comment thread orangecontrib/snom/widgets/owpreprocessimage.py
Comment thread orangecontrib/snom/widgets/preprocessors/simple_normalize.py
@markotoplak
Copy link
Copy Markdown
Contributor

@borondics, @ngergihun, I made some structural changes to this PR.

  1. I changed how the mask goes into processors, now it goes in the parameter dict.
  2. Then, I changed how mask settings are saved and loaded and have fixed some connected to it (there were not loading properly in some cases).

As far as I see, regarding (1), I get the same thing as before with example from Jul 21. Regarding (2), workflows now load properly regardless of which value is selected (before that got reset sometimes). Workflows saved with the previous version won't load properly, but whatever you set anew and load should now work.

Because I may have introduced new issues, testing is welcome. Pretty please. :)

@markotoplak
Copy link
Copy Markdown
Contributor

OK, this is probably it...

In the end, when I was writing tests, I did not quite get why the complication with this mask and nan values in it. Wouldn't it be simpler to have just booleans? Or are they also going to become weights? But I did not get into this and left that as-is.

It would be nice to get a confirmation from you that this works before I make a Quasar package. For now, I'll just merge and if you have complaints, fix them later.

@markotoplak markotoplak merged commit 0743bda into Quasars:master Dec 22, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants