c++调用opencv库实现视频关键帧提取--灰度帧差法

为了提取关键帧,这里使用帧差法,语言为C语言,调用opencv库实现。

我们将视频第一帧设定为关键帧,后面的每一个帧与前一个关键帧进行像素帧差(灰度图),并设定阈值判断发生变化的像素点比例,通过此比例判断帧是否有发生突变,有发生突变的帧设定为关键帧并保存在特定文件夹中。以此循环将所有帧遍历完成即可。

在测试程序前,为了方便测试,我们将电影截取为两分钟的片段,不然太长了不方便测试,如果有备好的视频片段可以跳过这一步。在终端terminal打开窗口,输入以下命令,将(流浪地球)liulang_earth.mkv在一小时16分到一小时18分截取两分钟的视频片段并不保存为cutout1.mp4。之后对此两分钟视频提取关键帧。

 ffmpeg  -i ./liulang_earth.mkv -vcodec copy -acodec copy -ss 01:16:00 -to 01:18:00 ./cutout1.mp4 -y

程序我是放在文本编辑器中的,然后用g++编译。将pixels_cha.cpp编译生成pixels_cha可执行程序。g++编译命令如下

g++ `pkg-config opencv --cflags` pixels_cha.cpp -o pixels_cha `pkg-config opencv --libs

成功后再终端继续输入  ./pixels_cha   即可运行程序。如果使用其他编译器也是没有问题的。

程序如下

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
using namespace cv;
 
int main()
{
	system("color 2F");
	long currentFrame = 1;
	float p;
	VideoCapture cap;
	//这里放置需要提取关键字的视频
	cap.open("./cutout1.mp4");
	if(!cap.isOpened())//如果视频不能正常打开则返回
	{	cout<< "cannot open video!"<>frame_key;
	if(frame_key.empty())
		cout<< "frame_key is empty!" << endl;
	imshow("fram_1",frame_key);
	waitKey(20);
	stringstream str;  
	str<<"./keyframes_pixels_cha/" <>>>>>>>>>>>>00");
		currentFrame++;
		Mat frame;
		cap>>frame;
		//printf(">>>>>>>>>>>>>1");
		if(frame.empty())
		{
			cout<< "frame is empty!" << endl;
			break;}
		imshow("fram_1",frame);
		waitKey(20);
	
		Mat srcImage_base, hsvImage_base;
		Mat srcImage_test1, hsvImage_test1;
		srcImage_base = frame_key;
		srcImage_test1 = frame;									
		//将图像从BGR色彩空间转换到 HSV色彩空间
		cvtColor(srcImage_base, previousImage, CV_BGR2GRAY);
		cvtColor(srcImage_test1, currentImage, CV_BGR2GRAY);		
		//printf(">>>>>>>>>>>>>2");
		absdiff(currentImage,previousImage,resultImage);  //帧差法,相减
		//printf(">>>>>>>>>>>>>3");
		threshold(resultImage, resultImage, 10, 255.0, CV_THRESH_BINARY); //二值化,像素值相差大于20则置为255,其余为0
		printf(">>>>>>>>>>>>>1\n");
		float counter = 0;
		float num = 0;
		// 统计两帧相减后图像素
		for (int i=0; i(i); //获取每一行的指针
			for (int j=0;j>>>>>counter>>>>num>>>>p: %f  %f  %f  \n",counter,num,p);
		if (p > 0.55) //达到阈值的像素数达到一定的数量则保存该图像
		{
			//printf(">>>>>>>>>>>>>6");
			cout<< ">>>>>>>>>>>>>>>>>>>>.>>>>>>>.this frame is keyframe!"<>>>>>>>>>>>.this frame is not keyframe!"<

程序运行结果如下。第一帧不知道怎么不显示图,不过双击后仍然可以打开的。关键帧名字代表该帧属于视频中的第几帧。结果很理想,没有太多冗余帧。程序中可调参数为threshold(resultImage, resultImage, 10, 255.0, CV_THRESH_BINARY)中的 10,10为二值化阈值,还有p,p为比例。通过调节这两个参数可以优化关键帧提取结果。

如果有需要视频片段+程序的压缩包的,我已经在csdn上传的资源https://download.csdn.net/download/weixin_39704651/11181825

也可以在评论留下邮箱我发送过去。欢迎讨论~

c++调用opencv库实现视频关键帧提取--灰度帧差法_第1张图片

你可能感兴趣的:(图像处理,关键帧提取,帧差法)