我正在尝试使用OpenCV 3.1版,Windows x64中的OpenCV VideoCapture类打开视频流。在我的覆盆子pi上我运行了mjpg_streamer,我可以通过http://192.168.1.245:8080/?action=stream看到输出,但是当我尝试在OpenCV中打开视频流时,它无法打开流。
这是我用来调试的代码,显然也适用于有连接问题的其他人。
#include <opencv2\core.hpp>
#include <opencv2\videoio.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,&amp; channel = 0&amp; .mjpg,以及&amp; type = .mjpeg,但这不起作用。另外,我在cmake中启用了ffmpeg并使用它构建。在这一点上,它似乎适用于其他人,并且似乎在该主题上没有任何其他内容。解决方案是什么?
答案 0 :(得分:0)
感谢@ api55的建议,我能够获取流,然后将原始jpg数据传递给opencv,并在第一时间做我想做的事情。
以下是链接@ api55提供的解决方案的c ++代码(link to python solution)。
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.1\r\n";
request_ << "Host: 192.168.1.245\r\n";
request_ << "Accept-Encoding: *\r\n";
request_ << "\r\n";
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(request_.str()), ignored_error);
for (;;)
{
char buf[1025];
buf[1024] = '\0';
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("\xff\xd8");
int b = jpgimg.find("\xff\xd9");
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上打开一个流到mjpg_streamer(在端口8080上),向原始链接的/?action = stream部分发送一个HTTP GET请求,寻找jpg数据的开头和结束标志(“\ xff \ xd8”和“\ xff \ xd9”),然后通过imdecode将此数据发送到OpenCV。
资源:
提升ASIO客户端代码: http://www.boost.org/doc/libs/1_65_1/doc/html/boost_asio/tutorial/tutdaytime1.html
有关jpgs如何工作的信息: How to parse MJPEG HTTP Stream within C++?
在OpenCV中使用原始jpg数据: opencv read jpeg image from buffer
希望OpenCV将来会有更好的mjpg支持。