In 1907, Sergei Mikhailovich Prokudin-Gorskii travelled to the Russian Empire to photograph various subjects. He captured everything in three different exposures of red, green, and blue. Although, there wasn't a way to print color photographs at that time, the Library of Congress obtained his collection of glass negatives and we will attempt to overlay the 3 different color channels for each scene and produce a colorized and aligned image in this project.
A first attempt to simply overlay all the channels will produce colorized but rather unaligned images. Because of this, we need to find a proper alignment for each red and green channel onto the blue channel. This is as simple as finding the best x and y pixel translation for each channel. We can exhaustively iterate over a range [-15, 15] for both x and y and score each shift compared to the blue channel using the L2 Norm, also known as the Euclidean distance, on the pixels. It's also important to note that we should crop the images before trying different shifts to avoid fitting to the borders which can affect our results. After trying these steps on both the red and green channels, we can obtain and apply the best shifts to each respective color channel and overlay it on the blue channel to produce properly aligned and colorized images as shown below.
While this exhaustive iteration over a small window works well for JPG files, it would require a larger window for high-resolution scans which can take longer and be quite inefficient. For this reason, we can instead utilize an image pyramid alignment approach. This approach takes advantage of the idea we saw earlier that smaller images are easier to exhaustively search over to find the best shift. We will first downscale the original image by 0.5 using sk.transform.rescale and store each downscaled image. This will be repeated for all color channels until the image's height or width is less than 200px. Next, we will start from the coarsest image and euclidean align it with the coarsest image of blue's downscaled images to find the best shift. We will repeat this for both red and green, each time moving from the coarse images to the finer ones and scaling the shift from the previous image by 2 and adding the new shifts until we have our final shifts on the highest resolution. The results from image pyramid alignment and the shifts used to achieve it for each image are shown below.
Here are the results of the Image Pyramid Alignment algorithm performed on other images I chose from the Prokudin-Gorskii collection
As you may have noticed, Emir.tif is still rather unaligned compared to the other tif files that were able to be aligned through image pyramid alignment. This is because the images to be matched have different brightness values across different color channels. In this case, it would be better to use a different metric than the raw pixel difference. I decided to use Canny Edge Detection (sk.feature.canny) to create an edge map of all three color channels. Once we have the edge maps, we can align them to each other using the image pyramid align with the L2 Norm scoring once again. This allows us to avoid suboptimal shifts that we would otherwise receive using the same scoring system on raw color channels that can have different brightness values. It is worth noting that if we are using edge maps from Canny Edge Detection, we no longer need to crop the images before exhaustively trying shifts as the borders will not appear in the edge maps. As you can see below, using the edge maps results in a better aligned image compared to just using the raw color channels.