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 }
00085
00086 }
00087
00088
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 }
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
00173 double determinant = rdIdx2 * rdIdy2 - rdIdxdIdy * rdIdxdIdy;
00174
00175 if(approximatelyEqual(determinant, 0.0, 1.0e-12)) {
00176 valid = false;
00177 return Vector2D(0.0, 0.0);
00178 }
00179
00180
00181 Float64 inverseFPrimeSq00 = rdIdy2 / determinant;
00182 Float64 inverseFPrimeSq01 = -rdIdxdIdy / determinant;
00183
00184 Float64 inverseFPrimeSq11 = rdIdx2 / determinant;
00185
00186
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
00243 if(kernelSize % 2 == 0) {
00244 kernelSize += 1;
00245 }
00246
00247
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
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
00265
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
00275
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 }
00324
00325 }
00326
00327 #endif