Closed WXY-Belief closed 1 year ago
Hi @WXY-Belief, So sorry it took me this long to get back to you, have just been a bit swamped lately. Anyway, you should be able to use the following function to extract the registration parameters (rigid and non-rigid) for the full resolution WSI :
from skimage import transform
import numpy as np
import pyvips
from valis import registration, warp_tools
def summarize_slide_transforms(slide_obj, crop=True):
# Transforms found on lower resolution images, so scale to use on slide
src_slide_shape_rc = slide_obj.slide_dimensions_wh[0][::-1]
uncropped_reg_slide_shape_rc = slide_obj.val_obj.aligned_slide_shape_rc
img_corners_xy = warp_tools.get_corners_of_image(src_slide_shape_rc)[:, ::-1]
warped_corners = warp_tools.warp_xy(img_corners_xy, M=slide_obj.M,
transformation_src_shape_rc=slide_obj.processed_img_shape_rc,
transformation_dst_shape_rc=slide_obj.reg_img_shape_rc,
src_shape_rc=src_slide_shape_rc,
dst_shape_rc=uncropped_reg_slide_shape_rc)
M_tform = transform.ProjectiveTransform()
M_tform.estimate(warped_corners, img_corners_xy)
slide_M = M_tform.params
if crop:
crop_method = slide_obj.get_crop_method(crop)
if crop_method is not False:
if crop_method == registration.CROP_REF:
ref_slide = slide_obj.val_obj.get_ref_slide()
slide_aligned_shape_rc = ref_slide.slide_dimensions_wh[0][::-1]
elif crop_method == registration.CROP_OVERLAP:
slide_aligned_shape_rc = slide_obj.val_obj.aligned_slide_shape_rc
slide_bbox_xywh, _ = slide_obj.get_crop_xywh(crop=crop_method, out_shape_rc=slide_aligned_shape_rc)
crop_T = np.eye(3)
crop_T[0:2, 2] = slide_bbox_xywh[0:2]
slide_M = slide_M @ crop_T
# Extract rigid transforms
slide_transform_summarizer = transform.SimilarityTransform(slide_M)
slide_rotation_rad = slide_transform_summarizer.rotation
slide_rotation_translation_xy = slide_transform_summarizer.translation
slide_rotation_scale = slide_transform_summarizer.scale
# Summarize non-rigid displacements inside registration mask
if slide_obj.bk_dxdy is not None:
if isinstance(slide_obj.non_rigid_reg_mask, pyvips.Image):
nr_mask = warp_tools.vips2numpy(slide_obj.non_rigid_reg_mask)
else:
nr_mask = slide_obj.non_rigid_reg_mask
reg_img_shape = np.array(slide_obj.reg_img_shape_rc)
downscaled_dxdy = warp_tools.scale_dxdy(slide_obj.bk_dxdy, out_shape_rc=reg_img_shape)
downscaled_dxdy = warp_tools.vips2numpy(downscaled_dxdy)
displacement_sxy = (uncropped_reg_slide_shape_rc/reg_img_shape)[::-1]
scaled_dx = downscaled_dxdy[..., 0]*displacement_sxy[0]
scaled_dy = downscaled_dxdy[..., 1]*displacement_sxy[1]
scaled_mask = warp_tools.resize_img(nr_mask, reg_img_shape)
mean_dx = np.mean(scaled_dx[scaled_mask>0])*slide_obj.resolution
mean_dy = np.mean(scaled_dy[scaled_mask>0])*slide_obj.resolution
mean_dxdy = (mean_dx, mean_dy, slide_obj.units)
else:
mean_dxdy = None
return slide_rotation_rad, slide_rotation_translation_xy, slide_rotation_scale, mean_dxdy
You can then loop through each slide and extract/summarize the transforms. This example loads a Valis
object that was saved the the /data
directory (ends in "_registrar.pickle") and then loops through the slides, but you could do this right after the registration, too:
registrar = registration.load_registrar(registrar_file)
for slide_name, slide_obj in registrar.slide_dict.items():
slide_rotation_rad, slide_rotation_translation_xy, slide_rotation_scale, slide_mean_dxdy = summarize_slide_transforms(slide_obj)
print(f"{slide_name} transforms:\n"
f"rotation (radians)={slide_rotation_rad}\n"
f"translation={slide_rotation_translation_xy}\n"
f"scaling={slide_rotation_scale}\n"
f"mean dxdy={slide_mean_dxdy}\n\n"
)
Hopefully that helps, but if not, please let me know.
Best, -Chandler
Thank you for your response. It's a great help to me.
Great! I'll go ahead and close the issue then.
Best, -Chandler
Hello, I would like to ask about how to obtain parameters for rigid registration, such as rotation angle and translation distance, after registration.