【问题标题】:OpenCV and Network Cameras -or- How to spy on the neighbors?OpenCV 和网络摄像机 - 或 - 如何监视邻居?
【发布时间】:2014-06-25 03:04:30
【问题描述】:

一点上下文;该程序最初是为使用 USB 摄像头而构建的 - 但由于需要在摄像头所在位置和计算机所在位置之间进行设置,因此切换到通过网络运行的摄像头更有意义。现在我正在尝试转换程序来实现这一点,但到目前为止我的努力结果不佳。我也在OpenCV forums 上问过同样的问题。帮我监视我的邻居! (当然,这是他们的许可!):D


我正在使用:

  • OpenCV v2.4.6.0
  • C++
  • D-Link Cloud Camera 7100(根据说明安装为 DCS-7010L。)

我正在尝试通过 OpenCV 访问 DLink 摄像头的视频源。

我可以通过浏览器的 IP 地址访问摄像机,没有任何问题。不幸的是;我的程序不太合作。尝试访问相机时,程序会给出 OpenCV 生成的错误:

警告:打开文件时出错 (../../modules/highgui/src/cap_ffmpeg_impl.hpp:529)

这个错误发生在我尝试的几乎所有不会以某种方式产生更多问题的事情。

供参考 - OpenCV 的 cap_ffmpeg_impl.hpp 第 529 行附近的代码如下:

522    bool CvCapture_FFMPEG::open( const char* _filename )
523    {
524        unsigned i;
525        bool valid = false;
526
527        close();
528
529    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
530        int err = avformat_open_input(&ic, _filename, NULL, NULL);
531    #else
532        int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
533    #endif
...
616    }

...我不知道我在看什么。它似乎正在寻找 ffmpeg 版本 - 但我已经在那台计算机上安装了最新的 ffmpeg,所以这不应该是问题。

这是我根据 Sebastian Schmitz 的建议尝试使用的经过编辑的版本:

 1    #include <fstream>                            // File input/output
 2    #include <iostream>                           // cout / cin / etc
 3    #include <windows.h>                      // Windows API stuff
 4    #include <stdio.h>                            // More input/output stuff
 5    #include <string>                         // "Strings" of characters strung together to form words and stuff
 6    #include <cstring>                            // "Strings" of characters strung together to form words and stuff
 7    #include <streambuf>                      // For buffering load files
 8    #include <array>                          // Functions for working with arrays
 9    #include <opencv2/imgproc/imgproc.hpp>        // Image Processor
10    #include <opencv2/core/core.hpp>          // Basic OpenCV structures (cv::Mat, Scalar)
11    #include <opencv2/highgui/highgui.hpp>        // OpenCV window I/O
12    #include "opencv2/calib3d/calib3d.hpp"
13    #include "opencv2/features2d/features2d.hpp"
14    #include "opencv2/opencv.hpp"
15    #include "resource.h"                     // Included for linking the .rc file
16    #include <conio.h>                            // For sleep()
17    #include <chrono>                         // To get start-time of program.
18    #include <algorithm>                      // For looking at whole sets.
19
20    #ifdef __BORLANDC__
21      #pragma argsused
22    #endif
23
24    using namespace std;                      // Standard operations. Needed for most basic functions.
25    using namespace std::chrono;              // Chrono operations. Needed getting starting time of program.
26    using namespace cv;                           // OpenCV operations. Needed for most OpenCV functions.
27
28    string videoFeedAddress = "";
29    VideoCapture videoFeedIP = NULL;
30    Mat clickPointStorage; //Artifact from original program.
31
32    void displayCameraViewTest()
33    {
34      VideoCapture cv_cap_IP;
35      Mat color_img_IP;
36      int capture;
37      IplImage* color_img;
38      cv_cap_IP.open(videoFeedAddress);
39      Sleep(100);
40      if(!cv_cap_IP.isOpened())
41      {
42          cout << "Video Error: Video input will not work.\n";
43          cvDestroyWindow("Camera View");
44          return;
45      }
46      clickPointStorage.create(color_img_IP.rows, color_img_IP.cols, CV_8UC3);
47      clickPointStorage.setTo(Scalar(0, 0, 0));
48      cvNamedWindow("Camera View", 0); // create window
49      IplImage* IplClickPointStorage = new IplImage(clickPointStorage);
50      IplImage* Ipl_IP_Img;
51      
52      for(;;)
53      {
54          cv_cap_IP.read(color_img_IP);
55          IplClickPointStorage = new IplImage(clickPointStorage);
56          Ipl_IP_Img = new IplImage(color_img_IP);
57          cvAdd(Ipl_IP_Img, IplClickPointStorage, color_img);
58          cvShowImage("Camera View", color_img); // show frame
59          capture = cvWaitKey(10); // wait 10 ms or for key stroke
60          if(capture == 27 || capture == 13 || capture == 32){break;} // if ESC, Return, or space; close window.
61      }
62      cv_cap_IP.release();
63      delete Ipl_IP_Img;
64      delete IplClickPointStorage;
65      cvDestroyWindow("Camera View");
66      return;
67    }
68    
69    int main()
70    {
71      while(1)
72      {
73          cout << "Please Enter Video-Feed Address: ";
74          cin >> videoFeedAddress;
75          if(videoFeedAddress == "exit"){return 0;}
76          cout << "\nvideoFeedAddress: " << videoFeedAddress << endl;
77          displayCameraViewTest();
78          if(cvWaitKey(10) == 27){return 0;}
79      }
80      return 0;
81    }

使用 added 'cout's 我能够将其缩小到第 38 行:“cv_cap_IP.open(videoFeedAddress);”

我为 videoFeedAddress 变量输入的值似乎没有得到不同的结果。我找到了THIS 站点,其中列出了许多可以连接到它的地址。由于列表中不存在 7100 并且考虑到安装标记为“DCS-7010L”,因此我使用了 DCS-7010L 列表旁边的地址。当尝试访问摄像头时,大多数都可以通过浏览器访问,确认它们到达摄像头 - 但当我在 videoFeedAddress 变量中使用它们时,它们似乎不会影响结果。

我已经尝试了很多,无论是否使用用户名:密码、端口号 (554) 以及末尾的 ?.mjpg(格式)的变体。

我四处搜索,发现了许多不同的“可能”答案——但它们似乎都不适合我。其中一些确实给了我包含上述用户名:密码等内容的想法,但似乎没有什么不同。当然,可能的组合的数量肯定是相当大的——所以我当然没有尝试过所有的组合(这里有更多的方向将不胜感激)。以下是我找到的一些链接:

  1. This 是我的代码最早使用的配置之一。没有骰子。
  2. This 一个是在谈论文件,而不是相机。它还提到了编解码器——但如果这是问题所在,我将无法在网络浏览器中观看它,对吧? (如果我在这里错了,请纠正我......)
  3. This 错误代码/指向错误的代码行!
  4. This 有人提到使用 ffmpeg 支持编译 OpenCV - 但我相信 2.4.6.0 已经准备好了!否则它与我已经尝试过的没有什么不同。
  5. 现在THIS 似乎与我所拥有的非常相似,但唯一提出的解决方案并没有真正帮助,因为我已经找到了连接列表。我不相信这是重复的,因为根据THIS 元讨论,我有更多的信息,所以接管别人的问题感觉不舒服 - 特别是如果我最终需要添加 更多 稍后提供信息。

感谢您阅读本文。我意识到我在问一个有点具体的问题——尽管我会很感激你能想到的关于 OpenCV 和网络摄像机甚至相关主题的任何建议。


TLDR: 网络摄像机和 OpenCV 不合作。我不确定是否 这是我用来将程序定向到相机或 我正在使用的命令 - 但我所做的任何调整似乎都没有改善 结果超出了我已经做过的!现在我的邻居们将无人看管!

【问题讨论】:

  • 努力+1 :),不幸的是我自己没有使用过网络摄像头。你有没有试过做一个最小的例子,有时你可以从那里推断出错误。
  • @SebastianSchmitz 我在你推荐之后尝试过,但我只能将其缩小到同一行代码:“cv_cap_IP.open(videoFeedAddress);”这导致 OpenCV 说“警告:打开文件时出错(../../modules/highgui/src/cap_ffmpeg_impl.hpp:529)”。我找不到任何其他适用于 IP 摄像头的命令。我假设我只是错过了一些东西(明显或其他)。感谢您的建议,寿 :/
  • 我没有这样的相机,但可能有两件事可以尝试:1)将部分流下载到文件中并尝试在该文件上运行您的应用程序。如果可行,则问题可能与网络支持或身份验证问题有关。 2)如果第一个成功了,尝试wget &lt;url&gt;看看OpenCV访问数据是否没有身份验证问题
  • 如果它与浏览器一起工作,您可以嗅探数据包以查看它连接到哪个端口。然后尝试使用不同的程序(vlc、ffmpeg、mencoder、gstreamer)打开网络流,如 rtsp://$ip:$port 等。这将帮助您缩小尝试范围
  • @Alexander 当我最后一次制作它时,我使用了 cmake,并且确实有一些复选框(如果你以前没有使用过。这是我第一次)你会检查。我记得检查并确认他们被检查过,或者如果他们没有检查过。比我更有知识的人可能知道事后如何判断,但是如果您使用 cmake 并查找 ffmpeg 标志并发现默认情况下未检查它们,那可能会解决您的一个问题。

标签: c++ opencv camera ffmpeg ip-camera


【解决方案1】:

有多种获取视频的方法。 ffmpeg 不是唯一的方法,尽管它最方便。要诊断 ffmpeg 是否能够读取流,您应该使用独立的 ffmpeg/ffplay 尝试打开 url。如果可以直接打开,可能是一些小东西,比如双斜杠等url格式(rtsp://IPADDRESS:554/live1.sdp而不是rtsp://IPADDRESS:554//live1.sdp)。如果它不能直接打开它,它可能需要一些额外的命令行开关才能使其工作。然后你需要修改 opencv 的 ffmpeg 实现@第 529 行以将选项传递给avformat_open_input。在您获得一个工作程序之前,这可能需要进行相当多的调整。

您还可以通过查阅相机手册来检查相机是否提供 http mjpeg 流。我没有你正在使用的相机。所以我在这方面帮不上什么忙。

或者,我有以下两个建议,因为您提到 vlc 正在工作,这可能会帮助您相对快速地启动和运行。

方法一

我假设您至少可以使用现有的 opencv/ffmpeg 组合打开 mjpeg url。由于 vlc 正在工作,只需使用 vlc 将视频转码为 mjpeg 就像

vlc.exe --ignore-config -I dummy rtsp://admin:admin@10.10.204.111 --sout=#transcode"{vcodec=MJPG,vb=5000,scale=1,acodec=none}:std{access=http,m‌​ux=raw,dst=127.0.0.1:9080/frame.mjpg}"

之后使用http://127.0.0.1:9080/frame.mjpg 使用opencv VideoCapture 抓取帧。这只需要您有一个可以将传入流转换为 mjpeg 的转码器程序。

方法2

您也可以直接以编程方式使用 vlc api。以下代码使用 vlc 来抓取帧。编译相关信息

  • C:\Program Files (x86)\VideoLAN\VLC\sdk\include
  • C:\Program Files (x86)\VideoLAN\VLC\sdk\lib
  • libvlc.lib,libvlccore.lib

代码

#include "opencv2/highgui/highgui.hpp"
#include <windows.h>
#include <vlc/vlc.h>

using namespace cv;

struct ctx
{
    Mat* image;
    HANDLE mutex;
    uchar* pixels;
};
bool isRunning=true;

Size getsize(const char* path)
{
    libvlc_instance_t *vlcInstance;
    libvlc_media_player_t *mp;
    libvlc_media_t *media;

    const char * const vlc_args[] = {
        "-R",
       "-I", "dummy",
       "--ignore-config",
       "--quiet",

    };
    vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    media = libvlc_media_new_location(vlcInstance, path);
    mp = libvlc_media_player_new_from_media(media);

    libvlc_media_release(media);
    libvlc_video_set_callbacks(mp, NULL, NULL, NULL, NULL);
    libvlc_video_set_format(mp, "RV24",100,100, 100 * 24 / 8); // pitch = width * BitsPerPixel / 8
    libvlc_media_player_play(mp);

    Sleep(2000);//wait a while so that something get rendered so that size info is available
    unsigned int width=640,height=480;
    libvlc_video_get_size(mp,0,&width,&height);


    if(width==0 || height ==0)
    {
        width=640;
        height=480;
    }
    libvlc_media_player_stop(mp);
    libvlc_release(vlcInstance);
    libvlc_media_player_release(mp);
    return Size(width,height);
}


void *lock(void *data, void**p_pixels)
{
    struct ctx *ctx = (struct ctx*)data;
    WaitForSingleObject(ctx->mutex, INFINITE);
    *p_pixels = ctx->pixels;
    return NULL;

}

void display(void *data, void *id){
    (void) data;
    assert(id == NULL);
}

void unlock(void *data, void *id, void *const *p_pixels)
{

    struct ctx *ctx = (struct ctx*)data;
    Mat frame = *ctx->image;
    if(frame.data)
    {
        imshow("frame",frame);
        if(waitKey(1)==27)
        {
            isRunning=false;
            //exit(0);
        }
    }
    ReleaseMutex(ctx->mutex);
}


int main( )
{
    string url="rtsp://admin:admin@10.10.204.111";
    //vlc sdk does not know the video size until it is rendered, so need to play it a bit so that size is     known
    Size sz = getsize(url.c_str());

    // VLC pointers
    libvlc_instance_t *vlcInstance;
    libvlc_media_player_t *mp;
    libvlc_media_t *media;

    const char * const vlc_args[] = {
        "-R",
        "-I", "dummy",
        "--ignore-config", 
        "--quiet", 
    };
    vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    media = libvlc_media_new_location(vlcInstance, url.c_str());
    mp = libvlc_media_player_new_from_media(media);

    libvlc_media_release(media);

    struct ctx* context = ( struct ctx* )malloc( sizeof( *context ) );
    context->mutex = CreateMutex(NULL, FALSE, NULL);
    context->image = new Mat(sz.height, sz.width, CV_8UC3);
    context->pixels = (unsigned char *)context->image->data;

    libvlc_video_set_callbacks(mp, lock, unlock, display, context);
    libvlc_video_set_format(mp, "RV24", sz.width, sz.height, sz.width * 24 / 8); // pitch = width *     BitsPerPixel / 8

    libvlc_media_player_play(mp);
    while(isRunning)
    {
        Sleep(1);
    }

    libvlc_media_player_stop(mp);
    libvlc_release(vlcInstance);
    libvlc_media_player_release(mp);
    free(context);

    return 0;
}

【讨论】:

  • VLC 正在连接,但恐怕连接比通过浏览器访问相机要慢得多。浏览器延迟小于 1/10 秒 - 但 VLC 是 2 秒,这对于我正在做的事情是不可接受的。这种延迟是我对 VLC 所做的任何事情所固有的吗?
猜你喜欢
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 2012-06-16
  • 2012-12-20
  • 1970-01-01
  • 1970-01-01
  • 2022-08-02
相关资源
最近更新 更多