【问题标题】:c++ opencv webcam stream to htmlc++ opencv网络摄像头流到html
【发布时间】:2014-10-26 19:31:24
【问题描述】:

我目前正在为我的研究开发一个项目,我必须在其中获取网络摄像头流、检测一些对象并在该流上添加一些附加信息。这一切都在服务器端完成。

现在我还必须向客户端提供流的修改图像。客户端只需打开一个包含以下内容的 HTML 文件:

<html>
    <head>
        <title></title>
    </head>
    <body>
        <h1>It works!</h1>
        <video width="320" height="240" src="http://127.0.0.1:4711/videostream" type="video/quicktime" autoplay controls>
            Your browser does not support the video tag.
        </video>
    </body>
</html>

这将在服务器上产生一个对 /videostream 的 HTTP 请求。为了在服务器端处理这个请求,我将使用 Boost 1.56。

目前我的网络摄像头流的每一帧都是IplImage 类型。我是否必须将 IplImage 转换为视频 MIME-Typespecific 格式?

我自己试图弄清楚整个事情是如何运作的,但我无法理解。我使用 Wireshark 分析通信,但没有任何意义。出于测试目的,我已将视频上传到我的网站空间并在本地打开上述文件。视频的 src 是我的网络服务器的地址。首先是 TCP 握手内容,然后是这条消息:

HTTP    765 GET /MOV_4198.MOV HTTP/1.1 

遵循以下消息(它包含连接:HTTP 部分中的 Keep-Alive):

HTTP    279 HTTP/1.1 304 Not Modified 

之后只有 TCP ACK 和 SYN 跟随,但没有数据。见下图: see picture

视频的真实数据是在哪里以及如何发送的?我在这里错过了什么?

如果您能提供一些有关浏览器(视频标签)和 C++ 套接字连接之间连接的信息,那就太好了。

谢谢你, 斯蒂芬

【问题讨论】:

  • mjpeg 可能是最简单的方法。 (请不要使用 opencv 已弃用的 c-api。IplImages 自 2010 年以来已死)
  • 谢谢 - 我会看看。关于死掉的 IplImages:我正在使用以下代码: capture = cvCaptureFromCAM(CV_CAP_ANY); IplImages* frame = cvQueryFrame(capture);在对已弃用的 api 进行一些研究后,我找到了 this post。当您下载 OpenCV 时,您可以在以下文件中找到:source\samples\cpp\starter_video.cpp;这是一个很好的例子,它是如何正确完成的。 (这在我发现的帖子中提到)。非常感谢您的提示!

标签: c++ opencv visual-c++ streaming webcam


【解决方案1】:

我想分享我的亲身经历——也许它也会对其他人有所帮助。为了从网络摄像头获取我的流,我使用了 OpenCV 2.4.9 作为协议,我使用了mjpeg streaming protocol(另见MJPEG over HTTP)——感谢@berak——他在我的问题帖下的评论中提到了 MJPEG。

下面的代码只是给出了一个概述——我不去讨论线程细节。 由于这是一个学生项目,我们使用的是 GitHub,你可以找到完整的源代码here on GitHub - project Swank Rats 我想在这里提一下,我不是 C++、OpenCV 或 Boost 大师。这个项目是我第一次使用这三个。

让您通过网络摄像头进行直播

做这样的事情(带有线程的完整代码,因此在 repo 中搜索 WebcamService)

cv::VideoCapture capture();
cv::Mat frame;
while (1) {
    if (!capture.isOpened()) {
        break; //do some logging here or something else - webcam not available
    }

    //Create image frames from capture
    capture >> frame;

    if (!frame.empty()) {
        //do something with your image (e.g. provide it)
        lastImage = frame.clone();
    }
}

通过 HTTP 提供您的图片

好吧,我不会详细介绍如何使用 C++ 创建 HTTP 服务器。 Boost for C++11 提供了一个很好的例子。我已经复制了这段代码并根据我的需要进行了调整。你可以在上面提到的 repo 中找到我的实现的源代码。该代码目前位于基础设施/网络/视频流中。

没有必要使用 FFMPEG、GStreamer 或类似的东西。您可以像这样使用 OpenCV 创建内存中的 JPEG(参见 StreamResponseHandler 的代码):

cv::Mat image = webcamService->GetLastImage();
// encode mat to jpg and copy it to content
std::vector<uchar> buf;
cv::imencode(".jpg", image, buf, std::vector<int>());

std::string content(buf.begin(), buf.end()); //this must be sent to the client

感谢@codeDr 的post here

content 变量以字节为单位表示图像,它将被发送到客户端。你必须关注 protocol of MJPEG

使用 HTML 连接到服务器

这样就足够了(如here所述)

<html>  
    <body>  
        <h1> Test for simple Webcam Live streaming </h1>  
        <img src="http://127.0.0.1:4711/videostream">
    </body>  
</html> 

您必须更改服务器连接的 IP、端口等。

我希望这会有所帮助。

【讨论】:

  • Python 的等价物是here。可以找到一个显示一张蓝色图像的最小项目here
  • 嗨,这似乎消耗了大量的 CPU 资源。我想知道imencode 是不是这个原因?有什么想法吗?
  • @Skully 你能帮我处理一下this question吗?
【解决方案2】:

我可能有点晚了,但由于我没有在 StackOverflow 中找到完全更新的 C++ 和 mjpeg 解决方案,所以考虑写一个新答案。

现在有一些用于 C++ 任务的简单易用的库(c++ mjpg 流式传输到 html)

https://github.com/nadjieb/cpp-mjpeg-streamer

https://github.com/jacksonliam/mjpg-streamer

https://github.com/codewithpassion/mjpg-streamer/tree/master/mjpg-streamer

我发现第一个非常简单。您需要 CMake,并在系统中安装 make。

git clone https://github.com/nadjieb/cpp-mjpeg-streamer.git;
cd cpp-mjpeg-streamer;
mkdir build && cd build;
cmake ../;
make;
sudo make install;
  • 确保您安装了正确版本的 OpenCV。

现在,写流光:

mjpeg_server.cc

#include <opencv2/opencv.hpp>

#include <nadjieb/mjpeg_streamer.hpp>

// for convenience
using MJPEGStreamer = nadjieb::MJPEGStreamer;

int main()
{
    cv::VideoCapture cap;
    cap.open("demo.mp4"); 
    if (!cap.isOpened())
    {
        std::cerr << "VideoCapture not opened\n";
        exit(EXIT_FAILURE);
    }

    std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};

    MJPEGStreamer streamer;

    // By default 1 worker is used for streaming
    // if you want to use 4 workers:
    //      streamer.start(8080, 4);
    streamer.start(8000);

    // Visit /shutdown or another defined target to stop the loop and graceful shutdown
    while (streamer.isAlive())
    {
        cv::Mat frame;
        cap >> frame;
        if (frame.empty())
        {
            std::cerr << "frame not grabbed\n";
            //continue;
            exit(EXIT_FAILURE);
        }

        // http://localhost:8080/bgr
        std::vector<uchar> buff_bgr;
        cv::imencode(".jpg", frame, buff_bgr, params);
        streamer.publish("/bgr", std::string(buff_bgr.begin(), buff_bgr.end()));

        cv::Mat hsv;
        cv::cvtColor(frame, hsv, cv::COLOR_BGR2HSV);

        // http://localhost:8080/hsv
        std::vector<uchar> buff_hsv;
        cv::imencode(".jpg", hsv, buff_hsv, params);
        streamer.publish("/hsv", std::string(buff_hsv.begin(), buff_hsv.end()));

        // std::cout<< "published" << std::endl;
    }

    streamer.stop();
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.1)

project(mjpeg_streamer CXX)

find_package(OpenCV 4.2 REQUIRED)
find_package(nadjieb_mjpeg_streamer REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(stream_test
  "mjpeg_server.cc")
target_compile_features(stream_test PRIVATE cxx_std_11)
target_link_libraries(stream_test PRIVATE nadjieb_mjpeg_streamer::nadjieb_mjpeg_streamer
                     ${OpenCV_LIBS})


| --- mjpeg_server.cc
| --- CMakeLists.txt
| --- ...
| --- build  
      | --- demo.mp4
      | --- ...

现在,我们可以构建流媒体了。

mkdir build && cd build;
cmake ../;
make;
./stream_test

现在,如果您转到"http://ip_address:port/bgr""http://ip_address:port/hsv",您应该能够看到流。在我的例子中,ip = 192.168.1.7 / localhost, port = 8000。

如果你想用另一个服务器抓取流,

index.html

<html>
  <body>
    <img src="http://localhost:8000/bgr">
    <img src="http://localhost:8000/hsv">
  </body>
</html>

serve.py

import http.server
import socketserver

class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.path = 'index.html'
        return http.server.SimpleHTTPRequestHandler.do_GET(self)

# Create an object of the above class
handler_object = MyHttpRequestHandler

PORT = 8080
my_server = socketserver.TCPServer(("", PORT), handler_object)

# Star the server
my_server.serve_forever()

python3 serve.py

最后,虽然它非常简单,但并不安全。

【讨论】:

  • 非常高的 CPU 和资源使用率。但很好的选择。
猜你喜欢
  • 2012-06-16
  • 2015-05-26
  • 1970-01-01
  • 1970-01-01
  • 2012-06-12
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
相关资源
最近更新 更多