implement image gaussian blur with arbitrary number of passes
This commit is contained in:
@@ -74,6 +74,7 @@
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Image/ImageInvertNode.hpp>
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Image/ImageMirrorNode.hpp>
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Image/ImageResizeNode.hpp>
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Image/ImageGaussianBlurNode.hpp>
|
||||
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Noise/NoisePerlinNode.hpp>
|
||||
#include <noggit/Red/NodeEditor/Nodes/Data/Noise/NoiseToImageNode.hpp>
|
||||
@@ -181,6 +182,7 @@ namespace noggit
|
||||
ret->registerModel<ImageSetPixelNode>("Data//Image");
|
||||
ret->registerModel<ImageToGrayscaleNode>("Data//Image");
|
||||
ret->registerModel<ImageMirrorNode>("Data//Image");
|
||||
ret->registerModel<ImageGaussianBlurNode>("Data//Image");
|
||||
|
||||
// Noise
|
||||
ret->registerModel<NoisePerlinNode>("Data//Noise//Generators");
|
||||
|
||||
@@ -37,7 +37,6 @@ void ImageFillNode::compute()
|
||||
|
||||
NodeValidationState ImageFillNode::validate()
|
||||
{
|
||||
|
||||
if (!static_cast<ImageData*>(_in_ports[1].in_value.lock().get()))
|
||||
{
|
||||
setValidationState(NodeValidationState::Error);
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#include "ImageGaussianBlurNode.hpp"
|
||||
#include "gaussianblur.h"
|
||||
|
||||
#include <noggit/Red/NodeEditor/Nodes/BaseNode.inl>
|
||||
#include <noggit/Red/NodeEditor/Nodes/DataTypes/GenericData.hpp>
|
||||
|
||||
using namespace noggit::Red::NodeEditor::Nodes;
|
||||
|
||||
ImageGaussianBlurNode::ImageGaussianBlurNode()
|
||||
: LogicNodeBase()
|
||||
{
|
||||
setName("ImageGaussianBlurNode");
|
||||
setCaption("Image Gaussian Blur");
|
||||
_validation_state = NodeValidationState::Valid;
|
||||
|
||||
addPortDefault<LogicData>(PortType::In, "Logic", true);
|
||||
addPortDefault<ImageData>(PortType::In, "Image", true);
|
||||
addPortDefault<DecimalData>(PortType::In, "Sigma<Decimal>", true);
|
||||
addPortDefault<UnsignedIntegerData>(PortType::In, "Passes<UInteger>", true);
|
||||
auto passes = static_cast<QSpinBox*>(_in_ports[3].default_widget);
|
||||
passes->setValue(1);
|
||||
passes->setMinimum(1);
|
||||
|
||||
addPort<LogicData>(PortType::Out, "Logic", true);
|
||||
addPort<ImageData>(PortType::Out, "Image", true);
|
||||
}
|
||||
|
||||
void ImageGaussianBlurNode::compute()
|
||||
{
|
||||
QImage* image = static_cast<ImageData*>(_in_ports[1].in_value.lock().get())->value_ptr();
|
||||
|
||||
QImage new_image = *image;
|
||||
for (int i = 0; i < defaultPortData<UnsignedIntegerData>(PortType::In, 3)->value(); ++i)
|
||||
{
|
||||
GaussianBlur blur(5.0,
|
||||
std::max(defaultPortData<DecimalData>(PortType::In, 2)->value(), 1.0));
|
||||
|
||||
new_image = blur.ApplyGaussianFilterToImage(new_image);
|
||||
}
|
||||
|
||||
_out_ports[0].out_value = std::make_shared<LogicData>(true);
|
||||
Q_EMIT dataUpdated(0);
|
||||
|
||||
_out_ports[1].out_value = std::make_shared<ImageData>(std::move(new_image));
|
||||
Q_EMIT dataUpdated(1);
|
||||
|
||||
}
|
||||
|
||||
NodeValidationState ImageGaussianBlurNode::validate()
|
||||
{
|
||||
|
||||
if (!static_cast<ImageData*>(_in_ports[1].in_value.lock().get()))
|
||||
{
|
||||
setValidationState(NodeValidationState::Error);
|
||||
setValidationMessage("Error: failed to evaluate image input.");
|
||||
return _validation_state;
|
||||
}
|
||||
|
||||
return LogicNodeBase::validate();
|
||||
}
|
||||
|
||||
QJsonObject ImageGaussianBlurNode::save() const
|
||||
{
|
||||
QJsonObject json_obj = BaseNode::save();
|
||||
|
||||
defaultWidgetToJson(PortType::In, 2, json_obj, "sigma");
|
||||
|
||||
return json_obj;
|
||||
}
|
||||
|
||||
void ImageGaussianBlurNode::restore(const QJsonObject& json_obj)
|
||||
{
|
||||
BaseNode::restore(json_obj);
|
||||
|
||||
defaultWidgetFromJson(PortType::In, 2, json_obj, "sigma");
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
||||
|
||||
#ifndef NOGGIT_IMAGEGAUSSIANBLURNODE_HPP
|
||||
#define NOGGIT_IMAGEGAUSSIANBLURNODE_HPP
|
||||
|
||||
#include <noggit/Red/NodeEditor/Nodes/LogicNodeBase.hpp>
|
||||
|
||||
using QtNodes::PortType;
|
||||
using QtNodes::PortIndex;
|
||||
using QtNodes::NodeData;
|
||||
using QtNodes::NodeDataType;
|
||||
using QtNodes::NodeDataModel;
|
||||
using QtNodes::NodeValidationState;
|
||||
|
||||
|
||||
namespace noggit
|
||||
{
|
||||
namespace Red::NodeEditor::Nodes
|
||||
{
|
||||
class ImageGaussianBlurNode : public LogicNodeBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageGaussianBlurNode();
|
||||
void compute() override;
|
||||
NodeValidationState validate() override;
|
||||
QJsonObject save() const override;
|
||||
void restore(QJsonObject const& json_obj) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //NOGGIT_IMAGEGAUSSIANBLURNODE_HPP
|
||||
172
src/noggit/Red/NodeEditor/Nodes/Data/Image/gaussianblur.cpp
Normal file
172
src/noggit/Red/NodeEditor/Nodes/Data/Image/gaussianblur.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "gaussianblur.h"
|
||||
|
||||
double GaussianBlur::GetNumberOnNormalDistribution(int i, int j, const int center, double sigma) const
|
||||
{
|
||||
return (1.0 / (2 * M_PI * pow(sigma, 2)) * exp ( - (pow(i - center, 2) + pow(j - center, 2)) / (2 * pow(sigma, 2))));
|
||||
}
|
||||
|
||||
|
||||
void GaussianBlur::GetPixelMatrix(const QPoint ¢er, const QImage &image, QRgb** matrix)
|
||||
{
|
||||
QSize image_size = image.size();
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
matrix[i][j] = image.pixel(GetCoordinate(QPoint(i, j) + center, image_size));
|
||||
}
|
||||
|
||||
|
||||
QRgb GaussianBlur::GetNewPixelValue(QRgb **matrix)
|
||||
{
|
||||
QRgb result = 0;
|
||||
double red = 0;
|
||||
double blue = 0;
|
||||
double green = 0;
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++) {
|
||||
red += qRed(matrix[i][j]) * matrix_[i][j];
|
||||
blue += qBlue(matrix[i][j]) * matrix_[i][j];
|
||||
green += qGreen(matrix[i][j]) * matrix_[i][j];
|
||||
}
|
||||
result = qRgb(red, green, blue);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
QPoint GaussianBlur::GetCoordinate(const QPoint &point, const QSize &image_size) {
|
||||
QPoint result(point);
|
||||
result.setX(result.x() - radius_);
|
||||
result.setY(result.y() - radius_);
|
||||
if (result.x() < 0)
|
||||
result.setX(0);
|
||||
if (result.y() < 0)
|
||||
result.setY(0);
|
||||
if (result.x() >= image_size.width())
|
||||
result.setX(image_size.width() - 1);
|
||||
if (result.y() >= image_size.height())
|
||||
result.setY(image_size.height() - 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void GaussianBlur::NormilizeElementsBySum() {
|
||||
double sum = GetSumElements();
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
matrix_[i][j] /= sum;
|
||||
}
|
||||
|
||||
|
||||
GaussianBlur::GaussianBlur(int radius, double sigma) :
|
||||
radius_ (radius),
|
||||
diviation_ (sigma),
|
||||
values_is_set_ (false)
|
||||
{
|
||||
if (true == (radius_ % 2))
|
||||
{
|
||||
size_ = 2 * radius_ + 1;
|
||||
matrix_ = new double* [size_];
|
||||
for (int i = 0; i < size_; i++)
|
||||
matrix_[i] = new double [size_];
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
matrix_[i][j] = GetNumberOnNormalDistribution(i, j, radius_, diviation_);
|
||||
NormilizeElementsBySum();
|
||||
values_is_set_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GaussianBlur::GaussianBlur(const GaussianBlur &original):
|
||||
radius_(original.radius_),
|
||||
diviation_(original.diviation_)
|
||||
{
|
||||
size_ = 2 * radius_ + 1;
|
||||
matrix_ = new double* [size_];
|
||||
|
||||
for (int i = 0; i < size_; i++)
|
||||
matrix_[i] = new double [size_];
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
matrix_[i][j] = original.matrix_[i][j];
|
||||
}
|
||||
|
||||
|
||||
GaussianBlur::~GaussianBlur()
|
||||
{
|
||||
for (int i = 0; i < size_; i++)
|
||||
delete[] matrix_[i];
|
||||
|
||||
delete[] matrix_;
|
||||
}
|
||||
|
||||
|
||||
double GaussianBlur::GetSumElements() const
|
||||
{
|
||||
double result = 0;
|
||||
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
result += matrix_[i][j];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
QImage GaussianBlur::ApplyGaussianFilterToImage(const QImage& input)
|
||||
{
|
||||
if (true == values_is_set_)
|
||||
{
|
||||
QImage output(input);
|
||||
QRgb **temp = new QRgb* [size_];
|
||||
for (int i = 0; i < size_; i++)
|
||||
temp[i] = new QRgb [size_];
|
||||
|
||||
for (int i = 0; i < output.width(); i++)
|
||||
for (int j = 0; j < output.height(); j++)
|
||||
{
|
||||
GetPixelMatrix(QPoint(i, j), output, temp);
|
||||
output.setPixel(QPoint(i,j), GetNewPixelValue(temp));
|
||||
}
|
||||
|
||||
for (int i = 0; i < size_; i++)
|
||||
delete[] temp[i];
|
||||
delete[] temp;
|
||||
|
||||
return output;
|
||||
} else
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
const GaussianBlur& GaussianBlur::operator = (const GaussianBlur &blur)
|
||||
{
|
||||
if (this != &blur)
|
||||
{
|
||||
for (int i = 0; i < size_; i ++)
|
||||
delete[] matrix_[i];
|
||||
delete[] matrix_;
|
||||
|
||||
radius_ = blur.radius_;
|
||||
diviation_ = blur.diviation_;
|
||||
size_ = blur.size_;
|
||||
matrix_ = new double* [size_];
|
||||
|
||||
for (int i = 0; i < size_; i++)
|
||||
matrix_[i] = new double [size_];
|
||||
for (int i = 0; i < size_; i++)
|
||||
for (int j = 0; j < size_; j++)
|
||||
matrix_[i][j] = blur.matrix_[i][j];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
QTextStream &operator << (QTextStream &stream, const GaussianBlur &blur) {
|
||||
stream.setRealNumberPrecision(6);
|
||||
for (int i = 0; i < blur.size_; i++) {
|
||||
for (int j = 0; j < blur.size_; j++)
|
||||
stream << blur.matrix_[i][j] << " ";
|
||||
stream << endl;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
37
src/noggit/Red/NodeEditor/Nodes/Data/Image/gaussianblur.h
Normal file
37
src/noggit/Red/NodeEditor/Nodes/Data/Image/gaussianblur.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef GAUSSIANBLUR_H
|
||||
#define GAUSSIANBLUR_H
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QImage>
|
||||
#include <qmath.h>
|
||||
|
||||
class GaussianBlur
|
||||
{
|
||||
private:
|
||||
int radius_;
|
||||
int size_;
|
||||
double diviation_;
|
||||
bool values_is_set_;
|
||||
double **matrix_;
|
||||
|
||||
private:
|
||||
double GetNumberOnNormalDistribution(int x, int y, const int center, double sigma) const;
|
||||
void GetPixelMatrix(const QPoint ¢er, const QImage &image, QRgb **matrix);
|
||||
QRgb GetNewPixelValue(QRgb** matrix);
|
||||
QPoint GetCoordinate(const QPoint &point, const QSize &image_size);
|
||||
void NormilizeElementsBySum();
|
||||
|
||||
public:
|
||||
explicit GaussianBlur(int radius = 1, double sigma = 1.0);
|
||||
GaussianBlur(const GaussianBlur &original);
|
||||
~GaussianBlur();
|
||||
|
||||
double GetSumElements() const;
|
||||
QImage ApplyGaussianFilterToImage(const QImage& input);
|
||||
|
||||
const GaussianBlur &operator = (const GaussianBlur &blur);
|
||||
friend QTextStream &operator << (QTextStream &stream, const GaussianBlur &blur);
|
||||
|
||||
};
|
||||
|
||||
#endif // GAUSSIANBLUR_H
|
||||
Reference in New Issue
Block a user