【发布时间】:2014-08-09 12:40:17
【问题描述】:
好的,所以下面的程序应该获取一个视频文件并将其分割成单独的帧并将每一帧保存在它自己的文件中,但是不是所有的帧都应该被保存,而只有那些里面有人的帧,包括大约有人进入画面前 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 个则应使用最大可用)预输入帧,以及补偿一些“丢失的帧”与里面的人。但是,当我保存它们时,似乎帧被正确插入到frameBuffer 时,当检测到内部人员时,第一帧被保存了 20 次。
我在currentFrame 中未检测到任何内容时向frameBuffer 插入一个帧,并在最后一帧中未检测到任何内容时使用这些帧。
这真的把我的大脑炸了,我似乎看不到问题(实际上什么也看不到),
所以有人请告诉我我犯了一个愚蠢的错误,我们也会非常感谢一些建议。
很抱歉,如果我的描述有些混乱,我找不到更好的解释方式。
【问题讨论】: