From e05bc2828bc213f1e78256f976284bad80722e1a Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Wed, 13 Jun 2012 14:52:22 +0100 Subject: avoiding edges version --- cvtest/cvtest.layout | 4 +- cvtest/src/testApp.cpp | 165 ++++++++++++++++++++++++++++++++++++------------ cvtest/src/testApp.h | 5 +- gaunt01/src/bird.cpp | 81 +++++++++++++++++++++++- gaunt01/src/bird.h | 37 +++++++---- gaunt01/src/main.cpp | 2 +- gaunt01/src/testApp.cpp | 37 ++++++----- 7 files changed, 257 insertions(+), 74 deletions(-) diff --git a/cvtest/cvtest.layout b/cvtest/cvtest.layout index 01f197d..bc9e1d9 100644 --- a/cvtest/cvtest.layout +++ b/cvtest/cvtest.layout @@ -11,9 +11,9 @@ - + - + diff --git a/cvtest/src/testApp.cpp b/cvtest/src/testApp.cpp index cf5061d..cfde019 100644 --- a/cvtest/src/testApp.cpp +++ b/cvtest/src/testApp.cpp @@ -25,7 +25,7 @@ void testApp::setup(){ } - vidPlayer.loadMovie("cam-grass-01.mov"); //camoutput3.mov"); // //footage/ camera needs to be the same res as opencv planes and output + vidPlayer.loadMovie("camoutput3.mov"); //cam-grass-01.mov"); // //footage/ camera needs to be the same res as opencv planes and output vidPlayer.setLoopState(OF_LOOP_NORMAL); vidPlayer.play(); @@ -39,7 +39,7 @@ void testApp::setup(){ mogoutput.allocate(CAM_WIDTH_FG, CAM_HEIGHT_FG); - learningRate = 0.1f; + learningRate = 0.01f; bFirstFrame=true; threshold=10.0; @@ -80,7 +80,10 @@ void testApp::setup(){ diffchannel=chan_V; hsvback = cvCreateImage(cvGetSize(currentFrame.getCvImage()), currentFrame.getCvImage()->depth, currentFrame.getCvImage()->nChannels); - //outchan = cvCreateImage(cvGetSize(currentFrame.getCvImage()), 8, 1); + //backchan = cvCreateImage(cvGetSize(currentFrame.getCvImage()), 8, 1); + + removeShadows=false; + shadowThreshold=10; } @@ -98,12 +101,12 @@ void testApp::update(){ currentFrame.setFromPixels(vidPlayer.getPixels(), CAM_WIDTH_FG, CAM_HEIGHT_FG); + cv::Mat img = currentFrame.getCvImage(); - - if (frameno%10==0) { //I THINK THIS APPROACH IS OK + if (frameno%1==0) { //I THINK THIS APPROACH IS OK //cv::Rect roi(0, 0, 32, 32); //doesn't seem that easy to apply the ROI weighted and you still have to convert a whole image each frame? - cv::Mat img = currentFrame.getCvImage(); + //cv::Mat imgroi = img(roi); if (bFirstFrame) { @@ -126,70 +129,140 @@ void testApp::update(){ //printf("tmp: %ix%i channels: %i depth:%i\n",tmp->width,tmp->height,tmp->nChannels,tmp->depth); - //get correct channel into outchan + //get correct channel into backchan vector chans; - if (diffchannel>chan_B) cvtColor(outmat, hsvback, CV_BGR2HSV); + //to remove shadows, need hsv of foreground and background + if (diffchannel>chan_B||removeShadows) cvtColor(outmat, hsvback, CV_BGR2HSV); switch (diffchannel) { case chan_R: split(outmat,chans); - chans[0].copyTo(outchan); + chans[0].copyTo(backchan); break; case chan_G: split(outmat,chans); - chans[1].copyTo(outchan); + chans[1].copyTo(backchan); break; case chan_B: split(outmat,chans); - chans[2].copyTo(outchan); + chans[2].copyTo(backchan); break; case chan_H: split(hsvback,chans); - chans[0].copyTo(outchan); + chans[0].copyTo(backchan); break; case chan_S: split(hsvback,chans); - chans[1].copyTo(outchan); + chans[1].copyTo(backchan); break; case chan_V: split(hsvback,chans); - chans[2].copyTo(outchan); + chans[2].copyTo(backchan); break; } - tmp = new IplImage(outchan); - //printf("tmp: %ix%i channels: %i depth:%i\n",tmp->width,tmp->height,tmp->nChannels,tmp->depth); - //printf("grayBg: %ix%i channels: %i depth:%i\n",grayBg.getCvImage()->width,grayBg.getCvImage()->height,grayBg.getCvImage()->nChannels,grayBg.getCvImage()->depth); + tmp = new IplImage(backchan); + grayBg = tmp; + + } + //first, optionally remove shadows from FG + //possibly use 1/4 screen res? + + //to remove shadows, need hsv of foreground and background + if (diffchannel>chan_B||removeShadows) cvtColor(img, hsvfront, CV_BGR2HSV); + + cv::Mat outimg; + + if (removeShadows) { + vector slicesFront, slicesBack; + cv::Mat valFront, valBack, satFront, satBack; + // split image to H,S and V images + split(hsvfront, slicesFront); + split(hsvback, slicesBack); + slicesFront[2].copyTo(valFront); // get the value channel + slicesFront[1].copyTo(satFront); // get the sat channel - grayBg = tmp; + slicesBack[2].copyTo(valBack); // get the value channel + slicesBack[1].copyTo(satBack); // get the sat channel - } - grayFrame = currentFrame; + int x,y; + for(x=0; x(y,x)[0] > satBack.at(y,x)[0]-shadowThreshold) && + (satFront.at(y,x)[0] < satBack.at(y,x)[0]+shadowThreshold)); + + if(sat && (valFront.at(y,x)[0] < valBack.at(y,x)[0])) { + hsvfront.at(y,x)[0]= hsvback.at(y,x)[0]; + hsvfront.at(y,x)[1]= hsvback.at(y,x)[1]; + hsvfront.at(y,x)[2]= hsvback.at(y,x)[2]; + } + + } + } + //convert back into RGB if necessary + + if (diffchannel chans; + split(outimg,chans); + + switch (diffchannel) { + case chan_R: + chans[0].copyTo(frontchan); + break; + case chan_G: + chans[1].copyTo(frontchan); + break; + case chan_B: + chans[2].copyTo(frontchan); + break; + case chan_H: + chans[0].copyTo(frontchan); + break; + case chan_S: + chans[1].copyTo(frontchan); + break; + case chan_V: + chans[2].copyTo(frontchan); + break; + } + + IplImage* tmp = new IplImage(outmat); + tmp = new IplImage(frontchan); + grayFrame = tmp; + + // take the abs value of the difference between background and incoming and then threshold: + grayDiff.absDiff(grayBg, grayFrame); + grayDiff.threshold(threshold); + //grayFrame.adaptiveThreshold( threshold,10,false,true); //int blockSize, int offset=0,bool invert=false, bool gauss=false); + //grayDiff.erode_3x3(); + //grayDiff.resize(windowWidth,windowHeight); /* - //MOG - mog(img, outmat, mogf); - - // Complement the image - //cv::threshold(outmat, output, threshold, 255, cv::THRESH_BINARY_INV); - IplImage* tmp1 = new IplImage(outmat); - //printf("tmp: %ix%i channels: %i depth:%i\n",tmp->width,tmp->height,tmp->nChannels,tmp->depth); - //printf("grayDiff: %ix%i channels: %i depth:%i\n",grayDiff.getCvImage()->width,grayDiff.getCvImage()->height,grayDiff.getCvImage()->nChannels,grayDiff.getCvImage()->depth); - grayDiff=tmp1; //copy to ofx + //MOG + mog(img, outmat, mogf); + + // Complement the image + //cv::threshold(outmat, output, threshold, 255, cv::THRESH_BINARY_INV); + IplImage* tmp1 = new IplImage(outmat); + //printf("tmp: %ix%i channels: %i depth:%i\n",tmp->width,tmp->height,tmp->nChannels,tmp->depth); + //printf("grayDiff: %ix%i channels: %i depth:%i\n",grayDiff.getCvImage()->width,grayDiff.getCvImage()->height,grayDiff.getCvImage()->nChannels,grayDiff.getCvImage()->depth); + grayDiff=tmp1; //copy to ofx */ - contourFinder.findContours(grayDiff, 200, (640*480)/3, 20, false); // find holes + contourFinder.findContours(grayDiff, 200, (640*480)/3, 20, false); // find holes @@ -280,11 +353,11 @@ void testApp::draw(){ } - ofSetHexColor(0xffffff); + ofSetHexColor(0xff0000); char reportStr[1024]; - sprintf(reportStr, "fps: %f\nthreshold: %f", ofGetFrameRate(),threshold); + sprintf(reportStr, "fps: %f\nthreshold: %f\nshadow threshold: %i", ofGetFrameRate(),threshold,shadowThreshold); //sprintf(reportStr, "fps: %f\nmog: %f", ofGetFrameRate(),mogf); - ofDrawBitmapString(reportStr, 1100, 440); + ofDrawBitmapString(reportStr, 1100, 420); } @@ -292,7 +365,7 @@ void testApp::draw(){ //-------------------------------------------------------------- void testApp::keyPressed(int key){ switch (key){ - case '+': + case '=': threshold ++; mogf +=.001; if (threshold > 255) threshold = 255; @@ -302,6 +375,14 @@ void testApp::keyPressed(int key){ mogf-=.001; if (threshold < 0) threshold = 0; break; + case '+': + shadowThreshold ++; + if (shadowThreshold > 255) threshold = 255; + break; + case '_': + shadowThreshold --; + if (shadowThreshold < 0) threshold = 0; + break; case '1': diffchannel = chan_R; break; @@ -320,6 +401,10 @@ void testApp::keyPressed(int key){ case '6': diffchannel = chan_V; break; + case 's': + removeShadows=!removeShadows; + printf(removeShadows?"removing shadows\n":"not removing shadows\n"); + break; } } diff --git a/cvtest/src/testApp.h b/cvtest/src/testApp.h index 4207bb9..32d7158 100644 --- a/cvtest/src/testApp.h +++ b/cvtest/src/testApp.h @@ -47,7 +47,7 @@ class testApp : public ofBaseApp{ //try to accumulate background using SHORT datatype ie CV_16UC / 4 (would 4 be faster, 64 bits) - cv::Mat accumulator,outmat,hsvback,outchan,output; // background accumulation + cv::Mat accumulator,outmat,hsvback,hsvfront,backchan,frontchan,output; // background accumulation int frameno; ofxCvColorImage currentFrame; @@ -72,6 +72,9 @@ class testApp : public ofBaseApp{ int diffchannel; + bool removeShadows; + int shadowThreshold; + /* ofxOpenCvUtilsForeground* fg; ofxOpenCvUtilsMeanShift* meanShift; diff --git a/gaunt01/src/bird.cpp b/gaunt01/src/bird.cpp index 49567bc..18f8227 100644 --- a/gaunt01/src/bird.cpp +++ b/gaunt01/src/bird.cpp @@ -37,13 +37,18 @@ bird::bird() centrePoint=ofVec2f(ofGetWidth()/2,600); //quick and dirty } +void bird::setBounds(ofPlane* _bounds) { + bounds=_bounds; +} bird::~bird() { //dtor } -void bird::update(map& players, float angle,vector border){ +void bird::update(map& players, float angle){ + + //movement basics float time=ofGetElapsedTimef(); float timeSeg=time-lastTime; lastTime=time; @@ -53,9 +58,77 @@ void bird::update(map& players, float angle,vector border){ position-=direction.rotated(heading,ofVec3f(0,0,-1))*velocity*timeSeg; //.rotate(heading,ofVec3f(0,1,0)) + //tending to straighten unless avoiding an edge + //turnRate *= 0.995; + + //create, -->draw a line representing the birds heading + //absolute ray pointer + //put on ground + //do intersection with outline? + //ray: can intersect with another ray + //so: make a ray for each segment of polygon and intersect, find the nearest? + //ray:: intersect returns a ray- shortest line between lines + //or: project bird & heading onto ground + //get intersection with each line of poly bounds + //or maybe just use screen edges- quicker + //find the shortest + //depending on the angle it makes, decide whether to turn left or right to avoid boundary or get back within it + + //similar for people - use similar 2d algorithm + //deal with elevation seperately + + //bounds is already an array of 4 planes representing edges of screen- does this work? pointer=ofRay(position.rotated(angle,ofVec3f(1,0,0)),-direction.rotated(heading,ofVec3f(0,0,-1)).rotated(angle,ofVec3f(1,0,0))*1000.0f,false); + //intersect with bounds and find shortest distance to edge of world + float shortest=1000000.0f; + vector pts; + int shnum=-1; + int bdnum=0; + for (int i=0;i<4;i++) { + ofVec3f p; + if (bounds[i].intersect(pointer,p)) { + pts.push_back(p); + if (position.rotated(angle,ofVec3f(1,0,0)).distance(p)-1) { + edgepoint=pts[shnum]; + edgelength=shortest; + ofVec3f bv=bounds[bdnum].getNormal().rotated(angle,ofVec3f(-1,0,0)); + edgeangle=((atan2(bv.y,bv.x)*RAD_TO_DEG)+90)+heading; + while (edgeangle>180) edgeangle -=360; + while (edgeangle<-180) edgeangle +=360; + } + else { + printf("error: no bird bounds intersection\n"); + } + + //decide whether we are running out of space and if so, which way to turn# + //turning tendency is more acute when we are more perpendicular, and closer, to the edge + //mayeb work out how many frames left before we crash + + //turn formula max(0,90-abs(turnangle))*sign(turnangle) + //avoiding edges is a bit of a nightmare + //what about a force attracting to the middle of the screen? + + turnRate=(turnRate*.99)+(0.05f*max(0.0f,1.0f-(pow(edgelength*.0100f,2.0f)))*max(0.0f,90.0f-abs(edgeangle))*sign(edgeangle)); + + //strip it right back + //bird flying in circle + + //bird cruising while avoiding edges + //bird floowing people while avoiding edges + //bird changing height + //morph targets + + /* + ofRay relpointer=ofRay(position,-direction.rotated(heading,ofVec3f(0,0,-1))*1000.0f,false); playang.clear(); @@ -102,6 +175,7 @@ void bird::update(map& players, float angle,vector border){ } if (nearest>-1) turnRate=-playhead[nearest]; } + */ } void bird::draw(){ @@ -135,6 +209,11 @@ void bird::drawDebug(){ if (leaving) ofSetHexColor(0xff0000); else ofSetHexColor(0xff00ff); ofLine(pointer.s,pointer.s+1000*pointer.t); + ofSphere(edgepoint,2.0f); + + char numStr[64]; + sprintf(numStr, "close: %4.1f\nangle: %4.1f\nheading: %4.1f", edgelength,edgeangle,heading); + ofDrawBitmapString(numStr,10,10); } diff --git a/gaunt01/src/bird.h b/gaunt01/src/bird.h index 3ab0da9..c1f3ac7 100644 --- a/gaunt01/src/bird.h +++ b/gaunt01/src/bird.h @@ -22,22 +22,24 @@ -build basic of time/speed/heading update/draw -basic anim cycle - - - + + + MAKING THE BIRD CHASE THE PLAYERS - + find distance to edge of play - alter turn behaviour depending on how bird needs to head detect player in FOV turn & swoop pick player and remove - + planes frustrum belongs to camera bird checks ray dist to planes avoids nearest +ve */ +#define sign(x) ((x > 0) - (x < 0)) + #include "ofMain.h" #include "morphmesh.h" #include "normBindTexture.h" @@ -51,34 +53,41 @@ class bird public: bird(); virtual ~bird(); - void update(map& players,float angle,vector border); + void update(map& players,float angle); void draw(); void drawShadow(); void drawDebug(); + void setBounds(ofPlane* _bounds); + string currentseq; morphmesh model; - + ofRay pointer; ofVec3f position; ofVec2f centrePoint; //2d coords of centre of screen - + + ofVec3f edgepoint; //point where the bird will hit the edge of the screen + float edgelength,edgeangle; + vector playang; vector playhead; vector playdip; vector playdist; vector playpos; - + + ofPlane* bounds; + bool leaving; float centrehead; - + float heading; - + protected: private: - + float fieldofview; - + ofVec3f direction; float velocity; //per second @@ -89,7 +98,7 @@ class bird ofImage texture; - + }; diff --git a/gaunt01/src/main.cpp b/gaunt01/src/main.cpp index 1f3ac12..d8ec5c8 100644 --- a/gaunt01/src/main.cpp +++ b/gaunt01/src/main.cpp @@ -6,7 +6,7 @@ int main( ){ ofAppGlutWindow window; - ofSetupOpenGL(&window, 1024,768, OF_FULLSCREEN ); // <-------- setup the GL context + ofSetupOpenGL(&window, 1024,768, OF_WINDOW ); // <-------- setup the GL context printf("%ix%i on screen %ix%i\n",ofGetWidth(),ofGetHeight(),ofGetScreenWidth(),ofGetScreenHeight()); // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN diff --git a/gaunt01/src/testApp.cpp b/gaunt01/src/testApp.cpp index 853a23f..6ac3d26 100644 --- a/gaunt01/src/testApp.cpp +++ b/gaunt01/src/testApp.cpp @@ -113,7 +113,7 @@ void testApp::setup(){ } scaleFactor=ofVec2f(windowWidth/1280.0f,windowHeight/768.0f); - gameState=TITLES; + gameState=PLAYING; //TITLES; segTimes[TITLES]=4.0; segTimes[CREDIT]=2.5; @@ -137,6 +137,7 @@ void testApp::setup(){ cam.end(); updatePlane(); + Bird.setBounds(bounds); } @@ -265,27 +266,32 @@ void testApp::updatePlane(){ ofVec2f l=ofVec2f(windowWidth/20,windowHeight/2); ofRay r=projector.castPixel(l.x,l.y); ofVec3f p; - plane.intersect(r,p); - ofVec3f pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(0,1,0)); - bounds[0]=ofPlane(p,pn,pn,ofVec2f(1000,1000)); + if (plane.intersect(r,p)) printf("found ground plane intersection 1 at %f,%f,%f\n",p.x,p.y,p.z); + else printf("bound plane 1 not found\n"); + ofVec3f pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(0,-1,0)); + bounds[0]=ofPlane(p,pn); //,pn,ofVec2f(1000,1000)); l=ofVec2f(windowWidth/2,windowHeight/20); r=projector.castPixel(l.x,l.y); - plane.intersect(r,p); + if (plane.intersect(r,p)) printf("found ground plane intersection 2 at %f,%f,%f\n",p.x,p.y,p.z); + else printf("bound plane 2 not found\n"); pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(1,0,0)); - bounds[1]=ofPlane(p,pn,-pn,ofVec2f(1000,1000)); + bounds[1]=ofPlane(p,pn); //,-pn,ofVec2f(1000,1000)); l=ofVec2f(19*windowWidth/20,windowHeight/2); r=projector.castPixel(l.x,l.y); - plane.intersect(r,p); + if (plane.intersect(r,p)) printf("found ground plane intersection 3 at %f,%f,%f\n",p.x,p.y,p.z); + else printf("bound plane 3 not found\n"); pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(0,1,0)); - bounds[2]=ofPlane(p,pn,-pn,ofVec2f(1000,1000)); + bounds[2]=ofPlane(p,pn); //,-pn,ofVec2f(1000,1000)); - l=ofVec2f(windowWidth/2,19*windowHeight/20); + l=ofVec2f(windowWidth/2,19*(windowHeight/20)); r=projector.castPixel(l.x,l.y); - plane.intersect(r,p); - pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(1,0,0)); - bounds[1]=ofPlane(p,pn,-pn,ofVec2f(1000,1000)); + if (plane.intersect(r,p)) printf("found ground plane intersection 4 at %f,%f,%f\n",p.x,p.y,p.z); + else printf("bound plane 4 not found\n"); + pn=(p-projector.getGlobalPosition()).getPerpendicular(ofVec3f(-1,0,0)); + bounds[3]=ofPlane(p,pn); //,-pn,ofVec2f(1000,1000)); + // vector trapdoors; // float trapdoorSize; @@ -504,7 +510,7 @@ void testApp::update(){ } } - Bird.update(players,cam_angle,border); + Bird.update(players,cam_angle); } @@ -693,13 +699,14 @@ void testApp::draw(){ ofVec3f bp; for (int i=0;i<4;i++) { bounds[i].draw(); - if ( - bounds[i].intersect(Bird.pointer,bp)) { + if (bounds[i].intersect(Bird.pointer,bp)) { char numStr[16]; sprintf(numStr, "%4.1f", (bp-Bird.position.rotated(cam_angle,ofVec3f(1,0,0))).length()); ofVec3f sc=cam.worldToScreen(bp); ofDrawBitmapString(numStr, sc.x, sc.y); } + //ofLine(bounds[i].getCenter(),bounds[i].getCenter()+(bounds[i].getNormal()*100)); + //normals sorted } ofSetHexColor(0xffff77); char numStr[16]; -- cgit v1.2.3