From 790dd853df12b0dac2892ac77a9786c191444b20 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Tue, 8 Oct 2013 17:01:16 +0000 Subject: first commit of new optical flow external svn path=/trunk/externals/pix_opencv/; revision=17219 --- pix_opencv_opticalflow.cc | 229 ++++++++++++++++++++++++++++++++++++++++++++++ pix_opencv_opticalflow.h | 96 +++++++++++++++++++ 2 files changed, 325 insertions(+) create mode 100644 pix_opencv_opticalflow.cc create mode 100644 pix_opencv_opticalflow.h diff --git a/pix_opencv_opticalflow.cc b/pix_opencv_opticalflow.cc new file mode 100644 index 0000000..cfce8f6 --- /dev/null +++ b/pix_opencv_opticalflow.cc @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////// +// +// GEM - Graphics Environment for Multimedia +// +// zmoelnig@iem.kug.ac.at +// +// Implementation file +// +// Copyright (c) 1997-2000 Mark Danks. +// Copyright (c) Günther Geiger. +// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM +// Copyright (c) 2002 James Tittle & Chris Clepper +// For information on usage and redistribution, and for a DISCLAIMER OF ALL +// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. +// +///////////////////////////////////////////////////////// +// based on code written by Lluis Gomez i Bigorda ( lluisgomez _at_ hangar _dot_ org ) (pix_opencv) +// pix_opencv_opticalflow compute optical flow, several algorithms are available in one object +// by Antoine Villeret - 2012 + +#include "pix_opencv_opticalflow.h" + +CPPEXTERN_NEW(pix_opencv_opticalflow) + +///////////////////////////////////////////////////////// +// +// pix_opencv_opticalflow +// +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// +pix_opencv_opticalflow :: pix_opencv_opticalflow() : m_gain(1.) +{ + m_dataout_middle = outlet_new(this->x_obj, 0); + m_dataout_right = outlet_new(this->x_obj, 0); + + //~ post("build on %s at %s", __DATE__, __TIME__); +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +pix_opencv_opticalflow :: ~pix_opencv_opticalflow() +{ +} + +///////////////////////////////////////////////////////// +// render +// +///////////////////////////////////////////////////////// +void pix_opencv_opticalflow :: processRGBAImage(imageStruct &image) +{ + if ( image.xsize <= 0 || image.ysize <= 0 ) return; + + cv::Mat rgbaImage( image.ysize, image.xsize, CV_8UC4, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data + //~cvtColor(rgbaImage, m_curr, cv::COLOR_RGBA2RGB); //convert RGBA to RGB + cvtColor(rgbaImage, m_curr, cv::COLOR_RGBA2GRAY); //convert RGBA to RGB + + if (m_prev.size() != m_curr.size()){ + m_prev = m_curr.clone(); + } + //~cv::calcOpticalFlowSF(m_curr, m_prev, m_flow, 3, 2, 4, 4.1, 25.5, 18, 55.0, 25.5, 0.35, 18, 55.0, 25.5, 10); + + cv::calcOpticalFlowFarneback(m_curr, m_prev, flow, 0.5, 3, 15, 3, 5, 1.2, 0); + m_prev = m_curr.clone(); // copy data + + cv::Size size = m_curr.size(); + // here is the idiom: check the arrays for continuity and, + // if this is the case, + // treat the arrays as 1D vectors + if( m_curr.isContinuous() && m_prev.isContinuous() && m_flow.isContinuous() ) + { + size.width *= size.height; + size.height = 1; + } + + float gain=m_gain; + if ( m_normalize ){ + float maxrad=1; + + for (int y = 0; y < flow.rows; ++y) + { + for (int x = 0; x < flow.cols; ++x) + { + cv::Point2f u = flow.at(x,y); + + if (!isFlowCorrect(u)) + continue; + float rad = sqrt(u.x * u.x + u.y * u.y); + maxrad = maxrad>rad?maxrad:rad; + } + } + gain=1/maxrad; + } + + for( int i = 0; i < size.height; i++ ) + { + // when the arrays are continuous, + // the outer loop is executed only once + const float* ptrFlow = flow.ptr(i); + unsigned char* data=image.data+i*image.csize*image.xsize; + + + for( int j = 0; j < 2*size.width; j+=2 ) + { + float fx = ptrFlow[j]; + float fy = ptrFlow[j+1]; + + cv::Vec3b pix; + + pix = computeColor(fx*gain, fy*gain); + + for ( int k = 0; k < 3; k++ ){ + data[k]=pix[k]; + } + //~printf("pix %d : %d\t%d\t%d\n",j+i*size.width, pix[0],pix[1], pix[2]); + //~m_colorcode.computeColor(fx, fy, data); + data+=4; + } + } +} + +///////////////////////////////////////////////////////// +// static member function +// +///////////////////////////////////////////////////////// +void pix_opencv_opticalflow :: obj_setupCallback(t_class *classPtr) +{ + CPPEXTERN_MSG1(classPtr, "gain", gainMess, double); + CPPEXTERN_MSG1(classPtr, "normalize", normalizeMess, double); +} + +///////////////////////////////////////////////////////// +// messages handling +// +///////////////////////////////////////////////////////// +void pix_opencv_opticalflow :: gainMess(double arg) +{ + m_gain = arg > 0 ? arg : 3.; +} + +void pix_opencv_opticalflow :: normalizeMess(double arg) +{ + m_normalize = arg > 0; +} + + + +/////////////////////////// +// static function for color coding +/////////////////////////// +using namespace cv; + +static cv::Vec3b computeColor(float fx, float fy) +{ +static bool first = true; + + // relative lengths of color transitions: + // these are chosen based on perceptual similarity + // (e.g. one can distinguish more shades between red and yellow + // than between yellow and green) + const int RY = 15; + const int YG = 6; + const int GC = 4; + const int CB = 11; + const int BM = 13; + const int MR = 6; + const int NCOLS = RY + YG + GC + CB + BM + MR; + static Vec3i colorWheel[NCOLS]; + + if (first) + { + int k = 0; + + for (int i = 0; i < RY; ++i, ++k) + colorWheel[k] = Vec3i(255, 255 * i / RY, 0); + + for (int i = 0; i < YG; ++i, ++k) + colorWheel[k] = Vec3i(255 - 255 * i / YG, 255, 0); + + for (int i = 0; i < GC; ++i, ++k) + colorWheel[k] = Vec3i(0, 255, 255 * i / GC); + + for (int i = 0; i < CB; ++i, ++k) + colorWheel[k] = Vec3i(0, 255 - 255 * i / CB, 255); + + for (int i = 0; i < BM; ++i, ++k) + colorWheel[k] = Vec3i(255 * i / BM, 0, 255); + + for (int i = 0; i < MR; ++i, ++k) + colorWheel[k] = Vec3i(255, 0, 255 - 255 * i / MR); + + first = false; + } + + const float rad = sqrt(fx * fx + fy * fy); + const float a = atan2(-fy, -fx) / (float) CV_PI; + + const float fk = (a + 1.0f) / 2.0f * (NCOLS - 1); + const int k0 = static_cast(fk); + const int k1 = (k0 + 1) % NCOLS; + const float f = fk - k0; + + Vec3b pix; + + for (int b = 0; b < 3; b++) + { + const float col0 = colorWheel[k0][b] / 255.0f; + const float col1 = colorWheel[k1][b] / 255.0f; + + float col = (1 - f) * col0 + f * col1; + + if (rad <= 1) + col = 1 - rad * (1 - col); // increase saturation with radius + else + col *= .75; // out of range + + pix[2 - b] = static_cast(255.0 * col); + } + + return pix; +} + +inline bool isFlowCorrect(cv::Point2f u) +{ + return !cvIsNaN(u.x) && !cvIsNaN(u.y) && fabs(u.x) < 1e9 && fabs(u.y) < 1e9; +} diff --git a/pix_opencv_opticalflow.h b/pix_opencv_opticalflow.h new file mode 100644 index 0000000..641f9c5 --- /dev/null +++ b/pix_opencv_opticalflow.h @@ -0,0 +1,96 @@ +/*----------------------------------------------------------------- +LOG + GEM - Graphics Environment for Multimedia + + Copyright (c) 1997-1999 Mark Danks. mark@danks.org + Copyright (c) Günther Geiger. geiger@epy.co.at + Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM. zmoelnig@iem.kug.ac.at + Copyright (c) 2002 James Tittle & Chris Clepper + For information on usage and redistribution, and for a DISCLAIMER OF ALL + WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. + +-----------------------------------------------------------------*/ + +#ifndef INCLUDE_PIX_OPENCV_OPTICALFLOW_H_ +#define INCLUDE_PIX_OPENCV_OPTICALFLOW_H_ + +#include "opencv2/opencv.hpp" +#include "Base/GemBase.h" +#include "Gem/Exception.h" +#include "Gem/State.h" +#include "Base/GemPixObj.h" +#include "RTE/MessageCallbacks.h" +#include + +/*----------------------------------------------------------------- +------------------------------------------------------------------- +CLASS + pix_opencv_opticalflow + apply a simple flow method to compute optical flow + +KEYWORDS + pix + +DESCRIPTION + +-----------------------------------------------------------------*/ + +//~class Colorcode +//~{ +//~// from colorcode.cpp by Daniel Scharstein, 4/2007 +//~// http://vision.middlebury.edu/flow/data/ +//~#define MAXCOLS 60 +//~ +//~public: + //~Colorcode(); + //~static cv::Vec3b computeColor(float fx, float fy); + //~ +//~private: + //~int ncols; + //~int colorwheel[MAXCOLS][3]; +//~ +//~ + //~void setcols(int r, int g, int b, int k); +//~ + //~void makecolorwheel(); +//~}; + +static cv::Vec3b computeColor(float fx, float fy); +inline bool isFlowCorrect(cv::Point2f u); + +class GEM_EXTERN pix_opencv_opticalflow : public GemPixObj +{ + CPPEXTERN_HEADER(pix_opencv_opticalflow, GemPixObj) + + public: + + ////////// + // Constructor + pix_opencv_opticalflow(); + + protected: + + ////////// + // Destructor + virtual ~pix_opencv_opticalflow(); + + ////////// + // Do the processing + virtual void processRGBAImage(imageStruct &image); + + // Messages handling + void gainMess(double arg); + void normalizeMess(double arg); + + private: + + cv::Mat prev, flow; + t_float m_gain; + bool m_normalize; + + cv::Mat m_prev, m_curr, m_flow; + + t_outlet *m_dataout_middle; // contour outlet + t_outlet *m_dataout_right; // info outlet +}; +#endif // for header file -- cgit v1.2.1