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

时间:2014-05-07 22:30:40

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


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


我正在使用:

  • OpenCV v2.4.6.0
  • C ++
  • D-Link Cloud Camera 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    }

...我不明白我在看什么。它似乎正在寻找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    }

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

我为videoFeedAddress变量输入的值似乎没有得到不同的结果。我发现THIS网站列出了许多可能连接到它的地址。由于列表中没有任何地方存在7100&amp;考虑到安装标记为“DCS-7010L”,我使用了DCS-7010L列表旁边的地址。当试图访问相机时,大部分都可以通过浏览器到达,确认它们到达相机 - 但是当我在videoFeedAddress变量中使用它们时,它们似乎不会影响结果。

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

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

  1. This是我的代码所在的第一个配置之一。没有骰子。
  2. This一个人在谈论文件 - 而不是相机。它还提到了编解码器 - 但如果这是问题,我将无法在网络浏览器中观看它,对吧? (如果我错了,请纠正我......)
  3. This一个错误的错误代码/指向错误的代码行!
  4. This有人提到用ffmpeg支持编译OpenCV - 但我相信2.4.6.0已经准备就绪了!否则它与我已经尝试过的没有什么不同。
  5. 现在THIS似乎与我的相似,但唯一提出的解决方案并没有真正帮助,因为我已经找到了一个连接列表。我不相信这是重复的,因为根据THIS元讨论,我有更多的信息,因此无法接受别人的问题 - 特别是如果我最终需要添加更多信息。
  6. 感谢您阅读此内容。我意识到我在问一个有点具体的问题 - 尽管我很感激您对OpenCV&amp; amp;网络摄像机甚至相关主题。


      

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

1 个答案:

答案 0 :(得分:1)

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

您还可以查看相机是否提供http mjpeg流,请参阅其手册。我没有你正在使用的相机。所以我对此无能为力。

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

方法1

我假设您至少可以使用现有的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;
}
相关问题