I first cropped the image by a fixed value on all sides to remove the border around the actual image. Then, to align 2 channels, for displacements in the range (-15, 15) in both the x and y directions, I calculated the sum of squared differences (SSD), and used the displacment with the smallest SSD for the final alignment.
My implementation calculated that the green channel had a (y,x) offset of (-8, 2) from the blue channel, and the red channel had an offset of (-14, 3) from the blue channel.
The output image is shown below:
I first cropped the image by a fixed value on all sides to remove the border around the actual image. Then, for my multi-scale alignment procedure, I used 5 image scales, where each successive scale was smaller by a factor of 2. I used my single-scale alignment function to calculate the best displacement at each scale. I then scaled the displacement by a factor of 2, then used that result as the initial displacement for the next scale.
I also added the following bells and whistles:
im = (im - np.min(im)) / (np.max(im) - np.min(im)) before separating the image's color channels. Here is a comparison of before and after adding the bells and whistles: