diff --git a/bin/data/scenes/yingKnowlton/exampleCode.cpp b/bin/data/scenes/yingKnowlton/exampleCode.cpp new file mode 100644 index 0000000..8b048d9 --- /dev/null +++ b/bin/data/scenes/yingKnowlton/exampleCode.cpp @@ -0,0 +1,33 @@ + +void draw() { + + currentVideo = getVideo([[videoNum]]).draw(); + + for (int i = 0; i < [[iterations]]; i++) { + + if (random() < [[mixRatio]]) { + targetImage = currentVideo; + } else { + targetImage = originalImage; + } + + for (int i = 0; i < imageWidth; i++) { + for (int j = 0; j < imageHeight; j++) { + + int randX = random(0, imageWidth); + int randY = random(0, imageHeight); + + // randomly swap a pixel + sourceImageAfterSwap = sourceImage.swapPixels(i,j, randX, randY); + + if (distanceToOriginal(sourceImageAfterSwap) < + distanceToOriginal(sourceImage)) { + sourceImage = sourceImageAfterSwap; + } + } + } + + + } + sourceImage.draw(); +} diff --git a/bin/data/scenes/yingKnowlton/sfpc-final_640.png b/bin/data/scenes/yingKnowlton/sfpc-final_640.png new file mode 100644 index 0000000..93b39a0 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/sfpc-final_640.png differ diff --git a/bin/data/scenes/yingKnowlton/videos/ann-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/ann-scaled.mp4 new file mode 100644 index 0000000..5d98702 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/ann-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/diego_640-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/diego_640-scaled.mp4 new file mode 100644 index 0000000..81398af Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/diego_640-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/fernando-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/fernando-scaled.mp4 new file mode 100644 index 0000000..8b776e4 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/fernando-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/heather_640-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/heather_640-scaled.mp4 new file mode 100644 index 0000000..9e5f113 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/heather_640-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/mattj_640-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/mattj_640-scaled.mp4 new file mode 100644 index 0000000..892ff5a Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/mattj_640-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/nik-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/nik-scaled.mp4 new file mode 100644 index 0000000..6f1a3eb Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/nik-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/qiao-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/qiao-scaled.mp4 new file mode 100644 index 0000000..8933c79 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/qiao-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/stacy-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/stacy-scaled.mp4 new file mode 100644 index 0000000..8342aaf Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/stacy-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/wei-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/wei-scaled.mp4 new file mode 100644 index 0000000..7332ed4 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/wei-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/ying_640-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/ying_640-scaled.mp4 new file mode 100644 index 0000000..de6f0a3 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/ying_640-scaled.mp4 differ diff --git a/bin/data/scenes/yingKnowlton/videos/yumi_640-scaled.mp4 b/bin/data/scenes/yingKnowlton/videos/yumi_640-scaled.mp4 new file mode 100644 index 0000000..786c1e7 Binary files /dev/null and b/bin/data/scenes/yingKnowlton/videos/yumi_640-scaled.mp4 differ diff --git a/recoded.xcodeproj/project.pbxproj b/recoded.xcodeproj/project.pbxproj index 761ed2b..d10c79c 100644 --- a/recoded.xcodeproj/project.pbxproj +++ b/recoded.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 2AAF4613693D9695224E47EA /* annMolnarRectangles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D790E5FFA07829E87D5854B1 /* annMolnarRectangles.cpp */; }; 2CDF949125CD5802082364F3 /* mattKnowlton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A39AE0D2FA3A4C9F76FC4E61 /* mattKnowlton.cpp */; }; 2DE293FAAF850C0ABF02DB62 /* exampleScene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 59429ADBB14FCD19148E74FB /* exampleScene.cpp */; }; + 2E55175E1FBC8D0300D6B8C9 /* yingKnowlton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2E55175D1FBC8CFD00D6B8C9 /* yingKnowlton.cpp */; }; 2E555A4FA8AD6EA2CA95AACF /* loloWhitney.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6397CED8F069F8CCB13C01F /* loloWhitney.cpp */; }; 2E6C274B1FBA494600D54DC9 /* zzSushiScene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2E6C27491FBA48AC00D54DC9 /* zzSushiScene.cpp */; }; 310ED8BB549B244C0DFB0FA1 /* mgsVeraMolnarLineStudy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA88C1467946DA7D2C11601B /* mgsVeraMolnarLineStudy.cpp */; }; @@ -246,6 +247,8 @@ 2BAEA0543B2829CB46F35032 /* mgsRileyEllipsesAndSquares.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 30; name = mgsRileyEllipsesAndSquares.cpp; path = src/scenes/mgsRileyEllipsesAndSquares/mgsRileyEllipsesAndSquares.cpp; sourceTree = SOURCE_ROOT; }; 2DB66B4D75A388D55904F54F /* fernandoWhitney2.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = fernandoWhitney2.h; path = src/scenes/fernandoWhitney2/fernandoWhitney2.h; sourceTree = SOURCE_ROOT; }; 2E3CEE46463AC03FCB57EC56 /* loloVera.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = loloVera.h; path = src/scenes/loloVera/loloVera.h; sourceTree = SOURCE_ROOT; }; + 2E55175C1FBC8CFD00D6B8C9 /* yingKnowlton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = yingKnowlton.h; sourceTree = ""; }; + 2E55175D1FBC8CFD00D6B8C9 /* yingKnowlton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = yingKnowlton.cpp; sourceTree = ""; }; 2E6C27491FBA48AC00D54DC9 /* zzSushiScene.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = zzSushiScene.cpp; sourceTree = ""; }; 2E6C274A1FBA48AC00D54DC9 /* zzSushiScene.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zzSushiScene.h; sourceTree = ""; }; 2F409986A645F575A744FC98 /* EstherKnowltonScene.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 30; name = EstherKnowltonScene.h; path = src/scenes/EstherKnowltonScene/EstherKnowltonScene.h; sourceTree = SOURCE_ROOT; }; @@ -713,6 +716,16 @@ name = mgsCooperSymbols; sourceTree = ""; }; + 2E55175B1FBC8CFD00D6B8C9 /* yingKnowlton */ = { + isa = PBXGroup; + children = ( + 2E55175C1FBC8CFD00D6B8C9 /* yingKnowlton.h */, + 2E55175D1FBC8CFD00D6B8C9 /* yingKnowlton.cpp */, + ); + name = yingKnowlton; + path = scenes/yingKnowlton; + sourceTree = ""; + }; 2E6C27481FBA48AC00D54DC9 /* zzSushiScene */ = { isa = PBXGroup; children = ( @@ -788,6 +801,7 @@ 36BF1C038F5AEC4D85473FE4 /* scenes */ = { isa = PBXGroup; children = ( + 2E55175B1FBC8CFD00D6B8C9 /* yingKnowlton */, B0822B3B1FB786C900007B2D /* Guillermo_Whitney_catalogue_1 */, B0822B311FB565DC00007B2D /* stacyButterflies */, B0822B2D1FB5646A00007B2D /* diegoScene_01 */, @@ -2226,6 +2240,7 @@ D391E4FB2414857BD467D9E8 /* gif_font.c in Sources */, B0822AE51FB5491200007B2D /* ofxMidiMessage.cpp in Sources */, 149FF2205EB6D2EB34272D36 /* gif_hash.c in Sources */, + 2E55175E1FBC8D0300D6B8C9 /* yingKnowlton.cpp in Sources */, FFBFC666B626901721B1798A /* gifalloc.c in Sources */, 928A7D091FBB5BDE003A2403 /* zzEggScene.cpp in Sources */, F3339D42B1A22AEF847B1F85 /* quantize.c in Sources */, diff --git a/src/sceneManager.cpp b/src/sceneManager.cpp index c28c28d..9aea6a5 100644 --- a/src/sceneManager.cpp +++ b/src/sceneManager.cpp @@ -89,6 +89,7 @@ #include "diegoScene_01.h" #include "stacyButterflies.h" #include "EstherMolnarScene.h" +#include "yingKnowlton.h" // these are food related scenes @@ -198,6 +199,7 @@ void sceneManager::setup(){ scenes.push_back(new annMolnarRectangles()); scenes.push_back(new weiWhitney()); scenes.push_back(new yumiNishida01()); + scenes.push_back(new yingKnowlton()); #endif diff --git a/src/scenes/yingKnowlton/yingKnowlton.cpp b/src/scenes/yingKnowlton/yingKnowlton.cpp new file mode 100644 index 0000000..7475265 --- /dev/null +++ b/src/scenes/yingKnowlton/yingKnowlton.cpp @@ -0,0 +1,195 @@ + +#include "yingKnowlton.h" + +void yingKnowlton::setup(){ + + originalImage.load("scenes/yingKnowlton/sfpc-final_640.png"); + originalImage.setImageType(OF_IMAGE_COLOR); + sourceImage.load("scenes/yingKnowlton/sfpc-final_640.png"); + sourceImage.setImageType(OF_IMAGE_COLOR); + targetScores = NULL; + + ofBackground(0); + + res = 4; + + // note: pulled from @sfpc_nyc instagram feed + directory = ofDirectory("scenes/yingKnowlton/videos/"); + directory.listDir(); + + playVideo(0); + center.set(dimensions.width/2, dimensions.height/2); + screenScale = dimensions.width/vidPlayer.getWidth(); + screenScale *= 1.01; // MULTIPLY HERE TO MAKE EDGES BLEED PAST THE SCREEN + + parameters.add(videoNum.set("videoNum", 0, 0, directory.size())); + parameters.add(iterations.set("iterations", 5000, 10, 10000)); + parameters.add(mixRatio.set("mixRatio", 1, 0, 1)); + + setAuthor("Ying Quan Tan"); + setOriginalArtist("Ken Knowlton"); + loadCode("scenes/yingKnowlton/exampleCode.cpp"); +} + +void yingKnowlton::update(){ + vidPlayer.update(); + if (vidPlayer.isPlaying() && vidPlayer.getTotalNumFrames() - vidPlayer.getCurrentFrame() < 30) { + videoNum = ++videoNum % directory.size(); + playVideo(videoNum); + } + if (current != videoNum) { + current = videoNum; + playVideo(videoNum); + } +} + +void yingKnowlton::draw(){ + ofPushMatrix(); + + int vidWidth = vidPlayer.getWidth() * screenScale; + int vidHeight = vidPlayer.getHeight() * screenScale; + // center the video + ofTranslate(center - ofPoint(vidWidth, vidHeight)/2); + + // make sure video scales to screen. + ofScale(screenScale, screenScale); + + + if ((vidPlayer.isPlaying() && sourceImage.isAllocated())) { + unsigned char * vidPixels = vidPlayer.getPixels().getData(); + unsigned char * originalPixels = originalImage.getPixels().getData(); + + ofImage &image = sourceImage; + int cols = image.getWidth() / res; + int rows = image.getHeight() / res; + int positions = cols * rows; + int bytesPerPixel = 3; + + for (int it = 0; it < iterations; it++) { + unsigned char * targetPointer; + if (ofRandom(1.0) < mixRatio) { + targetPointer = vidPixels; + } else { + targetPointer = originalPixels; + } + + int i = floor(ofRandom(cols)) * res; + int j = floor(ofRandom(rows)) * res; + float previousTargetScore = targetScore; + int index = (j * image.getWidth() + i) * bytesPerPixel; + int x = i / res; + int y = j / res; + + int randX = floor(ofRandom(cols)) * res; + int randY = floor(ofRandom(rows)) * res; + int randIndex = (randY * image.getWidth() + randX) * bytesPerPixel; + + unsigned char * from = getSubImage(image, i, j, res); + unsigned char * to = getSubImage(image, randX, randY, res); + + // calculate costs + float fromScore = distance(from, targetPointer + index); + float toScore = distance(to, targetPointer + randIndex); + + float afterSwapFromScore = distance(to, targetPointer + index); + float afterSwapToScore = distance(from, targetPointer + randIndex); + + if (afterSwapFromScore + afterSwapToScore < fromScore + toScore) { + // perform swap + setSubImage(image, i, j, res, to); + setSubImage(image, randX, randY, res, from); + } + delete[] from; + delete[] to; + } + + image.update(); + image.draw(0, 0); + } + ofPopMatrix(); +} + +void yingKnowlton::playVideo(int index) { + vidPlayer.load(directory.getPath(index)); + int cols = vidPlayer.getWidth() / res; + int rows = vidPlayer.getHeight() / res; + if (targetScores == NULL) { + targetScores = new unsigned char[cols * rows]; + } + memset(targetScores,0,cols * rows); + + vidPlayer.setVolume(0); + vidPlayer.play(); + +} + +unsigned char * yingKnowlton::getSubImage(ofImage &image, + int _x, + int _y, + int maskSize) { + int bytesPerPixel = 3; + unsigned char * subImage = new unsigned char[maskSize * maskSize * bytesPerPixel]; + unsigned char * data = image.getPixels().getData(); + + int c = 0; + for (int y = _y; y < _y + maskSize; y++) { + for (int x = _x; x < _x + maskSize; x++) { + int idx = y * image.getWidth()*bytesPerPixel + x*bytesPerPixel; + for (int i = 0; i < bytesPerPixel; i++) { + subImage[c + i] = data[idx + i]; + } + c += bytesPerPixel; + } + } + return subImage; +} + + +void yingKnowlton::setSubImage(ofImage &image, + int _x, + int _y, + int maskSize, + unsigned char * subImage) { + int bytesPerPixel = 3; + unsigned char * data = image.getPixels().getData(); + int c = 0; + for (int y = _y; y < _y + maskSize; y++) { + for (int x = _x; x < _x + maskSize; x++) { + int idx = (y * image.getWidth() + x) * bytesPerPixel; + for (int i = 0; i < bytesPerPixel; i++) { + data[idx + i] = subImage[c + i]; + } + c += bytesPerPixel; + } + } +} + +float yingKnowlton::distance(unsigned char * pixel1, + unsigned char * pixel2) { + + float r1 = pixel1[0]; + float g1 = pixel1[1]; + float b1 = pixel1[2]; + + float r2 = pixel2[0]; + float g2 = pixel2[1]; + float b2 = pixel2[2]; + + float dist = abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2); + dist /= (255*3); + return dist; +} + +float yingKnowlton::getTargetScore() { + + float total = 0; + int cols = sourceImage.getWidth() / res; + int rows = sourceImage.getHeight() / res; + for (int i = 0; i < cols; i++) { + for (int j = 0; j < rows; j++) { + int score = targetScores[j * cols + i]; + total += score; + } + } + return total; +} diff --git a/src/scenes/yingKnowlton/yingKnowlton.h b/src/scenes/yingKnowlton/yingKnowlton.h new file mode 100644 index 0000000..736891b --- /dev/null +++ b/src/scenes/yingKnowlton/yingKnowlton.h @@ -0,0 +1,45 @@ +#pragma once + +#include "ofMain.h" +#include "baseScene.h" + +class yingKnowlton : public baseScene { + +public: + + void setup(); + void update(); + void draw(); + + int res; + ofVideoPlayer vidPlayer; + ofImage sourceImage; + ofImage originalImage; + ofImage targetImage; + ofPoint center; + float screenScale; + unsigned char * targetScores; + float targetScore; + + unsigned char * getSubImage(ofImage &image, + int x, + int y, + int maskSize); + void setSubImage(ofImage &image, + int x, + int y, + int maskSize, + unsigned char * subImage); + float distance(unsigned char * pixel1, + unsigned char * pixel2); + float getTargetScore(); + + void playVideo(int index); + + + int current; + ofParameter < float > mixRatio; + ofParameter < int > videoNum; + ofParameter < int > iterations; + ofDirectory directory; +};