Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Masked pixels appear in segmentation map #149

Closed
ysBach opened this issue Feb 18, 2023 · 1 comment
Closed

Masked pixels appear in segmentation map #149

ysBach opened this issue Feb 18, 2023 · 1 comment

Comments

@ysBach
Copy link
Contributor

ysBach commented Feb 18, 2023

The docs says

Masking a pixel is equivalent to setting data to zero and noise (if present) to infinity.

A test case to demonstrate this:

import numpy as np
import sep

mask = np.zeros((7, 7)).astype(bool)
mask[3, 3:] = True
data = np.ones((7, 7))
data[2:5, 2:5] += 20
obj, seg = sep.extract(data, thresh=1,
                       mask=mask, 
                       segmentation_map=True)
print(data)
print(mask.astype(int))
print(seg)
print(obj["x"], obj["y"])
# image
[[ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]]
# mask
[[0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 1 1 1 1]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]]
# Segmap
[[0 0 0 0 0 0 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 0 0 0 0 0 0]]
# Final x, y
[2.8595679] [3.]

The obj is correctly calculated after masking the pixels. (∵ obj["x"] != 3.0)
However, seg includes masked pixels, too.
I think this might be intentional, because the pixels used for extract can be retrived by seg & ~mask, while the additional segmentation information is given to the user. (I am not sure what is SExtractor's default, as I have never used it)
However, if that's the case, I think the documentation needs a bit more information.

@PJ-Watson
Copy link
Member

The docs says

Masking a pixel is equivalent to setting data to zero and noise (if present) to infinity.

A test case to demonstrate this:

import numpy as np
import sep

mask = np.zeros((7, 7)).astype(bool)
mask[3, 3:] = True
data = np.ones((7, 7))
data[2:5, 2:5] += 20
obj, seg = sep.extract(data, thresh=1,
                       mask=mask, 
                       segmentation_map=True)
print(data)
print(mask.astype(int))
print(seg)
print(obj["x"], obj["y"])

The obj is correctly calculated after masking the pixels. (∵ obj["x"] != 3.0) However, seg includes masked pixels, too. I think this might be intentional, because the pixels used for extract can be retrived by seg & ~mask, while the additional segmentation information is given to the user. (I am not sure what is SExtractor's default, as I have never used it) However, if that's the case, I think the documentation needs a bit more information.

This is actually quite an interesting issue - thanks for pointing this out! This is the intended behaviour (there is no equivalent in SExtractor to my knowledge), and stems from the order in which operations are applied. The mask is applied before the default filtering, which becomes clearer when turning this off (filter_kernel=None):

Default filter
# image
[[ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1. 21. 21. 21.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.]]
# mask
[[0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 1 1 1 1]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]]
# Segmap
[[0 0 0 0 0 0 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 1 1 1 1 1 0]
 [0 0 0 0 0 0 0]]
# Final x, y
[2.8595679] [3.]
`filter_kernel=None`
# image
[[ 1.  1.  1.  1.  1.  1.  1.]
[ 1.  1.  1.  1.  1.  1.  1.]
[ 1.  1. 21. 21. 21.  1.  1.]
[ 1.  1. 21. 21. 21.  1.  1.]
[ 1.  1. 21. 21. 21.  1.  1.]
[ 1.  1.  1.  1.  1.  1.  1.]
[ 1.  1.  1.  1.  1.  1.  1.]]
# mask
[[0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 1 1 1 1]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]]
# Segmap
[[0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]
 [0 0 1 1 1 0 0]
 [0 0 1 0 0 0 0]
 [0 0 1 1 1 0 0]
 [0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0]]
# Final x, y
[2.85714286] [3.]

Or to show the difference graphically, this is how the input data changes when a mask is given:

Figure

Image

The quantities are measured from these masked (and convolved) images, so it's not correct that the extracted pixels can be retrieved from seg & ~mask. This can be checked by comparing the number of pixels detected above the threshold - either tnpix, or npix - with and without the mask.

@PJ-Watson PJ-Watson mentioned this issue Feb 3, 2025
@PJ-Watson PJ-Watson linked a pull request Feb 3, 2025 that will close this issue
@PJ-Watson PJ-Watson removed a link to a pull request Feb 3, 2025
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

No branches or pull requests

2 participants