Writing AVI files in OpenCV - c

There example on the net and code given in Learn OpenCv,Orielly.
After many attempts the out.avi file is written with 0 bytes.
I wonder where i went wrong.
The following are the code i used...
int main(int argc, char* argv[]) {
CvCapture* input = cvCaptureFromFile(argv[1]);
IplImage* image = cvRetrieveFrame(input);
if (!image) {
printf("Unable to read input");
return 0;
}
CvSize imgSize;
imgSize.width = image->width;
imgSize.height = image->height;
double fps = cvGetCaptureProperty(
input,
CV_CAP_PROP_FPS
);
CvVideoWriter *writer = cvCreateVideoWriter(
"out.avi",
CV_FOURCC('M', 'J', 'P', 'G'),
fps,
imgSize
);
IplImage* colourImage;
//Keep processing frames...
for (;;) {
//Get a frame from the input video.
colourImage = cvQueryFrame(input);
cvWriteFrame(writer, colourImage);
}
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&input);
}

My bet is that cvCreateVideoWriter returns NULL. Just step through it to see if it's true. In that case, the problem is probably with CV_FOURCC(..) which doesnt find the codec and force a return 0;
you can try using -1 instead of CV_FOURCC. There is gonna be a prompt during runtime for you to chose the appropriate codec

When i google this problem i meet an answer: "OpenCV on mac os x don`t support avi write until it will be compiled with a ffmpeg"
For me seem to wrok this solution
http://article.gmane.org/gmane.comp.lib.opencv/16005
You need to provide the full path to
the file with the movie in
cvCreateVideoWriter. I don't know
whether it's only an Mac OS X port
issue, but might be, since
QTNewDataReferenceFromFullPathCFString
from the QT backend is used.

hey This code works in DevC++ try it:
#include<cv.h>
#include<highgui.h>
#include<cvaux.h>
#include<cvcam.h>
#include<cxcore.h>
int main()
{
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 5; // or 30
int frameW = 1600; //640; // 744 for firewire cameras
int frameH = 1200; //480; // 480 for firewire cameras
//writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
// fps,cvSize(frameW,frameH),isColor);
writer=cvCreateVideoWriter("out.avi",-1,
fps,cvSize(frameW,frameH),isColor);
IplImage* img = 0;
img=cvLoadImage("CapturedFrame_0.jpg");
cvWriteFrame(writer,img); // add the frame to the file
img=cvLoadImage("CapturedFrame_1.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_2.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_3.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_4.jpg");
cvWriteFrame(writer,img);
img=cvLoadImage("CapturedFrame_5.jpg");
cvWriteFrame(writer,img);
cvReleaseVideoWriter(&writer);
return 0;
}
I compiled it and ran it, works fine.
(I did not see above whether you got your answer or not .. but for this particular thing I worked very hard earlier and suddenly I just did it, from some code snippets.)

It's a codec issue. Try out all the possible codecs (option -1 in cvCreateVideo). In my case Microsoft Video 1 worked well.

Maybe you could try inserting a printf("Frame found\n") inside the for(;;) to see if it is actually capturing frames. Or even better:
if(colourImage == NULL) {
printf("Warning - got NULL colourImage\n");
continue;
}
cvNamedWindow( "test", 1);
cvShowImage( "test", colourImage );
cvWaitKey( 0 );
cvDestroyWindow( "test" );
Then see if you get any windows, and if they contain the right contents.

This code worked fine:
cv.h
highgui.h
cvaux.h
cvcam.h
cxcore.h
int main(){
CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 5; // or 30
IplImage* img = 0;
img=cvLoadImage("animTest_1.bmp");
int frameW = img->width; //640; // 744 for firewire cameras
int frameH = img->height; //480; // 480 for firewire cameras
writer=cvCreateVideoWriter("out.avi",-1,
fps,cvSize(frameW,frameH),1);
cvWriteFrame(writer, img); // add the frame to the file
char *FirstFile,fF[20]="",*fileNoStr,fns[4]="";
fileNoStr=fns;
for(int fileNo;fileNo<100;fileNo++){
FirstFile=fF;
itoa(fileNo,fileNoStr,10);
FirstFile=strcat ( FirstFile,"animTest_");
FirstFile=strcat ( FirstFile,fileNoStr);
FirstFile=strcat ( FirstFile,".bmp");
printf(" \n%s .",FirstFile);
img=cvLoadImage(FirstFile);
cvWriteFrame(writer, img);
}
cvReleaseVideoWriter(&writer);
return 0;
}

I think the problem you're encountering is that your "for" loop never ends; therefore, cvReleaseVideoWriter(&writer); and cvReleaseCapture(&input); never get called. Try something like for(int i=0; i<200; i++) and see if you end up with a working video.
Often video is written to a temporary files before being finalized on disk. If your file isn't finalized, there won't be anything to see.
Hope that helps.

Related

Time/pitchshift in c

I'm fairly new to C. As part of a Uni project, I'm required to put together a programme that processes audio in some form. So, I've decided to make a pitch shifter. So far, I've managed to at least make the program process the audiofile, if not actually alter the sound. I've looked into using samplerate, but from what I've gathered, it won't give me the desired outcome.
I've downloaded and compiled the rubberband library but I'm not really sure where to start using it in conjunction with my work. I was just wondering if anyone has any tips/experience with it, perhaps to achieve similar things?
void shiftsoundfile() {
//Part 1 - File input and reading
SNDFILE *inputsf, *outputsf;
SF_INFO ininfo, outinfo2;
SRC_DATA src_data;
static float datain [BUFFER_LEN];
static float dataout [BUFFER_LEN];
int readfile;
const char *inputsfname = "Scifi.wav";
const char *outputsfname = "Scifi2.wav";
ininfo.format = 0;
if ( !(inputsf = sf_open(inputsfname, SFM_READ, &ininfo)))
if (inputsf != inputsfname)
{
printf("The file could not be opened.\n");
exit(0);
}
outputsf = sf_open (outputsfname, SFM_WRITE, &ininfo);
inputsf = sf_open (inputsfname, SFM_READ, &outinfo2);
//Part 2 - Audio file conversion
//>>SOMETHING NEEDS TO GO HERE TO PERFORM THE CONVERSION<<
//librubberband perhaps, or something along these lines?...
/*float shift [BUFFER_LEN];
int j;
for (j = 0; j < readfile; j++) {
shift [j] = datain [j]; }
for (j = 0; j < readfile; j++) {
datain [j] = shift [j]; }*/ //?
//Part 3 - Outputting the new audio file
while (readfile = sf_read_float (inputsf, datain, BUFFER_LEN))
{
sf_write_float (outputsf, datain, BUFFER_LEN);
//Write's the data in the array, pointed to by outputsf, to the file
}
sf_close (inputsf); //closes the 'osf' function
sf_close (outputsf); //closes the 'csf' function

Pixel manipulation using sdl

I am trying to manipulate pixel using sdl and manage to read them up now. Below is my sample code. When I print I this printf("\npixelvalue is is : %d",MyPixel); I get values like this
11275780
11275776
etc
I know these are not in hex form but how to manipulate say I want to filter just the blue colors out? Secondly after manipulation how to generate the new image?
#include "SDL.h"
int main( int argc, char* argv[] )
{
SDL_Surface *screen, *image;
SDL_Event event;
Uint8 *keys;
int done = 0;
if (SDL_Init(SDL_INIT_VIDEO) == -1)
{
printf("Can't init SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
SDL_WM_SetCaption("sample1", "app.ico");
/* obtain the SDL surfance of the video card */
screen = SDL_SetVideoMode(640, 480, 24, SDL_HWSURFACE);
if (screen == NULL)
{
printf("Can't set video mode: %s\n", SDL_GetError());
exit(1);
}
printf("Loading here");
/* load BMP file */
image = SDL_LoadBMP("testa.bmp");
Uint32* pixels = (Uint32*)image->pixels;
int width = image->w;
int height = image->h;
printf("Widts is : %d",image->w);
for(int iH = 1; iH<=height; iH++)
for(int iW = 1; iW<=width; iW++)
{
printf("\nIh is : %d",iH);
printf("\nIw is : %d",iW);
Uint32* MyPixel = pixels + ( (iH-1) + image->w ) + iW;
printf("\npixelvalue is is : %d",MyPixel);
}
if (image == NULL) {
printf("Can't load image of tux: %s\n", SDL_GetError());
exit(1);
}
/* Blit image to the video surface */
SDL_BlitSurface(image, NULL, screen, NULL);
SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
/* free the image if it is no longer needed */
SDL_FreeSurface(image);
/* process the keyboard event */
while (!done)
{
// Poll input queue, run keyboard loop
while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_QUIT )
{
done = 1;
break;
}
}
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_q])
{
done = 1;
}
// Release CPU for others
SDL_Delay(100);
}
// Release memeory and Quit SDL
SDL_FreeSurface(screen);
SDL_Quit();
return 0;
}
Use SDL_MapRGB and SDL_MapRGBA to sort colors out. SDL will filter it out for you, based on surface format.
Just like this:
Uint32 rawpixel = getpixel(surface, x, y);
Uint8 red, green, blue;
SDL_GetRGB(rawpixel, surface->format, &red, &green, &blue);
You are printing the value of the pointer MyPixel. To get the value you have to dereference the pointer to the pixel value like this: *MyPixel
Then the printf would look like this:
printf("\npixelvalue is : %d and the address of that pixel is: %p\n",*MyPixel , MyPixel);
Other errors:
Your for loops are incorrect. You should loop from 0 to less than width or height, or else you will read uninitialized memory.
You didn't lock the surface. Although you are only reading the pixels and nothing should go wrong it is still not correct.
Test for correctness if the image pointer comes after you are already using the pointer. Put the test right after the initialization.
If I recall correctly I used sdl_gfx for pixel manipulation.
It also contains function like drawing a circle, oval etc.

I want to display output image in different windows in OpenCV

I want to display the same image multiple times in different windows, for which I have used a for loop but I am getting only one window display. Can anybody provide me any suggestion on how to display output images in multiple windows? Following is the code in OpenCV with C API. Here, I am simply loading an image from argv[1] and trying to display it in 4 different windows.
#include "cv.h"
#include "highgui.h"
#include <stdlib.h>
#include <stdio.h>
int main( int argc, char** argv ) {
int i;
IplImage* img = cvLoadImage( argv[1],1);
cvMoveWindow("Example1", 100, 100);
cvNamedWindow( "Example1", 1);
for(i =0; i<=4;i++) // for loop to display the same image in 4 different windows
{
cvShowImage( "Example1", img );
}
cvWaitKey(0);
cvReleaseImage( &img );
cvDestroyWindow( "Example1" );
}
P.S. I have asked a similar question show multiple images in different window in OpenCV before which was not solved and the code was difficult to understand so I am trying this question with a simpler code.
Here you go
int i;
IplImage* img = cvLoadImage("/home/khashayar/Downloads/bug14.png", 1);
cvMoveWindow("Example1", 100, 100);
cvNamedWindow("Example1", 1);
for (i = 0; i <= 4; i++)
{
char str[5] = "test";
str[4] = i+48;
cvShowImage(str, img);
}
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("Example1");
for(i =0; i<=4;i++) // hmm, i<=4 will actually run 5 times ...
{
cvShowImage( "Example1", img ); // <-- same window name for all == only 1 shown
}
but, please discard the c api and use c++ !. please !
#include "opencv2/opencv.hpp"
int main( int argc, char** argv ) {
cv::Mat img = cv::imread( argv[1],1);
for( int i=0; i<4; i++ ) // for loop to display the same image in 4 different windows
{
cv::String name = cv::format("Example%d",i);
cv::namedWindow( name, 1);
cv::imshow( name, img );
}
cv::waitKey(0);
}

Opencv Capture Causes Memory Allocation Error

I have implemented a capture code runs on OpenCV libraries. Code captures from 2 cameras order by order. But the code causes memory allocation error after a while.
I have to release a capture stream of camera1 to open a capture stream of camera2. I could not able to get two capture simultanously so I have to capture it order by order.
Why it couses memory allocation error in this scenario?
My code is located below:
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#include <stdio.h>
CvCapture* camera; // Use the default camera
IplImage* frame;
int main(int argc, char* argv[])
{
while(1)
{
camera = cvCreateCameraCapture(0); // Use the default camera
//camera2 = cvCreateCameraCapture(1); // Use the default camera
frame = 0;
//frame2 = 0;
cvSetCaptureProperty(camera,CV_CAP_PROP_FRAME_WIDTH,1024) ;
cvSetCaptureProperty(camera,CV_CAP_PROP_FRAME_HEIGHT,768);
frame = cvQueryFrame(camera); //need to capture at least one extra frame
if (frame != NULL) {
printf("Frame extracted from CAM1\n\r");
cvSaveImage("/dev/shm/webcam1.jpg", frame,0);
printf("Frame from CAM1 saved\n\r");
} else {
printf("Null frame 1\n\r");
}
cvReleaseImage(&frame);
cvReleaseCapture(&camera);
camera = cvCreateCameraCapture(1); // Use the default camera
cvSetCaptureProperty(camera,CV_CAP_PROP_FRAME_WIDTH,1024) ;
cvSetCaptureProperty(camera,CV_CAP_PROP_FRAME_HEIGHT,768);
frame = cvQueryFrame(camera); //need to capture at least one extra frame
if (frame != NULL) {
printf("Frame extracted from CAM2\n\r");
cvSaveImage("/dev/shm/webcam2.jpg", frame,0);
printf("Frame from CAM2 saved\n\r");
} else {
printf("Null frame 2\n\r");
}
cvReleaseImage(&frame);
cvReleaseCapture(&camera);
}
First of all, you can start declaring out of while() statement the cameraCapture:
camera0 = cvCreateCameraCapture(0);
camera1 = cvCreateCameraCapture(1);
frame0 = 0;
frame1 = 0;
cvSetCaptureProperty(camera0,CV_CAP_PROP_FRAME_WIDTH,1024) ;
cvSetCaptureProperty(camera0,CV_CAP_PROP_FRAME_HEIGHT,768);
cvSetCaptureProperty(camera1,CV_CAP_PROP_FRAME_WIDTH,1024) ;
cvSetCaptureProperty(camera1,CV_CAP_PROP_FRAME_HEIGHT,768);
while(1) {
/* your operation */
frame0 = cvQueryFrame(camera0);
frame1 = cvQueryFrame(camera1);
/* your operation */
}
cvReleaseImage(&frame0);
cvReleaseImage(&frame1);
cvReleaseCapture(&camera0);
cvReleaseCapture(&camera1);
Edit
If you want to take first stream from A-cam and then from B-cam, you'll have a code like the this. I don't understand exactly what do you want to do, so this code simply show your stream on a window.
Remember to use cvWaitKey(...) in order to give to highgui time to process the draw requests from cvShowImage().
Also, take a look at the documentation of cvSetCaptureProperty: here is written that currently the function supports only video files:
CV_CAP_PROP_POS_MSEC;
CV_CAP_PROP_POS_FRAMES;
CV_CAP_PROP_POS_AVI_RATIO.
By the way, this is my suggest:
const char* wndName = "window";
cvNamedWindow(wndName, CV_WINDOW_NORMAL);
IplImage* frame;
CvCapture* capture;
while(true) {
capture = cvCaptureFromCAM(0);
/* Showing for a while capture in window */
while(/* your condition */) {
frame = cvQueryFrame(capture);
/* operation with A cam */
cvShowImage(wndName, frame);
cvWaitKey(30);
}
cvReleaseCapture(&capture);
cvWaitKey(100);
/* switching source cam */
capture = cvCaptureFromCAM(1);
/* Showing for a while capture in the same window */
while(/* your condition */) {
frame = cvQueryFrame(capture);
/* operation with B cam */
cvShowImage(wndName, frame);
cvWaitKey(30);
}
}
cvReleaseImage(&frame);
cvReleaseCapture(&capture);
This works for me, give me any feedback.

SDL: Unable to flip multiple surfaces

I've been trying to flip surfaces and have been successful if I'm only flipping a single surface (the same surface I got back from SDL_SetVideoMode). If I try to flip the surface I get back from SDL_DisplayFormat, nothing happens. I've attached demo code that demonstrates my problem:
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *mysurface1;
SDL_Surface *mysurface2;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
mysurface1 = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface1->pixels + i*mysurface1->pitch + i;
*pxl = 100; // Red Line
}
SDL_Flip(mysurface1); // Works, we see a red line
sleep(5);
printf("Sleeping for 5...\n");
mysurface2 = SDL_DisplayFormat(mysurface1);
for (i = 0; i < 20; i++)
{
pxl = (char *)mysurface2->pixels + i*mysurface2->pitch + i;
*pxl = 255; // White line
}
SDL_Flip(mysurface2); // White line doesnt appear
printf("Done... No white line\n");
sleep(10);
}
Has anyone ever seen this before? Again, I think I tracked it down to surfaces that wont display if its a surface I got back from SDL_DisplayFormat. If I do it on the surface I get back from SDL_SetVideoMode, then I see the red line and everything works fine.
You can only flip the main display surface (the one created with SDL_SetVideoMode). In order to make your other surface visible, you need to blit it onto the main surface. Lookup SDL_BlitSurface for details on how to do that.
Pass the screen to the SDL_Flip function. The flip function modifies the value of screen->pixels so that it points to the surface that isn't visible on the screen.
However, this is only applicable to video devices such as SVGA and DGA. On X11, calling SDL_Flip(screen) is equivalent to calling SDL_UpdateRect(screen, 0, 0, 0, 0).
#include <stdio.h>
#include <stdlib.h>
#include "SDL/SDL.h"
void main()
{
int i;
SDL_Surface *screen;
char *pxl;
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 8, SDL_DOUBLEBUF|SDL_HWSURFACE );
printf("Drawing the red line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 100; // Red Line
}
printf("Flip screens\n");
SDL_Flip(screen); // Display the red line
printf("Drawing the white line ...\n");
printf("screen->pixels = %p\n", screen->pixels);
for (i = 0; i < 100; i++)
{
pxl = (char *)screen->pixels + i*screen->pitch + i;
*pxl = 255; // White line
}
sleep(3);
printf("Flip screens\n");
SDL_Flip(screen); // Display the white line
sleep(10);
}
On my Linux notebook, this prints:
Drawing the red line ...
screen->pixels = 0xb6c8c008
Flip screens
Drawing the white line ...
screen->pixels = 0xb6c8c008
Flip screens
The value of screen->pixels is the same, but this is only because on X11 the flip operation is a no-operation. On a video device such as SVGA or DGA, the two values would be different.
First, it seems SDL_Flip() only works on surfaces that correspond to the screen or a window, like those created by SDL_SetVideoMode(). Your other surface is off-screen; it doesn't make much sense to double-buffer it (or flip it), and it most likely isn't double-buffered anyway. Being an off screen surface, it won't appear until you blit it to your display surface with SDL_BlitSurface() or a similar function -- then, the changes will be visible next time you flip the display surface.
Essentially, mysurface2 isn't actually on your display until you put it there, by blitting it onto a surface that is on your display. If you replace the following:
SDL_Flip(mysurface2); // White line doesnt appear
With this:
SDL_BlitSurface(mysurface2,NULL,mysurface1,NULL);
SDL_Flip(mysurface1);
...then your code will probably work as you expect.

Resources