一、简述
OpenCV中imread() 读取图像函数是不可以载入图像的网络url路径的,如果想要将网络url图像加载并转成mat数据格式,那么还需要借助第三方网络库curl。
二、环境
windows 10 + vs2017 + opencv3.4.7 + curl-7.78.0 + cmake
三、安装curl
1、curl简介
libcurl是免费的客户端URL传输库,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP。libcurl支持SSL证书, HTTP POST、HTTP PUT、FTP上传、基于HTTP表单的上传、代理、Cookie、用户+口令认证(基本、摘要、NTLM、协商、Kerberos)、文件续传、HTTP代理隧道等!
libcurl是高度可移植的,它构建和工作在许多平台上,包括Solaris、NETBSD、FreeBSD、OpenBSD、Darwin、HPUX、IIX、AIX、TUR64、Linux、UNIX、HUD、Windows、AMIGA、OS/2、BeOs、Mac OS X、ULTRIX、QNX、OpenVMS、RISC OS、Novell NETWORD、DOS等等。
libcurl是免费的,线程安全,IpV6兼容,功能丰富,良好支撑,快速,文档全面,并已被许多知名的,大的和成功的公司使用。
2、在curl官方中下载curl库
官方地址:https://curl.se/download.html
3、编译
有多种编译方式,比如:vs 自带的 nmake 编译、cmake编译。我这里选择的是cmake编译。
(1)解压curl-7.78.0.zip,进入目录中,并创建目录build,用于存放编译后的文件;创建install目录用于存放最终编译生成的头文件、dll、lib文件。
(2)打开cmake,源码目录选择解压后的curl-7.78.0目录,编译目录选择刚刚创建的build目录。点击“Configure”按钮,选择vs2017 、x64,配置成功。
(3)CMAKE_INSTALL_PREFIX选项,参数修改为刚刚创建的install目录,用于存放生成的头文件、库文件;
(4)再次点击“Configure”按钮,再点击“Generate”按钮,生成成功。
(5)在build目录中找到 CURL.sln,用vs2017打开【注意:一定要用管理员身份运行vs2017,不然生成库时会报错】,选择Debug/Release x64,这里我选择的是Release x64。
4、依次对项目“ALL_BUILD”、“INSTALL”生成
5、全部生成成功后,在install目录中看到生成的头文件、dll文件和lib文件
6、我们只需要install这一个目录即可,其他的所有文件都可以删除了。我这里把install目录单独拷贝出来,修改了名称
7、根据需求,自行在windows环境变量Path中添加curl的bin路径;【添加到系统环境变量中后就不需要把dll文件拷贝到项目运行目录下了】
四、网络url图像路径转Mat
1、配置
(1)在vs2017中,右击项目进入属性页;
(2)在“配置属性”->“C/C++”->“常规”->“附加包含目录”中添加curl的include目录;
(3)在“配置属性”->“链接器”->“常规”->“附加库目录”中添加curl的lib目录;
(4)在“配置属性”->“链接器”->“常规”->“输入”->“附加依赖项”中添加libcurl_imp.lib(Release模式)或libcurl-d_imp.lib(Debug模式)。
2、使用
这里参考链接:https://answers.opencv.org/question/91344/load-image-from-url/
直接贴上代码:
#include "curl/curl.h" // has to go before opencv headers
#include <iostream>
#include <vector>using namespace std;
#include <opencv2/opencv.hpp>
using namespace cv;
//curl writefunction to be passed as a parameter// we can't ever expect to get the whole image in one piece,// every router / hub is entitled to fragment it into parts// (like 1-8k at a time),// so insert the part at the end of our stream.size_t write_data(char *ptr, size_t size, size_t nmemb, void *userdata)
{
vector<uchar> *stream = (vector<uchar>*)userdata;
size_t count = size * nmemb;
stream->insert(stream->end(), ptr, ptr + count);
return count;
}
//function to retrieve the image as cv::Mat data type
cv::Mat curlImg(const char *img_url, int timeout=10)
{
vector<uchar> stream;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, img_url); //the img url
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // pass the writefunction
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream); // pass the stream ptr to the writefunction
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); // timeout if curl_easy hangs,
CURLcode res = curl_easy_perform(curl); // start curl
curl_easy_cleanup(curl); // cleanup
return cv::imdecode(stream, -1); // 'keep-as-is'
}
int main(void)
{
Mat image = curlImg("https://img-blog.csdnimg.cn/2020122114040625.png");
if (image.empty())
return -1; // load fail
namedWindow( "Image output", CV_WINDOW_AUTOSIZE );
imshow("Image output",image); // here's your car ;)
waitKey(0); // infinite
}
3、耗时统计
测试了一下,从网络上找了一个 837*675尺寸的png图像,测试几百次,平均获取耗时达到 170ms了;也测试了一些其他网络图像,获取耗时也是很大。当然可能和网络也有些关系。