Project 1 - Images of the Russian Empire

By Nithin Chalapathi

Project Overview - The main goal of this project is to colorize images taken of Russia in the early 20th century by Sergey Prokudin-Gorsky. His conviction that color images were the future lead him to take three photographs of the same scene using red, green, and blue filters. Given three grayscale images taken using a red, green, and blue filter, the project aims to combine the three into a color image. My approach involves:

  1. Using the normalized cross-correlation to align color channels.
  2. Using an image pyramid for larger images instead of an exhaustive search.
  3. Ignoring the borders of each color channel.

For each implementation point, I first describe the approach and thought process. I conclude with some closing remarks.

1. Normalized Cross Correlation - During the single-scale implementation, I decided to use both the sum of squared distances and normalized cross correlation metric to see which performed better. Visually, the NCC seems to perform slightly better when edges of each channel are used to compute the similarity metric between channels. As I implemented the multi-scale and edge exclusion, they performed almost identically in my testing. For the sake of simplicity, I only use the NCC but the functionality for the sum of squared distances is still in the code. For the single-scale implementation, an exhaust search of [-15, 15] pixels for both height and width are used.

2. Image pyramid - As to be expected, the single-scale implementation is far too slow to do an exhaustive search on the large tif images. As a result, I implemented an image pyramid. The pyramid uses a scale factor of 2 when creating each successive layer. In my brief testing, it seemed that going beyond a certain resolution didn't yield much visual difference. Thus, the base case for my pyramid is when one dimension (height or width) of the image reach below 600 pixels. After which, the program computes the best possible channel alignment and recurses up to the finer representation. Similar to the single scale implementation, at each level of the pyramid an exhaustive search of [-15, 15] pixel alignment for both height and width is performed.

3. Ignoring borders - As I was testing out my code, I noticed that some images performed poorly in the alignment phase (notably emir.tif). I hypothesized that this might be due to the edges of the image. For each image, I ignored 10% of the border on all sides. I found that this was a sufficient offset to ignore the artifacts on the edges of the color negatives.

Implementation notes - As I developed the multi-scale representation, I scrapped my single-scale implementation. The only images I used for the single-scale implementation were the small JPEG images, all of which had dimensions less than 600 x 600. I was able to reduce the amount of code required for all the images as a result. To shift the channels, I used Numpy.roll.

Further Work - One place for improvement is the performance of the program. While the average amount of time per image on my computer is roughly 1 minute, I believe the program could be accelerated. It might help to have the image pyramid go to a much finer level and search over a smaller displacement window. It may also help to have a smarter scaling factor (i.e. one that was adjusted based off of the level's current size).

Results - The naive image is on the top and the output of my program is on the bottom. The displacement vectors for red and blue are below each image (width offset, height offset).

emir.tif

Unedited Emir

Edited Emir

Green Displacement: (24, 49) Red Displacement: (55, 103)

church.tif

Unedited church Edited church

Green Displacement: (4, 25) Red Displacement: (-4, 58)

harvesters.tif

Unedited harvesters Edited harvesters

Green Displacement: (16, 59) Red Displacement: (13, 124)

icon.tif

Unedited icon

Edited icon

Green Displacement: (17, 41) Red Displacement: (23, 89)

lady.tif

Unedited lady

Edited lady

Green Displacement: (9, 51) Red Displacement: (11, 112)

melons.tif

Unedited melons

Edited melons

Green Displacement: (10, 81) Red Displacement: (13, 178)

onion_church.tif

Unedited onion_church

Edited onion_church

Green Displacement: (26, 51) Red Displacement: (36, 108)

self_portrait.tif

Unedited self_portrait

Edited self_portrait

Green Displacement: (29, 78) Red Displacement: (37, 176)

three_generations.tif

Unedited three_generations

Edited three_generations

Green Displacement: (14, 53) Red Displacement: (11, 112)

train.tif

Unedited train

Edited train

Green Displacement: (5, 42) Red Displacement: (32, 87)

workshop.tif

Unedited workshop

Edited workshop

Green Displacement: (0, 53) Red Displacement: (-12, 105)

cathedral.jpg

Unedited cathedral

Edited cathedral

Green Displacement: (2, 5) Red Displacement: (3, 12)

monastery.jpg

Unedited monastery

Edited monastery

Green Displacement: (2, -3) Red Displacement: (2, 3)

tobolsk.jpg

Unedited tobolsk

Edited tobolsk

Green Displacement: (3, 3) Red Displacement: (3, 6)

alter.tif - Pulled from LoC's website.

Unedited alter

Edited alter

Green Displacement: (16, 20) Red Displacement: (17, 59)

monument.tif - Pulled from LoC's website.

Unedited monument

Edited monument

Green Displacement: (21, 22) Red Displacement: (29, 60)

poppies.tif - Pulled from LoC's website.

Unedited Poppies Edited Poppies

Green Displacement: (19, 24) Red Displacement: (40, 121)