Registration of rotation

I have two DAPI stained images and I would like to register a minor rotation between them of at most a few degrees. I have managed to register the translations using the function: skimage.registration.phase_cross_correlation and it seems to work well but the rotation I’m not too sure about. Has anyone worked out a solution to this using skimage or some other python module? Any suggestions would be really appreciated.

Hey,

Do you know the center of rotation? If so, this example created by @mellertd might be just the trick!

https://scikit-image.org/docs/stable/auto_examples/registration/plot_register_rotation.html

It can also deal with some translation as you’ll read, but I don’t know just how robust it is. Worth a shot!

This example might also do the trick, depending on how many robust feature keypoints are found in your images:

https://scikit-image.org/docs/dev/auto_examples/features_detection/plot_orb.html#sphx-glr-auto-examples-features-detection-plot-orb-py

Finally, another question is whether you need this to be fully automated or whether some manual interaction is ok. If so, I’m just working on a package to do this in napari, based on an idea suggested by either @axtimwalde or @albertcardona, I can’t remember now, but certainly not me! :sweat_smile:

That’s really fresh in the oven, no docs, no robustness, no nothing, so let me know if manual input is ok and I’ll add more info on usage, but briefly:

pip install git+https://github.com/jni/affinder
affinder /path/to/*images.png

Then, you select the two images in the right menu, select Euclidean as the transform (rotation + translation), and “start”. You will choose three points on the first image, three points on the second image, and then you’ll alternate between them until you’re happy with the result, then click “Finish”. Then… :sweat_smile: Then you have to open the console (bottom left button) and get layer = viewer.layers['<moving-layer-name>'], and layer.rotation and layer.translate, because I have absolutely no saving facility implemented yet! :sweat_smile: As I said, fresh in the oven. But it’s pretty fun to play with even now!

3 Likes

I don’t know how robust it is, either! I would be very curious to hear your experience, @Christoffer_Langseth :slight_smile:

I have gotten this to work on a few different types of images before. If you want to try it, I can tell you the key parameters to tweak are the cutoffs for the bandpass filter applied in these lines:

image = difference_of_gaussians(image, 5, 20)
rts_image = difference_of_gaussians(rts_image, 5, 20)

And this line is going to depend on which parameters you choose in the above lines:

radius = shape[0] // 8  # only take lower frequencies

I chose that number just by looking at the resulting FFTs to see where there is still signal – the bp filter cuts out a lot of high frequency stuff as you’d expect.

I don’t have any great suggestions as to how to choose those parameters, other than to eyeball the output to make sure you have a fair bit of structure left in the image (i.e., it shouldn’t be too smoothed out). Once you find a good bp filter, everything else is pretty robust. And honestly, in my experience the tolerance for the bp filter parameters is pretty high.

You could also play with the choice of windowing function, but I don’t think that matters much. Hann is almost always fine.