Skip to content

Add face substitution example #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions example-facesubstitution/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ofxFaceTracker2 - Face Substitution
This code provides an example of using the [FaceSubstitution](https://github.com/arturoc/FaceSubstitution) library with ofxFaceTracker2.

# Instructions

- Download [shape_predictor_68_face_landmarks.dat](://github.com/AKSHAYUBHAT/TensorFace/blob/master/openface/models/dlib/shape_predictor_68_face_landmarks.dat) and place in bin/data
- Modify replace the following OfxCv addon files in your IDE/editor of choice:
- [Kalman.cpp](https://gist.github.com/ThomasColliers/375c65a3afd529bd1b9f28fe48f94cd3#file-kalman-cpp)
- [Kalman.h](https://gist.github.com/ThomasColliers/375c65a3afd529bd1b9f28fe48f94cd3#file-kalman-h)
- See [issue #25](https://github.com/HalfdanJ/ofxFaceTracker2/issues/25) for information about this replacement.

# Thanks

To [Thomas Colliers](https://github.com/ThomasColliers) for sharing his solution in the issue above :)

15 changes: 15 additions & 0 deletions example-facesubstitution/bin/data/Clone.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect src, srcBlur, dstBlur;

void main() {
vec2 pos = gl_TexCoord[0].st;
vec4 srcColorBlur = texture2DRect(srcBlur, pos);
if(srcColorBlur.a > 0.) {
vec3 srcColor = texture2DRect(src, pos).rgb;
vec4 dstColorBlur = texture2DRect(dstBlur, pos);
vec3 offset = (dstColorBlur.rgb - srcColorBlur.rgb);
gl_FragColor = vec4(srcColor + offset, 1.);
} else {
gl_FragColor = vec4(0.);
}
}
72 changes: 72 additions & 0 deletions example-facesubstitution/bin/data/MaskBlur.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#extension GL_ARB_texture_rectangle : enable
uniform sampler2DRect tex, mask;
uniform vec2 direction;
uniform int k;

//#define LOW_RES
//#define USE_HARDWARE_INTERPOLATION
#define STANDARD

void main() {
vec2 pos = gl_TexCoord[0].st;
vec4 sum = texture2DRect(tex, pos);
int i;

// 350 fps
#ifdef LOW_RES
for(i = 2; i < k; i += 4) {
vec2 offset = float(i) * direction;
vec4 leftMask = texture2DRect(mask, pos - offset);
vec4 rightMask = texture2DRect(mask, pos + offset);
bool valid = leftMask.r == 1. && rightMask.r == 1.; // ignore black pixels
if(valid) {
sum +=
texture2DRect(tex, pos + offset) +
texture2DRect(tex, pos - offset);
} else {
break;
}
}
int samples = 1 + (i - 1) * 2 / 4;
#endif

// 240 fps
#ifdef USE_HARDWARE_INTERPOLATION
for(i = 2; i < k; i += 2) {
vec2 maskOffset = float(i) * direction;
vec4 leftMask = texture2DRect(mask, pos - maskOffset);
vec4 rightMask = texture2DRect(mask, pos + maskOffset);
bool valid = leftMask.r == 1. && rightMask.r == 1.; // ignore black pixels
if(valid) {
vec2 sampleOffset = (float(i) - .5) * direction;
sum +=
texture2DRect(tex, pos + sampleOffset) +
texture2DRect(tex, pos - sampleOffset);
} else {
break;
}
}
int samples = 1 + (i - 2);
#endif

// 140 fps
#ifdef STANDARD
int samples = 1;
for(i = 1; i < k; i++) {
vec2 curOffset = float(i) * direction;
vec4 leftMask = texture2DRect(mask, pos - curOffset);
vec4 rightMask = texture2DRect(mask, pos + curOffset);
bool valid = leftMask.r == 1. && rightMask.r == 1.; // ignore black pixels
if(valid) {
sum +=
texture2DRect(tex, pos + curOffset) +
texture2DRect(tex, pos - curOffset);
samples += 2;
} else {
break;
}
}
#endif

gl_FragColor = sum / float(samples);
}
Binary file added example-facesubstitution/bin/data/faces/src.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 111 additions & 0 deletions example-facesubstitution/src/Clone.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "Clone.h"

char maskBlurShaderSource[] =
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect tex, mask;\
uniform vec2 direction;\
uniform int k;\
void main() {\
vec2 pos = gl_TexCoord[0].st;\
vec4 sum = texture2DRect(tex, pos);\
int i;\
for(i = 1; i < k; i++) {\
vec2 curOffset = float(i) * direction;\
vec4 leftMask = texture2DRect(mask, pos - curOffset);\
vec4 rightMask = texture2DRect(mask, pos + curOffset);\
bool valid = leftMask.r == 1. && rightMask.r == 1.;\
if(valid) {\
sum +=\
texture2DRect(tex, pos + curOffset) +\
texture2DRect(tex, pos - curOffset);\
} else {\
break;\
}\
}\
int samples = 1 + (i - 1) * 2;\
gl_FragColor = sum / float(samples);\
}";

char cloneShaderSource[] =
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect src, srcBlur, dstBlur;\
void main() {\
vec2 pos = gl_TexCoord[0].st; \
vec4 srcColorBlur = texture2DRect(srcBlur, pos);\
if(srcColorBlur.a > 0.) {\
vec3 srcColor = texture2DRect(src, pos).rgb;\
vec4 dstColorBlur = texture2DRect(dstBlur, pos);\
vec3 offset = (dstColorBlur.rgb - srcColorBlur.rgb);\
gl_FragColor = vec4(srcColor + offset, 1.);\
} else {\
gl_FragColor = vec4(0.);\
}\
}";

void Clone::setup(int width, int height) {
ofFbo::Settings settings;
settings.width = width;
settings.height = height;

buffer.allocate(settings);
srcBlur.allocate(settings);
dstBlur.allocate(settings);

maskBlurShader.setupShaderFromSource(GL_FRAGMENT_SHADER, maskBlurShaderSource);
cloneShader.setupShaderFromSource(GL_FRAGMENT_SHADER, cloneShaderSource);
maskBlurShader.linkProgram();
cloneShader.linkProgram();

strength = 0;
}

void Clone::maskedBlur(ofTexture& tex, ofTexture& mask, ofFbo& result) {
int k = strength;

buffer.begin();
maskBlurShader.begin();
maskBlurShader.setUniformTexture("tex", tex, 1);
maskBlurShader.setUniformTexture("mask", mask, 2);
maskBlurShader.setUniform2f("direction", 1, 0);
maskBlurShader.setUniform1i("k", k);
tex.draw(0, 0);
maskBlurShader.end();
buffer.end();

result.begin();
maskBlurShader.begin();
maskBlurShader.setUniformTexture("tex", buffer, 1);
maskBlurShader.setUniformTexture("mask", mask, 2);
maskBlurShader.setUniform2f("direction", 0, 1);
maskBlurShader.setUniform1i("k", k);
buffer.draw(0, 0);
maskBlurShader.end();
result.end();
}

void Clone::setStrength(int strength) {
this->strength = strength;
}

void Clone::update(ofTexture& src, ofTexture& dst, ofTexture& mask) {
maskedBlur(src, mask, srcBlur);
maskedBlur(dst, mask, dstBlur);

buffer.begin();
ofPushStyle();
ofEnableAlphaBlending();
dst.draw(0, 0);
cloneShader.begin();
cloneShader.setUniformTexture("src", src, 1);
cloneShader.setUniformTexture("srcBlur", srcBlur, 2);
cloneShader.setUniformTexture("dstBlur", dstBlur, 3);
dst.draw(0, 0);
cloneShader.end();
ofDisableAlphaBlending();
ofPopStyle();
buffer.end();
}

void Clone::draw(float x, float y) {
buffer.draw(x, y);
}
17 changes: 17 additions & 0 deletions example-facesubstitution/src/Clone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "ofMain.h"

class Clone {
public:
void setup(int width, int height);
void setStrength(int strength);
void update(ofTexture& src, ofTexture& dst, ofTexture& mask);
void draw(float x, float y);

protected:
void maskedBlur(ofTexture& tex, ofTexture& mask, ofFbo& result);
ofFbo buffer, srcBlur, dstBlur;
ofShader maskBlurShader, cloneShader;
int strength;
};
38 changes: 38 additions & 0 deletions example-facesubstitution/src/Coord.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include "ofMain.h"

struct Coord
{
int x;
int y;

bool operator==(const Coord &other) const
{
return (x == other.x
&& y == other.y);
}
};

namespace std {

template <>
struct hash<Coord>
{
std::size_t operator()(const Coord& k) const
{
using std::size_t;
using std::hash;
using std::string;

// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:

size_t h1 = std::hash<int>()(k.x);
size_t h2 = std::hash<int>()(k.y);
return (h1 ^ (h2 << 1));
}
};

}
Loading