Bloom shader finished

This commit is contained in:
m.gaedke 2023-01-25 10:20:27 +01:00
parent 9a8d6bcccd
commit 0d4814c901
5 changed files with 100 additions and 108 deletions

View file

@ -3,6 +3,7 @@
#include <fstream>
#include <iostream>
#include <string>
#include <utility>
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<float> kernel = computeGaussianKernel(kernelSize, sigma);
image_ = convolution(image_, kernel);
CImg<float> Texture::getImage() {
return image_;
}
// Function to compute Gaussian kernel
CImg<float> Texture::computeGaussianKernel(int kernelSize, float sigma) {
// Create kernel
CImg<float> 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<float> image){
image_ = std::move(image);
}
// Function to perform convolution
CImg<float> Texture::convolution(CImg<float> &img, CImg<float> &kernel) {
int kernelSize = kernel.width();
int imgRows = img.height();
int imgCols = img.width();
CImg<float> 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;
}

View file

@ -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<float> image);
// Color functions
Color color(float u, float v, bool interpolate = true) const;
Color color(Vector2d const &surfacePosition, bool interpolate = true) const;
CImg<float> getImage();
private:
// Function to compute Gaussian kernel
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
// Function to perform convolution
CImg<float> convolution(CImg<float> &img, CImg<float> &kernel);
CImg<float> image_;
};

View file

@ -2,43 +2,87 @@
#include <iostream>
#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<float> 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));
}
}
}
thresholdImage.save("maskResult.png");
image.save("originalPicture.png");
}
Texture Bloomshader::getimage() {
CImg<float> Bloomshader::bloom(float threshold, int kernelSize, float sigma, float intensity) {
// Apply threshold to image
//CImg<float> brightPixels = image_.get_threshold(threshold);
//brightPixels.save("brightpixels.png");
// Apply gaussian blur to bright pixels
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
CImg<float> 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;
}
return image;
}
void Bloomshader::bloomshader() {
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);
}
}
void Bloomshader::gaussianBlur(int kernelSize, float sigma) {
CImg<float> kernel = computeGaussianKernel(kernelSize, sigma);
image = convolution(image, kernel);
}
float Bloomshader::luminance(Color color) {
return dotProduct(Vector3d(color.r, color.g, color.b), Vector3d(0.2126, 0.7152, 0.0722));
// Function to compute Gaussian kernel
CImg<float> Bloomshader::computeGaussianKernel(int kernelSize, float sigma) {
// Create kernel
CImg<float> 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;
}
// Function to perform convolution
CImg<float> Bloomshader::convolution(CImg<float> &img, CImg<float> &kernel) {
int kernelSize = kernel.width();
int imgRows = img.height();
int imgCols = img.width();
CImg<float> 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;
}

View file

@ -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<float> image);
CImg<float> 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<float> convolution(CImg<float> &img, CImg<float> &kernel);
CImg<float> computeGaussianKernel(int kernelSize, float sigma);
CImg<float> image;
};

View file

@ -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;
}