赞
踩
目录
1,cmake编译opencv+opencv_contrib
③DNN: CUDA backend requires cuDNN. Please resolve dependency or disableOPENCV_DNN_CUDA=OFF
④CONFIGURATION IS NOT SUPPORTED: validate setupvars script in installdirectory
⑤setUpNet DNN module was not built with CUDA backend;
⑦AttributeError: 'Upsample' object has no attribute 'recompute_scale_factor'
windows安装配置opencv opencv_contrib_野马AS的博客-CSDN博客
GitHub大佬opencv dnn加载onnx源码:源码地址
大佬的源码是在Ubuntu上运行的,但是windows上opencv环境配好后也可直接运行。由于第一次装的时候,没有编译cuda,所以只能运行cpu版本,只有5~6fps。且只能运行大佬的onnx模型,自己的yolov5模型用不了。记录一下cuda加速,opencv环境配置,以及opencv dnn调用自己yolov5训练导出生成的onnx。
cuda下载官网:CUDA Toolkit Archive | NVIDIA Developer
cudnn下载官网:cuDNN Archive | NVIDIA Developer
前排提醒:下载之前注意一下cuda和cudnn版本对应,不对应后面会出找不到cudnn的问题。还要注意一下VS和cuda版本,cuda必须是在vs之后出的版本,否则安装cuda会提示检测不到VS,导致VS最后生成解决方案失败,生成不了opencv的dll和lib文件。不过博主由于VS和cuda不对应,我选择的是能对应的cuda11.6.1,cudnn没有出for cuda11.6,就用的最新的11.5,最后报错下载zlip解决。
①选择完版本后,选择网络好的话选择本地下载,网络不好的可以选择网络下载。网络下载优点是包小,缺点是如果安装失败又得重新在安装时下载完整安装包。
安装时,这一步不用选位置,,最后会消失的,好像是临时文件,不是安装文件。后面的cuda toolkit才是安装文件。(疑神疑鬼了好久,为什么cuda文件夹消失了,还重装了两次)
②cuda选择精简安装,如果不报VS的错则直接选择下一步到安装完成,开始cudann安装
②-1,VS报错的情况不要按照网上的别的教程取消勾选Visual Studio Intergration,然后添加文件到cuda路径。我试过,这样的结果是在最后一步生成解决方案失败,然后全部重新来过。我的解决办法是找最新cuda版本以适应我最新的VS2022版本,最后生成解决方案成功。对于cuda版本有要求的,可降低VS版本。 ·
②-2,选择好合适的版本,点击精简安装直接出现下图,则cuda安装,VS的问题就解决了
③安装cuda nn注意对应版本,下载时注意选择zip安装,不要exe安装,cmake编译时找不到cudnn(血坑!!!)
④下载解压后将其中所有文件移到cuda安装目录中,我的路径为:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.5,license也移一下。安装完成
⑤(zip安装好了的朋友跳过这一步)博主后知后觉,重试了几遍,对安装cuda和cudnn文件夹熟悉之后,发现cudnn的exe方式安装的文件在路径C:\Program Files\NVIDIA\CUDNN\v8.3中,如果用的这种安装方式的朋友要做环境变量中添加该路径,则就能检测到cudnn。zip安装方式不用添加。
⑥按照以上步骤,没有报错弄完之后,以博主五六次重试的经验担保,cuda和cudnn已经安装完成。
做了前置环境的,应该比较熟悉这一步,没有做过的可以看看,编译时需要加上cuda。
如果第一次编译没有加上cuda,或者版本对应不对会出现如下报错。
已经装过opencv和opencv_contrib的朋友,需要删除之前的build文件夹,重新编译opencv和opnecv_contrib,也可参考前置环境安装。出现下图则cuda和cudnn编译成功(选项框爆红再次configure即可)。
前面步骤没有出问题的话,这一步不会有问题,不过比较费时间,之前不加cuda生成需要几十分钟,加上cuda需要三四个小时。
源码内容:
- #include <fstream>
-
- #include <opencv2/opencv.hpp>
-
- std::vector<std::string> load_class_list()
- {
- std::vector<std::string> class_list;
- std::ifstream ifs("config_files/classes.txt");
- std::string line;
- while (getline(ifs, line))
- {
- class_list.push_back(line);
- }
- return class_list;
- }
-
- void load_net(cv::dnn::Net &net, bool is_cuda)
- {
- auto result = cv::dnn::readNet("config_files/yolov5s.onnx");
- if (is_cuda)
- {
- std::cout << "Attempty to use CUDA\n";
- result.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
- result.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
- }
- else
- {
- std::cout << "Running on CPU\n";
- result.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
- result.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
- }
- net = result;
- }
-
- const std::vector<cv::Scalar> colors = {cv::Scalar(255, 255, 0), cv::Scalar(0, 255, 0), cv::Scalar(0, 255, 255), cv::Scalar(255, 0, 0)};
-
- const float INPUT_WIDTH = 640.0;
- const float INPUT_HEIGHT = 640.0;
- const float SCORE_THRESHOLD = 0.2;
- const float NMS_THRESHOLD = 0.4;
- const float CONFIDENCE_THRESHOLD = 0.4;
-
- struct Detection
- {
- int class_id;
- float confidence;
- cv::Rect box;
- };
-
- cv::Mat format_yolov5(const cv::Mat &source) {
- int col = source.cols;
- int row = source.rows;
- int _max = MAX(col, row);
- cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
- source.copyTo(result(cv::Rect(0, 0, col, row)));
- return result;
- }
-
- void detect(cv::Mat &image, cv::dnn::Net &net, std::vector<Detection> &output, const std::vector<std::string> &className) {
- cv::Mat blob;
-
- auto input_image = format_yolov5(image);
-
- cv::dnn::blobFromImage(input_image, blob, 1./255., cv::Size(INPUT_WIDTH, INPUT_HEIGHT), cv::Scalar(), true, false);
- net.setInput(blob);
- std::vector<cv::Mat> outputs;
- net.forward(outputs, net.getUnconnectedOutLayersNames());
-
- float x_factor = input_image.cols / INPUT_WIDTH;
- float y_factor = input_image.rows / INPUT_HEIGHT;
-
- float *data = (float *)outputs[0].data;
-
- const int dimensions = 85;
- const int rows = 25200;
-
- std::vector<int> class_ids;
- std::vector<float> confidences;
- std::vector<cv::Rect> boxes;
-
- for (int i = 0; i < rows; ++i) {
-
- float confidence = data[4];
- if (confidence >= CONFIDENCE_THRESHOLD) {
-
- float * classes_scores = data + 5;
- cv::Mat scores(1, className.size(), CV_32FC1, classes_scores);
- cv::Point class_id;
- double max_class_score;
- minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
- if (max_class_score > SCORE_THRESHOLD) {
-
- confidences.push_back(confidence);
-
- class_ids.push_back(class_id.x);
-
- float x = data[0];
- float y = data[1];
- float w = data[2];
- float h = data[3];
- int left = int((x - 0.5 * w) * x_factor);
- int top = int((y - 0.5 * h) * y_factor);
- int width = int(w * x_factor);
- int height = int(h * y_factor);
- boxes.push_back(cv::Rect(left, top, width, height));
- }
-
- }
-
- data += 85;
-
- }
-
- std::vector<int> nms_result;
- cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, nms_result);
- for (int i = 0; i < nms_result.size(); i++) {
- int idx = nms_result[i];
- Detection result;
- result.class_id = class_ids[idx];
- result.confidence = confidences[idx];
- result.box = boxes[idx];
- output.push_back(result);
- }
- }
-
- int main(int argc, char **argv)
- {
-
- std::vector<std::string> class_list = load_class_list();
-
- cv::Mat frame;
- cv::VideoCapture capture("sample.mp4");
- if (!capture.isOpened())
- {
- std::cerr << "Error opening video file\n";
- return -1;
- }
-
- bool is_cuda = argc > 1 && strcmp(argv[1], "cuda") == 0;
-
- cv::dnn::Net net;
- load_net(net, is_cuda);
-
- auto start = std::chrono::high_resolution_clock::now();
- int frame_count = 0;
- float fps = -1;
- int total_frames = 0;
-
- while (true)
- {
- capture.read(frame);
- if (frame.empty())
- {
- std::cout << "End of stream\n";
- break;
- }
-
- std::vector<Detection> output;
- detect(frame, net, output, class_list);
-
- frame_count++;
- total_frames++;
-
- int detections = output.size();
-
- for (int i = 0; i < detections; ++i)
- {
-
- auto detection = output[i];
- auto box = detection.box;
- auto classId = detection.class_id;
- const auto color = colors[classId % colors.size()];
- cv::rectangle(frame, box, color, 3);
-
- cv::rectangle(frame, cv::Point(box.x, box.y - 20), cv::Point(box.x + box.width, box.y), color, cv::FILLED);
- cv::putText(frame, class_list[classId].c_str(), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
- }
-
- if (frame_count >= 30)
- {
-
- auto end = std::chrono::high_resolution_clock::now();
- fps = frame_count * 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
-
- frame_count = 0;
- start = std::chrono::high_resolution_clock::now();
- }
-
- if (fps > 0)
- {
-
- std::ostringstream fps_label;
- fps_label << std::fixed << std::setprecision(2);
- fps_label << "FPS: " << fps;
- std::string fps_label_str = fps_label.str();
-
- cv::putText(frame, fps_label_str.c_str(), cv::Point(10, 25), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 0, 255), 2);
- }
-
- cv::imshow("output", frame);
-
- if (cv::waitKey(1) != -1)
- {
- capture.release();
- std::cout << "finished by user\n";
- break;
- }
- }
-
- std::cout << "Total frames: " << total_frames << "\n";
-
- return 0;
- }
在配有opencv环境的VS项目下,大佬的源码可直接运行,如果上述步骤配置好,则会cuda加速GPU运行;没有配置好,则会cpu运行。GPU是CPU的三倍,感觉opencv的加速还是不够理想,运行起来,GPU并没有消耗太多,最高22fps,最低11fps,平均18fps左右。
运行效果:
①这一步,首先得有自己的模型,避免踩坑提前说一下,下载yolov5 v6.1版本训练的模型导出才能使用。yolov5-6.1版本训练看这篇博客的前面部分。导出onnx模型,yolov5有export.py文件(导出onnx需要下载onnx包),可直接使用导出。yolov5 6.1需注意pytorch版本,我使用时导出onnx模型,还不支持pytorch 1.11,可conda创建一个较低的pytorch版本用于导出。
- #python export文件路径 --weights pt文件路径 --include onnx
- python export.py --weights yolov5s.pt --include onnx
①-1,(更新)随着对yolov5模型理解的加深,明白了之前为什么导出的onnx模型,使用不成功。在我那一版yolov5中,他的模型结构还没有优化完全,output分支有三个,没有整合到一起。而大佬源码处理的是整合到一起的onnx模型,也就是输出为[1.25200,85]的模型。
原来的yolov5 5.0导出onnx模型结构:
现在yolov5 6.1导出的onnx模型结构:
①-2,查看模型结构软件Netron,大力推荐,后续进一步学习必备工具。下载地址
②修改源码
在8行修改为自己的分类txt文件路径。19行修改为自己的模型文件路径,
②-1,110行修改分类,这个85=80 (COCO 数据集的类数) + 1 (confidence) + 4 (xywh),所以你的模型分类为2的话,那么这就改为data+=7。
②-2,132行修改输入流——路径:视频文件;0:电脑自带摄像头;1:usb摄像头;139行选择运行模型的设备为CPU还是GPU,CPU修改红框内容为0,GPU修改红框内容为1。源码这句话是,获取ubuntu命令行运行可执行文件时手动输入cuda的信息,如终端./yolo_example cuda。就会以GPU方式运行。windows运行如果不修改,就会默认cpu加载模型。
③点击运行即可,我使用的是yolov5n的模型,FPS贼高,非常适合移动端的部署。
jetson的ubuntu系统镜像上面自带cuda,所以ubuntu安装cuda的过程就省略了(后续有机会安装,再更新一下)。openc和opencv_contrib的编译安装,由于raw网址的封禁,所以编译的时候往往会编译失败。建议在windows上编译成功了,再复制文件jetson nano上进行编译,这样由于在windows上配置的时候,缺的包已经补齐,所以可一次编译成功。
windows上编译参考前置环境安装.
①windows上编译成功后,新建opencv-4.5.5文件夹(4.5.5为版本信息,根据自己的版本命名),将能够成功编译的opencv中的source中所有文件,移到新建文件夹中。再将能够成功编译的opencv_contrib文件夹移到新建文件夹中。
②然后将这个文件夹拷贝到jetson nano上,在这个文件夹中,新建build文件夹,新建build.sh,用执行build.sh文件的方式,可避免再次编译时重新输入参数的麻烦,也可以记录编译时选择的配置,以后可根据需求增删,重新编译
cd opencv-4.5.5 #打开opencv-4.5.5
mkdir build #新建build文件夹
cd build #打开build
touch build.sh #新建build.sh
chmod 777 build.sh #给build可执行权限,777:给文件所有权限
gedit build.sh #编辑build.sh
③在build.sh中添加cmake编译指令。
- cmake \
- -DCMAKE_BUILD_TYPE=Release \
- -DBUILD_PNG=ON \
- -DBUILD_TIFF=ON \
- -DBUILD_TBB=OFF \
- -DBUILD_JPEG=ON \
- -DBUILD_JASPER=OFF \
- -DBUILD_ZLIB=ON \
- -DBUILD_EXAMPLES=OFF \
- -DBUILD_opencv_java=OFF \
- -DBUILD_opencv_python2=OFF \
- -DBUILD_opencv_python3=ON \ #选择opencv3
- -DENABLE_PRECOMPILED_HEADERS=OFF \
- -DWITH_OPENCL=ON \
- -DWITH_OPENMP=OFF \
- -DWITH_FFMPEG=ON \
- -DWITH_GSTREAMER=ON \
- -DWITH_GSTREAMER_0_10=OFF \
- -DWITH_CUDA=ON \ #链接cuda
- -DWITH_GTK=ON \
- -DWITH_VTK=OFF \
- -DWITH_TBB=ON \
- -DWITH_1394=OFF \
- -DWITH_OPENEXR=OFF \
- -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda \
- -DCUDA_ARCH_BIN=5.3\ #根据自己显卡算力修改,jetson nano为5.3
- -DCUDA_ARCH_PTX="" \
- -DINSTALL_C_EXAMPLES=OFF \
- -DOPENCV_ENABLE_NONFREE=ON \
- -DINSTALL_TESTS=OFF \
- -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib-4.5.5/modules \ #根据自己的版本改
- -DCMAKE_INSTALL_PREFIX=/usr/ \
- ..
-
- make -j4
- sudo make install
-
-
④最后执行build
./build.sh
不使用cuda
git clone https://github.com/doleron/yolov5-opencv-cpp-python.git
cd yolov5-opencv-cpp-python
g++ -O3 cpp/yolo.cpp -o yolo_example `pkg-config --cflags --libs opencv4`
./yolo_example
使用cuda( 且cuda编译成功)
git clone https://github.com/doleron/yolov5-opencv-cpp-python.git
cd yolov5-opencv-cpp-python
g++ -O3 cpp/yolo.cpp -o yolo_example `pkg-config --cflags --libs opencv4`
./yolo_example cuda
git clone https://github.com/doleron/yolov5-opencv-cpp-python.git
cd yolov5-opencv-cpp-python
touch CMakeLists.txt
gedit CMakeLists.txt
在CMakeLists.txt中添加如下内容
- cmake_minimum_required(VERSION 2.8)
-
-
- SET(CMAKE_CXX_STANDARD 11)
-
- PROJECT(yolo_example)
-
- find_package(OpenCV REQUIRED)
-
- include_directories( ${OpenCV_INCLUDE_DIRS} )
-
- add_executable(yolo_example cpp/yolo.cpp)
-
- target_link_libraries(yolo_example ${OpenCV_LIBS})
然后cmake编译执行,生成可执行文件yolo_example
cmake ./
make
cpu运行
./yolo_example
cuda运行
./yolo_example cuda
①yolov5s运行,cpu模式只有零点几帧,cuda模式运行稳定后有3.5帧左右
②yolov5n运行,cpu有1.5帧左右,cuda模式有9.6帧左右。不得不说,yolov5n真的强。
从第一眼看到大佬源码的惊喜,再到加载自己模型始终成功不了的绝望,再到看懂大佬源码进行修改,一步一步学到了很多。不过总感觉深度学习入门,还是配置环境问题,一个模型的训练,到部署需要很多环境才能实现。进一步,就是对算法源码的理解,对模型的理解。目前对于博主来说,关于yolov5这种算法的环境部署大致弄懂。但对模型结构理解还不是很通透,所以使用别人的源码,出了很多问题,不过还好解决问题过程,也是学习的过程。
关于实现github大佬源码有什么问题,欢迎在评论区留言讨论。
ONNX export failure: No module named 'onnx'
解决方法:在环境中下载onnx
解决办法:配置cuda和cudnn
解决办法:正确配置cudnn,在cmake编译时,能在报错框显示cudnn已找到
解决办法:忽略,不用管
解决办法:不懂原理,下载zlib添加环境变量解决。解决办法链接
解决办法:更换yolov5版本,换为yolov5-6.1版本训练导出,导出时注意自己的pytorch版本,pytorch版本<=1.10才行。
解决办法:降低pytorch版本,pytorch版本<=1.10才行。
参考文章
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。