elhuhdron / pylibczi

Python module utilizing libCZI for reading Zeiss CZI files.
GNU General Public License v3.0
9 stars 8 forks source link

Unable to read multiband czi file with 3 scenes #2

Closed dougwood closed 4 years ago

dougwood commented 4 years ago

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

heeler commented 4 years ago

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

dougwood commented 4 years ago

Hi Jamie,

I see that you were able to access the upload folder I created on our sharefile site. If by mosasiced you mean that the three scenes tile together to make a single image, then yes, it is, moasiaced. I was thinking it might be helpful to scan the same sample as a single scene, if that would help.

Thank you for looking into this.

Doug

On August 7, 2019 at 8:17 PM Jamie Sherman notifications@github.com wrote:

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

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub https://github.com/elhuhdron/pylibczi/issues/2?email_source=notifications&email_token=ADZ7K7XP6TZEZELGKIZABXDQDNQY3A5CNFSM4IJXIRGKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD32BWDA#issuecomment-519314188 , or mute the thread https://github.com/notifications/unsubscribe-auth/ADZ7K7URM4WDZCJUKNIZSKLQDNQY3ANCNFSM4IJXIRGA .
heeler commented 4 years ago

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

elhuhdron commented 4 years ago

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

dougwood commented 4 years ago

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

heeler commented 4 years ago

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

heeler commented 4 years ago

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?

dougwood commented 4 years ago

Hi Jamie, Yes, it looks like you have successfully loaded the first channel for all scenes. Here is a rendering of it in 20190618_CL001_HB01_Rescan_002  channel 0 'DAPI'

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

heeler commented 4 years ago

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

dougwood commented 4 years ago

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

heeler commented 4 years ago

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.

dougwood commented 4 years ago

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

heeler commented 4 years ago

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.

dougwood commented 4 years ago

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

heeler commented 4 years ago

Thanks, I'll try some stuff my end and hopefully have a better idea shortly. Sorry for the delay on this.

heeler commented 4 years ago

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/ .

elhuhdron commented 4 years ago

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.

dougwood commented 4 years ago

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

elhuhdron commented 4 years ago

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

dougwood commented 4 years ago

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 pylibczi error

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

elhuhdron commented 4 years ago

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.

dougwood commented 4 years ago

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.

heeler commented 4 years ago

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.

heeler commented 4 years ago

I was just looking at this code, are the offending image by any chance a BGR (BlueGreenRed) pixel type?

dougwood commented 4 years ago

No, they are 5 channel fluorescent images, not bright field. I have sent you and Paul a link to them in a separate message.

elhuhdron commented 4 years ago

I'm going to close this, as I think the aics fork has addressed theses issues.