Colorizing the Prokudin-Gorskii Photo Collection

Introduction

This webpage mainly introduces the steps I took to solve the problem, and the results.

First attemp

With the start code, I first tried to simply combine original RGB channels, getting unaligned result. Apparently, it needs a certain shift.

Unaligned cathedral
Cathedral - Unaligned

Single-scale implementation

As discussed above, we need to find a certain shift(i, j) for every channel, where i refers to the vertical shift, and j refers to the horizontal shift. Suppose we have a 3-channel image, fix the blue channel, and try to find the best shift for the green and red channel. This could be done by brute-force search through shifting window of size 15. Namely, i and j are both in the range [-15, 15]. For each pair of (i, j), we calculate the sum of squared difference (SSD) between the channels, and take the pair with the smallest SSD as the best shift.

Metric

I tried both SSD and normalized cross-correlation(NCC) as the metric to find the best shift. In provided dataset, I didn't see clear difference between the two. Eventually I picked SSD since it's faster.

Here is the aligned result for calthedral image.

Aligned cathedral
Cathedral - Aligned

Coarse-to-fine pyramid speedup

Noticing that for single-scale implementation, our data is of very small size(390*1024), actually we have pretty large-scale images sizing approximately 4000*10000. In this case, a window of size 15 probably is not large enough to find the best shift. A naive solution is to increase the window size, while it is extremely time-consuming to calculate the metrics given such a large image.

Therefore, we need to find a more efficient way to solve the problem. We use image-pyramid to speed-up the search. The idea is to first find the best shift for the coarsest image, and then multiply the shift by 2 for the next level as its initial shift. It might also need a little adjustment to the shift, but this shift has a smaller range, which is more efficient to calculate.

A problem: image doesn't align well

A naive implementation didn't work well for me. After visualizing the stacked output from each level, I found that even for the coarsest image, the algorithm didn't find the best shift and the image stays unaligned.

I first attempted to solve this by increasing the window size, but the result remains almost the same(Actually it took me a lot of time to adjust parameters of window sizes in different levels, but the result just didn't become better). I inferred that the marginal pixels is a factor. Since the pixel values change dramatically(from white to black to the image itself), when we do np.roll, it generates a considerable loss that makes the result worse.

Solution: naive cut-off

Therefore, I tried to crop the image to remove the marginal pixels, and the result becomes better. Here I simply cut off 100 pixels from each side. Here are my results.

Emir - Unaligned
Harvesters - Aligned
Icon - Aligned
Lady - Unaligned
Self portrait - Aligned?
Three generations - Aligned
Train - Aligned
Turkmen - Aligned?
Village - Unaligned

Improvement

With the naive cut-off, the result becomes better. However, the result is still not perfect. I further defined a range in the middle of the image, and only calculate the metric in this range. This approach is more efficient, and the result becomes better.

Lady - Aligned
Self portrait - Aligned
Village - Aligned
Turkmen - Aligned

Unfortunately, this method didn't apply well to emir, which I guess needs a smarter cropping, color correction or parameter changes.

Extension

When I was exploring approches to solve the problem, I implemented a simple cropping algorithm. I first used Canny to detect edges, dilate and erode it to get a closed border, and then find the largest contour to get the bounding box. This method has some deficiencies, like for the images of lady and village, which themselves contain a sudden transition from white to black in pixel color, it cut off some undesirable parts of images. I didn't have time to make it work in my final implementation, but I think it's a promising approach.

Emir - Channel b - Cropped
Emir - Channel g - Cropped
Emir - Channel r - Cropped