这周,OpenCV的老师在讲完HighGUI模块后,布置了一个作业。
当然,因为自己编程基础不太牢固,去网络上寻找了很多的代码,但是鱼龙混杂,错误一堆,借鉴了其中一些优秀大佬的思想,自己编程调试了很久,终于基本成功了,也想分享一下这个过程中的一些感想。本文仅介绍老师留的基础作业,挑战作业会另外开贴细说(和OpenCV本身关系不大)。
由于在OpenCV中实现视频播放的方法是将视频一帧一帧提取出来播放,因此联想到,如果使用滑动条控制视频的进度,最方便的办法是将进度条代表的的值为视频的当前帧,正好HighGUI模块中有对应的函数。
从上面的分析中可知,我们可以将滑动条的回调函数设置成视频的当前帧数:
void onTrackbackSlide(int poss, void*) {
cap.set(CAP_PROP_POS_FRAMES, poss);//将视频当前显示的帧位置的int值赋给poss
}
由于创建滑动条时需要有个最大值,在该例子中为视频的总帧数(视频最后的帧位置)所以可以编写以下一段代码:
int totalframe = cap.get(CAP_PROP_FRAME_COUNT);
接下来就可以创建滑动条,在创建滑动条(假设名字为”FPS“)后,需要在循环中加入以下一段代码,这样滑动条就会跟着视频动:
int currentpos = (int)cap.get(CAP_PROP_POS_FRAMES);
setTrackbarPos("FPS", "test2", currentpos);
这是在编写程序中最让我头疼的事情,后来借鉴了网络上的某种方法能够让程序接到鼠标指令后一直跑空循环,同时在接收到鼠标的另一指令后重新开始循环,大概的实现思想如下:
首先定义一个全局变量play=-1,在循环中加上if(play!=0),在每次循环结束后让play减1,只要让play=1,那么在显示一帧后能够一直跑空循环,即暂停,若让play重新等于-1,那么程序继续循环。
假设相应的操作是左键暂停,右键播放,鼠标的回调函数如下(假设鼠标返回值为a):
void on_mouseevent(int event, int x, int y, int flags, void* param) {
if (event == EVENT_LBUTTONDOWN) {
a = 1;
}
else if (event == EVENT_RBUTTONDOWN) {
a = 2;
}
else {
a = 0;
}
}
当时看到这个算法真的惊叹到我了,不过后来一想应该是比较基础的编程思想,但还是很惊叹。
于是根据鼠标操作的不同返回值,就能实现鼠标左键暂停、右键重新播放的操作了。
想实现该条件其实很简单,首先需要了解waitKey()这个函数,括号内的值代表等待时间(整型,单位为ms),即程序运行到该处时,在等待时间内,如果有键盘输入,那么waitKey会返回输入的字符(char),或者相应键位的ASC码(这个网上可以查到),在该条件下,Esc的ASC码为27,因此秩序一行代码即可实现该功能:
if (waitKey(5) == 'q' || waitKey(5) == 27)break;//5ms内键盘输入q键或者Esc键则跳出循环(播放视频)
思路很简单,因此不给出完整代码了。
#include
using namespace cv;
VideoCapture cap;
int pos = 0;
void onTrackbackSlide(int poss, void*) {
cap.set(CAP_PROP_POS_FRAMES, poss);
}
int main()
{
cap.open("1.mp4");//读入视频
int totalframe =(int)cap.get(CAP_PROP_FRAME_COUNT);//获取视频总帧数
namedWindow("Video", 0);
createTrackbar("FPS", "Video", &pos, totalframe,onTrackbackSlide);//产生滑动条
while (1) {
Mat frame;//储存每一帧的图像
cap >> frame;//读取当前帧
int currentpos = (int)cap.get(CAP_PROP_POS_FRAMES);//获取视频当前帧位置数
setTrackbarPos("FPS", "Video", currentpos);//设置滑动条的数值为当前帧位置数
imshow("Video", frame);//显示当前帧
waitKey(10);//等待10ms,若无键盘输入进入下一循环
}
destroyAllWindows;
}
#include
using namespace cv;
VideoCapture cap;
int a = 0;
int play = -1;
void on_mouseevent(int event, int x, int y, int flags, void* param) {
if (event == EVENT_LBUTTONDOWN) {
a = 1;
}//点击左键返回a值为1
else if (event == EVENT_RBUTTONDOWN) {
a = 2;
}//点击右键返回a值为2
else {
a = 0;
}
}
int main()
{
cap.open("1.mp4");//读入视频
namedWindow("Video", 0);
Mat frame;
while (1) {
if (play != 0)//让a为0时,会让while进行空循环,play大于零时即表示显示几帧图像,play小于零时流畅播放视频
{
cap >> frame;
if (!frame.data)break;
imshow("Video", frame);
setMouseCallback("Video", on_mouseevent);//鼠标回调函数
play = play - 1;
}
if (a == 1)
{
play = 1;
a = 0;
}
else if (a == 2) {
play = -1;
a = 0;
}
waitKey(10);
}
destroyAllWindows;
}
以上就是我自己对本周OpenCV作业的一些想法,有些源自于自己的思考,有些借鉴了其他人思想的精华,如果有错误的地方或者不太准确的地方请指出,因为严格来说不算计算机科班的(),也欢迎大家交流。