\[\newcommand{\norm}[1]{\left\lVert#1\right\rVert}\]

In this project, we’ll explore multiple strategies for aligning multiple monochrome captures of an image into a single color image. There are 2 main strategies employed: naive search and image pyramid. For bells and whistles, an automatic edge cropper as well as a feature-based image metric were implemented.

Problem Statement.

We have 3 monochrome images captured independently and the task is to merge each into a single color image. Since these images were captured separately, they are not guaranteed to line up perfectly; so simply merging three $W\times H\times1$ numpy arrays into one $W\times H\times3$ array won’t work. Instead, we need to find a displacement for each color channel to ensure image details line up.

1. Naive Search (with gradient-based image metric)

The first obvious approach to try would by to search over a grid of possible displacements to find the best alignment. To measure the quality of each alignment, we use a simple metric function. Something such as $\norm{im_1 - im_2}_2$ would do. This works well for most images, except for a few such as emir.tif.

To make the L2 norm works for emir, I decided to take the norm on the gradients of an image, rather than directly on its color value. The approximated gradient in the x direction of an image could be computed as its convolution with the Prewitt operator: $\frac{dIm}{dx} = G_x * Im$ where $G_x$ is the Prewitt kernel and is defined as follows: \(G_x = \begin{bmatrix}+1 & +1 & +1 \\ 0 & 0 & 0 \\ -1 & -1 & -1 \end{bmatrix}\) and \(G_y = G_x^{T}\).

$\frac{dIm}{dy}$ is defined analogously.

The revised norm for images $Im_1$ and $Im_2$ is then \(\sqrt{\norm{\frac{dIm_1}{dx} - \frac{dIm_2}{dx}}^2 + \norm{\frac{dIm_1}{dy} - \frac{dIm_2}{dy}}^2}\).

Since the edges of the monochrome images are highly irregular and don’t really reflect the quality of an alignment, I also excluded a margin around the edges before taking the norm. Using this new norm, we see a marked improvement for emir as well as other images.

L2 on color value L2 on gradient
emir_bad emir_good
church_bad church_good

2. Image Pyramid.

The first approach works well if we aren’t constrained by time since doing a blind search for a large image (such as emir.tif) could be very time consuming. To have more a reasonable runtime, we will employ image pyramid.

The idea is to align the image at multiple scales, starting from the coarsest one. At the coarsest scale, we search over a large grid since it is faster to compute the norm for smaller images. As the resolution increases, we search over increasingly smaller grids to make finer adjustments to the original displacement.

Suppose at each level of the pyramid we downsize the image by a factor of 2x (with anti-aliasing enabled so skimage internally applies some Gaussian smoothing). Let $\Delta_i$ be the displacement at the $i$-th level in the pyramid and $G_i$ be the displacement at level $i$ found by searching over a grid. The displacement at level $i$ is then $\Delta_i = G_i + \Delta_{i-1} \times 2$.

This approach yields great improvements in runtime. For example, running emir.tif only took less than 10 seconds! Here are some results:

train emir_good
train emir_good
train emir_good
train emir_good

3. Auto-cropping

The images produced tend to have black edges or edges that were artifacts of the alignment process so we’d like to remove them. For vertical edges, I noticed that taking the gradient in the $x$ direction would result in really small gradients near the edges. Here’s an example of the gradient (in the x direction) of melons.tif (inverted for easier viewing).

train emir_good

If we took the standard deviation of the pixel values of each column (so np.std(grayscale(im)[:, col])), we have the following graph. Notice the stark increase in the variance of the pixel values train

What remains is to crop the picture at these outlying columns. The first approach is to simply use the statistical definition for outliers (i.e. $mean + 1.5\times std$). This is fairly successful at cropping out the black edges. Here are some results.

Before After
emir_good train
emir_good train
emir_good train
emir_good train
emir_good train

Appendix

Here are all the pictures (without autocrop) and their displacements

Picture Red displacement Green displacement
emir_good (12, 3) (5, 2)
emir_good (58, -4) (25, 4)
emir_good (106, 42) (49, 24)
emir_good (123,13) (60, 17)
emir_good (89, 23) (40, 17)
emir_good (177, 13) (80, 10)
emir_good (3, 2) (-3, 2)
emir_good (108, 36) (51, 27)
emir_good (140, -27) (33, -11)
emir_good (175, 37) (79, 30)
emir_good (7, 3) (3, 3)
emir_good (86, 33) (42, 8)

For three_generations.tif, I found that aligning both red and blue to green works better so here is the displacement:

Picture Red displacement Blue displacement
emir_good (-53, -13) (59, -5)

Similarly, for lady.tif, I found that aligning green and blue to red works better:

Picture Blue displacement Green displacement
emir_good (-63, -4) (-119, -13)