首页 > 编程语言 >基于opencv + GPU cuda的光流算法demo

基于opencv + GPU cuda的光流算法demo

时间:2024-07-08 23:32:11浏览次数:12  
标签:chrono demo frame opencv hsv cuda time gpu

该demo来自learnopencv.com网站,是作为opencv cuda 模块的启蒙示例。看来这是一个简单的例子,但是由于从未接触过opencv cuda图像处理,我个人仍感觉比较新颖和有趣,特别是运行效果很惊奇,这里和大家一起学习解读以下。想看一手内容可以在网络直接搜索Getting Started With Opencv cuda Module。这里是对其直接搬运、截取、翻译和个人解读。

代码主要应用到的算法是Gunnar Farneback的稠密光流算法(Farneback算法),是一种基于梯度的经典光流算法。具体算法内容比较复杂,可以参考论文和网上解读。OpenCV中提供了cuda::FarnebackOpticalFlow这个实现进行稠密光流计算。

1. 读取视频图像

 1 cout << "Hello Cuda!" << endl;
 2 
 3     /** 打开本地视频流  */
 4     VideoCapture capture("/home/workspace/av/testcuvid/input2.mp4");
 5     if(!capture.isOpened())
 6     {
 7         cout << "Failed to open video." << endl;
 8         return 0;
 9     }
10 
11     /** 获取本地视频关键信息  */
12     double fps = capture.get(CAP_PROP_FPS);
13     int num_frames = int(capture.get(CAP_PROP_FRAME_COUNT));
14 
15     cout << "fps:" << fps << "  frames:" << num_frames << endl;

上面代码主要是使用opencv的VideoCapture打开本地视频,并获取本地视频的帧率和总帧数。

2. 读取第一帧图像并载入GPU显存中

 1     Mat frame, previous_frame;
 2 
 3     /** 读取第一帧图像,并转换大小,转换成灰度图 */
 4     capture >> frame;
 5     resize(frame, frame, Size(960, 540), 0, 0, INTER_LINEAR);
 6     cvtColor(frame, previous_frame, COLOR_BGR2GRAY);
 7 
 8     /** 定义GPU版本的mat,并将视频图像帧上传到GPU显存中  */
 9     cuda::GpuMat gpu_previous;
10     gpu_previous.upload(previous_frame);

3. 定义一些运算中间量和统计中间量

 1     /** 定义运算中间量  */
 2     Mat hsv[3], angle, bgr;
 3     cuda::GpuMat gpu_magnitude, gpu_normalized_magnitude, gpu_angle;
 4     cuda::GpuMat gpu_hsv[3], gpu_merged_hsv, gpu_hsv_8u, gpu_bgr;
 5 
 6     /** 单通道矩阵,第一列是1,其他是0  */
 7     hsv[1] = Mat::ones(frame.size(), CV_32F);
 8     gpu_hsv[1].upload(hsv[1]);
 9 
10     /** 定义统计信息记录map  */
11     map<string,list<double> > timers;
12     timers.insert(map<string, list<double> >::value_type("reading", list<double>()));
13     timers.insert(map<string, list<double> >::value_type("pre-process", list<double>()));
14     timers.insert(map<string, list<double> >::value_type("optical flow", list<double>()));
15     timers.insert(map<string, list<double> >::value_type("post-process", list<double>()));
16     timers.insert(map<string, list<double> >::value_type("full pipeline", list<double>()));

4. 循环读取图像并进行预处理

 1     while(true)
 2     {
 3         auto start_full_time = chrono::high_resolution_clock::now();
 4 
 5         auto start_read_time = chrono::high_resolution_clock::now();
 6 
 7         /** 继续读取下一帧视频图像,直到为空  */
 8         capture >> frame;
 9         if(frame.empty())
10             break;
11 
12         /** 将读取到的图像上传到显存  */
13         cuda::GpuMat gpu_frame;
14         gpu_frame.upload(frame);
15 
16         auto end_read_time = chrono::high_resolution_clock::now();
17 
18         timers["reading"].push_back(chrono::duration_cast<chrono::milliseconds>(end_read_time - start_read_time).count() / 1000.0);
19 
20         auto start_pre_time = chrono::high_resolution_clock::now();
21 
22         /** 设置图像大小,并转换为灰度图  */
23         cv::cuda::resize(gpu_frame, gpu_frame, Size(960, 540), 0, 0, INTER_LINEAR);
24         cv::cuda::GpuMat gpu_current;
25         cv::cuda::cvtColor(gpu_frame, gpu_current, COLOR_BGR2GRAY);

以上以此读取本地视频中的视频帧,直到结束。读取到的图像上传到GPU显存中,然后调用cuda实现的算法将其缩放,并转为灰度图。这里说明以下,稠密 光流计算的输入为灰度图像。

5. 计算光流图

 1 auto end_pre_time = chrono::high_resolution_clock::now();
 2 
 3         timers["pre-process"].push_back(chrono::duration_cast<chrono::milliseconds>(end_pre_time - start_pre_time).count() /1000.0);
 4 
 5         auto start_of_time = chrono::high_resolution_clock::now();
 6 
 7         /** Farneback算子创建  */
 8         Ptr<cuda::FarnebackOpticalFlow> ptr_calc = cuda::FarnebackOpticalFlow::create(5, 0.5, false, 15, 3, 5, 1.2, 0);
 9 
10         /** 计算光流图像  */
11         cuda::GpuMat gpu_flow;
12         ptr_calc->calc(gpu_previous, gpu_current, gpu_flow);
13 
14         auto end_of_time = chrono::high_resolution_clock::now();
15 
16         timers["optical flow"].push_back(chrono::duration_cast<chrono::milliseconds>(end_of_time - start_of_time).count() /1000.0);

调用opencv封装好的算法,输入前一帧图像和当前帧图像,计算出光流结果。

6. 光流结果处理,转换成直观的光流图

 1 auto start_post_time = chrono::high_resolution_clock::now();
 2         /** 将光流图中xy通道数据分割  */
 3         cv::cuda::GpuMat gpu_flow_xy[2];
 4         cv::cuda::split(gpu_flow, gpu_flow_xy);
 5 
 6         /** 笛卡尔坐标转极坐标(向量坐标)  */
 7         cv::cuda::cartToPolar(gpu_flow_xy[0], gpu_flow_xy[1], gpu_magnitude, gpu_angle, true);
 8         /** 将上面的数值进行标准化  */
 9         cv::cuda::normalize(gpu_magnitude, gpu_normalized_magnitude, 0.0, 1.0, NORM_MINMAX, -1);
10         /** 将光流相位信息下载到内存  */
11         gpu_angle.download(angle);
12         angle *= ((1/360.0)*(180/255.0));   // 角度信息转为h通道信息
13         /** 将转化后的h通道上传到GPU显存中,将归一化后的数值上传到v通道中  */
14         gpu_hsv[0].upload(angle);               // h通道对应角度
15 //        gpu_hsv[1].upload(Mat::ones(frame.size(), CV_32F));   // s通道为1,上面定义了
16         gpu_hsv[2] = gpu_normalized_magnitude;  // 通道对应归一化的位移
17         /** 合并通道  */
18         cv::cuda::merge(gpu_hsv, 3, gpu_merged_hsv);
19         /** 转换数据格式  */
20         gpu_merged_hsv.cv::cuda::GpuMat::convertTo(gpu_hsv_8u, CV_8U, 255.0);
21         /** 转成RBG图像  */
22         cv::cuda::cvtColor(gpu_hsv_8u, gpu_bgr, COLOR_HSV2BGR);

5中计算出来的光流结果是像素xy方向的位移。这里将其转成极坐标表示,然后对极坐标的标量(位移量)进行归一化,对极坐标的角度(方向量)进行转化。归一化后的位移量作为光流图的h通道,转化后的方向量作为光流图的通道。加上前面定义的s通道,就形成光流图了。最后将光流图多通道合并,然后转rgb。

7. 显示

 1 /** 将原图和光流图下载到内存  */
 2         gpu_frame.download(frame);
 3         gpu_bgr.download(bgr);
 4 
 5         /** 更新前一帧图像,准备下次计算  */
 6         gpu_previous = gpu_current;
 7 
 8         auto end_post_time = chrono::high_resolution_clock::now();
 9 
10         timers["post-process"].push_back(chrono::duration_cast<chrono::milliseconds>(end_post_time - start_post_time).count() / 1000.0);
11 
12         auto end_full_time = chrono::high_resolution_clock::now();
13 
14         timers["full pipeline"].push_back(chrono::duration_cast<chrono::milliseconds>(end_full_time - start_full_time).count() / 1000.0);
15 
16         /** 显示原图和光流图  */
17         imshow("original", frame);
18         imshow("result", bgr);
19         
20         int keyboard = waitKey(1);
21         if(keyboard == 27)
22             break;
23 
24     }

最后将原图和计算的光流图下载到内存中并显示。

标签:chrono,demo,frame,opencv,hsv,cuda,time,gpu
From: https://www.cnblogs.com/uuvv/p/18289138

相关文章

  • 音频demo:使用opencore-amr将PCM数据与AMR-NB数据进行相互编解码
    1、READMEa.编译编译demo由于提供的.a静态库是在x86_64的机器上编译的,所以仅支持该架构的主机上编译运行。$make编译opencore-amr如果想要在其他架构的CPU上编译运行,可以使用以下命令(脚本)编译opencore-amr[下载地址]得到相应的库文件进行替换:#!/bin/bashtarxzf......
  • NVIDIA+CUDA Toolkit+Pytroch安装
    1NVIDIA驱动安装一般来说,驱动可以使用兼容的最新版本window安装https://www.nvidia.cn/geforce/drivers/2CUDAToolkit安装(1)CUDAToolkit版本要求win+R输入nvidia-smi查询可以安装CUDAToolkit版本,CUDAToolkit版本小一点没有关系(2)下载CUDAToolkit并直接运行安装h......
  • Python OpenCv对规则物体进行实时检测
    前言很多情况需要对物体进行检测,常规的方法也有很多种。但是检测出来的边缘一般都是非常多,结果也是非常杂乱的,显然这种结果不是我们想要的。如果颜色相较于背景非常鲜艳的可以调节hsv阈值再进行检测,如果是一直在运动的物体可以通过帧差法进行物体检测,还有很多高深的算法也可以进......
  • Linux系统配置Opencv+cuda+ffmpeg开发环境,-217:Gpu API call unknown error code问题
    Opencv是当前比较热门的图像处理开源算法库,但是随着深度学习在图像存储里领域的大放异彩,基于python的图像处理和深度学习算法大有超越opencv的趋势。opencv在最近的版本更新中,重点都放在了人工智能算法方面,本文介绍linux环境下配置支持GPU/cuda的ffmpeg和opencv开发环境,并将其中遇......
  • OpenCV GPU解码简单例子
    基于GPU/cuda的运算能够极大解放CPU的负担,特别是针对复杂图像处理的场景中。该例子主要展示利用GPU的硬解码模块,对本地和网络视频流进行解码和本地显示。环境如下,ubuntu20.04+opencv4.10.0+cuda12.5.代码逻辑比较简单,不涉及复杂逻辑和算法,直接看代码。GPU解码本地视频并进行显......
  • opencv环境搭建-python
    最近遇到了一些图像处理的需求,所以需要学习一下opencv,来记录一下我的学习历程。安装numpypipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simplenumpy安装matplotlibpipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simplematplotlib安装opencvpipin......
  • 树莓派5 — 官方Raspberry Pi OS — OpenCV图像处理 — 1
    引言一名视觉入门选手,在校生大一,了解OpenCV的皮毛。撰写此文,一是为了分享内容,帮助后来人;二更是为了能吸引大佬能给我提出我在学习上的建议和问题。说明环境:树莓派5  官方操作系统RaspberryPiOS  OpenCV  Python语言  CSI500万摄像头内容:树莓派5安装OpenCV,调......
  • Linux系统中交叉编译opencv库
    目标:将opencv进行交叉编译,使其能在rk3326板子上运行使用。环境:ubuntu:18.04opencv:4.5.4opencv源码从挂网下载:opencv源码下载地址交叉编译链:gcc-arm-10.3-linux-gun一.环境准备1.交叉编译链我配置在/opt/gcc-arm-10.3-linux-gun中,可根据实际情况自行配置目录;2.opencv......
  • MinGW GCC 5.3.0 编译OpenCV4.5.5 运行到imshow时崩溃
    Windows 下通过mingw32-make编译opencv4.5.5,经过一系列问题解决后发现其他正常,imshow崩溃.GCC版本太低原因,换更高版本的GCC解决.毕竟GCC5.3.0是2015年发行的,opencv4.5.5是2020年发行的尝试换GCC i686-8.1.0-release-posix-sjlj-rt_v6-rev0编译,调用imshow时正常运行,并且......
  • opencv 编译报错: error: temporary of non-literal type 'google::protobuf::intern
    完整报错:C:\Users\MyName\MyProject\lib\include\google\protobuf\stubs\mutex.h:124:error:temporaryofnon-literaltype'google::protobuf::internal::CallOnceInitializedMutex<std::mutex>'inaconstantexpressionInfileincludedfrom......