赞
踩
此文为毕设内容的一部分,分为两个大块:(1)YOLO模块 (2) openvino模块
下面分别介绍两个模块的安装流程。
1、环境配置
此次任务我采用的是yolov5算法,代码地址如下:https://github.com/ultralytics/yolov5
首先要把环境配置好,在本机终端输入pip install -r requirements.txt
若在colab则 添加代码块为:
git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt # install
执行即可,至此环境配置完成。
2、数据集构建
(1)在 yolov5目录下 新建文件夹 VOCData(可以自定义命名)
、92
(2)在VOCData下新建两个文件夹 Annotations 以及 images
images:用于存放要标注的图片(jpg格式)
Annotations :用于存放标注图片后产生的内容(这里采用XML格式)
然后使用labellmg进行数据集标注,标注完后会生成XML文件。
(3)在VOCData目录下创建程序 split_train_val.py 并运行
# coding:utf-8 import os import random import argparse parser = argparse.ArgumentParser() #xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下 parser.add_argument('--xml_path', default='Annotations', type=str, help='input xml label path') #数据集的划分,地址选择自己数据下的ImageSets/Main parser.add_argument('--txt_path', default='ImageSets/Main', type=str, help='output txt label path') opt = parser.parse_args() trainval_percent = 1.0 # 训练集和验证集所占比例。 这里没有划分测试集 train_percent = 0.8 # 训练集所占比例,可自己进行调整 xmlfilepath = opt.xml_path txtsavepath = opt.txt_path total_xml = os.listdir(xmlfilepath) if not os.path.exists(txtsavepath): os.makedirs(txtsavepath) num = len(total_xml) list_index = range(num) tv = int(num * trainval_percent) tr = int(tv * train_percent) trainval = random.sample(list_index, tv) train = random.sample(trainval, tr) file_trainval = open(txtsavepath + '/trainval.txt', 'w') file_test = open(txtsavepath + '/test.txt', 'w') file_train = open(txtsavepath + '/train.txt', 'w') file_val = open(txtsavepath + '/val.txt', 'w') for i in list_index: name = total_xml[i][:-4] + '\n' if i in trainval: file_trainval.write(name) if i in train: file_train.write(name) else: file_val.write(name) else: file_test.write(name) file_trainval.close() file_train.close() file_val.close() file_test.close()
运行完毕后 会生成 ImagesSets\Main 文件夹,且在其下生成 测试集、训练集、验证集,存放图片的名字(无后缀.jpg)由于没有分配测试集,所以测试集为空。若要分配,更改第 14、15 行代码,更改所在比例即可。
(4)在VOCData目录下创建程序 text_to_yolo.py 并运行
需要将第 7 行改成自己所标注的类别 以及修改各绝对路径
# -*- coding: utf-8 -*- import xml.etree.ElementTree as ET import os from os import getcwd sets = ['train', 'val', 'test'] classes = ["light", "post"] # 改成自己的类别 abs_path = os.getcwd() print(abs_path) def convert(size, box): dw = 1. / (size[0]) dh = 1. / (size[1]) x = (box[0] + box[1]) / 2.0 - 1 y = (box[2] + box[3]) / 2.0 - 1 w = box[1] - box[0] h = box[3] - box[2] x = x * dw w = w * dw y = y * dh h = h * dh return x, y, w, h def convert_annotation(image_id): in_file = open('D:/Yolov5/yolov5/VOCData/Annotations/%s.xml' % (image_id), encoding='UTF-8') out_file = open('D:/Yolov5/yolov5/VOCData/labels/%s.txt' % (image_id), 'w') tree = ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): difficult = obj.find('difficult').text #difficult = obj.find('Difficult').text cls = obj.find('name').text if cls not in classes or int(difficult) == 1: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) b1, b2, b3, b4 = b # 标注越界修正 if b2 > w: b2 = w if b4 > h: b4 = h b = (b1, b2, b3, b4) bb = convert((w, h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') wd = getcwd() for image_set in sets: if not os.path.exists('D:/Yolov5/yolov5/VOCData/labels/'): os.makedirs('D:/Yolov5/yolov5/VOCData/labels/') image_ids = open('D:/Yolov5/yolov5/VOCData/ImageSets/Main/%s.txt' % (image_set)).read().strip().split() if not os.path.exists('D:/Yolov5/yolov5/VOCData/dataSet_path/'): os.makedirs('D:/Yolov5/yolov5/VOCData/dataSet_path/') list_file = open('dataSet_path/%s.txt' % (image_set), 'w') # 这行路径不需更改,这是相对路径 for image_id in image_ids: list_file.write('D:/Yolov5/yolov5/VOCData/images/%s.jpg\n' % (image_id)) convert_annotation(image_id) list_file.close()
运行后会生成如下 labels 文件夹和 dataSet_path 文件夹。
其中 labels 中为不同图像的标注文件。每个图像对应一个txt文件,文件每一行为一个目标的信息,包括class, x_center, y_center, width, height格式,这种即为 yolo_txt格式
dataSet_path文件夹包含三个数据集的txt文件,train.txt等txt文件为划分后图像所在位置的路径,如train.txt就含有所有训练集图像的路径。
3、配置yaml文件
在 yolov5 目录下的 data 文件夹下 新建一个 myvoc.yaml文件(可以自定义命名),用记事本打开。
内容是:
训练集以及验证集(train.txt和val.txt)的路径(可以改为相对路径)
以及 目标的类别数目和类别名称。
还需要在model文件夹中,选择一个自己需要的模型,我这里选择的是yolov5s,把nc改成自己所标注的类别 nc = 1
4、训练
然后运行train.py即可。注意train.py中的参数。
weights:权重文件路径
cfg:存储模型结构的配置文件.
data:存储训练、测试数据的文件
epochs:指的就是训练过程中整个数据集将被迭代(训练)了多少次
batch-size:训练完多少张图片才进行权重更新,显卡不行就调小点。
img-size:输入图片宽高,显卡不行就调小点。
device:cuda device, i.e. 0 or 0,1,2,3 or cpu。选择使用GPU还是CPU
workers:线程数。默认是8。
修改自己参数和文件路径后在运行即可。
训练后得到best.pt模型,采用以下命令运行
python detect.py --weights runs/train/exp/weights/best.pt --source …/data/0001.png
source后接需要检测的图片、文件夹、视频等。我们在此还可以先把pt模型转换成onnx模型,直接运行export.py文件,需要改路径如下
选择所需要的模型onnx 后面openvino会用到
转换完成后会有best.onnx模型文件。至此yolo可以告一段落。
主要步骤有:
https://visualstudio.microsoft.com/zh-hans/downloads/
2.2下载并解压 OpenVINO Runtime
OpenVINO™ Runtime 2022.3 以压缩包(OpenVINO Archives)的形式提供,里面包含了开发 OpenVINO C++ 推理程序所必需的文件首先,打开下面的链接,下载 OpenVINO™ Runtime 2022.3 压缩包:
https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/download.html
然后,手动新建 C:\Program Files (x86)\Intel\openvino_2022.3.0 文件夹,并把压缩包解压后的文件拷贝到 openvino_2022.3.0 文件夹中,完成OpenVINO Runtime 压缩包的下载和解压工作,如图
2.3下载并解压 OpenCV
OpenCV 也是以压缩包的形式提供,从下方地址下载 Windows 平台上的压缩包:
https://opencv.org/releases/
首先,手动新建 C:\opencv 文件夹;然后,把 OpenCV 解压后的 build 文件夹全部拷贝到 C:\opencv 文件夹,如图 所示,完成 OpenCV 的下载并解压2.4在 Visual Studio 中配置项目属性
在 Visual Studio 中配置项目属性,主要是告诉 C++ 编译器和链接器,OpenVINO™ 和 OpenCV 的头文件以及库文件在哪里。
第一步,打开 Visual Studio,在“文件(F)”菜单中选择“新建(N)→项目§”,新建一个 C++ 空项目。
第二步,在“文件(F)菜单”中选择“新建(N)→文件(F)”,新建一个 main.cpp 文件,并添加到项目管理器的源文件文件夹中。
第三步,在“解决方案资源管理器”中,右键单击项目名称,在右键菜单中选择“属性®”,启动“属性页”对话框。
在“配置”栏选择“所有配置”,在“平台§”栏选择“所有平台”;
在“输出目录”输入
“$(SolutionDir)bin$(Platform)$(Configuration)\”;
在“中间目录”输入
“$(SolutionDir)Intermediate$(Platform)$(Configuration)\”
第四步,在“属性页”对话框中选中“C/C++→常规”;在“平台§”栏选择“x64”;在“附加包含目录”中输入:
C:\Program Files (x86)\Intel\openvino_2022.3.0\runtime\include
C:\opencv\build\include
第五步,在“属性页”对话框中选中“链接器→常规”;在“平台§”栏选择“x64”;在“附加库目录”中输入:
C:\Program Files (x86)\Intel\openvino_2022.3.0\runtime\lib\intel64$(Configuration)
C:\opencv\build\x64\vc16\lib
此处路径要具体看自己的解压位置和bin位置,并不唯一,文中写的只是我的路径。
第六步,在“属性页”对话框中选中“链接器→输入”,在“配置©”栏选择“Debug”,在“平台§”栏选择“x64”,然后在“附加依赖项”中添加:
openvinod.lib;opencv_world470d.lib;
将“配置”栏改为“Release”,然后在“附加依赖项”中添加:
openvino.lib;opencv_world470.lib;
此处也要看自己的C:\opencv\build\x64\vc16\lib(也有可能是x64\vc15\lib)路径下的文件名,不可一股脑复制 比如别人此路径下就为opencv_world3415 所以附加项依赖要改成3415.lib。
到此,完成在 Visual Studio 中配置 OpenVINO C++ 推理计算项目属性。
2.51.5 运行 OpenVINO C++ 范例程序
注意此代码中有图片路径需修改
#include <iostream> #include <string> #include <openvino/openvino.hpp> //openvino header file #include <opencv2/opencv.hpp> //opencv header file int main(int argc, char* argv[]) { // -------- Get OpenVINO runtime version -------- std::cout << ov::get_openvino_version().description << ':' << ov::get_openvino_version().buildNumber << std::endl; // -------- Step 1. Initialize OpenVINO Runtime Core -------- ov::Core core; // -------- Step 2. Get list of available devices -------- std::vector<std::string> availableDevices = core.get_available_devices(); // -------- Step 3. Query and print supported metrics and config keys -------- std::cout << "Available devices: " << std::endl; for (auto&& device : availableDevices) { std::cout << device << std::endl; } // -------- Step 4. Read a picture file and show by OpenCV -------- cv::Mat img = cv::imread("zidane.jpg"); //Load a picture into memory cv::imshow("Test OpenVINO & OpenCV IDE", img); std::cout << "Image width: " << img.cols << " height: " << img.rows << std::endl; cv::waitKey(0); cv::destroyAllWindows(); return 0; }
运行后得到
表示环境配置完成。
在这里直接给出代码
#include <openvino/openvino.hpp> #include <opencv2/opencv.hpp> using namespace std; using namespace ov; using namespace cv; // 数据集的标签 vector<string> class_names = { "bad" }; //模型文件路径 string model_file = "D:/yolov5_master/best.onnx"; //测试图片路径 string image_file = "D:/yolov5_master/00036.png"; int main(int argc, char** argv) { //1.创建OpenVINO Runtime Core对象 Core core; //2.载入并编译模型 CompiledModel compiled_model = core.compile_model(model_file, "GPU"); //3.创建推理请求 InferRequest infer_request = compiled_model.create_infer_request(); //4.设置模型输入 //4.1 获取模型输入节点形状 Tensor input_node = infer_request.get_input_tensor(); Shape tensor_shape = input_node.get_shape(); //4.2读取图片并按照模型输入要求进行预处理 Mat frame = imread(image_file, IMREAD_COLOR); //Lettterbox resize is the default resize method in YOLOv5. int w = frame.cols; int h = frame.rows; int _max = max(h, w); Mat image = Mat::zeros(Size(_max, _max), CV_8UC3); Rect roi(0, 0, w, h); frame.copyTo(image(roi)); //交换RB通道 cvtColor(image, image, COLOR_BGR2RGB); //计算缩放因子 size_t num_channels = tensor_shape[1]; size_t height = tensor_shape[2]; size_t width = tensor_shape[3]; float x_factor = image.cols / width; float y_factor = image.rows / height; int64 start = cv::getTickCount(); //缩放图片并归一化 Mat blob_image; resize(image, blob_image, cv::Size(width, height)); blob_image.convertTo(blob_image, CV_32F); blob_image = blob_image / 255.0; // 4.3 将图像数据填入input tensor Tensor input_tensor = infer_request.get_input_tensor(); // 获取指向模型输入节点数据块的指针 float* input_tensor_data = input_tensor.data<float>(); // 将图片数据填充到模型输入节点中 // 原有图片数据为 HWC格式,模型输入节点要求的为 CHW 格式 for (size_t c = 0; c < num_channels; c++) { for (size_t h = 0; h < height; h++) { for (size_t w = 0; w < width; w++) { input_tensor_data[c * width * height + h * width + w] = blob_image.at<Vec<float, 3>>(h, w)[c]; } } } // 5.执行推理计算 infer_request.infer(); // 6.处理推理计算结果 // 6.1 获得推理结果 const ov::Tensor& output = infer_request.get_tensor("output0"); const float* output_buffer = output.data<const float>(); // 6.2 解析推理结果,YOLOv5 output format: cx,cy,w,h,score int out_rows = output.get_shape()[1]; //获得"output"节点的rows int out_cols = output.get_shape()[2]; //获得"output"节点的cols Mat det_output(out_rows, out_cols, CV_32F, (float*)output_buffer); vector<cv::Rect> boxes; vector<int> classIds; vector<float> confidences; for (int i = 0; i < det_output.rows; i++) { float confidence = det_output.at<float>(i, 4); if (confidence < 0.5) { continue; } Mat classes_scores = det_output.row(i).colRange(0, 2); Point classIdPoint; double score; minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint); // 置信度 0~1之间 if (score > 0.5) { float cx = det_output.at<float>(i, 0); float cy = det_output.at<float>(i, 1); float ow = det_output.at<float>(i, 2); float oh = det_output.at<float>(i, 3); int x = static_cast<int>((cx - 0.5 * ow) * x_factor); int y = static_cast<int>((cy - 0.5 * oh) * y_factor); int width = static_cast<int>(ow * x_factor); int height = static_cast<int>(oh * y_factor); Rect box; box.x = x; box.y = y; box.width = width; box.height = height; boxes.push_back(box); classIds.push_back(classIdPoint.x); confidences.push_back(score); } } // NMS vector<int> indexes; dnn::NMSBoxes(boxes, confidences, 0.25, 0.45, indexes); for (size_t i = 0; i < indexes.size(); i++) { int index = indexes[i]; int idx = classIds[index]; rectangle(frame, boxes[index], Scalar(0, 0, 255), 2, 8); rectangle(frame, Point(boxes[index].tl().x, boxes[index].tl().y - 20), Point(boxes[index].br().x, boxes[index].tl().y), Scalar(0, 255, 255), -1); putText(frame, class_names[idx], Point(boxes[index].tl().x, boxes[index].tl().y - 10), FONT_HERSHEY_SIMPLEX, .5, Scalar(0, 0, 0)); } // 计算FPS float t = (getTickCount() - start) / static_cast<float>(getTickFrequency()); cout << "Infer time(ms): " << t * 1000 << "ms; Detections: " << indexes.size() << endl; putText(frame, format("FPS: %.2f", 1.0 / t), Point(20, 40), FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 0), 2, 8); imshow("YOLOv5-6.1 + OpenVINO 2022.1 C++ Demo", frame); waitKey(0); destroyAllWindows(); return 0; }
运行后得到结果
onnx模型经过剪枝后可得到IR模型,因笔者能力有限,IR模型暂未调试成功,希望后续会取得进步。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。