OpenCV:如何在Windows窗体应用程序中显示网络摄像头捕获的图像?

6

通常我们使用以下方式在OpenCV窗口中显示网络摄像头或视频运动:

      CvCapture* capture = cvCreateCameraCapture(0);
            cvNamedWindow( "title", CV_WINDOW_AUTOSIZE );
   cvMoveWindow("title",x,y);
   while(1) 
   {
    frame = cvQueryFrame( capture );
    if( !frame )
    {
     break;
    }
    cvShowImage( "title", frame );
    char c = cvWaitKey(33);
    if( c == 27 )
    {
     break;
    }
   }

我尝试使用pictureBox在Windows窗体中显示图像,成功的代码如下:
 pictureBox1->Image = gcnew System::Drawing::Bitmap( image->width,image->height,image->widthStep,System::Drawing::Imaging::PixelFormat::Undefined, ( System::IntPtr ) image-> imageData);

但是当我尝试从视频中显示捕获的图像时,它无法正常工作,这里是源代码:

            CvCapture* capture = cvCreateCameraCapture(0);
   while(1) 
   {
    frame = cvQueryFrame( capture );
    if( !frame )
    {
     break;
    }
    pictureBox1->Image = gcnew System::Drawing::Bitmap( frame->width,frame->height,frame->widthStep,System::Drawing::Imaging::PixelFormat::Undefined, ( System::IntPtr ) frame-> imageData);
    char c = cvWaitKey(33);
    if( c == 27 )
    {
     break;
    }
   }

有没有办法使用Windows窗体来显示视频或网络摄像头,而不是使用OpenCV窗口?

还是我的代码有问题吗? 谢谢你的帮助.. :)

4个回答

2
建议:使用VideoInput而不是CvCapture(CvCapture是highgui库的一部分,不适用于生产环境,仅用于快速测试)。是的,VideoInput主页看起来很奇怪,但该库非常值得使用。
这里是一个快速示例,展示如何使用VideoInput(从VideoInput.h文件中提取):
//create a videoInput object
videoInput VI;

//Prints out a list of available devices and returns num of devices found
int numDevices = VI.listDevices();  

int device1 = 0;  //this could be any deviceID that shows up in listDevices
int device2 = 1;  //this could be any deviceID that shows up in listDevices

//if you want to capture at a different frame rate (default is 30) 
//specify it here, you are not guaranteed to get this fps though.
//VI.setIdealFramerate(dev, 60);    

//setup the first device - there are a number of options:

VI.setupDevice(device1);                          //setup the first device with the default settings
//VI.setupDevice(device1, VI_COMPOSITE);              //or setup device with specific connection type
//VI.setupDevice(device1, 320, 240);                  //or setup device with specified video size
//VI.setupDevice(device1, 320, 240, VI_COMPOSITE);  //or setup device with video size and connection type

//VI.setFormat(device1, VI_NTSC_M);                 //if your card doesn't remember what format it should be
                                                    //call this with the appropriate format listed above
                                                    //NOTE: must be called after setupDevice!

//optionally setup a second (or third, fourth ...) device - same options as above
VI.setupDevice(device2);                          

//As requested width and height can not always be accomodated
//make sure to check the size once the device is setup

int width   = VI.getWidth(device1);
int height  = VI.getHeight(device1);
int size    = VI.getSize(device1);

unsigned char * yourBuffer1 = new unsigned char[size];
unsigned char * yourBuffer2 = new unsigned char[size];

//to get the data from the device first check if the data is new
if(VI.isFrameNew(device1)){
    VI.getPixels(device1, yourBuffer1, false, false);   //fills pixels as a BGR (for openCV) unsigned char array - no flipping
    VI.getPixels(device1, yourBuffer2, true, true);     //fills pixels as a RGB (for openGL) unsigned char array - flipping!
}

//same applies to device2 etc

//to get a settings dialog for the device
VI.showSettingsWindow(device1);


//Shut down devices properly
VI.stopDevice(device1);
VI.stopDevice(device2);

同时进行视频输出和背景图像处理对同一信息的性能有显著影响吗? - Aggelos Biboudis
不确定我是否正确理解了您的问题。据我所记,抓取的图像并没有直接复制到屏幕缓冲区中。然而,VideoInput是基于DirectShow的,这意味着两件事:它非常快,并且编译起来很麻烦(您需要从微软获取相应的DirectShow实现)。上次我尝试时,我必须获取一个旧版本的DirectShow库。但是,下载中提供了VideoInput库的已编译版本。 - Pascal T.

1

当你从相机中捕获图像时,应该知道像素格式,很可能是24位BGR格式。 System::Drawing::Imaging::PixelFormat::Format24bppRgb 是最接近的格式,但你可能会得到奇怪的颜色显示。重新排列颜色分量将解决此问题。

实际上,这里有可用的.NET版本OpenCV库: http://code.google.com/p/opencvdotnet/ 和这里: http://www.emgu.com/wiki/index.php/Main_Page

希望能帮到你!


1
我不知道你是否会喜欢这个,但是你可以使用OpenGL在除了OpenCV提供的窗口之外的其他窗口中显示视频流。(捕获帧并在矩形上显示它...或者类似的东西..)

0

你可能想考虑另一种选择,即使用emgu。这是一个带有winforms控件的opencv .Net封装。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接