转载请注明转自:http://blog.csdn.net/ding977921830/article/details/50953895
网上很多opencv的帧差法资料,但是大都直接调用视频,或者调用摄像头,调用文件夹下的图片库的资料比较少,通过网上整理资料,终于利用opencv按照帧来处理图片。
使用opencv批量读取文件夹下的视频帧批量读取图片;
使用opencv批量读取图片,二帧差分法二帧差法;
具体代码如下:
//#include "stdAfx.h"
#include <opencv2/core/core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <iostream>
#include <direct.h>//for mk_dir
#include <io.h>//for _acess()
#include <opencv2/imgproc/imgproc.hpp>
#define threshold_diff1 10 //设置简单帧差法阈值
#define threshold_diff2 10 //设置简单帧差法阈值
using namespace cv;
using namespace std;
int recursive_mkdir( char *dir );//创建多级目录
///三帧差分法
int main(int argc, char** argv)
{ 批处理读入图片部分参数//
char* inputDir="F:\\论文视频库\\视频帧库\\Walking\\"; //一定要加上最后的两个双斜线,输入视频帧的目录
char* videoName="Walking.avi"; //输出的视频名字
char* outDir="F:\\论文视频库\\视频帧库\\Walking\\"; //一定要加上最后的两个双斜线,输出的视频的目录
int startFrame = 20; //含义:起始帧
int tmpFrame = startFrame; //含义:记录起始帧
int endFrame = 412; //含义:起始帧,结束帧
int imgW = 768; //含义:视频帧的宽
int imgH = 576; //含义:视频帧的高
char* imgExt = ".jpg"; //根据图片的性质选择.jpg,.bmp等类型,一定要注意jpg前面那个
//点,当时我缺了这个点,浪费了我一晚上的时间才找到问题
double fps=24; //帧率
int isColor=1; //颜色
int fourcc=CV_FOURCC('X','V','I','D'); //CV_FOURCC('X', 'V', 'I', 'D') 表示是XVID库进行压缩,压缩为MPEG4格式
IplImage *pImg=NULL;
IplImage *pImg2=NULL;
IplImage *pImg3=NULL;
char cur_fn[255]; //表示某张图片的绝对路径
char fullVideoName[255]; //输出视频的完整文件名:路径+文件名
int frameCount = startFrame; //计算运行到第N帧
int frames = 0 ; //总帧数
CvSize size=cvSize(imgW,imgH);
//帧差法部分参数
Mat img_src1,img_src2,img_src3;//3帧法需要3帧图片
Mat img_dst,gray1,gray2,gray3;
Mat gray_diff1,gray_diff2,gray_diff;//存储2次相减的图片
Mat gray;//用来显示前景的
//判断输入文件夹是否存在
if (_access(inputDir,0)==-1)
{
cout<<"the input directory does not exist!"<<endl;
return 0;
}
//判断输出文件夹是否创建 若没有则创建;若为NULL则默认当前工作目录
strcpy_s(fullVideoName,"");
if (outDir==NULL)
{
sprintf_s(fullVideoName,"%s",videoName);//把videoName打印成一个字符串保存在fullVideoName 中
}
else
{
if (_access(outDir,0)==-1)
{
recursive_mkdir(outDir);
}
sprintf_s(fullVideoName,"%s%s",outDir,videoName);//将字符串outDir和videoName连接起来,打印,保存在fullVideoName中
}
while(startFrame<=endFrame)
{
strcpy_s(cur_fn,"");
sprintf_s(cur_fn,"%s%d%s",inputDir,startFrame,imgExt);//need to change
pImg=cvLoadImage(cur_fn,isColor);
sprintf_s(cur_fn,"%s%d%s",inputDir,startFrame-1,imgExt);//need to change
pImg2=cvLoadImage(cur_fn,isColor);
sprintf_s(cur_fn,"%s%d%s",inputDir,startFrame-2,imgExt);//need to change
pImg3=cvLoadImage(cur_fn,isColor);
if (!pImg)
{
std::cout<<"can't open an image file"<<std::endl;
}
Mat mtx(pImg); // IplImage格式转换成Mat格式
Mat mtx2(pImg2); // IplImage格式转换成Mat格式
Mat mtx3(pImg3); // IplImage格式转换成Mat格式
//为了方便使用后一帧减去前一帧:
img_src3 = mtx; //当前帧
img_src2 = mtx2; //第二帧
img_src1 = mtx3; //第一帧
//img_src3;//3帧法需要3帧图片
namedWindow("MyWindow", CV_WINDOW_AUTOSIZE);
imshow("MyWindow", mtx);
cout<<"运行到第 "<< frameCount<<" 帧 "<<endl;
waitKey(1);
cvtColor(img_src1,gray1,CV_BGR2GRAY);
//imshow("第一帧video_src1",img_src1);//可以事先不用新建一个窗口
//waitKey(5);
cvtColor(img_src2,gray2,CV_BGR2GRAY);
//imshow("第二帧video_src2",img_src2);//可以事先不用新建一个窗口
//waitKey(5);
cvtColor(img_src3,gray3,CV_BGR2GRAY);
//imshow("第三帧即当前帧video_src3",img_src2);//可以事先不用新建一个窗口
//waitKey(5);
subtract(gray2,gray1,gray_diff1);//第二帧减第一帧
subtract(gray3,gray2,gray_diff2);//第三帧减第二帧
for(int i=0;i<gray_diff1.rows;i++)
for(int j=0;j<gray_diff1.cols;j++)
{
if(abs(gray_diff1.at<unsigned char>(i,j))>=threshold_diff1)//这里模板参数一定要用unsigned char,否则就一直报错
gray_diff1.at<unsigned char>(i,j)=255; //第一次相减阈值处理
else gray_diff1.at<unsigned char>(i,j)=0;
if(abs(gray_diff2.at<unsigned char>(i,j))>=threshold_diff2)//第二次相减阈值处理
gray_diff2.at<unsigned char>(i,j)=255;
else gray_diff2.at<unsigned char>(i,j)=0;
}
bitwise_and(gray_diff1,gray_diff2,gray);
imshow("运动目标foreground",gray);
waitKey(5);
Mat ero ;
Mat dil ;
Mat ero_dil ;
Mat gaosi ;
erode(gray,ero,cv::Mat()); //腐蚀
dilate(gray,dil,cv::Mat()); //膨胀
dilate(ero,ero_dil,cv::Mat()); //腐蚀后再膨胀
imshow("腐蚀后的二值图片",ero); //可以事先不用新建一个窗口
waitKey(5);
imshow("膨胀后的二值图片",dil); //可以事先不用新建一个窗口
waitKey(5);
imshow("腐蚀后再膨胀后的二值图片",ero_dil); //可以事先不用新建一个窗口
waitKey(5);
GaussianBlur(gray,gaosi,Size(5,5),0,0); //高斯滤波
imshow("高斯滤波后的二值图片",gaosi); //可以事先不用新建一个窗口
waitKey(5);
startFrame++;
frameCount++;
frames++;
}
rename(videoName,fullVideoName);//移动文件到指定文件夹
cout<<"起始帧为: "<<tmpFrame<<endl;
cout<<"total frames 为: "<<frames<<" have been write to video."<<endl;
system("pause");
return 0;
}
//该函数借鉴了网上资料,自动创建多级目录
int recursive_mkdir( char *dir )
{
//分解路径名E:\\AA\\BB\\CC\\
//
std::string str = dir;
int index = 0;
int i = 0;
while(1)
{
std::string::size_type pos = str.find("\\",index);
std::string str1;
str1 = str.substr(0,pos);
if( pos != -1 && i > 0 )
{
if (_access(str1.c_str(),0)==-1)
{
_mkdir(str1.c_str());
}
}
if( pos==-1 )
{
break;
}
i ++;
index = pos+1;
}
return 0;
}
参考文献:
1.http://blog.csdn.net/sway_2012/article/details/7786465
2.http://www.cnblogs.com/tornadomeet/archive/2012/05/01/2477629.html