Unable to read multiband czi file with 3 scenes
dougwood opened this issue · 26 comments
Hi Paul,
First thank you for this effort, it looks very promising and very useful!
Unfortunately, I am having trouble with reading a file that has 3 scenes. Image size: 73638x44269, 5 channels, 16 bit pixel depth. I am using pylibczi v1.1.1 and Python 3.7
I can create a pylibczi.CziFile object with it and successfully read the metadata with that object's read_meta() method. But when I try use read_image() I get back an array that has a shape with only two dimensions (height, width) and 16 bit dtype. I was expecting an array with shape (height, width, 5). If I write the image out, it appears to be the first channel only and there are some missing tiles (i.e. the merging of the 3 scenes is almost correct, but there are errors).
I will be happy to provide and example image but it is way too big to attach (I can get it to you by other means).
Again, thank you for this great contribution!
-Doug
Hi Doug,
I've started working on contributing a pull request back to Paul's repo. Hopefully, neither you nor Paul mind me butting in. Is your file purely multiscene or is it a multiscene mosaic file? If you're able to share the file (google drive / dropbox / ...) I'd be happy to take a crack at opening it.
Cheers,
--Jamie
Hi Doug,
It's definitely a multi-scene mosaic file, I wrote used the EnumerateSublocks function to print out the descriptor info and the image as a PNG. The PNGs look reasonable. The subblock info I print looks like
1 C1S0B0 Rect = (21884,19201,950,650) mIndex = 0 physicalSize = (950,650)
2 C0S0B0 Rect = (21884,19201,950,650) mIndex = 0 physicalSize = (950,650)
3 C1S0B0 Rect = (22739,19201,950,650) mIndex = 1 physicalSize = (950,650)
4 C0S0B0 Rect = (22739,19201,950,650) mIndex = 1 physicalSize = (950,650)
5 C1S0B0 Rect = (23594,19201,950,650) mIndex = 2 physicalSize = (950,650)
6 C0S0B0 Rect = (23594,19201,950,650) mIndex = 2 physicalSize = (950,650)
7 C1S0B0 Rect = (24449,19201,950,650) mIndex = 3 physicalSize = (950,650)
8 C0S0B0 Rect = (24449,19201,950,650) mIndex = 3 physicalSize = (950,650)
9 C1S0B0 Rect = (25304,19786,950,650) mIndex = 4 physicalSize = (950,650)
.
.
.
954 C0S8B0 Rect = (39328,28699,950,650) mIndex = 12 physicalSize = (950,650)
955 C1S8B0 Rect = (40183,28699,950,650) mIndex = 13 physicalSize = (950,650)
956 C0S8B0 Rect = (40183,28699,950,650) mIndex = 13 physicalSize = (950,650)
957 C1S8B0 Rect = (41038,28699,950,650) mIndex = 14 physicalSize = (950,650)
958 C0S8B0 Rect = (41038,28699,950,650) mIndex = 14 physicalSize = (950,650)
959 C1S8B0 Rect = (41893,28699,950,650) mIndex = 15 physicalSize = (950,650)
960 C0S8B0 Rect = (41893,28699,950,650) mIndex = 15 physicalSize = (950,650)
961 C1S8B0 Rect = (41893,29284,950,650) mIndex = 16 physicalSize = (950,650)
The mIndex show's it's a mosaic file. I'm working on these but they need a little more effort.
I'll update you as soon as I have something.
Cheers,
~Jamie
Hi guys,
I was also able to download the files, and I think it might be possible to load the data with a SingleChannel or MultiChannel tile accessor. Right now this method is a bit tied into the current scene support which is geared specifically to mSEM Zen. In addition to what Jamie is working on, I think a small change to make CziScene a bit more "generic" might allow us to read your multichannel data with multiple scenes. I'm a bit short on time at the moment, but I will try to work on this and see if I can get a proof-of-concept in another branch, then we can decide what changes to incorporate into a new release.
Cheers,
Paul
Hi Paul and Jamie,
Thank you for diving in to this! I was going to ask if it would be possible to read a single channel instead of all channels at once. This is really they way I would prefer to access these images and it would be a big saving in memory use, of course. Some of our images are pushing 100k on a side and have 5 16 bit channels so the whole thing is a very large numpy array.
If you would like to get a scan of the same slide but as a single scene, let me know.
Thanks again!
-Doug
I was finally able to download the file. I have a function that works for reading the file. I'm just writing the bridging code for the interface. I'm hoping to have a branch that can be tried out by end of day my time. I'm using the SingleChannelTileAccessor function in C++ and I'm just working on getting the parameters from python to C++ in a reasonably general way.
Cheers,
~Jamie
So before I go too far down the path does this look like Channel=1 of the czi file?
https://www.dropbox.com/s/ac5u76xdjdbw0zp/test1.tif?dl=0
it's scaled to 1/10th the size. The original image is too large to reasonably work with. Note how you save the file out / format etc plays a role in how it appears and I had to adjust the image a little to see what was going on.
If the file is correct, I think I have something that might work for Doug. I'm not sure it's mature enough to be merged into Paul's master branch but it should work for you for a 1 off.
How would be best to help you install it?
Hi Jamie,
Yes, it looks like you have successfully loaded the first channel for all scenes. Here is a rendering of it in
I would be happy to install and test it, but I do not have the development environment set up for this module. Do I need to get that working first or can I install the changes you have made in my python environment.
BTW you can get a copy of Zen to view these .czi files directly if you are interested. It can export single channel images for comparison.
https://www.zeiss.com/microscopy/us/products/microscope-software/zen-lite.html
Cheers and thanks!
Doug
Hi Doug,
What OS are you on? You have python installed, can pip install stuff? Do you have a C++11 or better compiler installed (gcc, clang, or ... )? If so it's fairly easy to build on your system. If not I can take a shot at building a 1 off binary for you and see if that works, no guarantees. The alternative is to wait till it's been through Pull request review and assuming it's ok with Paul merged into the project.
Thanks,
~Jamie
Hi Jamie,
Sorry--lots of other things going on right now==so I could not get back to this quickly. Thank you very much for working the multi-scene issue--I really appreciate it.
Part of the delay getting back to you was I updated some components and I now have my build system working. I followed the instructions on the bottom of https://github.com/elhuhdron/pylibczi and I've attached the output.
pylibczi build.txt
and it appears to be working. So let me know how I can try out your fix.
Best,
Doug
So the code is on my fork of the repo until we get it merged into the main repo.
To try it out go through the following steps:
git clone --recurse-submodules https://github.com/AllenCellModeling/pylibczi.git
cd pylibczi
git checkout feature/tiles
pip install -r requirements.txt
pip install -r dev-requirements.txt
python setup.py develop
pip install -e .
then example usage would be something along the lines of
from PIL import Image
from pylibczi import CziFile
czi = CziFile(<filename>)
im = czi.read_mosaic(scale_factor=0.1, C=1)
# on the line above you need to pull out the channels one by one currently
# you can specify dimensions with C=1, T=10, Z=5 as kwargs
img = Image.fromarray(im)
If you run into problems let me know and I'll try to help. It's still a bit green, I could probably put in better error handling and such but as long as you stick to pulling out single planes I think you'll be ok.
Hi Jamie,
Thank you for the build instructions. I ran them but during the build I see some warnings about DLL inconsistent DLL linkage. Perhaps I need to recompile libczi? Need to use a different compiler in the make? When i try to run a short test like the one you suggested, I cannot import pylibczi because the DLLs in _pylibczi will not load. Please see the attached...
pylibczi DLL Load failed.txt
Thank you!
-Doug
In the project folder try doing:
python setup.py clean
python setup.py develop
I've only worked on windows systems when I absolutely had to so I'm not as familiar. I'll try and have a teammate build it locally on windows. But try the clean
and rebuild approach and let me know how it goes.
Sorry, no joy.
In the pylibczi folder that contains the git local directory, I tried
python setup.py clean
this did report that it deleted a build directory, then I tried
python setup.py develop
The log still shows warnings (in yellow) like this
C:\dev\pylibczi\libCZI\Src\libCZI\libCZI_Utilities.cpp(53): warning C4273: 'libCZI::Utils::CharToDimension': inconsistent dll linkage [C:\dev\pylibczi\libCZI\build\Src\libCZI\libCZIStatic.vcxproj]
so I m not sure that it built correctly.
Finally I did a
pip install -e .
and then ran the test script and I still get
C:\dev\pylibczi>python C:\dev\pylibczi-testing\readmultisceneczi.py
Traceback (most recent call last):
File "C:\dev\pylibczi-testing\readmultisceneczi.py", line 4, in
czi = CziFile("D:\czi multiscene\20190807_RS013_MJM01_Doug_1_000.czi")
File "c:\dev\pylibczi\pylibczi\CziFile.py", line 72, in init
import _pylibczi
ImportError: DLL load failed: The specified module could not be found.
When I do a pip list I see it is trying to use the new build:
C:\dev\pylibczi>pip list
Package Version Location
cffi 1.12.3
cmake 3.14.4
cycler 0.10.0
czifile 2019.7.2
decorator 4.4.0
imagecodecs 2019.5.22
imageio 2.5.0
kiwisolver 1.1.0
lxml 4.3.4
matplotlib 3.1.1
networkx 2.3
numpy 1.16.4
opencv-python 4.1.0.25
pandas 0.24.2
Pillow 6.1.0
pip 19.2.1
pycparser 2.19
pylibczi 1.1.1 c:\dev\pylibczi
pyparsing 2.4.2
python-dateutil 2.8.0
pytz 2019.1
pyvips 2.1.8
PyWavelets 1.0.3
scikit-image 0.15.0
scipy 1.3.0
setuptools 40.8.0
six 1.12.0
tifffile 2019.7.2
Thanks, I'll try some stuff my end and hopefully have a better idea shortly. Sorry for the delay on this.
I got a coworker to try building on windows. The build is working in that it builds everything it needs, the python binary library (extension pyd) and the libCZI.dll library. Unfortunately, the libCZI.dll doesn't get moved into the same folder as the pyd file. With the pip install -e .
I think it looks in the project directory so if you copy the dll to the project folder (the pylibczi folder you git cloned) hopefully that will sort you out. If that's not the right place then maybe Paul has a suggestion. The dll should be in somewhere under libCZI/build/Src/libCZI/ .
I think I see the issue. python setup.py develop
as opposed to python setup.py install
creates a link in site-packages to the git folder, instead of copying the files, and so most likely python can not find the libCZI dll as Jamie pointed out. I'm not sure the develop target uses the data_files mechanism at all, which is the hack I created because I could not get the windows static build to work properly. Maybe can you try with a normal python setup.py install
? Usually I'd agree this is not ideal for testing purposes (I don't want you to corrupt up your python install), but because of this hack I think we might have to add another special case for copying the dll for the develop target (which I have not tested). Better yet if we could make the windows static build work, as it does on linux and mac...
I agree with Jamie that based on your build output it looks like it did build properly and should be at the location relative to the pylibczi git at libCZI\build\Src\libCZI\Release
. I think also if you copy the dll either to the top level of pylibczi git, (or the pylibczi subdirectory? not totally sure), then this might alternatively work.
Hi All,
I have been able to get back to this and I find that if I copy the libCZI.dll to c:/dev/pylibczi, which is my local git directory, then I am able to load the module. So thanks for that.
from PIL import Image
from pylibczi import CziFile
czi = CziFile("D:\czi multiscene\20190807_RS013_MJM01_Doug_1_000.czi")
print(czi)
im = czi.read_mosaic(scale_factor=0.1, C=1)
print(im)
img = Image.fromarray(im)
print(img)
produces this output:
C:\Users\Doug>python C:\dev\pylibczi-testing\readmultisceneczi.py
<pylibczi.CziFile.CziFile object at 0x0000028AA5B011D0>
[[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
...
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]
[0 0 0 ... 0 0 0]]
<PIL.Image.Image image mode=I;16 size=3143x3512 at 0x28AA5B01470>
I think could now incorporate this in my code to read multiscene files (yea!), but assuming I am successful with that, am I correct in assuming that if I want to run that code on another machine, I would need to repeat the steps:
git clone --recurse-submodules https://github.com/AllenCellModeling/pylibczi.git
cd pylibczi
git checkout feature/tiles
pip install -r requirements.txt
pip install -r dev-requirements.txt
python setup.py develop
pip install -e .
on that machine and copy the dll again? I assume I would need a compiler on that machine as well.
If the architectures on the two machines are the same, can I just copy folders to the new machine in order to install pylibczi built on this dev machine, or can I replace files in an existing pylibczi of for the current version. Sorry for all these questions--would be nice to have this in the regular pip installer!
Cheers and Thanks!
Doug
Hi Doug,
Yes, what you describe is correct for now. As you describe, you can theoretically just copy the dll to the other machine if the platform is identical, so that you do not need a compiler/build tools on that machine.
Then once we get around to creating a new release that incorporates Jamie's changes this will no longer be necessary, and the pip install method will work again.
Cheers,
Paul
Hi All,
Have been successful building Jamie's fork that supports multi-scene czi files, but I did encounter one issue using the Visual Studio 2019 compiler. It throws this error when running python setup.py develop:
_pylibczi_pylibczi.cpp(259): error C3499: a lambda that has been specified to have a void return type
Returning a value directly from the iterator on line 259 is not allowed, so as you can see, I commented out the offending line 259 and added the following line to set ret_value instead. I think this accomplishes the same thing (except that it will not return on the first occurrence).
I'm very interested in this multi-scene support being added to the regular release distribution as it is a multi-step process for me to get his working on each new system in our environment and having it part of the regular distribution would be very convenient.
Thank you again for your work on this!
-Doug
Hi Doug,
@heeler has refactored this part of the code entirely in a new version that will be the candidate for release. You can try it out if you want (using a version that should build with Visual Studio) with the feature/pybind11_build branch. The interface function that you want should still be read_mosaic.
OK. Thank you, I will try the new branch out.
Just a heads up that I have had a couple of examples where the mosaic is not put together correctly (repeated scenes). Some images work fine, but others do not. I will try the new branch and hopefully that will work better, otherwise I will post an example or two soon.
Thanks for trying this out. I just got building working for MSVC on the feature/pybind11 borrowing some stuff from the feature/pybind11_build branch and one thing that came to light was that on windows with anaconda you may need to set the PYTHONHOME variable. It's under the build section.
for the problem files if they continue not to work do you know if they contain non-pyramid0 data? Also when specifying the DIMS you need to lock in 1 channel. If the problem persists please let me know and any example data would be incredibly helpful.
I used a small tile of the image you provided initially. Firstly is this ok? Secondly, what's the appropriate attribution for the image.
I was just looking at this code, are the offending image by any chance a BGR (BlueGreenRed) pixel type?
No, they are 5 channel fluorescent images, not bright field. I have sent you and Paul a link to them in a separate message.