main文件
// 程序摘要:视频读取及自定义视频类处理
/* 读取视频序列;
自定义视频处理类VideoProcessor:可以处理视频和独立的图像序列,前者用以前的帧处理函数(回调函数process),
后者用自定义的帧处理类(FrameProcessor类接口即对象->process方法);其中用到了canny函数,其中涉及把每帧图像彩色转灰度和用Canny和
threshold函数*/
// 写入视频帧类VideoWriter,在VideoProcessor的方法中应用写入类实例的成员函数,也分为处理视频和独立的图像序列即用到成员函数重载
// 以上描述为:程序后半段用自定义视频处理类封装视频捕捉类、帧处理类和视频帧写入类
// 2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include <opencv2\opencv.hpp>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace cv;
using namespace std;
#include "videoprocessor.h"
void draw(const cv::Mat& img, cv::Mat& out) {
img.copyTo(out);
cv::circle(out, cv::Point(100, 100), 5, cv::Scalar(255, 0, 0), 2);
}
// processing function此函数定义用于真正的图像处理,为回调函数在main中注册后每次执行的函数处理,注意canny是封装了Canny函数
void canny(cv::Mat& img, cv::Mat& out) {
// Convert to gray
if (img.channels() == 3)
cv::cvtColor(img, out, CV_BGR2GRAY);
// Compute Canny edges
cv::Canny(out, out, 100, 200);
// Invert the image
cv::threshold(out, out, 128, 255, cv::THRESH_BINARY_INV);
}
int main()
{
// 打开视频文件
cv::VideoCapture capture("D:\\workplace\\opencv_training\\bike.avi");
//cv::VideoCapture capture("http://www.laganiere.name/bike.avi");
// 核实视频文件是否却是打开
if (!capture.isOpened())
return 1;
// Get the frame rate
double rate = capture.get(CV_CAP_PROP_FPS);
std::cout << "Frame rate: " << rate << "fps" << std::endl;
bool stop(false);
cv::Mat frame; // current video frame
cv::namedWindow("Extracted Frame");
// Delay between each frame
// corresponds to video frame rate
int delay = 1000 / rate;//视频播放按原始帧率,可设置使视频快进或倒退
long long i = 0;
std::string b = "bike";
std::string ext = ".bmp";
// for all frames in video抽取视频帧保存到同一工程目录下!!!!!!!!!
while (!stop)
{
// read next frame if any
if (!capture.read(frame))
break;
cv::imshow("Extracted Frame", frame);
std::string name(b);
// note: some MinGW compilers generate an error for this line
// this is a compiler bug
// try: std::ostringstream ss; ss << i; name+= ss.rdbuf(); i++;
// name+=std::to_string(i++);
std::ostringstream ss; ss << i; name += ss.str(); i++;
name += ext;
std::cout << name << std::endl;
cv::imwrite(name, frame);
// introduce a delay
// or press key to stop
if (cv::waitKey(delay) >= 0)//当超过指定时间,没有按键盘时,返回值-1
stop = true;
}
// Close the video file
capture.release();
cv::waitKey();
//###########################################################################################
// Now using the VideoProcessor class用自定义视频处理类封装视频捕捉类、帧处理类和视频帧写入类
// Create instance
VideoProcessor processor;
// Open video file
processor.setInput("D:\\workplace\\opencv_training\\bike.avi");
// Declare a window to display the video注册窗口内存预备显示用
processor.displayInput("Input Video");//彩色图像
processor.displayOutput("Output Video");//灰度图像
// Play the video at the original frame rate
processor.setDelay(1000. / processor.getFrameRate());
// 此为注册回调函数Set the frame processor callback function*****设置类的实例的回调函数方法为main前声明的canny()函数!!!
processor.setFrameProcessor(canny);
// output a video
//传入值-1代表不采用与输入一致的编解码方式,而是提供MFC供选择,15代表帧的速率
processor.setOutput("D:\\workplace\\opencv_training\\bike1.avi", -1, 15);
// stop the process at this frame,只处理前51帧并保存到内存
processor.stopAtFrameNo(51);
// Start the process
processor.run();
cv::waitKey();
return 0;
}
自定义头文件
#if !defined VPROCESSOR
#define VPROCESSOR
#include <iostream>
#include <iomanip>//流控制头文件
#include <sstream>
#include <string>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
// The frame processor interface
class FrameProcessor {
public:
// processing method
virtual void process(cv::Mat &input, cv::Mat &output) = 0;
};
class VideoProcessor {
private:
// the OpenCV video capture object
cv::VideoCapture capture;
// the callback function to be called
// for the processing of each frame
void(*process)(cv::Mat&, cv::Mat&);
// the pointer to the class implementing
// the FrameProcessor interface
FrameProcessor *frameProcessor;
// a bool to determine if the
// process callback will be called
bool callIt;
// Input display window name
std::string windowNameInput;
// Output display window name
std::string windowNameOutput;
// delay between each frame processing
int delay;
// number of processed frames
long fnumber;
// stop at this frame number
long frameToStop;
// to stop the processing
bool stop;
// vector of image filename to be used as input
std::vector<std::string> images;
// image vector iterator
std::vector<std::string>::const_iterator itImg;
// the OpenCV video writer object
cv::VideoWriter writer;
// output filename
std::string outputFile;
// current index for output images
int currentIndex;
// number of digits in output image filename
int digits;
// extension of output images
std::string extension;
// to get the next frame
// could be: video file; camera; vector of images
bool readNextFrame(cv::Mat& frame) {
if (images.size() == 0)
return capture.read(frame);
else {
if (itImg != images.end()) {
frame = cv::imread(*itImg);
itImg++;
return frame.data != 0;
}
return false;
}
}
// to write the output frame
// could be: video file or images
void writeNextFrame(cv::Mat& frame) {
if (extension.length()) { // then we write images
std::stringstream ss;
ss << outputFile << std::setfill('0') << std::setw(digits) << currentIndex++ << extension;
cv::imwrite(ss.str(), frame);
}
else { // then write video file
writer.write(frame);
}
}
public:
// Constructor setting the default values
VideoProcessor() : callIt(false), delay(-1),
fnumber(0), stop(false), digits(0), frameToStop(-1),
process(0), frameProcessor(0) {}
// set the name of the video file
bool setInput(std::string filename) {
fnumber = 0;
// In case a resource was already
// associated with the VideoCapture instance
capture.release();
images.clear();
// Open the video file
return capture.open(filename);
}
// set the camera ID
bool setInput(int id) {
fnumber = 0;
// In case a resource was already
// associated with the VideoCapture instance
capture.release();
images.clear();
// Open the video file
return capture.open(id);
}
// set the vector of input images
bool setInput(const std::vector<std::string>& imgs) {
fnumber = 0;
// In case a resource was already
// associated with the VideoCapture instance
capture.release();
// the input will be this vector of images
images = imgs;
itImg = images.begin();
return true;
}
// set the output video file
// by default the same parameters than input video will be used
bool setOutput(const std::string &filename, int codec = 0, double framerate = 0.0, bool isColor = true) {
outputFile = filename;
extension.clear();
if (framerate == 0.0)
framerate = getFrameRate(); // same as input
char c[4];
// use same codec as input
if (codec == 0) {
codec = getCodec(c);
}
// Open output video
return writer.open(outputFile, // filename
codec, // codec to be used
framerate, // frame rate of the video
getFrameSize(), // frame size
isColor); // color video?
}
// set the output as a series of image files
// extension must be ".jpg", ".bmp" ...
bool setOutput(const std::string &filename, // filename prefix
const std::string &ext, // image file extension
int numberOfDigits = 3, // number of digits
int startIndex = 0) { // start index
// number of digits must be positive
if (numberOfDigits<0)
return false;
// filenames and their common extension
outputFile = filename;
extension = ext;
// number of digits in the file numbering scheme
digits = numberOfDigits;
// start numbering at this index
currentIndex = startIndex;
return true;
}
// set the callback function that will be called for each frame
void setFrameProcessor(void(*frameProcessingCallback)(cv::Mat&, cv::Mat&)) {
// invalidate frame processor class instance
frameProcessor = 0;
// this is the frame processor function that will be called
process = frameProcessingCallback;
callProcess();
}
// set the instance of the class that implements the FrameProcessor interface
void setFrameProcessor(FrameProcessor* frameProcessorPtr) {
// invalidate callback function
process = 0;
// this is the frame processor instance that will be called
frameProcessor = frameProcessorPtr;
callProcess();
}
// stop streaming at this frame number
void stopAtFrameNo(long frame) {
frameToStop = frame;
}
// process callback to be called
void callProcess() {
callIt = true;
}
// do not call process callback
void dontCallProcess() {
callIt = false;
}
// to display the input frames
void displayInput(std::string wn) {
windowNameInput = wn;
cv::namedWindow(windowNameInput);
}
// to display the processed frames
void displayOutput(std::string wn) {
windowNameOutput = wn;
cv::namedWindow(windowNameOutput);
}
// do not display the processed frames
void dontDisplay() {
cv::destroyWindow(windowNameInput);
cv::destroyWindow(windowNameOutput);
windowNameInput.clear();
windowNameOutput.clear();
}
// set a delay between each frame
// 0 means wait at each frame
// negative means no delay
void setDelay(int d) {
delay = d;
}
// a count is kept of the processed frames
long getNumberOfProcessedFrames() {
return fnumber;
}
// return the size of the video frame
cv::Size getFrameSize() {
if (images.size() == 0) {
// get size of from the capture device
int w = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_WIDTH));
int h = static_cast<int>(capture.get(CV_CAP_PROP_FRAME_HEIGHT));
return cv::Size(w, h);
}
else { // if input is vector of images
cv::Mat tmp = cv::imread(images[0]);
if (!tmp.data) return cv::Size(0, 0);
else return tmp.size();
}
}
// return the frame number of the next frame
long getFrameNumber() {
if (images.size() == 0) {
// get info of from the capture device
long f = static_cast<long>(capture.get(CV_CAP_PROP_POS_FRAMES));
return f;
}
else { // if input is vector of images
return static_cast<long>(itImg - images.begin());
}
}
// return the position in ms
double getPositionMS() {
// undefined for vector of images
if (images.size() != 0) return 0.0;
double t = capture.get(CV_CAP_PROP_POS_MSEC);
return t;
}
// return the frame rate
double getFrameRate() {
// undefined for vector of images
if (images.size() != 0) return 0;
double r = capture.get(CV_CAP_PROP_FPS);
return r;
}
// return the number of frames in video
long getTotalFrameCount() {
// for vector of images
if (images.size() != 0) return images.size();
long t = capture.get(CV_CAP_PROP_FRAME_COUNT);
return t;
}
// get the codec of input video
int getCodec(char codec[4]) {
// undefined for vector of images
if (images.size() != 0) return -1;
union {
int value;
char code[4];
} returned;
returned.value = static_cast<int>(capture.get(CV_CAP_PROP_FOURCC));
codec[0] = returned.code[0];
codec[1] = returned.code[1];
codec[2] = returned.code[2];
codec[3] = returned.code[3];
return returned.value;
}
// go to this frame number
bool setFrameNumber(long pos) {
// for vector of images
if (images.size() != 0) {
// move to position in vector
itImg = images.begin() + pos;
// is it a valid position?
if (pos < images.size())
return true;
else
return false;
}
else { // if input is a capture device
return capture.set(CV_CAP_PROP_POS_FRAMES, pos);
}
}
// go to this position
bool setPositionMS(double pos) {
// not defined in vector of images
if (images.size() != 0)
return false;
else
return capture.set(CV_CAP_PROP_POS_MSEC, pos);
}
// go to this position expressed in fraction of total film length
bool setRelativePosition(double pos) {
// for vector of images
if (images.size() != 0) {
// move to position in vector
long posI = static_cast<long>(pos*images.size() + 0.5);
itImg = images.begin() + posI;
// is it a valid position?
if (posI < images.size())
return true;
else
return false;
}
else { // if input is a capture device
return capture.set(CV_CAP_PROP_POS_AVI_RATIO, pos);
}
}
// Stop the processing
void stopIt() {
stop = true;
}
// Is the process stopped?
bool isStopped() {
return stop;
}
// Is a capture device opened?
bool isOpened() {
return capture.isOpened() || !images.empty();
}
// to grab (and process) the frames of the sequence
void run() {
// current frame
cv::Mat frame;
// output frame
cv::Mat output;
// if no capture device has been set
if (!isOpened())
return;
stop = false;
while (!isStopped()) {
// read next frame if any
if (!readNextFrame(frame))
break;
// display input frame
if (windowNameInput.length() != 0)
cv::imshow(windowNameInput, frame);
// calling the process function or method
if (callIt) {
// process the frame
if (process)
process(frame, output);
else if (frameProcessor)
frameProcessor->process(frame, output);
// increment frame number
fnumber++;
}
else {
output = frame;
}
// write output sequence
if (outputFile.length() != 0)
writeNextFrame(output);
// display output frame
if (windowNameOutput.length() != 0)
cv::imshow(windowNameOutput, output);
// introduce a delay
if (delay >= 0 && cv::waitKey(delay) >= 0)
stopIt();
// check if we should stop
if (frameToStop >= 0 && getFrameNumber() == frameToStop)
stopIt();
}
}
};
#endif