opencv4-highgui之视频的输入和输出以及滚动条
这是《opencv2.4.9tutorial.pdf》的highgui的三个例子。通过简短的介绍来实现不同函数的理解,省去一些不需要说的东西。
一、增加滑动条
这是opencv中为数不多的可以用来交互的东西,其实因为opencv的定位不是界面性编程,所以也没打算提供多好的交互性。可以在“highgui.h”文件中查找提供了的GUI用法,滑动条主要是用来处理鼠标事件的。对于滚动条来说,需要先创建个回调函数用来用户自定义当激发滑动条事件的时候该做什么样的操作。
int createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0);
这就是创建滑动条的函数原型,其中的函数列表:滑动条的名字、滑动条所依附的窗口的名字、滑动条传递的参数、滑动条的最大值(最小值不得小于0)、回调函数的函数指针、用户的数据指针。
值得注意的是这里的最大值可以用户指定,但是最小值默认总是0;回调函数的类型只能是void Foo(int,void*);其中回调函数第一个参数就是滑动条当前的值,第二个参数就是所谓的用户数据指针。void*userdata 所表示的指针指向的值可以用来在不使用全局变量的时候进行回调函数的参数传递,例如传递一个包含着所需要数据的结构体指针。
一般的流程就是:
1、在main函数外进行回调函数的声明 然后在后面定义或者直接定义:
- /// 全局变量的声明与初始化
- const int alpha_slider_max = 100;
- int alpha_slider;//滚动条
- double alpha;
- double beta;
- /// 声明存储图像的变量
- Mat src1;
- Mat src2;
- Mat dst;
省事的做法:在函数外进行声明回调函数所需要用到的参数。
- void on_trackbar( int, void* )//函数名字自己定
- {
- /*your operation*/
- }
2、然后定义回调函数,其中的操作就是当鼠标点击滑动条,也就是触发事件之后就会调用这个函数,那么里面的操作就是我们需要执行的。
- int main( int argc, char** argv )
- {
- //other operation
- alpha_slider = 0;//先将滑动条上的值初始化为0
- /// 创建窗体
- namedWindow("winName", 1);
- /// 在创建的窗体中创建一个滑动条控件
- string str = "myTrackbar";
- createTrackbar( TrackbarName,str, &alpha_slider, alpha_slider_max, on_trackbar );
- /// 结果在回调函数中显示
- on_trackbar(alpha_slider,0);//这里需要调用一次,算是在窗口创建之后的第一次刷新。可以试着把这个函数注销也行,(MFC中也有这种情况,某些时候需要调用一次来初始化的刷新,不然会觉得怪异。)
- /// 按任意键退出
- waitKey(0);//为了与用户进行交互
- return 0;
- }
可以创建多个滑动条,但是却只使用一个回调函数,每次处理不同的值(在创建的时候就是指定传递的值)。
所以其实滑动条的建立和使用其实相当简单。
对应的有getTrackbarPos()和setTrackbarPos()两个对滑动条的滑块位置进行操作的函数:
int getTrackbarPos(const string& trackbarname, const string& winname);
这就是函数的原型,参数列表:滑动条的名字、滑动条所依附的窗口的名字。返回的是滑动条滑块当前的位置。
void setTrackbarPos(const string& trackbarname, const string& winname, int pos);
这就是设置滑动条位置函数的原型,参数列表:滑动条名字、滑动条所依附的窗口的名字,设置滑动条滑块的值。
二、视频的输入
针对opencv来说,视频的输入可以分为视频文件和摄像头实时获取视频两种方式。
总的来说,视频捕获需要的所有函数都集成在 VideoCapture C++
类里面。虽然它底层依赖另一个FFmpeg开源库,但是它已经被集成在OpenCV里所以你不需要额外地关注它的具体实现方法。
1、输入视频
- VideoCapture capVideoFile("your video name")//采用字符串打开视频文件
VideoCapture capVideoCam(0)//采用数字打开摄像头获取视频,0表示第1个摄像头capVideoFile.open("your video name")//采用字符串打开视频文件
capVideoCam.open(0)//采用数字打开视频文件 CV_Assert(capVideoFile.isOpened());//检测是否打开 CV_Assert(capVideoCam.isOpened());//检测是否打开
可以采用构造函数的方式或者使用open()来打开所需要的视频输入。
2、释放视频
当析构函数调用时,会自动关闭视频。如果你希望提前关闭的话,你可以调用 release 函数.
- capVideoCam.release();//释放视频
- capVideoFile.release();//释放视频
3、视频的图像帧获取
- Mat frame;
- capVideoFile >> frame;//或者capVideoCam >> frame;
- capVideoFile.read(frame);//或者capVideoCam.read(frame);
可以直接用重载操作符>>或者使用read函数来进行不断的获取,这里每操作一次,capVideoFile中内部指向的视频图像帧就会自动往后移动,无需人为的像迭代器那样自增。
读取视频帧的时候也会自动进行解码操作。你可以通过调用 grab 和 retrieve 函数来显示地进行这两项操作。
4、视频的操作
视频通常拥有很多除了视频帧图像以外的信息,像是帧数之类,有些时候数据较短,有些时候用4个字节的字符串来表示。所以 get 函数返回一个double(8个字节)类型的数据来表示这些属性。然后你可以使用位操作符来操作这个返回值从而得到想要的整型数据等。这个函数有一个参数,代表着试图查询的属性ID。
int VideoCapture::get(int propId);用来获取视频的其他信息。如果所获取的属性不被VideoCapture类支持的话,返回值为0.
对于参数proId可以为以下参数值:
– CV_CAP_PROP_POS_MSEC //视频文件在以微秒为单位的当前的位置或者视频抓取的时间戳。
– CV_CAP_PROP_POS_FRAMES //解码基于0索引的帧,然后自动抓取下一帧.
– CV_CAP_PROP_POS_AVI_RATIO //相对于视频文件的位置: 0 表示视频的开始, 1 表示视频的结尾.
– CV_CAP_PROP_FRAME_WIDTH //视频流中帧的宽度.
– CV_CAP_PROP_FRAME_HEIGHT //视频流中帧的高度.
– CV_CAP_PROP_FPS //帧速率.
– CV_CAP_PROP_FOURCC //4-character code of codec.
– CV_CAP_PROP_FRAME_COUNT //视频文件中帧的总数.
– CV_CAP_PROP_FORMAT //通过 retrieve()来返回Mat对象的格式 .
– CV_CAP_PROP_MODE //Backend-specific 的值指示当前的拍摄模式
– CV_CAP_PROP_BRIGHTNESS //图像的亮度 (only for cameras).
– CV_CAP_PROP_CONTRAST //图像的对比度 (only for cameras).
– CV_CAP_PROP_SATURATION //图像的饱和度 (only for cameras).
– CV_CAP_PROP_HUE //图像的色调 (only for cameras).
– CV_CAP_PROP_GAIN //图像的增益 (only for cameras).
– CV_CAP_PROP_EXPOSURE //图像的曝光度(only for cameras).
– CV_CAP_PROP_CONVERT_RGB //布尔标识来表示是否需要将图像转换成RGB
– CV_CAP_PROP_WHITE_BALANCE //Currently not supported,待开发
– CV_CAP_PROP_RECTIFICATION //立体相机的整流标志 (note: only supported by DC1394 v 2.x backend currently
例如:
- Size refS = Size((int) capVideoFile.get(CV_CAP_PROP_FRAME_WIDTH),
- (int) capVideoFile.get(CV_CAP_PROP_FRAME_HEIGHT));//获取视频的高和宽
当你需要设置这些值的时候你可以调用 set 函数。函数的第一个参数是需要设置的属性ID,第二个参数是需要设定的值,如果返回true的话就表示成功设定,否则就是false。
bool
VideoCapture::set(int propId, double value);
三、创建视频
首先,你需要知道一个视频文件是什么样子的。每一个视频文件本质上都是一个容器,文件的扩展名只是表示容器格式(例如 avi , mov ,或者 mkv)而不是视频和音频的压缩格式。容器里可能会有很多元素,例如视频流,音频流和一些字幕流等等。这些流的储存方式是由每一个流对应的编解码器(codec)决定的。通常来说,音频流很可能使用 mp3 或 aac 格式来储存。而视频格式就更多些,通常是 XVID , DIVX , H264 或 LAGS (Lagarith
Lossless Codec)等等。
然而OpenCV只是个计算机视觉库而不是一个视频处理编码库。所以开发者们试图将这个部分尽可能地精简,结果就是OpenCV能够处理的视频只剩下 avi 扩展名的了。另外一个限制就是你不能创建超过2GB的单个视频,还有就是每个文件里只能支持一个视频流,不能将音频流和字幕流等其他数据放在里面。尽管如此,任何系统支持的编解码器在这里应该都能工作。如果这些视频处理能力不够你使用的话,我想你应该去找一些专门处理视频的库例如 FFMpeg 或者更多的编解码器例如 HuffYUV , CorePNG 和 LCL 。你可以先用OpenCV创建一个原始的视频流然后通过其他编解码器转换成其他格式并用 VirtualDub 和 AviSynth 这样的软件去创建各种格式的视频文件。
要创建一个视频文件,你需要创建一个 VideoWriter 类的对象。可以通过和输入视频部分一样的构造函数或者使用 open 函数来打开,不过这里就是生成视频文件,所以参数都是字符串形式。
1、创建视频文件的名字
输出的文件名中包含了容器的类型,当然在现在仅仅支持 avi 格式:
- string source = "input.mp4" ; // 原视频文件名
- string::size_type pAt = source.find_last_of('.'); // 找到点的位置,并返回之前的char类型的个数,这里为5
- string NAME = source.substr(0, pAt) + ".avi"; // 创建视频文件名 substr(a,b)是提取字符串中【a,b)的子字符串
上面为提取现有视频文件的名字,然后对应的生成需要输出的视频文件的名字,有助于一一对应。
2、设置编码器
然后决定使用的编解码器,现在所有的视频编解码器都使用最多四个字节的名称来标识,例如 XVID, DIVX,
和 H264 等。这个被称作FourCC(four character code)。你可以通过 get 函数来向视频询问这个编码, get 函数会返回一个double数,仅仅是因为double包含了64位数据而已,由于FourCC编码只占据了其中低位的4个字节,所以可以直接通过强制转换成int型来扔掉高位的四个字节。
- VideoCapture inputVideo(source); // 打开视频输入
- int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // 得到编码器的int表达式
上面就是获取存在的视频文件,然后提取这个视频文件的编码方式
- char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0};
上面就是将编码的4个字节进行从低到高进行逐个提取。
或者使用联合体来得到这4个字节。
- union { int v; char c[5];} uEx ;
- uEx.v = ex; // 通过联合体来分解字符串
- uEx.c[4]='\0';
- 反过来,当你需要修改视频的格式时,你都需要修改FourCC码,而更改ForCC的时候都要做逆转换来指定新类型。如果你已经知道这个FourCC编码的具体字符的话,可以直接使用 *CV_FOURCC* 宏来构建这个int数:
联合体就是只存储其中的一个类型的数据,而当读取的时候按照所指定的类型进行输出,所以这里先使用对器中的int类型进行赋值,但是却对char类型最后进行修改,如果再次读取的话直接使用uEx.c[1~4]就行了。不过记得char类型后面加个‘\0’;
如果传入的参数是一个负数的话,就会在执行时弹出一个对话框,在里面包括了所有已安装的编码器类型,你可以在里面选择一个并使用之。
3.创建视频文件
- VideoWriter outputVideo;
- outputVideo.open(NAME , ex, inputVideo.get(CV_CAP_PROP_FPS),refS, true);
参数列表:需要创建文件的文件名极其后缀“.avi”、编码器类型、帧率、视频的尺寸、彩色(true)或是黑白(false)视频。
ex=-1的时候就会跳出个对话框让用户选择编码器的。
接着使用isOpened()函数测试是否所需要创建的视频文件已经打开,如果返回true,那么就可以接下来的对这个文件塞入图像帧了。就可以用 write 函数向这个对象按照序列发送一些图像帧了,另外使用重载操作符
<< 也可以完成这些操作。最后,视频会在 VideoWriter 对象析构时自动关闭。
- outputVideo.write(frame);
- 或者outputVideo<<frame;
结束的时候VideoWriter类会自动析构。
ps:顺带把那边的图像帧的通道分离和合并的代码贴着;
Mat src,res; vector<Mat> spl;
- split(src, spl); // 分离三个通道 参数列表:原图像,目标数组
- for( int i =0; i < 3; ++i)
- if (i != channel)
- spl[i] = Mat::zeros(S, spl[0].type());/创建相同大小的黑色图像。通过将所需要的通道使用spl[]的形式访问
- merge(spl, res); //重新合并参数列表:所需要合并的数组,目标图像
opencv4-highgui之视频的输入和输出以及滚动条的更多相关文章
- FFmpeg内存IO模式(内存区作输入或输出)
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10318145.html 所谓内存IO,在FFmpeg中叫作"buffered ...
- FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出
对于FFMPEG SDK 提供的Demuxing 为我们实现多路复用 提供了非常多方便,以下的案案例 实现的是 分离一个媒体文件的音频 视频流 而且解码输出 到 不同的文件里. 对于音频被还原回 ...
- c语言学习笔记第四章——字符串和格式化输入、输出
B站有视频演示 本章学习printf函数的输入输出,字符串的定义与实用. 字符串 字符串(character string)是一个或多个字符的序列,如下所示: "Zing went the ...
- Pytorch从0开始实现YOLO V3指南 part5——设计输入和输出的流程
本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...
- 了解一下C++输入和输出的概念
我们经常用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上.从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件.除了以终端为对象进行输入和输出外,还经常 ...
- [总结] I/O输入,输出
I/O输入,输出第一:先判断到底是输入还是输出,站在程序的立场第二:判断是传递字节,还是字符,决定管道粗细,字节流是最基本的数据输出管道.字符类型管道专门用来传送文本数据.Java流的四大父类:1.字 ...
- C#语言基础— 输入与输出
C#语言基础— 输入与输出 1.1函数的四要素:名称.输入.输出.加工 1.2主函数:输出语句.输入语句: Static viod Main(string[] stgs)//下划线部分可以自己指定 { ...
- Shell编程基础教程3--Shell输入与输出
3.Shell输入与输出 3.1.echo echo命令可以显示文本行或变量,或者把字符串输出到文件 echo [option] string ...
- 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出
[源码下载] 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 预处理命令 输入 ...
随机推荐
- iOS 导航栏实现总结
目标: 在UI界面中实现 整体效果的导航栏, 比如1 首页无导航条,次页有导航条, 2 导航条中不包含下方不包含黑边 3 导航条包含多个筛选项 等等 问题: 用系统带的NavigateBar 来实现时 ...
- mysql metadata lock(三)
前言 MDL锁主要用来保护Mysql内部对象的元数据,通过MDL机制保证DDL与DML以及SELECT查询操作的并发.MySQL Meta Lock(一)和MySQL Meta Lock(二)已经讲了 ...
- 编写BinIoDemo.java的Java应用程序,程序完成的功能是:完成1.doc文件的复制,复制以后的文件的名称为自己的学号姓名.doc。
package zuoye; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; ...
- MVC Ajax Helper或jQuery异步方式加载部分视图
Model: namespace MvcApplication1.Models { public class Team { public string Preletter { get; set; } ...
- Linux磁盘管理之磁盘结构、概念、原理01
一.磁盘的分类 磁盘主要有IDE.SATA.SCSI.IDE是比较老的硬盘,数据速度比较慢:SATA是现在用的比较多的,台式机.笔记本大多都用的SATA硬盘:SCSI硬盘速度最快,但是价格相对较高. ...
- cal 命令
cal命令是linux里面查看日历的一个命令,效果如下: [root@localhost ~]# cal 十月 日 一 二 三 四 五 六 我们可以的很形象的从日历上看出今天是哪年,哪年的哪天,周几, ...
- mac 启动apache服务
启动服务:sudo /usr/sbin/apachectl start 停止服务:sudo /usr/sbin/apachectl stop 重启服务:sudo /usr/sbin/apachectl ...
- zookeeper 相关学习资料
zookeeper的配置:http://www.cnblogs.com/yuyijq/p/3438829.html zookeeper运维:http://blog.csdn.net/hengyunab ...
- finereport普通报表的移动端自适应方案
移动端报表呈现,首先要求的是页面随手机屏幕大小自动放缩(自适应),下面给出一个普通报表中的finereport移动端自适应方案,适用于finereport 7.1之前的版本. 首先,了解一下当前我们可 ...
- 《Invert》开发日志01:核心玩法设计
前面提过,这个游戏的核心玩法基于我做的第一个Unity游戏,名字就叫<Invert>,现在在应用宝上面还能搜到.不过那个游戏也不是我原创的,它的玩法设计来自github上的一个开源项目(h ...