I’ve played with using motion compensation to align image stacks for noise reduction before, but I thought I would have another go.
These images are from a real estate agent’s building near my house. I shot 7 handheld images underexposed about 2 stops at ISO 1600. I then used Avisynth and Virtualdub to created motion compensated frames to match the reference image. That is, every 8×8 pixel block is shifted from the its position in the current image to match the position in the reference image. The result is 7 images that overlap near perfectly. I them used a median filter to blend the now matching frames together to create an image with reduced noise and added detail. Using a median filter helps reduce errors from poor motion compensation from showing up in the final image.
In the images above you can see the original crop; an attempt at manually aligning and blending the whole image, which results in softness and blur; A motion compensated and blended version; a version of the reference image with standard noise reduction applied; and a version with motion compensated blending and standard noise reduction applied afterwards.
The processing is pretty quick by noise reduction standards. Even if you are only using 2 or 3 images you get noticeable improvements in details and reduced noise. Problems occur with parallax and other large changes between images, I’ve tried it photos of people on a windy day, and it does fail in some areas due to the wind, but where it works it works well. I’m not sure why this method is not an option used by more noise reduction software.
For the interested here is my Avisynth script. I first created an uncompressed AVI file of the 7 frames I shot to make things easier
super = MSuper()
backward_vectors = MAnalyse(super, isb = true,blksize=8, searchparam=4)
backward_vectors2 = MAnalyse(super, isb = true,blksize=8, searchparam=4, delta=2)
backward_vectors3 = MAnalyse(super, isb = true,blksize=8, searchparam=4, delta=3)
forward_vectors = MAnalyse(super, isb = false,blksize=8, searchparam=4)
forward_vectors2 = MAnalyse(super, isb = false,blksize=8,searchparam=4, delta=2)
forward_vectors3 = MAnalyse(super, isb = false,blksize=8,searchparam=4, delta=3)
forward_compensation3 = MCompensate(super, forward_vectors3, thSCD1=6000)
forward_compensation2 = MCompensate(super, forward_vectors2, thSCD1=6000)
forward_compensation = MCompensate(super, forward_vectors, thSCD1=6000)
backward_compensation = MCompensate(super, backward_vectors, thSCD1=6000)
backward_compensation2 = MCompensate(super, backward_vectors2, thSCD1=6000)
backward_compensation3 = MCompensate(super, backward_vectors3, thSCD1=6000)
# create interleaved 5 frames sequences
interleave(forward_compensation3, forward_compensation2, forward_compensation, last, backward_compensation, backward_compensation2, backward_compensation3)
medianblurt(radiusy=0, radiusu=0, radiusv=0, temporalradius=3)