"free(): invalid size" crash trying to call CziFile.read_mosaic()
markemus opened this issue · 22 comments
I'm trying to read a mosaic czi file but it crashes consistently when I call img.read_mosaic(). img.read_image() works, but returns a stack of (overlapping?) mosaic tiles so I would prefer to get read_mosaic working.
import aicspylibczi as acz
...:
...: import numpy as np
...: import matplotlib.pyplot as plt
...:
...:
...: path = "/home/markemus/data/dev/Zeiss/2020_11_22__17_01__0165.czi"
...: img = acz.CziFile(path)
...: print(img.dims)
...: print(img.dims_shape())
...: y = img.read_mosaic(C=0)
...:
results:
SCMYX
[{'X': (0, 1600), 'Y': (0, 1200), 'C': (0, 1), 'M': (0, 2203), 'S': (0, 1)}]
free(): invalid size
I tried specifying S=0, but the program told me that S is not used for mosaic images.
I tried again reading only a subregion:
y = img.read_mosaic(region=(100,100,100,100), C=0)
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py", line 2882, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-6-ef2c2c78f23d>", line 1, in <module>
y = img.read_mosaic(region=(100,100,100,100), C=0)
File "/home/markemus/.local/lib/python3.6/site-packages/aicspylibczi/CziFile.py", line 458, in read_mosaic
img = self.reader.read_mosaic(plane_constraints, scale_factor, region)
_aicspylibczi.PylibCZI_RegionSelectionException: Requirement violated requested region is not a subset of the defined image!
(100,100,100,100) ⊄ (-162802,9720,93906,55354)
Requested region not in image!
This looks like an integer overflow problem? I searched previous issues but couldn't find anyone who had this before. Is there a bug or am I doing something incorrect?
Is there any chance you can share the file you are trying to read solely for the purpose of debugging?
jamies@alleninstitute.org
So I just did a few local sanity checks with a mosaic file I have.
The output
SCMYX
[{'X': (0, 1600), 'Y': (0, 1200), 'C': (0, 1), 'M': (0, 2203), 'S': (0, 1)}]
suggests that dims
and dims_shape()
are working correctly.
The free(): invalid size
I have not seen before but it could be you're exhausting the local memory available.
If that's the case then you are on the right track:
y = img.read_mosaic(region=(100,100,100,100), C=0)
the output line (100,100,100,100) ⊄ (-162802,9720,93906,55354)
is trying to tell you what's wrong.
The coordinate system is from the file itself and the region box is defined by (x0, y0, width, height)
The origin for the image is (-162802, 9720) with width=93906, h=55354.
If you would try:
y = img.read_mosaic(region=(-162800,9800,100,100), C=0)
The other thing to try would be
y = img.read_mosaic(C=0, scale_factor=0.05)
@heeler Thanks, that got me further. I believe you're correct about it running out of memory. However I ran into another issue.
I changed it to:
bbox = img.scene_bounding_box()
y = img.read_mosaic(region=(bbox[0],bbox[1],30000,30000), C=0, scale_factor=.1)
plt.imshow(y[0], cmap="gray")
plt.show()
The resulting image looks like a bunch of tiles overlaid on each other.
I exported to tiff using bioformat's bfconvert and I can confirm that in the exported tiff it doesn't look like that. Any advice?
So the code for stitching together the mosaic files is from Zeiss, specifically libCZI. My understanding is that Mosaic files can be acquired in various ways with gaps between the image acquisitions and imaging settings can be changed across the image. That may be what you're seeing but it's hard for me to know. You can use read_image
will give you the (img(np.ndarray), dict of dims). That will have an M dimension which is an index for the tiles in the plane (it's the m_index).
-
how do you expect the image to appear? Can you share images of what you expect vs what you're getting? I'm not sure I can fix it but I'll have a look.
-
what is the
pixel_type
of the image? -
when I open the test file in the repo
aicspylibczi/tests/resources/mosaic_test.czi
it seems to render correctly. Does that work in your environment? Snapshot below.
@markemus Can you share the image file with me that is causing this or was this resolved?
Also, could you check the version you have installed? I reimplemented the core memory management somewhere after 2.6 and there were bugs that crept in. If you upgrade to 2.8 and it still has this problem it would be incredibly helpful to have this file to debug with. Thanks.
@heeler Unfortunately I can't share the file- it's proprietary data and we don't currently have a way to anonymize czis. The version I was using was 2.7.7. I haven't had a chance to test another file, but I will try to do so and report back- feel free to remind me.
@markemus Thanks for letting me know. Details wise
- what's the pixel type?
- what does dims_shape() return?
I doubt upgrading to 2.8.0 will fix it but it might be worth trying.
If you are able to create a file that you can share I would really appreciate it. If you don't have time to create a file if you could explain acquisition settings I can ask our microscopy team to attempt to reproduce it for me.
Thanks
Any updates on this? I have the same issues as reported above.
Hey @rg314 can you answer the above questions:
what's the pixel type?
what does dims_shape() return?
It may be that your machine simply doesn't have enough memory to fit the whole mosaic in memory.
And re above, we dont have any test data ourselves to work on the issue. We cant debug something we cant reproduce. Can you share your file somehow?
Hey @JacksonMaxfield
Pixel type:
czi.pixel_type
'gray16'
Shape:
czi = CziFile(pth_fl)
czi.get_dims_shape()
[{'X': (...), 'Y': (...), 'C': (...), 'M': (...), 'S': (...)}, {'X': (...), 'Y': (...), 'C': (...), 'M': (...), 'S': (...)}]
special variables
function variables
0:{'X': (0, 1920), 'Y': (0, 2040), 'C': (0, 5), 'M': (0, 308), 'S': (0, 1)}
1:{'X': (0, 1920), 'Y': (0, 2040), 'C': (0, 5), 'M': (0, 324), 'S': (1, 2)}
len():2
The following code works
SCALE_FACTOR=0.1
czi.read_mosaic(C=0, scale_factor=SCALE_FACTOR)
In terms of memory I think things are fine as I can get the image into an np.array and manipulate given I use the scale_factor
arg. But FYI
(base) ryan@ryan:~$ grep MemTotal /proc/meminfo
MemTotal: 65757720 kB
If I run:
czi.read_mosaic(C=0, scale_factor=0.1, region=(0,0,1000,1000))
Then I get the following error
_aicspylibczi.PylibCZI_RegionSelectionException: Requirement violated requested region is not a subset of the defined image!
(0,0,1000,1000) ⊄ (-138240,16503,79744,44309)
Requested region not in image
Running the following code works fine.
czi.read_mosaic(C=0, scale_factor=0.1, region=(-138240,16503,79744,44309))
When I try czi.read_mosaic(C=0, scale_factor=0.1, region=(-138240-10000,16503,79744,44309))
I get the same error as before. However, ff I comment out the following exception and rebuild it works
aicspylibczi/_aicspylibczi/Reader.cpp
Line 438 in 96110fd
However, I have to calculate the pos from x0=-138240,y0=16503
which is strange. Not sure why the image is indexed in this way.
Let me know if this help. I will need to check with client if I can send over an example image.
Thanks for all the info!
Hmmm. I think it may be indexed by the overall stage position? But that is a good question.
cc @toloudis any ideas?
Cheers @JacksonMaxfield that was also my guess ;)
I'm rusty on this but if I remember correctly it's the format that Zeiss's libczi takes. It could possibly translate into a more sensible system but I was hesitant to depart from what Zeiss used and in their system (-138240,16503) is the origin of the image.
Having any image to repro with would help. I'm not sure what's going on with these coordinates or how a user would know what coordinates to use. I'm prepared to do a deep dive when we can repro.
@toloudis, the documentation get_mosaic_bounding_box()
should give you the origin and the size of the mosaic so you know where to start from. I can't comment on the logic behind Zeiss's origin. I do wonder what Zen does.
Okay, I'm going to get the client in on the thread. I’m sure we can get something sorted.
Hey! I have a czi mosaic that shows the error and that I'm happy to share :)
It's 2.77GB, though... If that's ok, I can put it on Zenodo for example.
Would that work?
print(dimensions)
print(czi.dims)
print(czi.is_mosaic())
print(czi.pixel_type)
[{'A': (0, 3), 'X': (0, 1600), 'Y': (0, 1200), 'C': (0, 1), 'M': (0, 27492), 'S': (0, 1), 'B': (0, 1)}]
BSCMYXA
True
bgr24
Wow, I completely forgot about this issue, so sorry! As a backup for @r03ert0 I will try to find an image I can send you as well. Roberto, do not depend on me, clearly I am unreliable. Let's get these people some examples.
Hi @r03ert0 If you can share the file on Zenodo I'll have a look and see if I can figure out what's going wrong.
Thanks for this.
here's the link:
https://zenodo.org/record/6637864
loading the whole image doesn't work, but loading subregions does:
from matplotlib import pyplot as plt
from aicspylibczi import CziFile
from pathlib import Path
pth = Path("ferret-slices-mosaic-encoding.czi")
czi = CziFile(pth)
d = czi.get_dims_shape()
bbox = czi.get_mosaic_bounding_box()
plt.figure(figsize=(20,15))
for row in range(0, 5):
for col in range(0, 5):
x = bbox.x + int(col*bbox.w/5)
y = bbox.y + int(row*bbox.h/5)
w = int(bbox.w/5)-1000 # -1000 just to make sure the region is well inside...
h = int(bbox.h/5)-1000 # ... it doesn't really work, because the last tile throws an error anyway
img = czi.read_mosaic(
C=0,
scale_factor=1/8,
region=(x, y, w, h)
)
plt.subplot(5, 5, row*5 + col + 1)
plt.imshow(img[0,:,:,:])
The result is this (the last tile throws an error):
What I would like to do is to convert the image to bigtiff, or to deepzoom (dzi) format.
thank you for your help!