Optical Flow

    xiaoxiao2023-10-19  157

    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()){ //error in opening the video input cerr << "Unable to open file!" << endl; return 0; } // Create some random colors 随机颜色,后期画光流需要 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;//特征点,p0为初始通过Shi-Tomas获取的角点,p1为检测到的对应角点(有好有坏,后期会进行选择) // Take first frame and find corners in it capture >> old_frame; cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);//由于角点检测输入为灰度图像,此处转换 goodFeaturesToTrack(old_gray, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);//p0中角点的检测与初始化 // Create a mask image for drawing purposes Mat mask = Mat::zeros(old_frame.size(), old_frame.type());//创建一个与frame大小、类型相同的掩膜 while(true){ Mat frame, frame_gray; capture >> frame; if (frame.empty()) break; cvtColor(frame, frame_gray, COLOR_BGR2GRAY); // calculate optical flow vector<uchar> status;//特征点检测的状态,相近(基本成功)为1,检测失败为0 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);//此处进行稀疏光流的计算,得到输出特征点向量p1 vector<Point2f> good_new;//好的可以继续使用的特征点(角点) for(uint i = 0; i < p0.size(); i++) { // Select good points if(status[i] == 1) { good_new.push_back(p1[i]);//将匹配成功的特征点存入向量 // draw the tracks line(mask,p1[i], p0[i], colors[i], 2);//在掩膜上连接初始特征点与检测到的特征点(只有检测成功时才画,所以可能会看到最后画出来的为折线,并不光滑) circle(frame, p1[i], 5, colors[i], -1);//突出转折的角点(就是标明检测到的特征点) } } Mat img; add(frame, mask, img);//在原图像上添加掩膜并输出到img中 imshow("Frame", img);//展示检测结果 int keyboard = waitKey(30); if (keyboard == 'q' || keyboard == 27) break; // Now update the previous frame and previous points 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()){ //error in opening the video input 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);//此处计算没有看到算法原理,不敢乱讲 // visualization 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)); //build hsv image 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; } }

    运行截图:

    最新回复(0)