Optical Flow
参考博客:
https://my.oschina.net/u/3702502/blog/1815343/
一.算法了解
光流(Optical Flow)是一种研究图像对齐的算法,一般包括两大类:稀疏光流和稠密光流。顾名思义,稀疏光流就是研究图像中稀疏点的光流,这些点一般是角点;稠密光流则是研究图像中所有点的偏移量。
1.稀疏光流
2.稠密光流
由于网上有较多的解释,此处附一个百科解释
参考网址:
https://baike.baidu.com/item/Optical Flow/19180399?fr=aladdin
二.代码实现
1.基于特征点(角点)的稀疏光流:Lucas-Kanade Optical Flow
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
using namespace cv
;
using namespace std
;
int main(int argc
, char **argv
)
{
const string about
=
"This sample demonstrates Lucas-Kanade Optical Flow calculation.\n"
"The example file can be downloaded from:\n"
" https://www.bogotobogo.com/python/OpenCV_Python/images/mean_shift_tracking/slow_traffic_small.mp4";
const string keys
=
"{ h help | | print this help message }"
"{ @image |<none>| path to image file }";
CommandLineParser
parser(argc
, argv
, keys
);
parser
.about(about
);
if (parser
.has("help"))
{
parser
.printMessage();
return 0;
}
string filename
= parser
.get
<string
>("@image");
if (!parser
.check())
{
parser
.printErrors();
return 0;
}
VideoCapture
capture(filename
);
if (!capture
.isOpened()){
cerr
<< "Unable to open file!" << endl
;
return 0;
}
vector
<Scalar
> colors
;
RNG rng
;
for(int i
= 0; i
< 100; i
++)
{
int r
= rng
.uniform(0, 256);
int g
= rng
.uniform(0, 256);
int b
= rng
.uniform(0, 256);
colors
.push_back(Scalar(r
,g
,b
));
}
Mat old_frame
, old_gray
;
vector
<Point2f
> p0
, p1
;
capture
>> old_frame
;
cvtColor(old_frame
, old_gray
, COLOR_BGR2GRAY
);
goodFeaturesToTrack(old_gray
, p0
, 100, 0.3, 7, Mat(), 7, false, 0.04);
Mat mask
= Mat
::zeros(old_frame
.size(), old_frame
.type());
while(true){
Mat frame
, frame_gray
;
capture
>> frame
;
if (frame
.empty())
break;
cvtColor(frame
, frame_gray
, COLOR_BGR2GRAY
);
vector
<uchar
> status
;
vector
<float> err
;
TermCriteria criteria
= TermCriteria((TermCriteria
::COUNT
) + (TermCriteria
::EPS
), 10, 0.03);
calcOpticalFlowPyrLK(old_gray
, frame_gray
, p0
, p1
, status
, err
, Size(15,15), 2, criteria
);
vector
<Point2f
> good_new
;
for(uint i
= 0; i
< p0
.size(); i
++)
{
if(status
[i
] == 1) {
good_new
.push_back(p1
[i
]);
line(mask
,p1
[i
], p0
[i
], colors
[i
], 2);
circle(frame
, p1
[i
], 5, colors
[i
], -1);
}
}
Mat img
;
add(frame
, mask
, img
);
imshow("Frame", img
);
int keyboard
= waitKey(30);
if (keyboard
== 'q' || keyboard
== 27)
break;
old_gray
= frame_gray
.clone();
p0
= good_new
;
}
}
ps:
传视频地址时要加参数:
完整命令行:
./<当前路径下的可执行文件> -@image=<视频文件路径>
运行截图:
2.基于所有点的稠密光流:Dense Optical Flow
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
using namespace cv
;
using namespace std
;
int main()
{
VideoCapture
capture("./vtest.avi");
if (!capture
.isOpened()){
cerr
<< "Unable to open file!" << endl
;
return 0;
}
Mat frame1
, prvs
;
capture
>> frame1
;
cvtColor(frame1
, prvs
, COLOR_BGR2GRAY
);
while(true){
Mat frame2
, next
;
capture
>> frame2
;
if (frame2
.empty())
break;
cvtColor(frame2
, next
, COLOR_BGR2GRAY
);
Mat
flow(prvs
.size(), CV_32FC2
);
calcOpticalFlowFarneback(prvs
, next
, flow
, 0.5, 3, 15, 3, 5, 1.2, 0);
Mat flow_parts
[2];
split(flow
, flow_parts
);
Mat magnitude
, angle
, magn_norm
;
cartToPolar(flow_parts
[0], flow_parts
[1], magnitude
, angle
, true);
normalize(magnitude
, magn_norm
, 0.0f, 1.0f, NORM_MINMAX
);
angle
*= ((1.f / 360.f) * (180.f / 255.f));
Mat _hsv
[3], hsv
, hsv8
, bgr
;
_hsv
[0] = angle
;
_hsv
[1] = Mat
::ones(angle
.size(), CV_32F
);
_hsv
[2] = magn_norm
;
merge(_hsv
, 3, hsv
);
hsv
.convertTo(hsv8
, CV_8U
, 255.0);
cvtColor(hsv8
, bgr
, COLOR_HSV2BGR
);
imshow("frame2", bgr
);
imshow("frame", frame2
);
int keyboard
= waitKey(30);
if (keyboard
== 'q' || keyboard
== 27)
break;
prvs
= next
;
}
}
运行截图: