这是《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之视频的输入和输出以及滚动条的更多相关文章

  1. FFmpeg内存IO模式(内存区作输入或输出)

    本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10318145.html 所谓内存IO,在FFmpeg中叫作"buffered ...

  2. FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出

    对于FFMPEG SDK  提供的Demuxing 为我们实现多路复用  提供了非常多方便,以下的案案例 实现的是 分离一个媒体文件的音频 视频流 而且解码输出 到  不同的文件里. 对于音频被还原回 ...

  3. c语言学习笔记第四章——字符串和格式化输入、输出

    B站有视频演示 本章学习printf函数的输入输出,字符串的定义与实用. 字符串 字符串(character string)是一个或多个字符的序列,如下所示: "Zing went the ...

  4. Pytorch从0开始实现YOLO V3指南 part5——设计输入和输出的流程

    本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...

  5. 了解一下C++输入和输出的概念

    我们经常用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上.从操作系统的角度看,每一个与主机相连的输入输出设备都被看作一个文件.除了以终端为对象进行输入和输出外,还经常 ...

  6. [总结] I/O输入,输出

    I/O输入,输出第一:先判断到底是输入还是输出,站在程序的立场第二:判断是传递字节,还是字符,决定管道粗细,字节流是最基本的数据输出管道.字符类型管道专门用来传送文本数据.Java流的四大父类:1.字 ...

  7. C#语言基础— 输入与输出

    C#语言基础— 输入与输出 1.1函数的四要素:名称.输入.输出.加工 1.2主函数:输出语句.输入语句: Static viod Main(string[] stgs)//下划线部分可以自己指定 { ...

  8. Shell编程基础教程3--Shell输入与输出

    3.Shell输入与输出    3.1.echo        echo命令可以显示文本行或变量,或者把字符串输出到文件        echo [option] string             ...

  9. 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出

    [源码下载] 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 预处理命令 输入 ...

随机推荐

  1. ThreadLocal源码分析

    1.概述 ThreadLocal,可以理解为线程的局部变量,作用就是为每一个使用该变量的线程都提供一个变量值的副本,每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突. ThreadLo ...

  2. Linux 僵尸进程查杀

    僵尸进程概念 僵尸进程(Zombie process)通俗来说指那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸. 书面形式一点:一个进程结束了,但是他的父进程没有等待(调用wait ...

  3. 获取session、request、parmeter的方法

    package com.hanqi.action; import java.util.Map; import com.opensymphony.xwork2.ActionContext; public ...

  4. Kafka三款监控工具比较(转)

    在之前的博客中,介绍了Kafka Web Console这 个监控工具,在生产环境中使用,运行一段时间后,发现该工具会和Kafka生产者.消费者.ZooKeeper建立大量连接,从而导致网络阻塞.并且 ...

  5. Jmeter默认报告优化

    一.本文目的: 之前写了两篇文章搭建持续集成接口测试平台(Jenkins+Ant+Jmeter)和ANT批量执行Jmeter脚本,功能实现上都没有什么问题,但是最后生成的报告有一点小问题,虽然不影响使 ...

  6. 使用VIM插件ctags来阅读C代码

    说明 Ctags是vim下方便代码阅读的工具.尽管ctags也可以支持其它编辑器,但是它正式支持的只有vim.并且vim中已经默认安装ctags,它可以帮助程序员很容易地浏览源代码:ctags最先是用 ...

  7. CTO和技术副总裁应该如何分工?谁才是技术领导者?

    谁是初创公司的技术领导者,是CTO还是技术副总裁?任何在创业公司工作的人都知道,我们不应该去问这个问题.因为这两个是非常不同的角色,角色本身会随着创业公司的发展而变化,两者对于业务规模都很重要. 简单 ...

  8. monkeyrunner之安卓开发环境搭建(一)

    在学习monkeyrunner之前,让我们先搭建好eclipse安卓开发环境. 对于程序开发人员而言,eclipse并不陌生,它提供了一个非常广阔的平台来开发程序.同样也可以用它来开发android程 ...

  9. Carcraft

    魔兽登录系统   创建魔兽系统相关窗体: 登录窗体(frmLogin) 注册窗体(frmRegister) 主窗体   (frmMain) 实现魔兽登录系统: 登录的界面如下 实现思路: 1.创建一个 ...

  10. 高大上的uGUI正式版发布了

    uGUI发布啦 本周期待已久的New UI System 发布了,因为这段时间项目是开发期,所以比较忙,也就没过多关注新UI了,趁着周六日有空,来瞅瞅这高大上的New UI System. PS:我也 ...