OpenCV和网络摄像机 - 或者 - 如何监视邻居?

Ale*_*der 5 c++ camera opencv ffmpeg ip-camera


一点背景; 这个程序最初是为了与USB摄像头配合使用而设计的 - 但是由于摄像机需要的位置和计算机的位置之间的设置,切换到通过网络运行的摄像机更有意义.现在我正在尝试转换程序以实现这一目标,但到目前为止我的努力都遇到了糟糕的结果.我也在OpenCV论坛上问了同样的问题.帮我监视我的邻居!(当然,这是他们的许可!):D


我正在使用:

  • OpenCV v2.4.6.0
  • C++
  • D-Link云相机7100(安装程序是DCS-7010L,根据说明.)

我试图通过OpenCV访问DLink相机的视频源.

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

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

我尝试的几乎所有事情都会发生这种错误,但不会产生更多问题.

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

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    }
Run Code Online (Sandbox Code Playgroud)

...我不明白我在看什么.它似乎正在寻找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    }
Run Code Online (Sandbox Code Playgroud)

使用添加的'cout'我可以将其缩小到第38行:"cv_cap_IP.open(videoFeedAddress);"

我为videoFeedAddress变量输入的值似乎没有得到不同的结果.我发现这个站点列出了许多可能的地址来连接它.由于列表中没有任何地方7100并且考虑到安装标记为"DCS-7010L",我使用了DCS-7010L列表旁边的地址.当试图访问摄像机时,可以通过浏览器访问它们,确认它们到达摄像机 - 但是当我在videoFeedAddress变量中使用它们时,它们似乎不会影响结果.

我已经尝试了很多有和没有用户名:密码,端口号(554),以及最后的..mjpg(格式)的变体.

我四处搜索并发现了许多不同的"可能"答案 - 但它们似乎都不适合我.他们中的一些确实给了我包含上述用户名:密码等内容的想法,但似乎没有什么区别.当然,可能的组合数量当然相当大 - 所以我当然没有尝试过所有这些组合(这里有更多的方向值得赞赏).以下是我发现的一些链接:

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

感谢您阅读此内容.我意识到我在问一个有点具体的问题 - 尽管我很感激您对OpenCV和网络摄像机甚至相关主题的任何建议.


TLDR:网络摄像头和OpenCV没有合作.我不确定这是否是我用来将程序导向相机或我正在使用的命令的地址 - 但我做的调整似乎没有超出我已经完成的结果!现在我的邻居将无人看见!

Zaw*_*Lin 1

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

\n\n

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

\n\n

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

\n\n

方法1

\n\n

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

\n\n

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\xe2\x80\x8c\xe2\x80\x8bux=raw,dst=127.0.0.1:9080/frame.mjpg}"

\n\n

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

\n\n

方法2

\n\n

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

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

代码

\n\n
#include "opencv2/highgui/highgui.hpp"\n#include <windows.h>\n#include <vlc/vlc.h>\n\nusing namespace cv;\n\nstruct ctx\n{\n    Mat* image;\n    HANDLE mutex;\n    uchar* pixels;\n};\nbool isRunning=true;\n\nSize getsize(const char* path)\n{\n    libvlc_instance_t *vlcInstance;\n    libvlc_media_player_t *mp;\n    libvlc_media_t *media;\n\n    const char * const vlc_args[] = {\n        "-R",\n       "-I", "dummy",\n       "--ignore-config",\n       "--quiet",\n\n    };\n    vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);\n    media = libvlc_media_new_location(vlcInstance, path);\n    mp = libvlc_media_player_new_from_media(media);\n\n    libvlc_media_release(media);\n    libvlc_video_set_callbacks(mp, NULL, NULL, NULL, NULL);\n    libvlc_video_set_format(mp, "RV24",100,100, 100 * 24 / 8); // pitch = width * BitsPerPixel / 8\n    libvlc_media_player_play(mp);\n\n    Sleep(2000);//wait a while so that something get rendered so that size info is available\n    unsigned int width=640,height=480;\n    libvlc_video_get_size(mp,0,&width,&height);\n\n\n    if(width==0 || height ==0)\n    {\n        width=640;\n        height=480;\n    }\n    libvlc_media_player_stop(mp);\n    libvlc_release(vlcInstance);\n    libvlc_media_player_release(mp);\n    return Size(width,height);\n}\n\n\nvoid *lock(void *data, void**p_pixels)\n{\n    struct ctx *ctx = (struct ctx*)data;\n    WaitForSingleObject(ctx->mutex, INFINITE);\n    *p_pixels = ctx->pixels;\n    return NULL;\n\n}\n\nvoid display(void *data, void *id){\n    (void) data;\n    assert(id == NULL);\n}\n\nvoid unlock(void *data, void *id, void *const *p_pixels)\n{\n\n    struct ctx *ctx = (struct ctx*)data;\n    Mat frame = *ctx->image;\n    if(frame.data)\n    {\n        imshow("frame",frame);\n        if(waitKey(1)==27)\n        {\n            isRunning=false;\n            //exit(0);\n        }\n    }\n    ReleaseMutex(ctx->mutex);\n}\n\n\nint main( )\n{\n    string url="rtsp://admin:admin@10.10.204.111";\n    //vlc sdk does not know the video size until it is rendered, so need to play it a bit so that size is     known\n    Size sz = getsize(url.c_str());\n\n    // VLC pointers\n    libvlc_instance_t *vlcInstance;\n    libvlc_media_player_t *mp;\n    libvlc_media_t *media;\n\n    const char * const vlc_args[] = {\n        "-R",\n        "-I", "dummy",\n        "--ignore-config", \n        "--quiet", \n    };\n    vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);\n    media = libvlc_media_new_location(vlcInstance, url.c_str());\n    mp = libvlc_media_player_new_from_media(media);\n\n    libvlc_media_release(media);\n\n    struct ctx* context = ( struct ctx* )malloc( sizeof( *context ) );\n    context->mutex = CreateMutex(NULL, FALSE, NULL);\n    context->image = new Mat(sz.height, sz.width, CV_8UC3);\n    context->pixels = (unsigned char *)context->image->data;\n\n    libvlc_video_set_callbacks(mp, lock, unlock, display, context);\n    libvlc_video_set_format(mp, "RV24", sz.width, sz.height, sz.width * 24 / 8); // pitch = width *     BitsPerPixel / 8\n\n    libvlc_media_player_play(mp);\n    while(isRunning)\n    {\n        Sleep(1);\n    }\n\n    libvlc_media_player_stop(mp);\n    libvlc_release(vlcInstance);\n    libvlc_media_player_release(mp);\n    free(context);\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n