Ipseity

This project started as part of my research and theory course and is still ongoing. Using openFrameworks add-on ofOpenCV, the level of agitation of the user create a beautiful spirographed self-portrait, creating a coherent visual language of emotions and inviting them to self-soothe and reflect on their emotional state.

you can also find the code here

#include "ofMain.h"
#include "ofApp.h"
#include "ofAppGlutWindow.h"

//========================================================================
int main( ){

	ofSetupOpenGL(1280,720, OF_WINDOW);			// <-------- setup the GL context

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once
/*
 --------------- ATTENTION --------------
 Before running the project, fix a small ofxOpenCv bug.
 
 Currently the operation image = &iplImage raises error, if the image is not allocated.
 To fix it, open the addon's file addons/ofxOpenCv/src/ofxCvImage.cpp
 and find the following function definition:
 void ofxCvImage::operator = ( const IplImage* mom )
 In this function body, replace line
	if( mom->nChannels == cvImage->nChannels && mom->depth == cvImage->depth ){
 with the following line:
	if( !bAllocated || ( mom->nChannels == cvImage->nChannels && mom->depth == cvImage->depth ) ){
 
 (Note, without this fix, the following example lines flowX = &iplX; and flowY = &iplY;
 can raise runtime error)
 */
#include "ofMain.h"
#include "ofxOpenCv.h"
using namespace cv;

class ofApp : public ofBaseApp{

public:
	void setup();
	void update();
	void draw();
	
	float sumX, sumY, avgX, avgY;
	int numOfEntries;

    ofVideoGrabber video;
	bool calculatedFlow;

	ofxCvColorImage currentColor;		//First and second original images
	ofxCvGrayscaleImage gray1, gray2;	//Decimated grayscaled images
	ofxCvFloatImage flowX, flowY;		//Resulted optical flow in x and y axes

	ofVideoGrabber vidGrabber;
	deque<ofImage> imgBuffer;
	int maxBufferSize;
	void keyPressed(int key);

};
#include "ofApp.h"
#include "opencv2/opencv.hpp"

//optical flow based off of Dr Theo Papatheodorou's opticalFlow exercise for the computational arts MA at Goldsmiths, London 
//--------------------------------------------------------------
void ofApp::setup()
{
	ofBackground(0);
	ofSetFrameRate(60);
	ofSetBackgroundAuto(false);
	maxBufferSize = 1000;
    video.setDeviceID(0);
    video.setDesiredFrameRate(60);
    video.initGrabber(1280, 720);
    calculatedFlow = false;
	
}

//--------------------------------------------------------------
void ofApp::update(){

	video.update();

	if (video.isFrameNew())
	{
		//add to buffer
		ofImage img;
		img.setFromPixels(video.getPixels());
		img.mirror(false, true); // if you want to mirror input
		imgBuffer.push_front(img);
	}

	//if buffer reched max size
	if (imgBuffer.size() > maxBufferSize) imgBuffer.pop_back();



		//Decode the new frame if needed

	if ( video.isFrameNew() )
        {
		if ( gray1.bAllocated ) {
			gray2 = gray1;
			calculatedFlow = true;
		}

        //Convert to ofxCv images
        ofPixels & pixels = video.getPixels();
        currentColor.setFromPixels( pixels );

        float decimate = 0.5;              //Decimate images to 25% (makes calculations faster + works like a blur too)
        ofxCvColorImage imageDecimated1;
        imageDecimated1.allocate( currentColor.width * decimate, currentColor.height * decimate );
        imageDecimated1.scaleIntoMe( currentColor, CV_INTER_AREA );             //High-quality resize
        gray1 = imageDecimated1;

		if ( gray2.bAllocated ) {
            Mat img1 = cvarrToMat(gray1.getCvImage());
            Mat img2 = cvarrToMat(gray2.getCvImage());
            Mat flow;                        //Image for flow
            //Computing optical flow (visit https://goo.gl/jm1Vfr for explanation of parameters)
            calcOpticalFlowFarneback( img1, img2, flow, 0.7, 3, 11, 5, 5, 1.1, 0 );
            //Split flow into separate images
            vector<Mat> flowPlanes;
            split( flow, flowPlanes );
            //Copy float planes to ofxCv images flowX and flowY
            //we call this to convert back from native openCV to ofxOpenCV data types
            IplImage iplX( flowPlanes[0] );
            //cvConvert(flowX, iplX);
            flowX = &iplX;
            IplImage iplY( flowPlanes[1] );
            flowY = &iplY;
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw() {


	sumX, sumY, avgX, avgY = 0;
	numOfEntries = 0;
	ofSetRectMode(OF_RECTMODE_CENTER);


	if (calculatedFlow)
	{
		
		int w = gray1.width;
		int h = gray1.height;


		//1. Input images + optical flow
		ofPushMatrix();
		ofScale(4, 4);

		//Optical flow
		float *flowXPixels = flowX.getPixelsAsFloats();
		float *flowYPixels = flowY.getPixelsAsFloats();
		ofSetColor(0, 0, 255);
		for (int y = 0; y < h; y++) {
			for (int x = 0; x < w; x++) {
				float fx = flowXPixels[x + w * y];
				float fy = flowYPixels[x + w * y];
				sumX += fx;
				sumY += fy;
				numOfEntries++;
			}
		}
		ofPopMatrix();
	}

	if (numOfEntries > 0) {
		avgX = sumX / numOfEntries;
		avgY = sumY / numOfEntries;
	}
	
	float angle = atan2(avgX, avgY)*RAD_TO_DEG;
	int rotAngle = ofMap(angle, -360, 360, -20, 20, true); //change those map values to change the steps

	int slitLocX;

	ofScale(0.5);
	ofSetColor(255);


	if (imgBuffer.size() > 0) {
		slitLocX = imgBuffer[0].getHeight();

	}

	ofTranslate(ofGetWidth(), ofGetHeight());
	ofSetColor(255);

	//change to i+=3 etc to play with the image
	for (int i = 0; i < imgBuffer.size(); i++) {

		ofRotate(rotAngle);

		imgBuffer[i].drawSubsection(0, i, ofGetWidth(), 5, 0, i); // 5 corresponds to the width of the pixel line drawn, change that for thicker or thinner lines


	}


	
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key) {

	//save image
	if (key == 's') {
		glReadBuffer(GL_FRONT);
		ofSaveScreen(ofToString(ofGetFrameNum()) + ".jpg");
	}

	//restart
	if (key == 'r') {
		setup();
	}

}