diff --git a/common/texture.cpp b/common/texture.cpp index 6f7e845..30a5238 100644 --- a/common/texture.cpp +++ b/common/texture.cpp @@ -3,6 +3,7 @@ #include #include #include +#include Texture::Texture(int width, int height) { this->resize(width, height); } @@ -84,61 +85,11 @@ Color Texture::color(Vector2d const &surfacePosition, bool interpolate) const { return color(surfacePosition.u, surfacePosition.v, interpolate); } -void Texture::gaussianBlur(int kernelSize, float sigma) { - CImg kernel = computeGaussianKernel(kernelSize, sigma); - image_ = convolution(image_, kernel); +CImg Texture::getImage() { + return image_; } -// Function to compute Gaussian kernel -CImg Texture::computeGaussianKernel(int kernelSize, float sigma) { - // Create kernel - CImg kernel(kernelSize, kernelSize, 1, 1); - - // Compute Gaussian kernel - float sum = 0.0f; - int i, j; - for (i = 0; i < kernelSize; i++) { - for (j = 0; j < kernelSize; j++) { - kernel(i, j) = exp(-0.5f * (pow((i - kernelSize / 2.f) / sigma, 2.f) + - pow((j - kernelSize / 2.f) / sigma, 2.f))) / (2 * M_PI * sigma * sigma); - sum += kernel(i, j); - } - } - - // Normalize kernel - kernel /= sum; - - return kernel; +void Texture::setTexture(CImg image){ + image_ = std::move(image); } -// Function to perform convolution -CImg Texture::convolution(CImg &img, CImg &kernel) { - int kernelSize = kernel.width(); - int imgRows = img.height(); - int imgCols = img.width(); - CImg result(imgCols, imgRows, 1, 3); - float sum; - int i, j, m, n; - int kernelRadius = kernelSize / 2; - - // Perform convolution - cimg_forXYC(img, i, j, c) { - sum = 0; - cimg_forY(kernel, m) { - cimg_forX(kernel, n) { - int x = i + n - kernelRadius; - int y = j + m - kernelRadius; - if(x >= 0 && x < imgCols && y >= 0 && y < imgRows){ - sum += img(x, y, 0, c) * kernel(n, m); - } - - } - } - result(i, j, 0, c) = sum; - } - return result; -} - -void Texture::scaleBrightness(float scale) { - image_ *= scale; -} diff --git a/common/texture.h b/common/texture.h index 184a754..4eb21c6 100644 --- a/common/texture.h +++ b/common/texture.h @@ -18,12 +18,6 @@ public: bool load(char const *fileName); bool save(char const *fileName) const; - // Gaussian blur function - void gaussianBlur(int kernelSize, float sigma); - - // Scale function - void scaleBrightness(float scale); - // Get inline bool isNull() const { return this->image_.is_empty(); } inline int width() const { return this->image_.width(); } @@ -32,18 +26,16 @@ public: // Set void setPixelAt(int x, int y, Color const &color); + void setTexture(CImg image); + // Color functions Color color(float u, float v, bool interpolate = true) const; Color color(Vector2d const &surfacePosition, bool interpolate = true) const; + CImg getImage(); + private: - // Function to compute Gaussian kernel - CImg computeGaussianKernel(int kernelSize, float sigma); - - // Function to perform convolution - CImg convolution(CImg &img, CImg &kernel); - CImg image_; }; diff --git a/post-processing/bloomshader.cpp b/post-processing/bloomshader.cpp index 5a0ab26..62cb032 100644 --- a/post-processing/bloomshader.cpp +++ b/post-processing/bloomshader.cpp @@ -2,43 +2,87 @@ #include #include "bloomshader.h" -Bloomshader::Bloomshader(Texture image, float threshold, int blurRange) : image(image), threshold(threshold), blurRange(blurRange), - thresholdImage(Texture(image.width() + 2 * blurRange, image.height() + 2 * blurRange)) {} +Bloomshader::Bloomshader(CImg image) : image(image) {} -void Bloomshader::thresholdshader() { - for(int i = 0; i < image.width(); i++) { - for(int j = 0; j < image.height(); j++){ - if(luminance(image.getPixelAt(i, j)) < threshold){ - thresholdImage.setPixelAt(i + blurRange, j + blurRange, Color(0, 0, 0)); - } else { - thresholdImage.setPixelAt(i + blurRange, j + blurRange, image.getPixelAt(i, j)); - } - } + +CImg Bloomshader::bloom(float threshold, int kernelSize, float sigma, float intensity) { + // Apply threshold to image + //CImg brightPixels = image_.get_threshold(threshold); + //brightPixels.save("brightpixels.png"); + + // Apply gaussian blur to bright pixels + CImg kernel = computeGaussianKernel(kernelSize, sigma); + CImg blurred = convolution(image, kernel); + for(int i = 0; i < 3; i++){ + kernel = computeGaussianKernel(kernelSize, sigma); + blurred = convolution(image, kernel); + blurred *= intensity; + } + + // Add blurred image back to original image + cimg_forXYC(image, x, y, c) { + float value = image(x,y,0,c) + blurred(x,y,0,c); + image(x,y,0,c) = (value > 1.0f) ? 1.0f : value; } - thresholdImage.save("maskResult.png"); - image.save("originalPicture.png"); -} -Texture Bloomshader::getimage() { return image; } +void Bloomshader::gaussianBlur(int kernelSize, float sigma) { + CImg kernel = computeGaussianKernel(kernelSize, sigma); + image = convolution(image, kernel); +} -void Bloomshader::bloomshader() { +// Function to compute Gaussian kernel +CImg Bloomshader::computeGaussianKernel(int kernelSize, float sigma) { + // Create kernel + CImg kernel(kernelSize, kernelSize, 1, 1); - thresholdImage.gaussianBlur(blurRange * 2, 8.5f); - thresholdImage.scaleBrightness(0.3f); - - thresholdImage.save("blurredMaskResult.png"); - - for(int i = 0; i < image.width(); i++) { - for(int j = 0; j < image.height(); j++){ - Color temp = clamped(image.getPixelAt(i, j) + thresholdImage.getPixelAt(i + blurRange, j + blurRange)); - image.setPixelAt(i, j, temp); + // Compute Gaussian kernel + float sum = 0.0f; + int i, j; + for (i = 0; i < kernelSize; i++) { + for (j = 0; j < kernelSize; j++) { + kernel(i, j) = exp(-0.5f * (pow((i - kernelSize / 2.f) / sigma, 2.f) + + pow((j - kernelSize / 2.f) / sigma, 2.f))) / (2 * M_PI * sigma * sigma); + sum += kernel(i, j); } } + + // Normalize kernel + kernel /= sum; + + return kernel; } -float Bloomshader::luminance(Color color) { - return dotProduct(Vector3d(color.r, color.g, color.b), Vector3d(0.2126, 0.7152, 0.0722)); +// Function to perform convolution +CImg Bloomshader::convolution(CImg &img, CImg &kernel) { + int kernelSize = kernel.width(); + int imgRows = img.height(); + int imgCols = img.width(); + CImg result(imgCols, imgRows, 1, 3); + float sum; + int i, j, m, n; + int kernelRadius = kernelSize / 2; + + // Perform convolution + cimg_forXYC(img, i, j, c) { + sum = 0; + cimg_forY(kernel, m) { + cimg_forX(kernel, n) { + int x = i + n - kernelRadius; + int y = j + m - kernelRadius; + if(x >= 0 && x < imgCols && y >= 0 && y < imgRows){ + sum += img(x, y, 0, c) * kernel(n, m); + } + + } + } + result(i, j, 0, c) = sum; + } + return result; +} + +void Bloomshader::scaleBrightness(float scale) { + image *= scale; } diff --git a/post-processing/bloomshader.h b/post-processing/bloomshader.h index 403e7a7..addcf0a 100644 --- a/post-processing/bloomshader.h +++ b/post-processing/bloomshader.h @@ -8,19 +8,19 @@ class Bloomshader { public: - Bloomshader(Texture image, float threshold, int blurRange); - void thresholdshader(); - Texture getimage(); - //void gaussianBlur(int x, int y); - void bloomshader(); - float luminance(Color color); - + Bloomshader(CImg image); + CImg bloom(float threshold, int kernelSize, float sigma, float intensity); private: - Texture image; - Texture thresholdImage; - float threshold; - int blurRange; + void scaleBrightness(float scale); + void gaussianBlur(int kernelSize, float sigma); + + CImg convolution(CImg &img, CImg &kernel); + CImg computeGaussianKernel(int kernelSize, float sigma); + + + + CImg image; }; diff --git a/renderer/simplerenderer.cpp b/renderer/simplerenderer.cpp index 6762ee6..ffd69e2 100644 --- a/renderer/simplerenderer.cpp +++ b/renderer/simplerenderer.cpp @@ -76,10 +76,15 @@ Texture SimpleRenderer::renderImage(Scene const &scene, Camera const &camera, in // Post-processing // Bloom shader - Bloomshader bloomshader = Bloomshader(image, 0.68f, 30); - bloomshader.thresholdshader(); - bloomshader.bloomshader(); - image = bloomshader.getimage(); + //Bloomshader bloomshader = Bloomshader(image, 0.48f, 10); + //bloomshader.thresholdshader(); + + image.save("original.png"); + + Bloomshader bloomEffect = Bloomshader(image.getImage()); + image.setTexture(bloomEffect.bloom(0.55f, 5, 10.0f, 0.06f)); + + //image = bloomshader.getimage(); return image; }