I am trying to put number of frames which are taken from a video in a loop.I want to display that frames in sequence an after that I want to subtract it using opencv 2.3.
My problem is that I am not able to know where function is not called.
here is my code below:
using namespace cv;
void loadImage(IplImage *image, int number)
{
// Store path to directory
char filename[100];
strcpy(filename, "S:\FINAL PROJECT ABSTRACT\images 1");
char *frame;
// Convert integer to char
char frameNo[10];
//sprintf(frame, "%0.3i", number);
// Combine to generate path
strcat(filename, frameNo);
strcat(filename, ".jpg");
// Use path to load image
image = cvLoadImage(filename);
}
int _tmain(int argc, _TCHAR* argv[]){
IplImage *im=0;
int nImages = 6;
for (int i = 0; i < nImages; ++i)
{
loadImage(im, i);
char filename[100];
strcpy(filename, "images 1");
char frameNo[10];
sprintf(frameNo, "%03i", i);
strcat(filename, frameNo);
strcat(filename, ".jpg");
IplImage *im = cvLoadImage(filename,CV_LOAD_IMAGE_COLOR);
cvNamedWindow("pic");
cvShowImage("pic",im);
cvWaitKey();
}
}
//}
I am not getting any error in build.bt while debugging it shows:-
Unhandled exception at 0x77db15de in loop of frames.exe: 0xC0000005: Access violation.
At
strcat(filename, frameNo);
strcat(filename, ".jpg");
this point some error is there..
Your string handling is pretty confused. It's not clear exactly what path you're trying to generate.
You can replace most of your path generation with a single sprintf()
char filename[100];
sprintf(filename, "S:\\FINAL PROJECT ABSTRACT\\images 1%03i.jpg",number);
image = cvLoadImage(filename);
(100 chars seems somewhat arbitrary - and potentially a bit short)
No idea if that's the right string for your image paths, you were trying to insert a '.' in there, so I don't know what your real file paths look like.
However having loaded the image inside the loadImage() function, you then seem to do the exact same thing in main() (throw away the image you've just loaded, generate another path, and then load that instead). So I doubt this is going to work even when you fix the string handling.
Related
The libavcodec documentation is not very specific about when to free allocated data and how to free it. After reading through documentation and examples, I've put together the sample program below. There are some specific questions inlined in the source but my general question is, am I freeing all memory properly in the code below? I realize the program below doesn't do any cleanup after errors -- the focus is on final cleanup.
The testfile() function is the one in question.
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
}
#include <cstdio>
using namespace std;
void AVFAIL (int code, const char *what) {
char msg[500];
av_strerror(code, msg, sizeof(msg));
fprintf(stderr, "failed: %s\nerror: %s\n", what, msg);
exit(2);
}
#define AVCHECK(f) do { int e = (f); if (e < 0) AVFAIL(e, #f); } while (0)
#define AVCHECKPTR(p,f) do { p = (f); if (!p) AVFAIL(AVERROR_UNKNOWN, #f); } while (0)
void testfile (const char *filename) {
AVFormatContext *format;
unsigned streamIndex;
AVStream *stream = NULL;
AVCodec *codec;
SwsContext *sws;
AVPacket packet;
AVFrame *rawframe;
AVFrame *rgbframe;
unsigned char *rgbdata;
av_register_all();
// load file header
AVCHECK(av_open_input_file(&format, filename, NULL, 0, NULL));
AVCHECK(av_find_stream_info(format));
// find video stream
for (streamIndex = 0; streamIndex < format->nb_streams && !stream; ++ streamIndex)
if (format->streams[streamIndex]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
stream = format->streams[streamIndex];
if (!stream) {
fprintf(stderr, "no video stream\n");
exit(2);
}
// initialize codec
AVCHECKPTR(codec, avcodec_find_decoder(stream->codec->codec_id));
AVCHECK(avcodec_open(stream->codec, codec));
int width = stream->codec->width;
int height = stream->codec->height;
// initialize frame buffers
int rgbbytes = avpicture_get_size(PIX_FMT_RGB24, width, height);
AVCHECKPTR(rawframe, avcodec_alloc_frame());
AVCHECKPTR(rgbframe, avcodec_alloc_frame());
AVCHECKPTR(rgbdata, (unsigned char *)av_mallocz(rgbbytes));
AVCHECK(avpicture_fill((AVPicture *)rgbframe, rgbdata, PIX_FMT_RGB24, width, height));
// initialize sws (for conversion to rgb24)
AVCHECKPTR(sws, sws_getContext(width, height, stream->codec->pix_fmt, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL));
// read all frames fromfile
while (av_read_frame(format, &packet) >= 0) {
int frameok = 0;
if (packet.stream_index == (int)streamIndex)
AVCHECK(avcodec_decode_video2(stream->codec, rawframe, &frameok, &packet));
av_free_packet(&packet); // Q: is this necessary or will next av_read_frame take care of it?
if (frameok) {
sws_scale(sws, rawframe->data, rawframe->linesize, 0, height, rgbframe->data, rgbframe->linesize);
// would process rgbframe here
}
// Q: is there anything i need to free here?
}
// CLEANUP: Q: am i missing anything / doing anything unnecessary?
av_free(sws); // Q: is av_free all i need here?
av_free_packet(&packet); // Q: is this necessary (av_read_frame has returned < 0)?
av_free(rgbframe);
av_free(rgbdata);
av_free(rawframe); // Q: i can just do this once at end, instead of in loop above, right?
avcodec_close(stream->codec); // Q: do i need av_free(codec)?
av_close_input_file(format); // Q: do i need av_free(format)?
}
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: %s filename\n", argv[0]);
return 1;
}
testfile(argv[1]);
}
Specific questions:
Is there anything I need to free in the frame processing loop; or will libav take care of memory management there for me?
Is av_free the correct way to free an SwsContext?
The frame loop exits when av_read_frame returns < 0. In that case, do I still need to av_free_packet when it's done?
Do I need to call av_free_packet every time through the loop or will av_read_frame free/reuse the old AVPacket automatically?
I can just av_free the AVFrames at the end of the loop instead of reallocating them each time through, correct? It seems to be working fine, but I'd like to confirm that it's working because it's supposed to, rather than by luck.
Do I need to av_free(codec) the AVCodec or do anything else after avcodec_close on the AVCodecContext?
Do I need to av_free(format) the AVFormatContext or do anything else after av_close_input_file?
I also realize that some of these functions are deprecated in current versions of libav. For reasons that are not relevant here, I have to use them.
Those functions are not just deprecated, they've been removed some time ago. So you should really consider upgrading.
Anyway, as for your questions:
1) no, nothing more to free
2) no, use sws_freeContext()
3) no, if av_read_frame() returns an error then the packet does not contain any valid data
4) yes you have to free the packet after you're done with it and before next av_read_frame() call
5) yes, it's perfectly valid
6) no, the codec context itself is allocated by libavformat so av_close_input_file() is
responsible for freeing it. So nothing more for you to do.
7) no, av_close_input_file() frees the format context so there should be nothing more for you to do.
I am working in visual c++, usually I do it on .NET, because I need a method which is available only on this language. What I want to do is obtain the frames per second of a video file. The best I could make was creating a project with this main() method, in which (after Debug) I could see the result is saving fine in the res variable.
void main()
{
// initialize the COM library
CoInitialize(NULL);
// get a property store for the video file
IPropertyStore* store = NULL;
SHGetPropertyStoreFromParsingName(L"C:\\Users\\Public\\Videos\\Sample Videos\\Wildlife.wmv",
NULL, GPS_READWRITE, __uuidof(IPropertyStore), (void**)&store);
// get the frame rate
PROPVARIANT variant;
store->GetValue(PKEY_Video_FrameRate, &variant);
int res = variant.intVal;
store->Release();
}
Now, I want to create this method generic, in order to obtain the frameRate of any video. For example, if the method's name is frameRate:
char* path = "C:\\Users\\Public\\Videos\\Sample Videos\\Wildlife.wmv";
int fps = frameRate(path);
Thanks
Does this not work?
int getFrameRate(std::wstring path)
{
// initialize the COM library
CoInitialize(NULL);
// get a property store for the video file
IPropertyStore* store = NULL;
SHGetPropertyStoreFromParsingName(path.c_str(),
NULL, GPS_READWRITE, __uuidof(IPropertyStore), (void**)&store);
// get the frame rate
PROPVARIANT variant;
store->GetValue(PKEY_Video_FrameRate, &variant);
int res = variant.intVal;
store->Release();
return res;
}
The assumption here is that SHGetPropertyStoreFromParsingName takes a string as its first parameter. In C++ I recommend staying away from char*, std::string is preferable in almost all situations. The only difficulty I see is making sure path is the correct type.
If you don't want to recompile your code for every video path, then you can read the path from the program parameters. To do that, modify you main() as follows:
int main(int argc, char* argv[])
{
if (argc != 2)
{
std::cout << "You have to specify the video path!" << std::endl;
return 1;
}
const char* path = arg[1];
// Rest of the program logic
return 0;
}
You can pass more than one parameter, if you want to. Note that there is always at least 1 argument (arg[0] is the program name). For further reading on the topic go here.
#include "opencv2/opencv.hpp"
#pragma comment (lib , "opencv_core244d.lib")
#pragma comment (lib ,"opencv_highgui244d.lib")
#pragma comment(lib , "opencv_imgproc244d.lib")
int main(int argc, char* argv[])
{
CvCapture* capture = cvCaptureFromFile("try.avi");
IplImage* frame = NULL;
do
{
frame = skipNFrames(capture, 1);
cvNamedWindow("frame", CV_WINDOW_AUTOSIZE);
cvShowImage("frame", frame);
cvWaitKey(0);
} while( frame != NULL );
cvReleaseCapture(&capture);
cvDestroyWindow("frame");
cvReleaseImage(&frame);
return 0;
}
This is my program to get frames from the video , but when i run this program , it works , it show me the video , but its not saving the frames automatically (without using any button or mouse) , which should save in my directory
To see each frame of the video individually use cvWaitKey(0). It shows current frame of the video and wait for a key press infinitely. So to see the next frame press a key.
To save each frame individually,
#include<stdio.h>
Declare a global variable
int flag=0;
add following code just below to cvWaitKey(0) :
char *str=new char[50];
flag++;
sprintf(str,"%d",flag);
strcat(str," frame");
strcat(str,".jpg");
Mat image=frame;
imwrite(str,image);
#include"stdafx.h"
#include<cv.h>
#include<highgui.h>
#include<cxcore.h>
int main(int argc, char* argv[]) {
int c=1;
IplImage* img=0;
char buffer[1000];
CvCapture* cv_cap = cvCaptureFromFile("try.avi");
cvNamedWindow("Video",CV_WINDOW_AUTOSIZE);
while(1) {
img=cvQueryFrame(cv_cap);
cvShowImage("Video",img);
sprintf(buffer,"D:/image%u.jpg",c);
cvSaveImage(buffer,img);
c++;
if (cvWaitKey(100)== 27) break;
}
cvDestroyWindow("Video");
return 0;
}
Try this , this will work
You need to use cvSaveImage() to explicitly save each frame.
This should be done in your loop, wherever you want to save the frame.
Obviously, if you want to save each frame with a different name you have to generate different names for each call. #baban shows one way to do it.
In my project, I use to load textures by specifying its file name. Now, I made this function const char* app_dir(std::string fileToAppend); that returns the mains argv[0] and change the application name by the fileToAppend. Since I cannot make the string manipulation easy with a char*, I use the std::string. My texture loader takes a const char* for file name so need to switch back to c_str(), now it generates a sequence of ASCII symbol characters (bug). I already fix the problem by changing the return type of the app_dir() to std::string. But why is that happening?
EDIT
sample code:
//in main I did this
extern std::string app_filepath;
int main(int argc, char** arv) {
app_filepath = argv[0];
//...
}
//on other file
std::string app_filepath;
void remove_exe_name() {
//process the app_filepath to remove the exe name
}
const char* app_dir(std::string fileToAppend) {
string str_app_fp = app_filepath;
return str_app_fp.append(fileToAppend).c_str();
//this is the function the generates the bug
}
I already have the functioning one by changing its return type to std::string as I said earlier.
A big no no :) returning pointer to local objects
return str_app_fp.append(fileToAppend).c_str();
Change your function to
std::string app_dir(const std::string& fileToAppend) {
string str_app_fp = app_filepath + fileToAppend;
return str_app_fp;
}
And on the return value use c_str()
When you using function const char* app_dir(std::string fileToAppend); you get pointer to the memory that allocated on the stack and already deleted when the function ends.
I had a perfectly working OpenCV code (having the function cvCaptureFromCAM(0)). But when I modified it to run in a separate thread, I get this "Video Source" selection dialog box and it asks me to choose the Webcam. Even though I select a cam, it appears that the function cvCaptureFromCAM(0) returns null. I also tried by passing the values 0, -1,1, CV_CAP_ANYto this function. I have a doubt that this dialog box causes this issue. Is there any way to avoid this or does anyone have any other opinion?
I've followed the following posts when debugging:
cvCreateCameraCapture returns null
OpenCV cvCaptureFromCAM returns zero
EDIT
Code structure
//header includes
CvCapture* capture =NULL;
IplImage* frame = NULL;
int main(int argc, char** argv){
DWORD qThreadID;
HANDLE ocvThread = CreateThread(0,0,startOCV, NULL,0, &qThreadID);
initGL(argc, argv);
glutMainLoop();
CloseHandle(ocvThread);
return 0;
}
void initGL(int argc, char** argv){
//Initialize GLUT
//Create the window
//etc
}
DWORD WINAPI startOCV(LPVOID vpParam){
//capture = cvCaptureFromCAM(0); //0 // CV_CAP_ANY
if ((capture = cvCaptureFromCAM(1)) == NULL){ // same as simply using assert(capture)
cerr << "!!! ERROR: vCaptureFromCAM No camera found\n";
return -1;
}
frame = cvQueryFrame(capture);
}
//other GL functions
Thanks.
Since this is a problem that only happens on Windows, an easy fix is to leave cvCaptureFromCAM(0) on the main() thread and then do the image processing stuff on a separate thread, as you intented originally.
Just declare CvCapture* capture = NULL; as a global variable so all your threads can access it.
Solved. I couldn't get rid of the above mentioned dialog box, but I avoided the error by simply duplicating the line capture = cvCaptureFromCAM(0);
capture = cvCaptureFromCAM(0);
capture = cvCaptureFromCAM(0);
It was just random. I suspect it had something to do with behavior of Thread. What's your idea?
Thanks all for contributing.