|
【深度学习】【Opencv】【GPU】python/C++调用onnx模型【基础】提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论文章目录【深度学习】【Opencv】【GPU】python/C++调用onnx模型【基础】前言Python版本OpenCVWindows平台安装OpenCVopencv调用onnx模型C++版本OpenCV_GPUWindows平台编译安装OpenCVopencv调用onnx模型总结前言OpenCV是一个基于BSD许可发行的跨平台计算机视觉和机器学习软件库(开源),可以运行在Linux、Windows、Android和MacOS操作系统上。可以将pytorch中训练好的模型使用ONNX导出,再使用opencv中的dnn模块直接进行加载使用。系列学习目录:【CPU】Pytorch模型转ONNX模型流程详解【GPU】Pytorch模型转ONNX格式流程详解【ONNX模型】快速部署【ONNX模型】多线程快速部署【ONNX模型】opencv_cpu调用onnx【ONNX模型】opencv_gpu调用onnxPython版本OpenCVWindows平台安装OpenCV博主在win10环境下装anaconda环境,而后搭建onnx模型运行所需的openCV环境。#搭建opencv环境condacreate-nopencv_onnx_gpupython=3.10.9-y#激活环境activateopencv_onnx_gpu1234博主使用opencv-4.8.0版本,GPU版本不能直接通过pip下载安装进行使用,必须要在本地进行编译。编译过程具体参考博主的博文windows10下opencv4.8.0-cudaPython版本源码编译教程。importcv2cv2.__version__12opencv调用onnx模型随便拷贝一组数据用来测试数据GPU版本相比于CPU版本在速度上的提升。在项目路径下博主拷贝了CAMO数据集。将PFNet.onnx也拷贝到项目路径下。使用opencv并调用gpu完成了整个推理流程。importcv2importnumpyasnpimportglobimportosimporttimedefreadImagesInFolder(folderPath,images):fileNames=glob.glob(os.path.join(folderPath,'*.jpg'))forfileNameinfileNames:bgrImage=cv2.imread(fileName,cv2.IMREAD_COLOR)ifbgrImageisnotNone:rgbImage=cv2.cvtColor(bgrImage,cv2.COLOR_BGR2RGB)images.append(rgbImage)deftransformation(image,targetSize,mean,std):resizedImage=cv2.resize(image,targetSize,interpolation=cv2.INTER_AREA)normalized=resizedImage.astype(np.float32)normalized/=255.0normalized-=meannormalized/=stdreturnnormalizeddefloadModel(onnx_path):net=cv2.dnn.readNetFromONNX(onnx_path)returnnetdefmain():#图片存放文件路径folderPath="D:/deeplean_demo/opencv_onnx_gpu/CAMO/c"rgbImages=[]readImagesInFolder(folderPath,rgbImages)#加载ONNX模型onnx_path="D:/deeplean_demo/opencv_onnx_gpu/PFNet.onnx"net=loadModel(onnx_path)#设置CUDA为后端#net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)#net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)output_probs=[]output_layer_names=net.getUnconnectedOutLayersNames()#定义目标图像大小target_size=(416,416)#定义每个通道的归一化参数mean=(0.485,0.456,0.406)#均值std=(0.229,0.224,0.225)#标准差#开始计时start=time.time()forrgb_imageinrgbImages:#获取图像的大小original_size=(rgb_image.shape[1],rgb_image.shape[0])#图片归一化normalized=transformation(rgb_image,target_size,mean,std)print(normalized.shape[:2])blob=cv2.dnn.blobFromImage(normalized)#将Blob设置为模型的输入net.setInput(blob)#运行前向传播output_probs=net.forward(output_layer_names)#获取最完整的预测prediction=output_probs[3]#预测图变maskmask=cv2.resize(np.squeeze(prediction)*255.0,original_size,interpolation=cv2.INTER_AREA)end=time.time()#计算耗时elapsed_time=end-start#打印耗时print("Elapsedtime:",elapsed_time,"seconds")if__name__=="__main__":main()123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869gpu模式下250张图片只用了大约13秒。假设注释掉与gou相关的代码net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)12cpu模式下250张图片就用了大约95秒。C++版本OpenCV_GPUWindows平台编译安装OpenCV博主使用opencv-4.8.0版本,GPU版本不能直接通过官网下载exe进行使用,必须要在本地进行编译。编译过程具体参考博主的博文【windows10下opencv4.8.0-cudaC++版本源码编译教程】。编译完成后,在输出的文件夹内找到install文件,将其拷贝合适的位置。博主新建了一个名为opencv_gpu的文件夹,并将install重命名位build放在其中。打开VS2019:新建新项目---->空项目---->配置项目---->项目路径以及勾选“将解决方案和项目放在同一目录中---->点击创建。在解决方案–>源文件–>右键添加新建项。这里暂时可以默认空着不做处理。设置OpenCV路径:项目---->属性。假设没有新建cpp文件,空项目的属性页就不会存在C/C++这一项目。添加附加包含目录:Release|x64---->C/C+±—>常规---->附加包含目录。D:\C++_demo\opencv_gpu\build\x64\vc16\binD:\C++_demo\opencv_gpu\build\binD:\C++_demo\opencv_gpu\build\includeD:\C++_demo\opencv_gpu\build\include\opencv21234链接器:Release|x64---->链接器---->常规---->附加包含目录。D:\C++_demo\opencv_gpu\build\x64\vc16\lib1链接器:Release|x64---->链接器---->输入---->附加依赖项。在D:\C++_demo\opencv_gpu\build\x64\vc16\lib下找到附加依赖项的文件。opencv_world480.lib1在Releasex64模式下测试,将opencv_world480.dll文件复制到自己项目的Release下。没有Release目录时,需要在Release|x64模式下运行一遍代码,代码部分在下一节提供,读者可以先行新建文件复制代码。D:\C++_demo\opencv_gpu\build\x64\vc16\bin===>D:\C++_demo\opencv_onnx_gpu\x64\Releas123这里博主为了方便安装的是release版本的,读者可以安装debug版本的,流程基本一致,只需要将属性的Release|x64变成Debug|x64,然后附加依赖项由opencv_world480.lib变成opencv_world480d.lib,再将opencv_world480d.dll文件复制到自己项目的Release下。前提是你编译了debug版本oepncv。opencv调用onnx模型随便拷贝一组数据用来测试数据GPU版本相比于CPU版本在速度上的提升。在项目路径下博主拷贝了CAMO数据集。将PFNet.onnx也拷贝到项目路径下。将python版本的opencv转化成对应的c++版本的,发现输出的效果完全一致,onnx模型可以作为c++的接口来供其他应用调用。#include#include#include#include#includeusingnamespacestd;voidreadImagesInFolder(conststd::string&folderPath,std::vector&images){cv::Stringpath(folderPath+"/*.jpg");//这里假设你的图片格式是.jpg,如果是其他格式请相应修改std::vectorfileNames;cv::glob(path,fileNames,true);//通过glob函数获取文件夹内所有符合格式的文件名for(constauto&fileName:fileNames){//使用imread函数读取图片cv::MatbgrImage=cv::imread(fileName,cv::IMREAD_COLOR);//图片格式转化bgr-->rgbif(!bgrImage.empty()){ cv::MatrgbImage;cv::cvtColor(bgrImage,rgbImage,cv::COLOR_BGR2RGB);images.push_back(rgbImage);}}}cv::Mattransformation(constcv::Mat&image,constcv::Size&targetSize,constcv::Scalar&mean,constcv::Scalar&std){cv::MatresizedImage;//图片尺寸缩放cv::resize(image,resizedImage,targetSize,0,0,cv::INTER_AREA);cv::Matnormalized;resizedImage.convertTo(normalized,CV_32F);cv::subtract(normalized/255.0,mean,normalized);cv::divide(normalized,std,normalized);returnnormalized;}cv::dnn::NetloadModel(conststring&onnx_path){cv::dnn::Netnet=cv::dnn::readNetFromONNX(onnx_path);returnnet;}intmain(){//图片存放文件路径stringfolderPath="D:/C++_demo/opencv_onnx_gpu/CAMO/c";std::vectorrgbImages;readImagesInFolder(folderPath,rgbImages);//stringimage_path="./animal-1.jpg";//加载ONNX模型stringonnx_path="D:/C++_demo/opencv_onnx_gpu/PFNet.onnx";cv::dnn::Netnet=loadModel(onnx_path);//设置CUDA为后端net.setPreferableBackend(cv::dnn:NN_BACKEND_CUDA);net.setPreferableTarget(cv::dnn:NN_TARGET_CUDA);cv::Matoutput_prob;std::vectoroutput_probs;std::vectoroutput_layer_names=net.getUnconnectedOutLayersNames();//定义目标图像大小cv::SizetargetSize(416,416);//定义每个通道的归一化参数cv::Scalarmean(0.485,0.456,0.406);//均值cv::Scalarstd(0.229,0.224,0.225);//标准差//开始计时autostart=chrono::high_resolution_clock::now();for(constauto&rgbImage:rgbImages){//获取图像的大小cv::SizeoriginalSize(rgbImage.cols,rgbImage.rows);//cv::imshow("输入窗口",rgbImage);//cv::waitKey(0);//cv::destroyAllWindows();//图片归一化cv::Matnormalized=transformation(rgbImage,targetSize,mean,std);std::cout<< normalized.size() << std::endl;
cv::Mat blob = cv::dnn::blobFromImage(normalized);
// 将Blob设置为模型的输入
net.setInput(blob);
// 运行前向传播
net.forward(output_probs, output_layer_names);
// 获取最完整的预测
cv::Mat prediction = output_probs[3];
// 预测图变mask
cv::Mat mask;
cv::resize(prediction.reshape(1, 416) * 255.0, mask, originalSize, 0, 0, cv::INTER_AREA);
}
auto end = std::chrono::high_resolution_clock::now();
// 计算耗时
std::chrono::durationelapsed=end-start;doubleelapsedTime=elapsed.count();//打印耗时std::cout<< "Elapsed time: " << elapsedTime << " seconds" << std::endl;
return 0;
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
gpu模式下250张图片只用了大约16秒。 假设注释掉与gou相关的代码
net.setPreferableBackend(cv::dnn:NN_BACKEND_CUDA);
net.setPreferableTarget(cv::dnn:NN_TARGET_CUDA);
12
cpu模式下250张图片就用了大约95秒。
总结
尽可能简单、详细的介绍Python和C++下Opencv_GPU调用ONNX模型的流程。
|
|