PDA

View Full Version : read webcam with opencv



rodolfo.marques
22nd January 2012, 01:37
Hello!

I've trying to set just a really simple program to make sure my OpenCV installation is working properly. The idea is simple get the frames from my webcam and show them.

I made a code that is able to load an image from a directory and i also have a code that uses the opencv to get the images from the webcam and show them with the opencv highgui. I already figured out that i need to convert the IplImage to the QImage so i also managed to find a function that does the conversion between formats. What i did was this:



QImage* IplImage2QImage(IplImage *iplImg)
{
int h = iplImg->height;
int w = iplImg->width;
int channels = iplImg->nChannels;
QImage *qimg = new QImage(w, h, QImage::Format_ARGB32);
char *data = iplImg->imageData;

for (int y = 0; y < h; y++, data += iplImg->widthStep) {
for (int x = 0; x < w; x++) {
char r, g, b, a = 0;

if (channels == 1) {
r = data[x * channels];
g = data[x * channels];
b = data[x * channels]; }
else if (channels == 3 || channels == 4) {
r = data[x * channels + 2];
g = data[x * channels + 1];
b = data[x * channels]; }

if (channels == 4) {
a = data[x * channels + 3];
qimg->setPixel(x, y, qRgba(r, g, b, a)); }
else {
qimg->setPixel(x, y, qRgb(r, g, b)); }
}
}
return qimg;
}

int main(int argc, char *argv[])
{
IplImage* frame;
CvCapture* capture;
QImage* myImage;
QLabel myLabel;

QApplication a(argc, argv);

capture = cvCreateCameraCapture(1);

while(1) {
frame = cvQueryFrame(capture);
myImage = IplImage2QImage(frame);

myLabel.setPixmap(QPixmap::fromImage(*myImage));
myLabel.show(); }

cvReleaseCapture(&capture);
return a.exec();
}


it builds without any error but when i run it i only get this:
7300

i also checked THIS (http://www.qtcentre.org/threads/46583-How-to-Display-Multi-Webcam-with-QT-OpenCV-Eclipse) post and from it i assumed that only using openCV i should also be able to get the output of the webcam (i rewritten the code only for one web)



int main( int argc, char *argv[] )
{
CvCapture *capture = 0;
IplImage *frame = 0;
int key = 0;

/* initialize camera */
capture = cvCaptureFromCAM( 0 );

/* always check */
if ( !capture ) {
fprintf( stderr, "Cannot open initialize webcam!\n" );
return 1; }

cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);

cvSetCaptureProperty(capture, CV_CAP_PROP_FPS, 8);

/* create a window for the video */
cvNamedWindow( "result", CV_WINDOW_AUTOSIZE );

while( key != 'q' ) {
/* get a frame */
frame = cvQueryFrame( capture );

/* always check */
if( !frame ) break;

/* display current frame */
cvShowImage("Left", frame);

/* exit if user press 'q' */
key = cvWaitKey( 1 ); }

/* free memory */
cvDestroyWindow( "result" );
cvReleaseCapture( &capture );
return 0;
}


and i get exactly the same results. no errors when built and the a similar cmd window as the previous picture...

can someone give me a hint on what is wrong in either of the codes and why i'm not getting the images from the webcam?
many thanks

ChrisW67
22nd January 2012, 22:29
First program:
The fundamental problem from a Qt viewpoint is that your code never reaches the Qt event loop, i.e. the a.exec() call, and therefore Qt is not functioning. QWidget::show() schedules the widget to be displayed when the event loop is functioning: it does not show it immediately.

Aside from that, you code leaks memory, line 6, such that it would probably not run for long before crashing out of memory or at least thrashing the machine's virtual memory.

Second program:
You create a named window "result" to display the frames, and then cvShowImage targeting a window called "Left".

rodolfo.marques
22nd January 2012, 23:16
thanks a lot!

well i changed the window name in the second program but it still does the same...

and regarding the first program, what do you advise then? removing the "while(1)" loop or extending it until the "return a.exec()" ?

ChrisW67
22nd January 2012, 23:56
The problem in the second program is entirely between you and OpenCV, nothing to do with Qt. I cannot offer much help.

First program: Neither. The looping behaviour needs to be replaced with event driven behaviour. It doesn't belong in the main() function. Try plugging your code into something like the framework below. Also, have your conversion function return the QImage by value rather than using the heap.


#include <QtGui>
#include <QDebug>

class MainWindow: public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *p = 0): QMainWindow(p) {
QLabel *label = new QLabel(this);
setCentralWidget(label);

// setup OpenCv

connect(&timer, SIGNAL(timeout()), SLOT(capture()));
timer.setInterval(200); // about 5 times per second
timer.start();
}
~MainWindow() {
// tear down OpenCv
}
public slots:
void capture() {
// capture, convert and display image on label
qDebug() << "Capturing";
}

private:
QLabel *label;
QTimer timer;
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

MainWindow m;
m.show();
return app.exec();
}
#include "main.moc"

You can adjust the "sampling" rate or use a single shot timer to run as-fast-as-possible, but most video sources will produce a frame every 30th or 25th of a second.

MrShahi
23rd January 2012, 06:38
Hi ,
I have made an application using opencv for webcam
I put here some of mine code , i hope it will help you
/***********************************/
//first you make a dummy image
QImage dummy(100,100,QImage::Format_RGB32);
image = dummy;
for (int x = 0; x < 100; x ++) {
for (int y =0; y < 100; y++) {
image.setPixel(x,y,qRgb(x, y, y));
}
}

//start a timer to capture frame of your webcam

pCamraTimer = new QTimer(this);
connect(pCamraTimer,SIGNAL(timeout()),this,SLOT(st artCapture()));
//In slot start capture

void WebCamViewer::startCapture()
{
if(NULL != camera)
{
IplImage *image=cvQueryFrame(camera);
putImage(image);
}
}
void WebCamViewer::putImage(IplImage *cvimage)
{
int cvIndex, cvLineStart;
// switch between bit depths
switch (cvimage->depth) {
case IPL_DEPTH_8U:
switch (cvimage->nChannels) {
case 3:
if ( (cvimage->width != image.width()) || (cvimage->height != image.height()) ) {
QImage temp(cvimage->width, cvimage->height, QImage::Format_RGB32);
image = temp;
}
cvIndex = 0; cvLineStart = 0;
for (int y = 0; y < cvimage->height; y++) {
unsigned char red,green,blue;
cvIndex = cvLineStart;
for (int x = 0; x < cvimage->width; x++) {
// DO it
red = cvimage->imageData[cvIndex+2];
green = cvimage->imageData[cvIndex+1];
blue = cvimage->imageData[cvIndex+0];

image.setPixel(x,y,qRgb(red, green, blue));
cvIndex += 3;
}
cvLineStart += cvimage->widthStep;
}
break;
default:
printf("This number of channels is not supported\n");
break;
}
break;
default:
printf("This type of IplImage is not implemented in QOpenCVWidget\n");
break;
}

//set this image to your label to show
ui->imgLbl->setPixmap(QPixmap::fromImage(image.scaled(ui->imgLbl->size(),Qt::KeepAspectRatio,Qt::SmoothTransformatio n)));
}

/***********************************/

study24816
1st July 2012, 08:30
Thanks you all for some good guides around here!

I've tried to implement with these and found some problems:
+ the framework of ChrisW67 is good but in OpenCV, the SLOT capture() needs to hold an object Videocapture (an OpenCV class) to avoid repeating creating this class inside SLOT capture() -> by now, I still don't know how to work around this

Besides, I work with both Qt and OpenCV new versions Qt 4 and OpenCV 2.3.1 respectively and I had to do some editings to recode your ideas

** Solution:
I've just found it:
+ create a class variable VideoCapture cap
+ open it in class constructor with cap.Open(0) // default device
+ then, it can be used in SLOT without having to pass this 'cap' variable around

=> DONE already !! thanks all!