Booritas / slideio

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

CZI driver switching channels? #13

Closed ValentinKoch closed 1 year ago

ValentinKoch commented 1 year ago

Hi, it seems to me as if the CZI driver is switching the RGB channels to BGR? Not sure if somethings wrong with my data or if its an issue of the driver. If i open my slides it with any visualization software such as QUPath the channels are not switched, but if loading with slideio they somehow are..

Booritas commented 1 year ago

Hello, thank you for your message. SlideIO does not switch channels. The library reads raster exactly as it is presented in the image without any transformation. I believe, it is important for image processing. Viewers, on other side, very oft apply visual settings for better visualization. Metadata of czi file contains recommendation for the visualization.

If you can share the file I can check it and try to understand why visualization is different.

Anyway, SlideIO allows you to switch channels if you want. Below is an example of switching first and the last channels. Reading image as it is:

img = scene.read_block(size=(500,0))

Reading with custom channel order:

img = scene.read_block(size=(500,0), channel_indices=[2,1,0])

If you have any doubts, czi normally supplies names to channels. You can access the names through the scene method get_channel_name:

slide = slideio.open_slide(path, 'CZI')
scene = slide.get_scene(0)
scene.get_channel_name(0)
> 'Brigh:1'

You can compare it with the channel order in the visualization software.

I hope it helps, Do not hesitate to ask any question, I'm happy to assist you. If you like the library, please consider giving a star to the repository. Best regards, Stanislav

ValentinKoch commented 1 year ago

my code:

slide = slideio.open_slide("/xxx.czi","CZI")
scene = slide.get_scene(0)
block = scene.read_block()
resized_img=Image.fromarray(block).resize((512,512))

check for channels:

scene.get_channel_name(0),scene.get_channel_name(1),scene.get_channel_name(2)
> ('Brigh:1', 'Brigh:2', 'Brigh:3')

seems okay, but when displaying resized_img the ordering of channels is wrong. so i change it:

b, g, r = resized_img.split()
img_rgb = Image.merge("RGB", (r, g, b))

and img_rgb has then the correct ordering of channels.. I can provide you with a sample file!

Booritas commented 1 year ago

Thank you for the code. I'll check it ASAP! Image would be very helpful. If you can post a download link here or send it to my email stanislav.melnikov@gmail.com, it would be perfect. Let me know if you have a problem with this approach then I will look for a place for uploading of the image. Best regards, Stanislav

ValentinKoch commented 1 year ago

Dear Stanislav, were you able to look into it already? Best Valentin

Booritas commented 1 year ago

Hi Valentin, thank you for the image. I can confirm that the channel order of the raster returned by the SlideIO is different from the image presentation in the QUPath. I'll check why this happens and report you soon (I would need 1-2 days). Best regards, Stanislav

ValentinKoch commented 1 year ago

Awesome thanks a lot for your help!

Booritas commented 1 year ago

Hi Valentin, I just did some investigations. First of all I checked if channel mixing is correct. I read color raster and separated channels from some region of the image you provided:

slide = slideio.open_slide(path, 'CZI')
scene = slide.get_scene(0)
block_rect = (85000,40000,1000,1000)
scene_raster = scene.read_block(block_rect)
channel1 = scene.read_block(block_rect,channel_indices=[0])
channel2 = scene.read_block(block_rect,channel_indices=[1])
channel3 = scene.read_block(block_rect,channel_indices=[2])
print(f'R={channel1[0][0]}, G={channel2[0][0]}, B={channel3[0][0]}, RGB={scene_raster[0][0]}')

The result is:

'R=110, G=79, B=183, RGB=[110  79 183]'

As you can see, the channel values are mixed correctly.

After this, I extracted slide metadata and wrote it in an XML file:

mtd = slide.raw_metadata
with open('metadata.xml', 'w') as f:
    f.write(mtd)

The result is a large xml file. Here is some extract from the file:

  <Image>
    <AcquisitionDateAndTime>2021-11-25T14:27:53.424244Z</AcquisitionDateAndTime>
    <SizeC>1</SizeC>
    <ComponentBitCount>8</ComponentBitCount>
    <PixelType>Bgr24</PixelType>
    <SizeX>114979</SizeX>
    <SizeY>80069</SizeY>
    <SizeS>1</SizeS>
    <SizeM>702</SizeM>
    <OriginalCompressionMethod>JpgXr</OriginalCompressionMethod>
    <OriginalEncodingQuality>85</OriginalEncodingQuality>
    <AcquisitionDuration>159228.84410000002</AcquisitionDuration>
    <Dimensions>
      <Channels>
        <Channel Id="Channel:0" Name="Brigh">
          <Color>#00FFFFFF</Color>
          <Fluor>TL Brightfield</Fluor>
          <ExposureTime>200000</ExposureTime>

You can notice that the pixel type for the image is BGR <PixelType>Bgr24</PixelType> and color of the first channel is blue <Color>#00FFFFFF</Color>. It means that the saved image is BGR. Viewers use this information for proper visualization. SlideIO does not change channel order for sake of visualization. I believe, for image processing it is important to keep image as it is w/o any transformation.

If you want to reorder the channels, you can use 'channel_indices' parameter from read_block method.

I hope it helps. Thanks a lot for using the library. Please, do not hesitate to contact if you have any problems with the library or have any suggestions about new features you would need in your work. Best regards, Stanislav

ValentinKoch commented 1 year ago

Awesome thanks a lot for your help! From my side the issue can be closed.