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

Microns data cutout, EmptyVolumeException #544

Open
KoenKole opened this issue Jul 1, 2022 · 20 comments
Open

Microns data cutout, EmptyVolumeException #544

KoenKole opened this issue Jul 1, 2022 · 20 comments
Labels
question What is going on??? :thinking emoji:

Comments

@KoenKole
Copy link

KoenKole commented Jul 1, 2022

Hello!

Using CloudVolume I'm trying to get a cutout of some of the Microns EM data so I can further process it locally as a TIFF.
I'm using the code below which has worked previously on another EM dataset on Neurodata, but unfortunately I can't seem to get it to work for Microns and I get an EmptyVolumeException. I'm pretty new to EM data and command line so there might be something very obvious that I'm overlooking. Any idea what I might be doing wrong?

Many thanks in advance for your help!

Koen

======

from cloudvolume import CloudVolume^M
...: vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True)^M
...: cutout = vol[190205:190363, 144905:144991, 20058:20092]^M
...:
Decompressing: 0it [00:00, ?it/s]█████████████████████▌ | 1/2 [00:00<00:00, 4.48it/s]

EmptyVolumeException Traceback (most recent call last)
in
1 from cloudvolume import CloudVolume
2 vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True)
----> 3 cutout = vol[190205:190363, 144905:144991, 20058:20092]

~\anaconda3\lib\site-packages\cloudvolume\frontends\precomputed.py in getitem(self, slices)
526 requested_bbox = Bbox.from_slices(slices)
527
--> 528 img = self.download(requested_bbox, self.mip)
529 return img[::steps.x, ::steps.y, ::steps.z, channel_slice]
530

~\anaconda3\lib\site-packages\cloudvolume\frontends\precomputed.py in download(self, bbox, mip, parallel, segids, preserve_zeros, agglomerate, timestamp, stop_layer, renumber, coord_resolution)
706 parallel = self.parallel
707
--> 708 tup = self.image.download(
709 bbox.astype(np.int64), mip, parallel=parallel, renumber=bool(renumber)
710 )

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image_init_.py in download(self, bbox, mip, parallel, location, retain, use_shared_memory, use_file, order, renumber)
154 scale = self.meta.scale(mip)
155 spec = sharding.ShardingSpecification.from_dict(scale['sharding'])
--> 156 return rx.download_sharded(
157 bbox, mip,
158 self.meta, self.cache, self.lru, spec,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in download_sharded(requested_bbox, mip, meta, cache, lru, spec, compress, progress, fill_missing, order, background_color)
90 for zcode, chunkdata in itertools.chain(io_chunkdata.items(), lru_chunkdata):
91 cutout_bbox = code_map[zcode]
---> 92 img3d = decode_fn(
93 meta, cutout_bbox,
94 chunkdata, fill_missing, mip,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in decode(meta, input_bbox, content, fill_missing, mip, background_color)
576 Returns: ndarray
577 """
--> 578 return _decode_helper(
579 chunks.decode,
580 meta, input_bbox,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in _decode_helper(fn, meta, input_bbox, content, fill_missing, mip, background_color)
627 content = b''
628 else:
--> 629 raise EmptyVolumeException(input_bbox)
630
0it [00:00, ?it/s]list(bbox.
size3()) + [ meta.num_channels ]

EmptyVolumeException: Bbox([190225, 144868, 20034],[190353, 144996, 20066], dtype=int32)

@ceesem
Copy link
Collaborator

ceesem commented Jul 1, 2022

While the default visualization in neuroglancer is at a [4,4,40] nm/voxel resolution, the actual MIP-0 image data is in [8,8,40] nm/voxel, so you need to adjust your bounding box accordingly. Alternatively, if you use the vol.download function instead of the slicing approach, you can actually set the coord_resolution your bounding box is in explicitly, and then let cloudvolume sort out the right conversions for you.

@KoenKole
Copy link
Author

KoenKole commented Jul 1, 2022

While the default visualization in neuroglancer is at a [4,4,40] nm/voxel resolution, the actual MIP-0 image data is in [8,8,40] nm/voxel, so you need to adjust your bounding box accordingly. Alternatively, if you use the vol.download function instead of the slicing approach, you can actually set the coord_resolution your bounding box is in explicitly, and then let cloudvolume sort out the right conversions for you.

Thanks for your help!
The vol.download function seems a lot easier, I'd like to try that. Unfortunately I'm having trouble finding documentation on how to use it together with the coord_resolution. Could you point me to the documentation or give an example on how to use it?

@ceesem
Copy link
Collaborator

ceesem commented Jul 1, 2022

I think that at the moment you have to either look at the docstring or the code itself:

@KoenKole
Copy link
Author

KoenKole commented Jul 1, 2022

I think that at the moment you have to either look at the docstring or the code itself:

Thanks! But it seems like this is beyond my skill, it's unclear to me how to use vol.download or use the coord_resolution argument.

Although less straightforward at first glance, maybe converting the nm/voxel size in my original command might work sooner. But I guess it's also not just a matter of multiplying the x/y values by 2, because then it tells me I'm outside the inclusive range. Could you give some guidance as to how to adjust the bounding box? Sorry for all the questions...

@william-silversmith
Copy link
Contributor

william-silversmith commented Jul 1, 2022 via email

@KoenKole
Copy link
Author

KoenKole commented Jul 1, 2022

Thanks Will!

Wasn't sure where to add it, so I tried two ways but with no success.

I tried:

from cloudvolume import CloudVolume^M
...: vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True)^M
...: cutout = vol[380410:380726, 289810:289982, 20058:20092], coord_resolution=[4,4,40]^M
...:

ValueError Traceback (most recent call last)
in
1 from cloudvolume import CloudVolume
2 vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True)
----> 3 cutout = vol[380410:380726, 289810:289982, 20058:20092], coord_resolution=[4,4,40]

ValueError: too many values to unpack (expected 2)

and:

from cloudvolume import CloudVolume^M
...: vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True, coord_resolut
...: ion=[4,4,40])^M
...:

TypeError Traceback (most recent call last)
in
1 from cloudvolume import CloudVolume
----> 2 vol = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True, coord_resolution=[4,4,40])

TypeError: new() got an unexpected keyword argument 'coord_resolution'

====

Maybe I'm trying to use the argument in the wrong line? The last error (unexpected keyword) also made me think that maybe I'm using an older version where this function isn't available yet, but I tried reinstalling Cloudvolume with no change.

@william-silversmith
Copy link
Contributor

william-silversmith commented Jul 1, 2022 via email

@KoenKole
Copy link
Author

KoenKole commented Jul 1, 2022

I tried, but still no luck unfortunately:

In [1]: from cloudvolume import CloudVolume^M
...: import numpy as np^M
...: ^M
...: cv = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg",^M
...: mip=0, use_https=True)^M
...: ^M
...: bounds = np.s_[380410:380726, 289810:289982, 20058:20092]^M
...: img = cv.download(bounds, mip=1, coord_resolution=[4,4,40])^M
...:
Decompressing: 0it [00:00, ?it/s]█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:00<00:00, 3.75it/s]

EmptyVolumeException Traceback (most recent call last)
in
6
7 bounds = np.s_[380410:380726, 289810:289982, 20058:20092]
----> 8 img = cv.download(bounds, mip=1, coord_resolution=[4,4,40])

~\anaconda3\lib\site-packages\cloudvolume\frontends\precomputed.py in download(self, bbox, mip, parallel, segids, preserve_zeros, agglomerate, timestamp, stop_layer, renumber, coord_resolution)
706 parallel = self.parallel
707
--> 708 tup = self.image.download(
709 bbox.astype(np.int64), mip, parallel=parallel, renumber=bool(renumber)
710 )

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image_init_.py in download(self, bbox, mip, parallel, location, retain, use_shared_memory, use_file, order, renumber)
154 scale = self.meta.scale(mip)
155 spec = sharding.ShardingSpecification.from_dict(scale['sharding'])
--> 156 return rx.download_sharded(
157 bbox, mip,
158 self.meta, self.cache, self.lru, spec,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in download_sharded(requested_bbox, mip, meta, cache, lru, spec, compress, progress, fill_missing, order, background_color)
90 for zcode, chunkdata in itertools.chain(io_chunkdata.items(), lru_chunkdata):
91 cutout_bbox = code_map[zcode]
---> 92 img3d = decode_fn(
93 meta, cutout_bbox,
94 chunkdata, fill_missing, mip,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in decode(meta, input_bbox, content, fill_missing, mip, background_color)
576 Returns: ndarray
577 """
--> 578 return _decode_helper(
579 chunks.decode,
580 meta, input_bbox,

~\anaconda3\lib\site-packages\cloudvolume\datasource\precomputed\image\rx.py in _decode_helper(fn, meta, input_bbox, content, fill_missing, mip, background_color)
627 content = b''
628 else:
--> 629 raise EmptyVolumeException(input_bbox)
630
631 shape = list(bbox.size3()) + [ meta.num_channels ]

EmptyVolumeException: Bbox([94984, 72370, 20034],[95112, 72498, 20066], dtype=int32)

@william-silversmith
Copy link
Contributor

william-silversmith commented Jul 1, 2022 via email

@william-silversmith
Copy link
Contributor

Hi Koen,

I finally have my laptop and internet so I took a look. It seems this copy of minnie65 does not have a fake 4nm base resolution, so if you look at the segmentation in Neuroglancer you can read the coordinates right off.

The largest X dimension is 218808, so the coordinates you provided are far too large. The coordinates you should provide to CloudVolume are in units of voxels, not physical units, so you'll need to divide by the resolution at minimum to be able to work with it.

@KoenKole
Copy link
Author

KoenKole commented Jul 4, 2022

Hi William,

Many thanks for taking a look, I very much appreciate your help!
I'm slightly confused, because the coordinates I'm using as far as I can tell are within the source dimensions.

These are the dimensions I see (and the ones I'm trying to get):
X: 26385 to 218809 (190205 to 190363)
Y: 30308 to 161359 (144905 to 144991)
Z: 14850 to 27858 (20058 to 20092)

So therefore I was assuming I was in the right range.
It occurred to my that I hadn't tried your previous command with those coordinates, so I tried and it does seem to get me a step further. If I use:

from cloudvolume import CloudVolume
import numpy as np
cv = CloudVolume("precomputed://gs://iarpa_microns/minnie/minnie65/seg", mip=0, use_https=True)
bounds = np.s_[190205:190363, 144905:144991, 20058:20092]
img = cv.download(bounds, mip=1, coord_resolution=[4,4,40])

Decompressing: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 2/2 [00:00<?, ?it/s]

and then

import tifffile
tifffile.imwrite(r"[path]\data.tiff", data=np.transpose(img))

I do get a TIFF file with specific dimensions that seem to correspond to the ones I used in the command, but all the images are black. I tried dividing the coordinates, but then I get back to the same errors as before (EmptyVolumeException).

@ceesem
Copy link
Collaborator

ceesem commented Jul 4, 2022

I tend to find that the easiest way to work with bounding boxes is the cloudvolume Bbox class. In this case, for example, what I would have done is:

coords = [[190205, 144905, 20058], [190363, 144991, 20090]]
bbox = cloudvolume.Bbox(coords[0], coords[1])
img = cv.download(bbox, coord_resolution=[4,4,40])

This downloads a perfectly good cutout for me. I suspect that the reason you're only seeing blacks is that the tiff is being interpreted as 16 bit, when it should be 8 bit (0-255).

One other note: are you intending to download the downsampled 16,16,40 imagery? That is what the mip=1 argument is doing in the download function, because mip 0 is already 8,8,40 (you can check this with cv.mip_resolution(0).

The result:
image

@KoenKole
Copy link
Author

KoenKole commented Jul 4, 2022

Thanks! Then maybe I'm closer than I thought :)
If I try your code I get the same result as I had before (a black TIF file), so the issue has to be on that end. It looks like you open the files in Python whereas I use FIJI, which indeed recognizes the file as 32-bit. I'll have a look around and see if I can find a way to save/open the file as 8-bit.

@ceesem
Copy link
Collaborator

ceesem commented Jul 4, 2022

Scanning the examples for tifffile, it looks like it inherits the bit size from the dtype of the numpy array. Try setting the dtype of the downloaded array to an 8 bit unsigned integer when you pass it to the imwrite: img.astype('uint8').

@william-silversmith william-silversmith added the question What is going on??? :thinking emoji: label Jul 4, 2022
@KoenKole
Copy link
Author

KoenKole commented Jul 5, 2022

Thanks for that suggestion! Doing that seems to help, but it doesn't look quite right yet:

image

Do you think this has to do with the download or the conversion to TIFF?

@ceesem
Copy link
Collaborator

ceesem commented Jul 5, 2022

Oh, I see, you're downloading the segmentation. This looks correct for that. Segmentation data has the 64-bit object id in each voxel of the downloaded array. If you want to be doing that (as opposed to imagery), then you also have to convert the int64 segment ids to random colors for visualization. I recommend using Will's fastremap package to convert them to small integers and then make a lookup table of colors using any color palette package. I have an example of doing this in a package I made a while ago called ImageryClient, but it might not work right now with recent cloudvolume versions — I need to do some work to bring it up to date with a lot of useful changes to cloudvolume in the last year or so.

@KoenKole
Copy link
Author

KoenKole commented Jul 5, 2022

Ah, that's what we're looking at! I didn't realize I was downloading from the segmentation channel, so I changed the source for the download and: success!

image

Many thanks to the both of you for helping me out with this! Hopefully this thread will be useful for others too :)

@william-silversmith
Copy link
Contributor

Glad that worked for you Koen! re: coloring segmentation, I recently found this interesting library that uses fastremap under the hood. Might be useful at some point! You can also colorize segmentation with matplotlib color maps too.

https://github.com/kevinjohncutler/ncolor/

@william-silversmith
Copy link
Contributor

william-silversmith commented Oct 11, 2022 via email

@KoenKole
Copy link
Author

KoenKole commented Oct 11, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question What is going on??? :thinking emoji:
Projects
None yet
Development

No branches or pull requests

3 participants