MathOnco / valis

Virtual Alignment of pathoLogy Image Series
https://valis.readthedocs.io/en/latest/
MIT License
124 stars 29 forks source link

Register DAPI image and IHC image (rgb) ? #132

Closed Nal44 closed 4 months ago

Nal44 commented 5 months ago

Hi,

I want to register some image that comes in 2 flavors : 1 DAPI image 1 RGB (IHC) image.

I used the code that you send me before (that works wonders for multiplex IF), but the registration was poor.

I split the RGB into 3 channels (red,blue,green) and tried to register the DAPI (ch00) to red /blue / green but the registration is very poor (not aligned at all with some zoom and strange position) .

hence using the code you send me before or else is there a way to align an IF image to and RGB image(H&E) ?

Thanks a lot, Antho

cdgatenbee commented 5 months ago

Hi @Nal44, If aligning DAPI to an H&E image, you may be able to get better results by using stain deconvolution to process the RGB image. That should highlight the nuclei in the H&E image, making it look more like the DAPI channel. This can be done using the HEDeconvolution image processor for the RGB image:

from valis import registration, preprocessing

registrar = registration.Valis(src_dir, dst_dir)
rigid_registrar, non_rigid_registrar, error_df = registrar.register(brightfield_processing_cls=preprocessing.HEDeconvolution)

Please try that out and let me know how it goes.

Best, -Chandler

Nal44 commented 5 months ago

Hi Chandler,

Thanks a lot :) Trying this afternoon, I will keep you updated, Have a nice weekend ;D antho

Nal44 commented 4 months ago

I updated to the last version, previous float problem solved . running now ;D

Nal44 commented 4 months ago

It ran, but the results are not what I was expecting ... while saving it provides a 2 ome tiff files : -one with 3 channles (RGB) , one for each but I would prefer a 1 one channel RGB, and the image is wrapped and not aligned to the dapi.

Is there a way to apply the preprocessing onto the RGB and see the results alone ? also is the expected output ? (a 3 channel image or a 1 channel image ?) Then I could apply the preprocessing first then register, (for QC purposes) .

Thanks a lot, I could provide image , processed or from the rigid non rigid (in between steps),

Antho

Nal44 commented 4 months ago

Hi Chandler, I found a work around using : https://scikit-image.org/docs/stable/auto_examples/color_exposure/plot_ihc_color_separation.html#sphx-glr-auto-examples-color-exposure-plot-ihc-color-separation-py

First I deal with the RGB image, then save each separated channel (ch00,ch01,ch03) , then align with the dapi image ch00, and apply the same transformations to the corresponding channels. Results is good but not perfect (but the image is huge , so was excepting that) .

Thanks antho

FYI :

import numpy as np import matplotlib.pyplot as plt from skimage import io from skimage.color import rgb2hed, hed2rgb

Load your TIFF image

image_path = 'path/to/your/image.tiff' ihc_rgb = io.imread(image_path)

Get the shape for QC

print(f"Image shape: {ihc_rgb.shape}")

Check if the image is RGB (3 channels)

if ihc_rgb.shape[-1] != 3: raise ValueError("The image should have 3 channels (RGB)")

Separate the stains from the IHC image

ihc_hed = rgb2hed(ihc_rgb)

Create an RGB image for each of the stains

null = np.zeros_like(ihc_hed[:, :, 0]) ihc_h = hed2rgb(np.stack((ihc_hed[:, :, 0], null, null), axis=-1)) ihc_e = hed2rgb(np.stack((null, ihc_hed[:, :, 1], null), axis=-1)) ihc_d = hed2rgb(np.stack((null, null, ihc_hed[:, :, 2]), axis=-1))

import numpy as np import matplotlib.pyplot as plt from skimage import io from skimage.color import rgb2hed from skimage.exposure import rescale_intensity import os

Rescale intensity for each channel

h = rescale_intensity( ihc_hed[:, :, 0], out_range=(0, 1), in_range=(0, np.percentile(ihc_hed[:, :, 0], 99)), ) e = rescale_intensity( ihc_hed[:, :, 1], out_range=(0, 1), in_range=(0, np.percentile(ihc_hed[:, :, 1], 99)), ) d = rescale_intensity( ihc_hed[:, :, 2], out_range=(0, 1), in_range=(0, np.percentile(ihc_hed[:, :, 2], 99)), )

Get the directory and base filename

output_dir = os.path.dirname(image_path) base_filename = os.path.splitext(os.path.basename(image_path))[0]

Save each channel as a separate 8-bit TIFF file

io.imsave(os.path.join(output_dir, f"{base_filename}_merged_ch00.tif"), (h 255).astype(np.uint8)) io.imsave(os.path.join(output_dir, f"{base_filename}_merged_ch01.tif"), (e 255).astype(np.uint8)) io.imsave(os.path.join(output_dir, f"{base_filename}_merged_ch02.tif"), (d * 255).astype(np.uint8))

print(f"8-bit grayscale channels saved successfully in: {output_dir}")