Merge pull request #68 from tpietruszka/deepflow
Deepflow implementation (and optical flow testing again)pull/72/head
commit
12e1e11d69
8 changed files with 1679 additions and 3 deletions
@ -0,0 +1,36 @@ |
||||
Optical flow input / output |
||||
============================ |
||||
|
||||
Functions reading and writing .flo files in "Middlebury" format, see: [MiddleburyFlo]_ |
||||
|
||||
readOpticalFlow |
||||
----------------- |
||||
Read a .flo file |
||||
|
||||
.. ocv:function:: Mat readOpticalFlow( const String& path ) |
||||
|
||||
:param path: Path to the file to be loaded |
||||
|
||||
The function readOpticalFlow loads a flow field from a file and returns it as a single matrix. |
||||
Resulting ``Mat`` has a type ``CV_32FC2`` - floating-point, 2-channel. |
||||
First channel corresponds to the flow in the horizontal direction (u), second - vertical (v). |
||||
|
||||
writeOpticalFlow |
||||
----------------- |
||||
Write a .flo to disk |
||||
|
||||
.. ocv:function:: bool writeOpticalFlow( const String& path, InputArray flow ) |
||||
|
||||
:param path: Path to the file to be written |
||||
|
||||
:param flow: Flow field to be stored |
||||
|
||||
The function stores a flow field in a file, returns ``true`` on success, ``false`` otherwise. |
||||
|
||||
The flow field must be a 2-channel, floating-point matrix (``CV_32FC2``). |
||||
First channel corresponds to the flow in the horizontal direction (u), second - vertical (v). |
||||
|
||||
|
||||
.. [MiddleburyFlo] http://vision.middlebury.edu/flow/code/flow-code/README.txt |
||||
|
||||
|
@ -0,0 +1,367 @@ |
||||
#include "opencv2/highgui.hpp" |
||||
#include "opencv2/video.hpp" |
||||
#include "opencv2/optflow.hpp" |
||||
#include <fstream> |
||||
|
||||
using namespace std; |
||||
using namespace cv; |
||||
using namespace optflow; |
||||
|
||||
const String keys = "{help h usage ? | | print this message }" |
||||
"{@image1 | | image1 }" |
||||
"{@image2 | | image2 }" |
||||
"{@algorithm | | [farneback, simpleflow, tvl1 or deepflow] }" |
||||
"{@groundtruth | | path to the .flo file (optional), Middlebury format }" |
||||
"{m measure |endpoint| error measure - [endpoint or angular] }" |
||||
"{r region |all | region to compute stats about [all, discontinuities, untextured] }" |
||||
"{d display | | display additional info images (pauses program execution) }"; |
||||
|
||||
inline bool isFlowCorrect( const Point2f u ) |
||||
{ |
||||
return !cvIsNaN(u.x) && !cvIsNaN(u.y) && (fabs(u.x) < 1e9) && (fabs(u.y) < 1e9); |
||||
} |
||||
inline bool isFlowCorrect( const Point3f u ) |
||||
{ |
||||
return !cvIsNaN(u.x) && !cvIsNaN(u.y) && !cvIsNaN(u.z) && (fabs(u.x) < 1e9) && (fabs(u.y) < 1e9) |
||||
&& (fabs(u.z) < 1e9); |
||||
} |
||||
static Mat endpointError( const Mat_<Point2f>& flow1, const Mat_<Point2f>& flow2 ) |
||||
{ |
||||
Mat result(flow1.size(), CV_32FC1); |
||||
for ( int i = 0; i < flow1.rows; ++i ) |
||||
{ |
||||
for ( int j = 0; j < flow1.cols; ++j ) |
||||
{ |
||||
const Point2f u1 = flow1(i, j); |
||||
const Point2f u2 = flow2(i, j); |
||||
|
||||
if ( isFlowCorrect(u1) && isFlowCorrect(u2) ) |
||||
{ |
||||
const Point2f diff = u1 - u2; |
||||
result.at<float>(i, j) = sqrt((float)diff.ddot(diff)); //distance
|
||||
} else |
||||
result.at<float>(i, j) = NAN; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
static Mat angularError( const Mat_<Point2f>& flow1, const Mat_<Point2f>& flow2 ) |
||||
{ |
||||
Mat result(flow1.size(), CV_32FC1); |
||||
|
||||
for ( int i = 0; i < flow1.rows; ++i ) |
||||
{ |
||||
for ( int j = 0; j < flow1.cols; ++j ) |
||||
{ |
||||
const Point2f u1_2d = flow1(i, j); |
||||
const Point2f u2_2d = flow2(i, j); |
||||
const Point3f u1(u1_2d.x, u1_2d.y, 1); |
||||
const Point3f u2(u2_2d.x, u2_2d.y, 1); |
||||
|
||||
if ( isFlowCorrect(u1) && isFlowCorrect(u2) ) |
||||
result.at<float>(i, j) = acos((float)(u1.ddot(u2) / norm(u1) * norm(u2))); |
||||
else |
||||
result.at<float>(i, j) = NAN; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
// what fraction of pixels have errors higher than given threshold?
|
||||
static float stat_RX( Mat errors, float threshold, Mat mask ) |
||||
{ |
||||
CV_Assert(errors.size() == mask.size()); |
||||
CV_Assert(mask.depth() == CV_8U); |
||||
|
||||
int count = 0, all = 0; |
||||
for ( int i = 0; i < errors.rows; ++i ) |
||||
{ |
||||
for ( int j = 0; j < errors.cols; ++j ) |
||||
{ |
||||
if ( mask.at<char>(i, j) != 0 ) |
||||
{ |
||||
++all; |
||||
if ( errors.at<float>(i, j) > threshold ) |
||||
++count; |
||||
} |
||||
} |
||||
} |
||||
return (float)count / all; |
||||
} |
||||
static float stat_AX( Mat hist, int cutoff_count, float max_value ) |
||||
{ |
||||
int counter = 0; |
||||
int bin = 0; |
||||
int bin_count = hist.rows; |
||||
while ( bin < bin_count && counter < cutoff_count ) |
||||
{ |
||||
counter += (int) hist.at<float>(bin, 0); |
||||
++bin; |
||||
} |
||||
return (float) bin / bin_count * max_value; |
||||
} |
||||
static void calculateStats( Mat errors, Mat mask = Mat(), bool display_images = false ) |
||||
{ |
||||
float R_thresholds[] = { 0.5f, 1.f, 2.f, 5.f, 10.f }; |
||||
float A_thresholds[] = { 0.5f, 0.75f, 0.95f }; |
||||
if ( mask.empty() ) |
||||
mask = Mat::ones(errors.size(), CV_8U); |
||||
CV_Assert(errors.size() == mask.size()); |
||||
CV_Assert(mask.depth() == CV_8U); |
||||
|
||||
//displaying the mask
|
||||
if(display_images) |
||||
{ |
||||
namedWindow( "Region mask", WINDOW_AUTOSIZE ); |
||||
imshow( "Region mask", mask ); |
||||
} |
||||
|
||||
//mean and std computation
|
||||
Scalar s_mean, s_std; |
||||
float mean, std; |
||||
meanStdDev(errors, s_mean, s_std, mask); |
||||
mean = (float)s_mean[0]; |
||||
std = (float)s_std[0]; |
||||
printf("Average: %.2f\nStandard deviation: %.2f\n", mean, std); |
||||
|
||||
//RX stats - displayed in percent
|
||||
float R; |
||||
int R_thresholds_count = sizeof(R_thresholds) / sizeof(float); |
||||
for ( int i = 0; i < R_thresholds_count; ++i ) |
||||
{ |
||||
R = stat_RX(errors, R_thresholds[i], mask); |
||||
printf("R%.1f: %.2f%%\n", R_thresholds[i], R * 100); |
||||
} |
||||
|
||||
//AX stats
|
||||
double max_value; |
||||
minMaxLoc(errors, NULL, &max_value, NULL, NULL, mask); |
||||
|
||||
Mat hist; |
||||
const int n_images = 1; |
||||
const int channels[] = { 0 }; |
||||
const int n_dimensions = 1; |
||||
const int hist_bins[] = { 1024 }; |
||||
const float iranges[] = { 0, (float) max_value }; |
||||
const float* ranges[] = { iranges }; |
||||
const bool uniform = true; |
||||
const bool accumulate = false; |
||||
calcHist(&errors, n_images, channels, mask, hist, n_dimensions, hist_bins, ranges, uniform, |
||||
accumulate); |
||||
int all_pixels = countNonZero(mask); |
||||
int cutoff_count; |
||||
float A; |
||||
int A_thresholds_count = sizeof(A_thresholds) / sizeof(float); |
||||
for ( int i = 0; i < A_thresholds_count; ++i ) |
||||
{ |
||||
cutoff_count = (int) (floor(A_thresholds[i] * all_pixels + 0.5f)); |
||||
A = stat_AX(hist, cutoff_count, (float) max_value); |
||||
printf("A%.2f: %.2f\n", A_thresholds[i], A); |
||||
} |
||||
} |
||||
|
||||
static Mat flowToDisplay(const Mat flow) |
||||
{ |
||||
Mat flow_split[2]; |
||||
Mat magnitude, angle; |
||||
Mat hsv_split[3], hsv, rgb; |
||||
split(flow, flow_split); |
||||
cartToPolar(flow_split[0], flow_split[1], magnitude, angle, true); |
||||
normalize(magnitude, magnitude, 0, 1, NORM_MINMAX); |
||||
hsv_split[0] = angle; // already in degrees - no normalization needed
|
||||
hsv_split[1] = Mat::ones(angle.size(), angle.type()); |
||||
hsv_split[2] = magnitude; |
||||
merge(hsv_split, 3, hsv); |
||||
cvtColor(hsv, rgb, COLOR_HSV2BGR); |
||||
return rgb; |
||||
} |
||||
|
||||
int main( int argc, char** argv ) |
||||
{ |
||||
CommandLineParser parser(argc, argv, keys); |
||||
parser.about("OpenCV optical flow evaluation app"); |
||||
if ( parser.has("help") || argc < 4 ) |
||||
{ |
||||
parser.printMessage(); |
||||
printf("EXAMPLES:\n"); |
||||
printf("./example_optflow_optical_flow_evaluation im1.png im2.png farneback -d \n"); |
||||
printf("\t - compute flow field between im1 and im2 with farneback's method and display it"); |
||||
printf("./example_optflow_optical_flow_evaluation im1.png im2.png simpleflow groundtruth.flo \n"); |
||||
printf("\t - compute error statistics given the groundtruth; all pixels, endpoint error measure"); |
||||
printf("./example_optflow_optical_flow_evaluation im1.png im2.png farneback groundtruth.flo -m=angular -r=untextured \n"); |
||||
printf("\t - as before, but with changed error measure and stats computed only about \"untextured\" areas"); |
||||
printf("\n\n Flow file format description: http://vision.middlebury.edu/flow/code/flow-code/README.txt\n\n"); |
||||
return 0; |
||||
} |
||||
String i1_path = parser.get<String>(0); |
||||
String i2_path = parser.get<String>(1); |
||||
String method = parser.get<String>(2); |
||||
String groundtruth_path = parser.get<String>(3); |
||||
String error_measure = parser.get<String>("measure"); |
||||
String region = parser.get<String>("region"); |
||||
bool display_images = parser.has("display"); |
||||
|
||||
if ( !parser.check() ) |
||||
{ |
||||
parser.printErrors(); |
||||
return 0; |
||||
} |
||||
|
||||
Mat i1, i2; |
||||
Mat_<Point2f> flow, ground_truth; |
||||
Mat computed_errors; |
||||
i1 = imread(i1_path, 1); |
||||
i2 = imread(i2_path, 1); |
||||
|
||||
if ( !i1.data || !i2.data ) |
||||
{ |
||||
printf("No image data \n"); |
||||
return -1; |
||||
} |
||||
if ( i1.size() != i2.size() || i1.channels() != i2.channels() ) |
||||
{ |
||||
printf("Dimension mismatch between input images\n"); |
||||
return -1; |
||||
} |
||||
// 8-bit images expected by all algorithms
|
||||
if ( i1.depth() != CV_8U ) |
||||
i1.convertTo(i1, CV_8U); |
||||
if ( i2.depth() != CV_8U ) |
||||
i2.convertTo(i2, CV_8U); |
||||
|
||||
if ( (method == "farneback" || method == "tvl1" || method == "deepflow") && i1.channels() == 3 ) |
||||
{ // 1-channel images are expected
|
||||
cvtColor(i1, i1, COLOR_BGR2GRAY); |
||||
cvtColor(i2, i2, COLOR_BGR2GRAY); |
||||
} else if ( method == "simpleflow" && i1.channels() == 1 ) |
||||
{ // 3-channel images expected
|
||||
cvtColor(i1, i1, COLOR_GRAY2BGR); |
||||
cvtColor(i2, i2, COLOR_GRAY2BGR); |
||||
} |
||||
|
||||
flow = Mat(i1.size[0], i1.size[1], CV_32FC2); |
||||
Ptr<DenseOpticalFlow> algorithm; |
||||
|
||||
if ( method == "farneback" ) |
||||
algorithm = createOptFlow_Farneback(); |
||||
else if ( method == "simpleflow" ) |
||||
algorithm = createOptFlow_SimpleFlow(); |
||||
else if ( method == "tvl1" ) |
||||
algorithm = createOptFlow_DualTVL1(); |
||||
else if ( method == "deepflow" ) |
||||
algorithm = createOptFlow_DeepFlow(); |
||||
else |
||||
{ |
||||
printf("Wrong method!\n"); |
||||
parser.printMessage(); |
||||
return -1; |
||||
} |
||||
|
||||
double startTick, time; |
||||
startTick = (double) getTickCount(); // measure time
|
||||
algorithm->calc(i1, i2, flow); |
||||
time = ((double) getTickCount() - startTick) / getTickFrequency(); |
||||
printf("\nTime [s]: %.3f\n", time); |
||||
if(display_images) |
||||
{ |
||||
Mat flow_image = flowToDisplay(flow); |
||||
namedWindow( "Computed flow", WINDOW_AUTOSIZE ); |
||||
imshow( "Computed flow", flow_image ); |
||||
} |
||||
|
||||
if ( !groundtruth_path.empty() ) |
||||
{ // compare to ground truth
|
||||
ground_truth = optflow::readOpticalFlow(groundtruth_path); |
||||
if ( flow.size() != ground_truth.size() || flow.channels() != 2 |
||||
|| ground_truth.channels() != 2 ) |
||||
{ |
||||
printf("Dimension mismatch between the computed flow and the provided ground truth\n"); |
||||
return -1; |
||||
} |
||||
if ( error_measure == "endpoint" ) |
||||
computed_errors = endpointError(flow, ground_truth); |
||||
else if ( error_measure == "angular" ) |
||||
computed_errors = angularError(flow, ground_truth); |
||||
else |
||||
{ |
||||
printf("Invalid error measure! Available options: endpoint, angular\n"); |
||||
return -1; |
||||
} |
||||
|
||||
Mat mask; |
||||
if( region == "all" ) |
||||
mask = Mat::ones(ground_truth.size(), CV_8U) * 255; |
||||
else if ( region == "discontinuities" ) |
||||
{ |
||||
Mat truth_merged, grad_x, grad_y, gradient; |
||||
vector<Mat> truth_split; |
||||
split(ground_truth, truth_split); |
||||
truth_merged = truth_split[0] + truth_split[1]; |
||||
|
||||
Sobel( truth_merged, grad_x, CV_16S, 1, 0, -1, 1, 0, BORDER_REPLICATE ); |
||||
grad_x = abs(grad_x); |
||||
Sobel( truth_merged, grad_y, CV_16S, 0, 1, 1, 1, 0, BORDER_REPLICATE ); |
||||
grad_y = abs(grad_y); |
||||
addWeighted(grad_x, 0.5, grad_y, 0.5, 0, gradient); //approximation!
|
||||
|
||||
Scalar s_mean; |
||||
s_mean = mean(gradient); |
||||
double threshold = s_mean[0]; // threshold value arbitrary
|
||||
mask = gradient > threshold; |
||||
dilate(mask, mask, Mat::ones(9, 9, CV_8U)); |
||||
} |
||||
else if ( region == "untextured" ) |
||||
{ |
||||
Mat i1_grayscale, grad_x, grad_y, gradient; |
||||
if( i1.channels() == 3 ) |
||||
cvtColor(i1, i1_grayscale, COLOR_BGR2GRAY); |
||||
else |
||||
i1_grayscale = i1; |
||||
Sobel( i1_grayscale, grad_x, CV_16S, 1, 0, 7 ); |
||||
grad_x = abs(grad_x); |
||||
Sobel( i1_grayscale, grad_y, CV_16S, 0, 1, 7 ); |
||||
grad_y = abs(grad_y); |
||||
addWeighted(grad_x, 0.5, grad_y, 0.5, 0, gradient); //approximation!
|
||||
GaussianBlur(gradient, gradient, Size(5,5), 1, 1); |
||||
|
||||
Scalar s_mean; |
||||
s_mean = mean(gradient); |
||||
// arbitrary threshold value used - could be determined statistically from the image?
|
||||
double threshold = 1000; |
||||
mask = gradient < threshold; |
||||
dilate(mask, mask, Mat::ones(3, 3, CV_8U)); |
||||
} |
||||
|
||||
else |
||||
{ |
||||
printf("Invalid region selected! Available options: all, discontinuities, untextured"); |
||||
return -1; |
||||
} |
||||
|
||||
//masking out NaNs and incorrect GT values
|
||||
Mat truth_split[2]; |
||||
split(ground_truth, truth_split); |
||||
Mat abs_mask = Mat((abs(truth_split[0]) < 1e9) & (abs(truth_split[1]) < 1e9)); |
||||
Mat nan_mask = Mat((truth_split[0]==truth_split[0]) & (truth_split[1] == truth_split[1])); |
||||
bitwise_and(abs_mask, nan_mask, nan_mask); |
||||
|
||||
bitwise_and(nan_mask, mask, mask); //including the selected region
|
||||
|
||||
if(display_images) // display difference between computed and GT flow
|
||||
{ |
||||
Mat difference = ground_truth - flow; |
||||
Mat masked_difference; |
||||
difference.copyTo(masked_difference, mask); |
||||
Mat flow_image = flowToDisplay(masked_difference); |
||||
namedWindow( "Error map", WINDOW_AUTOSIZE ); |
||||
imshow( "Error map", flow_image ); |
||||
} |
||||
|
||||
printf("Using %s error measure\n", error_measure.c_str()); |
||||
calculateStats(computed_errors, mask, display_images); |
||||
|
||||
} |
||||
if(display_images) // wait for the user to see all the images
|
||||
waitKey(0); |
||||
return 0; |
||||
|
||||
} |
@ -0,0 +1,868 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp" |
||||
#include <opencv2/highgui.hpp> |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace optflow |
||||
{ |
||||
|
||||
class OpticalFlowDeepFlow: public DenseOpticalFlow |
||||
{ |
||||
public: |
||||
OpticalFlowDeepFlow(); |
||||
|
||||
void calc( InputArray I0, InputArray I1, InputOutputArray flow ); |
||||
void collectGarbage(); |
||||
|
||||
// AlgorithmInfo* info() const;
|
||||
|
||||
protected: |
||||
float sigma; // Gaussian smoothing parameter
|
||||
int minSize; // minimal dimension of an image in the pyramid
|
||||
float downscaleFactor; // scaling factor in the pyramid
|
||||
int fixedPointIterations; // during each level of the pyramid
|
||||
int sorIterations; // iterations of SOR
|
||||
float alpha; // smoothness assumption weight
|
||||
float delta; // color constancy weight
|
||||
float gamma; // gradient constancy weight
|
||||
float omega; // relaxation factor in SOR
|
||||
|
||||
float zeta; // added to the denomimnator of theta_0 (normaliation of the data term)
|
||||
float epsilon; // robust penalizer const
|
||||
int maxLayers; // max amount of layers in the pyramid
|
||||
|
||||
private: |
||||
void calcOneLevel( const Mat I0, const Mat I1, Mat W ); |
||||
Mat warpImage( const Mat input, const Mat flow ); |
||||
void dataTerm( const Mat W, const Mat dW, const Mat Ix, const Mat Iy, const Mat Iz, |
||||
const Mat Ixx, const Mat Ixy, const Mat Iyy, const Mat Ixz, const Mat Iyz, |
||||
Mat a11, Mat a12, Mat a22, Mat b1, Mat b2 ); |
||||
void smoothnessWeights( const Mat W, Mat weightsX, Mat weightsY ); |
||||
void smoothnessTerm( const Mat W, const Mat weightsX, const Mat weightsY, Mat b1, Mat b2 ); |
||||
void sorSolve( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2, |
||||
const Mat smoothX, const Mat smoothY, Mat dW ); |
||||
void sorUnfolded( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2, |
||||
const Mat smoothX, const Mat smoothY, Mat dW ); |
||||
std::vector<Mat> buildPyramid( const Mat& src ); |
||||
|
||||
int interpolationType; |
||||
|
||||
}; |
||||
|
||||
OpticalFlowDeepFlow::OpticalFlowDeepFlow() |
||||
{ |
||||
// parameters
|
||||
sigma = 0.6f; |
||||
minSize = 25; |
||||
downscaleFactor = 0.95f; |
||||
fixedPointIterations = 5; |
||||
sorIterations = 25; |
||||
alpha = 1.0f; |
||||
delta = 0.5f; |
||||
gamma = 5.0f; |
||||
omega = 1.6f; |
||||
|
||||
//consts
|
||||
interpolationType = INTER_LINEAR; |
||||
zeta = 0.1f; |
||||
epsilon = 0.001f; |
||||
maxLayers = 200; |
||||
} |
||||
|
||||
std::vector<Mat> OpticalFlowDeepFlow::buildPyramid( const Mat& src ) |
||||
{ |
||||
std::vector<Mat> pyramid; |
||||
pyramid.push_back(src); |
||||
Mat prev = pyramid[0]; |
||||
int i = 0; |
||||
while ( i < this->maxLayers ) |
||||
{ |
||||
Mat next; //TODO: filtering at each level?
|
||||
Size nextSize((int) (prev.cols * downscaleFactor + 0.5f), |
||||
(int) (prev.rows * downscaleFactor + 0.5f)); |
||||
if( nextSize.height <= minSize || nextSize.width <= minSize) |
||||
break; |
||||
resize(prev, next, |
||||
nextSize, 0, 0, |
||||
interpolationType); |
||||
pyramid.push_back(next); |
||||
prev = next; |
||||
} |
||||
return pyramid; |
||||
} |
||||
Mat OpticalFlowDeepFlow::warpImage( const Mat input, const Mat flow ) |
||||
{ |
||||
// warps the image "backwards"
|
||||
// if flow = computeFlow( I0, I1 ), then
|
||||
// I0 = warpImage( I1, flow ) - approx.
|
||||
|
||||
Mat output; |
||||
Mat mapX = Mat(flow.size(), CV_32FC1); |
||||
Mat mapY = Mat(flow.size(), CV_32FC1); |
||||
const float *pFlow; |
||||
float *pMapX, *pMapY; |
||||
for ( int j = 0; j < flow.rows; ++j ) |
||||
{ |
||||
pFlow = flow.ptr<float>(j); |
||||
pMapX = mapX.ptr<float>(j); |
||||
pMapY = mapY.ptr<float>(j); |
||||
for ( int i = 0; i < flow.cols; ++i ) |
||||
{ |
||||
pMapX[i] = i + pFlow[2 * i]; |
||||
pMapY[i] = j + pFlow[2 * i + 1]; |
||||
} |
||||
} |
||||
remap(input, output, mapX, mapY, interpolationType, BORDER_TRANSPARENT); |
||||
return output; |
||||
} |
||||
void OpticalFlowDeepFlow::calc( InputArray _I0, InputArray _I1, InputOutputArray _flow ) |
||||
{ |
||||
Mat I0temp = _I0.getMat(); |
||||
Mat I1temp = _I1.getMat(); |
||||
|
||||
CV_Assert(I0temp.size() == I1temp.size()); |
||||
CV_Assert(I0temp.type() == I1temp.type()); |
||||
CV_Assert(I0temp.channels() == 1); |
||||
// TODO: currently only grayscale - data term could be computed in color version as well...
|
||||
|
||||
Mat I0, I1; |
||||
|
||||
I0temp.convertTo(I0, CV_32F); |
||||
I1temp.convertTo(I1, CV_32F); |
||||
|
||||
_flow.create(I0.size(), CV_32FC2); |
||||
Mat W = _flow.getMat(); // if any data present - will be discarded
|
||||
|
||||
// pre-smooth images
|
||||
int kernelLen = ((int)floor(3 * sigma) * 2) + 1; |
||||
Size kernelSize(kernelLen, kernelLen); |
||||
GaussianBlur(I0, I0, kernelSize, sigma); |
||||
GaussianBlur(I1, I1, kernelSize, sigma); |
||||
// build down-sized pyramids
|
||||
std::vector<Mat> pyramid_I0 = buildPyramid(I0); |
||||
std::vector<Mat> pyramid_I1 = buildPyramid(I1); |
||||
int levelCount = (int) pyramid_I0.size(); |
||||
|
||||
// initialize the first version of flow estimate to zeros
|
||||
Size smallestSize = pyramid_I0[levelCount - 1].size(); |
||||
W = Mat::zeros(smallestSize, CV_32FC2); |
||||
|
||||
for ( int level = levelCount - 1; level >= 0; --level ) |
||||
{ //iterate through all levels, beginning with the most coarse
|
||||
calcOneLevel(pyramid_I0[level], pyramid_I1[level], W); |
||||
if ( level > 0 ) //not the last level
|
||||
{ |
||||
Mat temp; |
||||
Size newSize = pyramid_I0[level - 1].size(); |
||||
resize(W, temp, newSize, 0, 0, interpolationType); //resize calculated flow
|
||||
W = temp * (1.0f / downscaleFactor); //scale values
|
||||
} |
||||
} |
||||
W.copyTo(_flow); |
||||
} |
||||
|
||||
void OpticalFlowDeepFlow::calcOneLevel( const Mat I0, const Mat I1, Mat W ) |
||||
{ |
||||
CV_DbgAssert( I0.size() == I1.size() );CV_DbgAssert( I0.type() == I1.type() );CV_DbgAssert( W.size() == I0.size() ); |
||||
|
||||
// linear equation systems
|
||||
Size s = I0.size(); |
||||
int t = CV_32F; // data type
|
||||
Mat a11, a12, a22, b1, b2; |
||||
a11.create(s, t); |
||||
a12.create(s, t); |
||||
a22.create(s, t); |
||||
b1.create(s, t); |
||||
b2.create(s, t); |
||||
// diffusivity coeffs
|
||||
Mat weightsX, weightsY; |
||||
weightsX.create(s, t); |
||||
weightsY.create(s, t); |
||||
|
||||
Mat warpedI1 = warpImage(I1, W); // warped second image
|
||||
Mat averageFrame = 0.5 * (I0 + warpedI1); // mean value of 2 frames - to compute derivatives on
|
||||
|
||||
//computing derivatives, notation as in Brox's paper
|
||||
Mat Ix, Iy, Iz, Ixx, Ixy, Iyy, Ixz, Iyz; |
||||
int ddepth = -1; //as source image
|
||||
int kernel_size = 1; |
||||
|
||||
Sobel(averageFrame, Ix, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Sobel(averageFrame, Iy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Iz.create(I1.size(), I1.type()); |
||||
Iz = warpedI1 - I0; |
||||
Sobel(Ix, Ixx, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Sobel(Ix, Ixy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Sobel(Iy, Iyy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Sobel(Iz, Ixz, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
Sobel(Iz, Iyz, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE); |
||||
|
||||
Mat tempW = W.clone(); // flow version to be modified in each iteration
|
||||
Mat dW = Mat::zeros(W.size(), W.type()); // flow increment
|
||||
|
||||
//fixed-point iterations
|
||||
for ( int i = 0; i < fixedPointIterations; ++i ) |
||||
{ |
||||
dataTerm(W, dW, Ix, Iy, Iz, Ixx, Ixy, Iyy, Ixz, Iyz, a11, a12, a22, b1, b2); |
||||
smoothnessWeights(tempW, weightsX, weightsY); |
||||
smoothnessTerm(W, weightsX, weightsY, b1, b2); |
||||
sorSolve(a11, a12, a22, b1, b2, weightsX, weightsY, dW); |
||||
tempW = W + dW; |
||||
} |
||||
tempW.copyTo(W); |
||||
} |
||||
void OpticalFlowDeepFlow::dataTerm( const Mat W, const Mat dW, const Mat Ix, const Mat Iy, |
||||
const Mat Iz, const Mat Ixx, const Mat Ixy, const Mat Iyy, const Mat Ixz, |
||||
const Mat Iyz, Mat a11, Mat a12, Mat a22, Mat b1, Mat b2 ) |
||||
{ |
||||
const float zeta_squared = zeta * zeta; // added in normalization factor to be non-zero
|
||||
const float epsilon_squared = epsilon * epsilon; |
||||
|
||||
const float *pIx, *pIy, *pIz; |
||||
const float *pIxx, *pIxy, *pIyy, *pIxz, *pIyz; |
||||
const float *pdU, *pdV; // accessing 2 layers of dW. Succesive columns interleave u and v
|
||||
float *pa11, *pa12, *pa22, *pb1, *pb2; // linear equation sys. coeffs for each pixel
|
||||
|
||||
float derivNorm; //denominator of the spatial-derivative normalizing factor (theta_0)
|
||||
float derivNorm2; |
||||
float Ik1z, Ik1zx, Ik1zy; // approximations of I^(k+1) values by Taylor expansions
|
||||
float temp; |
||||
for ( int j = 0; j < W.rows; j++ ) //for each row
|
||||
{ |
||||
pIx = Ix.ptr<float>(j); |
||||
pIy = Iy.ptr<float>(j); |
||||
pIz = Iz.ptr<float>(j); |
||||
pIxx = Ixx.ptr<float>(j); |
||||
pIxy = Ixy.ptr<float>(j); |
||||
pIyy = Iyy.ptr<float>(j); |
||||
pIxz = Ixz.ptr<float>(j); |
||||
pIyz = Iyz.ptr<float>(j); |
||||
|
||||
pa11 = a11.ptr<float>(j); |
||||
pa12 = a12.ptr<float>(j); |
||||
pa22 = a22.ptr<float>(j); |
||||
pb1 = b1.ptr<float>(j); |
||||
pb2 = b2.ptr<float>(j); |
||||
|
||||
pdU = dW.ptr<float>(j); |
||||
pdV = pdU + 1; |
||||
for ( int i = 0; i < W.cols; i++ ) //for each pixel in the row
|
||||
{ // TODO: implement masking of points warped out of the image
|
||||
//color constancy component
|
||||
derivNorm = (*pIx) * (*pIx) + (*pIy) * (*pIy) + zeta_squared; |
||||
Ik1z = *pIz + (*pIx * *pdU) + (*pIy * *pdV); |
||||
temp = (0.5f*delta/3) / sqrt(Ik1z * Ik1z / derivNorm + epsilon_squared); |
||||
*pa11 = *pIx * *pIx * temp / derivNorm; |
||||
*pa12 = *pIx * *pIy * temp / derivNorm; |
||||
*pa22 = *pIy * *pIy * temp / derivNorm; |
||||
*pb1 = -*pIz * *pIx * temp / derivNorm; |
||||
*pb2 = -*pIz * *pIy * temp / derivNorm; |
||||
|
||||
// gradient constancy component
|
||||
|
||||
derivNorm = *pIxx * *pIxx + *pIxy * *pIxy + zeta_squared; |
||||
derivNorm2 = *pIyy * *pIyy + *pIxy * *pIxy + zeta_squared; |
||||
Ik1zx = *pIxz + *pIxx * *pdU + *pIxy * *pdV; |
||||
Ik1zy = *pIyz + *pIxy * *pdU + *pIyy * *pdV; |
||||
|
||||
temp = (0.5f*gamma/3) |
||||
/ sqrt( |
||||
Ik1zx * Ik1zx / derivNorm + Ik1zy * Ik1zy / derivNorm2 |
||||
+ epsilon_squared); |
||||
*pa11 += temp * (*pIxx * *pIxx / derivNorm + *pIxy * *pIxy / derivNorm2); |
||||
*pa12 += temp * (*pIxx * *pIxy / derivNorm + *pIxy * *pIyy / derivNorm2); |
||||
*pa22 += temp * (*pIxy * *pIxy / derivNorm + *pIyy * *pIyy / derivNorm2); |
||||
*pb1 += -temp * (*pIxx * *pIxz / derivNorm + *pIxy * *pIyz / derivNorm2); |
||||
*pb2 += -temp * (*pIxy * *pIxz / derivNorm + *pIyy * *pIyz / derivNorm2); |
||||
|
||||
++pIx; |
||||
++pIy; |
||||
++pIz; |
||||
++pIxx; |
||||
++pIxy; |
||||
++pIyy; |
||||
++pIxz; |
||||
++pIyz; |
||||
pdU += 2; |
||||
pdV += 2; |
||||
++pa11; |
||||
++pa12; |
||||
++pa22; |
||||
++pb1; |
||||
++pb2; |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
void OpticalFlowDeepFlow::smoothnessWeights( const Mat W, Mat weightsX, Mat weightsY ) |
||||
{ |
||||
float k[] = { -0.5, 0, 0.5 }; |
||||
const float epsilon_squared = epsilon * epsilon; |
||||
Mat kernel_h = Mat(1, 3, CV_32FC1, k); |
||||
Mat kernel_v = Mat(3, 1, CV_32FC1, k); |
||||
Mat Wx, Wy; // partial derivatives of the flow
|
||||
Mat S = Mat(W.size(), CV_32FC1); // sum of squared derivatives
|
||||
weightsX = Mat::zeros(W.size(), CV_32FC1); //output - weights of smoothness terms in x and y directions
|
||||
weightsY = Mat::zeros(W.size(), CV_32FC1); |
||||
|
||||
filter2D(W, Wx, CV_32FC2, kernel_h); |
||||
filter2D(W, Wy, CV_32FC2, kernel_v); |
||||
|
||||
const float * ux, *uy, *vx, *vy; |
||||
float * pS, *pWeight, *temp; |
||||
|
||||
for ( int j = 0; j < S.rows; ++j ) |
||||
{ |
||||
ux = Wx.ptr<float>(j); |
||||
vx = ux + 1; |
||||
uy = Wy.ptr<float>(j); |
||||
vy = uy + 1; |
||||
pS = S.ptr<float>(j); |
||||
for ( int i = 0; i < S.cols; ++i ) |
||||
{ |
||||
*pS = alpha / sqrt(*ux * *ux + *vx * *vx + *uy * *uy + *vy * *vy + epsilon_squared); |
||||
ux += 2; |
||||
vx += 2; |
||||
uy += 2; |
||||
vy += 2; |
||||
++pS; |
||||
} |
||||
} |
||||
// horizontal weights
|
||||
for ( int j = 0; j < S.rows; ++j ) |
||||
{ |
||||
pWeight = weightsX.ptr<float>(j); |
||||
pS = S.ptr<float>(j); |
||||
for ( int i = 0; i < S.cols - 1; ++i ) |
||||
{ |
||||
*pWeight = *pS + *(pS + 1); |
||||
++pS; |
||||
++pWeight; |
||||
} |
||||
} |
||||
//vertical weights
|
||||
for ( int j = 0; j < S.rows - 1; ++j ) |
||||
{ |
||||
pWeight = weightsY.ptr<float>(j); |
||||
pS = S.ptr<float>(j); |
||||
temp = S.ptr<float>(j + 1); // next row pointer for easy access
|
||||
for ( int i = 0; i < S.cols; ++i ) |
||||
{ |
||||
*pWeight = *(pS++) + *(temp++); |
||||
++pWeight; |
||||
} |
||||
} |
||||
} |
||||
void OpticalFlowDeepFlow::smoothnessTerm( const Mat W, const Mat weightsX, const Mat weightsY, |
||||
Mat b1, Mat b2 ) |
||||
{ |
||||
float *pB1, *pB2; |
||||
const float *pU, *pV, *pWeight; |
||||
float iB1, iB2; // increments of b1 and b2
|
||||
//horizontal direction - both U and V (b1 and b2)
|
||||
for ( int j = 0; j < W.rows; j++ ) |
||||
{ |
||||
pB1 = b1.ptr<float>(j); |
||||
pB2 = b2.ptr<float>(j); |
||||
pU = W.ptr<float>(j); |
||||
pV = pU + 1; |
||||
pWeight = weightsX.ptr<float>(j); |
||||
for ( int i = 0; i < W.cols - 1; i++ ) |
||||
{ |
||||
iB1 = (*(pU + 2) - *pU) * *pWeight; |
||||
iB2 = (*(pV + 2) - *pV) * *pWeight; |
||||
*pB1 += iB1; |
||||
*(pB1 + 1) -= iB1; |
||||
*pB2 += iB2; |
||||
*(pB2 + 1) -= iB2; |
||||
|
||||
pB1++; |
||||
pB2++; |
||||
pU += 2; |
||||
pV += 2; |
||||
pWeight++; |
||||
} |
||||
} |
||||
const float *pUnext, *pVnext; // temp pointers for next row
|
||||
float *pB1next, *pB2next; |
||||
//vertical direction - both U and V
|
||||
for ( int j = 0; j < W.rows - 1; j++ ) |
||||
{ |
||||
pB1 = b1.ptr<float>(j); |
||||
pB2 = b2.ptr<float>(j); |
||||
pU = W.ptr<float>(j); |
||||
pV = pU + 1; |
||||
pUnext = W.ptr<float>(j + 1); |
||||
pVnext = pUnext + 1; |
||||
pB1next = b1.ptr<float>(j + 1); |
||||
pB2next = b2.ptr<float>(j + 1); |
||||
pWeight = weightsY.ptr<float>(j); |
||||
for ( int i = 0; i < W.cols; i++ ) |
||||
{ |
||||
iB1 = (*pUnext - *pU) * *pWeight; |
||||
iB2 = (*pVnext - *pV) * *pWeight; |
||||
*pB1 += iB1; |
||||
*pB1next -= iB1; |
||||
*pB2 += iB2; |
||||
*pB2next -= iB2; |
||||
|
||||
pB1++; |
||||
pB2++; |
||||
pU += 2; |
||||
pV += 2; |
||||
pWeight++; |
||||
pUnext += 2; |
||||
pVnext += 2; |
||||
pB1next++; |
||||
pB2next++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void OpticalFlowDeepFlow::sorSolve( const Mat a11, const Mat a12, const Mat a22, const Mat b1, |
||||
const Mat b2, const Mat smoothX, const Mat smoothY, Mat dW ) |
||||
{ |
||||
CV_Assert(a11.isContinuous()); |
||||
CV_Assert(a12.isContinuous()); |
||||
CV_Assert(a22.isContinuous()); |
||||
CV_Assert(b1.isContinuous()); |
||||
CV_Assert(b2.isContinuous()); |
||||
CV_Assert(smoothX.isContinuous()); |
||||
CV_Assert(smoothY.isContinuous()); |
||||
|
||||
if(dW.cols > 2 && dW.rows > 2) |
||||
{ |
||||
sorUnfolded(a11, a12, a22, b1, b2, smoothX, smoothY, dW ); |
||||
//more efficient version - this one is mostly for future reference and readability
|
||||
return; |
||||
} |
||||
std::vector<Mat> dWChannels(2); |
||||
split(dW, dWChannels); |
||||
|
||||
Mat *du = &(dWChannels[0]); |
||||
Mat *dv = &(dWChannels[1]); |
||||
|
||||
CV_Assert(du->isContinuous()); |
||||
CV_Assert(dv->isContinuous()); |
||||
|
||||
const float *pa11, *pa12, *pa22, *pb1, *pb2, *psmoothX, *psmoothY; |
||||
float *pdu, *pdv; |
||||
psmoothX = smoothX.ptr<float>(0); |
||||
psmoothY = smoothY.ptr<float>(0); |
||||
pdu = du->ptr<float>(0); |
||||
pdv = dv->ptr<float>(0); |
||||
|
||||
float sigmaU, sigmaV, dPsi, A11, A22, A12, B1, B2, det; |
||||
|
||||
int cols = dW.cols; |
||||
int rows = dW.rows; |
||||
|
||||
int s = dW.cols; // step between rows
|
||||
|
||||
for ( int iter = 0; iter < sorIterations; ++iter ) |
||||
{ |
||||
pa11 = a11.ptr<float>(0); |
||||
pa12 = a12.ptr<float>(0); |
||||
pa22 = a22.ptr<float>(0); |
||||
pb1 = b1.ptr<float>(0); |
||||
pb2 = b2.ptr<float>(0); |
||||
for ( int j = 0; j < rows; ++j ) |
||||
{ |
||||
for ( int i = 0; i < cols; ++i ) |
||||
{ |
||||
int o = j * s + i; |
||||
if ( i == 0 && j == 0 ) |
||||
{ |
||||
dPsi = psmoothX[o] + psmoothY[o]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s]; |
||||
} else if ( i == cols - 1 && j == 0 ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
} else if ( j == 0 ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s]; |
||||
} else if ( i == 0 && j == rows - 1 ) |
||||
{ |
||||
dPsi = psmoothX[o] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
} else if ( i == cols - 1 && j == rows - 1 ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
} else if ( j == rows - 1 ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
} else if ( i == 0 ) |
||||
{ |
||||
dPsi = psmoothX[o] + psmoothY[o - s] + psmoothY[o]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
} else if ( i == cols - 1 ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothY[o - s] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
} else |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s] |
||||
+ psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
} |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
} |
||||
} |
||||
} |
||||
merge(dWChannels, dW); |
||||
} |
||||
|
||||
|
||||
void OpticalFlowDeepFlow::sorUnfolded( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2, |
||||
const Mat smoothX, const Mat smoothY, Mat dW ) |
||||
{ |
||||
// the same effect as sorSolve(), but written more efficiently
|
||||
std::vector<Mat> dWChannels(2); |
||||
split(dW, dWChannels); |
||||
|
||||
Mat *du = &(dWChannels[0]); |
||||
Mat *dv = &(dWChannels[1]); |
||||
|
||||
CV_Assert(du->isContinuous()); |
||||
CV_Assert(dv->isContinuous()); |
||||
|
||||
const float *pa11, *pa12, *pa22, *pb1, *pb2, *psmoothX, *psmoothY; |
||||
float *pdu, *pdv; |
||||
|
||||
|
||||
float sigmaU, sigmaV, dPsi, A11, A22, A12, B1, B2, det; |
||||
|
||||
int cols = dW.cols; |
||||
int rows = dW.rows; |
||||
|
||||
int s = dW.cols; // step between rows
|
||||
int j, i, o; //row, column, offset
|
||||
|
||||
for ( int iter = 0; iter < sorIterations; ++iter ) |
||||
{ |
||||
pa11 = a11.ptr<float>(0); |
||||
pa12 = a12.ptr<float>(0); |
||||
pa22 = a22.ptr<float>(0); |
||||
pb1 = b1.ptr<float>(0); |
||||
pb2 = b2.ptr<float>(0); |
||||
psmoothX = smoothX.ptr<float>(0); |
||||
psmoothY = smoothY.ptr<float>(0); |
||||
pdu = du->ptr<float>(0); |
||||
pdv = dv->ptr<float>(0); |
||||
|
||||
// first row
|
||||
// first column
|
||||
o=0; |
||||
dPsi = psmoothX[o] + psmoothY[o]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
// middle rows
|
||||
for ( o = 1; o < cols-1; ++o ) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
} |
||||
// last column
|
||||
dPsi = psmoothX[o - 1] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
//middle rows
|
||||
for ( j = 1; j < rows - 1; ++j) |
||||
{ |
||||
// first column
|
||||
dPsi = psmoothX[o] + psmoothY[o - s] + psmoothY[o]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
// middle columns
|
||||
for ( i = 1; i < cols - 1; ++i) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s] |
||||
+ psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
} |
||||
//last column
|
||||
dPsi = psmoothX[o - 1] + psmoothY[o - s] + psmoothY[o]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o - s] * pdu[o - s] |
||||
+ psmoothY[o] * pdu[o + s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o - s] * pdv[o - s] |
||||
+ psmoothY[o] * pdv[o + s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
} |
||||
//last row
|
||||
//first column
|
||||
dPsi = psmoothX[o] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
//middle columns
|
||||
for ( i = 1; i < cols - 1; ++i) |
||||
{ |
||||
dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothX[o] * pdu[o + 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothX[o] * pdv[o + 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
++o; |
||||
} |
||||
//last column
|
||||
dPsi = psmoothX[o - 1] + psmoothY[o - s]; |
||||
sigmaU = psmoothX[o - 1] * pdu[o - 1] |
||||
+ psmoothY[o - s] * pdu[o - s]; |
||||
sigmaV = psmoothX[o - 1] * pdv[o - 1] |
||||
+ psmoothY[o - s] * pdv[o - s]; |
||||
A11 = *pa22 + dPsi; |
||||
A12 = -*pa12; |
||||
A22 = *pa11 + dPsi; |
||||
det = A11 * A22 - A12 * A12; |
||||
A11 /= det; |
||||
A12 /= det; |
||||
A22 /= det; |
||||
B1 = *pb1 + sigmaU; |
||||
B2 = *pb2 + sigmaV; |
||||
pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]); |
||||
pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]); |
||||
++pa11; ++pa12; ++pa22; ++pb1; ++pb2; |
||||
} |
||||
merge(dWChannels, dW); |
||||
|
||||
} |
||||
void OpticalFlowDeepFlow::collectGarbage() |
||||
{ |
||||
|
||||
} |
||||
//
|
||||
//CV_INIT_ALGORITHM(OpticalFlowDeepFlow, "DenseOpticalFlow.DeepFlow",
|
||||
// obj.info()->addParam(obj, "sigma", obj.sigma, false, 0, 0, "Gaussian blur parameter");
|
||||
// obj.info()->addParam(obj, "alpha", obj.alpha, false, 0, 0, "Smoothness assumption weight");
|
||||
// obj.info()->addParam(obj, "delta", obj.delta, false, 0, 0, "Color constancy weight");
|
||||
// obj.info()->addParam(obj, "gamma", obj.gamma, false, 0, 0, "Gradient constancy weight");
|
||||
// obj.info()->addParam(obj, "omega", obj.omega, false, 0, 0, "Relaxation factor in SOR");
|
||||
// obj.info()->addParam(obj, "minSize", obj.minSize, false, 0, 0, "Min. image size in the pyramid");
|
||||
// obj.info()->addParam(obj, "fixedPointIterations", obj.fixedPointIterations, false, 0, 0, "Fixed point iterations");
|
||||
// obj.info()->addParam(obj, "sorIterations", obj.sorIterations, false, 0, 0, "SOR iterations");
|
||||
// obj.info()->addParam(obj, "downscaleFactor", obj.downscaleFactor, false, 0, 0,"Downscale factor"))
|
||||
|
||||
|
||||
Ptr<DenseOpticalFlow> createOptFlow_DeepFlow() |
||||
{ |
||||
return makePtr<OpticalFlowDeepFlow>(); |
||||
} |
||||
|
||||
}//optflow
|
||||
}//cv
|
@ -0,0 +1,183 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp" |
||||
|
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include "opencv2/video.hpp" |
||||
#include "opencv2/optflow.hpp" |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace optflow |
||||
{ |
||||
class OpticalFlowSimpleFlow : public DenseOpticalFlow |
||||
{ |
||||
public: |
||||
OpticalFlowSimpleFlow(); |
||||
void calc(InputArray I0, InputArray I1, InputOutputArray flow); |
||||
void collectGarbage(); |
||||
// AlgorithmInfo* info() const;
|
||||
|
||||
protected: |
||||
int layers; |
||||
int averaging_radius; |
||||
int max_flow; |
||||
double sigma_dist; |
||||
double sigma_color; |
||||
int postprocess_window; |
||||
double sigma_dist_fix; |
||||
double sigma_color_fix; |
||||
double occ_thr; |
||||
int upscale_averaging_radius; |
||||
double upscale_sigma_dist; |
||||
double upscale_sigma_color; |
||||
double speed_up_thr; |
||||
}; |
||||
|
||||
OpticalFlowSimpleFlow::OpticalFlowSimpleFlow() |
||||
{ |
||||
// values from the example app
|
||||
layers = 3; |
||||
averaging_radius = 2; |
||||
max_flow = 4; |
||||
// values from the default function parameters
|
||||
sigma_dist = 4.1; |
||||
sigma_color = 25.5; |
||||
postprocess_window = 18; |
||||
sigma_dist_fix = 55.0; |
||||
sigma_color_fix = 25.5; |
||||
occ_thr = 0.35; |
||||
upscale_averaging_radius = 18; |
||||
upscale_sigma_dist = 55.0; |
||||
upscale_sigma_color = 25.5; |
||||
speed_up_thr = 10; |
||||
} |
||||
|
||||
void OpticalFlowSimpleFlow::calc(InputArray I0, InputArray I1, InputOutputArray flow) |
||||
{ |
||||
optflow::calcOpticalFlowSF(I0, I1, flow, layers, averaging_radius, max_flow, sigma_dist, sigma_color, |
||||
postprocess_window, sigma_dist_fix, sigma_color_fix, occ_thr, |
||||
upscale_averaging_radius, upscale_sigma_dist, upscale_sigma_color, speed_up_thr); |
||||
} |
||||
void OpticalFlowSimpleFlow::collectGarbage() |
||||
{ |
||||
|
||||
} |
||||
//CV_INIT_ALGORITHM(OpticalFlowSimpleFlow, "DenseOpticalFlow.SimpleFlow"),
|
||||
// obj.info()->addParam(obj, "layers", obj.layers);
|
||||
// obj.info()->addParam(obj, "averaging_radius", obj.averaging_radius);
|
||||
// obj.info()->addParam(obj, "max_flow", obj.max_flow);
|
||||
// obj.info()->addParam(obj, "sigma_dist", obj.sigma_dist);
|
||||
// obj.info()->addParam(obj, "sigma_color", obj.sigma_color);
|
||||
// obj.info()->addParam(obj, "postprocess_window", obj.postprocess_window);
|
||||
// obj.info()->addParam(obj, "sigma_dist_fix", obj.sigma_dist_fix);
|
||||
// obj.info()->addParam(obj, "sigma_color_fix", obj.sigma_color_fix);
|
||||
// obj.info()->addParam(obj, "occ_thr", obj.occ_thr);
|
||||
// obj.info()->addParam(obj, "upscale_averaging_radius", obj.upscale_averaging_radius);
|
||||
// obj.info()->addParam(obj, "upscale_sigma_dist", obj.upscale_sigma_dist);
|
||||
// obj.info()->addParam(obj, "upscale_sigma_color", obj.upscale_sigma_color);
|
||||
// obj.info()->addParam(obj, "speed_up_thr", obj.speed_up_thr))
|
||||
|
||||
Ptr<DenseOpticalFlow> createOptFlow_SimpleFlow() |
||||
{ |
||||
return makePtr<OpticalFlowSimpleFlow>(); |
||||
} |
||||
|
||||
class OpticalFlowFarneback : public DenseOpticalFlow |
||||
{ |
||||
public: |
||||
OpticalFlowFarneback(); |
||||
void calc(InputArray I0, InputArray I1, InputOutputArray flow); |
||||
void collectGarbage(); |
||||
// AlgorithmInfo* info() const;
|
||||
protected: |
||||
int numLevels; |
||||
double pyrScale; |
||||
bool fastPyramids; |
||||
int winSize; |
||||
int numIters; |
||||
int polyN; |
||||
double polySigma; |
||||
int flags; |
||||
}; |
||||
|
||||
OpticalFlowFarneback::OpticalFlowFarneback() |
||||
{ |
||||
// values copied from the FarnebackOpticalFlow class
|
||||
numLevels = 5; |
||||
pyrScale = 0.5; |
||||
fastPyramids = false; |
||||
winSize = 13; |
||||
numIters = 10; |
||||
polyN = 5; |
||||
polySigma = 1.1; |
||||
flags = 0; |
||||
} |
||||
|
||||
void OpticalFlowFarneback::calc(InputArray I0, InputArray I1, InputOutputArray flow) |
||||
{ |
||||
calcOpticalFlowFarneback(I0, I1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); |
||||
} |
||||
void OpticalFlowFarneback::collectGarbage() |
||||
{ |
||||
} |
||||
|
||||
//CV_INIT_ALGORITHM(OpticalFlowFarneback, "DenseOpticalFlow.Farneback",
|
||||
// obj.info()->addParam(obj, "numLevels", obj.numLevels);
|
||||
// obj.info()->addParam(obj, "pyrScale", obj.pyrScale);
|
||||
// obj.info()->addParam(obj, "fastPyramids", obj.fastPyramids);
|
||||
// obj.info()->addParam(obj, "winSize", obj.winSize);
|
||||
// obj.info()->addParam(obj, "numIters", obj.numIters);
|
||||
// obj.info()->addParam(obj, "polyN", obj.polyN);
|
||||
// obj.info()->addParam(obj, "polySigma", obj.polySigma);
|
||||
// obj.info()->addParam(obj, "flags", obj.flags))
|
||||
|
||||
|
||||
|
||||
|
||||
Ptr<DenseOpticalFlow> createOptFlow_Farneback() |
||||
{ |
||||
return makePtr<OpticalFlowFarneback>(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,139 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "precomp.hpp" |
||||
#include<iostream> |
||||
#include<fstream> |
||||
|
||||
namespace cv { |
||||
namespace optflow { |
||||
const float FLOW_TAG_FLOAT = 202021.25f; |
||||
const char *FLOW_TAG_STRING = "PIEH"; |
||||
CV_EXPORTS_W Mat readOpticalFlow( const String& path ) |
||||
{ |
||||
// CV_Assert(sizeof(float) == 4);
|
||||
//FIXME: ensure right sizes of int and float - here and in writeOpticalFlow()
|
||||
|
||||
Mat_<Point2f> flow; |
||||
std::ifstream file(path.c_str(), std::ios_base::binary); |
||||
if ( !file.good() ) |
||||
return flow; // no file - return empty matrix
|
||||
|
||||
float tag; |
||||
file.read((char*) &tag, sizeof(float)); |
||||
if ( tag != FLOW_TAG_FLOAT ) |
||||
return flow; |
||||
|
||||
int width, height; |
||||
|
||||
file.read((char*) &width, 4); |
||||
file.read((char*) &height, 4); |
||||
|
||||
flow.create(height, width); |
||||
|
||||
for ( int i = 0; i < flow.rows; ++i ) |
||||
{ |
||||
for ( int j = 0; j < flow.cols; ++j ) |
||||
{ |
||||
Point2f u; |
||||
file.read((char*) &u.x, sizeof(float)); |
||||
file.read((char*) &u.y, sizeof(float)); |
||||
if ( !file.good() ) |
||||
{ |
||||
flow.release(); |
||||
return flow; |
||||
} |
||||
|
||||
flow(i, j) = u; |
||||
} |
||||
} |
||||
file.close(); |
||||
return flow; |
||||
} |
||||
CV_EXPORTS_W bool writeOpticalFlow( const String& path, InputArray flow ) |
||||
{ |
||||
// CV_Assert(sizeof(float) == 4);
|
||||
|
||||
const int nChannels = 2; |
||||
|
||||
Mat input = flow.getMat(); |
||||
if ( input.channels() != nChannels || input.depth() != CV_32F || path.length() == 0 ) |
||||
return false; |
||||
|
||||
std::ofstream file(path.c_str(), std::ofstream::binary); |
||||
if ( !file.good() ) |
||||
return false; |
||||
|
||||
int nRows, nCols; |
||||
|
||||
nRows = (int) input.size().height; |
||||
nCols = (int) input.size().width; |
||||
|
||||
const int headerSize = 12; |
||||
char header[headerSize]; |
||||
memcpy(header, FLOW_TAG_STRING, 4); |
||||
// size of ints is known - has been asserted in the current function
|
||||
memcpy(header + 4, reinterpret_cast<const char*>(&nCols), sizeof(nCols)); |
||||
memcpy(header + 8, reinterpret_cast<const char*>(&nRows), sizeof(nRows)); |
||||
file.write(header, headerSize); |
||||
if ( !file.good() ) |
||||
return false; |
||||
|
||||
// if ( input.isContinuous() ) //matrix is continous - treat it as a single row
|
||||
// {
|
||||
// nCols *= nRows;
|
||||
// nRows = 1;
|
||||
// }
|
||||
|
||||
int row; |
||||
char* p; |
||||
for ( row = 0; row < nRows; row++ ) |
||||
{ |
||||
p = input.ptr<char>(row); |
||||
file.write(p, nCols * nChannels * sizeof(float)); |
||||
if ( !file.good() ) |
||||
return false; |
||||
} |
||||
file.close(); |
||||
return true; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue