opticalFlow.h

Go to the documentation of this file.
00001 
00016 #ifndef _DLRCOMPUTERVISION_OPTICALFLOW_H_
00017 #define _DLRCOMPUTERVISION_OPTICALFLOW_H_
00018 
00019 #include <dlrComputerVision/image.h>
00020 #include <dlrNumeric/array2D.h>
00021 #include <dlrNumeric/index2D.h>
00022 #include <dlrNumeric/vector2D.h>
00023 
00024 namespace dlr {
00025 
00026   namespace computerVision {
00027     
00037     template <ImageFormat Format>
00038     class OpticalFlow {
00039     public:
00040       OpticalFlow(const Image<Format>& image0,
00041                   const Image<Format>& image1,
00042                   double sigma = 2.5);
00043 
00044 
00045       OpticalFlow(const Image<Format>& image0,
00046                   const Image<Format>& image1,
00047                   const Array2D<Float64>& dIdx,
00048                   const Array2D<Float64>& dIdy);
00049       
00050       virtual
00051       ~OpticalFlow() {};
00052 
00053       Vector2D
00054       getFlow(const Index2D& upperLeftCorner,
00055               const Index2D& lowerRightCorner,
00056               bool& valid);
00057 
00058       void
00059       ignoreArea(const Array2D<bool>& flags);
00060 
00061     private:
00062 
00063       void
00064       setImages(const Image<Format>& image0,
00065                 const Image<Format>& image1,
00066                 double sigma = 2.5);
00067       
00068 
00069       void
00070       setImages(const Image<Format>& image0,
00071                 const Image<Format>& image1,
00072                 const Array2D<Float64>& dIdx,
00073                 const Array2D<Float64>& dIdy);
00074       
00075       
00076       Array2D<Float64> m_dIdx2;
00077       Array2D<Float64> m_dIdy2;
00078       Array2D<Float64> m_dIdxdIdy;
00079       Array2D<Float64> m_dIdxdIdt;
00080       Array2D<Float64> m_dIdydIdt;
00081     };
00082 
00083   
00084   } // namespace computerVision
00085 
00086 } // namespace dlr
00087 
00088 /* ========== Definitions of inline and template functions follow ========== */
00089 
00090 
00091 #include <dlrCommon/types.h>
00092 #include <dlrComputerVision/filter.h>
00093 #include <dlrComputerVision/kernel.h>
00094 #include <dlrComputerVision/kernels.h>
00095 #include <dlrComputerVision/utilities.h>
00096 #include <dlrNumeric/utilities.h>
00097 
00098 namespace dlr {
00099 
00100   namespace computerVision {
00101     
00103     namespace privateCode {
00104 
00105       const Kernel<double>&
00106       getGradientXKernel()
00107       {
00108         static Kernel<double> gradientXKernel(
00109           Array1D<double>("[-0.5, 0, 0.5]"), Array1D<double>("[1.0]"));
00110         return gradientXKernel;
00111       }
00112       
00113 
00114       const Kernel<double>&
00115       getGradientYKernel()
00116       {
00117         static Kernel<double> gradientYKernel(
00118           Array1D<double>("[1.0]"), Array1D<double>("[-0.5, 0, 0.5]"));
00119         return gradientYKernel;
00120       }
00121     
00122     } // namespace privateCode
00124 
00125 
00126     template <ImageFormat Format>
00127     OpticalFlow<Format>::
00128     OpticalFlow(const Image<Format>& image0,
00129                 const Image<Format>& image1,
00130                 double sigma)
00131       : m_dIdx2(),
00132         m_dIdy2(),
00133         m_dIdxdIdy(),
00134         m_dIdxdIdt(),
00135         m_dIdydIdt()
00136     {
00137       this->setImages(image0, image1, sigma);
00138     }
00139 
00140 
00141     
00142     template <ImageFormat Format>
00143     OpticalFlow<Format>::
00144     OpticalFlow(const Image<Format>& image0,
00145                 const Image<Format>& image1,
00146                 const Array2D<Float64>& dIdx,
00147                 const Array2D<Float64>& dIdy)
00148       : m_dIdx2(),
00149         m_dIdy2(),
00150         m_dIdxdIdy(),
00151         m_dIdxdIdt(),
00152         m_dIdydIdt()
00153     {
00154       this->setImages(image0, image1, dIdx, dIdy);
00155     }
00156 
00157 
00158     
00159     template <ImageFormat Format>
00160     Vector2D
00161     OpticalFlow<Format>::
00162     getFlow(const Index2D& upperLeftCorner,
00163             const Index2D& lowerRightCorner,
00164             bool& valid)
00165     {
00166       Float64 rdIdx2 = sum(m_dIdx2, upperLeftCorner, lowerRightCorner);
00167       Float64 rdIdy2 = sum(m_dIdy2, upperLeftCorner, lowerRightCorner);
00168       Float64 rdIdxdIdy = sum(m_dIdxdIdy, upperLeftCorner, lowerRightCorner);
00169       Float64 rdIdxdIdt = sum(m_dIdxdIdt, upperLeftCorner, lowerRightCorner);
00170       Float64 rdIdydIdt = sum(m_dIdydIdt, upperLeftCorner, lowerRightCorner);
00171 
00172       // Check for singularity.
00173       double determinant = rdIdx2 * rdIdy2 - rdIdxdIdy * rdIdxdIdy;
00174       // Warning(xxx): Hardcoded tolerance.
00175       if(approximatelyEqual(determinant, 0.0, 1.0e-12)) {
00176         valid = false;
00177         return Vector2D(0.0, 0.0);
00178       }
00179 
00180       // Do cofactor-based inversion by hand here.
00181       Float64 inverseFPrimeSq00 = rdIdy2 / determinant;
00182       Float64 inverseFPrimeSq01 = -rdIdxdIdy / determinant;
00183       // Float64 inverseFPrimeSq10 = inverseFPrimeSq01;
00184       Float64 inverseFPrimeSq11 = rdIdx2 / determinant;
00185 
00186       // Compute flow.
00187       Float64 vx =
00188         rdIdxdIdt * inverseFPrimeSq00 + rdIdydIdt * inverseFPrimeSq01;
00189       Float64 vy =
00190         rdIdxdIdt * inverseFPrimeSq01 + rdIdydIdt * inverseFPrimeSq11;
00191 
00192       valid = true;
00193       return Vector2D(-vx, -vy);
00194     }
00195 
00196 
00197     template <ImageFormat Format>
00198     void
00199     OpticalFlow<Format>::
00200     ignoreArea(const Array2D<bool>& flags)
00201     {
00202       if(flags.rows() != m_dIdx2.rows()
00203          || flags.columns() != m_dIdx2.columns()) {
00204         DLR_THROW(ValueException, "OpticalFlow::setImages()",
00205                   "Argument flags must have the same size as "
00206                   "the input images passed to constructor or setImages().");
00207       }
00208       for(size_t index0 = 0; index0 < flags.size(); ++index0) {
00209         if(flags[index0]) {
00210           m_dIdx2[index0] = 0.0;
00211           m_dIdy2[index0] = 0.0;
00212           m_dIdxdIdy[index0] = 0.0;
00213           m_dIdxdIdt[index0] = 0.0;
00214           m_dIdydIdt[index0] = 0.0;
00215         }
00216       }
00217     }
00218     
00219     
00220     template <ImageFormat Format>
00221     void
00222     OpticalFlow<Format>::
00223     setImages(const Image<Format>& image0,
00224               const Image<Format>& image1,
00225               double sigma)
00226     {
00227       if(image0.rows() != image1.rows()
00228          || image0.columns() != image1.columns()) {
00229         DLR_THROW(ValueException, "OpticalFlow::setImages()",
00230                   "Arguments image0 and image1 must have the same size.");
00231       }
00232       if(ImageFormatTraits<Format>::getNumberOfComponents() != 1) {
00233         DLR_THROW(NotImplementedException, "OpticalFlow::setImages()",
00234                   "Only single-component image formats are currently "
00235                   "supported.");
00236       }
00237 
00238       Array2D<Float64> dIdx;
00239       Array2D<Float64> dIdy;
00240       size_t kernelSize = static_cast<size_t>(6.0 * sigma + 0.5);
00241       if(sigma > 0.0 && kernelSize != 0) {
00242         // Make sure we have an odd kernel size.
00243         if(kernelSize % 2 == 0) {
00244           kernelSize += 1;
00245         }
00246         
00247         // Low pass filter the image to smooth out spacial gradients.
00248         Kernel<Float64> gaussian = getGaussianKernel<Float64>(
00249           kernelSize, kernelSize, sigma, sigma);
00250         Image<GRAY_FLOAT64> filteredImage0 =
00251           filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00252             gaussian, image0, static_cast<Float64>(0.0),
00253             DLR_CONVOLVE_PAD_RESULT);
00254 
00255         // Differentiate.
00256         dIdx = filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00257           privateCode::getGradientXKernel(), filteredImage0,
00258           static_cast<Float64>(0.0), DLR_CONVOLVE_PAD_RESULT);
00259         dIdy = filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00260           privateCode::getGradientYKernel(), filteredImage0,
00261           static_cast<Float64>(0.0), DLR_CONVOLVE_PAD_RESULT);
00262 
00263       } else {
00264         // Low pass filtering disabled by user.  Go straight to
00265         // differentiation.
00266         dIdx = filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00267           privateCode::getGradientXKernel(), image0,
00268           static_cast<Float64>(0.0), DLR_CONVOLVE_PAD_RESULT);
00269         dIdy = filter2D<GRAY_FLOAT64, GRAY_FLOAT64>(
00270           privateCode::getGradientYKernel(), image0,
00271           static_cast<Float64>(0.0), DLR_CONVOLVE_PAD_RESULT);
00272       }
00273 
00274       // Now that we have spacial gradients, dispatch to parent
00275       // version of setImages().
00276       this->setImages(image0, image1, dIdx, dIdy);
00277     }
00278 
00279 
00280     template <ImageFormat Format>
00281     void
00282     OpticalFlow<Format>::
00283     setImages(const Image<Format>& image0,
00284               const Image<Format>& image1,
00285               const Array2D<Float64>& dIdx,
00286               const Array2D<Float64>& dIdy)
00287     {
00288       if(image0.rows() != image1.rows()
00289          || image0.columns() != image1.columns()) {
00290         DLR_THROW(ValueException, "OpticalFlow::setImages()",
00291                   "Arguments image0 and image1 must have the same size.");
00292       }
00293       if(image0.rows() != dIdx.rows()
00294          || image0.columns() != dIdx.columns()) {
00295         DLR_THROW(ValueException, "OpticalFlow::setImages()",
00296                   "Arguments image0 and dIdx must have the same size.");
00297       }
00298       if(image0.rows() != dIdy.rows()
00299          || image0.columns() != dIdy.columns()) {
00300         DLR_THROW(ValueException, "OpticalFlow::setImages()",
00301                   "Arguments image0 and dIdy must have the same size.");
00302       }
00303       if(ImageFormatTraits<Format>::getNumberOfComponents() != 1) {
00304         DLR_THROW(NotImplementedException, "OpticalFlow::setImages()",
00305                   "Only single-component image formats are currently "
00306                   "supported.");
00307       }
00308 
00309       Image<GRAY_FLOAT64> image0Float =
00310         convertColorspace<GRAY_FLOAT64>(image0);
00311       Image<GRAY_FLOAT64> image1Float =
00312         convertColorspace<GRAY_FLOAT64>(image1);
00313       Array2D<Float64> dIdt = image1Float - image0Float;
00314 
00315       m_dIdx2 = dIdx * dIdx;
00316       m_dIdy2 = dIdy * dIdy;
00317       m_dIdxdIdy = dIdx * dIdy;
00318       m_dIdxdIdt = dIdx * dIdt;
00319       m_dIdydIdt = dIdy * dIdt;
00320     }
00321     
00322   
00323   } // namespace computerVision
00324   
00325 } // namespace dlr
00326 
00327 #endif /* #ifndef _DLRCOMPUTERVISION_OPTICALFLOW_H_ */

Generated on Wed Nov 25 12:15:05 2009 for dlrComputerVision Utility Library by  doxygen 1.5.8