For Fall 2024, I am taking an image processing class, and one assignment involves colorizing the historical Prokudin-Gorskii photo collection.

The approach involves splitting each image into its red, green, and blue channels and aligning them to form a full-color image. By iterating over offsets from -15 to 15 and computing the cross-correlation between channels, I could align most images accurately. For higher-resolution images, I implemented an image pyramid for faster alignment.

One challenging image featured a person seated in a chair. To address the alignment issues, I applied an edge detection filter to each channel, aligning the edges by maximizing normalized covariance.

Here’s the result of edge detection on the challenging photo:

Before:

Edge Detection Before Alignment

After Alignment:

After Alignment

Low-Resolution Results Link to heading

Here are some low-resolution images, with their respective offset values for the green and red channels (in the format (offsetX_g, offsetY_g), (offsetX_r, offsetY_r)):

Image 1 — Offset: (-3, 2) (3, 2)
Image 2 — Offset: (3, 3) (6, 3)
Image 3 — Offset: (5, 2) (12, 3)

High-Resolution Results Link to heading

For high-resolution images, offsets are applied progressively in an image pyramid (first multiplied by 16, then 8, then 4, and finally 1). Here are the high-resolution images before and after alignment:

Original Images:

Image 0
Image 1
Image 2
Image 3
Image 4
Image 5
Image 6
Image 7
Image 8
Image 9

Aligned Images:

Aligned Image 0
Aligned Image 1
Aligned Image 2
Aligned Image 3
Aligned Image 4
Aligned Image 5
Aligned Image 6
Aligned Image 7
Aligned Image 8
Aligned Image 9

Note: Some images, like Image 9, did not align well because the channels were not divided cleanly into thirds.

Calculated Offsets Link to heading

Here are the offsets used for aligning each high-resolution image.

For further details, you can view the code on GitHub.