光流法简单介绍(结合Opencv2)
2015-09-29 19:22
471 查看
什么是光流?
维基百科解释:Optical flow or optic flow is thepattern ofapparent motion of objects, surfaces, and edges in a visual scenecaused by the relative motion between an observer (an eye or acamera) and the scene.
名称来源:当人的眼睛观察运动物体时,物体的景象在人眼的视网膜上形成一系列连续变化的图像,这一系列连续变化的信息不断“流过”视网膜,好像一种光的“流”,故称之为光流。
光流算法的输入输出
光流算法分成稠密光流和稀疏光流,稠密光流(dense optical flow)对图像中的每个像素都进行速度的计算,而稀疏光流(sparse optical flow)是对图像中指定的一组点(常用角点)进行速度的计算。例如,第t帧的时候A点的位置是(x1,
y1),那么我们在第t+1帧的时候再找到A点,假如它的位置是(x2,y2),那么我们就可以确定A点的速度了:(ux,
vy) = (x2, y2) - (x1,y1)(可以认为是一个矢量)。
再具体一点,拿Opencv中的函数作为例子。
calcOpticalFlowPyrLK(InputArray prevImg,
InputArray nextImg, InputArray prevPts, InputOutputArray nextPts,
OutputArray status, OutputArray err, Size winSize=Size(15,15),
int maxLevel=3, TermCriteriacriteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,
30, 0.01), double derivLambda=0.5, int flags=0)
这个函数使用金字塔LK方法,属于稀疏光流,前四个参数依次为:前一帧图片,后一帧图片,需要跟踪的点在前一帧图片的坐标,那些需要跟踪的点在后一帧中的坐标(函数的输出)。
calcOpticalFlowFarneback(InputArray prevImg,
InputArray nextImg, InputOutputArray flow, double pyrScale,
intlevels, int winsize, int iterations,
int polyN, double polySigma, int flags)
这个函数使用Farneback的方法,属于稠密光流,前两个参数与上面一致,第三个参数是函数的输出,一个与图片尺寸一致(每个像素都有对应的值),CV_32FC2类型的矩阵(有两个通道),也就是说对于每个像素,都有x方向和y方向的速度值。
程序验证
<pre name="code" class="cpp">#include <iostream> #include "opencv2/opencv.hpp" /*include all opencv2 hpp*/ using namespace cv; using namespace std; /*定义π值*/ static const double pi = 3.14159265358979323846; /*读取两帧图片 使用calcOpticalFlowPyrLK 算出光流 并用向量表示 */ int main(int argc, char** argv) { /*初始化主要用到的变量*/ Mat prevGray, gray,prevFrame,frame,show,flow; prevFrame = imread("frame10.png"); frame = 4000 imread("frame11.png"); cvtColor(prevFrame, prevGray, COLOR_BGR2GRAY); cvtColor(frame, gray, COLOR_BGR2GRAY); /*最大特征点数量*/ const int MAX_COUNT = 300; /*算法终止条件termcrit 参数:第一个是类型,第二个参数为迭代的最大次数,最后一个是特定的阈值*/ TermCriteria termcrit(TermCriteria::COUNT + TermCriteria::EPS, 20, 0.01); /*搜索窗口*/ Size subPixWinSize(10, 10), winSize(31, 31); /*声明一个泛型为Point的vector,名为points 长度为2 points[0] points[1]各为一个Point类的数组*/ vector<Point2f> points[2]; /*寻找角点*/ goodFeaturesToTrack(prevGray, points[0], MAX_COUNT, 0.01, 10); /*如果对角点的精度有更高的要求,可以用cornerSubPix()函数将角点定位到子像素,从而取得亚像素级别的角点检测效果*/ cornerSubPix(gray, points[0], subPixWinSize, Size(-1, -1), termcrit); vector<uchar> status; vector<float> err; /*PyrLK法计算光流*/ calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,5, termcrit, 0, 0.001); /*Farneback法计算稠密光流 输出为flow CV32FC2 32位浮点型双通道矩阵 分别记录x y方向的速度*/ calcOpticalFlowFarneback(prevGray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0); /*尝试将flow转为灰度图显示*/ Mat flowIntensity(flow.size(), CV_32FC1); for (int i = 0; i < flow.rows; i++) for (int j = 0; j < flow.cols; j++) { Vec2f intensity = flow.at<Vec2f>(i, j); float maybeX = intensity.val[0]; float maybeY = intensity.val[1]; flowIntensity.at<float>(i, j) = sqrt(maybeX*maybeX + maybeY*maybeY); } /*画LK法向量图*/ for (int i = 0; i < points[1].size(); i++) { if (!status[i]) continue; if (points[0][i] == points[1][i]) continue; line(frame, points[0][i], points[1][i],Scalar(0,0,255),2); line(prevFrame, points[0][i], points[1][i], Scalar(0, 0, 255), 2); Point p, q; p=points[0][i]; q = points[1][i]; double angle; angle = atan2((double)p.y - q.y, (double)p.x - q.x); p.x = (int)(q.x + 9 * cos(angle + pi / 4)); p.y = (int)(q.y + 9 * sin(angle + pi / 4)); line(frame, p, q, Scalar(0, 0, 255), 2); line(prevFrame, p, q, Scalar(0, 0, 255), 2); p.x = (int)(q.x + 9 * cos(angle - pi / 4)); p.y = (int)(q.y + 9 * sin(angle - pi / 4)); line(frame, p, q, Scalar(0, 0, 255), 2); line(prevFrame, p, q, Scalar(0, 0, 255), 2); } /*打开窗口*/ namedWindow("LK Demo", WINDOW_AUTOSIZE); namedWindow("Farneback", WINDOW_AUTOSIZE); show=frame; for (;;) { imshow("LK Demo", show); imshow("Farneback", flowIntensity); char c = (char)waitKey(10); switch (c) { /*按下p键 观看前一帧*/ case 'p': show = prevFrame; break; /*按下n键 观看后一帧*/ case 'n': show = frame; break; case 'q': return 0; default: break; } } return 0; }
对于LK法,可以按下n键和p键对比前后帧图片点的位置。
对于Farneback,我把x和y方向的速度值合成了一个速度值并进行画图。
相关文章推荐
- python中使用OpenCV进行人脸检测的例子
- opencv 做人脸识别 opencv 人脸匹配分析
- 使用opencv拉伸图像扩大分辨率示例
- OpenCV 2.4.3 C++ 平滑处理分析
- 利用Python和OpenCV库将URL转换为OpenCV格式的方法
- python结合opencv实现人脸检测与跟踪
- 在树莓派2或树莓派B+上安装Python和OpenCV的教程
- OpenCV配置,从来没有这么简单!
- ubuntu下opencv和qt的安装配置
- OpenCV学习笔记(二十五)——OpenCV图形界面设计Qt+VS2008
- 分享一些OpenCV实现立体视觉的经验
- 关于OpenCv图像变换与基本图形检测
- "应用程序正常初始化失败"-0xc0150002 解决办法
- OpenCV->HSV色彩空间
- opencv 内存泄露
- OpenCV函数cvFindContours
- OpenCV 2.3.1图像文件的读入和显示
- opencv2 矩阵方式 resize图像缩放代码
- OpenCV 灰度直方图
- 彩色图转为灰度图