Mikhailovich Prokudin-Gorsky took three images of each scene with red, green, and blue filters. This project aims to align these three images of each scene to obtain the colored image.
Since each image contains three parts, each one for each channel. First, I divided an input image into three images. Then, I cropped each image to cut the spare borders. After that, I took the green channel as the anchor and aligned the red and blue channels to the anchor. At the end, I merged aligned blue, green, and aligned red channels.
I used the following methods for aligning images:
This method finds the best amount of shift needed to align two images by searching all possible movements in the space of [-15,15]. This method is an exhaustive search, so it is slow (especially for large images like “emir.tif”).

This method recursively scales the input image to half size until the size of the image reaches a specified threshold. It uses exhaustive method on the image with the size less than the threshold. The method adjusts returned shift from the next recursion by multiplying by 2. Then, it finds the best amount of shift needed to align current image in a space of [-4,4] of adjusted shift.

To find the optimal shift, I used error function which computes the displacement score for two images. I used following ways to compute the score:
Results of Normalized Cross-correlation are better than others. The reason is that the different channels may use different brightness values.

The results of Pyramid method are better than exhaustive method because searching process of exhaustive method limited to the window size while the optimal displacement may be out of the window.
| Exhaustive Alignment | Pyramid Alignment |
|---|---|
|
|
|
Displacement: Blue: (-2, -5) Red: (1, 7) |
Displacement: Blue: (-2, -5) Red: (1, 7) |
|
|
|
Displacement: Blue: (-15, -15) Red: (15, 15) |
Displacement: Blue: (-24, -52) Red: (18, 60) |
|
|
|
Displacement: Blue: (-12, -15) Red: (-2, 15) |
Displacement: Blue: (-14, -56) Red: (-2, 64) |
|
|
|
Displacement: Blue: (-8, -15) Red: (15, 15) |
Displacement: Blue: (-6, -44) Red: (26, 46) |
|
Displacement: Blue: (-15, -15) Red: (5, 15) |
Displacement: Blue: (-17, -42) Red: (5, 52) |
|
|
|
Displacement: Blue: (15, 0) Red: (-15, 15) |
Displacement: Blue: (-14, -68) Red: (11, 76) |
|
|
|
Displacement: Blue: (-15, -15) Red: (14, 15) |
Displacement: Blue: (-28, -84) Red: (8, 100) |
|
|
|
Displacement: Blue: (-15, -15) Red: (-1, 15) |
Displacement: Blue: (-17, -64) Red: (-3, 68) |
|
|
|
Displacement: Blue: (-8, -15) Red: (0, 15) |
Displacement: Blue: (-8, -56) Red: (3, 64) |
|
|
|
Displacement: Blue: (-15, -15) Red: (3, 15) |
Displacement: Blue: (-21, -60) Red: (7, 64) |
|
|
|
Displacement: Blue: (15, -15) Red: (-15, 15) |
Displacement: Blue: (36, -44) Red: (-40, 72) |
|
|
|
Displacement: Blue: (1, -15) Red: (-15, 15) |
Displacement: Blue: (1, -60) Red: (-15, 64) |
|
|
|
Displacement: Blue: (-8, 15) Red: (2, -12) |
Displacement: Blue: (-8, 22) Red: (2, -12) |
|
|
|
Displacement: Blue: (12, -15) Red: (0, 15) |
Displacement: Blue: (13, -42) Red: (2, 60) |
|
|
|
Displacement: Blue: (7, -15) Red: (-15, 15) |
Displacement: Blue: (6, -52) Red: (-18, 50) |
For Bells & Whistles, I implemented the followings:
I implemented the method by PyTorch in the following way:
I wrote a class named ImageAlignDataset to read data. I used dataloader to get data in batch.

In this method, I calculated displacement score using edges of images instead of intensity of pixels. This method leads better results.
I used two ways to detect edge:

I implemented automatic cropping in the following ways:
The last auto cropping method works better.
| Torch Implementation | Alignment by Edges | Auto Cropping |
|---|---|---|
|
|
|
|
Displacement: Blue: (-2, -5) Red: (1, 7) |
Displacement: Blue: (-2, -5) Red: (1, 7) |
Displacement: Blue: (-2, -5) Red: (1, 7) |
|
|
|
|
Displacement: Blue: (-24, -49) Red: (17, 57) |
Displacement: Blue: (-23, -52) Red: (17, 60) |
Displacement: Blue: (-24, -52) Red: (17, 60) |
|
|
|
|
Displacement: Blue: (-14, -53) Red: (-3, 58) |
Displacement: Blue: (-13, -56) Red: (-4, 64) |
Displacement: Blue: (-14, -56) Red: (-3, 62) |
|
|
|
|
Displacement: Blue: (-5, -42) Red: (27, 43) |
Displacement: Blue: (-2, -44) Red: (26, 46) |
Displacement: Blue: (-5, -44) Red: (27, 46) |
|
Displacement: Blue: (-17, -41) Red: (5, 48) |
Displacement: Blue: (-17, -42) Red: (5, 52) |
Displacement: Blue: (-17, -42) Red: (5, 50) |
|
|
|
|
Displacement: Blue: (-12, -64) Red: (10, 73) |
Displacement: Blue: (-12, -68) Red: (10, 76) |
Displacement: Blue: (-14, -68) Red: (11, 76) |
|
|
|
|
Displacement: Blue: (-29, -78) Red: (8, 98) |
Displacement: Blue: (-26, -84) Red: (8, 100) |
Displacement: Blue: (-30, -84) Red: (8, 100) |
|
|
|
|
Displacement: Blue: (-16, -59) Red: (-3, 65) |
Displacement: Blue: (-16, -64) Red: (-3, 68) |
Displacement: Blue: (-17, -62) Red: (-3, 68) |
|
|
|
|
Displacement: Blue: (-9, -51) Red: (3, 61) |
Displacement: Blue: (-8, -60) Red: (4, 68) |
Displacement: Blue: (-9, -52) Red: (3, 66) |
|
|
|
|
Displacement: Blue: (-21, -56) Red: (7, 60) |
Displacement: Blue: (-22, -60) Red: (7, 64) |
Displacement: Blue: (-22, -60) Red: (7, 64) |
|
|
|
|
Displacement: Blue: (38, -40) Red: (-43, 67) |
Displacement: Blue: (36, -44) Red: (-40, 72) |
Displacement: Blue: (-40, 72) Red: (36, -42) |
|
|
|
|
Displacement: Blue: (1, -55) Red: (-15, 58) |
Displacement: Blue: (1, -60) Red: (-15, 64) |
Displacement: Blue: (1, -58) Red: (-15, 62) |
|
|
|
|
Displacement: Blue: (-8, 22) Red: (2, -12) |
Displacement: Blue: (-9, 23) Red: (2, -12) |
Displacement: Blue: (-7, 22) Red: (17, 60) |
|
|
|
|
Displacement: Blue: (13, -40) Red: (2, 57) |
Displacement: Blue: (14, -48) Red: (2, 60) |
Displacement: Blue: (10, -52) Red: (2, 60) |
|
|
|
|
Displacement: Blue: (6, -49) Red: (-18, 47) |
Displacement: Blue: (6, -52) Red: (-19, 52) |
Displacement: Blue: (6, -52) Red: (-18, 50) |