xxxxxxxxxx
350
/*
This code is designed around the creative motif of "a mirror reflecting my emotions." It serves as a vivid and interactive visualization of human feelings, translating them into a virtual canvas where emotions become tangible and observable.
Emotion Color Spectrum:
The emotion-driven nature of the design is expressed through a color spectrum. Using a predefined set of colors, the code changes the background color based on the intensity of the user's voice. As emotions grow more intense, the colors adapt dynamically, symbolizing the fluctuating nature of human feelings. This represents the varying shades of emotions that can be experienced at different moments, echoing the complex and ever-changing nature of human sentiment.
Karaoke Room Inspiration:
Inspired by the lively ambiance of a karaoke room, an additional aspect of the code introduces music-related elements. A turntable is drawn on a dedicated layer, encapsulating the joy and excitement of singing along to favorite tunes. The rotation and visual elements of the turntable create a playful and musical mood, embodying the desire to express oneself freely and joyously.
*/
let think_layer;
let mic_layer;
let colors = ["#FC5882", "#FC5858", "#FC7958",
"#FC9A58", "#FCAA58", "#FCE858",
"#E8FC58", "#D3FC58", "#AAFC58",
"#58FC58", "#58FCAA", "#58FCD3",
"#58E8FC", "#58D3FC", "#58AAFC",
"#5858FC", "#9658FC", "#8000FF",
"#BF00FF", "#FC58FC", "#FC58D3", "#FC58AA"];
let mic;
let currentColorIndex = 0;
let flag_music = true;
let img_sonic;
// ml5 related code: Copyright (c) 2019 ml5 This software is released under the MIT License. https://opensource.org/licenses/MIT
let video;
let poseNet;
let poses = [];
let predictions = [];
let img_mic;
function preload() {
img_mic = loadImage('pngwing.com.png');
img_sonic = loadImage('Sonic.jpeg')
}
function setup() {
mic = new p5.AudioIn();
mic.start();
fft = new p5.FFT();
fft.setInput(mic);
createCanvas(640, 480);
video = createCapture(VIDEO);
video.size(width, height);
// Create a new poseNet method with a single detection
poseNet = ml5.poseNet(video, poseNetModelReady);
// This sets up an event that fills the global variable "poses"
// with an array every time new poses are detected
poseNet.on("pose", function (results) {
poses = results;
});
// Hide the video element, and just show the canvas
facemesh_layer = createGraphics(width, height);
body_keypoints_layer = createGraphics(width, height);
skeleton_layer = createGraphics(width, height);
pendraw_layer = createGraphics(width, height);
turntable_layer = createGraphics(width, height);
think_layer = createGraphics(width, height);
mic_layer = createGraphics(width, height);
video.hide();
}
function poseNetModelReady() {
console.log("poseNet Model ready!");
facemesh = ml5.facemesh(video, faceMeshModelReady);
facemesh.on("predict", (results) => {
predictions = results;
});
}
function faceMeshModelReady() {
console.log("faceMesh Model ready!");
}
function draw() {
if (frameCount % 10 == 0) {
clearScreen();
}
let vol = mic.getLevel();
currentColorIndex = int(map(vol, 0, 0.1, 0, colors.length));
currentColorIndex = constrain(currentColorIndex, 0, colors.length - 1);
// We can call both functions to draw all keypoints and the skeletons
drawFacemeshKeypoints();
drawSkeleton();
drawBodyKeypoints();
drawMicLevel(50, 50);
let spd = map(vol, 0, 1, 0.1, 2)
drawTurntable(100, 100, currentColorIndex*0.3, currentColorIndex*0.1);
drawThinkText();
image(video, 0, 0, width, height);
image(facemesh_layer, 0, 0, width, height);
image(skeleton_layer, 0, 0, width, height);
image(body_keypoints_layer, 0, 0, width, height);
image(think_layer, 0, 0, width, height);
image(turntable_layer, 0, 0, width, height);
pendraw();
noStroke()
mX = map(mouseX, 0, width, 0, 25)
mY = map(mouseY, 0, height, -5, 15)
// Display the microphone level layer
image(mic_layer, 0, 150, width, height);
mic_layer.clear();
// You can call the drawMicLevel function at the desired coordinates
// 볼륨에 따라 currentColorIndex 업데이트
fill(hexToColor(colors[currentColorIndex], 100));
for(var i=0; i<640; i+=20){
for(var j=0; j<480; j+=20){
ellipse(i, j, mX+mY, mX+mY)
}
}
}
// A function to draw ellipses over the detected keypoints
function drawBodyKeypoints() {
// Loop through all the poses detected
for (let i = 0; i < poses.length; i++) {
// For each pose detected, loop through all the keypoints
let pose = poses[i].pose;
for (let j = 0; j < pose.keypoints.length; j++) {
// A keypoint is an object describing a body part (like rightArm or leftShoulder)
let keypoint = pose.keypoints[j];
let x = keypoint.position.x;
let y = keypoint.position.y;
// Only draw an ellipse is the pose probability is bigger than 0.2
if (keypoint.score > 0.2) {
body_keypoints_layer.push();
body_keypoints_layer.noStroke();
body_keypoints_layer.circle(x, y, 20);
body_keypoints_layer.textAlign(CENTER, CENTER);
body_keypoints_layer.text(j, x, y);
body_keypoints_layer.textSize(20);
if (j == 1 || j == 2) {
body_keypoints_layer.textSize(42);
body_keypoints_layer.text("👀", x, y);
} else if (j == 10) {
body_keypoints_layer.textSize(84);
body_keypoints_layer.image(img_mic, x-100, y-90, 100, 100);
body_keypoints_layer.text("💪", x, y);
}
body_keypoints_layer.pop();
}
}
}
}
function drawFacemeshKeypoints() {
for (let i = 0; i < predictions.length; i += 1) {
const keypoints = predictions[i].scaledMesh;
// Draw facial keypoints.
for (let j = 0; j < keypoints.length; j += 1) {
const [x, y] = keypoints[j];
facemesh_layer.push();
facemesh_layer.noStroke()
facemesh_layer.fill(hexToColor(colors[currentColorIndex], 100));
facemesh_layer.circle(x, y, 3);
facemesh_layer.pop();
}
}
}
// A function to draw the skeletons
// A function to draw the skeletons
function drawSkeleton() {
// Loop through all the skeletons detected
for (let i = 0; i < poses.length; i++) {
let skeleton = poses[i].skeleton;
// For every skeleton, loop through all body connections
for (let j = 0; j < skeleton.length; j++) {
let partA = skeleton[j][0];
let partB = skeleton[j][1];
skeleton_layer.push();
skeleton_layer.strokeWeight(5); // 선의 두께 변경
skeleton_layer.stroke("purple"); // 선의 색상 변경
skeleton_layer.line(
partA.position.x,
partA.position.y,
partB.position.x,
partB.position.y
);
skeleton_layer.pop();
}
}
}
function clearScreen() {
facemesh_layer.clear();
skeleton_layer.clear();
body_keypoints_layer.clear();
}
function keyPressed() {
if (key == "1") {
facemesh_layer.clear();
} else if (key == "2") {
skeleton_layer.clear();
} else if (key == "3") {
body_keypoints_layer.clear();
}
}
function hexToColor(hex, alpha = 255) {
let r = parseInt(hex.slice(1, 3), 16);
let g = parseInt(hex.slice(3, 5), 16);
let b = parseInt(hex.slice(5, 7), 16);
return color(r, g, b, alpha);
}
let path = [];
let prevMouseX = null;
let prevMouseY = null;
function pendraw() {
if (mouseIsPressed) {
path.push({ x: mouseX, y: mouseY });
if (prevMouseX && prevMouseY) {
pendraw_layer.strokeWeight(5);
pendraw_layer.stroke(0);
pendraw_layer.line(prevMouseX, prevMouseY, mouseX, mouseY);
}
prevMouseX = mouseX;
prevMouseY = mouseY;
} else {
path = [];
prevMouseX = null;
prevMouseY = null;
}
// 레이어 이미지 표시
image(pendraw_layer, 0, 0);
}
function keyPressed() {
if (key == "s") {
pendraw_layer.clear();
turntable_layer.clear();
}
if (key === 'e') {
saveGif('mySketch', 5);
}
// 기존 keyPressed 코드...
}
function drawTurntable(x, y, s, speed){
turntable_layer.push();
turntable_layer.translate(x, y);
turntable_layer.scale(s);
if (flag_music){
angle = frameCount * speed;
// Rotate the canvas
turntable_layer.rotate(angle);
}
turntable_layer.fill("#192D4D");
turntable_layer.circle(0, 0, 100);
let imgsize = 40;
turntable_layer.imageMode(CENTER);
turntable_layer.image(img_sonic, 0, 0, imgsize, imgsize);
turntable_layer.noStroke();
turntable_layer.fill("#f5f5dc");
turntable_layer.circle(0, 0, 10);
turntable_layer.noFill();
turntable_layer.stroke("#1A1919");
turntable_layer.circle(0, 0, 10);
let stWeight = 4;
turntable_layer.strokeWeight(stWeight);
let flipflap = true;
for (let i = imgsize; i < 100; i += stWeight){
if (flipflap == true){
turntable_layer.stroke("#1A1919");
flipflap = false;
} else {
turntable_layer.stroke("#312E2E");
flipflap = true;
}
turntable_layer.circle(0, 0, i);
}
turntable_layer.pop();
}
function drawThinkText() {
// Clear the previous "Think" text
think_layer.clear();
// Generate random coordinates for the text position
let x = random(width);
let y = random(height);
// Select a random color from the defined colors array
let colorIndex = floor(random(colors.length));
let c = colors[colorIndex];
// Set the text properties and draw the word "Think"
think_layer.push();
think_layer.fill(c);
think_layer.textSize(32);
think_layer.textAlign(CENTER, CENTER);
think_layer.text("Think", x, y);
think_layer.pop();
}
function drawMicLevel(x, y) {
mic_layer.push();
mic_layer.translate(x, y);
mic_layer.fill("black");
mic_layer.text("click to start mic", 50, 30);
micLevel = mic.getLevel();
//text(micLevel, width / 2, height / 2);
let waveform = fft.waveform();
mic_layer.noFill();
mic_layer.beginShape();
mic_layer.stroke(20);
for (let i = 0; i < waveform.length; i++){
let x = mic_layer.map(i, 0, waveform.length, 0, mic_layer.width);
let y = mic_layer.map(waveform[i], -1, 1, 0, mic_layer.height);
mic_layer.vertex(x, y);
}
mic_layer.endShape();
mic_layer.pop();
}