mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-12 10:49:59 +01:00
Original implementation of Alpha Image filters
Chromakey (to finish), lumakey and alpha fill.
This commit is contained in:
@@ -579,6 +579,8 @@ set(VMIX_RSC_FILES
|
|||||||
./rsc/shaders/filters/contour_2.glsl
|
./rsc/shaders/filters/contour_2.glsl
|
||||||
./rsc/shaders/filters/sharpenedge.glsl
|
./rsc/shaders/filters/sharpenedge.glsl
|
||||||
./rsc/shaders/filters/chromakey.glsl
|
./rsc/shaders/filters/chromakey.glsl
|
||||||
|
./rsc/shaders/filters/lumakey.glsl
|
||||||
|
./rsc/shaders/filters/coloralpha.glsl
|
||||||
./rsc/shaders/filters/bilinear.glsl
|
./rsc/shaders/filters/bilinear.glsl
|
||||||
./rsc/shaders/filters/edge.glsl
|
./rsc/shaders/filters/edge.glsl
|
||||||
./rsc/shaders/filters/sobel.glsl
|
./rsc/shaders/filters/sobel.glsl
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
|
|||||||
case FrameBufferFilter::FILTER_EDGE:
|
case FrameBufferFilter::FILTER_EDGE:
|
||||||
filter_ = new EdgeFilter;
|
filter_ = new EdgeFilter;
|
||||||
break;
|
break;
|
||||||
|
case FrameBufferFilter::FILTER_ALPHA:
|
||||||
|
filter_ = new AlphaFilter;
|
||||||
|
break;
|
||||||
case FrameBufferFilter::FILTER_IMAGE:
|
case FrameBufferFilter::FILTER_IMAGE:
|
||||||
filter_ = new ImageFilter;
|
filter_ = new ImageFilter;
|
||||||
break;
|
break;
|
||||||
@@ -174,10 +177,6 @@ void CloneSource::setFilter(FrameBufferFilter::Type T)
|
|||||||
filter_ = new PassthroughFilter;
|
filter_ = new PassthroughFilter;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO : resampling of renderbuffer ?
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloneSource::play (bool on)
|
void CloneSource::play (bool on)
|
||||||
|
|||||||
@@ -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", "Resample", "Blur", "Sharpen", "Edge", "Shader code"
|
"None", "Delay", "Resample", "Blur", "Sharpen", "Edge", "Transparency", "Shader code"
|
||||||
};
|
};
|
||||||
|
|
||||||
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)
|
FrameBufferFilter::FrameBufferFilter() : enabled_(true), input_(nullptr)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ public:
|
|||||||
FILTER_BLUR,
|
FILTER_BLUR,
|
||||||
FILTER_SHARPEN,
|
FILTER_SHARPEN,
|
||||||
FILTER_EDGE,
|
FILTER_EDGE,
|
||||||
|
FILTER_ALPHA,
|
||||||
FILTER_IMAGE,
|
FILTER_IMAGE,
|
||||||
FILTER_INVALID
|
FILTER_INVALID
|
||||||
} Type;
|
} Type;
|
||||||
|
|||||||
@@ -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)
|
void ImGuiVisitor::visit (ImageFilter& f)
|
||||||
{
|
{
|
||||||
// Selection of Algorithm
|
// Selection of Algorithm
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
void visit (BlurFilter&) override;
|
void visit (BlurFilter&) override;
|
||||||
void visit (SharpenFilter&) override;
|
void visit (SharpenFilter&) override;
|
||||||
void visit (EdgeFilter&) override;
|
void visit (EdgeFilter&) override;
|
||||||
|
void visit (AlphaFilter&) override;
|
||||||
void visit (ImageFilter&) override;
|
void visit (ImageFilter&) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
#endif // IMAGEFILTER_H
|
||||||
|
|||||||
@@ -1304,6 +1304,30 @@ void SessionLoader::visit (EdgeFilter& f)
|
|||||||
f.setProgramParameters(filter_params);
|
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)
|
void SessionLoader::visit (ImageFilter& f)
|
||||||
{
|
{
|
||||||
const char * filter_name;
|
const char * filter_name;
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ public:
|
|||||||
void visit (BlurFilter&) override;
|
void visit (BlurFilter&) override;
|
||||||
void visit (SharpenFilter&) override;
|
void visit (SharpenFilter&) override;
|
||||||
void visit (EdgeFilter&) override;
|
void visit (EdgeFilter&) override;
|
||||||
|
void visit (AlphaFilter&) override;
|
||||||
void visit (ImageFilter&) override;
|
void visit (ImageFilter&) override;
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
|
|||||||
@@ -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)
|
void SessionVisitor::visit (ImageFilter& f)
|
||||||
{
|
{
|
||||||
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );
|
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public:
|
|||||||
void visit (BlurFilter&) override;
|
void visit (BlurFilter&) override;
|
||||||
void visit (SharpenFilter&) override;
|
void visit (SharpenFilter&) override;
|
||||||
void visit (EdgeFilter&) override;
|
void visit (EdgeFilter&) override;
|
||||||
|
void visit (AlphaFilter&) override;
|
||||||
void visit (ImageFilter&) override;
|
void visit (ImageFilter&) override;
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class ResampleFilter;
|
|||||||
class BlurFilter;
|
class BlurFilter;
|
||||||
class SharpenFilter;
|
class SharpenFilter;
|
||||||
class EdgeFilter;
|
class EdgeFilter;
|
||||||
|
class AlphaFilter;
|
||||||
class ImageFilter;
|
class ImageFilter;
|
||||||
|
|
||||||
class SourceCallback;
|
class SourceCallback;
|
||||||
@@ -112,6 +113,7 @@ public:
|
|||||||
virtual void visit (BlurFilter&) {}
|
virtual void visit (BlurFilter&) {}
|
||||||
virtual void visit (SharpenFilter&) {}
|
virtual void visit (SharpenFilter&) {}
|
||||||
virtual void visit (EdgeFilter&) {}
|
virtual void visit (EdgeFilter&) {}
|
||||||
|
virtual void visit (AlphaFilter&) {}
|
||||||
virtual void visit (ImageFilter&) {}
|
virtual void visit (ImageFilter&) {}
|
||||||
|
|
||||||
virtual void visit (SourceCallback&) {}
|
virtual void visit (SourceCallback&) {}
|
||||||
|
|||||||
@@ -46,11 +46,10 @@ float colorclose(vec3 yuv, vec3 keyYuv, vec2 tol)
|
|||||||
|
|
||||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
{
|
{
|
||||||
vec2 fragPos = fragCoord.xy / iResolution.xy;
|
vec4 texColor0 = texture(iChannel0, fragCoord.xy / iResolution.xy);
|
||||||
vec4 texColor0 = texture(iChannel0, fragPos);
|
|
||||||
|
|
||||||
//convert from RGB to YCvCr/YUV
|
//convert from RGB to YCvCr/YUV
|
||||||
vec4 keyYUV = RGBtoYUV * chromaKey;
|
vec4 keyYUV = RGBtoYUV * chromaKey;
|
||||||
vec4 yuv = RGBtoYUV * texColor0;
|
vec4 yuv = RGBtoYUV * texColor0;
|
||||||
|
|
||||||
float mask = 1.0 - colorclose(yuv.rgb, keyYUV.rgb, maskRange);
|
float mask = 1.0 - colorclose(yuv.rgb, keyYUV.rgb, maskRange);
|
||||||
|
|||||||
10
rsc/shaders/filters/coloralpha.glsl
Normal file
10
rsc/shaders/filters/coloralpha.glsl
Normal 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);
|
||||||
|
}
|
||||||
40
rsc/shaders/filters/lumakey.glsl
Normal file
40
rsc/shaders/filters/lumakey.glsl
Normal 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 ) );
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user