R: (104,15) G:(54,12) |
R: (139,48) G:(70,25) |
R: (123,18) G:(54,16) |
R: (141,14) G:(67,12) |
R: (80,44) G:(32,21) |
R: (92,21) G:(34,-9) |
R: (122,15) G:(56,14) |
R: (95,10) G:(47,16) |
R: (132,-58) G:(58,-13) |
First I used a simple 'shift and compare' method over a range of possible inputs. A shifted channel (red, green) is compared to a stationary channel (blue) using a sum of squared distances. Every position up to +/-5% of the image resolution was tested. For a 400x300 image, this means that 1200 possible configurations are tested for each channel! Obviously, this is a crappy way of doing things and will take forever on larger images.
As a second iteration, I implemented a version of the "image pyramid", each level being half the resolution of the level before it with the largest being the original image and the smallest being no less than 8x8. This allows up to a 12% shift in any dimension. Instead of saving every instance in memory, the original image is reduced down to the current level being considered at each level. This results in a slower runtime, but can be kinder to a system with less memory. Additionally, this allows for a chance to improve (see enhancements). In every image pyramid iteration, five possible moves are considered: up/down one pixel, left/right one pixel or no movement at all. The loop descends through the image pyramid, doubling the aggregated shift at each new level to account for the increase in resolution.
One problem I noticed was that the borders and other gunk on the edges were causing some skew in scoring. To correct this, I simply removed the outer edges of each layer before comparing it. The outermost 10% of each image was ignored for comparison purposes so that artifacts on the edges could not skew the correlation. Also, since I was using MATLAB's circshift function, other artifacts were often introduced because parts of the image would be rolled over to the opposite side, again throwing off the scoring. Instead of shifting the reduced image, I shifted the unscaled image, cropped it and then compared. This caused increased runtimes but gave a much more accurate alignment. The downside to this method is that the borders are no longer available as a frame of reference. Some images were thrown off, but on average, the channel alignments improved. One solution to this might be to use the uncropped version for early comparisons to establish a rough alignment and then use a cropped version for precise, final alignment.