【问题标题】:OpenCV: How to capture frames from an Ethernet cameraOpenCV:如何从以太网摄像机捕获帧
【发布时间】:2012-06-16 02:10:13
【问题描述】:

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

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

我将在英特尔 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),但显示“找不到页面”。这是什么意思?

【问题讨论】:

标签: c++ opencv ethernet ip-camera


【解决方案1】:

您可以使用 genIcam API 做到这一点。 genIcam 是相机的通用接口(USB、GigE、CameraLink 等)。它由多个模块组成,但我们将专注于 GenTL(传输层)。你可以阅读更多关于 GenTL 文档HERE。我建议使用作为 GenTL 消费者的 Basler API 或 Baumer API(生产者和消费者在 GenTL 文档中进行了描述)。我使用了 Baumer API,但两者都应该可以工作。

注意:我使用的是堡盟 HXG20 单声道。

要下载和安装的东西

  1. Visual Studios 社区版(我用的是 2015 LINK
  2. 堡盟 GAPI SDK,LINK
  3. openCV(这里是为 c++ 构建 openCV 3 的 youtube 教程)HERE

使用 CAMERA EXPLORER 测试相机

最好在 Camera Explorer 程序中验证您的网络接口卡 (NIC) 和相机是否正常工作和玩耍。您可能需要在 NIC 上启用巨型数据包。您也可以使用 IPconfig 程序配置摄像机 IP(DHCP 或静态 IP)。

设置视觉工作室

堡盟 GAPI SDK 程序员指南(第 4 章)中介绍了设置环境变量和配置 Visual Studio,位于以下目录中

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

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

  • 名称 = GENICAM_GENTL64_PATH

  • 值 = C:\Program Files\Baumer\Baumer GAPI SDK\Components\Bin\x64\

  • 在 Visual Studios 中,创建一个新的 C++ 项目并更新以下属性(请参阅程序员指南中的第 4.4.1 节)。

  • C/C++ > 常规 > 附加包含目录 = C:\Program Files\Baumer\Baumer GAPI SDK\Components\Dev\C++\Inc

  • 链接器 > 常规 > 附加库目录 = C:\Program Files\Baumer\Baumer GAPI SDK\Components\Dev\C++\Lib\x64

  • 链接器 > 输入 > 附加依赖 = bgapi2_genicam.lib

  • 构建事件 > 构建后事件 > 命令行 = 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 &lt; 8; i++)。我们希望将其更改为连续运行。我通过将其更改为 while 循环来做到这一点

while (pDataStream->GetIsGrabbing())

在我们新的while 循环中,有一个if 语句用于检查像素格式是“单色”(灰度)还是彩色。在原始文件中,它从第 619 行开始,到第 692 行结束。紧接在 ifelse 语句大括号关闭之后,pImage-&gt;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 窗口!

赞一个!!!!

【讨论】:

  • 我可以确认这适用于 Win7 64 位的 Win32 程序 Baumer-GAPI 2.8.1 唱 Baumer TXG06 相机。感谢您的介入。
【解决方案2】:

如果相机没有运行网络服务器,您将无法访问相机上的图像(查看其文档)。 尝试在命令提示符下输入:

telnet 192.169.2.3 80

如果 telnet 超时,您的相机没有在默认端口 80 上运行服务器。

也看到这个问题:C++ code Capturing image from IP / Ethernet Cameras (AXIS Cam)

【讨论】:

    【解决方案3】:

    添加到mark jay 的答案(我可以确认使用 Baumer-GAPI2 2.8.1 和 VC10 编译器和 Baumer 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 上发挥同样的作用。

    【讨论】:

    • 避免创建 BGAPI2::Image* 有什么好处?这是否意味着图像数据被复制一次而不是两次?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 2015-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多