squidpy icon indicating copy to clipboard operation
squidpy copied to clipboard

Image segmentation and extract segmentation features

Open Nasrine26 opened this issue 3 years ago • 10 comments

... Hello, I had a question concerning image segmentation and feature extraction. I am using a Visium image with H&E stains. When I follow your tutorial with your image, I get no errors but when I use mine I get the following error:

ValueError: Expected height to be in interval [0, 2000], found 9761.

My image has the following size:

ImageContainer object with 3 layers:

image: y (2000), x (1935), z (1), channels (3)

image_smooth: y (2000), x (1935), z (1), channels (3)

segmented_watershed: y (2000), x (1935), z (1), channels:0 (1)

Many thanks!

Nasrine26 avatar Jan 25 '22 14:01 Nasrine26

Hi @Nasrine26 , thank you for the interest in squidpy! from the log you posted it seems like the segmentation was already performed (looking at the segmented_watershed layer). Would you mind sharing at what point of the tutorial it fails as well as te tracebak? thank you!

giovp avatar Feb 02 '22 14:02 giovp

Yes segmentation is performed but then when I try to extract the features with:

sq.im.calculate_image_features(
    adata_vis,
    my_image,
    layer="image",
    features="segmentation",
    key_added="segmentation_features",
    features_kwargs={
        "segmentation": {
            "label_layer": "segmented_watershed",
            "props": ["label", "area", "mean_intensity"],
            "channels": [1, 2],
        }
    },
    mask_circle=True,
)

following this [tutorial](https://squidpy.readthedocs.io/en/stable/auto_examples/image/compute_segmentation_features.html, I get the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-13-090ef3048512> in <module>
----> 1 sq.im.calculate_image_features(
      2     adata_vis,
      3     my_image,
      4     layer="image",
      5     features="segmentation",

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/im/_feature.py in calculate_image_features(adata, img, layer, library_id, features, features_kwargs, key_added, copy, n_jobs, backend, show_progress_bar, **kwargs)
     89     start = logg.info(f"Calculating features `{list(features)}` using `{n_jobs}` core(s)")
     90 
---> 91     res = parallelize(
     92         _calculate_image_features_helper,
     93         collection=adata.obs_names,

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/_utils.py in wrapper(*args, **kwargs)
    166             pbar, queue, thread = None, None, None  # type: ignore[assignment]
    167 
--> 168         res = jl.Parallel(n_jobs=n_jobs, backend=backend)(
    169             jl.delayed(runner if use_runner else callback)(
    170                 *((i, cs) if use_ixs else (cs,)),

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/parallel.py in __call__(self, iterable)
   1039             # remaining jobs.
   1040             self._iterating = False
-> 1041             if self.dispatch_one_batch(iterator):
   1042                 self._iterating = self._original_iterator is not None
   1043 

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/parallel.py in dispatch_one_batch(self, iterator)
    857                 return False
    858             else:
--> 859                 self._dispatch(tasks)
    860                 return True
    861 

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/parallel.py in _dispatch(self, batch)
    775         with self._lock:
    776             job_idx = len(self._jobs)
--> 777             job = self._backend.apply_async(batch, callback=cb)
    778             # A job can complete so quickly than its callback is
    779             # called before we get here, causing self._jobs to

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/_parallel_backends.py in apply_async(self, func, callback)
    206     def apply_async(self, func, callback=None):
    207         """Schedule a func to be run"""
--> 208         result = ImmediateResult(func)
    209         if callback:
    210             callback(result)

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/_parallel_backends.py in __init__(self, batch)
    570         # Don't delay the application, to avoid keeping the input
    571         # arguments in memory
--> 572         self.results = batch()
    573 
    574     def get(self):

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/parallel.py in __call__(self)
    260         # change the default number of processes to -1
    261         with parallel_backend(self._backend, n_jobs=self._n_jobs):
--> 262             return [func(*args, **kwargs)
    263                     for func, args, kwargs in self.items]
    264 

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/joblib/parallel.py in <listcomp>(.0)
    260         # change the default number of processes to -1
    261         with parallel_backend(self._backend, n_jobs=self._n_jobs):
--> 262             return [func(*args, **kwargs)
    263                     for func, args, kwargs in self.items]
    264 

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/im/_feature.py in _calculate_image_features_helper(obs_ids, adata, img, layer, library_id, features, features_kwargs, queue, **kwargs)
    117 ) -> pd.DataFrame:
    118     features_list = []
--> 119     for crop in img.generate_spot_crops(
    120         adata, obs_names=obs_ids, library_id=library_id, return_obs=False, as_array=False, **kwargs
    121     ):

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/im/_container.py in generate_spot_crops(self, adata, spatial_key, library_id, spot_scale, obs_names, as_array, squeeze, return_obs, **kwargs)
    813                 y = int(y - self.data.attrs[Key.img.coords].y0)
    814                 x = int(x - self.data.attrs[Key.img.coords].x0)
--> 815             crop = self.crop_center(y=y, x=x, radius=radius, library_id=obs_library_ids[i], **kwargs)
    816             crop.data.attrs[Key.img.obs] = obs
    817             crop = crop._maybe_as_array(as_array, squeeze=squeeze, lazy=False)

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/im/_container.py in crop_center(self, y, x, radius, **kwargs)
    647         """
    648         y, x = self._convert_to_pixel_space((y, x))
--> 649         _assert_in_range(y, 0, self.shape[0], name="height")
    650         _assert_in_range(x, 0, self.shape[1], name="width")
    651 

/data/BCI-CRC/nasrine/anaconda/envs/scanpy/lib/python3.8/site-packages/squidpy/gr/_utils.py in _assert_in_range(value, minn, maxx, name)
    186 def _assert_in_range(value: float, minn: float, maxx: float, *, name: str) -> None:
    187     if not (minn <= value <= maxx):
--> 188         raise ValueError(f"Expected `{name}` to be in interval `[{minn}, {maxx}]`, found `{value}`.")
    189 
    190 

ValueError: Expected `height` to be in interval `[0, 2000]`, found `9761`.

Nasrine26 avatar Feb 04 '22 08:02 Nasrine26

Hi @Nasrine26

I was having the same issue and the solution here (set scale factors) worked for me: https://github.com/theislab/squidpy/issues/399

dst53 avatar Feb 24 '22 15:02 dst53

Hi, I had the same issue as above "ValueError: Expected height to be in interval [0, 2000], found 21430". I tried adding a scale factor as mentioned in #399 but it does not solve my problem.

My code: `scale = 1 img = sq.im.ImageContainer("image_path", scale=scale) feature_name = f"features_summary_scale{scale}"

sq.im.calculate_image_features( adata, img, features="summary", key_added=feature_name, n_jobs=4, scale=scale )`

DaisyCuttie avatar Mar 23 '22 04:03 DaisyCuttie

hi @Charlottehero ,

the scaling factor should be in adata.uns["spatial"]["V1_Adult_Mouse_Brain"]["scalefactors"], You should choose the one you are interested in with respect to your image resolution. May I kjnow what the file name in image_path in the image container you are pointing to? would be useful for debugging

giovp avatar Mar 23 '22 08:03 giovp

Hi @dst53,

the scale (set scale factors) worked for me as well. Many thanks!

Nasrine26 avatar Mar 23 '22 11:03 Nasrine26

Hi @giovp,

I had a question concerning extracting segmentation features.

I'm using the full H&E image fromadata.uns['spatial'][library_id]['images']['hires'] to infer segmentation features.

More precisely, I perform the following steps:

  1. smooth it using squidpy.im.process()
  2. squidpy.im.segment() with method = 'watershed' to do the segmentation, use the channel 0 as it is supposed to contain most of the nuclei info for H&E stain
  3. calculate segmentation features using:
sq.im.calculate_image_features(
    adata_vis,
    my_image,
    layer='image',
    features="segmentation",
    key_added="segmentation_features",
    features_kwargs={
        "segmentation": {
            "label_layer": "segmented_watershed",
            "props": ["label", "area", "mean_intensity"],
            "channels": [1, 2],
        }
    },
    mask_circle=True,
)

I then look at the number of nuclei per spot adata_vis.obsm["segmentation_features"]['segmentation_label'].describe()

  1. How can I be sure the segmentation is well performed and trust these values?
  2. Also is it ok if I use the image that's stored in adata.uns['spatial'][library_id]['images']['hires']?
  3. Finally, Are the steps are perform ok or would you go about it another way?

Many thanks, I am very new to segmentation!

Nasrine26 avatar Mar 28 '22 13:03 Nasrine26

Thanks @giovp. I figured out the scale factor value from your reply, but now I am encountering a resolution issue with the image. I used the sq.im.ImageContainer() to load in the hires_image I got from spatial results, but the resulting segmentation quality is not as good as what is shown in the tutorial here https://squidpy.readthedocs.io/en/stable/auto_tutorials/tutorial_visium_fluo.html. Am I going the right way?

DaisyCuttie avatar Mar 31 '22 18:03 DaisyCuttie

Hi @Nasrine26,

regarding your questions:

  1. I would suggest to look at the segmented image (stored as an additional layer in the ImageContainer) and do a visual inspectino of the results, see this tutorial
  2. You can perform the segmentation on any image, so using adata.uns['spatial'][library_id]['images']['hires'] is fine.
  3. I believe that the described steps are reasonable - most importantly the results should help your analysis. If they do, that is great!

MxMstrmn avatar Apr 07 '22 22:04 MxMstrmn

Hi @Charlottehero,

plase have a look at the previous post to evaluate segmentation quality. Bad results can be related to the data, do you think that the image quality might be an issue?

MxMstrmn avatar Apr 07 '22 22:04 MxMstrmn

closing due to inactivity, feel free to reopen

giovp avatar Oct 18 '22 12:10 giovp