OpenCV:如何从以太网相机捕获帧

时间:2012-06-13 06:39:58

标签: c++ opencv ethernet ip-camera

我之前编写过USB网络摄像头,其唯一目的是从摄像头获取实时帧并在窗口中显示。我为此目的使用了cvCaptureFromCAM,它适用于USB Camera(请参阅下面的代码)。

我想知道如何从千兆以太网相机中捕获帧?我想我需要使用一些API从一些默认IP地址捕获帧。有人能指出我正确的方向吗?

我将在Intel i3处理器上的Windows 7上使用C ++和OpenCV。

#include "cv.h"
#include "highgui.h"
#include <stdio.h>

// A Simple Camera Capture Framework 
int main() {
    CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
    if ( !capture ) {
        fprintf( stderr, "ERROR: capture is NULL \n" );
        getchar();
        return -1;
    }

    // Create a window in which the captured images will be presented
    cvNamedWindow( "mywindow", CV_WINDOW_AUTOSIZE );

    // Show the image captured from the camera in the window and repeat
    while ( 1 ) {
        // Get one frame
        IplImage* frame = cvQueryFrame( capture );

        if ( !frame ) {
            fprintf( stderr, "ERROR: frame is null...\n" );
            getchar();
            break;
        }

        cvShowImage( "mywindow", frame );

        // Do not release the frame!
        // If ESC key pressed, Key=0x10001B under OpenCV 0.9.7(linux version),
        // remove higher bits using AND operator
        if ( (cvWaitKey(10) & 255) == 27 ) break;
    }

    // Release the capture device housekeeping
    cvReleaseCapture( &capture );
    cvDestroyWindow( "mywindow" );
    return 0;
}

更新

所以现在我可以在供应商提供的软件GUI中显示实时图像。但我仍然希望使用相机的IP地址显示图像(可能还有视频)。

当我知道摄像机的IP地址时,为什么我无法访问摄像机发送的数据(图像)并在浏览器上显示?我尝试在我的浏览器(192.169.2.4)上键入摄像机的IP地址(即192.169.2.3),但它说“找不到页面”。这是什么意思?

3 个答案:

答案 0 :(得分:7)

您可以使用genIcam API执行此操作。 genIcam是相机的通用接口(USB,GigE,CameraLink等)。它由多个模块组成,但您最关心的是GenTL(传输层)。您可以阅读有关GenTL文档HERE的更多信息。为了简化流程,我建议使用Basler API或Baumer API,它们是GenTL消费者(生产者和消费者在GenTL文档中有描述)。我使用了堡盟API,但两者都有效。

注意:我正在使用堡盟HXG20单声道相机。

可以下载和安装

  1. Visual Studios社区版(我使用2015年LINK
  2. 堡盟GAPI SDK,LINK
  3. openCV(这是一个为c ++构建openCV 3的youtube教程)HERE
  4. 使用CAMERA EXPLORER测试相机

    最好通过使用Camera Explorer程序检查您的网络接口卡(NIC)和GigE相机是否正常工作并使用相机。您可能需要在NIC上启用Jumbo Packets。您也可以使用IPconfig程序配置摄像机IP。我使用DHCP设置,但您也可以为相机和NIC使用静态IP。

    设置可视化工作室

    Baumer GAPI SDK程序员指南(第4章)介绍了设置系统环境变量和配置Visual Studio的步骤,该指南位于以下目录中

    C:\Program Files\Baumer\Baumer GAPI SDK\Docs\Programmers_Guide

    • 检查您是否具有以下系统变量(如果使用64位版本),或者根据需要创建变量(请参阅程序员指南中的第4.3.1节)。

      • name = GENICAM_GENTL64_PATH
      • value = C:\Program Files\Baumer\Baumer GAPI SDK\Components\Bin\x64\
    • 在visual Studios中,创建一个新的C ++项目并更新以下属性(请参阅程序员指南中的第4.4.1节)。

      • C / C ++&gt;一般&gt;其他包含目录= C:\Program Files\Baumer\Baumer GAPI SDK\Components\Dev\C++\Inc
      • 链接器&gt;一般&gt;其他图书馆馆长= C:\Program Files\Baumer\Baumer GAPI SDK\Components\Dev\C++\Lib\x64
      • 链接器&gt;输入&gt;其他依赖关系= bgapi2_genicam.lib
      • 构建活动&gt;构建后事件&gt;命令行= copy "C:\Program Files\Baumer\Baumer GAPI SDK\Components\Bin\x64"\*.* .\

    创建.CPP文件以在OPENCV窗口中显示图像流

    最简单的入门方法是使用堡盟GAPI SDK中提供的示例代码之一并对其进行修改以添加openCV功能。要使用的示例代码是005_PixelTransformation,它位于此处

    C:\Program Files\Baumer\Baumer GAPI SDK\Components\Examples\C++\src\0_Common\005_PixelTransformation

    将此.cpp文件复制并粘贴到项目源目录中,并确保可以构建和编译。它应该捕获8个图像,并从每个图像的前6行打印出前6个像素值。

    将这些#include语句添加到.cpp源文件中:

    #include <opencv2\core\core.hpp>
    #include <opencv2\highgui\highgui.hpp>
    #include <opencv2\video\video.hpp>
    

    main()函数

    的开头添加这些变量声明
    // OPENCV VARIABLE DECLARATIONS
    cv::VideoWriter cvVideoCreator;                 // Create OpenCV video creator
    cv::Mat openCvImage;                            // create an OpenCV image
    cv::String videoFileName = "openCvVideo.avi";   // Define video filename
    cv::Size frameSize = cv::Size(2048, 1088);      // Define video frame size (frame width x height)
    cvVideoCreator.open(videoFileName, CV_FOURCC('D', 'I', 'V', 'X'), 20, frameSize, true); // set the codec type and frame rate
    

    在原始的005_PixelTransformation.cpp文件中,第569行有一个for循环,循环超过8个图像,即for(int i = 0; i < 8; i++)。我们想要改变它以持续运行。我这样做是通过将其更改为while循环来说明

    while (pDataStream->GetIsGrabbing())
    

    在我们新的while循环中,有一个if语句,用于检查Pixel格式是否为“Mono”(灰度)或颜色。在原始文件中,它从第619行开始,到692结束。在ifelse语句括号关闭之后,在pImage->Release();语句之前,我们需要添加openCV将图像显示到窗口的部分。添加以下代码行

    }   // This is the closing brace for the 'else color' statement 
    
    // OPEN CV STUFF
    openCvImage = cv::Mat(pTransformImage->GetHeight(), pTransformImage->GetWidth(), CV_8U, (int *)pTransformImage->GetBuffer());
    
    // create OpenCV window ----
    cv::namedWindow("OpenCV window: Cam", CV_WINDOW_NORMAL);
    
    //display the current image in the window ----
    cv::imshow("OpenCV window : Cam", openCvImage);
    cv::waitKey(1);
    

    需要注意的一点是openCvImage对象中的像素格式。我的相机是单声道8位,所以我需要指定CV_8U。如果您的相机是RGB或10位像素,则需要提供正确的格式(请参阅openCV文档HERE)。

    您可以参考调整相机参数的其他示例。

    现在一旦你构建和编译,你应该打开一个openCV窗口,显示相机图像!

    为了更多人的投票而大吵大闹!!!! (这需要花很多时间才能开始工作,所以请联系我!)

    THUMBS UP FOR MORE UP VOTES!!!!!

答案 1 :(得分:3)

如果没有运行Web服务器,您将无法访问相机上的图像(检查其doco)。 尝试在命令提示符下键入:

telnet 192.169.2.3 80

如果telnet超时,则相机未在默认端口80上运行服务器。

另请参阅此问题:C++ code Capturing image from IP / Ethernet Cameras (AXIS Cam)

答案 2 :(得分:0)

添加到mark jay的答案(我可以使用堡盟-GAPI2 2.8.1和VC10编译器以及堡盟TXG06摄像机确认在Win32程序中的Win7x64上工作)。如果相机设置为抓取Mono8并且您打算抓取相同格式CV_8UC1的图像,那么在005_PixelTransformation.cpp示例中,您可以避免创建BGAPI2::Image* pTransformImageBGAPI2::Image* pImage一起使用缓冲区内存指针构建cv::Mat,如下面GigE_cam类的摘录:

bool GigE_cam::operator>>(cv::Mat& out_mat)
{
    bool success(false);
    try
    {
        _p_buffer_filled = _p_data_stream->GetFilledBuffer(static_cast<bo_uint64>(_timeout_ms));
        if(_p_buffer_filled != 0)
        {
            if(_p_buffer_filled->GetIsIncomplete())
            {
                _p_buffer_filled->QueueBuffer();
            }
            else
            {
                if(_p_buffer_filled->GetPixelFormat() == "Mono8")
                {
                    _image_out_buffer = cv::Mat(static_cast<int>(_p_buffer_filled->GetHeight()), 
                                                static_cast<int>(_p_buffer_filled->GetWidth()), 
                                                CV_8UC1, 
                                                static_cast<uchar*>(_p_buffer_filled->GetMemPtr()));
                    if(_image_out_buffer.data)
                    {
                        _image_out_buffer.copyTo(out_mat);
                        success = true;
                    }
                }
                else if(_p_buffer_filled->GetPixelFormat() == "Mono10")
                {
                    // Todo transform to BGR8 etc. not implemented
                }
                _p_buffer_filled->QueueBuffer(); // Queue buffer after use
            }
        }   
    }
    catch(BGAPI2::Exceptions::IException& ex)
    {
        _last_BGAPI2_error_str = ex.GetType();
    }
    return success;
}

此代码以66.5 fps的速度从相机(776 X 582像素)获取全帧,即使数据表仅声称64.0 fps。我很想知道他们的API在Debian上的行为是否相同。

Incoming Image