-
Notifications
You must be signed in to change notification settings - Fork 50
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
best compression settings for a wsi viewer #490
Comments
Hello @sinamcr7,
|
I've just realised you already have the entire image in memory as a numpy array, is that right? In which case you can simply do: image = pyvips.Image.new_from_array(big_numpy_array)
image = image.rot90()
image.tiffsave("some-filename.tif",
compression="jpeg",
Q=85,
tile=True,
tile_width=256,
tile_height=256,
pyramid=True) libvips and numpy will share the memory, so there will (I think!) be no copy and no extra memuse.
You could also use pyvips to save as OME-TIFF, though it'll be slower. Have you looked at QuPath? |
thanks for suggestions |
I'd stick to opencv if your code is working. pyvips ought to be able to make the pyramidal tiff directly from the numpy array with only a relatively small amount of extra memory. It depends how you are making the slide image. What corrections do you apply to frames from the microscope? How accurate is your stage? We'd need to get into a lot of detail before I could answer. |
ok thanks then I'll keep opencv part, I also have issue with np.pad, when my app reaches that it takes double of array memory and after several seconds it goes down to actual memory that it should take, is there any faster and low memory method to pad an array? |
Sorry, no, array resize needs to reallocate memory, and that means it must double. You could change to a tiled array. Cut your image into eg. 1024x1024 tiles and keep a meta-array of references to them. Now you can pad by just making a new column of tiles on the right and nulling the references to the old column of tiles on the left. |
... though a tiled array will make save difficult, of course. I've built several imaging systems like this. I've always done it in two stages: first, scan the camera over the slide and capture a set of frames to your storage. You can keep a low-res version in memory to show the user what the slide looks like during the scan. You can do geometric and radiometric correction at this stage. You examine the overlap areas and estimate the frame positions from the content. Second, have an "assembly" phase which reads the corrected tiles from your storage, merges them together using offsets computed in stage 1, possibly does some extra corrections for lighting consistency or colour, and saves as a pyramidal tiff. pyvips would be a reasonable choice for the assembly stage. Commercial slide scanners usually work in the same way, though some very high throughput systems will have a huge area of RAM for assembly rather than temporary files on your drive. |
well our algorithm needs that big array for some calculations, if we remove that part I don't know how I should compute exact locations and overlaps, also without that how can I show thumbnail and current frame to user? also I tried vips tiffsave with jpeg and q=85, q=100 and opencv imwrite, but there wasn't much difference in quality and it seems opencv imwrite has more quality, is that right or I did something wrong? here's code:
|
The scanners I've made have driven the stage in an approximate grid, then examined the overlaps to find a set of exact offsets. The set of offsets are an overdetermined linear system, so you can use eg. least mean square to find a set of frame positions which minimise overall positioning error. Friends have made system which calibrate the stepper motors instead, so they use a known target, then drive the stage over the field grabbing frames and refining a pair of XY positioning tables. This can work very well, but calibration takes a long time and you have to redo it fairly often as the threads in the stages wear. You can keep eg. a 10k x 10k image in memory plus the current frame to show the user, then generate the full 100k x 100k image during save. The settings mostly affect file size. I see:
The uncompressed TIFF will obviously be the best quality, but 6GB is far too large to be practical. Almost no users will want to use it. Q100 is 10x smaller, Q85 is 40x smaller. Aperio (the slide scanner that makes SVS format slides) is using Q85. |
oh you're talking about motorized scanners, I'm working with manual wsi scanning, user should be able to see area around FOV, FOV itself for focus check and a thumbnail of big image so user can see when its reaching edges and need to wait for pad, and if there is any errors he will use tools to clear wrong frames up to last correct frame, then start scanning again |
Ah OK, I've never tried with a manual stage, I agree that would need a different approach. Other friends have made interactive scanners using a manual stage, but I don't know what technical solution they used. Probably allocating the complete image in memory before starting. |
Hi @jcupitt -- looking back at release libvips version 8.15.1 I noticed that Q >=90 is not supported. But in the statement above by @sinamcr7 (copied here): image.tiffsave('wsi3.tiff', tile=True, compression='jpeg', pyramid=True, Q=100, tile_width=256, tile_height=256, properties=True) I'm curious if Q=100 will result in a false image? Much appreciated. |
8.15.1 fixed that bug, so Q100 should be fine. |
I used 8.15.3 with this image: |
I see:
I can view it in vd and eog: Here's the file it generated: www.rollthepotato.net/~john/output_image.tif It could be a bug in your image viewer -- try downloading and viewing the version I made. |
You are using the old vips7 syntax, which is deprecated. The new CLI syntax is:
You can also write:
The new interface is often faster, so it's worth changing over. It's easier to read as well, of course. |
I think v 8.15.3 can not take Q>=90 and generate the correct compressed image. |
Maybe QuPath on mac is using some system library that can't read these files? In any case, it's clearly a bug in your image viewer, the file is correct. |
But how come the python image viewers showed the same false colors as qupath |
I suppose it's also picking up a buggy library. Did you download the version of the image that I made? |
I'll try on my mac. |
Thanks. |
I tried in macos Preview and the image looks fine. Did you download the version of the image that I made? What do you see with that exact file in macos Preview? |
It displayed fine. |
Oh! I tried running the conversion on macos and it made a bad file. Perhaps this is a bug in homebrew libtiff? I'll investigate. |
Thank you. |
Could you confirm that the file I made also works in your QuPath? |
QuPath displayed the correct colors. |
I made a conda env and installed pyvips and ran the vips CLI and still see the same false colors with Q90 packages in environment at /usr/local/Caskroom/miniforge/base/envs/test:Name Version Build Channelaom 3.9.1 hf036a51_0 conda-forge |
with Q=89 it displayed the image correctly (but not the Q=90)using the conda env for pyvips. |
JPEG in TIFF compression needs the jpeg encoding colourspace set to match the enclosing tiff file. fixes regression in 8.15.3 from #3924 see libvips/pyvips#490 reproduce error with ``` vips copy x.jpg x.tif[compression=jpeg,Q=90,pyramid] ``` thanks nahilsobh
There was a bug introduced in 8.15.3 where the colourspace for jpeg tiles didn't match the photometric interpretation in the enclosing tiff. I've made a PR and credited you, the fix should be in 8.15.4. Thanks for reporting this dumb thing! |
No worries. I'm glad you found it. Thanks for all your efforts. |
* call jpeg_set_colorspace for jpeg in tiff JPEG in TIFF compression needs the jpeg encoding colourspace set to match the enclosing tiff file. fixes regression in 8.15.3 from #3924 see libvips/pyvips#490 reproduce error with ``` vips copy x.jpg x.tif[compression=jpeg,Q=90,pyramid] ``` thanks nahilsobh Co-authored-by: Kleis Auke Wolthuizen <[email protected]>
hi, I have a project to make wsi images using frames captured from a camera on microscope, my maker code uses opencv and numpy to store final array and update it with every frame
I have some questions:
1- when I'm saving final file what's best settings to save as pyramid and make it suitable to show in a viewer for analysis without quality loss?(I was saving with opencv imwrite function first but when I needed to rotate final image it takes double memory to make rotated image then saves it so I decided to do this with pyvips)
2-I wanted to know if there is any other method that can speedup this process? or reduce memory usage because right now I'm making a 50k x 50k * 3 array at start of program and just update it or pad it when i get to edges, and it takes 7.5gb memory and when pad is running it goes up to double memory but after pad is finished it goes down to real size.
3-is it normal when I try to open these images with windows photo viewer it takes several seconds to minutes to open and show it?
this is the code I'm using to rotate and save the tiff image saved with opencv imwrite:
The text was updated successfully, but these errors were encountered: