O' k所以下面的程序应该把一个视频文件并将其切割成分离的帧并将每个帧保存在它自己的文件中,但不是所有的帧都应保存但只保存在他们进入框架之前,他们内部的人包括大约20帧。
我的代码:
#include <opencv2/opencv.hpp>
#include <vector>
void checkForPerson(const cv::Mat &frame, bool &personInside, bool &personInsideLastFrame);
void saveFrame(const cv::Mat &frame, std::vector<const cv::Mat> &frameBuffer, const bool personInsideLastFrame, int &savedFramesCount);
int main(){
cv::VideoCapture vc;
cv::Mat currFrame, currFrameBackup, filtered, bg;
std::vector<const cv::Mat> frameBuffer;
const cv::String org = "Original";
const cv::String filt = "Filtered";
bool personInside = false;
bool personInsideLastFrame;
int savedFramesCount = 0;
vc.open("res/video1.avi");
if(!vc.isOpened()){
std::cerr << "cant load video file!\n";
system("pause");
return EXIT_FAILURE;
}
vc >> bg; // use first frame as background asuming no people are inside
if(!bg.data){
std::cerr << "no frames found\n";
system("pause");
return EXIT_FAILURE;
}
cv:cvtColor(bg, bg, cv::COLOR_BGR2GRAY);
int c;
while(vc.read(currFrame) && ((c = cv::waitKey(5)) != 27)){
cv::cvtColor(currFrame, currFrameBackup, cv::COLOR_BGR2GRAY);
filtered = bg - currFrameBackup;
cv::threshold(filtered, filtered, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
cv::Mat erode = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3)); //just to clean up the mess a bit
cv::Mat dilate = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3));
cv::erode(filtered, filtered, erode);
cv::dilate(filtered, filtered, dilate);
checkForPerson(filtered, personInside, personInsideLastFrame);
if(personInside || personInsideLastFrame){
saveFrame(currFrame, frameBuffer, personInsideLastFrame, savedFramesCount);
}else{
if(frameBuffer.size() == 20){
frameBuffer.erase(frameBuffer.begin());
}
frameBuffer.push_back(currFrame);
}
cv::imshow(org, currFrame);
cv::imshow(filt, filtered);
}
return EXIT_SUCCESS;
}
void checkForPerson(const cv::Mat &frame, bool &personInside, bool &personInsideLastFrame){
if(personInside){
personInsideLastFrame = true;
}else{
personInsideLastFrame = false;
}
cv::MatConstIterator_<uchar> it = frame.begin<uchar>();
cv::MatConstIterator_<uchar> it_end = frame.end<uchar>();
for(; it != it_end; ++it){
if((*it) == 255){
personInside = true;
return;
}
}
personInside = false;
}
void saveFrame(const cv::Mat &frame, std::vector<const cv::Mat> &frameBuffer, const bool personInsideLastFrame, int &savedFramesCount){
if(personInsideLastFrame){
std::stringstream ss;
ss << "result/" << ++savedFramesCount << ".jpg";
cv::imwrite(ss.str(), frame);
}else{
for(int i = 0; i<frameBuffer.size(); ++i){
std::stringstream ss;
ss << "result/" << ++savedFramesCount << ".jpg";
cv::imwrite(ss.str(), frameBuffer[i]);
//cv::imshow("tmp", frameBuffer[i]);
//cv::waitKey(0);
}
frameBuffer.clear();
std::stringstream ss;
ss << "result/" << ++savedFramesCount << ".jpg";
cv::imwrite(ss.str(), frame);
}
}
代码中的frameBuffer
用于20(如果没有20,那么应该使用最大可用数量)前输入帧以及补偿少数&#34;错过帧&#34;与某人在一起。但是,当我保存帧时,似乎正确地将帧插入到frameBuffer
中,当检测到内部人员时,第一帧被保存20次。
我在frameBuffer
中未检测到任何内容时向currentFrame
插入一个帧,并在最后一帧中未检测到任何内容时使用这些帧。
这真的炒了我的大脑,我似乎无法看到问题(实际上看不到任何东西),
所以有人请告诉我,我犯了一个愚蠢的错误,一些建议也会非常感激。
对不起,如果我的描述有些混乱,我无法找到更好的解释方法。
答案 0 :(得分:4)
OpenCV除非需要,否则不会重新分配Mat。 Mat本质上是指向缓冲区的智能指针。如果将mat推送到向量中,就像将指针复制到同一个缓冲区一样。然后重用缓冲区,向量中的指针指向新内容!
当你将它推到矢量上时,你需要克隆Mat:
frameBuffer.push_back(currFrame.clone());