mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 02:40:00 +01:00
Original implementation of Sharpen Image filters
This commit is contained in:
@@ -150,6 +150,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
|
|||||||
case FrameBufferFilter::FILTER_BLUR:
|
case FrameBufferFilter::FILTER_BLUR:
|
||||||
filter_ = new BlurFilter;
|
filter_ = new BlurFilter;
|
||||||
break;
|
break;
|
||||||
|
case FrameBufferFilter::FILTER_SHARPEN:
|
||||||
|
filter_ = new SharpenFilter;
|
||||||
|
break;
|
||||||
case FrameBufferFilter::FILTER_IMAGE:
|
case FrameBufferFilter::FILTER_IMAGE:
|
||||||
filter_ = new ImageFilter;
|
filter_ = new ImageFilter;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "FrameBufferFilter.h"
|
#include "FrameBufferFilter.h"
|
||||||
|
|
||||||
const char* FrameBufferFilter::type_label[FrameBufferFilter::FILTER_INVALID] = {
|
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)
|
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public:
|
|||||||
FILTER_PASSTHROUGH = 0,
|
FILTER_PASSTHROUGH = 0,
|
||||||
FILTER_DELAY,
|
FILTER_DELAY,
|
||||||
FILTER_BLUR,
|
FILTER_BLUR,
|
||||||
|
FILTER_SHARPEN,
|
||||||
FILTER_IMAGE,
|
FILTER_IMAGE,
|
||||||
FILTER_INVALID
|
FILTER_INVALID
|
||||||
} Type;
|
} Type;
|
||||||
|
|||||||
@@ -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)
|
void ImGuiVisitor::visit (ImageFilter& f)
|
||||||
{
|
{
|
||||||
// Selection of Algorithm
|
// Selection of Algorithm
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public:
|
|||||||
void visit (PassthroughFilter&) override;
|
void visit (PassthroughFilter&) override;
|
||||||
void visit (DelayFilter&) override;
|
void visit (DelayFilter&) override;
|
||||||
void visit (BlurFilter&) override;
|
void visit (BlurFilter&) override;
|
||||||
|
void visit (SharpenFilter&) override;
|
||||||
void visit (ImageFilter&) override;
|
void visit (ImageFilter&) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -485,15 +485,15 @@ void ImageFilter::setProgramParameter(const std::string &p, float value)
|
|||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
const char* BlurFilter::method_label[BlurFilter::BLUR_INVALID] = {
|
const char* BlurFilter::method_label[BlurFilter::BLUR_INVALID] = {
|
||||||
"Gaussian", "Hash", "Openning", "Closing", "Fast 2x2"
|
"Gaussian", "Scattered", "Opening", "Closing", "Fast"
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector< FilteringProgram > BlurFilter::programs_ = {
|
std::vector< FilteringProgram > BlurFilter::programs_ = {
|
||||||
FilteringProgram("Gaussian", "shaders/filters/blur_1.glsl", "shaders/filters/blur_2.glsl", { { "Radius", 0.5} }),
|
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("Scattered","shaders/filters/hashedblur.glsl", "", { { "Radius", 0.5}, { "Iterations", 0.25 } }),
|
||||||
FilteringProgram("Openning", "shaders/filters/hashederosion.glsl", "shaders/filters/hasheddilation.glsl", { { "Radius", 0.5} }),
|
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("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)
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
#endif // IMAGEFILTER_H
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class FrameBufferFilter;
|
|||||||
class PassthroughFilter;
|
class PassthroughFilter;
|
||||||
class DelayFilter;
|
class DelayFilter;
|
||||||
class BlurFilter;
|
class BlurFilter;
|
||||||
|
class SharpenFilter;
|
||||||
class ImageFilter;
|
class ImageFilter;
|
||||||
|
|
||||||
class SourceCallback;
|
class SourceCallback;
|
||||||
@@ -106,6 +107,7 @@ public:
|
|||||||
virtual void visit (PassthroughFilter&) {}
|
virtual void visit (PassthroughFilter&) {}
|
||||||
virtual void visit (DelayFilter&) {}
|
virtual void visit (DelayFilter&) {}
|
||||||
virtual void visit (BlurFilter&) {}
|
virtual void visit (BlurFilter&) {}
|
||||||
|
virtual void visit (SharpenFilter&) {}
|
||||||
virtual void visit (ImageFilter&) {}
|
virtual void visit (ImageFilter&) {}
|
||||||
|
|
||||||
virtual void visit (SourceCallback&) {}
|
virtual void visit (SourceCallback&) {}
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
|||||||
float ar = iResolution.y / iResolution.x ;
|
float ar = iResolution.y / iResolution.x ;
|
||||||
float R = 0.25 * Radius ;
|
float R = 0.25 * Radius ;
|
||||||
|
|
||||||
vec4 O = vec4(1.);
|
vec4 O = vec4(1.);
|
||||||
float N = 17;
|
float N = 17;
|
||||||
for (float i = 0.; i < N; i++) {
|
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.));
|
// 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 );
|
O = min( texture(iChannel0, uv + q*R), O );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
|||||||
float ar = iResolution.y / iResolution.x ;
|
float ar = iResolution.y / iResolution.x ;
|
||||||
float R = 0.25 * Radius ;
|
float R = 0.25 * Radius ;
|
||||||
|
|
||||||
vec4 O = vec4(0.);
|
vec4 O = vec4(0.);
|
||||||
float N = 17;
|
float N = 17;
|
||||||
for (float i = 0.; i < N; i++) {
|
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));
|
// 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 );
|
O = max( texture(iChannel0, uv + q*R), O );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,22 @@
|
|||||||
uniform float Amount;
|
uniform float Amount;
|
||||||
|
|
||||||
float SCurve (float x) {
|
#define N 7
|
||||||
x = x * 2.0 - 1.0;
|
vec4 blur1D(vec2 U, vec2 D, float rad)
|
||||||
return -x * abs(x) * 0.5 + x + 0.5;
|
{
|
||||||
}
|
float w = rad * iResolution.y;
|
||||||
|
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
|
||||||
vec3 BlurV (sampler2D source, vec2 uv, float step, float radius) {
|
vec4 O = vec4(0);
|
||||||
vec3 C = vec3(0.0);
|
float r = float(N-1)/2., g, t=0., x;
|
||||||
float divisor = 0.0;
|
for( int k=0; k<N; k++ ) {
|
||||||
float weight = 0.0;
|
x = float(k)/r -1.;
|
||||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
t += g = exp(-2.*x*x );
|
||||||
|
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
|
||||||
// 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 O/t;
|
||||||
return C / divisor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
{
|
{
|
||||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
|
||||||
|
|
||||||
// Apply vertical blur
|
// 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,29 @@
|
|||||||
uniform float Amount;
|
uniform float Amount;
|
||||||
|
|
||||||
float SCurve (float x) {
|
#define N 7
|
||||||
x = x * 2.0 - 1.0;
|
vec4 blur1D(vec2 U, vec2 D, float rad)
|
||||||
return -x * abs(x) * 0.5 + x + 0.5;
|
{
|
||||||
}
|
float w = rad * iResolution.y;
|
||||||
|
float z = ceil(max(0.,log2(w/float(N)))); // LOD N/w = res/2^z
|
||||||
vec3 BlurH (sampler2D source, vec2 uv, float step, float radius) {
|
vec4 O = vec4(0);
|
||||||
vec3 C = vec3(0.0);
|
float r = float(N-1)/2., g, t=0., x;
|
||||||
float divisor = 0.0;
|
for( int k=0; k<N; k++ ) {
|
||||||
float weight = 0.0;
|
x = float(k)/r -1.;
|
||||||
float radiusMultiplier = 1.0 / max(1.0, radius);
|
t += g = exp(-2.*x*x );
|
||||||
|
O += g * textureLod(iChannel0, (U + w*x*D) / iResolution.xy, z );
|
||||||
// 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 O/t;
|
||||||
return C / divisor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
{
|
{
|
||||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
|
||||||
|
|
||||||
// get original image
|
// get original image
|
||||||
vec3 c = texture(iChannel1, uv).rgb;
|
vec4 c = texture(iChannel1, fragCoord.xy / iResolution.xy);
|
||||||
|
|
||||||
// Remove blurred image to original image
|
// Remove blurred image to original image
|
||||||
vec3 lumcoeff = vec3(0.299,0.587,0.114);
|
vec4 lumcoeff = vec4(0.299, 0.587, 0.114, 1.);
|
||||||
float luminance = dot( c - BlurH(iChannel0, uv, 1.0 / iResolution.x, mix(1.0, 0.1*iResolution.y, Amount) ), lumcoeff);
|
float luminance = dot( c - blur1D(fragCoord, vec2(0,1), 0.1 * Amount ), lumcoeff);
|
||||||
|
|
||||||
// composition
|
// composition
|
||||||
fragColor = vec4( c + vec3(luminance), 1.0);
|
fragColor = c + vec4(luminance);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user