Booritas / slideio

BSD 3-Clause "New" or "Revised" License
49 stars 2 forks source link

read_block throws out of bounds exception even when rectangle is in bounds #16

Closed jameshball closed 1 year ago

jameshball commented 1 year ago

Hi,

I've been facing some issues when using the slideio python library, particularly with the read_block function.

First an explanation of what I'm trying to achieve (can be skipped but as an extra reference for clarity):

I am trying to read blocks of 40000x40000 (as determined by MAG_LEVEL_SIZES and self.magnification_level) from SVS files that vary in size significantly.

Many images are smaller than 40000 pixels in one dimension or both, so I crop the width and height and change the x and y coordinates if necessary.

In short, I am trying to take a center crop of an image, without stretching or rescaling

I then want to rescale the image to fit into a 1024x1024 image (determined by self.patch_size) without scaling it up or down relative to differently sized images. This means if there is a 10000x10000 image, then the resulting patch should be 256x256 since 10000 is 4x less than the desired crop of 40000 and so 256 is 4x less than the desired crop of 1024.

        slide = slideio.open_slide(self.svs_dir + self.train_slide_ids[slide_index] + ".svs", "SVS").get_scene(0)
        width, height = slide.size

        center_x = width // 2
        center_y = height // 2
        zoomed_size = MAG_LEVEL_SIZES[self.magnification_level]
        x = center_x - zoomed_size // 2
        y = center_y - zoomed_size // 2

        cropped_x = 0 if x < 0 else x
        cropped_width = zoomed_size + 2 * x if x < 0 else zoomed_size

        cropped_y = 0 if y < 0 else y
        cropped_height = zoomed_size + 2 * y if y < 0 else zoomed_size

        patch_width = int(cropped_width * (self.patch_size / zoomed_size))
        patch_height = int(cropped_height * (self.patch_size / zoomed_size))

        cropped_patch = slide.read_block((cropped_x, cropped_y, cropped_width, cropped_height), size=(patch_width, patch_height))

The important line of code here is:

cropped_patch = slide.read_block((cropped_x, cropped_y, cropped_width, cropped_height), size=(patch_width, patch_height))

When I run this, it works on almost all SVS files, but there are a few that throw the following error on the read_block line:

  File "venv/lib/python3.9/site-packages/slideio/py_slideio.py", line 142, in read_block
    return self.scene.read_block(rect, size, channel_indices, slices, frames)
RuntimeError: OpenCV(4.1.1) data/opencv/4.1.1/slideio/stable/build/d2d7c166445ab3854d53f31fe8dffbc378a29414/source_subfolder/modules/core/src/matrix.cpp:465: error: (-215:Assertion failed) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function 'Mat'

(the opencv assertion is here https://github.com/npinto/opencv/blob/42f7329c788bf2eb60b2c1de2ed8efb91ae84cde/modules/core/src/matrix.cpp#L321)

This would seem to indicate a problem with the rectangle coordinates and width/height I passed in.

The dimension of the SVS file this fails for is 52188x37393 and below are the values I used for cropped_x, cropped_y, cropped_width, cropped_height, patch_width, and patch_height, and whether the error was thrown or not.

cropped_x cropped_y cropped_width cropped_height patch_width patch_height error?
6094 0 40000 37392 1024 957 yes
6094 0 39999 37391 1024 957 yes
6094 0 39997 37392 1024 957 yes
6094 0 40000 37392 1024 1024 yes
6094 0 40000 37392 1000 1000 yes
6094 0 40000 37392 1 1 yes
6094 0 40000 37392 0 0 no
6094 0 39996 37392 1024 957 no
6094 0 39995 37392 1024 957 no
6094 0 39990 37382 1024 957 no
6094 0 1000 1000 1024 957 no

The first row in the table above are the values that I actually want to run this with, the rest are just me testing whether it works or not.

I expected this to work for every single one of the entries in the table above, and have no idea why it suddenly starts working when cropped_width < 39997 even though 6094 + 40000 < 52188. I also thought that the size parameter (i.e. patch_width/height) should have no impact on whether this fails, but clearly when size=(0,0) this works fine.

I've been trying to figure this out for the last few days so any help at all would be super appreciated!

Thanks, James

Booritas commented 1 year ago

Hello James, thanks a lot for the message. I tried to reproduce the problem, but had no success. Do you use the latest (2.0.8) version? If not, please upgrade. I recently made a few fixes that may solve the problem. Should the problem persist, please share with me the following information about the problematic image:

If possible, please share the image with us, as it would greatly assist us in reproducing and fixing the problem. However, this may not be necessary in this case. Best regards, Stanislav

jameshball commented 1 year ago

Thanks for the quick reply - will try the latest version tomorrow and get back to you asap with the extra info if it doesn't work!

jameshball commented 1 year ago

Doh! I was on 1.0.4, but I have just upgraded to 2.0.8 and it seems to be working fine now. Thanks for your help - maybe this is worth noting somewhere as although in hindsight it's obvious I should have tried updating, it would have been much easier to solve if it was flagged somewhere as a bug in a previous version :)

Thanks so much for your help!