Index: /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.cpp
===================================================================
--- /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.cpp	(revision 324)
+++ /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.cpp	(revision 325)
@@ -77,24 +77,10 @@
   DataPlot1D* xVelocityPlot=new DataPlot1D(opticalFlowTab->NewRow(),"x speed (px/s)",-250,250);
   DataPlot1D* yVelocityPlot=new DataPlot1D(opticalFlowTab->LastRowLastCol(),"y speed (px/s)",-250,250);
-  DataPlot1D* xFirstPointPlot=new DataPlot1D(opticalFlowTab->NewRow(),"x movement first point",-25,25);
-  DataPlot1D* yFirstPointPlot=new DataPlot1D(opticalFlowTab->LastRowLastCol(),"y movement first point",-25,25);
-//  DataPlot1D* xAccelerationPlot=new DataPlot1D(opticalFlowTab->NewRow(),"x_acceleration",-250,250);
-//  DataPlot1D* yAccelerationPlot=new DataPlot1D(opticalFlowTab->LastRowLastCol(),"y_acceleration",-250,250);
-
+  
   xVelocityPlot->AddCurve(opticalFlowSpeedRaw->Output()->Element(0,0));
   xVelocityPlot->AddCurve(opticalFlowSpeed->GetMatrix()->Element(0,0),DataPlot::Blue);
   yVelocityPlot->AddCurve(opticalFlowSpeedRaw->Output()->Element(1,0));
   yVelocityPlot->AddCurve(opticalFlowSpeed->GetMatrix()->Element(1,0),DataPlot::Blue);
-  xFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(0,0));
-  xFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(1,0),DataPlot::Blue);
-  xFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(2,0),DataPlot::Green);
-  yFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(0,1));
-  yFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(1,1),DataPlot::Blue);
-  yFirstPointPlot->AddCurve(opticalFlowCompensated->GetFirstPointDisplacement()->Element(2,1),DataPlot::Green);
-//  xAccelerationPlot->AddCurve(opticalFlowAccelerationRaw->Matrix()->Element(0,0));
-//  xAccelerationPlot->AddCurve(opticalFlowAcceleration->Matrix()->Element(0,0),DataPlot::Blue);
-//  yAccelerationPlot->AddCurve(opticalFlowAccelerationRaw->Matrix()->Element(1,0));
-//  yAccelerationPlot->AddCurve(opticalFlowAcceleration->Matrix()->Element(1,0),DataPlot::Blue);
-
+  
   u_x=new Pid(setupLawTab->At(1,0),"u_x");
   u_x->UseDefaultPlot(graphLawTab->NewRow());
Index: /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.h
===================================================================
--- /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.h	(revision 324)
+++ /branches/sanscv/demos/OpticalFlow/uav/src/DemoOpticalFlow.h	(revision 325)
@@ -65,5 +65,5 @@
         flair::filter::OpticalFlowCompensated *opticalFlowCompensated;
         flair::filter::OpticalFlowSpeed *opticalFlowSpeedRaw;
-        flair::filter::EulerDerivative *opticalFlowAccelerationRaw;
+        //flair::filter::EulerDerivative *opticalFlowAccelerationRaw;
     flair::gui::PushButton *startOpticalflow,*stopOpticalflow;
     void StartOpticalFlow(void);
Index: /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.cpp	(revision 325)
@@ -13,5 +13,7 @@
 
 #include "CvtColor.h"
+#include "VisionFilter.h"
 #include <Image.h>
+//#include <dspcv_gpp.h>
 #include <typeinfo>
 
@@ -19,36 +21,99 @@
 using namespace flair::core;
 
+class CvtColor_impl {
+public:
+    CvtColor_impl(flair::filter::CvtColor *self,flair::filter::CvtColor::Conversion_t conversion):output(0) {
+        this->conversion=conversion;
+        this->self=self;
+
+        switch(conversion) {
+        case flair::filter::CvtColor::Conversion_t::ToGray:
+            try{
+                Image::Type const &imageType=dynamic_cast<Image::Type const &>(((IODevice*)(self->Parent()))->GetOutputDataType());
+                output=new Image(self,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray,"conversion",true,2);
+                //inIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+                //outIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+            } catch(std::bad_cast& bc) {
+                self->Err("io type mismatch\n");
+            }
+            break;
+        default:
+            self->Err("conversion not supported\n");
+        }
+    }
+
+    ~CvtColor_impl() {
+        //FreeFunction((char*)(inIplImage));
+        //FreeFunction((char*)(outIplImage));
+    }
+    
+    void UpdateFrom(const io_data *data){
+        Image *img=(Image*)data;
+
+        if(output!=NULL) {
+            data->GetMutex();/*
+            inIplImage->width=img->GetDataType().GetWidth();
+            inIplImage->height=img->GetDataType().GetHeight();
+            inIplImage->imageData=img->buffer;
+            */
+            output->GetMutex();/*
+            outIplImage->width=output->GetDataType().GetWidth();
+            outIplImage->height=output->GetDataType().GetHeight();
+            outIplImage->imageData=output->buffer;
+*/
+            switch(conversion) {
+            case flair::filter::CvtColor::Conversion_t::ToGray:
+                switch(((Image*)data)->GetDataType().GetFormat()) {
+                case Image::Type::Format::YUYV:
+                    //dspCvtColor(inIplImage,outIplImage,DSP_YUYV2GRAY);
+                    break;
+                case Image::Type::Format::UYVY:
+                    //dspCvtColor(inIplImage,outIplImage,DSP_UYVY2GRAY);
+                    break;
+                case Image::Type::Format::BGR:
+                    //dspCvtColor(inIplImage,outIplImage,DSP_BGR2GRAY);
+                    break;
+                default:
+                    self->Err("input format not supported\n");
+                }
+                break;
+            default:
+                self->Err("conversion not supported\n");
+            }
+
+            output->ReleaseMutex();
+            data->ReleaseMutex();
+
+            output->SetDataTime(data->DataTime());
+        }
+    };
+    
+    Image *output;
+
+private:
+    flair::filter::CvtColor::Conversion_t conversion;
+    //IplImage *inIplImage,*outIplImage;
+    flair::filter::CvtColor *self;
+};
+
+
 namespace flair { namespace filter {
 
-CvtColor::CvtColor(const core::IODevice* parent,std::string name,Conversion_t conversion) : IODevice(parent,name),output(0) {
-    this->conversion=conversion;
-
-    switch(conversion) {
-    case Conversion_t::ToGray:
-        try{
-            Image::Type const &imageType=dynamic_cast<Image::Type const &>(parent->GetOutputDataType());
-            output=new Image(this,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray,"conversion",true,2);
-
-        } catch(std::bad_cast& bc) {
-            Err("io type mismatch\n");
-        }
-        break;
-    default:
-        Err("conversion not supported\n");
-    }
-    
-    SetIsReady(true);
+CvtColor::CvtColor(const core::IODevice* parent,std::string name,Conversion_t conversion) : IODevice(parent,name) {
+    pimpl_=new CvtColor_impl(this,conversion);
 }
 
-CvtColor::~CvtColor(void) {}
+CvtColor::~CvtColor(void) {
+    delete pimpl_;
+}
 
 Image* CvtColor::Output(void) {
-    return output;
+    return pimpl_->output;
 
 }
 
 DataType const &CvtColor::GetOutputDataType() const {
-    if(output!=NULL) {
-        return output->GetDataType();
+    if(pimpl_->output!=NULL) {
+        return pimpl_->output->GetDataType();
     } else {
         return dummyType;
@@ -57,34 +122,7 @@
 
 void CvtColor::UpdateFrom(const io_data *data) {
-    Image *img=(Image*)data;
-
-    data->GetMutex();
-    output->GetMutex();
-
-    switch(conversion) {
-    case Conversion_t::ToGray:
-        switch(img->GetDataType().GetFormat()) {
-        case Image::Type::Format::YUYV:
-            //dspCvtColor(img,output->img,DSP_YUYV2GRAY);
-            break;
-        case Image::Type::Format::UYVY:
-            //dspCvtColor(img,output->img,DSP_UYVY2GRAY);
-            break;
-        case Image::Type::Format::BGR:
-            //dspCvtColor(img,output->img,DSP_BGR2GRAY);
-            break;
-        default:
-            Err("input format not supported\n");
-        }
-        break;
-    default:
-        Err("conversion not supported\n");
-    }
-
-    output->ReleaseMutex();
-    data->ReleaseMutex();
-
-    output->SetDataTime(data->DataTime());
-    ProcessUpdate(output);
+    pimpl_->UpdateFrom(data);
+    if(pimpl_->output!=NULL) ProcessUpdate(pimpl_->output);
+    
 }
 
Index: /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/CvtColor.h	(revision 325)
@@ -13,14 +13,13 @@
 #include <IODevice.h>
 
-namespace flair
-{
-    namespace core
-    {
+namespace flair {
+    namespace core {
         class Image;
     }
 }
 
-namespace flair
-{
+class CvtColor_impl;
+
+namespace flair {
 namespace filter
 {
@@ -82,6 +81,5 @@
             void UpdateFrom(const core::io_data *data);
 
-            core::Image *output;
-            Conversion_t conversion;
+            class CvtColor_impl *pimpl_;
     };
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.cpp	(revision 325)
@@ -13,5 +13,7 @@
 
 #include "HoughLines.h"
+#include "VisionFilter.h"
 #include <Image.h>
+#include <OneAxisRotation.h>
 #include <Matrix.h>
 #include <Layout.h>
@@ -19,5 +21,7 @@
 #include <SpinBox.h>
 #include <DoubleSpinBox.h>
+//#include <dspcv_gpp.h>
 #include <typeinfo>
+#include <math.h>
 
 #define MAX_LINES 100
@@ -27,56 +31,221 @@
 using namespace flair::gui;
 
+class HoughLines_impl {
+public:
+    HoughLines_impl(flair::filter::HoughLines *self,const LayoutPosition* position,string name,const Vector2Df *inPtRefGlobal,float inThetaRefGlobal) {
+        this->self=self;
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        rotation=new OneAxisRotation(reglages_groupbox->NewRow(),"pre rotation",OneAxisRotation::PostRotation);
+        fullRhoStep=new SpinBox(reglages_groupbox->NewRow(),"full rho step:","pixels",0,255,1,1);
+        fullThetaStep=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"full theta step:","degrees",0,90,1,1);
+        trackingRhoStep=new SpinBox(reglages_groupbox->NewRow(),"tracking rho step:","pixels",0,255,1,1);
+        trackingThetaStep=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"tracking theta step:","degrees",0,90,1,1);
+        trackingDeltaTheta=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"tracking delta theta:","degrees",0,90,1,1);
+        nbPoints=new SpinBox(reglages_groupbox->NewRow(),"nb points:",0,10000,10,100);
+
+        isTracking=false;
+        //linesStorage = (CvMat*)AllocFunction(sizeof(CvMat));
+        //linesStorage->data.fl = (float*)AllocFunction(MAX_LINES*2*sizeof(float));//was CV_32FC2, 2 channels
+        //gimg = (IplImage*)AllocFunction(sizeof(IplImage));
+
+        //init output matrix of same size as init
+        MatrixDescriptor* desc=new MatrixDescriptor(4,1);
+        desc->SetElementName(0,0,"distance");
+        desc->SetElementName(1,0,"orientation rad");
+        desc->SetElementName(2,0,"orientation deg");
+        desc->SetElementName(3,0,"line_detected");
+        output=new Matrix(self,desc,floatType,name);
+        delete desc;
+
+        try{
+            Image::Type const &imageType=dynamic_cast<Image::Type const &>(((IODevice*)(self->Parent()))->GetOutputDataType());
+            if(imageType.GetFormat()!=Image::Type::Format::Gray) {
+                self->Err("input image is not gray\n");
+            }
+        } catch(std::bad_cast& bc) {
+            self->Err("io type mismatch\n");
+        }
+
+        thetaRefGlobal=inThetaRefGlobal;
+        if (inPtRefGlobal==NULL) {
+            ptRefGlobal=NULL;
+        } else { //rotation from global coordinates to hough space
+            ptRefGlobal =new Vector2Df(inPtRefGlobal->x,inPtRefGlobal->y);
+        }
+        
+    }
+
+    ~HoughLines_impl() {
+        //FreeFunction((char*)(linesStorage->data.fl));
+        //FreeFunction((char*)linesStorage);
+        //FreeFunction((char*)gimg);
+        if(ptRefGlobal!=NULL) delete ptRefGlobal;
+    }
+    
+    void UpdateFrom(const io_data *data){
+        Image *img=(Image*)data;
+  /*
+        gimg->width=img->GetDataType().GetWidth();
+        gimg->height=img->GetDataType().GetHeight();
+        gimg->imageData=img->buffer;
+    
+        size_t nbLines;
+        Vector2Df ptRef;
+        float thetaRef;
+
+        if (ptRefGlobal==NULL) {
+          ptRef.x=img->GetDataType().GetWidth()/2;
+          ptRef.y=img->GetDataType().GetHeight()/2;
+        } else { //rotation from global coordinates to hough space
+          Vector3Df ptRef3D(ptRefGlobal->x,ptRefGlobal->y,0);
+          rotation->ComputeRotation(ptRef3D);
+          ptRef.x=ptRef3D.x;
+          ptRef.y=ptRef3D.y;
+        }
+          
+        //orientation in global space is rotated by pi/2 compared to orientation in hough space
+        //eg: vertical line has a 0 orientation in global space (north), but a pi/2 (or -pi/2) orientation in hough space (theta)
+        thetaRef=thetaRefGlobal+CV_PI/2+rotation->GetAngle();
+        if (thetaRef>CV_PI) thetaRef-=CV_PI;
+        if (thetaRef<0) thetaRef+=CV_PI;
+
+        data->GetMutex();
+        if(!isTracking) {
+        nbLines=dspHoughLines2(gimg,linesStorage,CV_HOUGH_STANDARD,
+                                fullRhoStep->Value(),fullThetaStep->Value()*CV_PI/180,
+                                nbPoints->Value());
+        } else {
+        nbLines=dspHoughLinesTracking(gimg,linesStorage,CV_HOUGH_STANDARD,
+                                     trackingRhoStep->Value(),
+                                     theta,trackingDeltaTheta->Value()*CV_PI/180,
+                                     trackingThetaStep->Value()*CV_PI/180,
+                                     nbPoints->Value());
+        //        nbLines=dspHoughLines2_test(gimg,linesStorage,CV_HOUGH_STANDARD,trackingRhoStep->Value(),thetaPrev-trackingDeltaTheta->Value()*CV_PI/180,thetaPrev+trackingDeltaTheta->Value()*CV_PI/180,trackingThetaStep->Value()*CV_PI/180,nbPoints->Value());
+        }
+        data->ReleaseMutex();
+
+        //saturation sur le nb max de ligne, au cas ou le DSP n'aurait pas la meme valeur
+        if(nbLines>MAX_LINES) {
+            self->Warn("erreur nb lines %u>%u\n",nbLines,MAX_LINES);
+            nbLines=MAX_LINES;
+        }
+        float rho;
+        bool noLine=!SelectBestLine(linesStorage,nbLines,rho,theta);
+
+        if (noLine) {
+            isTracking=false;
+        } else {
+            isTracking=true;
+        //        float thetaRef=0;
+
+            //line equation is ax+by+c=0 with a=cos(theta), b=sin(theta) and c=-rho
+            //distance from point xRef,yRef to the line is (a.xRef+b.yRef+c)/sqrt(a*a+b*b)
+            distance=-(cosf(theta)*ptRef.x+sinf(theta)*ptRef.y-rho);
+
+            orientation=theta-thetaRef;
+            if (orientation<-CV_PI/2) {
+              orientation+=CV_PI;
+              distance=-distance;
+            }
+            if (orientation>CV_PI/2) {
+              orientation-=CV_PI;
+              distance=-distance;
+            }
+
+            //printf("=> pour theta=%f et rho=%f, distance au point(%f,%f)=%f\n",theta,rho,xRef,yRef,distance);
+        }
+
+        output->GetMutex();
+        output->SetValueNoMutex(0,0,distance);
+        output->SetValueNoMutex(1,0,orientation);
+        output->SetValueNoMutex(2,0,orientation*180/CV_PI);
+        if(noLine) {
+            output->SetValueNoMutex(3,0,0);
+        } else {
+            output->SetValueNoMutex(3,0,1);
+        }
+        output->ReleaseMutex();
+*/
+        output->SetDataTime(data->DataTime());
+    };
+    
+    Matrix *output;
+    
+private:/*
+    //select best line. Returns false if no line found
+    bool SelectBestLine(CvMat* linesStorage, size_t nbLines, float &rho, float &theta) {
+      if(nbLines==0) {
+        return false;
+      }
+      //one line is found
+      if (nbLines==1) {
+        rho=linesStorage->data.fl[0];
+        theta=linesStorage->data.fl[1];
+        //printf("rho=%f,theta=%f (one line)\n",rho,theta);
+        return true;
+      }
+      //lines are ordered by quality, the first one will be our reference
+      float thetaRef=linesStorage->data.fl[1];
+      float thetaRefErrorSum=0;
+      float rhoSum=linesStorage->data.fl[0];
+      //printf("rho=%f,theta=%f (first of multilines)\n",rhoSum,thetaRef);
+      for(int i=1;i<nbLines;i++) {
+        //printf("rho=%f,theta=%f (multilines)\n",linesStorage->data.fl[2*i],linesStorage->data.fl[2*i+1]);
+        float thetaDiff=linesStorage->data.fl[2*i+1]-thetaRef;
+        float rhoLine=linesStorage->data.fl[2*i];
+        if (thetaDiff>CV_PI/2) {
+          thetaDiff-=CV_PI;
+          rhoLine=-rhoLine;
+        } else if (thetaDiff<-CV_PI/2) {
+          thetaDiff+=CV_PI;
+          rhoLine=-rhoLine;
+        }
+        thetaRefErrorSum += thetaDiff;
+        rhoSum+=rhoLine;
+      }
+      rho=rhoSum/nbLines;
+      theta=thetaRef+thetaRefErrorSum/nbLines;
+      if (theta<0) {
+        theta+=CV_PI;
+        rho=-rho;
+      }
+      if (theta>CV_PI) {
+        theta-=CV_PI;
+        rho=-rho;
+      }
+      return true;
+    }
+*/
+    flair::filter::HoughLines *self;
+    OneAxisRotation* rotation;
+    SpinBox *fullRhoStep,*trackingRhoStep,*nbPoints;
+    DoubleSpinBox *fullThetaStep,*trackingThetaStep,*trackingDeltaTheta;
+    bool isTracking;
+    float theta;
+    float distance,orientation;
+    Vector2Df* ptRefGlobal;
+    float thetaRefGlobal;
+    //CvMat* linesStorage;
+    //IplImage *gimg;
+};
+
 namespace flair { namespace filter {
 
-HoughLines::HoughLines(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name) {
-    GroupBox* reglages_groupbox=new GroupBox(position,name);
-    fullRhoStep=new SpinBox(reglages_groupbox->NewRow(),"full rho step:","pixels",0,255,1,1);
-    fullThetaStep=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"full theta step:","degrees",0,90,1,1);
-    trackingRhoStep=new SpinBox(reglages_groupbox->NewRow(),"tracking rho step:","pixels",0,255,1,1);
-    trackingThetaStep=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"tracking theta step:","degrees",0,90,1,1);
-    trackingDeltaTheta=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"tracking delta theta:","degrees",0,90,1,1);
-    nbPoints=new SpinBox(reglages_groupbox->NewRow(),"nb points:",0,10000,10,100);
-
-    isTracking=false;
-    lostLine=false;
-    initLine=false;
-    linesStorage = (CvMat*)malloc(sizeof(CvMat));
-    linesStorage->data.fl = (float*)malloc(MAX_LINES*2*sizeof(float));//was CV_32FC2, 2 channels
-
-
-    //init output matrix of same size as init
-    MatrixDescriptor* desc=new MatrixDescriptor(4,1);
-    desc->SetElementName(0,0,"distance");
-    desc->SetElementName(1,0,"orientation rad");
-    desc->SetElementName(2,0,"orientation deg");
-    desc->SetElementName(3,0,"line_detected");
-    output=new Matrix(this,desc,floatType,name);
-    delete desc;
-
-    try{
-        Image::Type const &imageType=dynamic_cast<Image::Type const &>(parent->GetOutputDataType());
-        if(imageType.GetFormat()!=Image::Type::Format::Gray) {
-            Err("input image is not gray\n");
-            return;
-        }
-    } catch(std::bad_cast& bc) {
-        Err("io type mismatch\n");
-        return;
-    }
-    
-    SetIsReady(true);
+HoughLines::HoughLines(const IODevice* parent,const LayoutPosition* position,string name,const Vector2Df *inPtRefGlobal,float inThetaRefGlobal) : IODevice(parent,name) {
+  pimpl_=new HoughLines_impl(this,position,name,inPtRefGlobal,inThetaRefGlobal);
+   
 }
 
 HoughLines::~HoughLines(void) {
-    free((char*)(linesStorage->data.fl));
-    free((char*)linesStorage);
+   delete  pimpl_;
 }
 
 void HoughLines::UpdateFrom(const io_data *data) {
- 
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
 }
 
 bool HoughLines::isLineDetected() const {
-    if(output->Value(3,0)==1) {
+    if(pimpl_->output->Value(3,0)==1) {
         return true;
     } else {
@@ -86,13 +255,13 @@
 
 float HoughLines::GetOrientation(void) const {
-    return output->Value(1,0);
+    return pimpl_->output->Value(1,0);
 }
 
 float HoughLines::GetDistance(void) const {
-    return output->Value(0,0);
+    return pimpl_->output->Value(0,0);
 }
 
 Matrix *HoughLines::Output(void) const {
-    return output;
+    return pimpl_->output;
 }
 
Index: /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/HoughLines.h	(revision 325)
@@ -12,17 +12,16 @@
 
 #include <IODevice.h>
-#include <cvtypes.h>
+#include <Vector2D.h>
 
 namespace flair {
     namespace core {
-        class Image;
         class Matrix;
     }
     namespace gui {
         class LayoutPosition;
-        class SpinBox;
-        class DoubleSpinBox;
     }
 }
+
+class HoughLines_impl;
 
 namespace flair { namespace filter {
@@ -44,6 +43,8 @@
             * \param position position
             * \param name name
+            * \param ptRefGlobal reference point used to compute distance to the line
+            * \param thetaRefGlobal reference angle used to compute orientation in range [-pi/2,pi/2]. Default value is 0 which defines a vertical line
             */
-            HoughLines(const core::IODevice* parent,const gui::LayoutPosition* position,std::string name);
+            HoughLines(const core::IODevice* parent,const gui::LayoutPosition* position,std::string name,const core::Vector2Df *ptRefGlobal=NULL,float thetaRefGlobal=0);
 
             /*!
@@ -60,14 +61,7 @@
         private:
             void UpdateFrom(const core::io_data *data);
-            gui::SpinBox *fullRhoStep,*trackingRhoStep,*nbPoints;
-            gui::DoubleSpinBox *fullThetaStep,*trackingThetaStep,*trackingDeltaTheta;
-            bool isTracking,lostLine,initLine,noLine;
-            int nbLines;
-            float yawMean,prevYawMean;
-            float prevRhoMean,rhoMean;
-            float prevThetaMean,thetaMean;
-            float distance,orientation;
-            CvMat* linesStorage;
-            core::Matrix *output;
+            class HoughLines_impl *pimpl_;
+            
+            
     };
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.cpp	(revision 325)
@@ -13,8 +13,10 @@
 
 #include "ImgThreshold.h"
+#include "VisionFilter.h"
 #include <Image.h>
 #include <Layout.h>
 #include <GroupBox.h>
 #include <SpinBox.h>
+//#include <dspcv_gpp.h>
 #include <typeinfo>
 
@@ -23,50 +25,84 @@
 using namespace flair::gui;
 
+class ImgThreshold_impl {
+public:
+    ImgThreshold_impl(flair::filter::ImgThreshold *self,const LayoutPosition* position,string name):output(0) {
+        this->self=self;
+        
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        threshold=new SpinBox(reglages_groupbox->NewRow(),"threshold:",0,255,1,127);
+
+        Printf("todo: pouvoir reutiliser la meme image en sortie\n");
+        try{
+            Image::Type const &imageType=dynamic_cast<Image::Type const &>(((IODevice*)(self->Parent()))->GetOutputDataType());
+            if(imageType.GetFormat()==Image::Type::Format::Gray) {
+                output=new Image(self,imageType.GetWidth(),imageType.GetHeight(),imageType.GetFormat(),"threshold");
+                //inIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+                //outIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+            } else {
+                self->Err("input image is not gray\n");
+            }
+        } catch(std::bad_cast& bc) {
+            self->Err("io type mismatch\n");
+        }
+
+        
+    }
+
+    ~ImgThreshold_impl() {
+        //FreeFunction((char*)(inIplImage));
+        //FreeFunction((char*)(outIplImage));
+    }
+    
+    void UpdateFrom(const io_data *data){
+        Image *img=(Image*)data;
+/*
+        data->GetMutex();
+        inIplImage->width=img->GetDataType().GetWidth();
+        inIplImage->height=img->GetDataType().GetHeight();
+        inIplImage->imageData=img->buffer;
+        
+        output->GetMutex();
+        outIplImage->width=output->GetDataType().GetWidth();
+        outIplImage->height=output->GetDataType().GetHeight();
+        outIplImage->imageData=output->buffer;
+                
+        dspThreshold(inIplImage,outIplImage, threshold->Value(), 255, CV_THRESH_BINARY);
+        output->ReleaseMutex();
+        data->ReleaseMutex();
+*/
+        output->SetDataTime(data->DataTime());
+    };
+    
+    Image *output;
+
+private:
+    flair::filter::ImgThreshold *self;
+    SpinBox *threshold;
+    //IplImage *inIplImage,*outIplImage;
+};
+
 namespace flair { namespace filter {
 
-ImgThreshold::ImgThreshold(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name),output(0) {
-    GroupBox* reglages_groupbox=new GroupBox(position,name);
-    threshold=new SpinBox(reglages_groupbox->NewRow(),"threshold:",0,255,1,127);
-
-    Printf("todo: pouvoir reutiliser la meme image en sortie\n");
-    try{
-        Image::Type const &imageType=dynamic_cast<Image::Type const &>(parent->GetOutputDataType());
-        if(imageType.GetFormat()==Image::Type::Format::Gray) {
-            output=new Image(this,imageType.GetWidth(),imageType.GetHeight(),imageType.GetFormat(),"threshold");
-        } else {
-            Err("input image is not gray\n");
-            return;
-        }
-    } catch(std::bad_cast& bc) {
-        Err("io type mismatch\n");
-        return;
-    }
-    SetIsReady(true);
+ImgThreshold::ImgThreshold(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name) {
+    pimpl_=new ImgThreshold_impl(this,position,name);
 }
 
 ImgThreshold::~ImgThreshold(void) {
+    delete pimpl_;
 }
 
 Image* ImgThreshold::Output(void) {
-    return output;
+    return pimpl_->output;
 }
 
 void ImgThreshold::UpdateFrom(const io_data *data) {
- /*   Image *cvImage=(Image*)data;
-    IplImage *gimg=cvImage->img;
-
-    data->GetMutex();
-    output->GetMutex();
-    dspThreshold(gimg, output->img, threshold->Value(), 255, CV_THRESH_BINARY);
-    output->ReleaseMutex();
-    data->ReleaseMutex();
-*/
-    output->SetDataTime(data->DataTime());
-    ProcessUpdate(output);
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
 }
 
 DataType const &ImgThreshold::GetOutputDataType() const {
-    if(output!=NULL) {
-        return output->GetDataType();
+    if(pimpl_->output!=NULL) {
+        return pimpl_->output->GetDataType();
     } else {
         return dummyType;
Index: /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/ImgThreshold.h	(revision 325)
@@ -19,7 +19,8 @@
     namespace gui {
         class LayoutPosition;
-        class SpinBox;
     }
 }
+
+class ImgThreshold_impl;
 
 namespace flair { namespace filter {
@@ -63,6 +64,5 @@
         private:
             void UpdateFrom(const core::io_data *data);
-            core::Image *output;
-            gui::SpinBox *threshold;
+            class ImgThreshold_impl *pimpl_;
     };
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.cpp	(revision 325)
@@ -14,9 +14,11 @@
 #include "OpticalFlow.h"
 #include "OpticalFlowData.h"
+#include "VisionFilter.h"
 #include <Image.h>
 #include <Layout.h>
 #include <GroupBox.h>
 #include <SpinBox.h>
-//#include <algorithm>
+//#include <dspcv_gpp.h>
+#include <algorithm>
 #include <OneAxisRotation.h>
 #include <Vector3D.h>
@@ -30,4 +32,171 @@
 using namespace flair::gui;
 
+class OpticalFlow_impl {
+public:
+    OpticalFlow_impl(flair::filter::OpticalFlow *self,const LayoutPosition* position,string name) {
+        this->self=self;
+        is_init=false;
+
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        rotation=new OneAxisRotation(reglages_groupbox->NewRow(),"post rotation",OneAxisRotation::PostRotation);
+        max_features=new SpinBox(reglages_groupbox->NewRow(),"max features:",1,65535,1,1);
+        
+        try{
+            Image::Type const &imageType=dynamic_cast<Image::Type const &>(((IODevice*)(self->Parent()))->GetOutputDataType());
+            pyr=new Image(self,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray);
+            pyr_old=new Image(self,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray);
+            output=new flair::filter::OpticalFlowData(self->Parent(),max_features->Value());
+/*
+            pointsA=(CvPoint*)AllocFunction(max_features->Value()*sizeof(CvPoint));
+            pointsB=(CvPoint*)AllocFunction(max_features->Value()*sizeof(CvPoint));
+
+            found_feature=(char*)AllocFunction(max_features->Value()*sizeof(char));
+            feature_error=(unsigned int*)AllocFunction(max_features->Value()*sizeof(unsigned int));
+            
+            iplgimg = (IplImage*)AllocFunction(sizeof(IplImage));
+            iplgimg_old = (IplImage*)AllocFunction(sizeof(IplImage));
+            iplpyr = (IplImage*)AllocFunction(sizeof(IplImage));
+            iplpyr_old = (IplImage*)AllocFunction(sizeof(IplImage));
+            
+            iplpyr->width=imageType.GetWidth();
+            iplpyr->height=imageType.GetHeight();
+            iplpyr_old->width=imageType.GetWidth();
+            iplpyr_old->height=imageType.GetHeight();
+*/  
+      } catch(std::bad_cast& bc) {
+            self->Err("io type mismatch\n");
+            pyr=NULL;
+            pyr_old=NULL;
+        }
+      
+    }
+
+    ~OpticalFlow_impl() {
+        /*
+        FreeFunction((char*)pointsA);
+        FreeFunction((char*)pointsB);
+        FreeFunction((char*)found_feature);
+        FreeFunction((char*)feature_error);
+        FreeFunction((char*)iplgimg);
+        FreeFunction((char*)iplgimg_old);
+        FreeFunction((char*)iplpyr);
+        FreeFunction((char*)iplpyr_old);*/
+    }
+    
+    void UpdateFrom(const io_data *data){
+        //Time tStart=GetTime();
+        Image *img=(Image*)data;
+        Image *img_old=((Image*)data->Prev(1));
+/*
+        iplgimg->width=img->GetDataType().GetWidth();
+        iplgimg->height=img->GetDataType().GetHeight();
+        iplgimg->imageData=img->buffer;
+        
+        iplgimg_old->width=img_old->GetDataType().GetWidth();
+        iplgimg_old->height=img_old->GetDataType().GetHeight();
+        iplgimg_old->imageData=img_old->buffer;
+        
+        iplpyr->imageData=pyr->buffer;
+        iplpyr_old->imageData=pyr_old->buffer;
+
+        unsigned int count;
+        CvSize window = {3,3};
+        CvTermCriteria termination_criteria ={CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 };
+        unsigned int i;
+
+        if(max_features->ValueChanged()==true) {
+            FreeFunction((char*)pointsA);
+            FreeFunction((char*)pointsB);
+            FreeFunction((char*)found_feature);
+            FreeFunction((char*)feature_error);
+            pointsA=(CvPoint*)AllocFunction(max_features->Value()*sizeof(CvPoint));
+            pointsB=(CvPoint*)AllocFunction(max_features->Value()*sizeof(CvPoint));
+            found_feature=(char*)AllocFunction(max_features->Value()*sizeof(char));
+            feature_error=(unsigned int*)AllocFunction(max_features->Value()*sizeof(unsigned int));
+
+            output->Resize(max_features->Value());
+        }
+
+        if(is_init==false) {
+            data->GetMutex();
+            //init image old
+            dspPyrDown(iplgimg,iplpyr_old,LEVEL_PYR);
+            data->ReleaseMutex();
+            is_init=true;
+            printf("ajouter mise a 0 des points\n");
+            return;
+        }
+
+        data->GetMutex();
+        data->Prev(1)->GetMutex();
+
+        //select good features
+        count=max_features->Value();
+        dspGoodFeaturesToTrack(iplgimg_old,pointsA,&count,0.08,5);
+        //pyramide
+        dspPyrDown(iplgimg,iplpyr,LEVEL_PYR);
+        //lk
+        dspCalcOpticalFlowPyrLK(iplgimg_old,iplgimg,iplpyr_old,iplpyr,pointsA,pointsB,count,window,LEVEL_PYR,found_feature,feature_error,termination_criteria,0) ;
+
+        data->Prev(1)->ReleaseMutex();
+        data->ReleaseMutex();
+
+        //apply rotation
+        for(i=0;i<count;i++) {
+            Vector3Df tmp;
+            tmp.x=pointsA[i].x;
+            tmp.y=pointsA[i].y;
+            tmp.z=0;
+            rotation->ComputeRotation(tmp);
+            pointsA[i].x=tmp.x;
+            pointsA[i].y=tmp.y;
+
+            tmp.x=pointsB[i].x;
+            tmp.y=pointsB[i].y;
+            tmp.z=0;
+            rotation->ComputeRotation(tmp);
+            pointsB[i].x=tmp.x;
+            pointsB[i].y=tmp.y;
+        }
+
+        output->GetMutex();
+        CvPoint2D32f* pointsBf= output->PointsB();
+        for(i=0;i<count;i++) {
+            pointsBf[i].x=pointsA[i].x+((float)pointsB[i].x)/256;
+            pointsBf[i].y=pointsA[i].y+((float)pointsB[i].y)/256;
+        }
+        output->ReleaseMutex();
+
+        output->SetPointsA(pointsA);
+        output->SetFoundFeature(found_feature);
+        output->SetFeatureError(feature_error);
+        output->SetNbFeatures(count);
+
+        //rotation
+        swap(pyr,pyr_old);
+*/
+        output->SetDataTime(data->DataTime());
+        //Printf("Optical flow computation time=%f\n",(GetTime()-tStart)/(1000.*1000));
+    };
+    
+    flair::filter::OpticalFlowData *output;
+
+private:
+    flair::filter::OpticalFlow *self;
+    SpinBox *max_features;
+    OneAxisRotation* rotation;
+
+    //CvPoint* pointsA;
+    //CvPoint* pointsB;
+    char *found_feature;
+    unsigned int *feature_error;
+    Image *pyr,*pyr_old;
+    //IplImage *iplgimg,*iplgimg_old;
+    //IplImage *iplpyr,*iplpyr_old;
+
+    bool is_init;
+};
+
+
 namespace flair
 {
@@ -35,127 +204,29 @@
 {
 
-OpticalFlow::OpticalFlow(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name)
-{
+OpticalFlow::OpticalFlow(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name) {
     Printf("optical flow: voir pour faire du multiple output\n");//pour pts A et B, found et error
-
-    try{
-        Image::Type const &imageType=dynamic_cast<Image::Type const &>(parent->GetOutputDataType());
-        pyr=new Image(this,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray);
-        pyr_old=new Image(this,imageType.GetWidth(),imageType.GetHeight(),Image::Type::Format::Gray);
-    } catch(std::bad_cast& bc) {
-        Err("io type mismatch\n");
-        pyr=NULL;
-        pyr_old=NULL;
-        return;
+    pimpl_=new OpticalFlow_impl(this,position,name);
+}
+
+OpticalFlow::~OpticalFlow(void) {
+    delete pimpl_;
+}
+
+void OpticalFlow::UpdateFrom(const io_data *data) {
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
+}
+
+OpticalFlowData* OpticalFlow::Output(void) {
+    return pimpl_->output;
+
+}
+
+DataType const &OpticalFlow::GetOutputDataType() const {
+    if(pimpl_->output!=NULL) {
+        return pimpl_->output->GetDataType();
+    } else {
+        return dummyType;
     }
-
-    is_init=false;
-
-    GroupBox* reglages_groupbox=new GroupBox(position,name);
-    rotation=new OneAxisRotation(reglages_groupbox->NewRow(),"post rotation",OneAxisRotation::PostRotation);
-    max_features=new SpinBox(reglages_groupbox->NewRow(),"max features:",1,65535,1,1);
-
-    output=new OpticalFlowData(parent,max_features->Value());
-
-    pointsA=(CvPoint*)malloc(max_features->Value()*sizeof(CvPoint));
-    pointsB=(CvPoint*)malloc(max_features->Value()*sizeof(CvPoint));
-
-    found_feature=(char*)malloc(max_features->Value()*sizeof(char));
-    feature_error=(unsigned int*)malloc(max_features->Value()*sizeof(unsigned int));
-    
-    SetIsReady(true);
-}
-
-OpticalFlow::~OpticalFlow(void) {
-    free((char*)pointsA);
-    free((char*)pointsB);
-    free((char*)found_feature);
-    free((char*)feature_error);
-}
-
-void OpticalFlow::UpdateFrom(const io_data *data) {/*
-    IplImage *gimg=((Image*)data)->img;
-    IplImage *gimg_old=((Image*)data->Prev(1))->img;
-
-    unsigned int count;
-    CvSize window = cvSize(3,3);
-    CvTermCriteria termination_criteria = cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3 );
-    unsigned int i;
-
-    if(max_features->ValueChanged()==true) {
-        cvFree(&pointsA);
-        cvFree(&pointsB);
-        cvFree(&found_feature);
-        cvFree(&feature_error);
-        pointsA=(CvPoint *)cvAlloc(max_features->Value()*sizeof(CvPoint));
-        pointsB=(CvPoint *)cvAlloc(max_features->Value()*sizeof(CvPoint));
-        found_feature=(char *)cvAlloc(max_features->Value()*sizeof(char));
-        feature_error=(unsigned int *)cvAlloc(max_features->Value()*sizeof(unsigned int));
-
-        output->Resize(max_features->Value());
-    }
-
-    if(is_init==false)
-    {
-        data->GetMutex();
-        //init image old
-        dspPyrDown(gimg,pyr_old,LEVEL_PYR);
-        data->ReleaseMutex();
-        is_init=true;
-        printf("ajouter mise a 0 des points\n");
-        return;
-    }
-
-    data->GetMutex();
-    data->Prev(1)->GetMutex();
-
-    //select good features
-    count=max_features->Value();
-    dspGoodFeaturesToTrack(gimg_old,pointsA,&count,0.08,5);
-    //pyramide
-    dspPyrDown(gimg,pyr,LEVEL_PYR);
-    //lk
-    dspCalcOpticalFlowPyrLK(gimg_old,gimg,pyr_old,pyr,pointsA,pointsB,count,window,LEVEL_PYR,found_feature,feature_error,termination_criteria,0) ;
-
-    data->Prev(1)->ReleaseMutex();
-    data->ReleaseMutex();
-
-    //apply rotation
-    for(i=0;i<count;i++) {
-        Vector3Df tmp;
-        tmp.x=pointsA[i].x;
-        tmp.y=pointsA[i].y;
-        tmp.z=0;
-        rotation->ComputeRotation(tmp);
-        pointsA[i].x=tmp.x;
-        pointsA[i].y=tmp.y;
-
-        tmp.x=pointsB[i].x;
-        tmp.y=pointsB[i].y;
-        tmp.z=0;
-        rotation->ComputeRotation(tmp);
-        pointsB[i].x=tmp.x;
-        pointsB[i].y=tmp.y;
-    }
-
-    output->GetMutex();
-    CvPoint2D32f* pointsBf= output->PointsB();
-    for(i=0;i<count;i++)
-    {
-        pointsBf[i].x=pointsA[i].x+((float)pointsB[i].x)/256;
-        pointsBf[i].y=pointsA[i].y+((float)pointsB[i].y)/256;
-    }
-    output->ReleaseMutex();
-
-    output->SetPointsA(pointsA);
-    output->SetFoundFeature(found_feature);
-    output->SetFeatureError(feature_error);
-    output->SetNbFeatures(count);
-
-    //rotation
-    swap(pyr,pyr_old);
-*/
-    output->SetDataTime(data->DataTime());
-    ProcessUpdate(output);
 }
 
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlow.h	(revision 325)
@@ -12,14 +12,8 @@
 
 #include <IODevice.h>
-#include <cvtypes.h>
 
 namespace flair {
-    namespace core {
-        class Image;
-        class OneAxisRotation;
-    }
     namespace gui {
         class LayoutPosition;
-        class SpinBox;
     }
     namespace filter {
@@ -27,4 +21,6 @@
     }
 }
+
+class OpticalFlow_impl;
 
 namespace flair {
@@ -57,18 +53,14 @@
             */
             ~OpticalFlow();
+            
+            filter::OpticalFlowData* Output(void);
+
+            core::DataType const &GetOutputDataType() const;
 
         private:
             void UpdateFrom(const core::io_data *data);
-            OpticalFlowData *output;
-            gui::SpinBox *max_features;
-            core::OneAxisRotation* rotation;
-
-            CvPoint* pointsA;
-            CvPoint* pointsB;
-            char *found_feature;
-            unsigned int *feature_error;
-            core::Image *pyr,*pyr_old;
-
-            bool is_init;
+            
+            class OpticalFlow_impl *pimpl_;
+            
     };
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.cpp	(revision 325)
@@ -32,91 +32,102 @@
 using namespace flair::gui;
 
+class OpticalFlowCompensated_impl {
+public:
+    OpticalFlowCompensated_impl(flair::filter::OpticalFlowCompensated *self,const flair::filter::Ahrs *ahrs, const LayoutPosition* position, string name): ahrs(ahrs), output(NULL) {
+        this->self=self;
+        previousStepsAngularRates=new Vector3Df*[10];
+        for (int i=0; i<10; i++) previousStepsAngularRates[i]=NULL;
+        previousStepsAngularRatesIndex=0;
+
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        //TODO: the gyroDelay is set to compensate for the time difference between image snapshot et gyro measurements
+        //it is equal to the time between 2 images (because optical flow always lags 1 frame) + the time to compute optical flow
+        //here it is approximated by 2 video frames
+        gyroDelay=new SpinBox(reglages_groupbox->NewRow(),"gyro delay (in video frames):",0,10,1,2);
+        gyroGain=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"gyro gain:",0.,500.,10.,2,300.);
+
+       
+    }
+
+    ~OpticalFlowCompensated_impl() {
+        delete output;
+    }
+    
+    void UpdateFrom(const io_data *data){
+        flair::filter::OpticalFlowData *input=(flair::filter::OpticalFlowData *)data;
+        if (!output) { //first pass
+            output=new flair::filter::OpticalFlowData(self,input->MaxFeatures(),input->ObjectName()+"_filtered");
+            previousTime=input->DataTime();
+            return;
+        }
+        //  float kX=320/Euler::ToRadian(70); //TEST: only for default simuCameraGL. fov=70° and image width=320 => k=320*180/(70*pi)
+        //  float kY=240/Euler::ToRadian(70); //TEST: only for default simuCameraGL. fov=70° and image height=240
+        float kX=gyroGain->Value();
+        float kY=gyroGain->Value();
+        float deltaT=(input->DataTime()-previousTime)/(1000*1000*1000.);
+        previousTime=input->DataTime();
+
+        int delayedIndex=previousStepsAngularRatesIndex-gyroDelay->Value(); // Ahhh décalage, esprit canal...
+        if (delayedIndex<0) delayedIndex+=10;
+
+        if (!previousStepsAngularRates[previousStepsAngularRatesIndex]) {
+            previousStepsAngularRates[previousStepsAngularRatesIndex]=new Vector3Df();
+        }
+        *previousStepsAngularRates[previousStepsAngularRatesIndex++]=ahrs->GetDatas()->GetAngularRates();
+
+        if (!previousStepsAngularRates[delayedIndex]) return;
+        float rotationFlowX=previousStepsAngularRates[delayedIndex]->y*deltaT*kY;
+        float rotationFlowY=-previousStepsAngularRates[delayedIndex]->x*deltaT*kX;
+        if (previousStepsAngularRatesIndex==10) previousStepsAngularRatesIndex=0;
+        input->GetMutex();
+        output->GetMutex();
+
+        for (int i=0; i<input->NbFeatures(); i++) {
+            output->PointsA()[i].x=input->PointsA()[i].x;
+            output->PointsA()[i].y=input->PointsA()[i].y;
+            output->PointsB()[i].x=input->PointsB()[i].x-rotationFlowX;
+            output->PointsB()[i].y=input->PointsB()[i].y-rotationFlowY;
+        }
+        output->SetNbFeatures(input->NbFeatures());
+        output->SetFoundFeature(input->FoundFeature());
+        output->SetFeatureError(input->FeatureError());
+
+        output->ReleaseMutex();
+        input->ReleaseMutex();
+
+        output->SetDataTime(input->DataTime());
+           
+    };
+    
+    flair::filter::OpticalFlowData *output;
+
+private:
+    flair::filter::OpticalFlowCompensated *self;
+    Time previousTime;
+    const flair::filter::Ahrs *ahrs;
+    Vector3Df **previousStepsAngularRates;
+    unsigned int previousStepsAngularRatesIndex;
+    SpinBox *gyroDelay;
+    DoubleSpinBox *gyroGain;
+};
+
+
 namespace flair {
 namespace filter {
 
-OpticalFlowCompensated::OpticalFlowCompensated(const OpticalFlow *parent, const Ahrs *ahrs, const LayoutPosition* position, string name) : IODevice(parent, name), ahrs(ahrs), output(NULL) {
-  MatrixDescriptor* desc=new MatrixDescriptor(3,2);
-  desc->SetElementName(0,0,"raw displacement X");
-  desc->SetElementName(0,1,"raw displacement Y");
-  desc->SetElementName(1,0,"compensation X");
-  desc->SetElementName(1,1,"compensation Y");
-  desc->SetElementName(2,0,"displacement with compensation X");
-  desc->SetElementName(2,0,"displacement with compensation Y");
-  firstPointDisplacement=new Matrix(this,desc,floatType,name);
-  delete desc;
-  previousStepsAngularRates=new Vector3Df*[10];
-  for (int i=0; i<10; i++) previousStepsAngularRates[i]=NULL;
-  previousStepsAngularRatesIndex=0;
-
-  GroupBox* reglages_groupbox=new GroupBox(position,name);
-  //TODO: the gyroDelay is set to compensate for the time difference between image snapshot et gyro measurements
-//it is equal to the time between 2 images (because optical flow always lags 1 frame) + the time to compute optical flow
-//here it is approximated by 2 video frames
-  gyroDelay=new SpinBox(reglages_groupbox->NewRow(),"gyro delay (in video frames):",0,10,1,2);
-  gyroGain=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"gyro gain:",0.,500.,10.,2,300.);
+OpticalFlowCompensated::OpticalFlowCompensated(const OpticalFlow *parent, const Ahrs *ahrs, const LayoutPosition* position, string name) : IODevice(parent, name) {
+    pimpl_=new OpticalFlowCompensated_impl(this,ahrs,position,name);
 
 }
 
 OpticalFlowCompensated::~OpticalFlowCompensated() {
-  delete output;
+    delete pimpl_;
 }
 
 void OpticalFlowCompensated::UpdateFrom(const io_data *data) {
-  OpticalFlowData *input=(OpticalFlowData *)data;
-  if (!output) { //first pass
-    output=new OpticalFlowData(this,input->MaxFeatures(),input->ObjectName()+"_filtered");
-    previousTime=input->DataTime();
-    return;
-  }
-//  float kX=320/Euler::ToRadian(70); //TEST: only for default simuCameraGL. fov=70° and image width=320 => k=320*180/(70*pi)
-//  float kY=240/Euler::ToRadian(70); //TEST: only for default simuCameraGL. fov=70° and image height=240
-  float kX=gyroGain->Value();
-  float kY=gyroGain->Value();
-  float deltaT=(input->DataTime()-previousTime)/(1000*1000*1000.);
-  previousTime=input->DataTime();
-
-  int delayedIndex=previousStepsAngularRatesIndex-gyroDelay->Value(); // Ahhh décalage, esprit canal...
-  if (delayedIndex<0) delayedIndex+=10;
-
-  if (!previousStepsAngularRates[previousStepsAngularRatesIndex]) {
-    previousStepsAngularRates[previousStepsAngularRatesIndex]=new Vector3Df();
-  }
-  *previousStepsAngularRates[previousStepsAngularRatesIndex++]=ahrs->GetDatas()->GetAngularRates();
-
-  if (!previousStepsAngularRates[delayedIndex]) return;
-  float rotationFlowX=previousStepsAngularRates[delayedIndex]->y*deltaT*kY;
-  float rotationFlowY=-previousStepsAngularRates[delayedIndex]->x*deltaT*kX;
-  if (previousStepsAngularRatesIndex==10) previousStepsAngularRatesIndex=0;
-  input->GetMutex();
-  output->GetMutex();
-
-  for (int i=0; i<input->NbFeatures(); i++) {
-    if (!i) {
-      firstPointDisplacement->SetValue(0,0,input->PointsB()[i].x-input->PointsA()[i].x);
-      firstPointDisplacement->SetValue(0,1,input->PointsB()[i].y-input->PointsA()[i].y);
-      firstPointDisplacement->SetValue(1,0,-rotationFlowX);
-      firstPointDisplacement->SetValue(1,1,-rotationFlowY);
-      firstPointDisplacement->SetValue(2,0,input->PointsB()[i].x-input->PointsA()[i].x-rotationFlowX);
-      firstPointDisplacement->SetValue(2,1,input->PointsB()[i].y-input->PointsA()[i].y-rotationFlowY);
-    }
-    output->PointsA()[i].x=input->PointsA()[i].x;
-    output->PointsA()[i].y=input->PointsA()[i].y;
-    output->PointsB()[i].x=input->PointsB()[i].x-rotationFlowX;
-    output->PointsB()[i].y=input->PointsB()[i].y-rotationFlowY;
-  }
-  output->SetNbFeatures(input->NbFeatures());
-  output->SetFoundFeature(input->FoundFeature());
-  output->SetFeatureError(input->FeatureError());
-
-  output->ReleaseMutex();
-  input->ReleaseMutex();
-
-  output->SetDataTime(input->DataTime());
-  ProcessUpdate(output);
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
 }
 
-  Matrix *OpticalFlowCompensated::GetFirstPointDisplacement() const {
-    return firstPointDisplacement;
-  }
 
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowCompensated.h	(revision 325)
@@ -16,22 +16,16 @@
 #include <IODevice.h>
 #include <Object.h>
-#include <Vector3D.h>
 
 namespace flair {
-  namespace core {
-    class io_data;
-    class Matrix;
-  }
   namespace gui {
     class LayoutPosition;
-    class SpinBox;
-    class DoubleSpinBox;
   }
   namespace filter {
     class Ahrs;
     class OpticalFlow;
-    class OpticalFlowData;
   }
 }
+
+class OpticalFlowCompensated_impl;
 
 namespace flair { namespace filter {
@@ -61,16 +55,8 @@
   ~OpticalFlowCompensated();
 
-  void UpdateFrom(const core::io_data *data);
-
-  core::Matrix *GetFirstPointDisplacement() const;
 private:
-  OpticalFlowData *output;
-  core::Time previousTime;
-  const Ahrs *ahrs;
-  core::Matrix *firstPointDisplacement;
-  core::Vector3Df **previousStepsAngularRates;
-  unsigned int previousStepsAngularRatesIndex;
-  gui::SpinBox *gyroDelay;
-  gui::DoubleSpinBox *gyroGain;
+    void UpdateFrom(const core::io_data *data);
+    OpticalFlowCompensated_impl *pimpl_;
+  
 };
 
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.cpp	(revision 325)
@@ -26,74 +26,101 @@
 using namespace flair::gui;
 
+class OpticalFlowSpeed_impl {
+public:
+    OpticalFlowSpeed_impl(flair::filter::OpticalFlowSpeed *self,const LayoutPosition* position,string name):output(0) {
+        this->self=self;
+        MatrixDescriptor* desc=new MatrixDescriptor(2,1);
+        desc->SetElementName(0,0,"vx");
+        desc->SetElementName(1,0,"vy");
+        output=new Matrix(self,desc,floatType,name);
+        delete desc;
+
+        self->AddDataToLog(output);
+
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        quality=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"optical flow quality:",0.,100.,1.,1,5.);
+        weightedAverage=new CheckBox(reglages_groupbox->LastRowLastCol(),"Weighted average", true);
+        timeMultiplication=new CheckBox(reglages_groupbox->LastRowLastCol(),"Time multiplication", true);
+
+       
+    }
+
+    ~OpticalFlowSpeed_impl() {
+       
+    }
+    
+    void UpdateFrom(const io_data *data){
+        flair::filter::OpticalFlowData *input=(flair::filter::OpticalFlowData*)data;
+        float deplx,deply;
+        float nb_depl=0;
+
+        deplx=0;
+        deply=0;
+
+        //error is 0 if perfect match and 7x7x255x255 at worst
+        float qualityThreshold=quality->Value()/100.*7*7*255*255;
+        input->GetMutex();
+        int nbUsedPoints=0;
+        for(int i=0;i<input->NbFeatures();i++) {
+            //if point is found in both images and quality is sufficient
+            if((input->FoundFeature()[i]!=0)&&(input->FeatureError()[i]<qualityThreshold)) {
+              nbUsedPoints++;
+              float qualityFactor=1.0;
+              if (weightedAverage->Value()) {
+                //displacement is weigthed by quality
+                qualityFactor/=(1+input->FeatureError()[i]);
+              } 
+                deplx+=(input->PointsB()[i].x-input->PointsA()[i].x)*qualityFactor;
+                deply+=(input->PointsB()[i].y-input->PointsA()[i].y)*qualityFactor;
+                nb_depl+=qualityFactor;
+            }
+        }
+        input->ReleaseMutex();
+        float deltaT;
+        if (timeMultiplication->Value()) deltaT=(float)(data->DataTime()-output->DataTime())/(1000.*1000.*1000.);
+        else deltaT=1.;
+        output->SetDataTime(data->DataTime());
+
+        if(nb_depl!=0) {
+    //Printf("Nombre de points=%d/%d (nb_depl=%f,pondération=%d), deltaT=%f\n",nbUsedPoints,input->NbFeatures(),nb_depl,weightedAverage->Value(),deltaT);
+            output->SetValue(0,0,deplx/(nb_depl*deltaT));
+            output->SetValue(1,0,deply/(nb_depl*deltaT));
+        }
+    };
+    
+    Matrix *output;
+   
+private:
+    flair::filter::OpticalFlowSpeed *self;    
+    DoubleSpinBox *quality;
+    CheckBox *weightedAverage;
+    CheckBox *timeMultiplication;
+};
+
 namespace flair { namespace filter {
 
 OpticalFlowSpeed::OpticalFlowSpeed(const IODevice* parent, const LayoutPosition* position,string name) : IODevice(parent,name) {
-  MatrixDescriptor* desc=new MatrixDescriptor(2,1);
-  desc->SetElementName(0,0,"vx");
-  desc->SetElementName(1,0,"vy");
-  output=new Matrix(this,desc,floatType,name);
-  delete desc;
-
-  AddDataToLog(output);
-
-  GroupBox* reglages_groupbox=new GroupBox(position,name);
-  quality=new DoubleSpinBox(reglages_groupbox->LastRowLastCol(),"optical flow quality:",0.,100.,1.,1,5.);
-  weightedAverage=new CheckBox(reglages_groupbox->LastRowLastCol(),"Weighted average", true);
-  timeMultiplication=new CheckBox(reglages_groupbox->LastRowLastCol(),"Time multiplication", true);
+    pimpl_=new OpticalFlowSpeed_impl(this,position,name);
 }
 
-OpticalFlowSpeed::~OpticalFlowSpeed(void) { }
+OpticalFlowSpeed::~OpticalFlowSpeed(void) {
+    delete pimpl_;
+}
 
 void OpticalFlowSpeed::UpdateFrom(const io_data *data) {
-    OpticalFlowData *input=(OpticalFlowData*)data;
-    float deplx,deply;
-    float nb_depl=0;
-
-    deplx=0;
-    deply=0;
-
-    //error is 0 if perfect match and 7x7x255x255 at worst
-    float qualityThreshold=quality->Value()/100.*7*7*255*255;
-    input->GetMutex();
-    int nbUsedPoints=0;
-    for(int i=0;i<input->NbFeatures();i++) {
-        //if point is found in both images and quality is sufficient
-        if((input->FoundFeature()[i]!=0)&&(input->FeatureError()[i]<qualityThreshold)) {
-          nbUsedPoints++;
-          float qualityFactor=1.0;
-          if (weightedAverage->Value()) {
-            //displacement is weigthed by quality
-            qualityFactor/=(1+input->FeatureError()[i]);
-          } 
-            deplx+=(input->PointsB()[i].x-input->PointsA()[i].x)*qualityFactor;
-            deply+=(input->PointsB()[i].y-input->PointsA()[i].y)*qualityFactor;
-            nb_depl+=qualityFactor;
-        }
-    }
-    input->ReleaseMutex();
-    float deltaT;
-    if (timeMultiplication->Value()) deltaT=(float)(data->DataTime()-output->DataTime())/(1000.*1000.*1000.);
-    else deltaT=1.;
-    output->SetDataTime(data->DataTime());
-
-    if(nb_depl!=0) {
-//Printf("Nombre de points=%d/%d (nb_depl=%f,pondération=%d), deltaT=%f\n",nbUsedPoints,input->NbFeatures(),nb_depl,weightedAverage->Value(),deltaT);
-        output->SetValue(0,0,deplx/(nb_depl*deltaT));
-        output->SetValue(1,0,deply/(nb_depl*deltaT));
-    }
-//    output->SetDataTime(data->DataTime());
-    ProcessUpdate(output);
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
 }
 
 float OpticalFlowSpeed::Vx(void) const {
-    return output->Value(0,0);
+    return pimpl_->output->Value(0,0);
 }
 
 float OpticalFlowSpeed::Vy(void) const {
-    return output->Value(1,0);
+    return pimpl_->output->Value(1,0);
 }
 
 core::Matrix *OpticalFlowSpeed::Output() const {
-    return output;
+    return pimpl_->output;
 }
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/OpticalFlowSpeed.h	(revision 325)
@@ -21,9 +21,8 @@
   namespace gui {
     class LayoutPosition;
-    class SpinBox;
-    class DoubleSpinBox;
-    class CheckBox;
   }
 }
+
+class OpticalFlowSpeed_impl;
 
 namespace flair
@@ -88,9 +87,6 @@
             */
             void UpdateFrom(const core::io_data *data);
-
-            core::Matrix *output;
-      gui::DoubleSpinBox *quality;
-      gui::CheckBox *weightedAverage;
-      gui::CheckBox *timeMultiplication;
+            
+            OpticalFlowSpeed_impl *pimpl_;
 };
 
Index: /branches/sanscv/lib/FlairVisionFilter/src/Sobel.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/Sobel.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/Sobel.cpp	(revision 325)
@@ -13,8 +13,10 @@
 
 #include "Sobel.h"
+#include "VisionFilter.h"
 #include <Image.h>
 #include <Layout.h>
 #include <GroupBox.h>
 #include <SpinBox.h>
+//#include <dspcv_gpp.h>
 #include <typeinfo>
 
@@ -23,53 +25,87 @@
 using namespace flair::gui;
 
+class Sobel_impl {
+public:
+    Sobel_impl(flair::filter::Sobel *self,const LayoutPosition* position,string name):output(0) {
+        this->self=self;
+        
+        GroupBox* reglages_groupbox=new GroupBox(position,name);
+        dx=new SpinBox(reglages_groupbox->NewRow(),"dx:",0,1,1,1);
+        dy=new SpinBox(reglages_groupbox->NewRow(),"dy:",0,1,1,1);
+
+        Printf("TODO: IODevice doit faire un check de GetInputDataType et GetOutputDataType\n");
+        //Image devrait accepter un type dans son constructeur pour construire un type identique
+        try{
+            Image::Type const &imageType=dynamic_cast<Image::Type const &>(((IODevice*)(self->Parent()))->GetOutputDataType());
+            if(imageType.GetFormat()==Image::Type::Format::Gray) {
+                output=new Image(self,imageType.GetWidth(),imageType.GetHeight(),imageType.GetFormat(),"sobel");
+                //inIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+                //outIplImage = (IplImage*)AllocFunction(sizeof(IplImage));
+            } else {
+                self->Err("input image is not gray\n");
+            }
+
+        } catch(std::bad_cast& bc) {
+            self->Err("io type mismatch\n");
+        }
+    }
+
+    ~Sobel_impl() {
+        //FreeFunction((char*)(inIplImage));
+        //FreeFunction((char*)(outIplImage));
+    }
+    
+    void UpdateFrom(const io_data *data){
+        Image *image=(Image*)data;
+/*
+        data->GetMutex();
+        inIplImage->width=image->GetDataType().GetWidth();
+        inIplImage->height=image->GetDataType().GetHeight();
+        inIplImage->imageData=image->buffer;
+        
+        output->GetMutex();
+        outIplImage->width=output->GetDataType().GetWidth();
+        outIplImage->height=output->GetDataType().GetHeight();
+        outIplImage->imageData=output->buffer;
+                
+        dspSobel(inIplImage,outIplImage,dx->Value(),dy->Value());
+        output->ReleaseMutex();
+        data->ReleaseMutex();
+*/
+        output->SetDataTime(data->DataTime());
+
+    };
+    
+    Image *output;
+
+private:
+    flair::filter::Sobel *self;
+    SpinBox *dx;
+    SpinBox *dy;
+    //IplImage *inIplImage,*outIplImage;
+};
+
 namespace flair { namespace filter {
 
-Sobel::Sobel(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name),output(0) {
-    GroupBox* reglages_groupbox=new GroupBox(position,name);
-    dx=new SpinBox(reglages_groupbox->NewRow(),"dx:",0,1,1,1);
-    dy=new SpinBox(reglages_groupbox->NewRow(),"dy:",0,1,1,1);
-
-    Printf("TODO: IODevice doit faire un check de GetInputDataType et GetOutputDataType\n");
-    //Image devrait accepter un type dans son constructeur pour construire un type identique
-    try{
-        Image::Type const &imageType=dynamic_cast<Image::Type const &>(parent->GetOutputDataType());
-        if(imageType.GetFormat()==Image::Type::Format::Gray) {
-            output=new Image(this,imageType.GetWidth(),imageType.GetHeight(),imageType.GetFormat(),"sobel");
-        } else {
-            Err("input image is not gray\n");
-            return;
-        }
-
-    } catch(std::bad_cast& bc) {
-        Err("io type mismatch\n");
-        return;
-    }
-    SetIsReady(true);
+Sobel::Sobel(const IODevice* parent,const LayoutPosition* position,string name) : IODevice(parent,name) {
+   pimpl_=new Sobel_impl(this,position,name);
 }
 
 Sobel::~Sobel(void) {
+    delete pimpl_;
 }
 
 Image* Sobel::Output(void) {
-    return output;
+    return pimpl_->output;
 }
 
-void Sobel::UpdateFrom(const io_data *data) {/*
-    Image *cvImage=(Image*)data;
-    IplImage *gimg=cvImage->img;
-
-    data->GetMutex();
-    output->GetMutex();
-    dspSobel(gimg,output->img,dx->Value(),dy->Value());
-    output->ReleaseMutex();
-    data->ReleaseMutex();
-*/
-    output->SetDataTime(data->DataTime());
-    ProcessUpdate(output);
+void Sobel::UpdateFrom(const io_data *data) {
+    pimpl_->UpdateFrom(data);
+    ProcessUpdate(pimpl_->output);
 }
 
 DataType const &Sobel::GetOutputDataType() const {
-    if(output!=NULL) {
-        return output->GetDataType();
+    if(pimpl_->output!=NULL) {
+        return pimpl_->output->GetDataType();
     } else {
         return dummyType;
Index: /branches/sanscv/lib/FlairVisionFilter/src/Sobel.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/Sobel.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/Sobel.h	(revision 325)
@@ -12,5 +12,5 @@
 
 #include <IODevice.h>
-#include <cvtypes.h>
+
 
 namespace flair {
@@ -20,7 +20,8 @@
     namespace gui {
         class LayoutPosition;
-        class SpinBox;
     }
 }
+
+ class Sobel_impl;
 
 namespace flair { namespace filter {
@@ -64,7 +65,5 @@
         private:
             void UpdateFrom(const core::io_data *data);
-            core::Image *output;
-            gui::SpinBox *dx;
-            gui::SpinBox *dy;
+            Sobel_impl *pimpl_;
     };
 } // end namespace filter
Index: /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.cpp
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.cpp	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.cpp	(revision 325)
@@ -8,5 +8,5 @@
 }
 
-void saveToJpeg(IplImage* src_img,std::string filename,PictureFormat_t input_format,PictureFormat_t output_format,unsigned char compression_level) {
+void saveToJpeg(flair::core::Image* src_img,std::string filename,PictureFormat_t input_format,PictureFormat_t output_format,unsigned char compression_level) {
 	printf("saveToJpeg todo\n");
     //if(!cvSaveImage(filename.c_str(),src_img)) printf("Could not save.\n");
Index: /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.h
===================================================================
--- /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.h	(revision 324)
+++ /branches/sanscv/lib/FlairVisionFilter/src/VisionFilter.h	(revision 325)
@@ -1,4 +1,10 @@
 #include <string>
-#include <cvtypes.h>
+
+namespace flair {
+    namespace core {
+        class Image;
+    }
+}
+
 
 /*!
@@ -19,3 +25,3 @@
                 } ;
 								
-void saveToJpeg(IplImage* src_img,std::string filename,PictureFormat_t input_format,PictureFormat_t output_format,unsigned char compression_level=95);
+void saveToJpeg(flair::core::Image* src_img,std::string filename,PictureFormat_t input_format,PictureFormat_t output_format,unsigned char compression_level=95);
