aboutsummaryrefslogtreecommitdiff
path: root/helium/gaussiansmooth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'helium/gaussiansmooth.cpp')
-rw-r--r--helium/gaussiansmooth.cpp101
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;
+}