Project 1: Colorizing the Prokudin-Gorskii Photo Collection

By: Andi Liu


1. Introduction

Note: Displacements for all the images are listed in the Gallery.

For this project, we are using a dataset of pictures taken by Sergei Mikhailovich Prokudin-Gorskii. Each picture is a set of three glass plate negatives,
taken with three different color filters of Red, Green, and Blue. For this project we are taking the three negatives and combining them into a single color image.

To start, we can place the three negatives side by side to get an idea of what they look like. For now we will start with an image with smaller
filesize, which is an image of a cathedral.

Black and White Negatives of Cathedral Image

This is what the negatives look like with the red, green, and blue filters applied.

Negatives of Cathedral Image with Red, Green, Blue filters, respectively

Now let us see what happens if we naively overlay the three color-filtered negatives as they are.

Poorly aligned full-color photo of Cathedral

While we seem to get something resembling full-color, there are clearly many issues with this photo. First and most glaring is the alignment of the negatives is poor,
giving the image a blurry effect, and we can clearly see the overlaid copies of the image. For the first step of this project, we will focus on this alignment issue.


2. Alignment by Exhaustive Search

Since the alignment on our cathedral image is fairly close, we can create good alignment by simply trying various displacements of the three negatives. We will exhaustively search over a
set window of displacements (between [-20,20] pixels in both horizontal and vertical directions) and score each one using the Normalized Cross-Correlation (the dot product between the two
normalized image vectors). We will then choose the displacement that gives us the best score, which ideally will be the displacement that give us good alignment between the three negatives.

Writing the Code:
There is a very important subtlety within our exhaustive search criteria. When we assign a score to each displacement, we only want to consider the quality of alignment of the parts that overlap.
So the Normalized Cross-Correlation is not computed between the entire images, but rather only the portion of the images that overlapped. Our algorithm will take this into consideration.

In order to see our results, we will also write a function to display the aligned images, using the displacement numbers given to us by our search algorithm. This function will not only align
the three filters, but it will also crop the images so that only the intersection of the three filters is shown. This allows us to inspect specifically the part of the image that our
search algorithm is optimizing. Once all this is done and we run our algorithm, we obtain the following:

Full Color Cathedral Image, Red and Green Aligned but Blue slightly misaligned

We can now see a drastic improvement in alignment, however there are still clearly issues. There are still blue and yellow outlines where misalignments still exist. We can tell that our
algorithm works because yellow is a combination of red and green, meaning our algorithm worked extremely well for the red and green negatives, but there were issues causing it to
fail when aligning the blue and red negatives.This is most likely because the borders are causing noise for our algorithm. As we can see in the above image, there is a very large blue/black border
on the right that may be the cause of the blue misalignment. For now, we will manually crop off a 10 pixel border on all sides of the negatives and see if this yields an improvement:

Full Color Cathedral Image, Perfectly Aligned, Borders Cropped

Indeed, the misalignment of the blue negative was because of noise caused by the borders. Once we cropped the images, the red-green displacement stayed the same, but the red-blue displacement shifted
by four pixels. As a result, we now have excellent alignment of the filters. Keeping this in mind, for the rest of the project we will manually crop the borders before running our algorithms.

3. Testing Our Single Scale Alignment Algorithm

Now that we have a working single-scale alignment algorithm, let's see how it performs on some other images that have relatively small filesize. We will use our algorithm on the monastery and
tobolsk images. Below is a side-by-side of the negatives, followed by the full-color images aligned by our algorithm.

Side by Side of negatives for the monastery and tobolsk images Full-Color Search Aligned Monastery and Tobolsk images

As we can see, our algorithm performs fantastically on both images. There are no visible alignment issues in either picture.

4. Image Pyramids

While our exhaustive search algorithm works very well for the relatively small pictures, for larger images exhaustive search is prohibitively expensive in runtime. Therefore, we will introduce a
new algorithm that uses image pyramids to speed up the process. The image pyramids will store the negatives at many resolutions, from coarse to fine, and this algorithm will perform a single-scale
displacement calculation at each layer. At the end, the displacements from each layer will be combined. The speedup from image pyramids should allow us to process the larger .tiff images.

Writing the Code:
Once I implemented the image pyramid alignment function pyramidBestDisplacement, it became immediately evident that my bestDisplacement function was too slow. The bestDisplacement function checked
alignments by adding different amounts of padding to each image, so that the images have lots of empty data and are displaced. Furthermore the bestDisplacement function could only calculate displacement
between two images at a time, so I had to call it twice. With these inefficiencies in mind I created an improved version, bestDisplacement2, that created different displacements by cropping the images
leaving only the intersecting area. Furthermore, bestDisplacement2 calculated two displacements at the same time, so I could calculate the green and blue displacements in one function call. This
drastically improved the runtime of the single-scale alignment algorithm, and in fact this was all that was needed. I wrote a second version of pyramidBestDisplacement using the improved single-scale
alignment and runtimes were generally around 2.5 minutes on each of the large .tif images. I further performed some tweaking with the parameters to determine which parameters would work on most images, and
settled on a 5-level image pyramid, with searching displacements between [-4,4] pixels at each scale. These parameters worked fairly well for most of the images. I furthermore introduced a wrapper
function to import, crop, and align the images. In this function I set the default cropping to 30 pixels on each edge. A few images had large borders that drastically affected alignment, however,
so those images required extra cropping.

Results Of Image Pyramid Algorithm

As we can see below, our image pyramid alignment algorithm works very well on most of the example images.

Cropping Issues Again

While the algorithm worked very well for the images above, there were a few images where it clearly had issues. In particular, the Onion Church image, the Self Portrait image, and the Train image
had substantial problems aligning. Upon inspection, the problem turned out to be the fairly large borders, which, just like in our single-scale algorithm, was causing problems. For these images
I had to manually increase the border cropping. Naturally, I could increase the universal border cropping, but that does cut off some of the picture, so it is preferable to manually tune the few
images that have problems. After a simple fix of increasing the border crop, these images also turned out excellently.

Before Cropping Adjustment

After Cropping Adjustment

For the Onion Church Image and Train Image, I adjusted border cropping from 30 pixels to 100 pixels. The Self Portrait Image required a larger adjustment, from 30 pixels to 200 pixels.

Other Examples From The Collection

Below are a few more example pictures I selected from the Prokudin-Gorskii collection. These are the results of running my algorithm on the 30ish MB .tif images.

Camel Carrying Sacks

Kostroma

Railroad Dam

Crumbling Mosque

Isfandiyar Khan of Khorezm

Note: this image also required a cropping adjustment, from 30 pixels to 200 pixels.

Below includes all the images from this project, as well as the respective displacements computed by my algorithm.
Note: The red negative is the reference, so displacement of the red negative is always (0,0). A displacement of (x,y) refers to
a horizontal displacement of x, and a vertical displacement of y. A displacement in the upwards direction is considered a
positive y-displacement; a displacement in the leftwards (not rightwards) direction is considered a positive x-displacement.


Cathedral

Displacements (relative to red, in pixels):
Green: (-1, -7)
Blue: (-3, -12)

Monastery

Displacements (relative to red, in pixels):
Green: (-1, -6)
Blue: (-2, -3)

Tobolsk

Displacements (relative to red, in pixels):
Green: (-1, -4)
Blue: (-3, -6)

Emir

Displacements (relative to red, in pixels):
Green: (-13, -57)
Blue: (-17, -107)

Church

Displacements (relative to red, in pixels):
Green: (5, -33)
Blue: (5, -57)

Harvesters

Displacements (relative to red, in pixels):
Green: (3, -65)
Blue: (-8, -124)

Icon

Displacements (relative to red, in pixels):
Green: (-5, -48)
Blue: (-22, -90)

Lady

Displacements (relative to red, in pixels):
Green: (9, -53)
Blue: (16, -111)

Melons

Displacements (relative to red, in pixels):
Green: (-3, -96)
Blue: (-8, -179)

Sculpture

Displacements (relative to red, in pixels):
Green: (16, -107)
Blue: (26, -139)

Three Generations

Displacements (relative to red, in pixels):
Green: (0, -57)
Blue: (-7, -111)

Onion Church

Displacements (relative to red, in pixels):
Green: (-10, -57)
Blue: (-35, -108)

Self Portrait

Displacements (relative to red, in pixels):
Green: (-8, -98)
Blue: (-36, -176)

Train

Displacements (relative to red, in pixels):
Green: (-26, -43)
Blue: (-29, -88)

Camel (Self Selected)

Displacements (relative to red, in pixels):
Green: (14, -53)
Blue: (15, -99)

Kostroma (Self Selected)

Displacements (relative to red, in pixels):
Green: (-16, -61)
Blue: (-32, -109)

Railroad (Self Selected)

Displacements (relative to red, in pixels):
Green: (8, -68)
Blue: (17, -83)

Crumbling Mosque (Self Selected)

Displacements (relative to red, in pixels):
Green: (0, -44)
Blue: (-9, -70)

Isfandiyar

Displacements (relative to red, in pixels):
Green: (17, -53)
Blue: (8, -94)