├── .gitignore ├── addon_config.mk ├── example-ar ├── addons.make ├── bin │ └── data │ │ └── mbp-2011-isight.yml └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-background ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-bayer ├── addons.make ├── bin │ └── data │ │ ├── bayer.png │ │ └── rgb.png └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-blur ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-calibration-lcp ├── addons.make ├── bin │ └── data │ │ └── distorted.jpg └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-calibration ├── addons.make ├── bin │ └── data │ │ ├── chessboard_a4.pdf │ │ ├── kinect-color.yml │ │ ├── kinect-ir.yml │ │ ├── mbp-2010-isight.yml │ │ ├── mbp-2011-isight.yml │ │ ├── ps3eye-zoomed.yml │ │ └── settings.yml └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-coherent-lines ├── addons.make ├── bin │ └── data │ │ ├── 0162681551.png │ │ ├── 0168366051.png │ │ └── 0168639352.png └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-advanced ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-basic ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-color ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-following ├── addons.make ├── bin │ └── data │ │ └── video.mov └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-quad ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-contours-tracking ├── addons.make ├── bin │ └── data │ │ └── video.mov └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-difference-columns ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-difference ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-edge ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-empty ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-estimate-affine ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-face-follow ├── addons.make ├── bin │ └── data │ │ ├── readme.txt │ │ └── sunglasses.png └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-face-zoom ├── addons.make ├── bin │ └── data │ │ └── readme.txt └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-face ├── addons.make ├── bin │ └── data │ │ └── readme.txt └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-flow-distort-shader ├── addons.make ├── bin │ └── data │ │ ├── MotionAmplifier.frag │ │ └── MotionAmplifier.vert └── src │ ├── MotionAmplifier.h │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-flow-distort ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-flow-keypoints ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-flow ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-gamma ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-gesture ├── addons.make └── src │ ├── GeometryHelpers.cpp │ ├── GeometryHelpers.h │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-highpass ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-homography ├── addons.make ├── bin │ └── data │ │ ├── left.jpg │ │ └── right.jpg └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-kalman-euler ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-kalman ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-smile ├── addons.make ├── bin │ └── data │ │ └── readme.txt └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-threshold ├── addons.make └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── example-undistortion ├── addons.make ├── bin │ └── data │ │ └── mbp-2011-isight.yml └── src │ ├── main.cpp │ ├── ofApp.cpp │ └── ofApp.h ├── libs ├── .gitignore ├── CLD │ ├── addons.make │ ├── include │ │ └── CLD │ │ │ ├── ETF.h │ │ │ ├── fdog.h │ │ │ ├── imatrix.h │ │ │ └── myvec.h │ └── src │ │ ├── ETF.cpp │ │ └── fdog.cpp └── ofxCv │ ├── addons.make │ ├── include │ └── ofxCv │ │ ├── Calibration.h │ │ ├── ContourFinder.h │ │ ├── Distance.h │ │ ├── Flow.h │ │ ├── Helpers.h │ │ ├── Kalman.h │ │ ├── ObjectFinder.h │ │ ├── RunningBackground.h │ │ ├── Tracker.h │ │ ├── Utilities.h │ │ └── Wrappers.h │ └── src │ ├── Calibration.cpp │ ├── ContourFinder.cpp │ ├── Distance.cpp │ ├── Flow.cpp │ ├── Helpers.cpp │ ├── Kalman.cpp │ ├── ObjectFinder.cpp │ ├── RunningBackground.cpp │ ├── Tracker.cpp │ ├── Utilities.cpp │ └── Wrappers.cpp ├── license.md ├── ofxaddons_thumbnail.png ├── readme.md ├── src └── ofxCv.h └── update-projects.py /.gitignore: -------------------------------------------------------------------------------- 1 | example-pulse/ 2 | example-color-transfer/ 3 | example-svm-smile/ 4 | example-svm/ 5 | example-tree/ 6 | example-tsp/ 7 | 8 | # don't push project files 9 | *.cbp 10 | *.sln 11 | *.vcx* 12 | *.workspace* 13 | config.make 14 | Makefile 15 | *.xcodeproj 16 | *.plist 17 | *.xcconfig 18 | *.suo 19 | 20 | *.depend 21 | *.layout 22 | *.mode*v3 23 | *.pbxuser 24 | *.app* 25 | *.DS_* 26 | *.xcworkspacedata 27 | xcuserdata/ 28 | project.xcworkspace 29 | 30 | *.opensdf 31 | *.sdf 32 | *.suo 33 | *.ipch 34 | 35 | .svn/ 36 | obj/ 37 | bin/ 38 | build/ 39 | !data/ 40 | 41 | ofxCv.wiki/ -------------------------------------------------------------------------------- /addon_config.mk: -------------------------------------------------------------------------------- 1 | # All variables and this file are optional, if they are not present the PG and the 2 | # makefiles will try to parse the correct values from the file system. 3 | # 4 | # Variables that specify exclusions can use % as a wildcard to specify that anything in 5 | # that position will match. A partial path can also be specified to, for example, exclude 6 | # a whole folder from the parsed paths from the file system 7 | # 8 | # Variables can be specified using = or += 9 | # = will clear the contents of that variable both specified from the file or the ones parsed 10 | # from the file system 11 | # += will add the values to the previous ones in the file or the ones parsed from the file 12 | # system 13 | # 14 | # The PG can be used to detect errors in this file, just create a new project with this addon 15 | # and the PG will write to the console the kind of error and in which line it is 16 | 17 | meta: 18 | ADDON_NAME = ofxCv 19 | ADDON_DESCRIPTION = Addon for computer vision using the open source library openCv 20 | ADDON_AUTHOR = Kyle McDonald 21 | ADDON_TAGS = "computer vision" "opencv" "image processing" 22 | ADDON_URL = https://github.com/kylemcdonald/ofxcv 23 | 24 | common: 25 | # dependencies with other addons, a list of them separated by spaces 26 | # or use += in several lines 27 | ADDON_DEPENDENCIES = ofxOpenCv 28 | 29 | # include search paths, this will be usually parsed from the file system 30 | # but if the addon or addon libraries need special search paths they can be 31 | # specified here separated by spaces or one per line using += 32 | ADDON_INCLUDES = libs/ofxCv/include 33 | ADDON_INCLUDES += libs/CLD/include/CLD 34 | ADDON_INCLUDES += src 35 | 36 | # any special flag that should be passed to the compiler when using this 37 | # addon 38 | # ADDON_CFLAGS = 39 | 40 | # any special flag that should be passed to the linker when using this 41 | # addon, also used for system libraries with -lname 42 | # ADDON_LDFLAGS = 43 | 44 | # linux only, any library that should be included in the project using 45 | # pkg-config 46 | # ADDON_PKG_CONFIG_LIBRARIES = 47 | 48 | # osx/iOS only, any framework that should be included in the project 49 | # ADDON_FRAMEWORKS = 50 | 51 | # source files, these will be usually parsed from the file system looking 52 | # in the src folders in libs and the root of the addon. if your addon needs 53 | # to include files in different places or a different set of files per platform 54 | # they can be specified here 55 | # ADDON_SOURCES = 56 | 57 | # some addons need resources to be copied to the bin/data folder of the project 58 | # specify here any files that need to be copied, you can use wildcards like * and ? 59 | # ADDON_DATA = 60 | 61 | # when parsing the file system looking for libraries exclude this for all or 62 | # a specific platform 63 | # ADDON_LIBS_EXCLUDE = 64 | -------------------------------------------------------------------------------- /example-ar/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-ar/bin/data/mbp-2011-isight.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 6.6278599887122368e+02, 0., 3.1244256016006659e+02, 0., 7 | 6.6129276875199082e+02, 2.2747179767124251e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ -1.8848338341464690e-01, 1.0721890419183855e+00, 17 | -3.5244467228016116e-03, -7.0195032848241403e-04, 18 | -2.0412827999027101e+00 ] 19 | reprojectionError: 2.1723265945911407e-01 20 | -------------------------------------------------------------------------------- /example-ar/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-ar/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | cam.setup(640, 480); 9 | 10 | calibration.load("mbp-2011-isight.yml"); 11 | patternSize = calibration.getPatternSize(); 12 | objectPoints = Calibration::createObjectPoints(patternSize, 1., CHESSBOARD); 13 | found = false; 14 | 15 | light.enable(); 16 | light.setPosition(500, 0, 0); 17 | ofDisableLighting(); 18 | } 19 | 20 | void ofApp::update() { 21 | cam.update(); 22 | if(cam.isFrameNew()) { 23 | found = calibration.findBoard(toCv(cam), imagePoints); 24 | if(found) { 25 | Mat cameraMatrix = calibration.getDistortedIntrinsics().getCameraMatrix(); 26 | Mat rvec, tvec; 27 | solvePnP(Mat(objectPoints), Mat(imagePoints), cameraMatrix, calibration.getDistCoeffs(), rvec, tvec); 28 | modelMatrix = makeMatrix(rvec, tvec); 29 | } 30 | } 31 | } 32 | 33 | void ofApp::draw() { 34 | ofSetColor(255); 35 | cam.draw(0, 0); 36 | if(found) { 37 | calibration.getDistortedIntrinsics().loadProjectionMatrix(); 38 | applyMatrix(modelMatrix); 39 | 40 | ofMesh mesh; 41 | mesh.setMode(OF_PRIMITIVE_POINTS); 42 | for(int i = 0; i < objectPoints.size(); i++) { 43 | mesh.addVertex(toOf(objectPoints[i])); 44 | } 45 | glPointSize(3); 46 | ofSetColor(magentaPrint); 47 | mesh.drawVertices(); 48 | 49 | ofEnableLighting(); 50 | ofSetColor(255); 51 | ofEnableDepthTest(); 52 | ofTranslate(.5, .5, -.5); 53 | for(int i = 0; i < patternSize.width / 2; i++) { 54 | for(int j = 0; j < patternSize.height / 2; j++) { 55 | for(int k = 0; k < 3; k++) { 56 | ofDrawBox(2 * i, 2 * j, -2 * k, 1); 57 | } 58 | } 59 | } 60 | ofDisableDepthTest(); 61 | ofDisableLighting(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /example-ar/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofxCv::Calibration calibration; 14 | vector objectPoints; 15 | vector imagePoints; 16 | ofMatrix4x4 modelMatrix; 17 | bool found; 18 | cv::Size patternSize; 19 | ofLight light; 20 | }; 21 | -------------------------------------------------------------------------------- /example-background/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-background/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-background/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | 9 | gui.setup(); 10 | gui.add(resetBackground.set("Reset Background", false)); 11 | gui.add(learningTime.set("Learning Time", 30, 0, 30)); 12 | gui.add(thresholdValue.set("Threshold Value", 10, 0, 255)); 13 | } 14 | 15 | void ofApp::update() { 16 | cam.update(); 17 | if(resetBackground) { 18 | background.reset(); 19 | resetBackground = false; 20 | } 21 | if(cam.isFrameNew()) { 22 | background.setLearningTime(learningTime); 23 | background.setThresholdValue(thresholdValue); 24 | background.update(cam, thresholded); 25 | thresholded.update(); 26 | } 27 | } 28 | 29 | void ofApp::draw() { 30 | cam.draw(0, 0); 31 | if(thresholded.isAllocated()) { 32 | thresholded.draw(640, 0); 33 | } 34 | gui.draw(); 35 | } 36 | -------------------------------------------------------------------------------- /example-background/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | ofVideoGrabber cam; 14 | ofxCv::RunningBackground background; 15 | ofImage thresholded; 16 | 17 | ofxPanel gui; 18 | ofParameter resetBackground; 19 | ofParameter learningTime, thresholdValue; 20 | }; 21 | -------------------------------------------------------------------------------- /example-bayer/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-bayer/bin/data/bayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-bayer/bin/data/bayer.png -------------------------------------------------------------------------------- /example-bayer/bin/data/rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-bayer/bin/data/rgb.png -------------------------------------------------------------------------------- /example-bayer/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-bayer/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | 9 | bayer.load("bayer.png"); 10 | rgb.load("rgb.png"); 11 | 12 | bayerType = 0; 13 | } 14 | 15 | void ofApp::update() { 16 | int code; 17 | switch(bayerType) { 18 | case 0: 19 | code = CV_BayerBG2RGB; 20 | bayerName = "CV_BayerBG2RGB"; 21 | break; 22 | case 1: 23 | code = CV_BayerGB2RGB; 24 | bayerName = "CV_BayerGB2RGB"; 25 | break; 26 | case 2: 27 | code = CV_BayerRG2RGB; 28 | bayerName = "CV_BayerRG2RGB"; 29 | break; 30 | case 3: 31 | code = CV_BayerGR2RGB; 32 | bayerName = "CV_BayerGR2RGB"; 33 | break; 34 | } 35 | 36 | convertColor(bayer, rgb, code); 37 | rgb.update(); 38 | } 39 | 40 | void ofApp::draw() { 41 | ofPushMatrix(); 42 | bayer.draw(0, 0); 43 | ofTranslate(rgb.getWidth(), 0); 44 | rgb.draw(0, 0); 45 | ofTranslate(bayer.getWidth(), 0); 46 | ofPopMatrix(); 47 | 48 | ofDrawBitmapStringHighlight("use the up/down keys: " + bayerName, 10, 20); 49 | } 50 | 51 | void ofApp::keyPressed(int key) { 52 | if(key == OF_KEY_UP) { 53 | bayerType--; 54 | } 55 | if(key == OF_KEY_DOWN) { 56 | bayerType++; 57 | } 58 | bayerType = ofClamp(bayerType, 0, 3); 59 | } -------------------------------------------------------------------------------- /example-bayer/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | void keyPressed(int key); 12 | 13 | ofImage bayer, rgb; 14 | int bayerType; 15 | string bayerName; 16 | }; 17 | -------------------------------------------------------------------------------- /example-blur/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-blur/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-blur/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | void ofApp::setup() { 4 | useGaussian = false; 5 | cam.setup(640, 480); 6 | 7 | gui.setup(); 8 | gui.add(useGaussian.set("Use Gaussian", false)); 9 | gui.add(radius.set("Radius", 50, 0, 100)); 10 | } 11 | 12 | void ofApp::update() { 13 | cam.update(); 14 | if(cam.isFrameNew()) { 15 | ofxCv::copy(cam, img); 16 | if(useGaussian) { 17 | ofxCv::GaussianBlur(img, radius); 18 | } else { 19 | ofxCv::blur(img, radius); 20 | } 21 | img.update(); 22 | } 23 | } 24 | 25 | void ofApp::draw() { 26 | if(img.isAllocated()) { 27 | img.draw(0, 0); 28 | } 29 | gui.draw(); 30 | } 31 | -------------------------------------------------------------------------------- /example-blur/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | ofVideoGrabber cam; 14 | ofImage img; 15 | 16 | ofxPanel gui; 17 | ofParameter radius; 18 | ofParameter useGaussian; 19 | }; 20 | -------------------------------------------------------------------------------- /example-calibration-lcp/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-calibration-lcp/bin/data/distorted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-calibration-lcp/bin/data/distorted.jpg -------------------------------------------------------------------------------- /example-calibration-lcp/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-calibration-lcp/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | distorted.load("distorted.jpg"); 8 | 9 | // These parameters can be found in the .lpc files that come with some cameras. 10 | 11 | float imageWidth = distorted.getWidth(); // ImageWidth, pixels 12 | float imageHeight = distorted.getHeight(); // ImageLength, pixels 13 | float focalLength = 28; // FocalLength, mm 14 | float cropFactor = 0.975939; // SensorFormatFactor, "focal length multiplier", "crop factor" 15 | float focalLengthX = 0.778962; // FocalLengthX 16 | float focalLengthY = 0.778962; // FocalLengthY 17 | float principalPointX = 0.500000; // ImageXCenter, ratio 18 | float principalPointY = 0.500000; // ImageYCenter, ratio 19 | 20 | float k1 = -0.147131; // RadialDistortParam1 21 | float k2 = 0.084927; // RadialDistortParam2 22 | calibration.setDistortionCoefficients(k1, k2, 0, 0); 23 | 24 | Intrinsics intrinsics; 25 | cv::Point2f sensorSize(35 * cropFactor, 35 * cropFactor * imageHeight / imageWidth); 26 | cv::Size imageSize(distorted.getWidth(), distorted.getHeight()); 27 | intrinsics.setup(focalLength, imageSize, sensorSize); 28 | calibration.setFillFrame(false); 29 | calibration.setIntrinsics(intrinsics); 30 | 31 | imitate(undistorted, distorted); 32 | 33 | Mat distortedMat = toCv(distorted); 34 | Mat undistortedMat = toCv(undistorted); 35 | calibration.undistort(distortedMat, undistortedMat); 36 | undistorted.update(); 37 | } 38 | 39 | void ofApp::update() { 40 | } 41 | 42 | void ofApp::draw() { 43 | float scale = ofGetHeight() / distorted.getHeight(); 44 | ofScale(scale, scale); 45 | distorted.draw(0, 0); 46 | if(ofGetKeyPressed()) { 47 | undistorted.draw(0, 0); 48 | } 49 | ofDrawBitmapStringHighlight("Hold any key to see undistorted.", 10, 20); 50 | } 51 | -------------------------------------------------------------------------------- /example-calibration-lcp/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofImage distorted; 13 | ofImage undistorted; 14 | 15 | ofxCv::Calibration calibration; 16 | }; 17 | -------------------------------------------------------------------------------- /example-calibration/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-calibration/bin/data/chessboard_a4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-calibration/bin/data/chessboard_a4.pdf -------------------------------------------------------------------------------- /example-calibration/bin/data/kinect-color.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 5.3893796492134459e+02, 0., 3.1511337206790159e+02, 0., 7 | 5.3979719485143403e+02, 2.4592265267769122e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ 2.4155128224014732e-01, -8.1011724263486762e-01, 17 | -1.6681878296497415e-03, 4.4869134116476460e-03, 18 | 9.3018013660014132e-01 ] 19 | reprojectionError: 3.4450665116310120e-01 20 | -------------------------------------------------------------------------------- /example-calibration/bin/data/kinect-ir.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 5.5875867402259189e+02, 0., 3.2015962801017355e+02, 0., 7 | 5.6313824661787146e+02, 2.0999445173364236e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ -1.5785436725034177e-01, 5.3557992507168006e-01, 17 | -1.6578843952074110e-02, -1.9955581754266837e-03, 18 | -7.8997476053822979e-01 ] 19 | reprojectionError: 1.3543131351470947e+00 20 | -------------------------------------------------------------------------------- /example-calibration/bin/data/mbp-2010-isight.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 6.3495680777673090e+02, 0., 3.2625860497501907e+02, 0., 7 | 6.3477863477453502e+02, 2.3520271872789803e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ 2.8451937079021987e-02, -1.9665948438007733e-01, 17 | 6.9577327727113007e-03, 2.2564188073174744e-04, 18 | 2.6227259396885910e-01 ] 19 | reprojectionError: 2.4427352845668793e-01 20 | -------------------------------------------------------------------------------- /example-calibration/bin/data/mbp-2011-isight.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 6.6278599887122368e+02, 0., 3.1244256016006659e+02, 0., 7 | 6.6129276875199082e+02, 2.2747179767124251e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ -1.8848338341464690e-01, 1.0721890419183855e+00, 17 | -3.5244467228016116e-03, -7.0195032848241403e-04, 18 | -2.0412827999027101e+00 ] 19 | reprojectionError: 2.1723265945911407e-01 20 | -------------------------------------------------------------------------------- /example-calibration/bin/data/ps3eye-zoomed.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 7.7264424957184565e+02, 0., 3.1294659824780257e+02, 0., 7 | 7.7346259977483453e+02, 2.4564109827326186e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ -1.0149521517825388e-01, 1.1755924265868904e-01, 17 | 2.3948205219152981e-03, -2.3766404831558285e-03, 18 | 5.1112359194101821e-02 ] 19 | reprojectionError: 2.0766365528106689e-01 20 | -------------------------------------------------------------------------------- /example-calibration/bin/data/settings.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | xCount: 7 3 | yCount: 10 4 | squareSize: 2.5 5 | patternType: 0 6 | -------------------------------------------------------------------------------- /example-calibration/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-calibration/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | const float diffThreshold = 2.5; // maximum amount of movement 7 | const float timeThreshold = 1; // minimum time between snapshots 8 | const int startCleaning = 10; // start cleaning outliers after this many samples 9 | 10 | void ofApp::setup() { 11 | ofSetVerticalSync(true); 12 | cam.setup(640, 480); 13 | 14 | FileStorage settings(ofToDataPath("settings.yml"), FileStorage::READ); 15 | if(settings.isOpened()) { 16 | int xCount = settings["xCount"], yCount = settings["yCount"]; 17 | calibration.setPatternSize(xCount, yCount); 18 | float squareSize = settings["squareSize"]; 19 | calibration.setSquareSize(squareSize); 20 | CalibrationPattern patternType; 21 | switch(settings["patternType"]) { 22 | case 0: patternType = CHESSBOARD; break; 23 | case 1: patternType = CIRCLES_GRID; break; 24 | case 2: patternType = ASYMMETRIC_CIRCLES_GRID; break; 25 | } 26 | calibration.setPatternType(patternType); 27 | } 28 | 29 | imitate(undistorted, cam); 30 | imitate(previous, cam); 31 | imitate(diff, cam); 32 | 33 | lastTime = 0; 34 | 35 | active = true; 36 | } 37 | 38 | void ofApp::update() { 39 | cam.update(); 40 | if(cam.isFrameNew()) { 41 | Mat camMat = toCv(cam); 42 | Mat prevMat = toCv(previous); 43 | Mat diffMat = toCv(diff); 44 | 45 | absdiff(prevMat, camMat, diffMat); 46 | camMat.copyTo(prevMat); 47 | 48 | diffMean = mean(Mat(mean(diffMat)))[0]; 49 | 50 | float curTime = ofGetElapsedTimef(); 51 | if(active && curTime - lastTime > timeThreshold && diffMean < diffThreshold) { 52 | if(calibration.add(camMat)) { 53 | cout << "re-calibrating" << endl; 54 | calibration.calibrate(); 55 | if(calibration.size() > startCleaning) { 56 | calibration.clean(); 57 | } 58 | calibration.save("calibration.yml"); 59 | lastTime = curTime; 60 | } 61 | } 62 | 63 | if(calibration.size() > 0) { 64 | calibration.undistort(toCv(cam), toCv(undistorted)); 65 | undistorted.update(); 66 | } 67 | } 68 | } 69 | 70 | void ofApp::draw() { 71 | ofSetColor(255); 72 | cam.draw(0, 0); 73 | undistorted.draw(640, 0); 74 | 75 | stringstream intrinsics; 76 | intrinsics << "fov: " << toOf(calibration.getDistortedIntrinsics().getFov()) << " distCoeffs: " << calibration.getDistCoeffs(); 77 | string oneLine = intrinsics.str(); 78 | ofStringReplace(oneLine, "\n", ""); 79 | ofDrawBitmapStringHighlight(oneLine, 10, 20, yellowPrint, ofColor(0)); 80 | ofDrawBitmapStringHighlight("movement: " + ofToString(diffMean), 10, 40, cyanPrint); 81 | ofDrawBitmapStringHighlight("reproj error: " + ofToString(calibration.getReprojectionError()) + " from " + ofToString(calibration.size()), 10, 60, magentaPrint); 82 | for(int i = 0; i < calibration.size(); i++) { 83 | ofDrawBitmapStringHighlight(ofToString(i) + ": " + ofToString(calibration.getReprojectionError(i)), 10, 80 + 16 * i, magentaPrint); 84 | } 85 | } 86 | 87 | void ofApp::keyPressed(int key) { 88 | if(key == ' ') { 89 | active = !active; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /example-calibration/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | void keyPressed(int key); 12 | 13 | ofVideoGrabber cam; 14 | ofImage undistorted; 15 | ofPixels previous; 16 | ofPixels diff; 17 | float diffMean; 18 | 19 | float lastTime; 20 | bool active; 21 | 22 | ofxCv::Calibration calibration; 23 | }; 24 | -------------------------------------------------------------------------------- /example-coherent-lines/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-coherent-lines/bin/data/0162681551.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-coherent-lines/bin/data/0162681551.png -------------------------------------------------------------------------------- /example-coherent-lines/bin/data/0168366051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-coherent-lines/bin/data/0168366051.png -------------------------------------------------------------------------------- /example-coherent-lines/bin/data/0168639352.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-coherent-lines/bin/data/0168639352.png -------------------------------------------------------------------------------- /example-coherent-lines/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(1280, 720, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-coherent-lines/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofBackground(255); 8 | ofDirectory dir; 9 | dir.allowExt("png"); 10 | dir.open("."); 11 | dir.listDir(); 12 | for(int i = 0; i < dir.size(); i++) { 13 | ofImage cur; 14 | cur.load(dir.getName(i)); 15 | cur.setImageType(OF_IMAGE_GRAYSCALE); 16 | input.push_back(cur); 17 | output.push_back(cur); 18 | canny.push_back(cur); 19 | } 20 | 21 | gui.setup(); 22 | gui.add(doFDoG.set("doFDoG", true)); 23 | gui.add(halfw.set("halfw", 4, 1, 8)); 24 | gui.add(smoothPasses.set("smoothPasses", 2, 1, 4)); 25 | gui.add(sigma1.set("sigma1", 0.68, 0.01, 2.0)); 26 | gui.add(sigma2.set("sigma2", 6.0, 0.01, 10.0)); 27 | gui.add(tau.set("tau", 0.974, 0.8, 1.0)); 28 | gui.add(black.set("black", -8, -255, 255)); 29 | gui.add(doThresh.set("doThresh", true)); 30 | gui.add(thresh.set("thresh", 150, 0, 255)); 31 | gui.add(doThin.set("doThin", true)); 32 | gui.add(doCanny.set("doCanny", true)); 33 | gui.add(cannyParam1.set("cannyParam1", 400, 0, 1024)); 34 | gui.add(cannyParam2.set("cannyParam2", 600, 0, 1024)); 35 | } 36 | 37 | void ofApp::update(){ 38 | for(int i = 0; i < input.size(); i++) { 39 | if(doFDoG) { 40 | CLD(input[i], output[i], halfw, smoothPasses, sigma1, sigma2, tau, black); 41 | invert(output[i]); 42 | if(doThresh) { 43 | threshold(output[i], thresh); 44 | } 45 | if(doThin) { 46 | thin(output[i]); 47 | } 48 | output[i].update(); 49 | if(doCanny) { 50 | Canny(input[i], canny[i], cannyParam1 * 2, cannyParam2 * 2, 5); 51 | canny[i].update(); 52 | } 53 | } 54 | } 55 | } 56 | 57 | void ofApp::draw(){ 58 | gui.draw(); 59 | 60 | ofTranslate(300, 0); 61 | for(int i = 0; i < input.size(); i++) { 62 | ofEnableBlendMode(OF_BLENDMODE_ALPHA); 63 | input[i].draw(i * 256, 0); 64 | ofEnableBlendMode(OF_BLENDMODE_ADD); 65 | output[i].draw(i * 256, 0); 66 | 67 | ofEnableBlendMode(OF_BLENDMODE_ALPHA); 68 | input[i].draw(i * 256, 256); 69 | ofEnableBlendMode(OF_BLENDMODE_ADD); 70 | canny[i].draw(i * 256, 256); 71 | } 72 | 73 | ofEnableBlendMode(OF_BLENDMODE_ALPHA); 74 | ofDrawBitmapStringHighlight("Coherent line drawing", 10, 20); 75 | ofDrawBitmapStringHighlight("Canny edge detection", 10, 256 + 20); 76 | } 77 | -------------------------------------------------------------------------------- /example-coherent-lines/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxGui.h" 5 | #include "ofxCv.h" 6 | 7 | class ofApp : public ofBaseApp{ 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | vector input, output, canny; 14 | 15 | ofParameter sigma1, sigma2, tau; 16 | ofParameter halfw, smoothPasses, black, thresh, cannyParam1, cannyParam2; 17 | ofParameter doFDoG, doThresh, doThin, doCanny; 18 | 19 | ofxPanel gui; 20 | }; 21 | -------------------------------------------------------------------------------- /example-contours-advanced/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-contours-advanced/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-advanced/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | contourFinder.setMinAreaRadius(10); 9 | contourFinder.setMaxAreaRadius(150); 10 | //contourFinder.setInvert(true); // find black instead of white 11 | 12 | gui.setup(); 13 | gui.add(threshold.set("Threshold", 128, 0, 255)); 14 | gui.add(trackHs.set("Track Hue/Saturation", false)); 15 | gui.add(holes.set("Holes", false)); 16 | } 17 | 18 | void ofApp::update() { 19 | cam.update(); 20 | if(cam.isFrameNew()) { 21 | contourFinder.setTargetColor(targetColor, trackHs ? TRACK_COLOR_HS : TRACK_COLOR_RGB); 22 | contourFinder.setThreshold(threshold); 23 | contourFinder.setFindHoles(holes); 24 | contourFinder.findContours(cam); 25 | } 26 | } 27 | 28 | void ofApp::draw() { 29 | ofSetColor(255); 30 | cam.draw(0, 0); 31 | 32 | ofSetLineWidth(2); 33 | contourFinder.draw(); 34 | 35 | ofNoFill(); 36 | int n = contourFinder.size(); 37 | for(int i = 0; i < n; i++) { 38 | // smallest rectangle that fits the contour 39 | ofSetColor(cyanPrint); 40 | ofPolyline minAreaRect = toOf(contourFinder.getMinAreaRect(i)); 41 | minAreaRect.draw(); 42 | 43 | // ellipse that best fits the contour 44 | ofSetColor(magentaPrint); 45 | cv::RotatedRect ellipse = contourFinder.getFitEllipse(i); 46 | ofPushMatrix(); 47 | ofVec2f ellipseCenter = toOf(ellipse.center); 48 | ofVec2f ellipseSize = toOf(ellipse.size); 49 | ofTranslate(ellipseCenter.x, ellipseCenter.y); 50 | ofRotate(ellipse.angle); 51 | ofDrawEllipse(0, 0, ellipseSize.x, ellipseSize.y); 52 | ofPopMatrix(); 53 | 54 | // minimum area circle that encloses the contour 55 | ofSetColor(cyanPrint); 56 | float circleRadius; 57 | ofVec2f circleCenter = toOf(contourFinder.getMinEnclosingCircle(i, circleRadius)); 58 | ofDrawCircle(circleCenter, circleRadius); 59 | 60 | // convex hull of the contour 61 | ofSetColor(yellowPrint); 62 | ofPolyline convexHull = toOf(contourFinder.getConvexHull(i)); 63 | convexHull.draw(); 64 | 65 | // defects of the convex hull 66 | vector defects = contourFinder.getConvexityDefects(i); 67 | for(int j = 0; j < defects.size(); j++) { 68 | ofDrawLine(defects[j][0], defects[j][1], defects[j][2], defects[j][3]); 69 | } 70 | 71 | // some different styles of contour centers 72 | ofVec2f centroid = toOf(contourFinder.getCentroid(i)); 73 | ofVec2f average = toOf(contourFinder.getAverage(i)); 74 | ofVec2f center = toOf(contourFinder.getCenter(i)); 75 | ofSetColor(cyanPrint); 76 | ofDrawCircle(centroid, 1); 77 | ofSetColor(magentaPrint); 78 | ofDrawCircle(average, 1); 79 | ofSetColor(yellowPrint); 80 | ofDrawCircle(center, 1); 81 | 82 | // you can also get the area and perimeter using ofPolyline: 83 | // ofPolyline::getArea() and ofPolyline::getPerimeter() 84 | double area = contourFinder.getContourArea(i); 85 | double length = contourFinder.getArcLength(i); 86 | 87 | // balance is useful for detecting when a shape has an "arm" sticking out 88 | // if balance.length() is small, the shape is more symmetric: like I, O, X... 89 | // if balance.length() is large, the shape is less symmetric: like L, P, F... 90 | ofVec2f balance = toOf(contourFinder.getBalance(i)); 91 | ofPushMatrix(); 92 | ofTranslate(centroid.x, centroid.y); 93 | ofScale(5, 5); 94 | ofDrawLine(0, 0, balance.x, balance.y); 95 | ofPopMatrix(); 96 | 97 | if(contourFinder.getHole(i)) { 98 | ofDrawBitmapStringHighlight("hole", center.x, center.y); 99 | } 100 | } 101 | 102 | gui.draw(); 103 | 104 | ofTranslate(8, 90); 105 | ofFill(); 106 | ofSetColor(0); 107 | ofDrawRectangle(-3, -3, 64+6, 64+6); 108 | ofSetColor(targetColor); 109 | ofDrawRectangle(0, 0, 64, 64); 110 | } 111 | 112 | void ofApp::mousePressed(int x, int y, int button) { 113 | targetColor = cam.getPixels().getColor(x, y); 114 | } 115 | -------------------------------------------------------------------------------- /example-contours-advanced/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | void mousePressed(int x, int y, int button); 13 | 14 | ofVideoGrabber cam; 15 | ofxCv::ContourFinder contourFinder; 16 | ofColor targetColor; 17 | 18 | ofxPanel gui; 19 | ofParameter threshold; 20 | ofParameter trackHs; 21 | ofParameter holes; 22 | }; 23 | -------------------------------------------------------------------------------- /example-contours-basic/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-contours-basic/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-basic/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | gui.setup(); 9 | gui.add(minArea.set("Min area", 10, 1, 100)); 10 | gui.add(maxArea.set("Max area", 200, 1, 500)); 11 | gui.add(threshold.set("Threshold", 128, 0, 255)); 12 | gui.add(holes.set("Holes", false)); 13 | } 14 | 15 | void ofApp::update() { 16 | cam.update(); 17 | if(cam.isFrameNew()) { 18 | contourFinder.setMinAreaRadius(minArea); 19 | contourFinder.setMaxAreaRadius(maxArea); 20 | contourFinder.setThreshold(threshold); 21 | contourFinder.findContours(cam); 22 | contourFinder.setFindHoles(holes); 23 | } 24 | } 25 | 26 | void ofApp::draw() { 27 | cam.draw(0, 0); 28 | contourFinder.draw(); 29 | gui.draw(); 30 | } 31 | -------------------------------------------------------------------------------- /example-contours-basic/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | ofVideoGrabber cam; 14 | ofxCv::ContourFinder contourFinder; 15 | 16 | ofxPanel gui; 17 | ofParameter minArea, maxArea, threshold; 18 | ofParameter holes; 19 | }; 20 | -------------------------------------------------------------------------------- /example-contours-color/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-contours-color/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-color/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | contourFinder.setMinAreaRadius(10); 9 | contourFinder.setMaxAreaRadius(150); 10 | //contourFinder.setInvert(true); // find black instead of white 11 | 12 | gui.setup(); 13 | gui.add(threshold.set("Threshold", 128, 0, 255)); 14 | gui.add(trackHs.set("Track Hue/Saturation", false)); 15 | } 16 | 17 | void ofApp::update() { 18 | cam.update(); 19 | if(cam.isFrameNew()) { 20 | contourFinder.setTargetColor(targetColor, trackHs ? TRACK_COLOR_HS : TRACK_COLOR_RGB); 21 | contourFinder.setThreshold(threshold); 22 | contourFinder.findContours(cam); 23 | } 24 | } 25 | 26 | void ofApp::draw() { 27 | ofSetColor(255); 28 | cam.draw(0, 0); 29 | 30 | ofSetLineWidth(2); 31 | contourFinder.draw(); 32 | 33 | gui.draw(); 34 | 35 | ofTranslate(8, 75); 36 | ofFill(); 37 | ofSetColor(0); 38 | ofDrawRectangle(-3, -3, 64+6, 64+6); 39 | ofSetColor(targetColor); 40 | ofDrawRectangle(0, 0, 64, 64); 41 | } 42 | 43 | void ofApp::mousePressed(int x, int y, int button) { 44 | targetColor = cam.getPixels().getColor(x, y); 45 | } 46 | -------------------------------------------------------------------------------- /example-contours-color/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | void mousePressed(int x, int y, int button); 13 | 14 | ofVideoGrabber cam; 15 | ofxCv::ContourFinder contourFinder; 16 | ofColor targetColor; 17 | 18 | ofxPanel gui; 19 | ofParameter threshold; 20 | ofParameter trackHs; 21 | }; 22 | -------------------------------------------------------------------------------- /example-contours-following/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-contours-following/bin/data/video.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-contours-following/bin/data/video.mov -------------------------------------------------------------------------------- /example-contours-following/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(320, 240, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-following/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | const float dyingTime = 1; 7 | 8 | void Glow::setup(const cv::Rect& track) { 9 | color.setHsb(ofRandom(0, 255), 255, 255); 10 | cur = toOf(track).getCenter(); 11 | smooth = cur; 12 | } 13 | 14 | void Glow::update(const cv::Rect& track) { 15 | cur = toOf(track).getCenter(); 16 | smooth.interpolate(cur, .5); 17 | all.addVertex(smooth); 18 | } 19 | 20 | void Glow::kill() { 21 | float curTime = ofGetElapsedTimef(); 22 | if(startedDying == 0) { 23 | startedDying = curTime; 24 | } else if(curTime - startedDying > dyingTime) { 25 | dead = true; 26 | } 27 | } 28 | 29 | void Glow::draw() { 30 | ofPushStyle(); 31 | float size = 16; 32 | ofSetColor(255); 33 | if(startedDying) { 34 | ofSetColor(ofColor::red); 35 | size = ofMap(ofGetElapsedTimef() - startedDying, 0, dyingTime, size, 0, true); 36 | } 37 | ofNoFill(); 38 | ofDrawCircle(cur, size); 39 | ofSetColor(color); 40 | all.draw(); 41 | ofSetColor(255); 42 | ofDrawBitmapString(ofToString(label), cur); 43 | ofPopStyle(); 44 | } 45 | 46 | void ofApp::setup() { 47 | ofSetVerticalSync(true); 48 | ofBackground(0); 49 | 50 | movie.load("video.mov"); 51 | movie.play(); 52 | 53 | contourFinder.setMinAreaRadius(1); 54 | contourFinder.setMaxAreaRadius(100); 55 | contourFinder.setThreshold(15); 56 | 57 | // wait for half a frame before forgetting something 58 | tracker.setPersistence(15); 59 | // an object can move up to 50 pixels per frame 60 | tracker.setMaximumDistance(50); 61 | } 62 | 63 | void ofApp::update() { 64 | movie.update(); 65 | if(movie.isFrameNew()) { 66 | blur(movie, 10); 67 | contourFinder.findContours(movie); 68 | tracker.track(contourFinder.getBoundingRects()); 69 | } 70 | } 71 | 72 | void ofApp::draw() { 73 | ofSetColor(255); 74 | movie.draw(0, 0); 75 | contourFinder.draw(); 76 | vector& followers = tracker.getFollowers(); 77 | for(int i = 0; i < followers.size(); i++) { 78 | followers[i].draw(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /example-contours-following/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class Glow : public ofxCv::RectFollower { 7 | protected: 8 | ofColor color; 9 | ofVec3f cur, smooth; 10 | float startedDying; 11 | ofPolyline all; 12 | public: 13 | Glow() 14 | :startedDying(0) { 15 | } 16 | void setup(const cv::Rect& track); 17 | void update(const cv::Rect& track); 18 | void kill(); 19 | void draw(); 20 | }; 21 | 22 | class ofApp : public ofBaseApp { 23 | public: 24 | void setup(); 25 | void update(); 26 | void draw(); 27 | 28 | ofVideoPlayer movie; 29 | ofxCv::ContourFinder contourFinder; 30 | ofxCv::RectTrackerFollower tracker; 31 | }; 32 | -------------------------------------------------------------------------------- /example-contours-quad/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-contours-quad/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-quad/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | contourFinder.setMinAreaRadius(10); 9 | contourFinder.setMaxAreaRadius(200); 10 | unwarped.allocate(150, 100, OF_IMAGE_COLOR); 11 | } 12 | 13 | void ofApp::update() { 14 | cam.update(); 15 | if(cam.isFrameNew()) { 16 | threshold = ofMap(mouseX, 0, ofGetWidth(), 0, 255); 17 | contourFinder.setThreshold(threshold); 18 | contourFinder.findContours(cam); 19 | 20 | int n = contourFinder.size(); 21 | quads.clear(); 22 | quads.resize(n); 23 | for(int i = 0; i < n; i++) { 24 | quads[i] = contourFinder.getFitQuad(i); 25 | 26 | // convert integer image coordinates Point2i to unwarp positions Point2f 27 | vector warpPoints; 28 | copy(quads[i].begin(), quads[i].end(), back_inserter(warpPoints)); 29 | unwarpPerspective(cam, unwarped, warpPoints); 30 | unwarped.update(); 31 | } 32 | } 33 | } 34 | 35 | void ofApp::draw() { 36 | ofSetColor(255); 37 | cam.draw(0, 0); 38 | 39 | ofSetLineWidth(2); 40 | contourFinder.draw(); 41 | 42 | ofNoFill(); 43 | ofSetColor(magentaPrint); 44 | for(int i = 0; i < quads.size(); i++) { 45 | toOf(quads[i]).draw(); 46 | } 47 | 48 | ofSetColor(255); 49 | ofDrawBitmapStringHighlight(ofToString((int) ofGetFrameRate()) + " fps", 10, 20); 50 | ofDrawBitmapStringHighlight(ofToString((int) threshold) + " threshold", 10, 40); 51 | 52 | ofTranslate(8, 75); 53 | ofFill(); 54 | ofSetColor(0); 55 | ofDrawRectangle(-3, -3, 64+6, 64+6); 56 | ofSetColor(targetColor); 57 | ofDrawRectangle(0, 0, 64, 64); 58 | 59 | ofSetColor(255); 60 | unwarped.draw(0, 70); 61 | } 62 | 63 | void ofApp::mousePressed(int x, int y, int button) { 64 | targetColor = cam.getPixels().getColor(x, y); 65 | contourFinder.setTargetColor(targetColor, TRACK_COLOR_HSV); 66 | } 67 | 68 | void ofApp::keyPressed(int key) { 69 | } -------------------------------------------------------------------------------- /example-contours-quad/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | void mousePressed(int x, int y, int button); 12 | void keyPressed(int key); 13 | 14 | ofVideoGrabber cam; 15 | ofxCv::ContourFinder contourFinder; 16 | vector< vector > quads; 17 | float threshold; 18 | ofColor targetColor; 19 | ofImage unwarped; 20 | }; 21 | -------------------------------------------------------------------------------- /example-contours-tracking/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxGui 3 | ofxOpenCv 4 | -------------------------------------------------------------------------------- /example-contours-tracking/bin/data/video.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-contours-tracking/bin/data/video.mov -------------------------------------------------------------------------------- /example-contours-tracking/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(320, 240, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-contours-tracking/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofBackground(0); 9 | 10 | movie.load("video.mov"); 11 | movie.play(); 12 | 13 | contourFinder.setMinAreaRadius(1); 14 | contourFinder.setMaxAreaRadius(100); 15 | contourFinder.setThreshold(15); 16 | // wait for half a second before forgetting something 17 | contourFinder.getTracker().setPersistence(15); 18 | // an object can move up to 32 pixels per frame 19 | contourFinder.getTracker().setMaximumDistance(32); 20 | 21 | showLabels = true; 22 | } 23 | 24 | void ofApp::update() { 25 | movie.update(); 26 | if(movie.isFrameNew()) { 27 | blur(movie, 10); 28 | contourFinder.findContours(movie); 29 | } 30 | } 31 | 32 | void ofApp::draw() { 33 | ofSetBackgroundAuto(showLabels); 34 | RectTracker& tracker = contourFinder.getTracker(); 35 | 36 | if(showLabels) { 37 | ofSetColor(255); 38 | movie.draw(0, 0); 39 | contourFinder.draw(); 40 | for(int i = 0; i < contourFinder.size(); i++) { 41 | ofPoint center = toOf(contourFinder.getCenter(i)); 42 | ofPushMatrix(); 43 | ofTranslate(center.x, center.y); 44 | int label = contourFinder.getLabel(i); 45 | string msg = ofToString(label) + ":" + ofToString(tracker.getAge(label)); 46 | ofDrawBitmapString(msg, 0, 0); 47 | ofVec2f velocity = toOf(contourFinder.getVelocity(i)); 48 | ofScale(5, 5); 49 | ofDrawLine(0, 0, velocity.x, velocity.y); 50 | ofPopMatrix(); 51 | } 52 | } else { 53 | for(int i = 0; i < contourFinder.size(); i++) { 54 | unsigned int label = contourFinder.getLabel(i); 55 | // only draw a line if this is not a new label 56 | if(tracker.existsPrevious(label)) { 57 | // use the label to pick a random color 58 | ofSeedRandom(label << 24); 59 | ofSetColor(ofColor::fromHsb(ofRandom(255), 255, 255)); 60 | // get the tracked object (cv::Rect) at current and previous position 61 | const cv::Rect& previous = tracker.getPrevious(label); 62 | const cv::Rect& current = tracker.getCurrent(label); 63 | // get the centers of the rectangles 64 | ofVec2f previousPosition(previous.x + previous.width / 2, previous.y + previous.height / 2); 65 | ofVec2f currentPosition(current.x + current.width / 2, current.y + current.height / 2); 66 | ofDrawLine(previousPosition, currentPosition); 67 | } 68 | } 69 | } 70 | 71 | // this chunk of code visualizes the creation and destruction of labels 72 | const vector& currentLabels = tracker.getCurrentLabels(); 73 | const vector& previousLabels = tracker.getPreviousLabels(); 74 | const vector& newLabels = tracker.getNewLabels(); 75 | const vector& deadLabels = tracker.getDeadLabels(); 76 | ofSetColor(cyanPrint); 77 | for(int i = 0; i < currentLabels.size(); i++) { 78 | int j = currentLabels[i]; 79 | ofDrawLine(j, 0, j, 4); 80 | } 81 | ofSetColor(magentaPrint); 82 | for(int i = 0; i < previousLabels.size(); i++) { 83 | int j = previousLabels[i]; 84 | ofDrawLine(j, 4, j, 8); 85 | } 86 | ofSetColor(yellowPrint); 87 | for(int i = 0; i < newLabels.size(); i++) { 88 | int j = newLabels[i]; 89 | ofDrawLine(j, 8, j, 12); 90 | } 91 | ofSetColor(ofColor::white); 92 | for(int i = 0; i < deadLabels.size(); i++) { 93 | int j = deadLabels[i]; 94 | ofDrawLine(j, 12, j, 16); 95 | } 96 | } 97 | 98 | void ofApp::keyPressed(int key) { 99 | if(key == ' ') { 100 | showLabels = !showLabels; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /example-contours-tracking/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | void keyPressed(int key); 12 | 13 | float threshold; 14 | ofVideoPlayer movie; 15 | ofxCv::ContourFinder contourFinder; 16 | bool showLabels; 17 | }; 18 | -------------------------------------------------------------------------------- /example-difference-columns/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-difference-columns/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(320 * 2, 240, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-difference-columns/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | cam.setup(320, 240); 9 | 10 | // imitate() will set up previous and diff 11 | // so they have the same size and type as cam 12 | imitate(previous, cam); 13 | imitate(diff, cam); 14 | } 15 | 16 | void ofApp::update() { 17 | cam.update(); 18 | if(cam.isFrameNew()) { 19 | // take the absolute difference of prev and cam and save it inside diff 20 | absdiff(cam, previous, diff); 21 | diff.update(); 22 | 23 | // like ofSetPixels, but more concise and cross-toolkit 24 | copy(cam, previous); 25 | 26 | // this is the key line: get the average of each column 27 | columnMean = meanCols(diff); 28 | } 29 | } 30 | 31 | void ofApp::draw() { 32 | ofSetColor(255); 33 | cam.draw(0, 0); 34 | 35 | ofTranslate(320, 0); 36 | diff.draw(0, 0); 37 | // draw the mean for each channel 38 | for(int k = 0; k < 3; k++) { 39 | // use the correct color for each channel 40 | switch(k) { 41 | case 0: ofSetColor(ofColor::red); break; 42 | case 1: ofSetColor(ofColor::blue); break; 43 | case 2: ofSetColor(ofColor::green); break; 44 | } 45 | 46 | ofNoFill(); 47 | ofBeginShape(); 48 | for(int i = 0; i < columnMean.rows; i++) { 49 | // Vec3b is one way of storing 24-bit (3 byte) colors 50 | Vec3b cur = columnMean.at(i); 51 | ofVertex(i, cur[k]); 52 | } 53 | ofEndShape(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example-difference-columns/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofPixels previous; 14 | ofImage diff; 15 | cv::Mat columnMean; 16 | }; 17 | -------------------------------------------------------------------------------- /example-difference/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-difference/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(320 * 2, 240, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-difference/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | cam.setup(320, 240); 9 | 10 | // imitate() will set up previous and diff 11 | // so they have the same size and type as cam 12 | imitate(previous, cam); 13 | imitate(diff, cam); 14 | } 15 | 16 | void ofApp::update() { 17 | cam.update(); 18 | if(cam.isFrameNew()) { 19 | // take the absolute difference of prev and cam and save it inside diff 20 | absdiff(cam, previous, diff); 21 | diff.update(); 22 | 23 | // like ofSetPixels, but more concise and cross-toolkit 24 | copy(cam, previous); 25 | 26 | // mean() returns a Scalar. it's a cv:: function so we have to pass a Mat 27 | diffMean = mean(toCv(diff)); 28 | 29 | // you can only do math between Scalars, 30 | // but it's easy to make a Scalar from an int (shown here) 31 | diffMean *= Scalar(50); 32 | } 33 | } 34 | 35 | void ofApp::draw() { 36 | ofSetColor(255); 37 | cam.draw(0, 0); 38 | diff.draw(320, 0); 39 | 40 | // use the [] operator to get elements from a Scalar 41 | float diffRed = diffMean[0]; 42 | float diffGreen = diffMean[1]; 43 | float diffBlue = diffMean[2]; 44 | 45 | ofSetColor(255, 0, 0); 46 | ofDrawRectangle(0, 0, diffRed, 10); 47 | ofSetColor(0, 255, 0); 48 | ofDrawRectangle(0, 15, diffGreen, 10); 49 | ofSetColor(0, 0, 255); 50 | ofDrawRectangle(0, 30, diffBlue, 10); 51 | } 52 | -------------------------------------------------------------------------------- /example-difference/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofPixels previous; 14 | ofImage diff; 15 | 16 | // a scalar is like an ofVec4f but normally used for storing color information 17 | cv::Scalar diffMean; 18 | }; 19 | -------------------------------------------------------------------------------- /example-edge/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-edge/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480 * 2, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-edge/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | } 9 | 10 | void ofApp::update() { 11 | cam.update(); 12 | if(cam.isFrameNew()) { 13 | convertColor(cam, gray, CV_RGB2GRAY); 14 | Canny(gray, edge, mouseX, mouseY, 3); 15 | Sobel(gray, sobel); 16 | gray.update(); 17 | sobel.update(); 18 | edge.update(); 19 | } 20 | } 21 | 22 | void ofApp::draw() { 23 | cam.draw(0, 0); 24 | gray.draw(0,480); 25 | edge.draw(640, 0); 26 | sobel.draw(640, 480); 27 | } 28 | -------------------------------------------------------------------------------- /example-edge/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofImage gray, edge, sobel; 14 | }; 15 | -------------------------------------------------------------------------------- /example-empty/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxGui 3 | ofxOpenCv 4 | -------------------------------------------------------------------------------- /example-empty/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(1025, 512, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-empty/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | } 8 | 9 | void ofApp::update() { 10 | } 11 | 12 | void ofApp::draw() { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /example-empty/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | }; 12 | -------------------------------------------------------------------------------- /example-estimate-affine/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-estimate-affine/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-estimate-affine/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | 9 | ofMatrix4x4 rigid; 10 | ofVec3f translation(ofRandomf(), ofRandomf(), ofRandomf()); 11 | ofQuaternion rotation(ofRandomf(), ofVec3f(ofRandomf(), ofRandomf(), ofRandomf())); 12 | rigid.translate(translation); 13 | rigid.rotate(rotation); 14 | 15 | vector from; 16 | for(int i = 0; i < 4; i++) { 17 | from.push_back(ofVec3f(ofRandom(1,2), ofRandom(1,2), ofRandom(5,6))); 18 | from.push_back(ofVec3f(ofRandom(3,4), ofRandom(3,4), ofRandom(5,6))); 19 | from.push_back(ofVec3f(ofRandom(1,2), ofRandom(3,4), ofRandom(5,6))); 20 | from.push_back(ofVec3f(ofRandom(3,4), ofRandom(1,2), ofRandom(5,6))); 21 | } 22 | 23 | vector to; 24 | for(int i = 0; i < from.size(); i++) { 25 | // opencv assumes you're doing premultiplication 26 | to.push_back(rigid.preMult(from[i])); 27 | } 28 | 29 | ofMatrix4x4 rigidEstimate = estimateAffine3D(from, to); 30 | 31 | cout << "original matrix: " << endl << rigid << endl; 32 | cout << "estimated as: " << endl << rigidEstimate << endl; 33 | 34 | for(int i = 0; i < from.size(); i++) { 35 | // opencv assumes you're doing premultiplication 36 | ofVec3f after = rigidEstimate.preMult(from[i]); 37 | cout << from[i] << " -> " << to[i] << " estimated as: " << after << endl; 38 | } 39 | 40 | ofVec3f decompTranslation, decompScale; 41 | ofQuaternion decompRotation, decompSo; 42 | rigidEstimate.decompose(decompTranslation, decompRotation, decompScale, decompSo); 43 | cout << "translation: " << translation << endl; 44 | cout << "estimated as: " << decompTranslation << endl; 45 | cout << "rotation: " << endl << rotation << endl; 46 | cout << "estimated as: " << endl << decompRotation << endl; 47 | } 48 | 49 | void ofApp::update() { 50 | } 51 | 52 | void ofApp::draw() { 53 | ofBackground(0); 54 | ofDrawBitmapString("See console window for results.", 10, 20); 55 | } 56 | -------------------------------------------------------------------------------- /example-estimate-affine/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | }; 12 | -------------------------------------------------------------------------------- /example-face-follow/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-face-follow/bin/data/readme.txt: -------------------------------------------------------------------------------- 1 | You need to add a copy of haarcascade_frontalface_default.xml to this directory. -------------------------------------------------------------------------------- /example-face-follow/bin/data/sunglasses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-face-follow/bin/data/sunglasses.png -------------------------------------------------------------------------------- /example-face-follow/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-face-follow/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofSetFrameRate(120); 9 | finder.setup("haarcascade_frontalface_default.xml"); 10 | finder.setPreset(ObjectFinder::Fast); 11 | finder.getTracker().setSmoothingRate(.3); 12 | cam.setup(640, 480); 13 | sunglasses.load("sunglasses.png"); 14 | ofEnableAlphaBlending(); 15 | } 16 | 17 | void ofApp::update() { 18 | cam.update(); 19 | if(cam.isFrameNew()) { 20 | finder.update(cam); 21 | } 22 | } 23 | 24 | void ofApp::draw() { 25 | cam.draw(0, 0); 26 | 27 | for(int i = 0; i < finder.size(); i++) { 28 | ofRectangle object = finder.getObjectSmoothed(i); 29 | sunglasses.setAnchorPercent(.5, .5); 30 | float scaleAmount = .85 * object.width / sunglasses.getWidth(); 31 | ofPushMatrix(); 32 | ofTranslate(object.x + object.width / 2., object.y + object.height * .42); 33 | ofScale(scaleAmount, scaleAmount); 34 | sunglasses.draw(0, 0); 35 | ofPopMatrix(); 36 | ofPushMatrix(); 37 | ofTranslate(object.getPosition()); 38 | ofDrawBitmapStringHighlight(ofToString(finder.getLabel(i)), 0, 0); 39 | ofDrawLine(ofVec2f(), toOf(finder.getVelocity(i)) * 10); 40 | ofPopMatrix(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example-face-follow/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofxCv::ObjectFinder finder; 14 | ofImage sunglasses; 15 | }; 16 | -------------------------------------------------------------------------------- /example-face-zoom/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-face-zoom/bin/data/readme.txt: -------------------------------------------------------------------------------- 1 | You need to add a copy of haarcascade_frontalface_default.xml to this directory. -------------------------------------------------------------------------------- /example-face-zoom/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(512, 512, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-face-zoom/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofSetFrameRate(120); 9 | 10 | objectFinder.setup(ofToDataPath("haarcascade_frontalface_default.xml")); 11 | objectFinder.setPreset(ObjectFinder::Fast); 12 | cam.setup(640, 480); 13 | cropped.allocate(ofGetWidth(), ofGetHeight(), OF_IMAGE_COLOR); 14 | } 15 | 16 | void ofApp::update() { 17 | cam.update(); 18 | if(cam.isFrameNew()) { 19 | objectFinder.update(cam); 20 | if(objectFinder.size() > 0) { 21 | cv::Rect roi = toCv(objectFinder.getObject(0)); 22 | Mat camMat = toCv(cam); 23 | Mat croppedCamMat(camMat, roi); 24 | resize(croppedCamMat, cropped); 25 | cropped.update(); 26 | } 27 | } 28 | } 29 | 30 | void ofApp::draw() { 31 | cropped.draw(0, 0); 32 | } 33 | -------------------------------------------------------------------------------- /example-face-zoom/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofImage cropped; 14 | ofxCv::ObjectFinder objectFinder; 15 | }; 16 | -------------------------------------------------------------------------------- /example-face/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-face/bin/data/readme.txt: -------------------------------------------------------------------------------- 1 | You need to add a copy of haarcascade_frontalface_default.xml to this directory. -------------------------------------------------------------------------------- /example-face/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-face/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofSetFrameRate(120); 9 | finder.setup("haarcascade_frontalface_default.xml"); 10 | finder.setPreset(ObjectFinder::Fast); 11 | cam.setup(640, 480); 12 | } 13 | 14 | void ofApp::update() { 15 | cam.update(); 16 | if(cam.isFrameNew()) { 17 | finder.update(cam); 18 | } 19 | } 20 | 21 | void ofApp::draw() { 22 | cam.draw(0, 0); 23 | finder.draw(); 24 | ofDrawBitmapStringHighlight(ofToString(finder.size()), 10, 20); 25 | } 26 | -------------------------------------------------------------------------------- /example-face/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofxCv::ObjectFinder finder; 14 | }; 15 | -------------------------------------------------------------------------------- /example-flow-distort-shader/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-flow-distort-shader/bin/data/MotionAmplifier.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform sampler2DRect source; 4 | varying vec2 texCoord; 5 | 6 | void main() { 7 | gl_FragColor = texture2DRect(source, texCoord); 8 | } -------------------------------------------------------------------------------- /example-flow-distort-shader/bin/data/MotionAmplifier.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform sampler2DRect source; 4 | uniform sampler2DRect flow; 5 | uniform float scaleFactor; 6 | uniform float strength; 7 | uniform float sourceRescale; 8 | uniform float flowRescale; 9 | varying vec2 texCoord; 10 | 11 | void main() { 12 | vec2 baseCoord = gl_Vertex.xy; 13 | texCoord = baseCoord * sourceRescale; 14 | vec2 offset = texture2DRect(flow, baseCoord * flowRescale).xy; 15 | vec4 position = gl_Vertex; 16 | offset = (offset - vec2(.5, .5)) / scaleFactor; 17 | position.x += strength * offset.x; 18 | position.y += strength * offset.y; 19 | position.z += length(offset); 20 | gl_Position = gl_ModelViewProjectionMatrix * position; 21 | } -------------------------------------------------------------------------------- /example-flow-distort-shader/src/MotionAmplifier.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class MotionAmplifier { 7 | private: 8 | cv::Mat rescaled, flow3; 9 | ofxCv::FlowFarneback flow; 10 | ofShader shader; 11 | float scaleFactor; 12 | ofTexture flowTexture; 13 | ofVboMesh mesh; 14 | float rescale; 15 | 16 | int stepSize, xSteps, ySteps; 17 | cv::Mat accumulator; 18 | bool needToReset; 19 | 20 | float strength, learningRate; 21 | int blurAmount, windowSize; 22 | 23 | void duplicateFirstChannel(cv::Mat& twoChannel, cv::Mat& threeChannel) { 24 | vector each; 25 | cv::split(twoChannel, each); 26 | each.push_back(each[0]); 27 | cv::merge(each, threeChannel); 28 | } 29 | 30 | public: 31 | void setup(int w, int h, int stepSize, float rescale = 1) { 32 | this->rescale = rescale; 33 | shader.load("MotionAmplifier"); 34 | scaleFactor = 1. / 10; // could dynamically calculate this from flow3 35 | needToReset = false; 36 | 37 | mesh.setMode(OF_PRIMITIVE_TRIANGLES); 38 | this->stepSize = stepSize; 39 | xSteps = 1+((rescale * w) / stepSize); 40 | ySteps = 1+((rescale * h) / stepSize); 41 | for(int y = 0; y < ySteps; y++) { 42 | for(int x = 0; x < xSteps; x++) { 43 | mesh.addVertex(ofVec3f(ofVec2f(x, y) * stepSize / rescale)); 44 | } 45 | } 46 | for(int y = 0; y + 1 < ySteps; y++) { 47 | for(int x = 0; x + 1 < xSteps; x++) { 48 | int nw = y * xSteps + x; 49 | int ne = nw + 1; 50 | int sw = nw + xSteps; 51 | int se = sw + 1; 52 | mesh.addIndex(nw); 53 | mesh.addIndex(ne); 54 | mesh.addIndex(se); 55 | mesh.addIndex(nw); 56 | mesh.addIndex(se); 57 | mesh.addIndex(sw); 58 | } 59 | } 60 | } 61 | 62 | template 63 | void update(T& img) { 64 | ofxCv::resize(img, rescaled, rescale, rescale); 65 | flow.calcOpticalFlow(rescaled); 66 | duplicateFirstChannel(flow.getFlow(), flow3); 67 | flow3 *= scaleFactor; 68 | flow3 += cv::Scalar_(.5, .5, 0); 69 | ofxCv::blur(flow3, blurAmount); 70 | int w = flow3.cols, h = flow3.rows; 71 | if(needToReset || accumulator.size() != flow3.size()) { 72 | needToReset = false; 73 | ofxCv::copy(flow3, accumulator); 74 | } 75 | cv::accumulateWeighted(flow3, accumulator, learningRate); 76 | // zero the edges 77 | cv::rectangle(accumulator, cv::Point(0, 0), cv::Point(w-1, h-1), cv::Scalar(.5, .5, 0)); 78 | flowTexture.loadData((float*) accumulator.ptr(), w, h, GL_RGB); 79 | } 80 | 81 | void draw(ofBaseHasTexture& tex) { 82 | if(flowTexture.isAllocated()) { 83 | shader.begin(); 84 | shader.setUniformTexture("source", tex, 1); 85 | shader.setUniformTexture("flow", flowTexture, 2); 86 | shader.setUniform1f("strength", strength); 87 | shader.setUniform1f("scaleFactor", scaleFactor); 88 | shader.setUniform1f("flowRescale", rescale); 89 | shader.setUniform1f("sourceRescale", 1); 90 | mesh.drawFaces(); 91 | shader.end(); 92 | } 93 | } 94 | 95 | void drawMesh() { 96 | if(flowTexture.isAllocated()) { 97 | shader.begin(); 98 | shader.setUniformTexture("source", flowTexture, 1); 99 | shader.setUniformTexture("flow", flowTexture, 2); 100 | shader.setUniform1f("strength", strength); 101 | shader.setUniform1f("scaleFactor", scaleFactor); 102 | shader.setUniform1f("flowRescale", rescale); 103 | shader.setUniform1f("sourceRescale", rescale); 104 | mesh.drawWireframe(); 105 | shader.end(); 106 | } 107 | } 108 | 109 | ofTexture& getFlowTexture() { 110 | return flowTexture; 111 | } 112 | 113 | void setStrength(float strength) { 114 | this->strength = strength; 115 | } 116 | 117 | void setLearningRate(float learningRate) { 118 | this->learningRate = learningRate; 119 | } 120 | 121 | void setBlurAmount(int blurAmount) { 122 | this->blurAmount = blurAmount; 123 | } 124 | 125 | void setWindowSize(int windowSize) { 126 | flow.setWindowSize(windowSize); 127 | } 128 | }; 129 | -------------------------------------------------------------------------------- /example-flow-distort-shader/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(1280, 720, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-flow-distort-shader/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(1280, 720); 8 | motionAmplifier.setup(cam.getWidth(), cam.getHeight(), 2, .25); 9 | } 10 | 11 | void ofApp::update() { 12 | motionAmplifier.setStrength(ofMap(mouseX, 0, ofGetWidth(), -10, 10)); 13 | motionAmplifier.setLearningRate(ofMap(mouseY, 0, ofGetHeight(), 0, 1, true)); 14 | motionAmplifier.setBlurAmount(0); 15 | motionAmplifier.setWindowSize(8); 16 | 17 | cam.update(); 18 | if(cam.isFrameNew()) { 19 | motionAmplifier.update(cam); 20 | } 21 | } 22 | 23 | void ofApp::draw() { 24 | ofBackground(0); 25 | ofSetupScreenOrtho(ofGetWidth(), ofGetHeight(), -100, +100); 26 | ofEnableDepthTest(); 27 | motionAmplifier.draw(cam); 28 | // motionAmplifier.drawMesh(); 29 | ofDisableDepthTest(); 30 | } -------------------------------------------------------------------------------- /example-flow-distort-shader/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "MotionAmplifier.h" 6 | 7 | class ofApp : public ofBaseApp { 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | ofVideoGrabber cam; 14 | MotionAmplifier motionAmplifier; 15 | }; -------------------------------------------------------------------------------- /example-flow-distort/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-flow-distort/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-flow-distort/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofSetFrameRate(120); 9 | cam.setup(320, 240); 10 | 11 | mesh.setMode(OF_PRIMITIVE_TRIANGLES); 12 | stepSize = 8; 13 | ySteps = cam.getHeight() / stepSize; 14 | xSteps = cam.getWidth() / stepSize; 15 | for(int y = 0; y < ySteps; y++) { 16 | for(int x = 0; x < xSteps; x++) { 17 | mesh.addVertex(ofVec3f(x * stepSize, y * stepSize, 0.0)); 18 | mesh.addTexCoord(ofVec2f(x * stepSize, y * stepSize)); 19 | } 20 | } 21 | for(int y = 0; y + 1 < ySteps; y++) { 22 | for(int x = 0; x + 1 < xSteps; x++) { 23 | int nw = y * xSteps + x; 24 | int ne = nw + 1; 25 | int sw = nw + xSteps; 26 | int se = sw + 1; 27 | mesh.addIndex(nw); 28 | mesh.addIndex(ne); 29 | mesh.addIndex(se); 30 | mesh.addIndex(nw); 31 | mesh.addIndex(se); 32 | mesh.addIndex(sw); 33 | } 34 | } 35 | } 36 | 37 | void ofApp::update() { 38 | cam.update(); 39 | if(cam.isFrameNew()) { 40 | flow.setWindowSize(8); 41 | flow.calcOpticalFlow(cam); 42 | int i = 0; 43 | float distortionStrength = 4; 44 | for(int y = 1; y + 1 < ySteps; y++) { 45 | for(int x = 1; x + 1 < xSteps; x++) { 46 | int i = y * xSteps + x; 47 | ofVec3f position(x * stepSize, y * stepSize, 0.0); 48 | ofRectangle area(position - ofVec3f(stepSize, stepSize, 0.0) / 2, stepSize, stepSize); 49 | ofVec2f offset = flow.getAverageFlowInRegion(area); 50 | mesh.setVertex(i, position + distortionStrength * offset); 51 | i++; 52 | } 53 | } 54 | } 55 | } 56 | 57 | void ofApp::draw() { 58 | ofBackground(0); 59 | ofScale(2, 2); 60 | cam.getTexture().bind(); 61 | mesh.draw(); 62 | cam.getTexture().unbind(); 63 | if(ofGetMousePressed()) { 64 | mesh.drawWireframe(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example-flow-distort/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofxCv::FlowFarneback flow; 14 | ofMesh mesh; 15 | int stepSize, xSteps, ySteps; 16 | }; -------------------------------------------------------------------------------- /example-flow-keypoints/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-flow-keypoints/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-flow-keypoints/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace cv; 4 | using namespace ofxCv; 5 | 6 | void ofApp::setup(){ 7 | grabber.setup(640,480); 8 | } 9 | 10 | void ofApp::update(){ 11 | grabber.update(); 12 | if(grabber.isFrameNew()){ 13 | flow.calcOpticalFlow(grabber); 14 | } 15 | } 16 | 17 | void ofApp::draw(){ 18 | grabber.draw(0,0); 19 | flow.draw(); 20 | if(ofGetMousePressed()){ 21 | ofNoFill(); 22 | ofDrawRectangle(rect); 23 | } 24 | } 25 | 26 | void ofApp::mouseDragged(int x, int y, int button){ 27 | ofVec2f p2(x,y); 28 | rect.set(p1,p2.x-p1.x,p2.y-p1.y); 29 | } 30 | 31 | void ofApp::mousePressed(int x, int y, int button){ 32 | p1.set(x,y); 33 | } 34 | 35 | void ofApp::mouseReleased(int x, int y, int button){ 36 | ofVec2f p2(x,y); 37 | rect.set(p1,p2.x-p1.x,p2.y-p1.y); 38 | vector keypoints; 39 | vector keypointsInside; 40 | vector featuresToTrack; 41 | copyGray(grabber, grabberGray); 42 | FAST(grabberGray,keypoints,2); 43 | for(int i=0;icalcOpticalFlow(camera); 55 | } 56 | } 57 | 58 | void ofApp::draw(){ 59 | ofPushMatrix(); 60 | ofTranslate(250, 100); 61 | camera.draw(0,0,640,480); 62 | curFlow->draw(0,0,640,480); 63 | ofDrawBitmapStringHighlight(ofToString((int) ofGetFrameRate()) + "fps", 10, 20); 64 | ofPopMatrix(); 65 | gui.draw(); 66 | } -------------------------------------------------------------------------------- /example-flow/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class ofApp : public ofBaseApp{ 8 | public: 9 | void setup(); 10 | void update(); 11 | void draw(); 12 | 13 | ofVideoGrabber camera; 14 | 15 | ofxCv::FlowFarneback fb; 16 | ofxCv::FlowPyrLK lk; 17 | 18 | ofxCv::Flow* curFlow; 19 | 20 | ofxPanel gui; 21 | ofParameter fbPyrScale, lkQualityLevel, fbPolySigma; 22 | ofParameter fbLevels, lkWinSize, fbIterations, fbPolyN, fbWinSize, lkMaxLevel, lkMaxFeatures, lkMinDistance; 23 | ofParameter fbUseGaussian, usefb; 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /example-gamma/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxGui 3 | ofxOpenCv 4 | -------------------------------------------------------------------------------- /example-gamma/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-gamma/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void adjustGamma(cv::Mat& img, float gamma = 0.5) { 7 | cv::Mat lookUpTable(1, 256, CV_8U); 8 | unsigned char* p = lookUpTable.ptr(); 9 | for (int i = 0; i < 256; i++) { 10 | p[i] = saturate_cast(pow(i / 255.0, gamma) * 255.0); 11 | } 12 | cv::LUT(img, lookUpTable, img); 13 | } 14 | 15 | void ofApp::setup() { 16 | cam.initGrabber(640, 480); 17 | } 18 | 19 | void ofApp::update() { 20 | cam.update(); 21 | if(cam.isFrameNew()) { 22 | img = toCv(cam); 23 | float gamma = ofMap(mouseX, 0, ofGetWidth(), 0, 2); 24 | adjustGamma(img, gamma); 25 | } 26 | } 27 | 28 | void ofApp::draw() { 29 | ofxCv::drawMat(img, 0, 0); 30 | } 31 | -------------------------------------------------------------------------------- /example-gamma/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | cv::Mat img; 14 | }; 15 | -------------------------------------------------------------------------------- /example-gesture/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-gesture/src/GeometryHelpers.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | template 7 | Real DistancePointEllipseSpecial (const Real e[2], const Real y[2], Real x[2]) 8 | { 9 | Real distance; 10 | if (y[1] > (Real)0) 11 | { 12 | if (y[0] > (Real)0) 13 | { 14 | // Bisect to compute the root of F(t) for t >= -e1*e1. 15 | Real esqr[2] = { e[0]*e[0], e[1]*e[1] }; 16 | Real ey[2] = { e[0]*y[0], e[1]*y[1] }; 17 | Real t0 = -esqr[1] + ey[1]; 18 | Real t1 = -esqr[1] + sqrt(ey[0]*ey[0] + ey[1]*ey[1]); 19 | Real t = t0; 20 | const int imax = 2*std::numeric_limits::max_exponent; 21 | for (int i = 0; i < imax; ++i) 22 | { 23 | t = ((Real)0.5)*(t0 + t1); 24 | if (t == t0 || t == t1) 25 | { 26 | break; 27 | } 28 | 29 | Real r[2] = { ey[0]/(t + esqr[0]), ey[1]/(t + esqr[1]) }; 30 | Real f = r[0]*r[0] + r[1]*r[1] - (Real)1; 31 | if (f > (Real)0) 32 | { 33 | t0 = t; 34 | } 35 | else if (f < (Real)0) 36 | { 37 | t1 = t; 38 | } 39 | else 40 | { 41 | break; 42 | } 43 | } 44 | 45 | x[0] = esqr[0]*y[0]/(t + esqr[0]); 46 | x[1] = esqr[1]*y[1]/(t + esqr[1]); 47 | Real d[2] = { x[0] - y[0], x[1] - y[1] }; 48 | distance = sqrt(d[0]*d[0] + d[1]*d[1]); 49 | } 50 | else // y0 == 0 51 | { 52 | x[0] = (Real)0; 53 | x[1] = e[1]; 54 | distance = fabs(y[1] - e[1]); 55 | } 56 | } 57 | else // y1 == 0 58 | { 59 | Real denom0 = e[0]*e[0] - e[1]*e[1]; 60 | Real e0y0 = e[0]*y[0]; 61 | if (e0y0 < denom0) 62 | { 63 | // y0 is inside the subinterval. 64 | Real x0de0 = e0y0/denom0; 65 | Real x0de0sqr = x0de0*x0de0; 66 | x[0] = e[0]*x0de0; 67 | x[1] = e[1]*sqrt(fabs((Real)1 - x0de0sqr)); 68 | Real d0 = x[0] - y[0]; 69 | distance = sqrt(d0*d0 + x[1]*x[1]); 70 | } 71 | else 72 | { 73 | // y0 is outside the subinterval. The closest ellipse point has 74 | // x1 == 0 and is on the domain-boundary interval (x0/e0)^2 = 1. 75 | x[0] = e[0]; 76 | x[1] = (Real)0; 77 | distance = fabs(y[0] - e[0]); 78 | } 79 | } 80 | return distance; 81 | } 82 | //---------------------------------------------------------------------------- 83 | // The ellipse is (x0/e0)^2 + (x1/e1)^2 = 1. The query point is (y0,y1). 84 | // The function returns the distance from the query point to the ellipse. 85 | // It also computes the ellipse point (x0,x1) that is closest to (y0,y1). 86 | //---------------------------------------------------------------------------- 87 | template 88 | Real DistancePointEllipse (const Real e[2], const Real y[2], Real x[2]) 89 | { 90 | // Determine reflections for y to the first quadrant. 91 | bool reflect[2]; 92 | int i, j; 93 | for (i = 0; i < 2; ++i) 94 | { 95 | reflect[i] = (y[i] < (Real)0); 96 | } 97 | 98 | // Determine the axis order for decreasing extents. 99 | int permute[2]; 100 | if (e[0] < e[1]) 101 | { 102 | permute[0] = 1; permute[1] = 0; 103 | } 104 | else 105 | { 106 | permute[0] = 0; permute[1] = 1; 107 | } 108 | 109 | int invpermute[2]; 110 | for (i = 0; i < 2; ++i) 111 | { 112 | invpermute[permute[i]] = i; 113 | } 114 | 115 | Real locE[2], locY[2]; 116 | for (i = 0; i < 2; ++i) 117 | { 118 | j = permute[i]; 119 | locE[i] = e[j]; 120 | locY[i] = y[j]; 121 | if (reflect[j]) 122 | { 123 | locY[i] = -locY[i]; 124 | } 125 | } 126 | 127 | Real locX[2]; 128 | Real distance = DistancePointEllipseSpecial(locE, locY, locX); 129 | 130 | // Restore the axis order and reflections. 131 | for (i = 0; i < 2; ++i) 132 | { 133 | j = invpermute[i]; 134 | if (reflect[j]) 135 | { 136 | locX[j] = -locX[j]; 137 | } 138 | x[i] = locX[j]; 139 | } 140 | 141 | return distance; 142 | } 143 | 144 | ofVec2f closestPointOnRay(const ofVec2f& p1, const ofVec2f& p2, const ofVec2f& p3) { 145 | if(p1 == p2) { 146 | return p1; 147 | } 148 | 149 | float u = (p3.x - p1.x) * (p2.x - p1.x); 150 | u += (p3.y - p1.y) * (p2.y - p1.y); 151 | float len = (p2 - p1).length(); 152 | u /= (len * len); 153 | 154 | return p1.getInterpolated(p2, u); 155 | } 156 | 157 | ofVec2f closestPointOnLine(const ofVec2f& p1, const ofVec2f& p2, const ofVec2f& p3) { 158 | if(p1 == p2) { 159 | return p1; 160 | } 161 | 162 | float u = (p3.x - p1.x) * (p2.x - p1.x); 163 | u += (p3.y - p1.y) * (p2.y - p1.y); 164 | float len = (p2 - p1).length(); 165 | u /= (len * len); 166 | 167 | // clamp u 168 | if(u > 1) { 169 | u = 1; 170 | } else if(u < 0) { 171 | u = 0; 172 | } 173 | return p1.getInterpolated(p2, u); 174 | } 175 | 176 | ofVec2f closestPointOnRect(const cv::RotatedRect& rect, const ofVec2f& point) { 177 | ofVec2f norm = point; 178 | ofVec2f offset(rect.center.x, rect.center.y); 179 | norm -= offset; 180 | norm.rotate(-rect.angle); 181 | float w = rect.size.width / 2, h = rect.size.height / 2; 182 | ofVec2f nearest; 183 | if((norm.x > w || norm.x < -w) || (norm.y < -h || norm.y > h)) { 184 | nearest.set(ofClamp(norm.x, -w, w), ofClamp(norm.y, -h, h)); 185 | } else { 186 | if(fabsf(fabsf(norm.x) - w) < fabsf(fabsf(norm.y) - h)) { 187 | nearest.set(w * (norm.x > 0 ? 1 : -1), norm.y); 188 | } else { 189 | nearest.set(norm.x, h * (norm.y > 0 ? 1 : -1)); 190 | } 191 | } 192 | nearest.rotate(rect.angle); 193 | nearest += offset; 194 | return nearest; 195 | } 196 | 197 | ofVec2f closestPointOnCircle(const ofVec2f& center, float radius, const ofVec2f& point) { 198 | ofVec2f nearest = point - center; 199 | nearest *= radius / nearest.length(); 200 | nearest += center; 201 | return nearest; 202 | } 203 | 204 | ofVec2f closestPointOnEllipse(const cv::RotatedRect& ellipse, const ofVec2f& point) { 205 | ofVec2f norm = point; 206 | ofVec2f offset(ellipse.center.x, ellipse.center.y); 207 | norm -= offset; 208 | norm.rotate(-ellipse.angle); 209 | bool flipX = norm.x < 0, flipY = norm.y < 0; 210 | if(flipX) norm.x *= -1; 211 | if(flipY) norm.y *= -1; 212 | float e[] = {ellipse.size.width / 2, ellipse.size.height / 2}; 213 | float y[] = {norm.x, norm.y}; 214 | float x[2]; 215 | DistancePointEllipse(e, y, x); 216 | ofVec2f result(x[0], x[1]); 217 | if(flipX) result.x *= -1; 218 | if(flipY) result.y *= -1; 219 | result.rotate(ellipse.angle); 220 | result += offset; 221 | return result; 222 | } 223 | 224 | float distanceToEllipse(const ofVec2f& point, const cv::RotatedRect& ellipse) { 225 | return closestPointOnEllipse(ellipse, point).distance(point); 226 | } 227 | 228 | float distanceToRect(const ofVec2f& point, const cv::RotatedRect& rect) { 229 | return closestPointOnRect(rect, point).distance(point); 230 | } 231 | 232 | float distanceToLine(const ofVec2f& point, const ofVec2f& start, const ofVec2f& end) { 233 | return closestPointOnLine(start, end, point).distance(point); 234 | } 235 | 236 | float distanceToRay(const ofVec2f& point, const ofVec2f& start, const ofVec2f& end) { 237 | return closestPointOnRay(start, end, point).distance(point); 238 | } 239 | -------------------------------------------------------------------------------- /example-gesture/src/GeometryHelpers.h: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | ofVec2f closestPointOnRay(const ofVec2f& p1, const ofVec2f& p2, const ofVec2f& p3); 7 | ofVec2f closestPointOnLine(const ofVec2f& p1, const ofVec2f& p2, const ofVec2f& p3); 8 | ofVec2f closestPointOnRect(const cv::RotatedRect& rect, const ofVec2f& point); 9 | ofVec2f closestPointOnCircle(const ofVec2f& center, float radius, const ofVec2f& point); 10 | ofVec2f closestPointOnEllipse(const cv::RotatedRect& ellipse, const ofVec2f& point); 11 | 12 | float distanceToEllipse(const ofVec2f& point, const cv::RotatedRect& ellipse); 13 | float distanceToRect(const ofVec2f& point, const cv::RotatedRect& rect); 14 | float distanceToRay(const ofVec2f& point, const ofVec2f& start, const ofVec2f& end); 15 | float distanceToLine(const ofVec2f& point, const ofVec2f& start, const ofVec2f& end); -------------------------------------------------------------------------------- /example-gesture/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(1280, 720, OF_FULLSCREEN); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-gesture/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofEnableSmoothing(); 9 | ofEnableAlphaBlending(); 10 | ofSetLineWidth(3); 11 | ofSetFrameRate(120); 12 | } 13 | 14 | void ofApp::update() { 15 | 16 | } 17 | 18 | void ofApp::draw() { 19 | ofBackground(0); 20 | ofSetColor(255, 64); 21 | polyline.draw(); 22 | 23 | switch(recognizer.getGestureType()) { 24 | case Recognizer::GESTURE_LINE: ofSetColor(magentaPrint); break; 25 | case Recognizer::GESTURE_ARC: ofSetColor(cyanPrint); break; 26 | } 27 | if(recognizer.getFitError() < .5) { 28 | recognizer.getPolyline().draw(); 29 | } 30 | } 31 | 32 | void ofApp::mousePressed(int x, int y, int button) { 33 | polyline.clear(); 34 | } 35 | 36 | void ofApp::mouseDragged(int x, int y, int button) { 37 | polyline.addVertex(x, y); 38 | recognizer.update(polyline); 39 | } 40 | -------------------------------------------------------------------------------- /example-gesture/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | #include "GeometryHelpers.h" 7 | 8 | class Recognizer { 9 | public: 10 | enum GestureType {GESTURE_LINE, GESTURE_ARC}; 11 | 12 | Recognizer() 13 | :lineRatio(6) 14 | ,gestureType(GESTURE_LINE) 15 | ,fitError(0) 16 | {} 17 | void setLineRatio(float lineRatio) { 18 | this->lineRatio = lineRatio; 19 | } 20 | GestureType getGestureType() const { 21 | return gestureType; 22 | } 23 | float getFitError() const { 24 | return fitError; 25 | } 26 | ofPolyline& getPolyline() { 27 | return idealized; 28 | } 29 | void update(ofPolyline& polyline) { 30 | if(polyline.size() > 5) { 31 | ellipse = fitEllipse(polyline); 32 | } 33 | rect = minAreaRect(polyline); 34 | fitLine(polyline, linePoint, lineDirection); 35 | 36 | float lineSum = 0, ellipseSum = 0; 37 | for(int i = 0; i < polyline.size(); i++) { 38 | lineSum += distanceToRay(polyline[i], linePoint, linePoint + lineDirection); 39 | ellipseSum += distanceToEllipse(polyline[i], ellipse); 40 | } 41 | float perimeter = polyline.getPerimeter(); 42 | lineSum /= perimeter, ellipseSum /= perimeter; 43 | 44 | bool isLine = rect.size.width / rect.size.height > lineRatio 45 | || rect.size.height / rect.size.width > lineRatio 46 | || (lineSum < ellipseSum) 47 | || ellipseSum != ellipseSum; 48 | idealized.clear(); 49 | if(isLine) { 50 | gestureType = GESTURE_LINE; 51 | fitError = lineSum; 52 | idealized.addVertex(closestPointOnRay(linePoint, linePoint + lineDirection, polyline[0])); 53 | idealized.addVertex(closestPointOnRay(linePoint, linePoint + lineDirection, polyline[polyline.size() - 1])); 54 | } else { 55 | gestureType = GESTURE_ARC; 56 | fitError = ellipseSum; 57 | ofVec2f center(ellipse.center.x, ellipse.center.y); 58 | // it would make more sense to do this at a fixed resolution 59 | for(int i = 0; i < polyline.size(); i++) { 60 | ofVec2f cur = polyline[i]; 61 | cur -= center, cur.rotate(-ellipse.angle); 62 | float a = ellipse.size.width / 2, b = ellipse.size.height / 2, x0 = cur.x, y0 = cur.y; 63 | cur *= (a * b) / sqrtf(a * a * y0 * y0 + b * b * x0 * x0); 64 | cur.rotate(ellipse.angle), cur += center; 65 | idealized.addVertex(cur); 66 | } 67 | } 68 | } 69 | 70 | protected: 71 | cv::RotatedRect ellipse, rect; 72 | ofVec2f linePoint, lineDirection; 73 | ofPolyline idealized; 74 | float lineRatio, fitError; 75 | GestureType gestureType; 76 | }; 77 | 78 | class ofApp : public ofBaseApp { 79 | public: 80 | void setup(); 81 | void update(); 82 | void draw(); 83 | 84 | void mousePressed(int x, int y, int button); 85 | void mouseDragged(int x, int y, int button); 86 | 87 | ofPolyline polyline; 88 | 89 | Recognizer recognizer; 90 | }; 91 | -------------------------------------------------------------------------------- /example-highpass/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxGui 3 | ofxOpenCv 4 | -------------------------------------------------------------------------------- /example-highpass/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main(){ 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-highpass/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofBackground(0); 8 | camera.setup(640, 480); 9 | gui.setup(); 10 | gui.add(size.set("size", 80, 0, 128)); 11 | gui.add(contrast.set("contrast", 1.5, .5, 5)); 12 | } 13 | 14 | void ofApp::update(){ 15 | camera.update(); 16 | 17 | if(camera.isFrameNew()) { 18 | highpass.filter(camera, filtered, size, contrast); 19 | filtered.update(); 20 | } 21 | } 22 | 23 | void ofApp::draw(){ 24 | camera.draw(0, 0); 25 | filtered.draw(ofGetWidth() / 2, 0); 26 | gui.draw(); 27 | } -------------------------------------------------------------------------------- /example-highpass/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | #include "ofxGui.h" 6 | 7 | class Highpass { 8 | public: 9 | cv::Mat lab, lowpass, highpass; 10 | vector labChannels; 11 | 12 | template 13 | void filter(S& src, D& dst, int size, float contrast = 1) { 14 | ofxCv::convertColor(src, lab, CV_RGB2Lab); 15 | cv::split(lab, labChannels); 16 | cv::Mat& lightness = labChannels[0]; 17 | ofxCv::blur(lightness, lowpass, size); 18 | // could convert to 16s instead of 32f for extra speed 19 | cv::subtract(lightness, lowpass, highpass, cv::noArray(), CV_32F); 20 | if (contrast != 1) { 21 | highpass *= contrast; 22 | } 23 | highpass += 128; // should be diff for other datatypes 24 | highpass.convertTo(lightness, lightness.type()); 25 | ofxCv::imitate(dst, src); 26 | cv::merge(labChannels, ofxCv::toCv(dst)); 27 | ofxCv::convertColor(dst, dst, CV_Lab2RGB); 28 | } 29 | }; 30 | 31 | class ofApp : public ofBaseApp{ 32 | public: 33 | void setup(); 34 | void update(); 35 | void draw(); 36 | 37 | ofVideoGrabber camera; 38 | Highpass highpass; 39 | ofImage filtered; 40 | ofxPanel gui; 41 | ofParameter size, contrast; 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /example-homography/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-homography/bin/data/left.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-homography/bin/data/left.jpg -------------------------------------------------------------------------------- /example-homography/bin/data/right.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/example-homography/bin/data/right.jpg -------------------------------------------------------------------------------- /example-homography/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-homography/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | 9 | left.load("left.jpg"); 10 | right.load("right.jpg"); 11 | imitate(warpedColor, right); 12 | 13 | movingPoint = false; 14 | saveMatrix = false; 15 | homographyReady = false; 16 | 17 | // load the previous homography if it's available 18 | ofFile previous("homography.yml"); 19 | if(previous.exists()) { 20 | FileStorage fs(ofToDataPath("homography.yml"), FileStorage::READ); 21 | fs["homography"] >> homography; 22 | homographyReady = true; 23 | } 24 | } 25 | 26 | void ofApp::update() { 27 | if(leftPoints.size() >= 4) { 28 | vector srcPoints, dstPoints; 29 | for(int i = 0; i < leftPoints.size(); i++) { 30 | srcPoints.push_back(Point2f(rightPoints[i].x - left.getWidth(), rightPoints[i].y)); 31 | dstPoints.push_back(Point2f(leftPoints[i].x, leftPoints[i].y)); 32 | } 33 | 34 | // generate a homography from the two sets of points 35 | homography = findHomography(Mat(srcPoints), Mat(dstPoints)); 36 | homographyReady = true; 37 | 38 | if(saveMatrix) { 39 | FileStorage fs(ofToDataPath("homography.yml"), FileStorage::WRITE); 40 | fs << "homography" << homography; 41 | saveMatrix = false; 42 | } 43 | } 44 | 45 | if(homographyReady) { 46 | // this is how you warp one ofImage into another ofImage given the homography matrix 47 | // CV INTER NN is 113 fps, CV_INTER_LINEAR is 93 fps 48 | warpPerspective(right, warpedColor, homography, CV_INTER_LINEAR); 49 | warpedColor.update(); 50 | } 51 | } 52 | 53 | void drawPoints(vector& points) { 54 | ofNoFill(); 55 | for(int i = 0; i < points.size(); i++) { 56 | ofDrawCircle(points[i], 10); 57 | ofDrawCircle(points[i], 1); 58 | } 59 | } 60 | 61 | void ofApp::draw() { 62 | 63 | ofSetColor(255); 64 | left.draw(0, 0); 65 | right.draw(left.getWidth(), 0); 66 | if(homographyReady) { 67 | ofEnableBlendMode(OF_BLENDMODE_MULTIPLY); 68 | ofSetColor(255, 128); 69 | warpedColor.draw(0, 0); 70 | ofDisableBlendMode(); 71 | } 72 | 73 | ofSetColor(ofColor::red); 74 | drawPoints(leftPoints); 75 | ofSetColor(ofColor::blue); 76 | drawPoints(rightPoints); 77 | ofSetColor(128); 78 | for(int i = 0; i < leftPoints.size(); i++) { 79 | ofDrawLine(leftPoints[i], rightPoints[i]); 80 | } 81 | 82 | ofSetColor(255); 83 | ofDrawBitmapString(ofToString((int) ofGetFrameRate()), 10, 20); 84 | } 85 | 86 | bool ofApp::movePoint(vector& points, ofVec2f point) { 87 | for(int i = 0; i < points.size(); i++) { 88 | if(points[i].distance(point) < 20) { 89 | movingPoint = true; 90 | curPoint = &points[i]; 91 | return true; 92 | } 93 | } 94 | return false; 95 | } 96 | 97 | void ofApp::mousePressed(int x, int y, int button) { 98 | ofVec2f cur(x, y); 99 | ofVec2f rightOffset(left.getWidth(), 0); 100 | if(!movePoint(leftPoints, cur) && !movePoint(rightPoints, cur)) { 101 | if(x > left.getWidth()) { 102 | cur -= rightOffset; 103 | } 104 | leftPoints.push_back(cur); 105 | rightPoints.push_back(cur + rightOffset); 106 | } 107 | } 108 | 109 | void ofApp::mouseDragged(int x, int y, int button) { 110 | if(movingPoint) { 111 | curPoint->set(x, y); 112 | } 113 | } 114 | 115 | void ofApp::mouseReleased(int x, int y, int button) { 116 | movingPoint = false; 117 | } 118 | 119 | void ofApp::keyPressed(int key) { 120 | if(key == ' ') { 121 | saveMatrix = true; 122 | } 123 | } -------------------------------------------------------------------------------- /example-homography/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | bool movePoint(vector& points, ofVec2f point); 12 | void mousePressed(int x, int y, int button); 13 | void mouseDragged(int x, int y, int button); 14 | void mouseReleased(int x, int y, int button); 15 | void keyPressed(int key); 16 | 17 | ofImage left, right, warpedColor; 18 | vector leftPoints, rightPoints; 19 | bool movingPoint; 20 | ofVec2f* curPoint; 21 | bool saveMatrix; 22 | bool homographyReady; 23 | 24 | cv::Mat homography; 25 | }; 26 | -------------------------------------------------------------------------------- /example-kalman-euler/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-kalman-euler/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-kalman-euler/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | 9 | kalman.init(1/100000., 1/10.); // inverse of (smoothness, rapidness) 10 | } 11 | 12 | void ofApp::update() { 13 | m.makeIdentityMatrix(); 14 | // generate rotation for demo 15 | m.rotate(ofMap(mouseX, 0, ofGetWidth(), -180, 180), 1, 0, 0); 16 | m.rotate(ofMap(mouseY, 0, ofGetHeight(), -180, 180), 0, 1, 0); 17 | m.rotate(ofMap(ofGetElapsedTimef(), 0, 1, 0, 180), 0, 1, 1); 18 | 19 | ofQuaternion q; 20 | q = m.getRotate(); 21 | kalman.update(q); 22 | mPredicted.setRotate(kalman.getEstimation()); 23 | } 24 | 25 | void drawTransparentAxis(float size, int alpha) { 26 | ofPushStyle(); 27 | ofSetLineWidth(3); 28 | 29 | // draw x axis 30 | ofSetColor(255, 0, 0, alpha); 31 | ofDrawLine(0, 0, 0, size, 0, 0); 32 | 33 | // draw y axis 34 | ofSetColor(0, 255, 0, alpha); 35 | ofDrawLine(0, 0, 0, 0, size, 0); 36 | 37 | // draw z axis 38 | ofSetColor(0, 0, 255, alpha); 39 | ofDrawLine(0, 0, 0, 0, 0, size); 40 | ofPopStyle(); 41 | } 42 | 43 | void ofApp::draw() { 44 | ofBackground(54); 45 | 46 | cam.begin(); 47 | 48 | ofPushMatrix(); 49 | glMultMatrixf((GLfloat*)m.getPtr()); 50 | drawTransparentAxis(200, 128); 51 | ofPopMatrix(); 52 | 53 | ofPushMatrix(); 54 | glMultMatrixf((GLfloat*)mPredicted.getPtr()); 55 | ofDrawAxis(200); 56 | ofPopMatrix(); 57 | 58 | cam.end(); 59 | } 60 | -------------------------------------------------------------------------------- /example-kalman-euler/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofxCv::KalmanEuler kalman; 13 | 14 | ofMatrix4x4 m, mPredicted; 15 | ofEasyCam cam; 16 | }; 17 | -------------------------------------------------------------------------------- /example-kalman/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-kalman/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-kalman/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | 9 | kalman.init(1/10000., 1/10.); // inverse of (smoothness, rapidness) 10 | 11 | line.setMode(OF_PRIMITIVE_LINE_STRIP); 12 | predicted.setMode(OF_PRIMITIVE_LINE_STRIP); 13 | estimated.setMode(OF_PRIMITIVE_LINE_STRIP); 14 | 15 | speed = 0.f; 16 | } 17 | 18 | void ofApp::update() { 19 | ofVec2f curPoint(mouseX, mouseY); 20 | line.addVertex(curPoint); 21 | 22 | kalman.update(curPoint); // feed measurement 23 | 24 | point = kalman.getPrediction(); // prediction before measurement 25 | predicted.addVertex(point); 26 | estimated.addVertex(kalman.getEstimation()); // corrected estimation after measurement 27 | 28 | speed = kalman.getVelocity().length(); 29 | int alpha = ofMap(speed, 0, 20, 50, 255, true); 30 | line.addColor(ofColor(255, 255, 255, alpha)); 31 | predicted.addColor(ofColor(255, 0, 0, alpha)); 32 | estimated.addColor(ofColor(0, 255, 0, alpha)); 33 | } 34 | 35 | void ofApp::draw() { 36 | ofBackground(0); 37 | 38 | line.draw(); 39 | 40 | predicted.draw(); 41 | ofPushStyle(); 42 | ofSetColor(ofColor::red, 128); 43 | ofFill(); 44 | ofDrawCircle(point, speed * 2); 45 | ofPopStyle(); 46 | 47 | estimated.draw(); 48 | } 49 | -------------------------------------------------------------------------------- /example-kalman/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofxCv::KalmanPosition kalman; 13 | 14 | ofMesh predicted, line, estimated; 15 | ofVec2f point; 16 | float speed; 17 | }; 18 | -------------------------------------------------------------------------------- /example-smile/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-smile/bin/data/readme.txt: -------------------------------------------------------------------------------- 1 | You need to add a copy of haarcascade_frontalface_default.xml and smiled_05.xml to this directory. 2 | 3 | haarcascade_frontalface_default.xml can be found at: 4 | 5 | openFrameworks/examples/addons/opencvHaarFinderExample/bin/haarcascade_frontalface_default.xml 6 | 7 | smiled_05.xml can be found at: 8 | 9 | https://github.com/hromi/SMILEsmileD/blob/master/smileD/smiled_05.xml -------------------------------------------------------------------------------- /example-smile/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-smile/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | ofSetFrameRate(120); 9 | cam.setup(640, 480); 10 | smile.setup(); 11 | } 12 | 13 | void ofApp::update() { 14 | cam.update(); 15 | if(cam.isFrameNew()) { 16 | smile.update(cam); 17 | if(smile.getFaceFound()) { 18 | float cur = smile.getSmileAmount(); 19 | graph.add(cur); 20 | ofLog() << graph.getNormalized(cur); 21 | } 22 | } 23 | } 24 | 25 | void ofApp::draw() { 26 | ofSetColor(255); 27 | cam.draw(0, 0); 28 | smile.draw(); 29 | 30 | ofTranslate(10, 10); 31 | ofSetColor(0); 32 | ofDrawRectangle(0, 0, 300, 100); 33 | ofSetColor(255); 34 | graph.draw(300, 100); 35 | } 36 | -------------------------------------------------------------------------------- /example-smile/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | // single-person smile strength detector 7 | // not robust against rotation 8 | class SmileDetector { 9 | protected: 10 | ofRectangle roi; 11 | 12 | public: 13 | ofxCv::ObjectFinder faceFinder, smileFinder; 14 | 15 | void setup() { 16 | faceFinder.setup("haarcascade_frontalface_default.xml"); 17 | faceFinder.setPreset(ofxCv::ObjectFinder::Accurate); 18 | faceFinder.setFindBiggestObject(true); 19 | smileFinder.setup("smiled_05.xml"); 20 | smileFinder.setPreset(ofxCv::ObjectFinder::Sensitive); 21 | smileFinder.setMinNeighbors(0); 22 | } 23 | template 24 | void update(T& img) { 25 | update(ofxCv::toCv(img)); 26 | } 27 | void update(const cv::Mat& mat) { 28 | faceFinder.update(mat); 29 | if(faceFinder.size()) { 30 | roi = faceFinder.getObject(0); 31 | float lowerRatio = .35; 32 | roi.y += roi.height * (1 - lowerRatio); 33 | roi.height *= lowerRatio; 34 | cv::Mat faceMat(mat, ofxCv::toCv(roi)); 35 | smileFinder.update(faceMat); 36 | } 37 | } 38 | void draw() const { 39 | faceFinder.draw(); 40 | if(faceFinder.size()) { 41 | ofPushMatrix(); 42 | ofTranslate(roi.position); 43 | smileFinder.draw(); 44 | ofPopMatrix(); 45 | } 46 | } 47 | bool getFaceFound() const { 48 | return faceFinder.size(); 49 | } 50 | ofRectangle getFace() const { 51 | return faceFinder.getObject(0); 52 | } 53 | int getSmileAmount() const { 54 | if(faceFinder.size()) { 55 | return smileFinder.size(); 56 | } else { 57 | return 0; 58 | } 59 | } 60 | }; 61 | 62 | class LineGraph { 63 | protected: 64 | ofMesh mesh; 65 | ofVec2f min, max; 66 | int n; 67 | 68 | public: 69 | LineGraph() 70 | :n(0) { 71 | } 72 | void reset() { 73 | n = 0; 74 | min = ofVec2f(); 75 | max = ofVec2f(); 76 | } 77 | void add(float y) { 78 | ofVec2f cur(n, y); 79 | mesh.addVertex(cur); 80 | if(n == 0) { 81 | min = cur; 82 | max = cur; 83 | } else { 84 | min.set(MIN(min.x, cur.x), MIN(min.y, cur.y)); 85 | max.set(MAX(max.x, cur.x), MAX(max.y, cur.y)); 86 | } 87 | n++; 88 | } 89 | float getNormalized(float y) { 90 | return ofNormalize(y, min.y, max.y); 91 | } 92 | void draw(float w, float h) { 93 | if(n > 2) { 94 | ofPushMatrix(); 95 | ofTranslate(0, h); 96 | ofScale(w / (max.x - min.x), -h / (max.y - min.y)); 97 | ofTranslate(-min); 98 | mesh.setMode(OF_PRIMITIVE_LINE_STRIP); 99 | mesh.draw(); 100 | ofPopMatrix(); 101 | } 102 | } 103 | }; 104 | 105 | class ofApp : public ofBaseApp { 106 | public: 107 | void setup(); 108 | void update(); 109 | void draw(); 110 | 111 | ofVideoGrabber cam; 112 | SmileDetector smile; 113 | LineGraph graph; 114 | }; 115 | -------------------------------------------------------------------------------- /example-threshold/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-threshold/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-threshold/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace cv; 4 | using namespace ofxCv; 5 | 6 | void ofApp::setup() { 7 | cam.setup(640, 480); 8 | thresh.allocate(640, 480, OF_IMAGE_GRAYSCALE); 9 | } 10 | 11 | void ofApp::update() { 12 | cam.update(); 13 | if(cam.isFrameNew()) { 14 | convertColor(cam, thresh, CV_RGB2GRAY); 15 | if(ofGetMousePressed()) { 16 | autothreshold(thresh); 17 | } else { 18 | float thresholdValue = ofMap(mouseX, 0, ofGetWidth(), 0, 255); 19 | threshold(thresh, thresholdValue); 20 | } 21 | thresh.update(); 22 | } 23 | } 24 | 25 | void ofApp::draw() { 26 | cam.draw(0, 0); 27 | thresh.draw(640, 0); 28 | } 29 | -------------------------------------------------------------------------------- /example-threshold/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofImage thresh; 14 | }; 15 | -------------------------------------------------------------------------------- /example-undistortion/addons.make: -------------------------------------------------------------------------------- 1 | ofxCv 2 | ofxOpenCv 3 | ofxGui 4 | -------------------------------------------------------------------------------- /example-undistortion/bin/data/mbp-2011-isight.yml: -------------------------------------------------------------------------------- 1 | %YAML:1.0 2 | cameraMatrix: !!opencv-matrix 3 | rows: 3 4 | cols: 3 5 | dt: d 6 | data: [ 6.6278599887122368e+02, 0., 3.1244256016006659e+02, 0., 7 | 6.6129276875199082e+02, 2.2747179767124251e+02, 0., 0., 1. ] 8 | imageSize_width: 640 9 | imageSize_height: 480 10 | sensorSize_width: 0 11 | sensorSize_height: 0 12 | distCoeffs: !!opencv-matrix 13 | rows: 5 14 | cols: 1 15 | dt: d 16 | data: [ -1.8848338341464690e-01, 1.0721890419183855e+00, 17 | -3.5244467228016116e-03, -7.0195032848241403e-04, 18 | -2.0412827999027101e+00 ] 19 | reprojectionError: 2.1723265945911407e-01 20 | -------------------------------------------------------------------------------- /example-undistortion/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | int main() { 4 | ofSetupOpenGL(640 * 2, 480, OF_WINDOW); 5 | ofRunApp(new ofApp()); 6 | } 7 | -------------------------------------------------------------------------------- /example-undistortion/src/ofApp.cpp: -------------------------------------------------------------------------------- 1 | #include "ofApp.h" 2 | 3 | using namespace ofxCv; 4 | using namespace cv; 5 | 6 | void ofApp::setup() { 7 | ofSetVerticalSync(true); 8 | cam.setup(640, 480); 9 | calibration.setFillFrame(true); // true by default 10 | calibration.load("mbp-2011-isight.yml"); 11 | imitate(undistorted, cam); 12 | } 13 | 14 | void ofApp::update() { 15 | cam.update(); 16 | if(cam.isFrameNew()) { 17 | calibration.undistort(toCv(cam), toCv(undistorted)); 18 | undistorted.update(); 19 | } 20 | } 21 | 22 | void ofApp::draw() { 23 | ofSetColor(255); 24 | cam.draw(0, 0); 25 | undistorted.draw(640, 0); 26 | } 27 | -------------------------------------------------------------------------------- /example-undistortion/src/ofApp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofMain.h" 4 | #include "ofxCv.h" 5 | 6 | class ofApp : public ofBaseApp { 7 | public: 8 | void setup(); 9 | void update(); 10 | void draw(); 11 | 12 | ofVideoGrabber cam; 13 | ofImage undistorted; 14 | ofxCv::Calibration calibration; 15 | }; 16 | -------------------------------------------------------------------------------- /libs/.gitignore: -------------------------------------------------------------------------------- 1 | opencv/ -------------------------------------------------------------------------------- /libs/CLD/addons.make: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/libs/CLD/addons.make -------------------------------------------------------------------------------- /libs/CLD/include/CLD/ETF.h: -------------------------------------------------------------------------------- 1 | #ifndef _ETF_H_ 2 | #define _ETF_H_ 3 | 4 | #include "imatrix.h" 5 | 6 | struct Vect { 7 | double tx, ty, mag; 8 | }; 9 | 10 | 11 | class ETF { 12 | private: 13 | int Nr, Nc; 14 | Vect** p; 15 | double max_grad; 16 | public: 17 | ETF() 18 | { 19 | Nr = 1, Nc = 1; 20 | p = new Vect*[Nr]; 21 | for(int i = 0; i < Nr; i++) 22 | p[i] = new Vect[Nc]; 23 | p[0][0].tx=1.0; p[0][0].ty=0.0; p[0][0].mag=1.0; 24 | max_grad = 1.0; 25 | }; 26 | ETF(int i, int j) 27 | { 28 | Nr = i, Nc = j; 29 | p = new Vect*[Nr]; 30 | for(i = 0; i < Nr; i++) 31 | p[i] = new Vect[Nc]; 32 | max_grad = 1.0; 33 | }; 34 | void delete_all() { 35 | for (int i = 0; i < Nr; i++) 36 | delete[] p[i]; 37 | delete[] p; 38 | } 39 | ~ETF() { delete_all(); } 40 | Vect* operator[](int i) { return p[i]; }; 41 | Vect& get( int i, int j ) const { return p[i][j]; } 42 | int getRow() const { return Nr; } 43 | int getCol() const { return Nc; } 44 | void init(int i, int j) 45 | { 46 | delete_all(); 47 | Nr = i, Nc = j; 48 | p = new Vect*[Nr]; 49 | for(i = 0; i < Nr; i++) 50 | p[i] = new Vect[Nc]; 51 | max_grad = 1.0; 52 | }; 53 | void copy(ETF& s) 54 | { 55 | for (int i = 0; i < Nr; i++) 56 | for (int j = 0; j < Nc; j++) { 57 | p[i][j].tx = s.p[i][j].tx; 58 | p[i][j].ty = s.p[i][j].ty; 59 | p[i][j].mag = s.p[i][j].mag; 60 | } 61 | max_grad = s.max_grad; 62 | }; 63 | void zero() 64 | { 65 | for (int i = 0; i < Nr; i++) 66 | for (int j = 0; j < Nc; j++) 67 | p[i][j].tx = p[i][j].ty = p[i][j].mag = 0.0; 68 | } 69 | void set(imatrix& image); 70 | void set2(imatrix& image); 71 | void Smooth(int half_w, int M); 72 | double GetMaxGrad() { return max_grad; } 73 | void normalize(); 74 | }; 75 | 76 | 77 | #endif -------------------------------------------------------------------------------- /libs/CLD/include/CLD/fdog.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _FDOG_H_ 3 | #define _FDOG_H_ 4 | 5 | extern void GaussSmoothSep(imatrix& image, double sigma); 6 | extern void ConstructMergedImage(imatrix& image, imatrix& gray, imatrix& merged); 7 | extern void ConstructMergedImageMult(imatrix& image, imatrix& gray, imatrix& merged); 8 | extern void GetFDoG(imatrix& image, ETF& e, double sigma, double sigma3, double tau); 9 | extern void Binarize(imatrix& image, double thres); 10 | extern void GrayThresholding(imatrix& image, double thres); 11 | 12 | #endif -------------------------------------------------------------------------------- /libs/CLD/include/CLD/imatrix.h: -------------------------------------------------------------------------------- 1 | #ifndef _IMATRIX_H_ 2 | #define _IMATRIX_H_ 3 | 4 | class imatrix { 5 | private: 6 | int Nr, Nc; 7 | int** p; 8 | void delete_all() { 9 | for (int i = 0; i < Nr; i++) 10 | delete[] p[i]; 11 | delete[] p; 12 | } 13 | public: 14 | imatrix() 15 | { 16 | Nr = 1, Nc = 1; 17 | p = new int*[Nr]; 18 | for(int i = 0; i < Nr; i++) 19 | p[i] = new int[Nc]; 20 | p[0][0]=1; 21 | }; 22 | imatrix(int i, int j) 23 | { 24 | Nr = i, Nc = j; 25 | 26 | p = new int*[Nr]; 27 | for(i = 0; i < Nr; i++) 28 | p[i] = new int[Nc]; 29 | }; 30 | imatrix(imatrix& b) { 31 | Nr = b.Nr; 32 | Nc = b.Nc; 33 | p = new int*[Nr]; 34 | for (int i = 0; i < Nr; i++) { 35 | p[i] = new int[Nc]; 36 | for (int j = 0; j < Nc; j++) { 37 | p[i][j] = b[i][j]; 38 | } 39 | } 40 | } 41 | void init(int i, int j) 42 | { 43 | delete_all(); 44 | Nr = i, Nc = j; 45 | p = new int*[Nr]; 46 | for(i = 0; i < Nr; i++) 47 | p[i] = new int[Nc]; 48 | }; 49 | 50 | ~imatrix() 51 | { 52 | delete_all(); 53 | } 54 | int* operator[](int i) { return p[i]; }; 55 | 56 | int& get( int i, int j ) const { return p[i][j]; } 57 | int getRow() const { return Nr; } 58 | int getCol() const { return Nc; } 59 | 60 | void zero() 61 | { 62 | for (int i = 0; i < Nr; i++) 63 | for (int j = 0; j < Nc; j++) 64 | p[i][j] = 0; 65 | } 66 | void copy(imatrix& b) 67 | { 68 | init(b.Nr, b.Nc); 69 | for (int i = 0; i < Nr; i++) 70 | for (int j = 0; j < Nc; j++) 71 | p[i][j] = b.p[i][j]; 72 | } 73 | }; 74 | 75 | 76 | #endif -------------------------------------------------------------------------------- /libs/CLD/include/CLD/myvec.h: -------------------------------------------------------------------------------- 1 | #ifndef _MYVEC_H_ 2 | #define _MYVEC_H_ 3 | 4 | #include 5 | 6 | class myvec { 7 | private: 8 | 9 | public: 10 | int N; 11 | double* p; 12 | myvec() 13 | { 14 | N = 1; 15 | p = new double[1]; 16 | p[0]=1.0; 17 | }; 18 | myvec(int i) 19 | { 20 | N = i; 21 | p = new double[N]; 22 | }; 23 | ~myvec() 24 | { 25 | delete[] p; 26 | } 27 | double& operator[](int i) { return p[i]; } 28 | const double& operator[](int i) const { return p[i]; } 29 | void zero() { 30 | for (int i = 0; i < N; i++) 31 | p[i] = 0.0; 32 | } 33 | void make_unit() { 34 | double sum = 0.0; 35 | for (int i = 0; i < N; i++) { 36 | sum += p[i]*p[i]; 37 | } 38 | sum = sqrt(sum); 39 | if (sum > 0.0) { 40 | for (int i = 0; i < N; i++) { 41 | p[i] = p[i] / sum; 42 | } 43 | } 44 | } 45 | double norm() { 46 | double sum = 0.0; 47 | for (int i = 0; i < N; i++) { 48 | sum += p[i]*p[i]; 49 | } 50 | sum = sqrt(sum); 51 | return sum; 52 | } 53 | double get(int n) const { return p[n]; } 54 | int getMax() { return N; } 55 | void init(int i) { 56 | delete[] p; 57 | N = i; 58 | p = new double[N]; 59 | } 60 | }; 61 | 62 | class mymatrix { 63 | private: 64 | int Nr, Nc; 65 | double** p; 66 | void delete_all() { 67 | for (int i = 0; i < Nr; i++) 68 | delete[] p[i]; 69 | delete[] p; 70 | } 71 | public: 72 | mymatrix() 73 | { 74 | Nr = 1, Nc = 1; 75 | p = new double*[Nr]; 76 | for(int i = 0; i < Nr; i++) 77 | p[i] = new double[Nc]; 78 | p[0][0]=1.0; 79 | }; 80 | mymatrix(int i, int j) 81 | { 82 | Nr = i, Nc = j; 83 | p = new double*[Nr]; 84 | for(i = 0; i < Nr; i++) 85 | p[i] = new double[Nc]; 86 | }; 87 | mymatrix(mymatrix& b) { 88 | Nr = b.Nr; 89 | Nc = b.Nc; 90 | p = new double*[Nr]; 91 | for (int i = 0; i < Nr; i++) { 92 | p[i] = new double[Nc]; 93 | for (int j = 0; j < Nc; j++) { 94 | p[i][j] = b[i][j]; 95 | } 96 | } 97 | } 98 | ~mymatrix() { 99 | delete_all(); 100 | } 101 | double* operator[](int i) { return p[i]; }; 102 | double& get( int i, int j ) const { return p[i][j]; } 103 | int getRow() const { return Nr; } 104 | int getCol() const { return Nc; } 105 | void init(int i, int j) 106 | { 107 | delete_all(); 108 | Nr = i, Nc = j; 109 | p = new double*[Nr]; 110 | for(i = 0; i < Nr; i++) 111 | p[i] = new double[Nc]; 112 | }; 113 | void zero() 114 | { 115 | for (int i = 0; i < Nr; i++) 116 | for (int j = 0; j < Nc; j++) 117 | p[i][j] = 0.0; 118 | } 119 | }; 120 | 121 | 122 | #endif -------------------------------------------------------------------------------- /libs/CLD/src/ETF.cpp: -------------------------------------------------------------------------------- 1 | #include "ETF.h" 2 | #include "imatrix.h" 3 | 4 | #include "ofMain.h" 5 | 6 | void ETF::set(imatrix& image) 7 | { 8 | int i, j; 9 | double MAX_VAL = 1020.; 10 | double v[2]; 11 | 12 | max_grad = -1.; 13 | 14 | for (i = 1; i < Nr - 1; i++) { 15 | for (j = 1; j < Nc - 1; j++) { 16 | //////////////////////////////////////////////////////////////// 17 | p[i][j].tx = (image[i+1][j-1] + 2*(double)image[i+1][j] + image[i+1][j+1] 18 | - image[i-1][j-1] - 2*(double)image[i-1][j] - image[i-1][j+1]) / MAX_VAL; 19 | p[i][j].ty = (image[i-1][j+1] + 2*(double)image[i][j+1] + image[i+1][j+1] 20 | - image[i-1][j-1] - 2*(double)image[i][j-1] - image[i+1][j-1]) / MAX_VAL; 21 | ///////////////////////////////////////////// 22 | v[0] = p[i][j].tx; 23 | v[1] = p[i][j].ty; 24 | p[i][j].tx = -v[1]; 25 | p[i][j].ty = v[0]; 26 | ////////////////////////////////////////////// 27 | p[i][j].mag = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 28 | 29 | if (p[i][j].mag > max_grad) { 30 | max_grad = p[i][j].mag; 31 | } 32 | } 33 | } 34 | 35 | for (i = 1; i <= Nr - 2; i++) { 36 | p[i][0].tx = p[i][1].tx; 37 | p[i][0].ty = p[i][1].ty; 38 | p[i][0].mag = p[i][1].mag; 39 | p[i][Nc - 1].tx = p[i][Nc - 2].tx; 40 | p[i][Nc - 1].ty = p[i][Nc - 2].ty; 41 | p[i][Nc - 1].mag = p[i][Nc - 2].mag; 42 | } 43 | 44 | for (j = 1; j <= Nc - 2; j++) { 45 | p[0][j].tx = p[1][j].tx; 46 | p[0][j].ty = p[1][j].ty; 47 | p[0][j].mag = p[1][j].mag; 48 | p[Nr - 1][j].tx = p[Nr - 2][j].tx; 49 | p[Nr - 1][j].ty = p[Nr - 2][j].ty; 50 | p[Nr - 1][j].mag = p[Nr - 2][j].mag; 51 | } 52 | 53 | p[0][0].tx = ( p[0][1].tx + p[1][0].tx ) / 2; 54 | p[0][0].ty = ( p[0][1].ty + p[1][0].ty ) / 2; 55 | p[0][0].mag = ( p[0][1].mag + p[1][0].mag ) / 2; 56 | p[0][Nc-1].tx = ( p[0][Nc-2].tx + p[1][Nc-1].tx ) / 2; 57 | p[0][Nc-1].ty = ( p[0][Nc-2].ty + p[1][Nc-1].ty ) / 2; 58 | p[0][Nc-1].mag = ( p[0][Nc-2].mag + p[1][Nc-1].mag ) / 2; 59 | p[Nr-1][0].tx = ( p[Nr-1][1].tx + p[Nr-2][0].tx ) / 2; 60 | p[Nr-1][0].ty = ( p[Nr-1][1].ty + p[Nr-2][0].ty ) / 2; 61 | p[Nr-1][0].mag = ( p[Nr-1][1].mag + p[Nr-2][0].mag ) / 2; 62 | p[Nr - 1][Nc - 1].tx = ( p[Nr - 1][Nc - 2].tx + p[Nr - 2][Nc - 1].tx ) / 2; 63 | p[Nr - 1][Nc - 1].ty = ( p[Nr - 1][Nc - 2].ty + p[Nr - 2][Nc - 1].ty ) / 2; 64 | p[Nr - 1][Nc - 1].mag = ( p[Nr - 1][Nc - 2].mag + p[Nr - 2][Nc - 1].mag ) / 2; 65 | 66 | normalize(); 67 | 68 | } 69 | 70 | void ETF::set2(imatrix& image) 71 | { 72 | int i, j; 73 | double MAX_VAL = 1020.; 74 | double v[2]; 75 | 76 | max_grad = -1.; 77 | 78 | imatrix tmp(Nr, Nc); 79 | 80 | for (i = 1; i < Nr - 1; i++) { 81 | for (j = 1; j < Nc - 1; j++) { 82 | //////////////////////////////////////////////////////////////// 83 | p[i][j].tx = (image[i+1][j-1] + 2*(double)image[i+1][j] + image[i+1][j+1] 84 | - image[i-1][j-1] - 2*(double)image[i-1][j] - image[i-1][j+1]) / MAX_VAL; 85 | p[i][j].ty = (image[i-1][j+1] + 2*(double)image[i][j+1] + image[i+1][j+1] 86 | - image[i-1][j-1] - 2*(double)image[i][j-1] - image[i+1][j-1]) / MAX_VAL; 87 | ///////////////////////////////////////////// 88 | v[0] = p[i][j].tx; 89 | v[1] = p[i][j].ty; 90 | ////////////////////////////////////////////// 91 | tmp[i][j] = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 92 | 93 | if (tmp[i][j] > max_grad) { 94 | max_grad = tmp[i][j]; 95 | } 96 | } 97 | } 98 | 99 | for (i = 1; i <= Nr - 2; i++) { 100 | tmp[i][0] = tmp[i][1]; 101 | tmp[i][Nc - 1] = tmp[i][Nc - 2]; 102 | } 103 | 104 | for (j = 1; j <= Nc - 2; j++) { 105 | tmp[0][j] = tmp[1][j]; 106 | tmp[Nr - 1][j] = tmp[Nr - 2][j]; 107 | } 108 | 109 | tmp[0][0] = ( tmp[0][1] + tmp[1][0] ) / 2; 110 | tmp[0][Nc-1] = ( tmp[0][Nc-2] + tmp[1][Nc-1] ) / 2; 111 | tmp[Nr-1][0] = ( tmp[Nr-1][1] + tmp[Nr-2][0] ) / 2; 112 | tmp[Nr - 1][Nc - 1] = ( tmp[Nr - 1][Nc - 2] + tmp[Nr - 2][Nc - 1] ) / 2; 113 | 114 | imatrix gmag(Nr, Nc); 115 | 116 | // normalize the magnitude 117 | for (i = 0; i < Nr; i++) { 118 | for (j = 0; j < Nc; j++) { 119 | tmp[i][j] /= max_grad; 120 | gmag[i][j] = (int) (tmp[i][j] * 255.0); 121 | } 122 | } 123 | 124 | for (i = 1; i < Nr - 1; i++) { 125 | for (j = 1; j < Nc - 1; j++) { 126 | //////////////////////////////////////////////////////////////// 127 | p[i][j].tx = (gmag[i+1][j-1] + 2*(double)gmag[i+1][j] + gmag[i+1][j+1] 128 | - gmag[i-1][j-1] - 2*(double)gmag[i-1][j] - gmag[i-1][j+1]) / MAX_VAL; 129 | p[i][j].ty = (gmag[i-1][j+1] + 2*(double)gmag[i][j+1] + gmag[i+1][j+1] 130 | - gmag[i-1][j-1] - 2*(double)gmag[i][j-1] - gmag[i+1][j-1]) / MAX_VAL; 131 | ///////////////////////////////////////////// 132 | v[0] = p[i][j].tx; 133 | v[1] = p[i][j].ty; 134 | p[i][j].tx = -v[1]; 135 | p[i][j].ty = v[0]; 136 | ////////////////////////////////////////////// 137 | p[i][j].mag = sqrt(p[i][j].tx * p[i][j].tx + p[i][j].ty * p[i][j].ty); 138 | 139 | if (p[i][j].mag > max_grad) { 140 | max_grad = p[i][j].mag; 141 | } 142 | } 143 | } 144 | 145 | for (i = 1; i <= Nr - 2; i++) { 146 | p[i][0].tx = p[i][1].tx; 147 | p[i][0].ty = p[i][1].ty; 148 | p[i][0].mag = p[i][1].mag; 149 | p[i][Nc - 1].tx = p[i][Nc - 2].tx; 150 | p[i][Nc - 1].ty = p[i][Nc - 2].ty; 151 | p[i][Nc - 1].mag = p[i][Nc - 2].mag; 152 | } 153 | 154 | for (j = 1; j <= Nc - 2; j++) { 155 | p[0][j].tx = p[1][j].tx; 156 | p[0][j].ty = p[1][j].ty; 157 | p[0][j].mag = p[1][j].mag; 158 | p[Nr - 1][j].tx = p[Nr - 2][j].tx; 159 | p[Nr - 1][j].ty = p[Nr - 2][j].ty; 160 | p[Nr - 1][j].mag = p[Nr - 2][j].mag; 161 | } 162 | 163 | p[0][0].tx = ( p[0][1].tx + p[1][0].tx ) / 2; 164 | p[0][0].ty = ( p[0][1].ty + p[1][0].ty ) / 2; 165 | p[0][0].mag = ( p[0][1].mag + p[1][0].mag ) / 2; 166 | p[0][Nc-1].tx = ( p[0][Nc-2].tx + p[1][Nc-1].tx ) / 2; 167 | p[0][Nc-1].ty = ( p[0][Nc-2].ty + p[1][Nc-1].ty ) / 2; 168 | p[0][Nc-1].mag = ( p[0][Nc-2].mag + p[1][Nc-1].mag ) / 2; 169 | p[Nr-1][0].tx = ( p[Nr-1][1].tx + p[Nr-2][0].tx ) / 2; 170 | p[Nr-1][0].ty = ( p[Nr-1][1].ty + p[Nr-2][0].ty ) / 2; 171 | p[Nr-1][0].mag = ( p[Nr-1][1].mag + p[Nr-2][0].mag ) / 2; 172 | p[Nr - 1][Nc - 1].tx = ( p[Nr - 1][Nc - 2].tx + p[Nr - 2][Nc - 1].tx ) / 2; 173 | p[Nr - 1][Nc - 1].ty = ( p[Nr - 1][Nc - 2].ty + p[Nr - 2][Nc - 1].ty ) / 2; 174 | p[Nr - 1][Nc - 1].mag = ( p[Nr - 1][Nc - 2].mag + p[Nr - 2][Nc - 1].mag ) / 2; 175 | 176 | normalize(); 177 | } 178 | 179 | 180 | inline void make_unit(double& vx, double& vy) 181 | { 182 | double mag = sqrt( vx*vx + vy*vy ); 183 | if (mag != 0.0) { 184 | vx /= mag; 185 | vy /= mag; 186 | } 187 | } 188 | 189 | void ETF::normalize() 190 | { 191 | int i, j; 192 | 193 | for (i = 0; i < Nr; i++) { 194 | for (j = 0; j < Nc; j++) { 195 | make_unit(p[i][j].tx, p[i][j].ty); 196 | p[i][j].mag /= max_grad; 197 | } 198 | } 199 | } 200 | 201 | 202 | void ETF::Smooth(int half_w, int M) 203 | { 204 | int i, j, k; 205 | int MAX_GRADIENT = -1; 206 | double weight; 207 | int s, t; 208 | int x, y; 209 | double mag_diff; 210 | 211 | int image_x = getRow(); 212 | int image_y = getCol(); 213 | 214 | ETF e2; 215 | 216 | e2.init(image_x, image_y); 217 | e2.copy(*this); 218 | 219 | double v[2], w[2], g[2]; 220 | double angle; 221 | double factor; 222 | 223 | for (k = 0; k < M; k++) { 224 | //////////////////////// 225 | // horizontal 226 | for (j = 0; j < image_y; j++) { 227 | for (i = 0; i < image_x; i++) { 228 | g[0] = g[1] = 0.0; 229 | v[0] = p[i][j].tx; 230 | v[1] = p[i][j].ty; 231 | for (s = -half_w; s <= half_w; s++) { 232 | //////////////////////////////////////// 233 | x = i+s; y = j; 234 | if (x > image_x-1) x = image_x-1; 235 | else if (x < 0) x = 0; 236 | if (y > image_y-1) y = image_y-1; 237 | else if (y < 0) y = 0; 238 | //////////////////////////////////////// 239 | mag_diff = p[x][y].mag - p[i][j].mag; 240 | ////////////////////////////////////////////////////// 241 | w[0] = p[x][y].tx; 242 | w[1] = p[x][y].ty; 243 | //////////////////////////////// 244 | factor = 1.0; 245 | angle = v[0] * w[0] + v[1] * w[1]; 246 | if (angle < 0.0) { 247 | factor = -1.0; 248 | } 249 | weight = mag_diff + 1; 250 | ////////////////////////////////////////////////////// 251 | g[0] += weight * p[x][y].tx * factor; 252 | g[1] += weight * p[x][y].ty * factor; 253 | } 254 | make_unit(g[0], g[1]); 255 | e2[i][j].tx = g[0]; 256 | e2[i][j].ty = g[1]; 257 | } 258 | } 259 | this->copy(e2); 260 | ///////////////////////////////// 261 | // vertical 262 | for (j = 0; j < image_y; j++) { 263 | for (i = 0; i < image_x; i++) { 264 | g[0] = g[1] = 0.0; 265 | v[0] = p[i][j].tx; 266 | v[1] = p[i][j].ty; 267 | for (t = -half_w; t <= half_w; t++) { 268 | //////////////////////////////////////// 269 | x = i; y = j+t; 270 | if (x > image_x-1) x = image_x-1; 271 | else if (x < 0) x = 0; 272 | if (y > image_y-1) y = image_y-1; 273 | else if (y < 0) y = 0; 274 | //////////////////////////////////////// 275 | mag_diff = p[x][y].mag - p[i][j].mag; 276 | ////////////////////////////////////////////////////// 277 | w[0] = p[x][y].tx; 278 | w[1] = p[x][y].ty; 279 | //////////////////////////////// 280 | factor = 1.0; 281 | /////////////////////////////// 282 | angle = v[0] * w[0] + v[1] * w[1]; 283 | if (angle < 0.0) factor = -1.0; 284 | ///////////////////////////////////////////////////////// 285 | weight = mag_diff + 1; 286 | ////////////////////////////////////////////////////// 287 | g[0] += weight * p[x][y].tx * factor; 288 | g[1] += weight * p[x][y].ty * factor; 289 | } 290 | make_unit(g[0], g[1]); 291 | e2[i][j].tx = g[0]; 292 | e2[i][j].ty = g[1]; 293 | } 294 | } 295 | this->copy(e2); 296 | } 297 | //////////////////////////////////////////// 298 | } 299 | -------------------------------------------------------------------------------- /libs/ofxCv/addons.make: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/libs/ofxCv/addons.make -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/Calibration.h: -------------------------------------------------------------------------------- 1 | /* 2 | this class handles per-camera intrinsic calibration and undistortion. 3 | given a series of chessboard images, it will calculate the intrinsics. 4 | to use it: 5 | 6 | 0 either load() from a yml file (skip to 5), 7 | or do the calibration as follows 8 | 1 set the board and physical square size of the chess board. whatever 9 | if your squares are in mm, your focal length will also be in mm. 10 | 2 add() each image containing a chess board 11 | 3 when all the images are added, call calibrate() 12 | 4 now you can save() a yml calibration file 13 | 5 now you can undistort() incoming images. 14 | 15 | to do inter-camera (extrinsics) calibration, you need to first calibrate 16 | each camera individually. then use getTransformation to determine the 17 | rotation and translation from camera to another. 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "ofxCv.h" 23 | #include "ofNode.h" 24 | 25 | namespace ofxCv { 26 | class Intrinsics { 27 | public: 28 | void setup(float focalLengthMm, cv::Size imageSizePx, cv::Size2f sensorSizeMm, cv::Point2d principalPointPct = cv::Point2d(.5,.5)); 29 | void setup(cv::Mat cameraMatrix, cv::Size imageSizePx, cv::Size2f sensorSizeMm = cv::Size2f(0, 0)); 30 | void setImageSize(cv::Size imgSize); 31 | cv::Mat getCameraMatrix() const; 32 | cv::Size getImageSize() const; 33 | cv::Size2f getSensorSize() const; 34 | cv::Point2d getFov() const; 35 | double getFocalLength() const; 36 | double getAspectRatio() const; 37 | cv::Point2d getPrincipalPoint() const; 38 | void loadProjectionMatrix(float nearDist = 10., float farDist = 10000., cv::Point2d viewportOffset = cv::Point2d(0, 0)) const; 39 | protected: 40 | void updateValues(); 41 | cv::Mat cameraMatrix; 42 | cv::Size imageSize; 43 | cv::Size2f sensorSize; 44 | cv::Point2d fov; 45 | double focalLength, aspectRatio; 46 | cv::Point2d principalPoint; 47 | }; 48 | 49 | enum CalibrationPattern {CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID}; 50 | 51 | class Calibration : public ofNode { 52 | public: 53 | Calibration(); 54 | 55 | void save(const std::string& filename, bool absolute = false) const; 56 | void load(const std::string& filename, bool absolute = false); 57 | void loadLcp(const std::string& filename, float focalLength, int imageWidth=0, int imageHeight=0, bool absolutePath = false); 58 | void reset(); 59 | 60 | void setPatternType(CalibrationPattern patternType); 61 | void setPatternSize(int xCount, int yCount); 62 | void setSquareSize(float squareSize); 63 | /// set this to the pixel size of your smallest square. default is 11 64 | void setSubpixelSize(int subpixelSize); 65 | 66 | bool add(cv::Mat img); 67 | bool clean(float minReprojectionError = 2.f); 68 | bool calibrate(); 69 | bool calibrateFromDirectory(std::string directory); 70 | bool findBoard(cv::Mat img, std::vector &pointBuf, bool refine = true); 71 | void setIntrinsics(Intrinsics& distortedIntrinsics); 72 | void setDistortionCoefficients(float k1, float k2, float p1, float p2, float k3=0, float k4=0, float k5=0, float k6=0); 73 | 74 | void undistort(cv::Mat img, int interpolationMode = cv::INTER_LINEAR); 75 | void undistort(cv::Mat src, cv::Mat dst, int interpolationMode = cv::INTER_LINEAR); 76 | 77 | glm::vec2 undistort(glm::vec2& src) const; 78 | void undistort(std::vector& src, std::vector& dst) const; 79 | 80 | bool getTransformation(Calibration& dst, cv::Mat& rotation, cv::Mat& translation); 81 | 82 | float getReprojectionError() const; 83 | float getReprojectionError(int i) const; 84 | 85 | const Intrinsics& getDistortedIntrinsics() const; 86 | const Intrinsics& getUndistortedIntrinsics() const; 87 | cv::Mat getDistCoeffs() const; 88 | 89 | // if you want a wider fov, say setFillFrame(false) before load() or calibrate() 90 | void setFillFrame(bool fillFrame); 91 | 92 | std::size_t size() const; 93 | cv::Size getPatternSize() const; 94 | float getSquareSize() const; 95 | static std::vector createObjectPoints(cv::Size patternSize, float squareSize, CalibrationPattern patternType); 96 | 97 | void customDraw(); 98 | void draw(std::size_t i) const; 99 | void draw() const; 100 | void draw3d() const; 101 | void draw3d(std::size_t i) const; 102 | 103 | bool isReady(); 104 | std::vector > imagePoints; 105 | 106 | protected: 107 | CalibrationPattern patternType; 108 | cv::Size patternSize, addedImageSize, subpixelSize; 109 | float squareSize; 110 | cv::Mat grayMat; 111 | 112 | cv::Mat distCoeffs; 113 | 114 | std::vector boardRotations, boardTranslations; 115 | std::vector > objectPoints; 116 | 117 | float reprojectionError; 118 | std::vector perViewErrors; 119 | 120 | bool fillFrame; 121 | cv::Mat undistortBuffer; 122 | cv::Mat undistortMapX, undistortMapY; 123 | 124 | void updateObjectPoints(); 125 | void updateReprojectionError(); 126 | void updateUndistortion(); 127 | 128 | Intrinsics distortedIntrinsics; 129 | Intrinsics undistortedIntrinsics; 130 | 131 | bool ready; 132 | }; 133 | 134 | } 135 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/ContourFinder.h: -------------------------------------------------------------------------------- 1 | /* 2 | the contour finder will automatically convert and threshold your image for you. 3 | by default, it finds bright regions. to find dark regions call setInvert(true). 4 | to track a color, call setTargetColor(). by default, it tracks in RGB space. 5 | to track in HSV or just hue space, pass TRACK_COLOR_HSV or TRACK_COLOR_H. 6 | to change the threshold value, use setThreshold(). by default, the threshold is 7 | 128. when finding bright regions, 128 is halfway between white and black. when 8 | tracking a color, 0 means "exactly similar" and 255 is "all colors". 9 | 10 | by default, the results are unfiltered by area. to filter by area use one of 11 | set(Min/Max)(Area/Radius/Norm) functions. set(Min/Max)Area is in pixels. 12 | set(Min/Max)Radius uses the area of a circle with the given radius for a more 13 | "linear" feeling. set(Min/Max)Norm uses values between (0-1) and multiplies 14 | by the input image area. to reset the min/max area call reset(Min/Max)Area. 15 | 16 | keeping with the ofxCv philosophy, no new objects (like ofxCvBlob) are used. 17 | you can get contours as std::vector or ofPolyline. for other features, 18 | you can use methods of ofPolyline (getArea(), getPerimiter()) or cv methods 19 | by asking ContourFinder (getContourArea(), getArcLength()). 20 | */ 21 | 22 | // to implement in ContourFinder: 23 | // holes/no holes 24 | // CV_THRESH_OTSU? 25 | // cv::matchShapes - similarity between two contours 26 | // cv::estimateRigidTransform? subdivision-based estimation for outline-flow? 27 | 28 | #pragma once 29 | 30 | #include "ofxCv/Utilities.h" 31 | #include "ofxCv/Tracker.h" 32 | 33 | namespace ofxCv { 34 | 35 | enum TrackingColorMode {TRACK_COLOR_RGB, TRACK_COLOR_HSV, TRACK_COLOR_H, TRACK_COLOR_HS}; 36 | 37 | class ContourFinder { 38 | public: 39 | ContourFinder(); 40 | 41 | template 42 | void findContours(T& img) { 43 | findContours(toCv(img)); 44 | } 45 | void findContours(cv::Mat img); 46 | const std::vector >& getContours() const; 47 | const std::vector& getPolylines() const; 48 | const std::vector& getBoundingRects() const; 49 | 50 | unsigned int size() const; 51 | std::vector& getContour(unsigned int i); 52 | ofPolyline& getPolyline(unsigned int i); 53 | 54 | cv::Rect getBoundingRect(unsigned int i) const; 55 | cv::Point2f getCenter(unsigned int i) const; // center of bounding box (most stable) 56 | cv::Point2f getCentroid(unsigned int i) const; // center of mass (less stable) 57 | cv::Point2f getAverage(unsigned int i) const; // average of contour vertices (least stable) 58 | cv::Vec2f getBalance(unsigned int i) const; // difference between centroid and center 59 | double getContourArea(unsigned int i) const; 60 | double getArcLength(unsigned int i) const; 61 | std::vector getConvexHull(unsigned int i) const; 62 | std::vector getConvexityDefects(unsigned int i) const; 63 | cv::RotatedRect getMinAreaRect(unsigned int i) const; 64 | cv::Point2f getMinEnclosingCircle(unsigned int i, float& radius) const; 65 | cv::RotatedRect getFitEllipse(unsigned int i) const; 66 | std::vector getFitQuad(unsigned int i) const; 67 | bool getHole(unsigned int i) const; 68 | cv::Vec2f getVelocity(unsigned int i) const; 69 | 70 | RectTracker& getTracker(); 71 | unsigned int getLabel(unsigned int i) const; 72 | 73 | // Performs a point-in-contour test. 74 | // The function determines whether the point is inside a contour, outside, or lies on an edge (or coincides with a vertex) 75 | // The return value is the signed distance (positive stands for inside). 76 | double pointPolygonTest(unsigned int i, cv::Point2f point); 77 | 78 | void setThreshold(float thresholdValue); 79 | void setAutoThreshold(bool autoThreshold); 80 | void setInvert(bool invert); 81 | void setUseTargetColor(bool useTargetColor); 82 | void setTargetColor(ofColor targetColor, TrackingColorMode trackingColorMode = TRACK_COLOR_RGB); 83 | void setFindHoles(bool findHoles); 84 | void setSortBySize(bool sortBySize); 85 | 86 | void resetMinArea(); 87 | void resetMaxArea(); 88 | void setMinArea(float minArea); 89 | void setMaxArea(float maxArea); 90 | void setMinAreaRadius(float minAreaRadius); 91 | void setMaxAreaRadius(float maxAreaRadius); 92 | void setMinAreaNorm(float minAreaNorm); 93 | void setMaxAreaNorm(float maxAreaNorm); 94 | 95 | void setSimplify(bool simplify); 96 | 97 | void draw() const; 98 | 99 | protected: 100 | cv::Mat hsvBuffer, thresh; 101 | bool autoThreshold, invert, simplify; 102 | float thresholdValue; 103 | 104 | bool useTargetColor; 105 | TrackingColorMode trackingColorMode; 106 | ofColor targetColor; 107 | 108 | float minArea, maxArea; 109 | bool minAreaNorm, maxAreaNorm; 110 | 111 | std::vector > contours; 112 | std::vector polylines; 113 | 114 | RectTracker tracker; 115 | std::vector boundingRects; 116 | std::vector holes; 117 | 118 | int contourFindingMode; 119 | bool sortBySize; 120 | }; 121 | 122 | } 123 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/Distance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ofxCv { 8 | 9 | // edit distance is the number of transformations required to turn one string into another 10 | int editDistance(const std::string& a, const std::string& b); 11 | 12 | // cross correlation using edit distance gives the most representative string from a set 13 | const std::string& mostRepresentative(const std::vector& strs); 14 | } 15 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/Flow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofxCv.h" 4 | 5 | namespace ofxCv { 6 | 7 | class Flow { 8 | public: 9 | // should constructor be protected? 10 | Flow(); 11 | virtual ~Flow(); 12 | 13 | //call these functions to calculate flow on sequential images. 14 | //After this call the flow field will be populated and 15 | //subsequent calls to getFlow() will be updated 16 | 17 | //call with two contiguous images 18 | template 19 | void calcOpticalFlow(const T& lastImage, const T& currentImage) { 20 | calcOpticalFlow(toCv(lastImage), toCv(currentImage)); 21 | } 22 | void calcOpticalFlow(cv::Mat lastImage, cv::Mat currentImage); 23 | 24 | //call with subsequent images to do running optical flow. 25 | //the Flow class internally stores the last image for convenience 26 | template 27 | void calcOpticalFlow(const T& currentImage) { 28 | calcOpticalFlow(toCv(currentImage)); 29 | } 30 | void calcOpticalFlow(cv::Mat nextImage); 31 | 32 | void draw(); 33 | void draw(float x, float y); 34 | void draw(float x, float y, float width, float height); 35 | void draw(ofRectangle rect); 36 | int getWidth(); 37 | int getHeight(); 38 | 39 | virtual void resetFlow(); 40 | 41 | private: 42 | cv::Mat last, curr; 43 | 44 | protected: 45 | bool hasFlow; 46 | 47 | //specific flow implementation 48 | virtual void calcFlow(cv::Mat prev, cv::Mat next) = 0; 49 | //specific drawing implementation 50 | virtual void drawFlow(ofRectangle r) = 0; 51 | }; 52 | 53 | //there are two implementations of Flow 54 | //use Farneback for a dense flow field, 55 | //use PyrLK for specific features 56 | 57 | //see http://opencv.willowgarage.com/documentation/cpp/motion_analysis_and_object_tracking.html 58 | //for more info on the meaning of these parameters 59 | 60 | class FlowPyrLK : public Flow { 61 | public: 62 | FlowPyrLK(); 63 | virtual ~FlowPyrLK(); 64 | 65 | //flow parameters 66 | void setMinDistance(int minDistance); 67 | void setWindowSize(int winsize); 68 | 69 | //feature finding parameters 70 | void setMaxLevel(int maxLevel); 71 | void setMaxFeatures(int maxFeatures); 72 | void setQualityLevel(float qualityLevel); 73 | void setPyramidLevels(int levels); 74 | 75 | //returns tracking features for this image 76 | std::vector getFeatures(); 77 | std::vector getCurrent(); 78 | std::vector getMotion(); 79 | 80 | // recalculates features to track 81 | void resetFeaturesToTrack(); 82 | void setFeaturesToTrack(const std::vector & features); 83 | void setFeaturesToTrack(const std::vector & features); 84 | void resetFlow(); 85 | protected: 86 | 87 | void drawFlow(ofRectangle r); 88 | void calcFlow(cv::Mat prev, cv::Mat next); 89 | void calcFeaturesToTrack(std::vector & features, cv::Mat next); 90 | 91 | std::vector prevPts, nextPts; 92 | 93 | //LK feature finding parameters 94 | int windowSize; 95 | int maxLevel; 96 | int maxFeatures; 97 | float qualityLevel; 98 | 99 | //min distance for PyrLK 100 | int minDistance; 101 | 102 | //pyramid levels 103 | int pyramidLevels; 104 | 105 | bool calcFeaturesNextFrame; 106 | 107 | //pyramid + err/status data 108 | std::vector pyramid; 109 | std::vector prevPyramid; 110 | std::vector status; 111 | std::vector err; 112 | }; 113 | 114 | class FlowFarneback : public Flow { 115 | public: 116 | 117 | FlowFarneback(); 118 | virtual ~FlowFarneback(); 119 | 120 | //see http://opencv.willowgarage.com/documentation/cpp/motion_analysis_and_object_tracking.html 121 | //for a description of these parameters 122 | 123 | void setPyramidScale(float scale); 124 | void setNumLevels(int levels); 125 | void setWindowSize(int winsize); 126 | void setNumIterations(int interations); 127 | void setPolyN(int polyN); 128 | void setPolySigma(float polySigma); 129 | void setUseGaussian(bool gaussian); 130 | 131 | cv::Mat& getFlow(); 132 | glm::vec2 getTotalFlow(); 133 | glm::vec2 getAverageFlow(); 134 | glm::vec2 getFlowOffset(int x, int y); 135 | glm::vec2 getFlowPosition(int x, int y); 136 | glm::vec2 getTotalFlowInRegion(ofRectangle region); 137 | glm::vec2 getAverageFlowInRegion(ofRectangle region); 138 | 139 | //call this if you switch to a new video file to reset internal caches 140 | void resetFlow(); 141 | 142 | protected: 143 | cv::Mat flow; 144 | 145 | void drawFlow(ofRectangle rect); 146 | void calcFlow(cv::Mat prev, cv::Mat next); 147 | 148 | float pyramidScale; 149 | int numLevels; 150 | int windowSize; 151 | int numIterations; 152 | int polyN; 153 | float polySigma; 154 | bool farnebackGaussian; 155 | }; 156 | 157 | } 158 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/Kalman.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ofxCv.h" 4 | #include "ofVectorMath.h" 5 | 6 | namespace ofxCv { 7 | 8 | // Kalman filter for positioning 9 | template 10 | class KalmanPosition_ { 11 | cv::KalmanFilter KF; 12 | cv::Mat_ measurement, prediction, estimated; 13 | public: 14 | // smoothness, rapidness: smaller is more smooth/rapid 15 | // bUseAccel: set true to smooth out velocity 16 | void init(T smoothness = 0.1, T rapidness = 0.1, bool bUseAccel = false); 17 | void update(const glm::vec3&); 18 | glm::vec3 getPrediction(); 19 | glm::vec3 getEstimation(); 20 | glm::vec3 getVelocity(); 21 | }; 22 | 23 | typedef KalmanPosition_ KalmanPosition; 24 | 25 | // Kalman filter for orientation 26 | template 27 | class KalmanEuler_ : public KalmanPosition_ { 28 | glm::vec3 eulerPrev; // used for finding appropriate dimension 29 | public: 30 | void init(T smoothness = 0.1, T rapidness = 0.1, bool bUseAccel = false); 31 | void update(const ofQuaternion&); 32 | ofQuaternion getPrediction(); 33 | ofQuaternion getEstimation(); 34 | //ofQuaternion getVelocity(); 35 | }; 36 | 37 | typedef KalmanEuler_ KalmanEuler; 38 | } 39 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/ObjectFinder.h: -------------------------------------------------------------------------------- 1 | /* 2 | this class is good for tracking things like faces. usually you want to speed 3 | up the tracking by doing detection on a smaller image, say setRescale(.25) for 4 | example to track on a 1/4 size image at a higher fps. other options for faster 5 | tracking include setCannyPruning(true) which will ignore low contrast regions, 6 | setFindBiggestObject(true) which finds the biggest object and returns it alone. 7 | it's rarely faster to do both of these together (learning opencv p 513). 8 | setMultiScaleFactor() provides a tradeoff between scale accuracy and speed. 9 | setMultiScaleFactor(1.01) will give a very accurate size for detected objects 10 | but will take longer to run. setMinNeighbors() tries to group multiple results 11 | from the tracker into a single result, and rejects anything that doesn't have 12 | enough results. setMinSizeScale() and setMaxSizeScale() set the minimum and 13 | maximum size for searching the space. you can set all these parameters at once 14 | with a preset using (for example) setPreset(ObjectFinder::Fast). 15 | 16 | need to add: 17 | - allow rotations 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "ofxCv/Utilities.h" 23 | #include "ofxCv/Tracker.h" 24 | #include "ofRectangle.h" 25 | 26 | #include "ofxCv.h" 27 | namespace ofxCv { 28 | class ObjectFinder { 29 | public: 30 | 31 | ObjectFinder(); 32 | void setup(std::string cascadeFilename); 33 | template 34 | void update(T& img) { 35 | update(toCv(img)); 36 | } 37 | void update(cv::Mat img); 38 | unsigned int size() const; 39 | ofRectangle getObject(unsigned int i) const; 40 | ofRectangle getObjectSmoothed(unsigned int i) const; 41 | RectTracker& getTracker(); 42 | unsigned int getLabel(unsigned int i) const; 43 | cv::Vec2f getVelocity(unsigned int i) const; 44 | void draw() const; 45 | 46 | enum Preset {Fast, Accurate, Sensitive}; 47 | void setPreset(ObjectFinder::Preset preset); 48 | 49 | void setRescale(float rescale); 50 | void setMinNeighbors(int minNeighbors); 51 | void setMultiScaleFactor(float multiScaleFactor); 52 | void setCannyPruning(bool cannyPruning); 53 | void setFindBiggestObject(bool findBiggestObject); 54 | void setUseHistogramEqualization(bool useHistogramEqualization); 55 | void setMinSizeScale(float minSizeScale); 56 | void setMaxSizeScale(float maxSizeScale); 57 | 58 | float getRescale() const; 59 | int getMinNeighbors() const; 60 | float getMultiScaleFactor() const; 61 | bool getCannyPruning() const; 62 | bool getFindBiggestObject() const; 63 | bool getUseHistogramEqualization() const; 64 | float getMinSizeScale() const; 65 | float getMaxSizeScale() const; 66 | 67 | protected: 68 | float rescale, multiScaleFactor; 69 | int minNeighbors; 70 | bool useHistogramEqualization, cannyPruning, findBiggestObject; 71 | float minSizeScale, maxSizeScale; 72 | cv::Mat gray, graySmall; 73 | cv::CascadeClassifier classifier; 74 | std::vector objects; 75 | RectTracker tracker; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /libs/ofxCv/include/ofxCv/RunningBackground.h: -------------------------------------------------------------------------------- 1 | /* 2 | this class is designed to handle the common task of detecting foreground 3 | objects in a complex scene by subtracting a known background. a good summary 4 | of different background subtraction techniques is available at: 5 | 6 | http://www-staff.it.uts.edu.au/~massimo/BackgroundSubtractionReview-Piccardi.pdf 7 | 8 | this class only implements the running average technique. this technique is 9 | also described in the opencv 2 cookbook in chapter 10, under "extracting the 10 | foreground objects in video". the example ignores foreground pixels during 11 | accumulation. this class uses all pixels by default, but can be set to ignore 12 | foreground pixels by calling setIgnoreForeground(true). 13 | 14 | learningRate determines how quickly the background is learned. a smaller value 15 | means the background takes longer to learn. default the learningRate is .0001 16 | and you can use setLearningRate() to change this. 17 | 18 | guessing a learningRate can be hard, because it's related to the threshold and 19 | your camera framerate. setLearningTime() will let you set the learningRate 20 | in terms of frames. larger values meaning the background takes longer to learn. 21 | a learning time of 900 means a 30 fps camera would take 30 seconds before 22 | a foreground object could leave a "shadow", or "trace" in the background 23 | that appears as foreground after thresholding. in practice, it will only take 24 | this amount of time exactly when the background is completely black and the 25 | foreground is completely white. most of the time it will take longer than 26 | learningTime, so it's safe to under-shoot. 27 | 28 | to do: 29 | - use hsb space, or sb space for differencing (like ContourFinder) 30 | */ 31 | 32 | #pragma once 33 | 34 | #include "ofxCv/Utilities.h" 35 | 36 | namespace ofxCv { 37 | class RunningBackground { 38 | public: 39 | enum DifferenceMode {ABSDIFF, BRIGHTER, DARKER}; 40 | 41 | RunningBackground(); 42 | template 43 | void update(F& frame, T& thresholded) { 44 | ofxCv::imitate(thresholded, frame, CV_8UC1); 45 | cv::Mat frameMat = toCv(frame); 46 | cv::Mat thresholdedMat = toCv(thresholded); 47 | update(frameMat, thresholdedMat); 48 | } 49 | void update(cv::Mat frame, cv::Mat& thresholded); 50 | cv::Mat& getBackground(); 51 | cv::Mat& getForeground(); 52 | float getPresence() const; 53 | void setThresholdValue(unsigned int thresholdValue); 54 | void setLearningRate(double learningRate); 55 | void setLearningTime(double learningTime); 56 | void setIgnoreForeground(bool ignoreForeground); 57 | void setDifferenceMode(DifferenceMode differenceMode); 58 | void reset(); 59 | protected: 60 | cv::Mat accumulator, background, foreground, foregroundGray; 61 | double learningRate, learningTime; 62 | unsigned int thresholdValue; 63 | bool useLearningTime, needToReset, ignoreForeground; 64 | DifferenceMode differenceMode; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Distance.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Distance.h" 2 | #include 3 | 4 | namespace ofxCv { 5 | 6 | // http://www.merriampark.com/ld.htm 7 | 8 | class Distance { 9 | public: 10 | int LD (char const *s, char const *t); 11 | private: 12 | int Minimum (int a, int b, int c); 13 | int *GetCellPointer (int *pOrigin, int col, int row, int nCols); 14 | int GetAt (int *pOrigin, int col, int row, int nCols); 15 | void PutAt (int *pOrigin, int col, int row, int nCols, int x); 16 | }; 17 | 18 | const std::string& mostRepresentative(const std::vector& strs) { 19 | int bestScore; 20 | int besti; 21 | int n = strs.size(); 22 | for(int i = 0; i < n; i++) { 23 | int curScore = 0; 24 | for(int j = 0; j < n; j++) { 25 | if(i != j) { 26 | int curDistance = editDistance(strs[i], strs[j]); 27 | curScore += curDistance * curDistance; 28 | } 29 | } 30 | if(curScore < bestScore || i == 0) { 31 | bestScore = curScore; 32 | besti = i; 33 | } 34 | } 35 | 36 | return strs[besti]; 37 | } 38 | 39 | int editDistance(const std::string& a, const std::string& b) { 40 | Distance dist; 41 | return dist.LD(a.c_str(), b.c_str()); 42 | } 43 | 44 | //**************************** 45 | // Get minimum of three values 46 | //**************************** 47 | 48 | int Distance::Minimum (int a, int b, int c) 49 | { 50 | int mi; 51 | 52 | mi = a; 53 | if (b < mi) { 54 | mi = b; 55 | } 56 | if (c < mi) { 57 | mi = c; 58 | } 59 | return mi; 60 | 61 | } 62 | 63 | //************************************************** 64 | // Get a pointer to the specified cell of the matrix 65 | //************************************************** 66 | 67 | int *Distance::GetCellPointer (int *pOrigin, int col, int row, int nCols) 68 | { 69 | return pOrigin + col + (row * (nCols + 1)); 70 | } 71 | 72 | //***************************************************** 73 | // Get the contents of the specified cell in the matrix 74 | //***************************************************** 75 | 76 | int Distance::GetAt (int *pOrigin, int col, int row, int nCols) 77 | { 78 | int *pCell; 79 | 80 | pCell = GetCellPointer (pOrigin, col, row, nCols); 81 | return *pCell; 82 | 83 | } 84 | 85 | //******************************************************* 86 | // Fill the specified cell in the matrix with the value x 87 | //******************************************************* 88 | 89 | void Distance::PutAt (int *pOrigin, int col, int row, int nCols, int x) 90 | { 91 | int *pCell; 92 | 93 | pCell = GetCellPointer (pOrigin, col, row, nCols); 94 | *pCell = x; 95 | 96 | } 97 | 98 | //***************************** 99 | // Compute Levenshtein distance 100 | //***************************** 101 | 102 | int Distance::LD (char const *s, char const *t) 103 | { 104 | int *d; // pointer to matrix 105 | int n; // length of s 106 | int m; // length of t 107 | int i; // iterates through s 108 | int j; // iterates through t 109 | char s_i; // ith character of s 110 | char t_j; // jth character of t 111 | int cost; // cost 112 | int result; // result 113 | int cell; // contents of target cell 114 | int above; // contents of cell immediately above 115 | int left; // contents of cell immediately to left 116 | int diag; // contents of cell immediately above and to left 117 | int sz; // number of cells in matrix 118 | 119 | // Step 1 120 | 121 | n = strlen (s); 122 | m = strlen (t); 123 | if (n == 0) { 124 | return m; 125 | } 126 | if (m == 0) { 127 | return n; 128 | } 129 | sz = (n+1) * (m+1) * sizeof (int); 130 | d = (int *) malloc (sz); 131 | 132 | // Step 2 133 | 134 | for (i = 0; i <= n; i++) { 135 | PutAt (d, i, 0, n, i); 136 | } 137 | 138 | for (j = 0; j <= m; j++) { 139 | PutAt (d, 0, j, n, j); 140 | } 141 | 142 | // Step 3 143 | 144 | for (i = 1; i <= n; i++) { 145 | 146 | s_i = s[i-1]; 147 | 148 | // Step 4 149 | 150 | for (j = 1; j <= m; j++) { 151 | 152 | t_j = t[j-1]; 153 | 154 | // Step 5 155 | 156 | if (s_i == t_j) { 157 | cost = 0; 158 | } 159 | else { 160 | cost = 1; 161 | } 162 | 163 | // Step 6 164 | 165 | above = GetAt (d,i-1,j, n); 166 | left = GetAt (d,i, j-1, n); 167 | diag = GetAt (d, i-1,j-1, n); 168 | cell = Minimum (above + 1, left + 1, diag + cost); 169 | PutAt (d, i, j, n, cell); 170 | } 171 | } 172 | 173 | // Step 7 174 | 175 | result = GetAt (d, n, m, n); 176 | free (d); 177 | return result; 178 | 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Flow.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Flow.h" 2 | #include "ofGraphics.h" 3 | 4 | namespace ofxCv { 5 | 6 | using namespace cv; 7 | using namespace std; 8 | Flow::Flow() 9 | :hasFlow(false) { 10 | } 11 | 12 | Flow::~Flow(){ 13 | } 14 | 15 | //call with two images 16 | void Flow::calcOpticalFlow(Mat lastImage, Mat currentImage){ 17 | if(lastImage.channels() == 1 && currentImage.channels() == 1) { 18 | calcFlow(lastImage, currentImage); 19 | } else { 20 | copyGray(lastImage, last); 21 | copyGray(currentImage, curr); 22 | calcFlow(last, curr); 23 | } 24 | hasFlow = true; 25 | } 26 | 27 | //you can add subsequent images this way without having to store 28 | //the previous one yourself 29 | void Flow::calcOpticalFlow(Mat nextImage){ 30 | copyGray(nextImage, curr); 31 | if(last.size == curr.size){ 32 | calcFlow(last, curr); 33 | hasFlow = true; 34 | } 35 | swap(curr, last); 36 | } 37 | 38 | void Flow::draw(){ 39 | if(hasFlow) { 40 | drawFlow(ofRectangle(0, 0, getWidth(), getHeight())); 41 | } 42 | } 43 | void Flow::draw(float x, float y){ 44 | if(hasFlow){ 45 | drawFlow(ofRectangle(x, y, getWidth(), getHeight())); 46 | } 47 | } 48 | void Flow::draw(float x, float y, float width, float height){ 49 | if(hasFlow){ 50 | drawFlow(ofRectangle(x,y,width,height)); 51 | } 52 | } 53 | void Flow::draw(ofRectangle rect){ 54 | if(hasFlow){ 55 | drawFlow(rect); 56 | } 57 | } 58 | int Flow::getWidth() { 59 | return curr.cols; 60 | } 61 | int Flow::getHeight() { 62 | return curr.rows; 63 | } 64 | void Flow::resetFlow() { 65 | last = Mat(); 66 | curr = Mat(); 67 | hasFlow = false; 68 | } 69 | 70 | FlowPyrLK::FlowPyrLK() 71 | :windowSize(32) 72 | ,maxLevel(3) 73 | ,maxFeatures(200) 74 | ,qualityLevel(0.01) 75 | ,minDistance(4) 76 | ,pyramidLevels(10) 77 | ,calcFeaturesNextFrame(true) 78 | { 79 | } 80 | 81 | FlowPyrLK::~FlowPyrLK(){ 82 | } 83 | 84 | void FlowPyrLK::setWindowSize(int winsize){ 85 | this->windowSize = winsize; 86 | } 87 | void FlowPyrLK::setMaxLevel(int maxLevel){ 88 | this->maxLevel = maxLevel; 89 | } 90 | void FlowPyrLK::setMaxFeatures(int maxFeatures){ 91 | this->maxFeatures = maxFeatures; 92 | } 93 | void FlowPyrLK::setQualityLevel(float qualityLevel){ 94 | this->qualityLevel = qualityLevel; 95 | } 96 | void FlowPyrLK::setMinDistance(int minDistance){ 97 | this->minDistance = minDistance; 98 | } 99 | 100 | void FlowPyrLK::calcFlow(Mat prev, Mat next){ 101 | if(!nextPts.empty() || calcFeaturesNextFrame){ 102 | if(calcFeaturesNextFrame){ 103 | calcFeaturesToTrack(prevPts, next); 104 | if (prevPts.empty()) { 105 | nextPts.clear(); 106 | return; 107 | } 108 | calcFeaturesNextFrame = false; 109 | }else{ 110 | swap(prevPts, nextPts); 111 | } 112 | nextPts.clear(); 113 | 114 | #if CV_MAJOR_VERSION>=2 && (CV_MINOR_VERSION>4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION>=1)) 115 | if (prevPyramid.empty()) { 116 | buildOpticalFlowPyramid(prev,prevPyramid,cv::Size(windowSize, windowSize),10); 117 | } 118 | buildOpticalFlowPyramid(next,pyramid,cv::Size(windowSize, windowSize),10); 119 | calcOpticalFlowPyrLK(prevPyramid, 120 | pyramid, 121 | prevPts, 122 | nextPts, 123 | status, 124 | err, 125 | cv::Size(windowSize, windowSize), 126 | maxLevel); 127 | prevPyramid = pyramid; 128 | pyramid.clear(); 129 | #else 130 | calcOpticalFlowPyrLK(prev, 131 | next, 132 | prevPts, 133 | nextPts, 134 | status, 135 | err, 136 | cv::Size(windowSize, windowSize), 137 | maxLevel); 138 | #endif 139 | status.resize(nextPts.size(),0); 140 | }else{ 141 | calcFeaturesToTrack(nextPts, next); 142 | } 143 | } 144 | 145 | void FlowPyrLK::calcFeaturesToTrack(std::vector & features, Mat next){ 146 | goodFeaturesToTrack( 147 | next, 148 | features, 149 | maxFeatures, 150 | qualityLevel, 151 | minDistance 152 | ); 153 | } 154 | 155 | void FlowPyrLK::resetFeaturesToTrack(){ 156 | calcFeaturesNextFrame=true; 157 | } 158 | 159 | void FlowPyrLK::setFeaturesToTrack(const std::vector & features){ 160 | nextPts.resize(features.size()); 161 | for(std::size_t i=0;i & features){ 168 | nextPts = features; 169 | calcFeaturesNextFrame = false; 170 | } 171 | 172 | std::vector FlowPyrLK::getFeatures(){ 173 | ofPolyline poly = toOf(prevPts); 174 | return poly.getVertices(); 175 | } 176 | 177 | std::vector FlowPyrLK::getCurrent(){ 178 | std::vector ret; 179 | for(std::size_t i = 0; i < nextPts.size(); i++) { 180 | if(status[i]){ 181 | ret.push_back(toOf(nextPts[i])); 182 | } 183 | } 184 | return ret; 185 | } 186 | 187 | std::vector FlowPyrLK::getMotion(){ 188 | std::vector ret; 189 | for(std::size_t i = 0; i < prevPts.size(); i++) { 190 | if(status[i]){ 191 | ret.push_back(toOf(nextPts[i])-toOf(prevPts[i])); 192 | } 193 | } 194 | return ret; 195 | } 196 | 197 | void FlowPyrLK::drawFlow(ofRectangle rect) { 198 | glm::vec2 offset(rect.x,rect.y); 199 | glm::vec2 scale(rect.width/getWidth(),rect.height/getHeight()); 200 | for(std::size_t i = 0; i < prevPts.size(); i++) { 201 | if(status[i]){ 202 | ofDrawLine(toOf(prevPts[i])*scale+offset, toOf(nextPts[i])*scale+offset); 203 | } 204 | } 205 | } 206 | 207 | void FlowPyrLK::resetFlow(){ 208 | Flow::resetFlow(); 209 | resetFeaturesToTrack(); 210 | prevPts.clear(); 211 | } 212 | 213 | FlowFarneback::FlowFarneback() 214 | :pyramidScale(0.5) 215 | ,numLevels(4) 216 | ,windowSize(8) 217 | ,numIterations(2) 218 | ,polyN(7) 219 | ,polySigma(1.5) 220 | ,farnebackGaussian(false) 221 | { 222 | } 223 | 224 | FlowFarneback::~FlowFarneback(){ 225 | } 226 | 227 | void FlowFarneback::setPyramidScale(float scale){ 228 | if(scale < 0.0 || scale >= 1.0){ 229 | ofLogWarning("FlowFarneback::setPyramidScale") << "setting scale to a number outside of 0 - 1"; 230 | } 231 | this->pyramidScale = scale; 232 | } 233 | 234 | void FlowFarneback::setNumLevels(int levels){ 235 | this->numLevels = levels; 236 | } 237 | void FlowFarneback::setWindowSize(int winsize){ 238 | this->windowSize = winsize; 239 | } 240 | void FlowFarneback::setNumIterations(int interations){ 241 | this->numIterations = interations; 242 | } 243 | void FlowFarneback::setPolyN(int polyN){ 244 | this->polyN = polyN; 245 | } 246 | void FlowFarneback::setPolySigma(float polySigma){ 247 | this->polySigma = polySigma; 248 | } 249 | void FlowFarneback::setUseGaussian(bool gaussian){ 250 | this->farnebackGaussian = gaussian; 251 | } 252 | 253 | void FlowFarneback::resetFlow(){ 254 | Flow::resetFlow(); 255 | flow.setTo(0); 256 | } 257 | 258 | void FlowFarneback::calcFlow(Mat prev, Mat next){ 259 | int flags = 0; 260 | if(hasFlow){ 261 | flags = OPTFLOW_USE_INITIAL_FLOW; 262 | } 263 | if(farnebackGaussian){ 264 | flags |= OPTFLOW_FARNEBACK_GAUSSIAN; 265 | } 266 | 267 | calcOpticalFlowFarneback(prev, 268 | next, 269 | flow, 270 | pyramidScale, 271 | numLevels, 272 | windowSize, 273 | numIterations, 274 | polyN, 275 | polySigma, 276 | flags); 277 | } 278 | Mat& FlowFarneback::getFlow() { 279 | if(!hasFlow) { 280 | flow = Mat::zeros(1, 1, CV_32FC2); 281 | } 282 | return flow; 283 | } 284 | glm::vec2 FlowFarneback::getFlowOffset(int x, int y){ 285 | if(!hasFlow){ 286 | return glm::vec2(0, 0); 287 | } 288 | const Vec2f& vec = flow.at(y, x); 289 | return glm::vec2(vec[0], vec[1]); 290 | } 291 | glm::vec2 FlowFarneback::getFlowPosition(int x, int y){ 292 | if(!hasFlow){ 293 | return glm::vec2(0, 0); 294 | } 295 | const Vec2f& vec = flow.at(y, x); 296 | return glm::vec2(x + vec[0], y + vec[1]); 297 | } 298 | glm::vec2 FlowFarneback::getTotalFlow(){ 299 | return getTotalFlowInRegion(ofRectangle(0,0,flow.cols, flow.rows)); 300 | } 301 | glm::vec2 FlowFarneback::getAverageFlow(){ 302 | return getAverageFlowInRegion(ofRectangle(0,0,flow.cols,flow.rows)); 303 | } 304 | 305 | glm::vec2 FlowFarneback::getAverageFlowInRegion(ofRectangle rect){ 306 | float area = rect.getArea(); 307 | 308 | if (area > 0) 309 | { 310 | return getTotalFlowInRegion(rect) / area; 311 | } 312 | else 313 | { 314 | return glm::vec2(0, 0); 315 | } 316 | } 317 | 318 | glm::vec2 FlowFarneback::getTotalFlowInRegion(ofRectangle region){ 319 | if(!hasFlow){ 320 | return glm::vec2(0, 0); 321 | } 322 | 323 | const Scalar& sc = sum(flow(toCv(region))); 324 | return glm::vec2(sc[0], sc[1]); 325 | } 326 | 327 | void FlowFarneback::drawFlow(ofRectangle rect){ 328 | if(!hasFlow){ 329 | return; 330 | } 331 | glm::vec2 offset(rect.x,rect.y); 332 | glm::vec2 scale(rect.width/flow.cols, rect.height/flow.rows); 333 | int stepSize = 4; //TODO: make class-level parameteric 334 | for(int y = 0; y < flow.rows; y += stepSize) { 335 | for(int x = 0; x < flow.cols; x += stepSize) { 336 | glm::vec2 cur = glm::vec2(x, y) * scale + offset; 337 | ofDrawLine(cur, getFlowPosition(x, y) * scale + offset); 338 | } 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Helpers.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Helpers.h" 2 | #include "ofxCv/Utilities.h" 3 | #include "ofGraphics.h" 4 | 5 | namespace ofxCv { 6 | 7 | using namespace cv; 8 | using namespace std; 9 | 10 | ofMatrix4x4 makeMatrix(Mat rotation, Mat translation) { 11 | Mat rot3x3; 12 | if(rotation.rows == 3 && rotation.cols == 3) { 13 | rot3x3 = rotation; 14 | } else { 15 | Rodrigues(rotation, rot3x3); 16 | } 17 | double* rm = rot3x3.ptr(0); 18 | double* tm = translation.ptr(0); 19 | return ofMatrix4x4(rm[0], rm[3], rm[6], 0.0f, 20 | rm[1], rm[4], rm[7], 0.0f, 21 | rm[2], rm[5], rm[8], 0.0f, 22 | tm[0], tm[1], tm[2], 1.0f); 23 | } 24 | 25 | void drawMat(const Mat& mat, float x, float y) { 26 | drawMat(mat, x, y, mat.cols, mat.rows); 27 | } 28 | 29 | // special case for copying into ofTexture 30 | template 31 | void copy(const S& src, ofTexture& tex) { 32 | imitate(tex, src); 33 | int w = tex.getWidth(), h = tex.getHeight(); 34 | int glType = tex.getTextureData().glInternalFormat; 35 | Mat mat = toCv(src); 36 | tex.loadData(mat.ptr(), w, h, glType); 37 | } 38 | 39 | void drawMat(const Mat& mat, float x, float y, float width, float height) { 40 | if(mat.empty()) { 41 | return; 42 | } 43 | ofTexture tex; 44 | copy(mat, tex); 45 | tex.draw(x, y, width, height); 46 | } 47 | 48 | void applyMatrix(const ofMatrix4x4& matrix) { 49 | glMultMatrixf((GLfloat*) matrix.getPtr()); 50 | } 51 | 52 | int forceOdd(int x) { 53 | return (x / 2) * 2 + 1; 54 | } 55 | 56 | int findFirst(const Mat& arr, unsigned char target) { 57 | for(int i = 0; i < arr.rows; i++) { 58 | if(arr.at(i) == target) { 59 | return i; 60 | } 61 | } 62 | return 0; 63 | } 64 | 65 | int findLast(const Mat& arr, unsigned char target) { 66 | for(int i = arr.rows - 1; i >= 0; i--) { 67 | if(arr.at(i) == target) { 68 | return i; 69 | } 70 | } 71 | return 0; 72 | } 73 | 74 | float weightedAverageAngle(const std::vector& lines) { 75 | float angleSum = 0; 76 | glm::vec2 start, end; 77 | float weights = 0; 78 | for(int i = 0; i < lines.size(); i++) { 79 | start = glm::vec2(lines[i][0], lines[i][1]); 80 | end = glm::vec2(lines[i][2], lines[i][3]); 81 | glm::vec2 diff = end - start; 82 | float length = glm::length(diff); 83 | float weight = length * length; 84 | float angle = atan2f(diff.y, diff.x); 85 | angleSum += angle * weight; 86 | weights += weight; 87 | } 88 | return angleSum / weights; 89 | } 90 | 91 | std::vector getConvexPolygon(const std::vector& convexHull, int targetPoints) { 92 | std::vector result = convexHull; 93 | 94 | static const unsigned int maxIterations = 16; 95 | static const double infinity = std::numeric_limits::infinity(); 96 | double minEpsilon = 0; 97 | double maxEpsilon = infinity; 98 | double curEpsilon = 16; // good initial guess 99 | 100 | // unbounded binary search to simplify the convex hull until it's targetPoints 101 | if(result.size() > targetPoints) { 102 | for(int i = 0; i < maxIterations; i++) { 103 | approxPolyDP(Mat(convexHull), result, curEpsilon, true); 104 | if(result.size() == targetPoints) { 105 | break; 106 | } 107 | if(result.size() > targetPoints) { 108 | minEpsilon = curEpsilon; 109 | if(maxEpsilon == infinity) { 110 | curEpsilon = curEpsilon * 2; 111 | } else { 112 | curEpsilon = (maxEpsilon + minEpsilon) / 2; 113 | } 114 | } 115 | if(result.size() < targetPoints) { 116 | maxEpsilon = curEpsilon; 117 | curEpsilon = (maxEpsilon + minEpsilon) / 2; 118 | } 119 | } 120 | } 121 | 122 | return result; 123 | } 124 | 125 | // Code for thinning a binary image using Zhang-Suen algorithm. 126 | // Normally you wouldn't call this function directly from your code. 127 | // 128 | // im Binary image with range = [0,1] 129 | // iter 0=even, 1=odd 130 | // 131 | // Author: Nash (nash [at] opencv-code [dot] com) 132 | // https://github.com/bsdnoobz/zhang-suen-thinning 133 | void thinningIteration( cv::Mat & img, int iter, cv::Mat & marker ) 134 | { 135 | CV_Assert(img.channels() == 1); 136 | CV_Assert(img.depth() != sizeof(uchar)); 137 | CV_Assert(img.rows > 3 && img.cols > 3); 138 | 139 | int nRows = img.rows; 140 | int nCols = img.cols; 141 | 142 | if (img.isContinuous()) { 143 | nCols *= nRows; 144 | nRows = 1; 145 | } 146 | 147 | int x, y; 148 | uchar *pAbove; 149 | uchar *pCurr; 150 | uchar *pBelow; 151 | uchar *nw, *no, *ne; // north (pAbove) 152 | uchar *we, *me, *ea; 153 | uchar *sw, *so, *se; // south (pBelow) 154 | 155 | uchar *pDst; 156 | 157 | // initialize row pointers 158 | pAbove = NULL; 159 | pCurr = img.ptr(0); 160 | pBelow = img.ptr(1); 161 | 162 | for (y = 1; y < img.rows-1; ++y) { 163 | // shift the rows up by one 164 | pAbove = pCurr; 165 | pCurr = pBelow; 166 | pBelow = img.ptr(y+1); 167 | 168 | pDst = marker.ptr(y); 169 | 170 | // initialize col pointers 171 | no = &(pAbove[0]); 172 | ne = &(pAbove[1]); 173 | me = &(pCurr[0]); 174 | ea = &(pCurr[1]); 175 | so = &(pBelow[0]); 176 | se = &(pBelow[1]); 177 | 178 | for (x = 1; x < img.cols-1; ++x) { 179 | // shift col pointers left by one (scan left to right) 180 | nw = no; 181 | no = ne; 182 | ne = &(pAbove[x+1]); 183 | we = me; 184 | me = ea; 185 | ea = &(pCurr[x+1]); 186 | sw = so; 187 | so = se; 188 | se = &(pBelow[x+1]); 189 | 190 | // @valillon 191 | // Beyond this point the original Nash's code used an unified conditional at the end 192 | // Intermediate conditionals speeds the process up (depending on the image to be thinned). 193 | if (*me == 0) continue; // do not thin already zeroed pixels 194 | 195 | int A = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) + 196 | (*ea == 0 && *se == 1) + (*se == 0 && *so == 1) + 197 | (*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) + 198 | (*we == 0 && *nw == 1) + (*nw == 0 && *no == 1); 199 | if (A != 1) continue; 200 | 201 | int B = *no + *ne + *ea + *se + *so + *sw + *we + *nw; 202 | if (B < 2 || B > 6) continue; 203 | 204 | int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we); 205 | if (m1) continue; 206 | 207 | int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we); 208 | if (m2) continue; 209 | 210 | // if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0) 211 | pDst[x] = 1; 212 | } 213 | } 214 | 215 | img &= ~marker; 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Kalman.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Kalman.h" 2 | 3 | namespace ofxCv { 4 | 5 | // based on code from: 6 | // http://www.morethantechnical.com/2011/06/17/simple-kalman-filter-for-tracking-using-opencv-2-2-w-code/ 7 | 8 | using namespace cv; 9 | 10 | template 11 | void KalmanPosition_::init(T smoothness, T rapidness, bool bUseAccel) { 12 | if( bUseAccel ) { 13 | KF.init(9, 3, 0); // 9 variables (position+velocity+accel) and 3 measurements (position) 14 | 15 | KF.transitionMatrix = (Mat_(9, 9) << 16 | 1,0,0,1,0,0,0.5,0,0, 17 | 0,1,0,0,1,0,0,0.5,0, 18 | 0,0,1,0,0,1,0,0,0.5, 19 | 0,0,0,1,0,0,1,0,0, 20 | 0,0,0,0,1,0,0,1,0, 21 | 0,0,0,0,0,1,0,0,1, 22 | 0,0,0,0,0,0,1,0,0, 23 | 0,0,0,0,0,0,0,1,0, 24 | 0,0,0,0,0,0,0,0,1); 25 | 26 | measurement = Mat_::zeros(3, 1); 27 | 28 | KF.statePre = Mat_::zeros(9, 1); 29 | } else { 30 | KF.init(6, 3, 0); // 6 variables (position+velocity) and 3 measurements (position) 31 | 32 | KF.transitionMatrix = (Mat_(6, 6) << 33 | 1,0,0,1,0,0, 34 | 0,1,0,0,1,0, 35 | 0,0,1,0,0,1, 36 | 0,0,0,1,0,0, 37 | 0,0,0,0,1,0, 38 | 0,0,0,0,0,1); 39 | 40 | measurement = Mat_::zeros(3, 1); 41 | 42 | KF.statePre = Mat_::zeros(6, 1); 43 | } 44 | setIdentity(KF.measurementMatrix); 45 | setIdentity(KF.processNoiseCov, Scalar::all(smoothness)); 46 | setIdentity(KF.measurementNoiseCov, Scalar::all(rapidness)); 47 | setIdentity(KF.errorCovPost, Scalar::all(.1)); 48 | } 49 | 50 | template 51 | void KalmanPosition_::update(const glm::vec3& p) { 52 | // First predict, to update the internal statePre variable 53 | prediction = KF.predict(); 54 | 55 | // The "correct" phase that is going to use the predicted value and our measurement 56 | measurement(0) = p.x; 57 | measurement(1) = p.y; 58 | measurement(2) = p.z; 59 | estimated = KF.correct(measurement); 60 | } 61 | 62 | template 63 | glm::vec3 KalmanPosition_::getPrediction() 64 | { 65 | return glm::vec3(prediction(0), prediction(1), prediction(2)); 66 | } 67 | 68 | template 69 | glm::vec3 KalmanPosition_::getEstimation() 70 | { 71 | return glm::vec3(estimated(0), estimated(1), estimated(2)); 72 | } 73 | 74 | template 75 | glm::vec3 KalmanPosition_::getVelocity() 76 | { 77 | return glm::vec3(estimated(3), estimated(4), estimated(5)); 78 | } 79 | 80 | template class KalmanPosition_; 81 | 82 | template 83 | void KalmanEuler_::init(T smoothness, T rapidness, bool bUseAccel) { 84 | KalmanPosition_::init(smoothness, rapidness, bUseAccel); 85 | eulerPrev.x = 0.f; 86 | eulerPrev.y = 0.f; 87 | eulerPrev.z = 0.f; 88 | } 89 | 90 | template 91 | void KalmanEuler_::update(const ofQuaternion& q) { 92 | // warp to appropriate dimension 93 | glm::vec3 euler = q.getEuler(); 94 | for( int i = 0; i < 3; i++ ) { 95 | float rev = floorf((eulerPrev[i] + 180) / 360.f) * 360; 96 | euler[i] += rev; 97 | if( euler[i] < -90 + rev && eulerPrev[i] > 90 + rev ) euler[i] += 360; 98 | else if( euler[i] > 90 + rev && eulerPrev[i] < -90 + rev ) euler[i] -= 360; 99 | } 100 | 101 | KalmanPosition_::update(euler); 102 | eulerPrev = euler; 103 | } 104 | 105 | template 106 | ofQuaternion KalmanEuler_::getPrediction() 107 | { 108 | ofQuaternion q; 109 | q.set(0, 0, 0, 1); 110 | glm::vec3 euler = KalmanPosition_::getPrediction(); 111 | 112 | q.makeRotate(euler.x, glm::vec3(1, 0, 0), euler.z, glm::vec3(0, 0, 1), euler.y, glm::vec3(0, 1, 0)); 113 | 114 | return q; 115 | } 116 | 117 | template 118 | ofQuaternion KalmanEuler_::getEstimation() 119 | { 120 | ofQuaternion q; 121 | q.set(0, 0, 0, 1); 122 | glm::vec3 euler = KalmanPosition_::getEstimation(); 123 | 124 | q.makeRotate(euler.x, glm::vec3(1, 0, 0), euler.z, glm::vec3(0, 0, 1), euler.y, glm::vec3(0, 1, 0)); 125 | 126 | return q; 127 | } 128 | 129 | template class KalmanEuler_; 130 | 131 | } 132 | -------------------------------------------------------------------------------- /libs/ofxCv/src/ObjectFinder.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/ObjectFinder.h" 2 | #include "ofGraphics.h" 3 | 4 | namespace ofxCv { 5 | using namespace cv; 6 | using namespace std; 7 | 8 | ObjectFinder::ObjectFinder() 9 | :rescale(1) 10 | ,multiScaleFactor(1.1) 11 | ,minNeighbors(3) 12 | ,minSizeScale(0) 13 | ,maxSizeScale(1) 14 | ,useHistogramEqualization(true) 15 | ,cannyPruning(false) 16 | ,findBiggestObject(false) 17 | { 18 | } 19 | void ObjectFinder::setup(std::string cascadeFilename) { 20 | cascadeFilename = ofToDataPath(cascadeFilename); 21 | if(ofFile(cascadeFilename).exists()) { 22 | classifier.load(cascadeFilename); 23 | } else { 24 | ofLogError("ObjectFinder::setup") << "Couldn't find " << cascadeFilename; 25 | } 26 | } 27 | void ObjectFinder::update(cv::Mat img) { 28 | cv::Mat gray; 29 | if(getChannels(img) == 1) { 30 | gray = img; 31 | } else { 32 | copyGray(img,gray); 33 | } 34 | resize(gray, graySmall, rescale, rescale); 35 | cv::Mat graySmallMat = toCv(graySmall); 36 | if(useHistogramEqualization) { 37 | equalizeHist(graySmallMat, graySmallMat); 38 | } 39 | cv::Size minSize, maxSize; 40 | float minSide = MIN(graySmallMat.rows, graySmallMat.cols); 41 | if(minSizeScale > 0) { 42 | int side = minSizeScale * minSide; 43 | minSize = cv::Size(side, side); 44 | } 45 | if(maxSizeScale < 1) { 46 | int side = maxSizeScale * minSide; 47 | maxSize = cv::Size(side, side); 48 | } 49 | classifier.detectMultiScale(graySmallMat, 50 | objects, 51 | multiScaleFactor, 52 | minNeighbors, 53 | (cannyPruning ? CASCADE_DO_CANNY_PRUNING : 0) | 54 | (findBiggestObject ? CASCADE_FIND_BIGGEST_OBJECT | CASCADE_DO_ROUGH_SEARCH : 0), 55 | minSize, 56 | maxSize); 57 | for(int i = 0; i < objects.size(); i++) { 58 | cv::Rect& rect = objects[i]; 59 | rect.width /= rescale, rect.height /= rescale; 60 | rect.x /= rescale, rect.y /= rescale; 61 | } 62 | tracker.track(objects); 63 | } 64 | unsigned int ObjectFinder::size() const { 65 | return objects.size(); 66 | } 67 | ofRectangle ObjectFinder::getObject(unsigned int i) const { 68 | return toOf(objects[i]); 69 | } 70 | ofRectangle ObjectFinder::getObjectSmoothed(unsigned int i) const { 71 | return toOf(tracker.getSmoothed(getLabel(i))); 72 | } 73 | cv::Vec2f ObjectFinder::getVelocity(unsigned int i) const { 74 | return tracker.getVelocity(i); 75 | } 76 | unsigned int ObjectFinder::getLabel(unsigned int i) const { 77 | return tracker.getCurrentLabels()[i]; 78 | } 79 | RectTracker& ObjectFinder::getTracker() { 80 | return tracker; 81 | } 82 | void ObjectFinder::draw() const { 83 | ofPushStyle(); 84 | ofNoFill(); 85 | for(int i = 0; i < size(); i++) { 86 | ofRectangle object = getObject(i); 87 | ofDrawRectangle(object); 88 | ofDrawBitmapStringHighlight(ofToString(getLabel(i)), object.x, object.y); 89 | } 90 | ofPopStyle(); 91 | } 92 | void ObjectFinder::setPreset(ObjectFinder::Preset preset) { 93 | if(preset == ObjectFinder::Fast) { 94 | setRescale(.25); 95 | setMinNeighbors(2); 96 | setMultiScaleFactor(1.2); 97 | setMinSizeScale(.25); 98 | setMaxSizeScale(.75); 99 | setCannyPruning(true); 100 | setFindBiggestObject(false); 101 | } else if(preset == ObjectFinder::Accurate) { 102 | setRescale(.5); 103 | setMinNeighbors(6); 104 | setMultiScaleFactor(1.02); 105 | setMinSizeScale(.1); 106 | setMaxSizeScale(1); 107 | setCannyPruning(true); 108 | setFindBiggestObject(false); 109 | } else if(preset == ObjectFinder::Sensitive) { 110 | setRescale(.5); 111 | setMinNeighbors(1); 112 | setMultiScaleFactor(1.02); 113 | setMinSizeScale(.1); 114 | setMaxSizeScale(1); 115 | setCannyPruning(false); 116 | setFindBiggestObject(false); 117 | } 118 | } 119 | 120 | void ObjectFinder::setRescale(float rescale) { 121 | this->rescale = rescale; 122 | } 123 | void ObjectFinder::setMinNeighbors(int minNeighbors) { 124 | this->minNeighbors = minNeighbors; 125 | } 126 | void ObjectFinder::setMultiScaleFactor(float multiScaleFactor) { 127 | this->multiScaleFactor = multiScaleFactor; 128 | } 129 | void ObjectFinder::setCannyPruning(bool cannyPruning) { 130 | this->cannyPruning = cannyPruning; 131 | } 132 | void ObjectFinder::setFindBiggestObject(bool findBiggestObject) { 133 | this->findBiggestObject = findBiggestObject; 134 | } 135 | void ObjectFinder::setUseHistogramEqualization(bool useHistogramEqualization) { 136 | this->useHistogramEqualization = useHistogramEqualization; 137 | } 138 | void ObjectFinder::setMinSizeScale(float minSizeScale) { 139 | this->minSizeScale = minSizeScale; 140 | } 141 | void ObjectFinder::setMaxSizeScale(float maxSizeScale) { 142 | this->maxSizeScale = maxSizeScale; 143 | } 144 | 145 | float ObjectFinder::getRescale() const { 146 | return rescale; 147 | } 148 | int ObjectFinder::getMinNeighbors() const { 149 | return minNeighbors; 150 | } 151 | float ObjectFinder::getMultiScaleFactor() const { 152 | return multiScaleFactor; 153 | } 154 | bool ObjectFinder::getCannyPruning() const { 155 | return cannyPruning; 156 | } 157 | bool ObjectFinder::getFindBiggestObject() const { 158 | return findBiggestObject; 159 | } 160 | bool ObjectFinder::getUseHistogramEqualization() const { 161 | return useHistogramEqualization; 162 | } 163 | float ObjectFinder::getMinSizeScale() const { 164 | return minSizeScale; 165 | } 166 | float ObjectFinder::getMaxSizeScale() const { 167 | return maxSizeScale; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /libs/ofxCv/src/RunningBackground.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/RunningBackground.h" 2 | #include "ofxCv/Wrappers.h" 3 | 4 | namespace ofxCv { 5 | RunningBackground::RunningBackground() 6 | :learningRate(.0001) 7 | ,learningTime(900.0) 8 | ,useLearningTime(false) 9 | ,thresholdValue(26) 10 | ,ignoreForeground(false) 11 | ,needToReset(false) 12 | ,differenceMode(ABSDIFF) { 13 | } 14 | void RunningBackground::update(cv::Mat frame, cv::Mat& thresholded) { 15 | if(needToReset || accumulator.empty()) { 16 | needToReset = false; 17 | frame.convertTo(accumulator, CV_32F); 18 | } 19 | 20 | accumulator.convertTo(background, CV_8U); 21 | switch(differenceMode) { 22 | case ABSDIFF: cv::absdiff(background, frame, foreground); break; 23 | case BRIGHTER: cv::subtract(frame, background, foreground); break; 24 | case DARKER: cv::subtract(background, frame, foreground); break; 25 | } 26 | ofxCv::copyGray(foreground, foregroundGray); 27 | int thresholdMode = ignoreForeground ? cv::THRESH_BINARY_INV : cv::THRESH_BINARY; 28 | cv::threshold(foregroundGray, thresholded, thresholdValue, 255, thresholdMode); 29 | 30 | float curLearningRate = learningRate; 31 | if(useLearningTime) { 32 | curLearningRate = 1. - powf(1. - (thresholdValue / 255.), 1. / learningTime); 33 | } 34 | if(ignoreForeground) { 35 | cv::accumulateWeighted(frame, accumulator, curLearningRate, thresholded); 36 | cv::bitwise_not(thresholded, thresholded); 37 | } else { 38 | cv::accumulateWeighted(frame, accumulator, curLearningRate); 39 | } 40 | } 41 | cv::Mat& RunningBackground::getBackground() { 42 | return background; 43 | } 44 | cv::Mat& RunningBackground::getForeground() { 45 | return foreground; 46 | } 47 | float RunningBackground::getPresence() const { 48 | // this could be memoized to improve speed 49 | return cv::mean(foreground)[0] / 255.; 50 | } 51 | void RunningBackground::setThresholdValue(unsigned int thresholdValue) { 52 | this->thresholdValue = thresholdValue; 53 | } 54 | void RunningBackground::setLearningRate(double learningRate) { 55 | this->learningRate = learningRate; 56 | useLearningTime = false; 57 | } 58 | void RunningBackground::setLearningTime(double learningTime) { 59 | this->learningTime = learningTime; 60 | useLearningTime = true; 61 | } 62 | void RunningBackground::setIgnoreForeground(bool ignoreForeground) { 63 | this->ignoreForeground = ignoreForeground; 64 | } 65 | void RunningBackground::setDifferenceMode(DifferenceMode differenceMode) { 66 | this->differenceMode = differenceMode; 67 | } 68 | void RunningBackground::reset() { 69 | needToReset = true; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Tracker.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Tracker.h" 2 | 3 | #include "ofxCv/Utilities.h" 4 | #include "ofRectangle.h" 5 | #include "ofVec2f.h" 6 | 7 | namespace ofxCv { 8 | 9 | float trackingDistance(const cv::Rect& a, const cv::Rect& b) { 10 | float dx = (a.x + a.width / 2.) - (b.x + b.width / 2.); 11 | float dy = (a.y + a.height / 2.) - (b.y + b.height / 2.); 12 | float dw = a.width - b.width; 13 | float dh = a.height - b.height; 14 | float pd = sqrtf(dx * dx + dy * dy); 15 | float sd = sqrtf(dw * dw + dh * dh); 16 | return pd + sd; 17 | } 18 | 19 | float trackingDistance(const cv::Point2f& a, const cv::Point2f& b) { 20 | float dx = a.x - b.x; 21 | float dy = a.y - b.y; 22 | return sqrtf(dx * dx + dy * dy); 23 | } 24 | 25 | float trackingDistance(const ofRectangle& a, const ofRectangle& b) { 26 | return trackingDistance(toCv(a), toCv(b)); 27 | } 28 | 29 | float trackingDistance(const ofVec2f& a, const ofVec2f& b) { 30 | return trackingDistance(toCv(a), toCv(b)); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /libs/ofxCv/src/Utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Utilities.h" 2 | 3 | #include "ofGraphicsBaseTypes.h" 4 | #include "ofMath.h" 5 | #include "ofMesh.h" 6 | 7 | 8 | // vs2010 support (this should be added to the OF core) 9 | #if (_MSC_VER) 10 | #include 11 | #endif 12 | 13 | namespace ofxCv { 14 | 15 | using namespace cv; 16 | using namespace std; 17 | 18 | Mat toCv(Mat& mat) { 19 | return mat; 20 | } 21 | 22 | Mat toCv(const Mat& mat) { 23 | return mat.clone(); 24 | } 25 | 26 | Point2f toCv(glm::vec2 vec) { 27 | return Point2f(vec.x, vec.y); 28 | } 29 | 30 | Point3f toCv(glm::vec3 vec) { 31 | return Point3f(vec.x, vec.y, vec.z); 32 | } 33 | 34 | cv::Rect toCv(ofRectangle rect) { 35 | return cv::Rect(rect.x, rect.y, rect.width, rect.height); 36 | } 37 | 38 | Mat toCv(ofMesh& mesh) { 39 | std::vector& vertices = mesh.getVertices(); 40 | return Mat(1, vertices.size(), CV_32FC3, &vertices[0]); 41 | } 42 | 43 | std::vector toCv(const ofPolyline& polyline) { 44 | // if polyline.getVertices() were const, this could wrap toCv(vec) 45 | std::vector contour(polyline.size()); 46 | for(int i = 0; i < polyline.size(); i++) { 47 | contour[i].x = polyline[i].x; 48 | contour[i].y = polyline[i].y; 49 | } 50 | return contour; 51 | } 52 | 53 | std::vector toCv(const std::vector& points) { 54 | std::vector out(points.size()); 55 | for(int i = 0; i < points.size(); i++) { 56 | out[i].x = points[i].x; 57 | out[i].y = points[i].y; 58 | } 59 | return out; 60 | } 61 | 62 | std::vector toCv(const std::vector& points) { 63 | std::vector out(points.size()); 64 | for(int i = 0; i < points.size(); i++) { 65 | out[i].x = points[i].x; 66 | out[i].y = points[i].y; 67 | out[i].z = points[i].z; 68 | } 69 | return out; 70 | } 71 | 72 | Scalar toCv(ofColor color) { 73 | return Scalar(color.r, color.g, color.b, color.a); 74 | } 75 | 76 | glm::vec2 toOf(Point2f point) { 77 | return glm::vec2(point.x, point.y); 78 | } 79 | 80 | glm::vec3 toOf(Point3f point) { 81 | return glm::vec3(point.x, point.y, point.z); 82 | } 83 | 84 | ofRectangle toOf(cv::Rect rect) { 85 | return ofRectangle(rect.x, rect.y, rect.width, rect.height); 86 | } 87 | 88 | ofPolyline toOf(cv::RotatedRect rect) { 89 | std::vector corners(4); 90 | rect.points(&corners[0]); 91 | ofPolyline polyline = toOf(corners); 92 | return polyline; 93 | } 94 | 95 | float getMaxVal(int cvDepth) { 96 | switch(cvDepth) { 97 | case CV_8U: return std::numeric_limits::max(); 98 | case CV_16U: return std::numeric_limits::max(); 99 | 100 | case CV_8S: return std::numeric_limits::max(); 101 | case CV_16S: return std::numeric_limits::max(); 102 | case CV_32S: return std::numeric_limits::max(); 103 | 104 | case CV_32F: return 1; 105 | case CV_64F: default: return 1; 106 | } 107 | } 108 | 109 | float getMaxVal(const Mat& mat) { 110 | return getMaxVal(mat.depth()); 111 | } 112 | 113 | // for some reason, cvtColor handles this info internally rather than having 114 | // a single helper function. so we have to create a helper function to aid 115 | // in doing the allocationg ofxCv::convertColor() 116 | #define mkcase(x, y) {case x: return y;} 117 | int getTargetChannelsFromCode(int conversionCode) { 118 | switch(conversionCode) { 119 | mkcase(CV_RGB2RGBA,4) mkcase(CV_RGBA2RGB,3) mkcase(CV_RGB2BGRA,4) 120 | mkcase(CV_RGBA2BGR,3) mkcase(CV_BGR2RGB,3) mkcase(CV_BGRA2RGBA,4) 121 | mkcase(CV_BGR2GRAY,1) mkcase(CV_RGB2GRAY,1) mkcase(CV_GRAY2RGB,3) 122 | mkcase(CV_GRAY2RGBA,4) mkcase(CV_BGRA2GRAY,1) mkcase(CV_RGBA2GRAY,1) 123 | mkcase(CV_BGR5652BGR,3) mkcase(CV_BGR5652RGB,3) mkcase(CV_BGR5652BGRA,4) 124 | mkcase(CV_BGR5652RGBA,4) mkcase(CV_BGR5652GRAY,1) mkcase(CV_BGR5552BGR,3) 125 | mkcase(CV_BGR5552RGB,3) mkcase(CV_BGR5552BGRA,4) mkcase(CV_BGR5552RGBA,4) 126 | mkcase(CV_BGR5552GRAY,1) mkcase(CV_BGR2XYZ,3) mkcase(CV_RGB2XYZ,3) 127 | mkcase(CV_XYZ2BGR,3) mkcase(CV_XYZ2RGB,3) mkcase(CV_BGR2YCrCb,3) 128 | mkcase(CV_RGB2YCrCb,3) mkcase(CV_YCrCb2BGR,3) mkcase(CV_YCrCb2RGB,3) 129 | mkcase(CV_BGR2HSV,3) mkcase(CV_RGB2HSV,3) mkcase(CV_BGR2Lab,3) 130 | mkcase(CV_RGB2Lab,3) mkcase(CV_BayerGB2BGR,3) mkcase(CV_BayerBG2RGB,3) 131 | mkcase(CV_BayerGB2RGB,3) mkcase(CV_BayerRG2RGB,3) mkcase(CV_BGR2Luv,3) 132 | mkcase(CV_RGB2Luv,3) mkcase(CV_BGR2HLS,3) mkcase(CV_RGB2HLS,3) 133 | mkcase(CV_HSV2BGR,3) mkcase(CV_HSV2RGB,3) mkcase(CV_Lab2BGR,3) 134 | mkcase(CV_Lab2RGB,3) mkcase(CV_Luv2BGR,3) mkcase(CV_Luv2RGB,3) 135 | mkcase(CV_HLS2BGR,3) mkcase(CV_HLS2RGB,3) mkcase(CV_BayerBG2RGB_VNG,3) 136 | mkcase(CV_BayerGB2RGB_VNG,3) mkcase(CV_BayerRG2RGB_VNG,3) 137 | mkcase(CV_BayerGR2RGB_VNG,3) mkcase(CV_BGR2HSV_FULL,3) 138 | mkcase(CV_RGB2HSV_FULL,3) mkcase(CV_BGR2HLS_FULL,3) 139 | mkcase(CV_RGB2HLS_FULL,3) mkcase(CV_HSV2BGR_FULL,3) 140 | mkcase(CV_HSV2RGB_FULL,3) mkcase(CV_HLS2BGR_FULL,3) 141 | mkcase(CV_HLS2RGB_FULL,3) mkcase(CV_LBGR2Lab,3) mkcase(CV_LRGB2Lab,3) 142 | mkcase(CV_LBGR2Luv,3) mkcase(CV_LRGB2Luv,3) mkcase(CV_Lab2LBGR,4) 143 | mkcase(CV_Lab2LRGB,4) mkcase(CV_Luv2LBGR,4) mkcase(CV_Luv2LRGB,4) 144 | mkcase(CV_BGR2YUV,3) mkcase(CV_RGB2YUV,3) mkcase(CV_YUV2BGR,3) 145 | mkcase(CV_YUV2RGB,3) 146 | default: return 0; 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /libs/ofxCv/src/Wrappers.cpp: -------------------------------------------------------------------------------- 1 | #include "ofxCv/Wrappers.h" 2 | 3 | namespace ofxCv { 4 | 5 | using namespace cv; 6 | using namespace std; 7 | 8 | void loadMat(Mat& mat, std::string filename) { 9 | FileStorage fs(ofToDataPath(filename), FileStorage::READ); 10 | fs["Mat"] >> mat; 11 | } 12 | 13 | void saveMat(Mat mat, std::string filename) { 14 | FileStorage fs(ofToDataPath(filename), FileStorage::WRITE); 15 | fs << "Mat" << mat; 16 | } 17 | 18 | void saveImage(Mat& mat, std::string filename, ofImageQualityType qualityLevel) { 19 | if(mat.depth() == CV_8U) { 20 | ofPixels pix8u; 21 | toOf(mat, pix8u); 22 | ofSaveImage(pix8u, filename, qualityLevel); 23 | } else if(mat.depth() == CV_16U) { 24 | ofShortPixels pix16u; 25 | toOf(mat, pix16u); 26 | ofSaveImage(pix16u, filename, qualityLevel); 27 | } else if(mat.depth() == CV_32F) { 28 | ofFloatPixels pix32f; 29 | toOf(mat, pix32f); 30 | ofSaveImage(pix32f, filename, qualityLevel); 31 | } 32 | } 33 | 34 | Vec3b convertColor(Vec3b color, int code) { 35 | Mat_ mat(1, 1, CV_8UC3); 36 | mat(0, 0) = color; 37 | cvtColor(mat, mat, code); 38 | return mat(0, 0); 39 | } 40 | 41 | ofColor convertColor(ofColor color, int code) { 42 | Vec3b cvColor(color.r, color.g, color.b); 43 | Vec3b result = convertColor(cvColor, code); 44 | return ofColor(result[0], result[1], result[2], color.a); 45 | } 46 | 47 | ofPolyline convexHull(const ofPolyline& polyline) { 48 | std::vector contour = toCv(polyline); 49 | std::vector hull; 50 | convexHull(Mat(contour), hull); 51 | return toOf(hull); 52 | } 53 | 54 | // this should be replaced by c++ 2.0 api style code once available 55 | std::vector convexityDefects(const std::vector& contour) { 56 | std::vector hullIndices; 57 | convexHull(Mat(contour), hullIndices, false, false); 58 | std::vector convexityDefects; 59 | if(hullIndices.size() > 0 && contour.size() > 0) { 60 | CvMat contourMat = cvMat(1, contour.size(), CV_32SC2, (void*) &contour[0]); 61 | CvMat hullMat = cvMat(1, hullIndices.size(), CV_32SC1, (void*) &hullIndices[0]); 62 | CvMemStorage* storage = cvCreateMemStorage(0); 63 | CvSeq* defects = cvConvexityDefects(&contourMat, &hullMat, storage); 64 | for(int i = 0; i < defects->total; i++){ 65 | CvConvexityDefect* cur = (CvConvexityDefect*) cvGetSeqElem(defects, i); 66 | cv::Vec4i defect; 67 | defect[0] = cur->depth_point->x; 68 | defect[1] = cur->depth_point->y; 69 | defect[2] = (cur->start->x + cur->end->x) / 2; 70 | defect[3] = (cur->start->y + cur->end->y) / 2; 71 | convexityDefects.push_back(defect); 72 | } 73 | cvReleaseMemStorage(&storage); 74 | } 75 | return convexityDefects; 76 | } 77 | 78 | std::vector convexityDefects(const ofPolyline& polyline) { 79 | std::vector contour2f = toCv(polyline); 80 | std::vector contour2i; 81 | Mat(contour2f).copyTo(contour2i); 82 | return convexityDefects(contour2i); 83 | } 84 | 85 | cv::RotatedRect minAreaRect(const ofPolyline& polyline) { 86 | return minAreaRect(Mat(toCv(polyline))); 87 | } 88 | 89 | cv::RotatedRect fitEllipse(const ofPolyline& polyline) { 90 | return fitEllipse(Mat(toCv(polyline))); 91 | } 92 | 93 | void fitLine(const ofPolyline& polyline, glm::vec2& point, glm::vec2& direction) { 94 | Vec4f line; 95 | fitLine(Mat(toCv(polyline)), line, CV_DIST_L2, 0, .01, .01); 96 | 97 | direction = glm::vec2(line[0], line[1]); 98 | point = glm::vec2(line[2], line[3]); 99 | } 100 | 101 | ofMatrix4x4 estimateAffine3D(std::vector& from, std::vector& to, float accuracy) { 102 | if(from.size() != to.size() || from.size() == 0 || to.size() == 0) { 103 | return ofMatrix4x4(); 104 | } 105 | std::vector outliers; 106 | return estimateAffine3D(from, to, outliers, accuracy); 107 | } 108 | 109 | ofMatrix4x4 estimateAffine3D(std::vector& from, std::vector& to, std::vector& outliers, float accuracy) { 110 | Mat fromMat(1, from.size(), CV_32FC3, &from[0]); 111 | Mat toMat(1, to.size(), CV_32FC3, &to[0]); 112 | Mat affine; 113 | estimateAffine3D(fromMat, toMat, affine, outliers, 3, accuracy); 114 | ofMatrix4x4 affine4x4; 115 | affine4x4.set(affine.ptr()); 116 | affine4x4(3, 0) = 0; 117 | affine4x4(3, 1) = 0; 118 | affine4x4(3, 2) = 0; 119 | affine4x4(3, 3) = 1; 120 | Mat affine4x4Mat(4, 4, CV_32F, affine4x4.getPtr()); 121 | affine4x4Mat = affine4x4Mat.t(); 122 | affine4x4.set(affine4x4Mat.ptr()); 123 | return affine4x4; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license). 2 | 3 | Copyright (c) 2012- Kyle McDonald 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ofxaddons_thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kylemcdonald/ofxCv/209a3986a8f8e1928c7a11f6e1c5d8ea5406e639/ofxaddons_thumbnail.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ofxCv represents an alternative approach to wrapping OpenCV for openFrameworks. 4 | 5 | # Installation 6 | 7 | First, pick the branch that matches your version of openFrameworks: 8 | 9 | * OF [stable](https://github.com/openframeworks/openFrameworks/tree/stable) (0.9.8): use [ofxCv/stable](https://github.com/kylemcdonald/ofxCv/tree/stable) 10 | * OF [master](https://github.com/openframeworks/openFrameworks) (0.10.0): use [ofxCv/master](https://github.com/kylemcdonald/ofxCv/) 11 | 12 | Either clone out the source code using git: 13 | 14 | > cd openFrameworks/addons/ 15 | > git clone https://github.com/kylemcdonald/ofxCv.git 16 | 17 | Or download the source from GitHub [here](https://github.com/kylemcdonald/ofxCv/archive/master.zip), unzip the folder, rename it from `ofxCv-master` to `ofxCv` and place it in your `openFrameworks/addons` folder. 18 | 19 | To run the examples, import them into the project generator, create a new project, and open the project file in your IDE. 20 | 21 | # Goals 22 | 23 | ofxCv has a few goals driving its development. 24 | 25 | ### Wrap complex things in a helpful way 26 | 27 | Sometimes this means: providing wrapper functions that require fewer arguments than the real CV functions, providing a smart interface that handles dynamic memory allocation to make things faster for you, or providing in place and out of place alternatives. 28 | 29 | ### Present the power of OpenCv clearly 30 | 31 | This means naming things in an intuitive way, and, more importantly, providing classes that have methods that transform the data represented by that class. It also means providing demos of CV functions, and generally being more useful than ofxOpenCv. 32 | 33 | ### Interoperability of openFrameworks and OpenCv 34 | 35 | Making it easy to work directly with CV by providing lightweight conversion functions, and providing wrappers for CV functions that do the conversions for you. 36 | 37 | ### Elegant internal OpenCv code 38 | 39 | Provide clean implementations of all functions in order to provide a stepping stone to direct OpenCV use. This means using function names and variable names that follow the OpenCV documentation, and spending the time to learn proper CV usage so I can explain it clearly to others through code. Sometimes there will be heavy templating in order to make OF interoperable with OpenCV, but this should be avoided in favor of using straight OpenCV as often as possible. 40 | 41 | # Usage 42 | 43 | Sometimes this readme will fall out of date. Please refer to the examples as the primary reference in that case. 44 | 45 | ## Project setup 46 | 47 | Using ofxCv requires: 48 | 49 | * ofxCv/libs/ofxCv/include/ Which contains all the ofxCv headers. 50 | * ofxCv/libs/ofxCv/src/ Which contains all the ofxCv source. 51 | * ofxCv/src/ Which ties together all of ofxCv into a single include. 52 | * opencv/include/ The OpenCv headers, located in addons/ofxOpenCv/ 53 | * opencv/lib/ The precompiled static OpenCv libraries, located in addons/ofxOpenCv/ 54 | 55 | Your linker will also need to know where the OpenCv headers are. In XCode this means modifying one line in Project.xconfig: 56 | 57 | HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS) "../../../addons/ofxOpenCv/libs/opencv/include/" "../../../addons/ofxCv/libs/ofxCv/include/" 58 | 59 | Alternatively, I recommend using [OFXCodeMenu](https://github.com/openframeworks/OFXcodeMenu) to add ofxCv to your project. 60 | 61 | ## Including ofxCv 62 | 63 | Inside your ofApp.h you will need one include: 64 | 65 | #include "ofxCv.h" 66 | 67 | OpenCv uses the `cv` namespace, and ofxCv uses the `ofxCv` namespace. You can automatically import them by writing this in your `.cpp` files: 68 | 69 | using namespace cv; 70 | using namespace ofxCv; 71 | 72 | If you look inside the ofxCv source, you'll find lots of cases of `ofxCv::` and `cv::`. In some rare cases, you'll need to write `cv::` in your code. For example, on OSX `Rect` and `Point` are defined by OpenCv, but also `MacTypes.h`. So if you're using an OpenCv `Rect` or `Point` you'll need to say so explicitly with `cv::Rect` or `cv::Point` to disambiguate. 73 | 74 | ofxCv takes advantage of namespaces by using overloaded function names. This means that the ofxCv wrapper for `cv::Canny()` is also called `ofxCv::Canny()`. If you write simply `Canny()`, the correct function will be chosen based on the arguments you pass. 75 | 76 | ## Working with ofxCv 77 | 78 | Unlike ofxOpenCv, ofxCv encourages you to use either native openFrameworks types or native OpenCv types, rather than introducing a third type like `ofxCvImage`. To work with OF and OpenCv types in a fluid way, ofxCv includes the `toCv()` and `toOf()` functions. They provide the ability to convert openFrameworks data to OpenCv data and vice versa. For large data, like images, this is done by wrapping the data rather than copying it. For small data, like vectors, this is done by copying the data. 79 | 80 | The rest of ofxCv is mostly helper functions (for example, `threshold()`) and wrapper classes (for example, `Calibration`). 81 | 82 | ### toCv() and copy() 83 | 84 | `toCv()` is used to convert openFrameworks data to OpenCv data. For example: 85 | 86 | ofImage img; 87 | img.load("image.png"); 88 | Mat imgMat = toCv(img); 89 | 90 | This creates a wrapper for `img` called `imgMat`. To create a deep copy, use `clone()`: 91 | 92 | Mat imgMatClone = toCv(img).clone(); 93 | 94 | Or `copy()`, which works with any type supported by `toCv()`: 95 | 96 | Mat imgCopy; 97 | copy(img, imgCopy); 98 | 99 | `toCv()` is similar to ofxOpenCv's `ofxCvImage::getCvImage()` method, which returns an `IplImage*`. The biggest difference is that you can't always use `toCv()` "in place" when calling OpenCv code directly. In other words, you can always write this: 100 | 101 | Mat imgMat = toCv(img); 102 | cv::someFunction(imgMat, ...); 103 | 104 | But you should avoid using `toCv()` like this: 105 | 106 | cv::someFunction(toCv(img), ...); 107 | 108 | Because there are cases where in place usage will cause a compile error. More specifically, calling `toCv()` in place will fail if the function requires a non-const reference for that parameter. 109 | 110 | ### imitate() 111 | 112 | `imitate()` is primarily used internally by ofxCv. When doing CV, you regularly want to allocate multiple buffers of similar dimensions and channels. `imitate()` follows a kind of prototype pattern, where you pass a prototype image `original` and the image to be allocated `mirror` to `imitate(mirror, original)`. `imitate()` has two big advantages: 113 | 114 | * It works with `Mat`, `ofImage`, `ofPixels`, `ofVideoGrabber`, and anything else that extends `ofBaseHasPixels`. 115 | * It will only reallocate memory if necessary. This means it can be used liberally. 116 | 117 | If you are writing a function that returns data, the ofxCv style is to call `imitate()` on the data to be returned from inside the function, allocating it as necessary. 118 | 119 | ### drawMat() vs. toOf() 120 | 121 | Sometimes you want to draw a `Mat` to the screen directly, as quickly and easily as possible, and `drawMat()` will do this for you. `drawMat()` is not the most optimal way of drawing images to the screen, because it creates a texture every time it draws. If you want to draw things efficiently, you should allocate a texture using `ofImage img;` *once* and draw it using `img.draw()`. 122 | 123 | 1. Either use `Mat mat = toCv(img);` to treat the `ofImage` as a `Mat`, modify the `mat`, then `img.update()` to upload the modified pixels to the GPU. 124 | 2. Alternatively; call `toOf(mat, img)` each time after modifying the `Mat`. This will only reallocate the texture if necessary, e.g. when the size has changed. 125 | 126 | 127 | # Working with OpenCv 2 128 | 129 | OpenCv 2 is an incredibly well designed API, and ofxCv encourages you to use it directly. Here are some hints on using OpenCv. 130 | 131 | ### OpenCv Types 132 | 133 | OpenCv 2 uses the `Mat` class in place of the old `IplImage`. Memory allocation, copying, and deallocation are all handled automatically. `operator=` is a shallow, reference-counted copy. A `Mat` contains a collection of `Scalar` objects. A `Scalar` contains a collection of basic types (unsigned char, bool, double, etc.). `Scalar` is a short vector for representing color or other multidimensional information. The hierarchy is: `Mat` contains `Scalar`, `Scalar` contains basic types. 134 | 135 | Different functions accept `Mat` in different ways: 136 | 137 | * `Mat` will create a lightweight copy of the underlying data. It's easy to write, and it allows you to use `toCv()` "in-place" when passing arguments to the function. 138 | * `Mat&` allows the function to modify the header passed in. This means the function can allocate if necessary. 139 | * `const Mat&` means that the function isn't going to modify the underlying data. This should be used instead of `Mat` when possible. It also allows "in-place" `toCv()` usage. 140 | 141 | ### Mat creation 142 | 143 | If you're working with `Mat` directly, it's important to remember that OpenCv talks about `rows` and `cols` rather than `width` and `height`. This means that the arguments are "backwards" when they appear in the `Mat` constructor. Here's an example of creating a `Mat` wrapper for some grayscale `unsigned char* pixels` for which we know the `width` and `height`: 144 | 145 | Mat mat = Mat(height, width, CV_8UC1, pixels, 0); 146 | 147 | ### Mat operations 148 | 149 | Basic mathematical operations on `Mat` objects of the same size and type can be accomplished with matrix expressions. Matrix expressions are a collection of overloaded operators that accept `Mat`, `Scalar`, and basic types. A normal mathematical operation might look like: 150 | 151 | float x, a, b; 152 | ... 153 | x = (a + b) * 10; 154 | 155 | A matrix operation looks similar: 156 | 157 | Mat x, a, b; 158 | ... 159 | x = (a + b) * 10; 160 | 161 | This will add every element of `a` and `b`, then multiply the results by 10, and finally assign the result to `x`. 162 | 163 | Available matrix expressions include mathematical operators `+`, `-`, `/` (per element division), `*` (matrix multiplication), `.mul()` (per-element multiplication). As well as comparison operators `!=`, `==`, `<`, `>`, `>=`, `<=` (useful for thresholding). Binary operators `&`, `|`, `^`, `~`. And a few others like `abs()`, `min()`, and `max()`. For the complete listing see the OpenCv documention or `mat.hpp`. 164 | 165 | # Code Style 166 | 167 | ofxCv tries to have a consistent code style. It's most similar to the K&R variant used for Java, and the indentation is primarily determined by XCode's auto-indent feature. 168 | 169 | Multiline comments are used for anything beyond two lines. 170 | 171 | Case statements have a `default:` fall-through with the last case. 172 | 173 | When two or three similar variables are initialized, commas are used instead of multiple lines. For example `Mat srcMat = toCv(src), dstMat = toCv(dst);`. This style was inherited from reading Jason Saragih's FaceTracker. 174 | 175 | - - -- 176 | 177 | *ofxCv was developed with support from [Yamaguchi Center for Arts and Media](http://ycam.jp/).* 178 | -------------------------------------------------------------------------------- /src/ofxCv.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // cv 4 | #include "opencv2/opencv.hpp" 5 | 6 | // ofxCv 7 | 8 | // there are three types of functions in the ofxCv namespace 9 | #include "ofxCv/Utilities.h" // low-level utilities like imitate and toCv 10 | #include "ofxCv/Wrappers.h" // wrappers that accept toCv-compatible objects 11 | #include "ofxCv/Helpers.h" // helper functions that handle more complex tasks 12 | 13 | /* 14 | all functions guarantee the size of the output with imitate when possible. data 15 | is returned using arguments when an expensive copy would be required or when 16 | you want to use a preallocated buffer, and a return value is used when the data 17 | is small or there is probably no preallocated buffer. 18 | */ 19 | 20 | // also in the namespace are a few helper classes that make common tasks easier: 21 | #include "ofxCv/Distance.h" // edit distance 22 | #include "ofxCv/Calibration.h" // camera calibration 23 | #include "ofxCv/Tracker.h" // object tracking 24 | #include "ofxCv/ContourFinder.h" // contour finding and tracking 25 | #include "ofxCv/RunningBackground.h" // background subtraction 26 | #include "ofxCv/Flow.h" // optical flow, from james george 27 | #include "ofxCv/ObjectFinder.h" // object finding (e.g., face detection) 28 | #include "ofxCv/Kalman.h" // Kalman filter for smoothing 29 | 30 | // <3 kyle 31 | -------------------------------------------------------------------------------- /update-projects.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | 3 | import glob, re, shutil, fileinput, os 4 | 5 | def toUpper(pattern): 6 | return pattern.group(1).upper() 7 | 8 | def replaceInFile(filename, pattern, replacement): 9 | for line in fileinput.FileInput(filename, inplace=1): 10 | print re.sub(pattern, replacement, line), 11 | 12 | sourceProjectName = "EmptyExample" 13 | 14 | # windows code::blocks 15 | sourceCbp = "example-empty/EmptyExample.cbp" 16 | sourceWorkspace = "example-empty/EmptyExample.workspace" 17 | 18 | # windows vs2010 19 | sourceSln = "example-empty/EmptyExample.sln" 20 | sourceVcxproj = "example-empty/EmptyExample.vcxproj" 21 | sourceVcxprojFilters = "example-empty/EmptyExample.vcxproj.filters" 22 | sourceVcxprojUser = "example-empty/EmptyExample.vcxproj.user" 23 | 24 | # xcode osx 25 | sourceXcconfig = "example-empty/Project.xcconfig" 26 | sourcePlist = "example-empty/openFrameworks-Info.plist" 27 | sourceXcodeproj = "example-empty/ofApp.xcodeproj/" 28 | 29 | # linux 30 | sourceMakefile = "example-empty/Makefile" 31 | sourceConfigs = "example-empty/config.make" 32 | sourceAddons = "example-empty/addons.make" 33 | 34 | examples = glob.glob("example*") 35 | for example in examples: 36 | if example != "example-empty": 37 | sansExample = re.sub("^example", "", example) 38 | upper = re.sub("-([a-z])", toUpper, sansExample) 39 | targetProjectName = upper + "Example" 40 | 41 | #linux 42 | targetDir = "{0}/".format(example, targetProjectName) 43 | emptyDir = "example-empty" 44 | shutil.copy(sourceMakefile, targetDir) 45 | shutil.copy(sourceConfigs, targetDir) 46 | shutil.copy(sourceAddons, targetDir) 47 | 48 | # windows code::blocks 49 | targetCbp = "{0}/{1}.cbp".format(example, targetProjectName) 50 | targetWorkspace = "{0}/{1}.workspace".format(example, targetProjectName) 51 | shutil.copy(sourceCbp, targetCbp) 52 | shutil.copy(sourceWorkspace, targetWorkspace) 53 | replaceInFile(targetCbp, sourceProjectName, targetProjectName) 54 | replaceInFile(targetWorkspace, sourceProjectName, targetProjectName) 55 | 56 | # windows vs2010 57 | targetSln = "{0}/{1}.sln".format(example, targetProjectName) 58 | targetVcxproj = "{0}/{1}.vcxproj".format(example, targetProjectName) 59 | targetVcxprojFilters = "{0}/{1}.vcxproj.filters".format(example, targetProjectName) 60 | targetVcxprojUser = "{0}/{1}.vcxproj.user".format(example, targetProjectName) 61 | shutil.copy(sourceSln, targetSln) 62 | shutil.copy(sourceVcxproj, targetVcxproj) 63 | shutil.copy(sourceVcxprojFilters, targetVcxprojFilters) 64 | shutil.copy(sourceVcxprojUser, targetVcxprojUser) 65 | replaceInFile(targetSln, sourceProjectName, targetProjectName) 66 | replaceInFile(targetVcxproj, sourceProjectName, targetProjectName) 67 | 68 | # xcode osx 69 | targetXcodeproj = "{0}/ofApp.xcodeproj".format(example) 70 | shutil.copy(sourceXcconfig, example) 71 | shutil.copy(sourcePlist, example) 72 | try: shutil.rmtree(targetXcodeproj) 73 | except: pass 74 | shutil.copytree(sourceXcodeproj, targetXcodeproj) 75 | print "Copied into " + targetProjectName + "." 76 | --------------------------------------------------------------------------------