Skip to content

Commit 38fa6b8

Browse files
committed
wrapper for optical flow (specifically Farneback dense technique, but designed to be extensible)
1 parent b8180f6 commit 38fa6b8

5 files changed

Lines changed: 242 additions & 3 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import gab.opencv.*;
2+
import processing.video.*;
3+
4+
OpenCV opencv;
5+
Movie video;
6+
7+
void setup() {
8+
size(568*2, 320);
9+
video = new Movie(this, "sample1.mov");
10+
opencv = new OpenCV(this, 568, 320);
11+
video.loop();
12+
video.play();
13+
}
14+
15+
void draw() {
16+
background(0);
17+
opencv.loadImage(video);
18+
opencv.calculateOpticalFlow();
19+
20+
image(video, 0, 0);
21+
translate(video.width,0);
22+
stroke(255,0,0);
23+
opencv.drawOpticalFlow();
24+
25+
PVector aveFlow = opencv.getAverageFlow();
26+
int flowScale = 50;
27+
28+
stroke(255);
29+
strokeWeight(2);
30+
line(video.width/2, video.height/2, video.width/2 + aveFlow.x*flowScale, video.height/2 + aveFlow.y*flowScale);
31+
}
32+
33+
void movieEvent(Movie m) {
34+
m.read();
35+
}
36+
2.32 MB
Binary file not shown.

resources/build.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,20 @@ source.repository=https://github.com/atduskgreg/OpenCVPro
149149
# This is used to compare different versions of the same library, and check if
150150
# an update is available.
151151

152-
library.version=11
152+
library.version=12
153153

154154

155155
# The version as the user will see it.
156156

157-
library.prettyVersion=0.5.0
157+
library.prettyVersion=0.5.1
158158

159159

160160
library.copyright=(c) 2013
161161
library.dependencies=?
162162
library.keywords=?
163163

164164
tested.platform=osx,windows7
165-
tested.processingVersion=2.1.12
165+
tested.processingVersion=2.2.1
166166

167167

168168
# Include javadoc references into your project's javadocs.

src/gab/opencv/Flow.java

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package gab.opencv;
2+
3+
import processing.core.*;
4+
import java.awt.Rectangle;
5+
6+
import org.opencv.video.Video;
7+
import org.opencv.core.Mat;
8+
import org.opencv.core.CvType;
9+
import org.opencv.core.Core;
10+
import org.opencv.core.Scalar;
11+
12+
public class Flow {
13+
14+
private Mat prev;
15+
private Mat flow;
16+
private boolean hasFlow = false;
17+
private double pyramidScale = 0.5;
18+
private int nLevels = 4;
19+
private int windowSize = 8;
20+
private int nIterations = 2;
21+
private int polyN = 7;
22+
private double polySigma = 1.5;
23+
private int runningFlags = Video.OPTFLOW_FARNEBACK_GAUSSIAN;
24+
private PApplet parent;
25+
26+
public Flow(PApplet parent) {
27+
flow = new Mat();
28+
this.parent = parent;
29+
}
30+
31+
public int width(){
32+
return flow.width();
33+
}
34+
35+
public int height(){
36+
return flow.height();
37+
}
38+
39+
public boolean hasFlow(){
40+
return hasFlow;
41+
}
42+
43+
public void calculateOpticalFlow(Mat m) {
44+
int flags = runningFlags;
45+
if (!hasFlow) {
46+
prev = m.clone();
47+
flags = Video.OPTFLOW_USE_INITIAL_FLOW;
48+
hasFlow = true;
49+
}
50+
Video.calcOpticalFlowFarneback(prev, m, flow, pyramidScale, nLevels, windowSize, nIterations, polyN, polySigma, flags);
51+
prev = m.clone();
52+
}
53+
54+
public PVector getTotalFlowInRegion(int x, int y, int w, int h) {
55+
Mat region = flow.submat(y, y+h, x, x+w);
56+
Scalar total = Core.sumElems(region);
57+
return new PVector((float)total.val[0], (float)total.val[1]);
58+
}
59+
60+
public PVector getAverageFlowInRegion(int x, int y, int w, int h) {
61+
PVector total = getTotalFlowInRegion(x, y, w, h);
62+
return new PVector(total.x/(flow.width() * flow.height()), total.y/(flow.width()*flow.height()));
63+
}
64+
65+
public PVector getTotalFlow() {
66+
return getTotalFlowInRegion(0, 0, flow.width(), flow.height());
67+
}
68+
69+
public PVector getAverageFlow() {
70+
return getAverageFlowInRegion(0, 0, flow.width(), flow.height());
71+
}
72+
73+
public PVector getFlowAt(int x, int y){
74+
return new PVector((float)flow.get(y, x)[0], (float)flow.get(y, x)[1]);
75+
}
76+
77+
public void draw() {
78+
int stepSize = 4;
79+
80+
for (int y = 0; y < flow.height(); y+=stepSize) {
81+
for (int x = 0; x < flow.width(); x+=stepSize) {
82+
PVector flowVec = getFlowAt(x,y);
83+
parent.line(x, y, x+flowVec.x, y+flowVec.y);
84+
}
85+
}
86+
}
87+
88+
public void setPyramidScale(double v){
89+
pyramidScale = v;
90+
}
91+
92+
public double getPyramidScale(){
93+
return pyramidScale;
94+
}
95+
96+
public void setLevels(int n){
97+
nLevels = n;
98+
}
99+
100+
public int getLevels(){
101+
return nLevels;
102+
}
103+
104+
public void setWindowSize(int s){
105+
windowSize = s;
106+
}
107+
108+
public int getWindowSize(){
109+
return windowSize;
110+
}
111+
112+
public void setIterations(int i){
113+
nIterations = i;
114+
}
115+
116+
public int getIterations(){
117+
return nIterations;
118+
}
119+
120+
public void setPolyN(int n){
121+
polyN = n;
122+
}
123+
124+
public int getPolyN(){
125+
return polyN;
126+
}
127+
128+
public void setPolySigma(double s){
129+
polySigma = s;
130+
}
131+
132+
public double getPolySigma(){
133+
return polySigma;
134+
}
135+
}

src/gab/opencv/OpenCV.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import gab.opencv.ContourComparator;
3434
import gab.opencv.Histogram;
3535
import gab.opencv.Line;
36+
import gab.opencv.Flow;
3637

3738
import java.awt.Rectangle;
3839
import java.awt.image.BufferedImage;
@@ -108,6 +109,7 @@ public class OpenCV {
108109

109110
public CascadeClassifier classifier;
110111
BackgroundSubtractorMOG backgroundSubtractor;
112+
public Flow flow;
111113

112114
public final static String VERSION = "##library.prettyVersion##";
113115
public final static String CASCADE_FRONTALFACE = "haarcascade_frontalface_alt.xml";
@@ -338,6 +340,7 @@ private void init(int w, int h){
338340
height = h;
339341
welcome();
340342
setupWorkingImages();
343+
setupFlow();
341344

342345
matR = new Mat(height, width, CvType.CV_8UC1);
343346
matG = new Mat(height, width, CvType.CV_8UC1);
@@ -348,6 +351,10 @@ private void init(int w, int h){
348351
matBGRA = new Mat(height, width, CvType.CV_8UC4);
349352
}
350353

354+
private void setupFlow(){
355+
flow = new Flow(parent);
356+
}
357+
351358
private void setupWorkingImages(){
352359
outputImage = parent.createImage(width,height, PConstants.ARGB);
353360
}
@@ -594,6 +601,67 @@ public void updateBackground(){
594601
setGray(foreground);
595602
}
596603

604+
/**
605+
* Calculate the optical flow of the current image relative
606+
* to a running series of images (typically frames from video).
607+
* Optical flow is useful for detecting what parts of the image
608+
* are moving and in what direction.
609+
*
610+
*/
611+
public void calculateOpticalFlow(){
612+
flow.calculateOpticalFlow(getCurrentMat());
613+
}
614+
615+
/*
616+
* Get the total optical flow within a region of the image.
617+
* Be sure to call calculateOpticalFlow() first.
618+
*
619+
*/
620+
public PVector getTotalFlowInRegion(int x, int y, int w, int h) {
621+
return flow.getTotalFlowInRegion(x, y, w, h);
622+
}
623+
624+
/*
625+
* Get the average optical flow within a region of the image.
626+
* Be sure to call calculateOpticalFlow() first.
627+
*
628+
*/
629+
public PVector getAverageFlowInRegion(int x, int y, int w, int h) {
630+
return flow.getAverageFlowInRegion(x,y,w,h);
631+
}
632+
633+
/*
634+
* Get the total optical flow for the entire image.
635+
* Be sure to call calculateOpticalFlow() first.
636+
*/
637+
public PVector getTotalFlow() {
638+
return flow.getTotalFlow();
639+
}
640+
641+
/*
642+
* Get the average optical flow for the entire image.
643+
* Be sure to call calculateOpticalFlow() first.
644+
*/
645+
public PVector getAverageFlow() {
646+
return flow.getAverageFlow();
647+
}
648+
649+
/*
650+
* Get the optical flow at a single point in the image.
651+
* Be sure to call calcuateOpticalFlow() first.
652+
*/
653+
public PVector getFlowAt(int x, int y){
654+
return flow.getFlowAt(x,y);
655+
}
656+
657+
/*
658+
* Draw the optical flow.
659+
* Be sure to call calcuateOpticalFlow() first.
660+
*/
661+
public void drawOpticalFlow(){
662+
flow.draw();
663+
}
664+
597665
/**
598666
* Flip the current image.
599667
*

0 commit comments

Comments
 (0)