I'm writing a logic to retrieve every 3rd frame from a video in opencv c++, while executing I am facing a problem in first 'for' loop when I try print(cout) 'i' value ouput is only upto 687, after which "Error: Insufficient memory (Failed to allocate 2764804 bytes) out of memory" error occurs.
int main(){
string path = "C:/vid_frames/Highway_Hamilton.avi";
VideoCapture capture(path);
Mat matImage[1000];
cout<<"initalization done";
//obtaining frames from the video into matimage variable
for(int i=0;i<1000;i++) {
char filename[30]="Existing frame";
capture >> matImage[i];
cout<<"i:"<<i;
if ( matImage[i].empty())
{
cout << "Cannot load image!,runnig application might abort exit,press any key:" << endl;
getchar();
}
char frame_id[30];
itoa(i, frame_id, 15);
strcat(filename, frame_id);
}
int num=0;
for(int i=0;num<1000;i++) {
char filename[30]="Required frame";
char frame_id[30];
itoa(num, frame_id, 10);
strcat(filename, frame_id);
num=num+3;
}
}
suggest me how I can access a array of Mat variable beyond 687,and kindly let me know if any other logic exists for retrieving every 3rd frame from a video, so that I can move out of this prob,solving this prob is surely appreciable. thanks in advance.
You can use CV_CAP_PROP_POS_FRAMES macro to set frame position to be decoded/captured next.
Like,
VideoCapture::set(CV_CAP_PROP_POS_FRAMES ,framePosition);
See OpenCV Doc for more details
Related
I am trying to build an application, which get data from webcam or external device, saves Video Frames into text file, then read frames from created text file.
I don't know whether it is a good idea to save to text file, I'm open suggestions.
So far I've done to saving to a text file.
My problem is reading from text file. Basically I read text line by line, but I don't know how to convert this text into Mat object.
So far my code is:
ifstream read_storage(new_vid_frm_path);
if(!read_storage.is_open()) {
perror("\n\n\n\t\t\t(-)FAIL : Can't Open SavedVideoFrames.txt\n\n\n\t\t\t");
return -1;
}
VideoWriter *vid = new VideoWriter(new_vid_frm_path,CV_FOURCC('P', 'I', 'M', '1'),30,Size(vc.get(CV_CAP_PROP_FRAME_WIDTH),vc.get(CV_CAP_PROP_FRAME_HEIGHT)));
Mat line;
vector<Mat> vid_frms;
while ( getline (read_storage,line) ) {
cout << line << '\n';
}
read_storage.close();
if(vid_frms.size() == 0){
printf("\n\n\n\t\t\t(-)FAIL: Error In Frame\n\n\n\t\t\t");
return -1;
}
for(size_t i = 0; i<vid_frms.size(); i++)
(*vid).write(vid_frms[i]);
printf("\n\n\n\t\t\t(+)SUCCESS: Video Processing Complete \n\n\n\t\t\t ");
Do you have ay suggestions how can I cast or convert this line string to Mat obejct?
while ( getline (read_storage,line) ) {
cout << line << '\n';
}
Thanks.
By the way, I looked at this solution, but I couldn't understand.
Convert a string of bytes to cv::mat
I couldn't find the byte type in c++ and I think there might be a direct conversion between String to Mat object.
You can save anything (just about) in OpenCV to a .xml or .yml text file and then read it back in using the OpenCV XML/YAML FileStorage methods.
I highly recomend this over using native C++ methods for file stuff.
It's specifically designed to handle all this legwork for you.
This post describes a very similar problem to mine however I am new here and was told to post a new question. Would very much appreciated anyone's help.
#Franksye I am stuck with the same problem. I am passing the path in this line
{#pd|C:/Cars/|pos_dir}{#p|Pos.lst|pos.lst}{#nd|C:/Cars/|neg_dir} {#n|Neg.lst|neg.lst}");
In the text file Pos.lst I wrote for example image0000.png, image0001.png underneath each other.
However when I run the debugger after build it gives me the below error
The program '[0x3CF0] opencv.exe' has exited with code -1 (0xffffffff).
When creating Brake points i realized that it is exiting on the load_images function when executing file.open((prefix + filename).c_str());
void load_images(const string & prefix, const string & filename, vector< Mat > & img_lst)
{
string line;
ifstream file;
file.open((prefix + filename).c_str());
if (!file.is_open())
{
cerr << "Unable to open the list of images from " << filename << " filename." << endl;
exit(-1);
}
bool end_of_parsing = false;
while (!end_of_parsing)
{
getline(file, line);
if (line.empty()) // no more file to read
{
end_of_parsing = true;
break;
}
Mat img = imread((prefix + line).c_str()); // load the image
if (img.empty()) // invalid image, just skip it.
continue;
#ifdef _DEBUG
imshow("image", img);
waitKey(10);
#endif
img_lst.push_back(img.clone());
}
}
I believe that I am doing something wrong when passing the path of the directory since the load_images function is not able to open the file of the images.
Can someone point me in the right direction or tell me what it is that I am doing wrong please.
Thank you in advance.
Solved it! Such a stupid mistake thanks to Windows.
pos.lst and neg.lst where actually pos.lst.txt and neg.lst.txt because of file extension being hidden. Thanks to This post managed to solve my problem.
Had to switch to Windows because i needed to use Visual Studio will revert back to Ubuntu once this project is over!
I am new to video decoding/encoding. Currently I have a task to test the video transmission for a network coding. The network coding programme was already done.
Firstly I tried to divide the video into frames in opencv, and transmit the frames, but after division, I found a 3MB video are converted to 80MB total size frames!! which is not efficient for transmission. Is there any better way to do the video transmission? Can any pros provide me a sample code in C++? I be told that cannot directly put video into buff due to the transmission bandwidth limitation. I am wondering using the inter frame difference to reduce the transmission file size but I do not know ht to do this in C++.
Here is my code for video divide into frames.
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
VideoCapture cap("/home/yonghao/Documents/50MbitMJPEG1080p.mp4"); // open the video file for reading
double fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
int numFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); // get the total number of frames
cout << "Frame per seconds : " << fps << endl;
cout << "Total Frame Numbers : " << numFrames << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
int frame_number = 1;
while(frame_number<=numFrames)
{
Mat frame;
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read the frame from video file" << endl;
break;
}
imshow("MyVideo", frame); //show the frame in "MyVideo" window
//save frame
stringstream ss;
string name = "/home/yonghao/Documents/Frames/frame_";
string type = ".jpg";
ss<<name<<(frame_number)<<type;
string filename = ss.str();
ss.str("");
imwrite(filename, frame);
cout << "Frame " << frame_number << " has been generated." << endl;
frame_number++;
//user exit by press ESC button
if(waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}
If the bitrate of your video is too high for your bandwidth, you need to recompress it, using a standard video codec, for example h264.
You can do that with the ffmpeg program, using something like :
ffmpeg -i <your_input_file> -c:v libx264 -crf 22 video.avi
This will encode with default options and a constant quality (crf parameter, the lower the higher quality), see here for the options of h264 encoder, in your case you may prefer to use constant bitrate instead of constant quality.
Reading the video at correct speed and streaming it on the network would be possible in c with libavformat library (part of ffmpeg libraries), but probably complex for a beginner.
One simpler solution would be to pipe the output of a ffmpeg command to your program that does the network coding.
For example:
ffmpeg -re -i input.avi -f rawvideo -c:v copy pipe:1 | ./network_encode
This will read the encoded video file and send the raw video stream to your network encoding program (here network_encode read data from standard input, apply your network coding and send it)
On the receiver, you can do something similar to visualize your video (here network_decode receive the data from the network, decode it, and write result to standard output):
./network_decode | ffplay -i -
I am capturing an avi file and processing it. My code has worked for sometime without problem but now it does not seem to stop after the last frame of the video is captured. Instead it keeps looping back to the beginning of the video. I do not understand why this is happening and I can not think of anything changing with regards to Eclipse or OpenCV. I have tried the same code on my Ubuntu pc with the same video and it works without problems. I have even tried as much as reinstalling the OS and apps without success.
Sample code:
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat frame;
VideoCapture capture;
const string inputVideo = argv[1];
char buff[PATH_MAX];
getcwd( buff, PATH_MAX );
std::string fileName( buff );
fileName.append("/");
fileName.append(inputVideo);
capture.open(inputVideo);
while(true)
{
capture >> frame;
if(!frame.empty())
{
imshow("frame", frame);
}
else
{
printf(" --(!) No captured frame -- Break!");
break;
}
int key = waitKey(10);
if((char)key == 'c')
{
break;
}
}
return 0;
}
I am running this on a Mac OS X (10.8.2), Eclipse Juno, and OpenCV 2.4.3.
Any advice or comments are appreciated. Thanks in advance
The solution that I used was posted as a comment by #G B. I am creating a solution so that it may be marked as one.
I used capture.get(CV_CAP_PROP_POS_FRAMES) before and after frame grabbing, if the value "after" is less than the value "before", then I've reached the end of the video.
Get the frame count like below,
int frameCnt = capture.get(CV_CAP_PROP_FRAME_COUNT);
And check to exit the loop when the frame count exceeds..
Im picking up values from a .txt file using ifstream. i am also using windows library to read all files in a folder, that is loop over until the end of folder is reached. In this loop I am reading values from a txt file and adding it to a matrix using push_back.
Here is the section of code under question:
Mat trainme(0, dictionarySize, CV_32FC1);
Mat labels(0, 1, CV_32FC1); //1d matrix with 32fc1 is requirement of normalbayesclassifier class
hTrain = FindFirstFile(full_path, &TrainData);
if (hTrain != INVALID_HANDLE_VALUE)
{
ifstream file("c:\\222\\labels.txt");
string line;
do {
strcpy(loc,DirSpec);
Mat img = imread(strcat(loc,TrainData.cFileName), 0);
cout<<"Processing file: "<<TrainData.cFileName<<endl;
if (!img.data){
cout << "Image data not loaded properly: " <<TrainData.cFileName<< endl;
cin.get();
}
vector<KeyPoint> keypoints;
features->detect(img, keypoints);
if(keypoints.empty()) cout<<"Cannot find keypoints in image: "<<TrainData.cFileName<<endl;
Mat bowDescriptor;
bowDE.compute(img, keypoints, bowDescriptor);
trainme.push_back(bowDescriptor);
getline(file, line);
labels.push_back(line);
strcpy(loc,"");
} while( FindNextFile(hTrain,&TrainData));
}
The problem arises at the line labels.push_back(line); after 3 loops. I mean the file is read 3 times and after that the error: Access violation writing location. And points to this line in memcpy.asm:
mov [edi],al ;U - put byte in destination
I cannot figure out why it fails. I thought it may be a problem transferring string format so I used float value = atof(line) but that gave an error that it cannot convert from string format and it can only take the old c style string.
Here is what is contained in the labels.txt
1
2
2
2
1
2
2
2
Thank you for looking.
Update: I tried moving the file reading out of the main loop and used while(file.good()) But I still get the same error at the same spot. I have no idea why.
string line;
ifstream file("c:\\222\\labels.txt");
if (file.is_open())
{
while (file.good() )
{
getline (file,line);
labels.push_back(line);
}
file.close();
}
Alrighty, I managed to get it solved... =/
The problem was here: labels.push_back(line);
I think adding std::string to Mat using push_back is not possible.
I solved it by converting the string to float using atof.
getline (file,line);
float label = atof(line.c_str());
labels.push_back(label);