基于OpenCV的三种光流算法实现源码及测试结果

本文包括基于OpenCV三种光流算法的实现源码及测试结果。具体为HS算法,LK算法,和ctfLK算法,算法的原实现作者是Eric Yuan,这里是作者的博客主页:http://eric-yuan.me。本文对这三种光流算法进行了相关调试及结果验证,供大家参考。

1. 第一种:HS光流法(作者HORN 和SCHUNCK)


#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 
#include 

using namespace cv;
using namespace std;

#define ATD at
#define elif else if

#ifndef bool
#define bool int
#define false ((bool)0)
#define true  ((bool)1)
#endif


Mat get_fx(Mat &src1, Mat &src2){
	Mat fx;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(1, 0) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fx = dst1 + dst2;
	return fx;
}

Mat get_fy(Mat &src1, Mat &src2){
	Mat fy;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(0, 1) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fy = dst1 + dst2;
	return fy;
}

Mat get_ft(Mat &src1, Mat &src2){
	Mat ft;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel = kernel.mul(-1);

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	kernel = kernel.mul(-1);
	filter2D(src2, dst2, -1, kernel);

	ft = dst1 + dst2;
	return ft;
}

bool isInsideImage(int y, int x, Mat &m){
	int width = m.cols;
	int height = m.rows;
	if (x >= 0 && x < width && y >= 0 && y < height) return true;
	else return false;
}

double get_Average4(Mat &m, int y, int x){
	if (x < 0 || x >= m.cols) return 0;
	if (y < 0 || y >= m.rows) return 0;

	double val = 0.0;
	int tmp = 0;
	if (isInsideImage(y - 1, x, m)){
		++tmp;
		val += m.ATD(y - 1, x);
	}
	if (isInsideImage(y + 1, x, m)){
		++tmp;
		val += m.ATD(y + 1, x);
	}
	if (isInsideImage(y, x - 1, m)){
		++tmp;
		val += m.ATD(y, x - 1);
	}
	if (isInsideImage(y, x + 1, m)){
		++tmp;
		val += m.ATD(y, x + 1);
	}
	return val / tmp;
}

Mat get_Average4_Mat(Mat &m){
	Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);
	for (int i = 0; i < m.rows; i++){
		for (int j = 0; j < m.cols; j++){
			res.ATD(i, j) = get_Average4(m, i, j);
		}
	}
	return res;
}

void saveMat(Mat &M, string s){
	s += ".txt";
	FILE *pOut = fopen(s.c_str(), "w+");
	for (int i = 0; i


基于OpenCV的三种光流算法实现源码及测试结果_第1张图片

1  HS光流法原始图像(之一)

基于OpenCV的三种光流算法实现源码及测试结果_第2张图片


2HS光流法计算结果:U

基于OpenCV的三种光流算法实现源码及测试结果_第3张图片

3 HS光流法计算结果:V

1. 第二种:LK光流法(作者LUCAS 和KANADE)


#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 
#include 

using namespace cv;
using namespace std;

#define ATD at
#define elif else if

#ifndef bool
#define bool int
#define false ((bool)0)
#define true  ((bool)1)
#endif


Mat get_fx(Mat &src1, Mat &src2){
	Mat fx;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(1, 0) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fx = dst1 + dst2;
	return fx;
}

Mat get_fy(Mat &src1, Mat &src2){
	Mat fy;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(0, 1) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fy = dst1 + dst2;
	return fy;
}

Mat get_ft(Mat &src1, Mat &src2){
	Mat ft;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel = kernel.mul(-1);

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	kernel = kernel.mul(-1);
	filter2D(src2, dst2, -1, kernel);

	ft = dst1 + dst2;
	return ft;
}

bool isInsideImage(int y, int x, Mat &m){
	int width = m.cols;
	int height = m.rows;
	if (x >= 0 && x < width && y >= 0 && y < height) return true;
	else return false;
}

double get_Sum9(Mat &m, int y, int x){
	if (x < 0 || x >= m.cols) return 0;
	if (y < 0 || y >= m.rows) return 0;

	double val = 0.0;
	int tmp = 0;
	if (isInsideImage(y - 1, x - 1, m)){
		++tmp;
		val += m.ATD(y - 1, x - 1);
	}
	if (isInsideImage(y - 1, x, m)){
		++tmp;
		val += m.ATD(y - 1, x);
	}
	if (isInsideImage(y - 1, x + 1, m)){
		++tmp;
		val += m.ATD(y - 1, x + 1);
	}
	if (isInsideImage(y, x - 1, m)){
		++tmp;
		val += m.ATD(y, x - 1);
	}
	if (isInsideImage(y, x, m)){
		++tmp;
		val += m.ATD(y, x);
	}
	if (isInsideImage(y, x + 1, m)){
		++tmp;
		val += m.ATD(y, x + 1);
	}
	if (isInsideImage(y + 1, x - 1, m)){
		++tmp;
		val += m.ATD(y + 1, x - 1);
	}
	if (isInsideImage(y + 1, x, m)){
		++tmp;
		val += m.ATD(y + 1, x);
	}
	if (isInsideImage(y + 1, x + 1, m)){
		++tmp;
		val += m.ATD(y + 1, x + 1);
	}
	if (tmp == 9) return val;
	else return m.ATD(y, x) * 9;
}

Mat get_Sum9_Mat(Mat &m){
	Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);
	for (int i = 1; i < m.rows - 1; i++){
		for (int j = 1; j < m.cols - 1; j++){
			res.ATD(i, j) = get_Sum9(m, i, j);
		}
	}
	return res;
}

void saveMat(Mat &M, string s){
	s += ".txt";
	FILE *pOut = fopen(s.c_str(), "w+");
	for (int i = 0; i

基于OpenCV的三种光流算法实现源码及测试结果_第4张图片

4 LK光流法原始图像(之一)

基于OpenCV的三种光流算法实现源码及测试结果_第5张图片

5 LK光流法计算结果:U


基于OpenCV的三种光流算法实现源码及测试结果_第6张图片

6 LK光流法计算结果:V


1. 第三种:ctfLK光流法(LK光流法的Coarse to fine版本

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 
#include 

using namespace cv;
using namespace std;

#define ATD at
#define ATF at
#define elif else if

#ifndef bool
#define bool int
#define false ((bool)0)
#define true  ((bool)1)
#endif

Mat get_fx(Mat &src1, Mat &src2){
	Mat fx;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(1, 0) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fx = dst1 + dst2;
	return fx;
}

Mat get_fy(Mat &src1, Mat &src2){
	Mat fy;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel.ATD(0, 0) = -1.0;
	kernel.ATD(0, 1) = -1.0;

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	filter2D(src2, dst2, -1, kernel);

	fy = dst1 + dst2;
	return fy;
}

Mat get_ft(Mat &src1, Mat &src2){
	Mat ft;
	Mat kernel = Mat::ones(2, 2, CV_64FC1);
	kernel = kernel.mul(-1);

	Mat dst1, dst2;
	filter2D(src1, dst1, -1, kernel);
	kernel = kernel.mul(-1);
	filter2D(src2, dst2, -1, kernel);

	ft = dst1 + dst2;
	return ft;
}

bool isInsideImage(int y, int x, Mat &m){
	int width = m.cols;
	int height = m.rows;
	if (x >= 0 && x < width && y >= 0 && y < height) return true;
	else return false;
}

double get_Sum9(Mat &m, int y, int x){
	if (x < 0 || x >= m.cols) return 0;
	if (y < 0 || y >= m.rows) return 0;

	double val = 0.0;
	int tmp = 0;
	for (int i = -1; i <= 1; i++){
		for (int j = -1; j <= 1; j++){
			if (isInsideImage(y + i, x + j, m)){
				++tmp;
				val += m.ATD(y + i, x + j);
			}
		}
	}
	if (tmp == 9) return val;
	else return m.ATD(y, x) * 9;
}

Mat get_Sum9_Mat(Mat &m){
	Mat res = Mat::zeros(m.rows, m.cols, CV_64FC1);
	for (int i = 1; i < m.rows - 1; i++){
		for (int j = 1; j < m.cols - 1; j++){
			res.ATD(i, j) = get_Sum9(m, i, j);
		}
	}
	return res;
}

void saveMat(Mat &M, string s){
	s += ".txt";
	FILE *pOut = fopen(s.c_str(), "w+");
	for (int i = 0; i getGaussianPyramid(Mat &img, int nLevels){
	vector pyr;
	pyr.push_back(img);
	for (int i = 0; i < nLevels - 1; i++){
		Mat tmp;
		pyrDown(pyr[pyr.size() - 1], tmp);
		pyr.push_back(tmp);
	}
	return pyr;
}

void coarseToFineEstimation(Mat &img1, Mat &img2, Mat &u, Mat &v, int nLevels){

	vector pyr1 = getGaussianPyramid(img1, nLevels);
	vector pyr2 = getGaussianPyramid(img2, nLevels);
	Mat upu, upv;
	for (int i = nLevels - 1; i >= 0; i--){

		Mat tmpu = Mat::zeros(pyr1[i].rows, pyr1[i].cols, CV_64FC1);
		Mat tmpv = Mat::zeros(pyr2[i].rows, pyr2[i].cols, CV_64FC1);
		getLucasKanadeOpticalFlow(pyr1[i], pyr2[i], tmpu, tmpv);
		if (i != nLevels - 1){
			tmpu += upu;
			tmpv += upv;
		}
		if (i == 0){
			u = tmpu;
			v = tmpv;
			return;
		}
		pyrUp(tmpu, upu);
		pyrUp(tmpv, upv);

		Mat map1(upu.size(), CV_32FC2);
		Mat map2(upu.size(), CV_32FC2);
		for (int y = 0; y < map1.rows; ++y){
			for (int x = 0; x < map1.cols; ++x){
				Point2f f = Point2f((float)(upu.ATD(y, x)), (float)(upv.ATD(y, x)));
				map1.at(y, x) = Point2f(x + f.x / 2, y + f.y / 2);
				map2.at(y, x) = Point2f(x - f.x / 2, y - f.y / 2);
			}
		}
		Mat warped1, warped2;
		remap(pyr1[i - 1], warped1, map1, cv::Mat(), INTER_LINEAR);
		remap(pyr2[i - 1], warped2, map2, cv::Mat(), INTER_LINEAR);
		warped1.copyTo(pyr1[i - 1]);
		warped2.copyTo(pyr2[i - 1]);
	}
}

int getMaxLayer(Mat &img){
	int width = img.cols;
	int height = img.rows;
	int res = 1;
	int p = 1;
	while (1){
		int tmp = pow(2, p);
		if (width % tmp == 0) ++p;
		else break;
	}
	res = p;
	p = 1;
	while (1){
		int tmp = pow(2, p);
		if (height % tmp == 0) ++p;
		else break;
	}
	res = res < p ? res : p;
	return res;
}

int main(){

	Mat ori1 = imread("table1.jpg", 0);
	Mat ori2 = imread("table2.jpg", 0);
	Mat img1 = ori1(Rect(0, 0, 640, 448));
	Mat img2 = ori2(Rect(0, 0, 640, 448));


	int maxLayer = getMaxLayer(img1);
	cout << img1.rows << ", " << img1.cols << ", Max layer = " << maxLayer << endl;


	img1.convertTo(img1, CV_64FC1, 1.0 / 255, 0);
	img2.convertTo(img2, CV_64FC1, 1.0 / 255, 0);


	Mat u = Mat::zeros(img1.rows, img1.cols, CV_64FC1);
	Mat v = Mat::zeros(img1.rows, img1.cols, CV_64FC1);
	Mat u2 = Mat::zeros(img1.rows, img1.cols, CV_64FC1);
	Mat v2 = Mat::zeros(img1.rows, img1.cols, CV_64FC1);

	if (maxLayer >= 1){
		coarseToFineEstimation(img1, img2, u, v, maxLayer);
		saveMat(u, "U");
		saveMat(v, "V");
	}

	getLucasKanadeOpticalFlow(img1, img2, u2, v2);
	saveMat(u2, "U2");
	saveMat(v2, "V2");

	imshow("U2", u2);
	imshow("v2", v2);
	
	waitKey(20000);

	return 0;
}

基于OpenCV的三种光流算法实现源码及测试结果_第7张图片

7 ctfLK光流法测试原始图像(之一)

基于OpenCV的三种光流算法实现源码及测试结果_第8张图片

8 ctfLK光流法计算结果:U2


基于OpenCV的三种光流算法实现源码及测试结果_第9张图片

9 ctfLK光流法计算结果:v2


你可能感兴趣的:(OpenCV,计算机视觉,光流,视频跟踪,机器视觉,图像处理,计算机视觉,机器视觉,视频跟踪,光流)