Oh, that naughty sketch! Please let us know what the issue is below.
Apply Template
Applying this template will reset your sketch and remove all your changes. Are you sure you would like to continue?
Report Sketch
Report Comment
Please confirm that you would like to report the comment below.
We will review your submission and take any actions necessary per our Community Guidelines. In addition to reporting this comment, you can also block the user to prevent any future interactions.
Please report comments only when necessary. Unnecessary or abusive use of this tool may result in your own account being suspended.
Are you sure you want to delete your sketch?
Any files uploaded will be deleted as well.
Delete Comment?
This will also delete all the replies to this comment.
Delete this tab? Any code in it will be deleted as well.
Select a collection to submit your sketch
We Need Your Support
Since 2008, OpenProcessing has provided tools for creative coders to learn, create, and share over a million open source projects in a friendly environment.
Niche websites like ours need your continued support for future development and maintenance, while keeping it an ad-free platform that respects your data and privacy!
Please consider subscribing below to show your support with a "Plus" badge on your profile and get access to many other features!
A fork of FaceExtractor-2024 by Golan Levin
CC Attribution NonCommercial NoDerivatives
FaceWork1
Levin
xxxxxxxxxx
// Uses p5.js v.1.9.2 + MediaPipe v.0.10.12
// Global variables.
let myFaceLandmarker;
let faceLandmarks;
let myCapture;
let lastVideoTime = -1;
let maskGfx;
let faceGfx;
let compGfx;
let mainGfx;
const maskThx = 40;
const camW = 640;
const camH = 480;
const imgW = 360;
const imgH = 640;
const winW = 540;
const winH = 960;
let dxdySc;
let myPoints = [];
let cxcy;
let facePercent = 0.6;//1.15;
let grdC = 96;
let particles = [];
let velocities = [];
const trackingConfig = {
cpuOrGpuString: "GPU",
/* "GPU" or "CPU" */
maxNumFaces: 1,
};
//------------------------------------------
async function preload() {
const mediapipe_module = await import('https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js');
FaceLandmarker = mediapipe_module.FaceLandmarker;
FilesetResolver = mediapipe_module.FilesetResolver;
const vision = await FilesetResolver.forVisionTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.12/wasm"
);
myFaceLandmarker = await FaceLandmarker.createFromOptions(vision, {
numFaces: trackingConfig.maxNumFaces,
runningMode: "VIDEO",
outputFaceBlendshapes: false,
baseOptions: {
delegate: trackingConfig.cpuOrGpuString,
modelAssetPath: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task",
},
});
}
//------------------------------------------
async function predictWebcam() {
let startTimeMs = performance.now();
if (lastVideoTime !== myCapture.elt.currentTime) {
if (myFaceLandmarker) {
faceLandmarks = myFaceLandmarker.detectForVideo(myCapture.elt, startTimeMs);
}
lastVideoTime = myCapture.elt.currentTime;
}
window.requestAnimationFrame(predictWebcam);
}
//------------------------------------------
function setup() {
createCanvas(winW, winH);
frameRate(60);
myCapture = createCapture(VIDEO);
myCapture.size(camW, camH);
myCapture.hide();
faceGfx = createGraphics(imgW, imgH);
maskGfx = createGraphics(imgW, imgH);
compGfx = createGraphics(imgW, imgH);
mainGfx = createGraphics(imgW, imgH);
faceGfx.background(0, 0, 0);
maskGfx.background(0, 0, 0);
compGfx.background(0, 0, 0);
mainGfx.background(0, 0, 0);
maskGfx.pixelDensity(1);
mainGfx.pixelDensity(1);
compGfx.pixelDensity(1);
mainGfx.pixelDensity(1);
dxdySc = createVector(0,0,1);
cxcy = createVector(0.5, 0.5, 0);
for (let i=0; i<5000; i++){
let rx = random(0,width);
let ry = random(0,height);
particles[i] = createVector(rx,ry);
let ra = random(0,0.25*TWO_PI);
velocities[i] = createVector(30*cos(ra),30*sin(ra));
}
}
function getTranslationAndScale(){
if (faceLandmarks && faceLandmarks.faceLandmarks) {
const nFaces = faceLandmarks.faceLandmarks.length;
if (nFaces >= 1) {
let aFace = faceLandmarks.faceLandmarks[0];
if (aFace) {
myPoints = [];
// Get translation:
// centroid of face in camera image
let dx = 0;
let dy = 0;
for (let i = 0; i < aFace.length; i++) {
let px = map(aFace[i].x, 0, 1, camW, 0);
let py = map(aFace[i].y, 0, 1, 0, camH);
myPoints.push(createVector(px, py));
dx += px;
dy += py;
}
dx /= myPoints.length;
dy /= myPoints.length;
// Get scale
let tx = myPoints[10].x;
let ty = myPoints[10].y;
let bx = myPoints[152].x;
let by = myPoints[152].y;
let len = dist(tx,ty,bx,by);
let sca = (imgH*facePercent)/len ;
// distance from point to line
let noseAxisDist = pointLineDistance(myPoints[10], myPoints[152], myPoints[4]);
let noseAxisPct = noseAxisDist / len;
let nx = myPoints[4].x;
let ny = myPoints[4].y;
let v1 = createVector(tx-nx, ty-ny);
let v2 = createVector(bx-nx, by-ny);
let cp = p5.Vector.cross(v1, v2);
let cpzs = (cp.z < 0)? -1:1;
let axcos = 1-abs(cos(atan2(ty-by,tx-bx)));
cxcy.x = 0.5 - noseAxisPct*cpzs*axcos;
cxcy.y = 0.5;
// Blur over time, set global
const dA = 0.25;
const dB = 1.0-dA;
dxdySc.x = dA*dxdySc.x + dB*dx;
dxdySc.y = dA*dxdySc.y + dB*dy;
dxdySc.z = dA*dxdySc.z + dB*sca;
for (let i = 0; i < myPoints.length; i++) {
myPoints[i].x = ((myPoints[i].x - dxdySc.x) * dxdySc.z) + imgW*cxcy.x;
myPoints[i].y = ((myPoints[i].y - dxdySc.y) * dxdySc.z) + imgH*cxcy.y;
}
}
}
}
}
function pointLineDistance ( p1, p2, p3){
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
if ((dx == 0) && (dy == 0)) {
return 0;
}
let u = ((p3.x - p1.x)*dx + (p3.y - p1.y)*dy) / (dx*dx + dy*dy);
let ax = (p1.x + p2.x)/2;
let ay = (p1.y + p2.y)/2;
if (u < 0) {
ax = p1.x;
ay = p1.y;
} else if (u > 1) {
ax = p2.x;
ay = p2.y;
} else {
ax = p1.x + u * dx;
ay = p1.y + u * dy;
}
return dist(p3.x,p3.y, ax,ay);
}
function draw(){
background('pink');
predictWebcam();
getTranslationAndScale();
renderFaceIntoComp();
renderHullOntoComp();
/*
BLEND, DARKEST, LIGHTEST, DIFFERENCE, MULTIPLY, EXCLUSION, SCREEN, R
EPLACE, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN, ADD, REMOVE or SUBTRACT
*/
mainGfx.clear();
mainGfx.background(0);
mainGfx.blendMode(SCREEN); //SCREEN
mainGfx.image(compGfx, 0,0,imgW,imgH);
mainGfx.filter(BLUR, 2); // base blur on sca
push();
scale(winW/imgW);
image(mainGfx,0,0, imgW,imgH);
// drawFacePoints();
pop();
}
function renderHullOntoComp(){
let myHull = makeHull(myPoints);
maskGfx.background(0,0,0, 20);
maskGfx.fill('white');
maskGfx.stroke('white');
maskGfx.strokeWeight(7);
maskGfx.beginShape();
for (let i = 0; i < myHull.length; i++) {
maskGfx.vertex(myHull[i].x, myHull[i].y);
}
maskGfx.endShape(CLOSE);
maskGfx.filter(BLUR, 6);
compGfx.blendMode(MULTIPLY);
compGfx.image(maskGfx, 0,0,imgW,imgH);
// compGfx.filter(BLUR, 2);
}
function renderFaceIntoComp(){
faceGfx.clear();
faceGfx.background(0,0,0);
faceGfx.push();
faceGfx.translate( imgW*cxcy.x, imgH*cxcy.y);
faceGfx.scale(dxdySc.z);
faceGfx.translate(-dxdySc.x,-dxdySc.y);
faceGfx.translate(camW,0);
faceGfx.scale(-1, 1);
faceGfx.image(myCapture, 0,0, camW,camH);
faceGfx.filter(GRAY);
faceGfx.pop();
compGfx.blendMode(BLEND);
compGfx.image(faceGfx, 0,0,imgW,imgH);
}
//------------------------------------------
// Tracks 478 points on the face.
function drawFacePoints() {
if (faceLandmarks && faceLandmarks.faceLandmarks) {
const nFaces = faceLandmarks.faceLandmarks.length;
if (nFaces > 0) {
for (let f = 0; f < nFaces; f++) {
let aFace = faceLandmarks.faceLandmarks[f];
if (aFace) {
fill('black');
noStroke();
push();
translate( imgW*cxcy.x, imgH*cxcy.y);
scale(dxdySc.z);
translate(-dxdySc.x,-dxdySc.y);
let nFaceLandmarks = aFace.length;
for (let i = 0; i < nFaceLandmarks; i++) {
let px = map(aFace[i].x, 0, 1, camW, 0);
let py = map(aFace[i].y, 0, 1, 0, camH);
fill('black');
circle(px, py, 2);
}
pop();
}
}
}
}
}
function draw2() {
predictWebcam();
if (faceLandmarks && faceLandmarks.faceLandmarks) {
const nFaces = faceLandmarks.faceLandmarks.length;
if (nFaces >= 1) {
let aFace = faceLandmarks.faceLandmarks[0];
if (aFace) {
getTranslationAndScale();
const imgSx = imgW/width;
const imgSy = imgH/height;
let dx = dxdySc.x;
let dy = dxdySc.y;
let sca = dxdySc.z;
faceGfx.clear();
faceGfx.background(0,0,0);
faceGfx.push();
faceGfx.scale(imgSx, imgSy);
faceGfx.translate( width/2, height/2);
faceGfx.scale(sca,sca);
faceGfx.translate(-dx,-dy);
faceGfx.translate(camW,0);
faceGfx.scale(-1, 1);
faceGfx.image(myCapture, 0,0, camW,camH);
faceGfx.filter(GRAY);
faceGfx.pop();
compGfx.blendMode(BLEND);
compGfx.image(faceGfx, 0,0,imgW,imgH);
let myHull = makeHull(myPoints);
maskGfx.background(0,0,0, 20);
maskGfx.fill('white');
maskGfx.stroke('white');
maskGfx.strokeWeight(5);
maskGfx.beginShape();
for (let i = 0; i < myHull.length; i++) {
maskGfx.vertex(myHull[i].x*imgSx, myHull[i].y*imgSy);
}
maskGfx.endShape(CLOSE);
maskGfx.filter(BLUR, 5);
compGfx.blendMode(MULTIPLY);
compGfx.image(maskGfx, 0,0,imgW,imgH);
mainGfx.clear();
mainGfx.background(0,0,0);
let ctx = mainGfx.canvas.getContext('2d');// canvas.getContext('2d');
let dh = dist(0,0,width,height)/2;
let myGradient = ctx.createRadialGradient(width/2, height/2, 1, width/2, height/2, dh);
myGradient.addColorStop(0, "rgb("+grdC+","+grdC+","+grdC+")");
myGradient.addColorStop(1, "black"); //"white");
ctx.fillStyle = myGradient;
ctx.fillRect(0, 0, width, height);
mainGfx.blendMode(ADD); //SCREEN
mainGfx.image(compGfx, 0,0,width,height);
mainGfx.filter(BLUR, 2); // base blur on sca
}
}
}
background(240,240,240,255);
tint(255,255,255,70);
image(mainGfx, 0,0, width,height);
drawFacePoints();
noStroke();
fill('red');
text(int(frameRate()), 30,30);
fill(0);
noStroke();
rectMode(CENTER);
const imgSx = width/imgW;
const imgSy = height/imgH;
mainGfx.loadPixels();
const mainPix = mainGfx.pixels;
if (mouseIsPressed){
for (let i=0; i<particles.length; i++){
const P = particles[i];
let col = mainPix[4*(int(P.y)*imgW + int(P.x))];
let colf = 0.01 + 0.99 * pow(col/255, 5.0);
P.x += colf * velocities[i].x;
P.y += colf * velocities[i].y;
if (P.y >= imgH){
P.y -= imgH;
} else if (P.y < 0){
P.y += imgH;
}
if (P.x >= imgW){
P.x -= imgW;
} else if (P.x < 0){
P.x += imgW;
}
square(imgSx*P.x,imgSx*P.y,2);
}
}
}
/*
* Convex hull algorithm - Library
* Copyright (c) 2021 Project Nayuki
* GNU General Public License v3.0+
* https://www.nayuki.io/page/convex-hull-algorithm
* https://www.nayuki.io/res/convex-hull-algorithm/convex-hull.js
*/
function makeHull(points) {
let newPoints = points.slice();
newPoints.sort(POINT_COMPARATOR);
return makeHullPresorted(newPoints);
}
function makeHullPresorted(points) {
if (points.length <= 1) return points.slice();
let upperHull = [];
for (let i = 0; i < points.length; i++) {
const p = points[i];
while (upperHull.length >= 2) {
const q = upperHull[upperHull.length - 1];
const r = upperHull[upperHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) {
upperHull.pop();
} else break;
}
upperHull.push(p);
}
upperHull.pop();
let lowerHull = [];
for (let i = points.length - 1; i >= 0; i--) {
const p = points[i];
while (lowerHull.length >= 2) {
const q = lowerHull[lowerHull.length - 1];
const r = lowerHull[lowerHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) {
lowerHull.pop();
} else break;
}
lowerHull.push(p);
}
lowerHull.pop();
if (
upperHull.length == 1 &&
lowerHull.length == 1 &&
upperHull[0].x == lowerHull[0].x &&
upperHull[0].y == lowerHull[0].y
) {
return upperHull;
} else return upperHull.concat(lowerHull);
}
function POINT_COMPARATOR(a, b) {
if (a.x < b.x) {
return -1;
} else if (a.x > b.x) {
return 1;
} else if (a.y < b.y) {
return -1;
} else if (a.y > b.y) {
return 1;
} else return 0;
}
See More Shortcuts
Please verify your email to comment
Verify Email