Original implementation of Edge Image filters

This commit is contained in:
Bruno Herbelin
2022-06-01 23:49:12 +02:00
parent fd942b28c6
commit d7be7a69ab
18 changed files with 258 additions and 15 deletions

View File

@@ -566,6 +566,8 @@ set(VMIX_RSC_FILES
./rsc/shaders/filters/blur.glsl
./rsc/shaders/filters/blur_1.glsl
./rsc/shaders/filters/blur_2.glsl
./rsc/shaders/filters/lens_1.glsl
./rsc/shaders/filters/lens_2.glsl
./rsc/shaders/filters/hashedblur.glsl
./rsc/shaders/filters/circularblur.glsl
./rsc/shaders/filters/hashederosion.glsl
@@ -574,6 +576,7 @@ set(VMIX_RSC_FILES
./rsc/shaders/filters/sharpen.glsl
./rsc/shaders/filters/sharpen_1.glsl
./rsc/shaders/filters/sharpen_2.glsl
./rsc/shaders/filters/contour_2.glsl
./rsc/shaders/filters/sharpenedge.glsl
./rsc/shaders/filters/chromakey.glsl
./rsc/shaders/filters/bilinear.glsl

View File

@@ -153,6 +153,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
case FrameBufferFilter::FILTER_SHARPEN:
filter_ = new SharpenFilter;
break;
case FrameBufferFilter::FILTER_EDGE:
filter_ = new EdgeFilter;
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", "Sharpen", "Shader code"
"None", "Delay", "Blur", "Sharpen", "Edge", "Shader code"
};
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)

View File

@@ -22,6 +22,7 @@ public:
FILTER_DELAY,
FILTER_BLUR,
FILTER_SHARPEN,
FILTER_EDGE,
FILTER_IMAGE,
FILTER_INVALID
} Type;

View File

@@ -821,7 +821,7 @@ void ImGuiVisitor::visit (BlurFilter& f)
void ImGuiVisitor::visit (SharpenFilter& f)
{
std::ostringstream oss;
oss << "Blur ";
oss << "Sharpen ";
// Method selection
if (ImGuiToolkit::IconButton(2, 1)) {
@@ -863,6 +863,51 @@ void ImGuiVisitor::visit (SharpenFilter& f)
}
}
void ImGuiVisitor::visit (EdgeFilter& f)
{
std::ostringstream oss;
oss << "Edge ";
// Method selection
if (ImGuiToolkit::IconButton(16, 8)) {
f.setMethod( 0 );
oss << EdgeFilter::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, EdgeFilter::method_label, IM_ARRAYSIZE(EdgeFilter::method_label) )) {
f.setMethod( m );
oss << EdgeFilter::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 << EdgeFilter::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

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

View File

@@ -78,27 +78,17 @@ std::string fragmentFooter = "void main() {\n"
std::list< FilteringProgram > FilteringProgram::presets = {
FilteringProgram(),
FilteringProgram("Blur", "shaders/filters/blur_1.glsl", "shaders/filters/blur_2.glsl", { { "Amount", 0.5} }),
FilteringProgram("HashBlur", "shaders/filters/hashedblur.glsl", "", { { "Radius", 0.5}, { "Iterations", 0.5 } }),
FilteringProgram("Unfocus", "shaders/filters/focus.glsl", "", { { "Factor", 0.5} }),
FilteringProgram("Smooth", "shaders/filters/bilinear.glsl", "", { }),
FilteringProgram("Kuwahara", "shaders/filters/kuwahara.glsl", "", { { "Radius", 1.0} }),
FilteringProgram("Denoise", "shaders/filters/denoise.glsl", "", { { "Threshold", 0.5} }),
FilteringProgram("Noise", "shaders/filters/noise.glsl", "", { { "Amount", 0.25} }),
FilteringProgram("Grain", "shaders/filters/grain.glsl", "", { { "Amount", 0.5} }),
FilteringProgram("Sharpen", "shaders/filters/sharp.glsl", "", { { "Amount", 0.5} }),
FilteringProgram("Unsharp Mask", "shaders/filters/sharpen_1.glsl", "shaders/filters/sharpen_2.glsl", { { "Amount", 0.5} }),
FilteringProgram("Sharp Edge", "shaders/filters/bilinear.glsl", "shaders/filters/sharpenedge.glsl", { { "Strength", 0.5} }),
FilteringProgram("Edge", "shaders/filters/bilinear.glsl", "shaders/filters/edge.glsl", { { "Threshold", 0.5} }),
FilteringProgram("Sobel", "shaders/filters/sobel.glsl", "", { { "Factor", 0.5} }),
FilteringProgram("Freichen", "shaders/filters/freichen.glsl", "", { { "Factor", 0.5} }),
FilteringProgram("Pixelate", "shaders/filters/pixelate.glsl", "", { { "Size", 0.5}, { "Sharpen", 0.5} }),
FilteringProgram("Erosion", "shaders/filters/erosion.glsl", "", { { "Radius", 0.5} }),
FilteringProgram("Dilation", "shaders/filters/dilation.glsl", "", { { "Radius", 0.5} }),
FilteringProgram("Openning", "shaders/filters/erosion.glsl", "shaders/filters/dilation.glsl", { { "Radius", 0.5} }),
FilteringProgram("Closing", "shaders/filters/dilation.glsl", "shaders/filters/erosion.glsl", { { "Radius", 0.5} }),
FilteringProgram("TopHat", "shaders/filters/erosion.glsl", "shaders/filters/tophat.glsl", { { "Radius", 0.5} }),
FilteringProgram("BlackHat", "shaders/filters/dilation.glsl", "shaders/filters/blackhat.glsl", { { "Radius", 0.5} }),
FilteringProgram("Bloom", "shaders/filters/bloom.glsl", "", { { "Intensity", 0.5} }),
FilteringProgram("Bokeh", "shaders/filters/bokeh.glsl", "", { { "Radius", 1.0} }),
FilteringProgram("Chalk", "shaders/filters/talk.glsl", "", { { "Factor", 1.0} }),
@@ -595,13 +585,15 @@ void BlurFilter::accept (Visitor& v)
////////////////////////////////////////
const char* SharpenFilter::method_label[SharpenFilter::SHARPEN_INVALID] = {
"Unsharp mask", "Convolution", "Edge"
"Unsharp mask", "Convolution", "Edge", "White hat", "Black hat"
};
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} }),
FilteringProgram("TopHat", "shaders/filters/erosion.glsl", "shaders/filters/tophat.glsl", { { "Radius", 0.5} }),
FilteringProgram("BlackHat", "shaders/filters/dilation.glsl", "shaders/filters/blackhat.glsl", { { "Radius", 0.5} }),
};
SharpenFilter::SharpenFilter (): ImageFilter(), method_(SHARPEN_INVALID)
@@ -630,4 +622,47 @@ void SharpenFilter::accept (Visitor& v)
}
////////////////////////////////////////
///// //
//// EDGE FILTERS ///
/// ////
////////////////////////////////////////
const char* EdgeFilter::method_label[EdgeFilter::EDGE_INVALID] = {
"Thresholding", "Sobel", "Freichen", "Contour"
};
std::vector< FilteringProgram > EdgeFilter::programs_ = {
FilteringProgram("Edge", "shaders/filters/bilinear.glsl", "shaders/filters/edge.glsl", { { "Threshold", 0.5} }),
FilteringProgram("Sobel", "shaders/filters/sobel.glsl", "", { { "Factor", 0.5} }),
FilteringProgram("Freichen", "shaders/filters/freichen.glsl", "", { { "Factor", 0.5} }),
FilteringProgram("Contour", "shaders/filters/sharpen_1.glsl", "shaders/filters/contour_2.glsl", { { "Amount", 0.5} }),
};
EdgeFilter::EdgeFilter (): ImageFilter(), method_(EDGE_INVALID)
{
}
void EdgeFilter::setMethod(int method)
{
method_ = (EdgeMethod) CLAMP(method, EDGE_THRESHOLD, EDGE_INVALID-1);
setProgram( programs_[ (int) method_] );
}
void EdgeFilter::draw (FrameBuffer *input)
{
// Default
if (method_ == EDGE_INVALID)
setMethod( EDGE_THRESHOLD );
ImageFilter::draw( input );
}
void EdgeFilter::accept (Visitor& v)
{
FrameBufferFilter::accept(v);
v.visit(*this);
}

View File

@@ -148,6 +148,8 @@ public:
SHARPEN_MASK = 0,
SHARPEN_CONVOLUTION,
SHARPEN_EDGE,
SHARPEN_WHITEHAT,
SHARPEN_BLACKHAT,
SHARPEN_INVALID
} SharpenMethod;
static const char* method_label[SHARPEN_INVALID];
@@ -166,5 +168,36 @@ private:
};
class EdgeFilter : public ImageFilter
{
public:
EdgeFilter();
// Algorithms used for edge detection
typedef enum {
EDGE_THRESHOLD = 0,
EDGE_SOBEL,
EDGE_FREICHEN,
EDGE_CONTOUR,
EDGE_INVALID
} EdgeMethod;
static const char* method_label[EDGE_INVALID];
EdgeMethod method () const { return method_; }
void setMethod(int method);
// implementation of FrameBufferFilter
Type type() const override { return FrameBufferFilter::FILTER_EDGE; }
void draw (FrameBuffer *input) override;
void accept (Visitor& v) override;
private:
EdgeMethod method_;
static std::vector< FilteringProgram > programs_;
};
#endif // IMAGEFILTER_H

View File

@@ -1273,6 +1273,30 @@ void SessionLoader::visit (SharpenFilter& f)
f.setProgramParameters(filter_params);
}
void SessionLoader::visit (EdgeFilter& f)
{
int m = 0;
xmlCurrent_->QueryIntAttribute("method", &m);
f.setMethod(m);
std::map< std::string, float > filter_params;
XMLElement* parameters = xmlCurrent_->FirstChildElement("parameters");
if (parameters) {
XMLElement* param = parameters->FirstChildElement("uniform");
for( ; param ; param = param->NextSiblingElement())
{
float val = 0.f;
param->QueryFloatAttribute("value", &val);
const char * name;
param->QueryStringAttribute("name", &name);
if (name)
filter_params[name] = val;
}
}
f.setProgramParameters(filter_params);
}
void SessionLoader::visit (ImageFilter& f)
{
const char * filter_name;

View File

@@ -66,6 +66,7 @@ public:
void visit (DelayFilter&) override;
void visit (BlurFilter&) override;
void visit (SharpenFilter&) override;
void visit (EdgeFilter&) override;
void visit (ImageFilter&) override;
// callbacks

View File

@@ -726,6 +726,22 @@ void SessionVisitor::visit (SharpenFilter& f)
}
}
void SessionVisitor::visit (EdgeFilter& f)
{
xmlCurrent_->SetAttribute("method", (int) f.method());
std::map< std::string, float > filter_params = f.program().parameters();
XMLElement *parameters = xmlDoc_->NewElement( "parameters" );
xmlCurrent_->InsertEndChild(parameters);
for (auto p = filter_params.begin(); p != filter_params.end(); ++p)
{
XMLElement *param = xmlDoc_->NewElement( "uniform" );
param->SetAttribute("name", p->first.c_str() );
param->SetAttribute("value", p->second );
parameters->InsertEndChild(param);
}
}
void SessionVisitor::visit (ImageFilter& f)
{
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );

View File

@@ -74,6 +74,7 @@ public:
void visit (DelayFilter&) override;
void visit (BlurFilter&) override;
void visit (SharpenFilter&) override;
void visit (EdgeFilter&) override;
void visit (ImageFilter&) override;
// callbacks

View File

@@ -46,6 +46,7 @@ class PassthroughFilter;
class DelayFilter;
class BlurFilter;
class SharpenFilter;
class EdgeFilter;
class ImageFilter;
class SourceCallback;
@@ -108,6 +109,7 @@ public:
virtual void visit (DelayFilter&) {}
virtual void visit (BlurFilter&) {}
virtual void visit (SharpenFilter&) {}
virtual void visit (EdgeFilter&) {}
virtual void visit (ImageFilter&) {}
virtual void visit (SourceCallback&) {}

View File

@@ -0,0 +1,29 @@
uniform float Amount;
#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 * texture(iChannel0, (U + w*x*D) / iResolution.xy );
}
return O/t;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// get original image
vec4 c = texture(iChannel1, fragCoord.xy / iResolution.xy);
// Remove blurred image to original image
vec4 lumcoeff = vec4(0.299, 0.587, 0.114, 1.);
float luminance = dot( blur1D(fragCoord, vec2(0,1), 0.1 * Amount ) - c, lumcoeff);
// composition
fragColor = vec4(luminance, luminance, luminance, 1.0);
}

View File

@@ -0,0 +1,17 @@
float BRIGHT_SPOT_TRESHOLD=0.5;
vec3 BriSp(vec3 p){
if(p.x+p.y+p.z>BRIGHT_SPOT_TRESHOLD*3.)p=(1./(1.-p)-1.)*(1.-BRIGHT_SPOT_TRESHOLD);
p=clamp(p,0.,100.);
return p;
}
vec3 bright(vec2 n){
vec3 p=texture(iChannel0,n).rgb;
p=BriSp(p);
return p;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
fragColor = vec4(bright(fragCoord/iResolution.xy),0.);
}

View File

@@ -0,0 +1,32 @@
uniform float Radius;
const float pi=4.*atan(1.);
const float ang=(3.-sqrt(5.))*pi;
float gamma=1.8;
const float SAMPLES=50.;
vec3 bokeh(sampler2D samp,vec2 uv,vec2 radius,float lod){
vec3 col = vec3(0);
for(float i=0.;i<SAMPLES;i++){
float d=i/SAMPLES;
vec2 p=vec2(sin(ang*i),cos(ang*i))*sqrt(d)*radius;
col+=pow(texture(samp,uv+p,lod).rgb,vec3(gamma));
}
return pow(col/SAMPLES,vec3(1./gamma));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 uv = fragCoord/iResolution.xy;
vec2 pix=1./iResolution.xy;
float r=sin(Radius) * 2.0;
r*=r*20.;
float lod=log2(r/SAMPLES*pi*5.);
//lod=0.;
vec3 col = bokeh(iChannel0,uv,r*pix,lod);
fragColor = vec4(col,1.0);
}

View File

@@ -10,7 +10,7 @@ vec4 blur1D(vec2 U, vec2 D, float rad)
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 );
O += g * texture(iChannel0, (U + w*x*D) / iResolution.xy );
}
return O/t;
}

View File

@@ -10,7 +10,7 @@ vec4 blur1D(vec2 U, vec2 D, float rad)
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 );
O += g * texture(iChannel0, (U + w*x*D) / iResolution.xy );
}
return O/t;
}