diff options
Diffstat (limited to 'helium/gaussiansmooth.cpp')
-rw-r--r-- | helium/gaussiansmooth.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/helium/gaussiansmooth.cpp b/helium/gaussiansmooth.cpp new file mode 100644 index 0000000..109e79c --- /dev/null +++ b/helium/gaussiansmooth.cpp @@ -0,0 +1,101 @@ +// Copyright 2006 Google Inc. +// All Rights Reserved. +// Author: <renn@google.com> (Marius Renn) + +// Local includes +#include "color.h" +#include "debugging.h" +#include "gaussiansmooth.h" +#include "point.h" +#include "mathfunctions.h" + +using namespace helium; + +GaussianSmooth::GaussianSmooth(unsigned size) : + kernel_size_(size + 1), + gauss_sum_(0), + kernel_(new int[size + 1]) { + + // Create gaussian mask by calculating the binomial coefficients. We will + // later divide by the sum of these coefficients to obtain the output value. + for (unsigned i = 0; i < kernel_size_; i ++) { + int coeff = Binomi(size + 1, i + 1); + kernel_[i] = coeff; + gauss_sum_ += coeff; + } +} + +GaussianSmooth::~GaussianSmooth() { + delete[] kernel_; +} + +Image GaussianSmooth::Smooth(const Image& image) { + ASSERT(kernel_); + + // Create intermediate and destination images + Image temp(image.width(), image.height()); + Image dest(image.width(), image.height()); + ASSERT(temp.Valid() && dest.Valid()); + + int s = kernel_size_ / 2; + Color pixel; + Point p; + int r, g, b; + int row = image.width(); + + // Setup data pointers + Color* src_ptr = image.Access(s, s); + Color* temp_ptr = temp.Access(s, s); + Color* dest_ptr = dest.Access(s, s); + + // First pass (horizontal smoothing) + for (p.y = s; p.y < image.height() - s; p.y++) { + for (p.x = s; p.x < image.width() - s; p.x++) { + int r_gauss = 0; + int g_gauss = 0; + int b_gauss = 0; + for (int i = 0; i < kernel_size_; i++) { + pixel = *(src_ptr + i - s); + ColorSeparate(pixel, r, g, b); + r_gauss += r * kernel_[i]; + g_gauss += g * kernel_[i]; + b_gauss += b * kernel_[i]; + } + r_gauss /= gauss_sum_; + g_gauss /= gauss_sum_; + b_gauss /= gauss_sum_; + + *(temp_ptr++) = MakeColor(r_gauss, g_gauss, b_gauss); + src_ptr++; + } + src_ptr += s*2; + temp_ptr += s*2; + } + + // Second pass (vertical smoothing) + temp_ptr = temp.Access(s, s); + for (p.y = s; p.y < image.height() - s; p.y++) { + for (p.x = s; p.x < image.width() - s; p.x++) { + int r_gauss = 0; + int g_gauss = 0; + int b_gauss = 0; + for (int i = 0; i < kernel_size_; i++) { + pixel = *(temp_ptr + (i - s) * row); + ColorSeparate(pixel, r, g, b); + + r_gauss += r * kernel_[i]; + g_gauss += g * kernel_[i]; + b_gauss += b * kernel_[i]; + } + r_gauss /= gauss_sum_; + g_gauss /= gauss_sum_; + b_gauss /= gauss_sum_; + + *(dest_ptr++) = MakeColor(r_gauss, g_gauss, b_gauss); + temp_ptr++; + } + dest_ptr += s*2; + temp_ptr += s*2; + } + return dest; +} |