OpenCV VideoCapture无法解析MJPG流

OpenCV VideoCapture unable to parse MJPG stream

本文关键字:MJPG VideoCapture OpenCV      更新时间:2023-10-16

我正试图在OpenCV 3.1版Windows x64中使用OpenCV VideoCapture类打开视频流。在我的树莓派上,我运行了mjpg_streamer,我可以通过http://192.168.1.245:8080/?action=stream,但是当我尝试在OpenCV中打开视频流时,它无法打开流。

这是我用来调试的代码,显然对其他有连接问题的人也有效。

#include <opencv2core.hpp>
#include <opencv2videoio.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
cv::VideoCapture vcap;
cv::Mat raw_image;
const string videoStreamAddress = "http://192.168.1.245:8080/?action=stream";
if (!vcap.open(videoStreamAddress))
{
cout << "Error opening video stream" << endl;
system("pause");
return -1;
}
cout << "Stream opened" << endl;
system("pause");
return 0;
}

在网上,人们说OpenCV必须在链接中有视频扩展。我试着使用其他人正在使用的扩展技巧,比如http://192.168.1.245:8080/?action=stream?dummy=param.mjpg,http://192.168.1.245:8080/?action=stream&type=.mjpg,&channel=0&。jpg和&type=.mjpeg,但这不起作用。此外,我已经在cmake中启用了ffmpeg并使用它进行了构建。在这一点上,它似乎对其他人有效,而且似乎没有其他关于这个主题的内容。解决这个问题的办法是什么?

多亏了@api55的建议,我能够获取流,然后将原始jpg数据传递给opencv,然后做我想做的事情。

以下是提供的链接@api55中的解决方案的c++代码(到python解决方案的链接)。

try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query("192.168.1.245", "8080");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
std::string jpgimg = "";
std::stringstream request_;
request_ << "GET /?action=stream HTTP/1.1rn";
request_ << "Host: 192.168.1.245rn";
request_ << "Accept-Encoding: *rn";
request_ << "rn";
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(request_.str()), ignored_error);
for (;;)
{
char buf[1025];
buf[1024] = '';
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf,1024), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
jpgimg.append(buf,buf+len);
int a = jpgimg.find("xffxd8");
int b = jpgimg.find("xffxd9");
if (a != -1 && b != -1)
{
Mat rawData(1, b-a+2, CV_8UC1, (void*)(&jpgimg[a]));
Mat i = cv::imdecode(rawData, CV_LOAD_IMAGE_COLOR);
cv::imshow("i", i);
if (cv::waitKey(1) == 27)
break;
jpgimg = jpgimg.substr(b+2);
}
}
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}

它绝不是经过优化的,纯粹是其他地方实现的基础。它与Boost ASIO 1.65.1一起工作,方法是在我的树莓pi(端口8080)上打开一个流到mjpg_streamer,向它发送一个HTTP GET请求,请求/?action=流式传输原始链接的一部分,查找jpg数据的开始和结束标志("\xff\xd8"answers"\xff#xd9"),然后通过imdecode将这些数据发送到OpenCV。

资源:

Boost ASIO客户端代码:http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/tutorial/tutdaytime1.html

关于jpg如何工作的信息:如何在C++中解析MJPEG HTTP流?

使用OpenCV中的原始jpg数据:opencv从缓冲区读取jpeg图像

希望OpenCV将来能有更好的.jpg支持。