From d7be7a69abfde6f3545ac72c84494d4fd06369bf Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Wed, 1 Jun 2022 23:49:12 +0200 Subject: [PATCH] Original implementation of Edge Image filters --- CMakeLists.txt | 3 ++ CloneSource.cpp | 3 ++ FrameBufferFilter.cpp | 2 +- FrameBufferFilter.h | 1 + ImGuiVisitor.cpp | 47 +++++++++++++++++++++++- ImGuiVisitor.h | 1 + ImageFilter.cpp | 57 ++++++++++++++++++++++++------ ImageFilter.h | 33 +++++++++++++++++ SessionCreator.cpp | 24 +++++++++++++ SessionCreator.h | 1 + SessionVisitor.cpp | 16 +++++++++ SessionVisitor.h | 1 + Visitor.h | 2 ++ rsc/shaders/filters/contour_2.glsl | 29 +++++++++++++++ rsc/shaders/filters/lens_1.glsl | 17 +++++++++ rsc/shaders/filters/lens_2.glsl | 32 +++++++++++++++++ rsc/shaders/filters/sharpen_1.glsl | 2 +- rsc/shaders/filters/sharpen_2.glsl | 2 +- 18 files changed, 258 insertions(+), 15 deletions(-) create mode 100644 rsc/shaders/filters/contour_2.glsl create mode 100644 rsc/shaders/filters/lens_1.glsl create mode 100644 rsc/shaders/filters/lens_2.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 565d6cf..d53910d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/CloneSource.cpp b/CloneSource.cpp index f24a87d..cefc99b 100644 --- a/CloneSource.cpp +++ b/CloneSource.cpp @@ -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; diff --git a/FrameBufferFilter.cpp b/FrameBufferFilter.cpp index 85564d1..b7ef866 100644 --- a/FrameBufferFilter.cpp +++ b/FrameBufferFilter.cpp @@ -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) diff --git a/FrameBufferFilter.h b/FrameBufferFilter.h index 0eae509..9e58885 100644 --- a/FrameBufferFilter.h +++ b/FrameBufferFilter.h @@ -22,6 +22,7 @@ public: FILTER_DELAY, FILTER_BLUR, FILTER_SHARPEN, + FILTER_EDGE, FILTER_IMAGE, FILTER_INVALID } Type; diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 52b11d2..3e4e424 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -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 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) <second; + Action::manager().store(oss.str()); + } + ImGui::PopID(); + } +} + void ImGuiVisitor::visit (ImageFilter& f) { // Selection of Algorithm diff --git a/ImGuiVisitor.h b/ImGuiVisitor.h index fac88c9..694876d 100644 --- a/ImGuiVisitor.h +++ b/ImGuiVisitor.h @@ -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; }; diff --git a/ImageFilter.cpp b/ImageFilter.cpp index 0660f4a..fe7bd60 100644 --- a/ImageFilter.cpp +++ b/ImageFilter.cpp @@ -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); +} + + diff --git a/ImageFilter.h b/ImageFilter.h index 4fab3dc..4e30508 100644 --- a/ImageFilter.h +++ b/ImageFilter.h @@ -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 diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 7409ff3..0899c30 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -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; diff --git a/SessionCreator.h b/SessionCreator.h index 16fbe0b..2ae2e6c 100644 --- a/SessionCreator.h +++ b/SessionCreator.h @@ -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 diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 8ea35ff..5e93a90 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -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() ); diff --git a/SessionVisitor.h b/SessionVisitor.h index 050dfc4..ccfbc75 100644 --- a/SessionVisitor.h +++ b/SessionVisitor.h @@ -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 diff --git a/Visitor.h b/Visitor.h index 9bafd86..df5d9c2 100644 --- a/Visitor.h +++ b/Visitor.h @@ -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&) {} diff --git a/rsc/shaders/filters/contour_2.glsl b/rsc/shaders/filters/contour_2.glsl new file mode 100644 index 0000000..3cf04d5 --- /dev/null +++ b/rsc/shaders/filters/contour_2.glsl @@ -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; kBRIGHT_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.); +} diff --git a/rsc/shaders/filters/lens_2.glsl b/rsc/shaders/filters/lens_2.glsl new file mode 100644 index 0000000..3c9f896 --- /dev/null +++ b/rsc/shaders/filters/lens_2.glsl @@ -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