Original implementation of Sharpen Image filters

This commit is contained in:
Bruno Herbelin
2022-05-31 22:53:28 +02:00
parent e3bb95b3dd
commit 7c850b0405
12 changed files with 153 additions and 57 deletions

View File

@@ -150,6 +150,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
case FrameBufferFilter::FILTER_BLUR:
filter_ = new BlurFilter;
break;
case FrameBufferFilter::FILTER_SHARPEN:
filter_ = new SharpenFilter;
break;
case FrameBufferFilter::FILTER_IMAGE:
filter_ = new ImageFilter;
break;

View File

@@ -6,7 +6,7 @@
#include "FrameBufferFilter.h"
const char* FrameBufferFilter::type_label[FrameBufferFilter::FILTER_INVALID] = {
"None", "Delay", "Blur", "Shader code"
"None", "Delay", "Blur", "Sharpen", "Shader code"
};
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)

View File

@@ -21,6 +21,7 @@ public:
FILTER_PASSTHROUGH = 0,
FILTER_DELAY,
FILTER_BLUR,
FILTER_SHARPEN,
FILTER_IMAGE,
FILTER_INVALID
} Type;

View File

@@ -818,6 +818,51 @@ void ImGuiVisitor::visit (BlurFilter& f)
}
void ImGuiVisitor::visit (SharpenFilter& f)
{
std::ostringstream oss;
oss << "Blur ";
// Method selection
if (ImGuiToolkit::IconButton(7, 16)) {
f.setMethod( 0 );
oss << SharpenFilter::method_label[0];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.method();
if (ImGui::Combo("Method", &m, SharpenFilter::method_label, IM_ARRAYSIZE(SharpenFilter::method_label) )) {
f.setMethod( m );
oss << SharpenFilter::method_label[m];
Action::manager().store(oss.str());
}
// List of parameters
std::map<std::string, float> filter_parameters = f.program().parameters();
for (auto param = filter_parameters.begin(); param != filter_parameters.end(); ++param)
{
ImGui::PushID( param->first.c_str() );
float v = param->second;
if (ImGuiToolkit::IconButton(13, 14)) {
v = 0.f;
f.setProgramParameter(param->first, v);
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( param->first.c_str(), &v, 0.f, 1.f, "%.2f")) {
f.setProgramParameter(param->first, v);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << SharpenFilter::method_label[ f.method() ];
oss << " : " << param->first << " " << std::setprecision(3) <<param->second;
Action::manager().store(oss.str());
}
ImGui::PopID();
}
}
void ImGuiVisitor::visit (ImageFilter& f)
{
// Selection of Algorithm

View File

@@ -40,6 +40,7 @@ public:
void visit (PassthroughFilter&) override;
void visit (DelayFilter&) override;
void visit (BlurFilter&) override;
void visit (SharpenFilter&) override;
void visit (ImageFilter&) override;
};

View File

@@ -485,15 +485,15 @@ void ImageFilter::setProgramParameter(const std::string &p, float value)
////////////////////////////////////////
const char* BlurFilter::method_label[BlurFilter::BLUR_INVALID] = {
"Gaussian", "Hash", "Openning", "Closing", "Fast 2x2"
"Gaussian", "Scattered", "Opening", "Closing", "Fast"
};
std::vector< FilteringProgram > BlurFilter::programs_ = {
FilteringProgram("Gaussian", "shaders/filters/blur_1.glsl", "shaders/filters/blur_2.glsl", { { "Radius", 0.5} }),
FilteringProgram("Hashed", "shaders/filters/hashedblur.glsl", "", { { "Iterations", 0.5 }, { "Radius", 0.5} }),
FilteringProgram("Openning", "shaders/filters/hashederosion.glsl", "shaders/filters/hasheddilation.glsl", { { "Radius", 0.5} }),
FilteringProgram("Scattered","shaders/filters/hashedblur.glsl", "", { { "Radius", 0.5}, { "Iterations", 0.25 } }),
FilteringProgram("Opening", "shaders/filters/hashederosion.glsl", "shaders/filters/hasheddilation.glsl", { { "Radius", 0.5} }),
FilteringProgram("Closing", "shaders/filters/hasheddilation.glsl","shaders/filters/hashederosion.glsl", { { "Radius", 0.5} }),
FilteringProgram("Fast 2x2", "shaders/filters/blur.glsl", "", { })
FilteringProgram("Fast", "shaders/filters/blur.glsl", "", { })
};
BlurFilter::BlurFilter (): ImageFilter(), method_(BLUR_INVALID), mipmap_buffer_(nullptr)
@@ -588,4 +588,37 @@ void BlurFilter::accept (Visitor& v)
}
////////////////////////////////////////
///// //
//// SHARPENING FILTERS ///
/// ////
////////////////////////////////////////
const char* SharpenFilter::method_label[SharpenFilter::SHARPEN_INVALID] = {
"Unsharp mask", "Convolution", "Edge"
};
std::vector< FilteringProgram > SharpenFilter::programs_ = {
FilteringProgram("Unsharp Mask", "shaders/filters/sharpen_1.glsl", "shaders/filters/sharpen_2.glsl", { { "Amount", 0.5} }),
FilteringProgram("Sharpen", "shaders/filters/sharp.glsl", "", { { "Amount", 0.5} }),
FilteringProgram("Sharp Edge", "shaders/filters/bilinear.glsl", "shaders/filters/sharpenedge.glsl", { { "Strength", 0.5} }),
};
SharpenFilter::SharpenFilter (): ImageFilter(), method_(SHARPEN_INVALID)
{
}
void SharpenFilter::setMethod(int method)
{
method_ = (SharpenMethod) CLAMP(method, SHARPEN_MASK, SHARPEN_INVALID-1);
setProgram( programs_[ (int) method_] );
}
void SharpenFilter::accept (Visitor& v)
{
FrameBufferFilter::accept(v);
v.visit(*this);
}

View File

@@ -137,6 +137,33 @@ private:
};
class SharpenFilter : public ImageFilter
{
public:
SharpenFilter();
// Algorithms used for sharpen
typedef enum {
SHARPEN_MASK = 0,
SHARPEN_CONVOLUTION,
SHARPEN_EDGE,
SHARPEN_INVALID
} SharpenMethod;
static const char* method_label[SHARPEN_INVALID];
SharpenMethod method () const { return method_; }
void setMethod(int method);
// implementation of FrameBufferFilter
Type type() const override { return FrameBufferFilter::FILTER_SHARPEN; }
void accept (Visitor& v) override;
private:
SharpenMethod method_;
static std::vector< FilteringProgram > programs_;
};
#endif // IMAGEFILTER_H

View File

@@ -45,6 +45,7 @@ class FrameBufferFilter;
class PassthroughFilter;
class DelayFilter;
class BlurFilter;
class SharpenFilter;
class ImageFilter;
class SourceCallback;
@@ -106,6 +107,7 @@ public:
virtual void visit (PassthroughFilter&) {}
virtual void visit (DelayFilter&) {}
virtual void visit (BlurFilter&) {}
virtual void visit (SharpenFilter&) {}
virtual void visit (ImageFilter&) {}
virtual void visit (SourceCallback&) {}

View File

@@ -40,7 +40,7 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord )
vec4 O = vec4(1.);
float N = 17;
for (float i = 0.; i < N; i++) {
vec2 q = vec2(cos(TWOPI*((i+.5)/N)) * ar, sin(TWOPI*(i+.5)/N)) * Hash01(uv, floatBitsToUint(i));
vec2 q = vec2(cos(TWOPI*((i+.5)/N)) * ar, sin(TWOPI*(i+.5)/N)) * (0.1 + 0.9 * Hash01(uv, floatBitsToUint(i)));
// vec2 q = vec2(cos(TWOPI*((i+.5)/N)) * ar, sin(TWOPI*(i+.5)/N)) * hash(vec2(i + 12., uv.x * uv.y + 24.));
O = min( texture(iChannel0, uv + q*R), O );
}

View File

@@ -41,7 +41,7 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord )
vec4 O = vec4(0.);
float N = 17;
for (float i = 0.; i < N; i++) {
vec2 q = vec2(cos(TWOPI*i/N) * ar, sin(TWOPI*i/N)) * Hash01(uv, floatBitsToUint(i) );
vec2 q = vec2(cos(TWOPI*i/N) * ar, sin(TWOPI*i/N)) * (0.1 + 0.9 * Hash01(uv, floatBitsToUint(i)));
// vec2 q = vec2(cos(TWOPI*i/N) * ar, sin(TWOPI*i/N)) * hash(vec2(i, uv.x + uv.y));
O = max( texture(iChannel0, uv + q*R), O );
}

View File

@@ -1,30 +1,22 @@
uniform float Amount;
float SCurve (float x) {
x = x * 2.0 - 1.0;
return -x * abs(x) * 0.5 + x + 0.5;
#define N 7
vec4 blur1D(vec2 U, vec2 D, float rad)
{
float w = rad * iResolution.y;
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
vec4 O = vec4(0);
float r = float(N-1)/2., g, t=0., x;
for( int k=0; k<N; k++ ) {
x = float(k)/r -1.;
t += g = exp(-2.*x*x );
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
}
vec3 BlurV (sampler2D source, vec2 uv, float step, float radius) {
vec3 C = vec3(0.0);
float divisor = 0.0;
float weight = 0.0;
float radiusMultiplier = 1.0 / max(1.0, radius);
// loop on pixels in Y to apply vertical blur
for (float y = -radius; y <= radius; y++) {
weight = SCurve(1.0 - (abs(y) * radiusMultiplier));
C += texture(source, uv + vec2(0.0, y * step)).rgb * weight;
divisor += weight;
}
return C / divisor;
return O/t;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
// Apply vertical blur
fragColor = vec4( BlurV(iChannel0, uv, 1.0 / iResolution.y, mix(1.0, 0.1*iResolution.y, Amount)), 1.0);
fragColor = blur1D(fragCoord, vec2(1,0), 0.1 * Amount);
}

View File

@@ -1,37 +1,29 @@
uniform float Amount;
float SCurve (float x) {
x = x * 2.0 - 1.0;
return -x * abs(x) * 0.5 + x + 0.5;
#define N 7
vec4 blur1D(vec2 U, vec2 D, float rad)
{
float w = rad * iResolution.y;
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
vec4 O = vec4(0);
float r = float(N-1)/2., g, t=0., x;
for( int k=0; k<N; k++ ) {
x = float(k)/r -1.;
t += g = exp(-2.*x*x );
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
}
vec3 BlurH (sampler2D source, vec2 uv, float step, float radius) {
vec3 C = vec3(0.0);
float divisor = 0.0;
float weight = 0.0;
float radiusMultiplier = 1.0 / max(1.0, radius);
// loop on pixels in X to apply horizontal blur
for (float x = -radius; x <= radius; x++) {
weight = SCurve(1.0 - (abs(x) * radiusMultiplier));
C += texture(source, uv + vec2(x * step, 0.0)).rgb * weight;
divisor += weight;
}
return C / divisor;
return O/t;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord.xy / iResolution.xy;
// get original image
vec3 c = texture(iChannel1, uv).rgb;
vec4 c = texture(iChannel1, fragCoord.xy / iResolution.xy);
// Remove blurred image to original image
vec3 lumcoeff = vec3(0.299,0.587,0.114);
float luminance = dot( c - BlurH(iChannel0, uv, 1.0 / iResolution.x, mix(1.0, 0.1*iResolution.y, Amount) ), lumcoeff);
vec4 lumcoeff = vec4(0.299, 0.587, 0.114, 1.);
float luminance = dot( c - blur1D(fragCoord, vec2(0,1), 0.1 * Amount ), lumcoeff);
// composition
fragColor = vec4( c + vec3(luminance), 1.0);
fragColor = c + vec4(luminance);
}