Original implementation of Alpha Image filters

Chromakey (to finish), lumakey and alpha fill.
This commit is contained in:
Bruno Herbelin
2022-06-06 23:33:36 +02:00
parent fec2fb7ce6
commit 1604eaa239
16 changed files with 246 additions and 8 deletions

View File

@@ -579,6 +579,8 @@ set(VMIX_RSC_FILES
./rsc/shaders/filters/contour_2.glsl
./rsc/shaders/filters/sharpenedge.glsl
./rsc/shaders/filters/chromakey.glsl
./rsc/shaders/filters/lumakey.glsl
./rsc/shaders/filters/coloralpha.glsl
./rsc/shaders/filters/bilinear.glsl
./rsc/shaders/filters/edge.glsl
./rsc/shaders/filters/sobel.glsl

View File

@@ -166,6 +166,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
case FrameBufferFilter::FILTER_EDGE:
filter_ = new EdgeFilter;
break;
case FrameBufferFilter::FILTER_ALPHA:
filter_ = new AlphaFilter;
break;
case FrameBufferFilter::FILTER_IMAGE:
filter_ = new ImageFilter;
break;
@@ -174,10 +177,6 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
filter_ = new PassthroughFilter;
break;
}
// TODO : resampling of renderbuffer ?
}
void CloneSource::play (bool on)

View File

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

View File

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

View File

@@ -928,6 +928,75 @@ void ImGuiVisitor::visit (EdgeFilter& f)
}
}
void ImGuiVisitor::visit (AlphaFilter& f)
{
std::ostringstream oss;
oss << "Alpha ";
// Method selection
if (ImGuiToolkit::IconButton(13, 4)) {
f.setOperation( 0 );
oss << AlphaFilter::operation_label[0];
Action::manager().store(oss.str());
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int m = (int) f.operation();
if (ImGui::Combo("Operation", &m, AlphaFilter::operation_label, IM_ARRAYSIZE(AlphaFilter::operation_label) )) {
f.setOperation( m );
oss << AlphaFilter::operation_label[m];
Action::manager().store(oss.str());
}
// List of parameters
std::map<std::string, float> filter_parameters = f.program().parameters();
if ( m == AlphaFilter::ALPHA_CHROMAKEY || m == AlphaFilter::ALPHA_LUMAKEY)
{
float v = filter_parameters["Tolerance"];
if (ImGuiToolkit::IconButton(13, 14)) {
v = 0.f;
f.setProgramParameter("Tolerance", v);
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::SliderFloat( "Tolerance", &v, 0.f, 1.f, "%.2f")) {
f.setProgramParameter("Tolerance", v);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " : " << "Tolerance" << " " << std::setprecision(3) << v;
Action::manager().store(oss.str());
}
}
if ( m == AlphaFilter::ALPHA_CHROMAKEY || m == AlphaFilter::ALPHA_FILL)
{
glm::vec4 color = glm::vec4(filter_parameters["Red"], filter_parameters["Green"], filter_parameters["Blue"], 1.f);
if (ImGuiToolkit::IconButton(13, 14)) {
color = glm::vec4(0.f, 0.8f, 0.f, 1.f);
f.setProgramParameter("Red", color.r);
f.setProgramParameter("Green", color.g);
f.setProgramParameter("Blue", color.b);
}
ImGui::SameLine(0, IMGUI_SAME_LINE);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::ColorEdit3("Color", glm::value_ptr(color), ImGuiColorEditFlags_Float | ImGuiColorEditFlags_NoOptions) )
{
f.setProgramParameter("Red", color.r);
f.setProgramParameter("Green", color.g);
f.setProgramParameter("Blue", color.b);
}
if (ImGui::IsItemDeactivatedAfterEdit()) {
oss << AlphaFilter::operation_label[ f.operation() ];
oss << " : " << "Color" << " " << color.r << " " << color.g << " " << color.b;
Action::manager().store(oss.str());
}
}
}
void ImGuiVisitor::visit (ImageFilter& f)
{
// Selection of Algorithm

View File

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

View File

@@ -770,3 +770,46 @@ void EdgeFilter::accept (Visitor& v)
////////////////////////////////////////
///// //
//// ALPHA FILTERS ///
/// ////
////////////////////////////////////////
const char* AlphaFilter::operation_label[AlphaFilter::ALPHA_INVALID] = {
"Chromakey", "Lumakey", "Fill transparent"
};
std::vector< FilteringProgram > AlphaFilter::programs_ = {
FilteringProgram("Chromakey","shaders/filters/chromakey.glsl", "", { { "Red", 0.0}, { "Green", 1.0}, { "Blue", 0.0}, { "Tolerance", 1.0} }),
FilteringProgram("Lumakey", "shaders/filters/lumakey.glsl", "", { { "Tolerance", 0.5} }),
FilteringProgram("coloralpha","shaders/filters/coloralpha.glsl", "", { { "Red", 0.0}, { "Green", 1.0}, { "Blue", 0.0} })
};
AlphaFilter::AlphaFilter (): ImageFilter(), operation_(ALPHA_INVALID)
{
}
void AlphaFilter::setOperation(int op)
{
operation_ = (AlphaOperation) CLAMP(op, ALPHA_CHROMAKEY, ALPHA_INVALID-1);
setProgram( programs_[ (int) operation_] );
}
void AlphaFilter::draw (FrameBuffer *input)
{
// Default
if (operation_ == ALPHA_INVALID)
setOperation( ALPHA_CHROMAKEY );
ImageFilter::draw( input );
}
void AlphaFilter::accept (Visitor& v)
{
FrameBufferFilter::accept(v);
v.visit(*this);
}

View File

@@ -230,4 +230,34 @@ private:
class AlphaFilter : public ImageFilter
{
public:
AlphaFilter();
// Operations on alpha
typedef enum {
ALPHA_CHROMAKEY = 0,
ALPHA_LUMAKEY,
ALPHA_FILL,
ALPHA_INVALID
} AlphaOperation;
static const char* operation_label[ALPHA_INVALID];
AlphaOperation operation () const { return operation_; }
void setOperation(int op);
// implementation of FrameBufferFilter
Type type() const override { return FrameBufferFilter::FILTER_ALPHA; }
void draw (FrameBuffer *input) override;
void accept (Visitor& v) override;
private:
AlphaOperation operation_;
static std::vector< FilteringProgram > programs_;
};
#endif // IMAGEFILTER_H

View File

@@ -1304,6 +1304,30 @@ void SessionLoader::visit (EdgeFilter& f)
f.setProgramParameters(filter_params);
}
void SessionLoader::visit (AlphaFilter& f)
{
int m = 0;
xmlCurrent_->QueryIntAttribute("operation", &m);
f.setOperation(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

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

View File

@@ -747,6 +747,22 @@ void SessionVisitor::visit (EdgeFilter& f)
}
}
void SessionVisitor::visit (AlphaFilter& f)
{
xmlCurrent_->SetAttribute("operation", (int) f.operation());
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

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

View File

@@ -48,6 +48,7 @@ class ResampleFilter;
class BlurFilter;
class SharpenFilter;
class EdgeFilter;
class AlphaFilter;
class ImageFilter;
class SourceCallback;
@@ -112,6 +113,7 @@ public:
virtual void visit (BlurFilter&) {}
virtual void visit (SharpenFilter&) {}
virtual void visit (EdgeFilter&) {}
virtual void visit (AlphaFilter&) {}
virtual void visit (ImageFilter&) {}
virtual void visit (SourceCallback&) {}

View File

@@ -46,8 +46,7 @@ float colorclose(vec3 yuv, vec3 keyYuv, vec2 tol)
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 fragPos = fragCoord.xy / iResolution.xy;
vec4 texColor0 = texture(iChannel0, fragPos);
vec4 texColor0 = texture(iChannel0, fragCoord.xy / iResolution.xy);
//convert from RGB to YCvCr/YUV
vec4 keyYUV = RGBtoYUV * chromaKey;

View File

@@ -0,0 +1,10 @@
uniform float Red;
uniform float Green;
uniform float Blue;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 fragPos = fragCoord.xy / iResolution.xy;
vec4 color = texture(iChannel0, fragPos);
fragColor = vec4( mix(vec3(Red, Green, Blue), color.rgb, color.a), 1.f);
}

View File

@@ -0,0 +1,40 @@
uniform float Tolerance;
//float sRGBtoLin( in float v ) {
// // Send this function a decimal sRGB gamma encoded color value
// // between 0.0 and 1.0, and it returns a linearized value.
// if ( v <= 0.04045 ) {
// return v / 12.92;
// } else {
// return pow((( v + 0.055)/1.055),2.4);
// }
//}
//// returns L* which is "perceptual lightness"
//float lightness ( in vec3 color )
//{
// float Y = 0.2126 * sRGBtoLin(color.r)
// + 0.7152 * sRGBtoLin(color.g)
// + 0.0722 * sRGBtoLin(color.b);
// if ( Y <= (216./24389.) ) { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
// Y = Y * (24389./27.); // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
// } else {
// Y = pow(Y,(1./3.)) * 116. - 16.;
// }
// return 0.01 * Y;
//}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 fragPos = fragCoord.xy / iResolution.xy;
vec3 RGB = texture(iChannel0, fragPos).rgb;
float L = dot(RGB, vec3(0.299, 0.587, 0.114));
// float L = lightness( RGB );
fragColor = vec4( RGB, smoothstep( 0.0, Tolerance, L ) );
}