1. Introduction
Pytorch+yolov5 detects that the onnx model is detected, and finally the IR file is deployed to openvino for detection. Openvino accelerates the detection to achieve a target detection rate of more than 30 frames without using a video card.
2. Install yolov5
Installation method reference link: https://blog.csdn.net/qq_54496810/article/details/121760261
3. Configuring the Python environment
How to install Anaconda? Many bloggers have published tutorials on the Internet, so I won't repeat them here;
(1) Open Anaconda Prompt in the start interface
(2) . Input command:
conda create -n Pytorch python=3.7
Considering the version conflict between some codes and libraries, the recommended python version in this process is 3.7. You can name the environment by modifying the content name after - n, such as the above command to name the environment as python.
After that, proceed (Y/[n]) will appear on the command line. Enter y and wait for the environment installation to complete.
3. Install PyTorch
First, activate the environment just created, and enter the following command under prompt
conda activate Pytorch(Self prepared environment name)
We need to get the installation command on the official website: https://pytorch.org/
After entering, scroll down the scroll wheel to find the installation path. Here we choose an older version to prevent various errors
This command is shown below. The note in the following figure can be ignored, because the version we use does not need to consider those situations. This command needs to be run in the newly established Python environment:
conda install pytorch torchvision torchaudio cudatoolkit=11.1 -c pytorch-lts -c conda-forge
After installation, you can check whether the installation is successful. Enter the following command on the command line
python import torch print(torch.cuda.is_available())
If it is True, the installation is successful
In general, if False occurs, it is usually because the version is too new. The new version is sometimes like this. I tried to install the 11.2 pytorch and 11.6 CUDA before. Running the command many times means that I did not install it. That is, the running result of the above command is False
4. Configure to Pycharm
(1) , Open Pycharm
(2) . Open File – Settings
(3) Open the environment configuration interface
Open project: xxx – Python Interpreter – Settings (that gear) – Add
(4) . Join the environment
Select Conda Environment – Existing environment – Interpreter. The path selection format of the Interpreter is (anaconda root directory/envs/Python (custom environment name)/python.exe). Press OK after the selection
(5) . Set the environment to Python
Set Interpreter to the environment added just now in the lower right corner of Pycharm
That's the end of it
4. pt model to onnx model
(1) . Install the openvino tool
Installation of official website: https://www.intel.com/content/www/us/en/developer/tools/openvino-toolkit/download.html
I see that many people on the Internet want others to follow the instructions of the official website, but according to my experience on the official website, I still want to say how to install. First, Dev tools and Runtime should be installed. The first one is needed to convert the onnx model to the IR model. The last one is an indispensable component for running IR files. Dev tools are installed offline, and Runtime is executed with the pip install command:
First is Dev tool, whose selected components are as follows:
Install it as 2021.4.2, or strange errors will appear;
Click Download to install the installation package:
After running the installation package, you don't need to change the installation path during the installation process, because this installation package can't change the installation path, and it doesn't take up much space, so it has little impact on disk C. Don't worry about it. The default installation path is C: Program Files (x86) Intel
Next is the Runtime tool, whose selection components are as follows:
It is also version 2021.04.02. If you continue to pull it down, there will be an installation command
Instructions are run in their own built environment
Add: If there are still errors in the later operation, you can try to add environment variables. For the name and content of environment variables, refer to the following link:
https://www.intel.sg/content/www/xa/en/support/articles/000033440/software/development-software.html
(2) , converting onnx files
In this case, because we use yolov5, we don't need so many troublesome steps to convert the onnx model. We just need to run the export that comes with yolov5 The py function can be converted. Here we change the default parameter in the code in line 567 to ROOT/'the location of our pt model', and then run the code to generate the onnx model in the yolov5 root directory
The average detection time of each frame is 0.15 s (150 ms)
(3) Running the onnx model
Although this is not our ultimate goal, we can also take a look at the running effect of this model The py function modifies the parameters. The default parameter in line 213 is changed to ROOT/'Position of the onnx model converted into ', and the default parameter in line 214 is changed from ROOT/'data/images' to ROOT/'0'. The significance of the latter modification is that the camera can be called. After running, it will be found that the reasoning time is twice as fast as that of the pt model, and the average detection time of each frame is 0.075s(75ms)
5. Conversion of onnx model to IR model
(1) Use the netron web app to view the node information of the onnx model
The website is as follows: https://netron.app/
(2) . Open the converted onnx model
Pull it to a very low position, as shown in the figure
Click three Conv nodes, and a pop-up window will pop up on the right side. Write down the information of the three nodes, the position of the red circle, and the information of the three nodes
(3) . Convert to IR model
In Dev tool, mo Run the instruction conversion IR model in the py function. Here I give the instruction with the yolov5 as an example. This instruction needs to be cd to the location of the mo function in the environment you installed. It is C: Program Files (x86) Intel openvino_ 2021\deployment_ tools\model_ Optimizer, and then run the instruction
python mo.py --input_model C:\Users\11408\yolov5\yolov5s.onnx -s 255 --reverse_input_channels --output_dir C:\Users\11408\yolov5 --output Conv_201,Conv_220,Conv_239
The two path locations correspond to their own onnx file locations and the locations where IR files are saved. The last three Conv of the command are the three node names just recorded
You can find the generated IR file in the yolov5 root directory (the IR file is essentially a file with bin, mapping, and xml as suffixes), as shown in the figure:
6. Deploy IR files to openvino
This process requires adding a new function, yolo, to the folder of yolov5_ openvino_ demo.py
Code source: https://raychiu.blog.csdn.net/article/details/121300602
The code is as follows:
#!/usr/bin/env python """ Copyright (C) 2018-2019 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from __future__ import print_function, division import logging import os import sys from argparse import ArgumentParser, SUPPRESS from time import time import cv2 import ngraph import numpy as np from openvino.inference_engine import IENetwork, IECore logging.basicConfig(format="[ %(levelname)s ] %(message)s", level=logging.INFO, stream=sys.stdout) log = logging.getLogger() def build_argparser(): parser = ArgumentParser(add_help=False) args = parser.add_argument_group('Options') args.add_argument('-h', '--help', action='help', default=SUPPRESS, help='Show this help message and exit.') args.add_argument("-m", "--model", default="yolov5s.xml",help="Required. Path to an .xml file with a trained model.", required=False, type=str) args.add_argument("-at", "--architecture_type",default="yolov5", help='Required. Specify model\' architecture type.', type=str, required=False, choices=('yolov3', 'yolov4', 'yolov5', 'yolov4-p5', 'yolov4-p6', 'yolov4-p7')) args.add_argument("-i", "--input",default=".0", help="Required. Path to an image/video file. (Specify 'cam' to work with " "camera)", required=False, type=str) args.add_argument("-l", "--cpu_extension", help="Optional. Required for CPU custom layers. Absolute path to a shared library with " "the kernels implementations.", type=str, default=None) args.add_argument("-d", "--device", help="Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL or MYRIAD is" " acceptable. The sample will look for a suitable plugin for device specified. " "Default value is CPU", default="CPU", type=str) args.add_argument("--labels", help="Optional. Labels mapping file", default=None, type=str) args.add_argument("-t", "--prob_threshold", help="Optional. Probability threshold for detections filtering", default=0.5, type=float) args.add_argument("-iout", "--iou_threshold", help="Optional. Intersection over union threshold for overlapping " "detections filtering", default=0.4, type=float) args.add_argument("-ni", "--number_iter", help="Optional. Number of inference iterations", default=1, type=int) args.add_argument("-pc", "--perf_counts", help="Optional. Report performance counters", default=False, action="store_true") args.add_argument("-r", "--raw_output_message", help="Optional. Output inference results raw values showing", default=False, action="store_true") args.add_argument("--no_show", help="Optional. Don't show output", action='store_true') return parser class YoloParams: # ------------------------------------------- Extracting layer parameters ------------------------------------------ # Magic numbers are copied from yolo samples def __init__(self, param, side, yolo_type): self.coords = 4 if 'coords' not in param else int(param['coords']) self.classes = 80 if 'classes' not in param else int(param['classes']) self.side = side if yolo_type == 'yolov4': self.num = 3 self.anchors = [12.0, 16.0, 19.0, 36.0, 40.0, 28.0, 36.0, 75.0, 76.0, 55.0, 72.0, 146.0, 142.0, 110.0, 192.0, 243.0, 459.0, 401.0] elif yolo_type == 'yolov4-p5': self.num = 4 self.anchors = [13.0, 17.0, 31.0, 25.0, 24.0, 51.0, 61.0, 45.0, 48.0, 102.0, 119.0, 96.0, 97.0, 189.0, 217.0, 184.0, 171.0, 384.0, 324.0, 451.0, 616.0, 618.0, 800.0, 800.0] elif yolo_type == 'yolov4-p6': self.num = 4 self.anchors = [13.0, 17.0, 31.0, 25.0, 24.0, 51.0, 61.0, 45.0, 61.0, 45.0, 48.0, 102.0, 119.0, 96.0, 97.0, 189.0, 97.0, 189.0, 217.0, 184.0, 171.0, 384.0, 324.0, 451.0, 324.0, 451.0, 545.0, 357.0, 616.0, 618.0, 1024.0, 1024.0] elif yolo_type == 'yolov4-p7': self.num = 5 self.anchors = [13.0, 17.0, 22.0, 25.0, 27.0, 66.0, 55.0, 41.0, 57.0, 88.0, 112.0, 69.0, 69.0, 177.0, 136.0, 138.0, 136.0, 138.0, 287.0, 114.0, 134.0, 275.0, 268.0, 248.0, 268.0, 248.0, 232.0, 504.0, 445.0, 416.0, 640.0, 640.0, 812.0, 393.0, 477.0, 808.0, 1070.0, 908.0, 1408.0, 1408.0] else: self.num = 3 self.anchors = [10.0, 13.0, 16.0, 30.0, 33.0, 23.0, 30.0, 61.0, 62.0, 45.0, 59.0, 119.0, 116.0, 90.0, 156.0, 198.0, 373.0, 326.0] def log_params(self): params_to_print = {'classes': self.classes, 'num': self.num, 'coords': self.coords, 'anchors': self.anchors} [log.info(" {:8}: {}".format(param_name, param)) for param_name, param in params_to_print.items()] def letterbox(img, size=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True): # Resize image to a 32-pixel-multiple rectangle https://github.com/ultralytics/yolov3/issues/232 shape = img.shape[:2] # current shape [height, width] w, h = size # Scale ratio (new / old) r = min(h / shape[0], w / shape[1]) if not scaleup: # only scale down, do not scale up (for better test mAP) r = min(r, 1.0) # Compute padding ratio = r, r # width, height ratios new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh = w - new_unpad[0], h - new_unpad[1] # wh padding if auto: # minimum rectangle dw, dh = np.mod(dw, 64), np.mod(dh, 64) # wh padding elif scaleFill: # stretch dw, dh = 0.0, 0.0 new_unpad = (w, h) ratio = w / shape[1], h / shape[0] # width, height ratios dw /= 2 # divide padding into 2 sides dh /= 2 if shape[::-1] != new_unpad: # resize img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border top2, bottom2, left2, right2 = 0, 0, 0, 0 if img.shape[0] != h: top2 = (h - img.shape[0]) // 2 bottom2 = top2 img = cv2.copyMakeBorder(img, top2, bottom2, left2, right2, cv2.BORDER_CONSTANT, value=color) # add border elif img.shape[1] != w: left2 = (w - img.shape[1]) // 2 right2 = left2 img = cv2.copyMakeBorder(img, top2, bottom2, left2, right2, cv2.BORDER_CONSTANT, value=color) # add border return img def scale_bbox(x, y, height, width, class_id, confidence, im_h, im_w, resized_im_h=640, resized_im_w=640): gain = min(resized_im_w / im_w, resized_im_h / im_h) # gain = old / new pad = (resized_im_w - im_w * gain) / 2, (resized_im_h - im_h * gain) / 2 # wh padding x = int((x - pad[0]) / gain) y = int((y - pad[1]) / gain) w = int(width / gain) h = int(height / gain) xmin = max(0, int(x - w / 2)) ymin = max(0, int(y - h / 2)) xmax = min(im_w, int(xmin + w)) ymax = min(im_h, int(ymin + h)) # Method item() used here to convert NumPy types to native types for compatibility with functions, which don't # support Numpy types (e.g., cv2.rectangle doesn't support int64 in color parameter) return dict(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, class_id=class_id.item(), confidence=confidence.item()) def entry_index(side, coord, classes, location, entry): side_power_2 = side ** 2 n = location // side_power_2 loc = location % side_power_2 return int(side_power_2 * (n * (coord + classes + 1) + entry) + loc) def parse_yolo_region(blob, resized_image_shape, original_im_shape, params, threshold, yolo_type): # ------------------------------------------ Validating output parameters ------------------------------------------ global idx out_blob_n, out_blob_c, out_blob_h, out_blob_w = blob.shape predictions = 1.0 / (1.0 + np.exp(-blob)) assert out_blob_w == out_blob_h, "Invalid size of output blob. It sould be in NCHW layout and height should " \ "be equal to width. Current height = {}, current width = {}" \ "".format(out_blob_h, out_blob_w) # ------------------------------------------ Extracting layer parameters ------------------------------------------- orig_im_h, orig_im_w = original_im_shape resized_image_h, resized_image_w = resized_image_shape objects = list() side_square = params.side[1] * params.side[0] # ------------------------------------------- Parsing YOLO Region output ------------------------------------------- bbox_size = int(out_blob_c / params.num) # 4+1+num_classes # print('bbox_size = ' + str(bbox_size)) # print('bbox_size = ' + str(bbox_size)) for row, col, n in np.ndindex(params.side[0], params.side[1], params.num): bbox = predictions[0, n * bbox_size:(n + 1) * bbox_size, row, col] x, y, width, height, object_probability = bbox[:5] class_probabilities = bbox[5:] if object_probability < threshold: continue # print('resized_image_w = ' + str(resized_image_w)) # print('out_blob_w = ' + str(out_blob_w)) x = (2 * x - 0.5 + col) * (resized_image_w / out_blob_w) y = (2 * y - 0.5 + row) * (resized_image_h / out_blob_h) if int(resized_image_w / out_blob_w) == 8 & int(resized_image_h / out_blob_h) == 8: # 80x80, idx = 0 elif int(resized_image_w / out_blob_w) == 16 & int(resized_image_h / out_blob_h) == 16: # 40x40 idx = 1 elif int(resized_image_w / out_blob_w) == 32 & int(resized_image_h / out_blob_h) == 32: # 20x20 idx = 2 elif int(resized_image_w / out_blob_w) == 64 & int(resized_image_h / out_blob_h) == 64: # 20x20 idx = 3 elif int(resized_image_w / out_blob_w) == 128 & int(resized_image_h / out_blob_h) == 128: # 20x20 idx = 4 if yolo_type == 'yolov4-p5' or yolo_type == 'yolov4-p6' or yolo_type == 'yolov4-p7': width = (2 * width) ** 2 * params.anchors[idx * 8 + 2 * n] height = (2 * height) ** 2 * params.anchors[idx * 8 + 2 * n + 1] else: width = (2 * width) ** 2 * params.anchors[idx * 6 + 2 * n] height = (2 * height) ** 2 * params.anchors[idx * 6 + 2 * n + 1] class_id = np.argmax(class_probabilities * object_probability) confidence = class_probabilities[class_id] * object_probability objects.append(scale_bbox(x=x, y=y, height=height, width=width, class_id=class_id, confidence=confidence, im_h=orig_im_h, im_w=orig_im_w, resized_im_h=resized_image_h, resized_im_w=resized_image_w)) return objects def intersection_over_union(box_1, box_2): width_of_overlap_area = min(box_1['xmax'], box_2['xmax']) - max(box_1['xmin'], box_2['xmin']) height_of_overlap_area = min(box_1['ymax'], box_2['ymax']) - max(box_1['ymin'], box_2['ymin']) if width_of_overlap_area < 0 or height_of_overlap_area < 0: area_of_overlap = 0 else: area_of_overlap = width_of_overlap_area * height_of_overlap_area box_1_area = (box_1['ymax'] - box_1['ymin']) * (box_1['xmax'] - box_1['xmin']) box_2_area = (box_2['ymax'] - box_2['ymin']) * (box_2['xmax'] - box_2['xmin']) area_of_union = box_1_area + box_2_area - area_of_overlap if area_of_union == 0: return 0 return area_of_overlap / area_of_union def main(): global frame, det_time, next_frame args = build_argparser().parse_args() model_xml = args.model model_bin = os.path.splitext(model_xml)[0] + ".bin" # ------------- 1. Plugin initialization for specified device and load extensions library if specified ------------- log.info("Creating Inference Engine...") ie = IECore() if args.cpu_extension and 'CPU' in args.device: ie.add_extension(args.cpu_extension, "CPU") # -------------------- 2. Reading the IR generated by the Model Optimizer (.xml and .bin files) -------------------- log.info("Loading network files:\n\t{}\n\t{}".format(model_xml, model_bin)) net = IENetwork(model = model_xml, weights = model_bin) # ---------------------------------- 3. Load CPU extension for support specific layer ------------------------------ # if "CPU" in args.device: # supported_layers = ie.query_network(net, "CPU") # not_supported_layers = [l for l in net.layers.keys() if l not in supported_layers] # if len(not_supported_layers) != 0: # log.error("Following layers are not supported by the plugin for specified device {}:\n {}". # format(args.device, ', '.join(not_supported_layers))) # log.error("Please try to specify cpu extensions library path in sample's command line parameters using -l " # "or --cpu_extension command line argument") # sys.exit(1) # # assert len(net.inputs.keys()) == 1, "Sample supports only YOLO V3 based single input topologies" # ---------------------------------------------- 4. Preparing inputs ----------------------------------------------- log.info("Preparing inputs") input_blob = next(iter(net.inputs)) # Defaulf batch_size is 1 net.batch_size = 1 # Read and pre-process input images n, c, h, w = net.inputs[input_blob].shape ng_func = ngraph.function_from_cnn(net) yolo_layer_params = {} for node in ng_func.get_ordered_ops(): layer_name = node.get_friendly_name() if layer_name not in net.outputs: continue shape = list(node.inputs()[0].get_source_output().get_node().shape) yolo_params = YoloParams(node._get_attributes(), shape[2:4], args.architecture_type) yolo_layer_params[layer_name] = (shape, yolo_params) if args.labels: with open(args.labels, 'r') as f: labels_map = [x.strip() for x in f] else: labels_map = None input_stream = 0 if args.input == "cam" else args.input is_async_mode = True cap = cv2.VideoCapture(0) number_input_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) number_input_frames = 1 if number_input_frames != -1 and number_input_frames < 0 else number_input_frames wait_key_code = 1 # Number of frames in picture is 1 and this will be read in cycle. Sync mode is default value for this case if number_input_frames != 1: ret, frame = cap.read() else: is_async_mode = False wait_key_code = 0 # ----------------------------------------- 5. Loading model to the plugin ----------------------------------------- log.info("Loading model to the plugin") exec_net = ie.load_network(network=net, num_requests=2, device_name=args.device) cur_request_id = 0 next_request_id = 1 render_time = 0 parsing_time = 0 # ----------------------------------------------- 6. Doing inference ----------------------------------------------- log.info("Starting inference...") print("To close the application, press 'CTRL+C' here or switch to the output window and press ESC key") print("To switch between sync/async modes, press TAB key in the output window") while cap.isOpened(): # Here is the first asynchronous point: in the Async mode, we capture frame to populate the NEXT infer request # in the regular mode, we capture frame to the CURRENT infer request if is_async_mode: ret, next_frame = cap.read() else: ret, frame = cap.read() if not ret: break if is_async_mode: request_id = next_request_id in_frame = letterbox(frame, (w, h)) else: request_id = cur_request_id in_frame = letterbox(frame, (w, h)) # resize input_frame to network size in_frame = in_frame.transpose((2, 0, 1)) # Change data layout from HWC to CHW in_frame = in_frame.reshape((n, c, h, w)) # Start inference start_time = time() exec_net.start_async(request_id=request_id, inputs={input_blob: in_frame}) # Collecting object detection results objects = list() if exec_net.requests[cur_request_id].wait(-1) == 0: det_time = time() - start_time output = exec_net.requests[cur_request_id].outputs start_time = time() for layer_name, out_blob in output.items(): # out_blob = out_blob.reshape(net.layers[layer_name].out_data[0].shape) layer_params = yolo_layer_params[ layer_name] # YoloParams(net.layers[layer_name].params, out_blob.shape[2]) out_blob.shape = layer_params[0] # log.info("Layer {} parameters: ".format(layer_name)) # layer_params.log_params() objects += parse_yolo_region(out_blob, in_frame.shape[2:], # in_frame.shape[2:], layer_params, frame.shape[:-1], layer_params[1], args.prob_threshold, args.architecture_type) parsing_time = time() - start_time # Filtering overlapping boxes with respect to the --iou_threshold CLI parameter objects = sorted(objects, key=lambda obj: obj['confidence'], reverse=True) for i in range(len(objects)): if objects[i]['confidence'] == 0: continue for j in range(i + 1, len(objects)): if objects[i]['class_id'] != objects[j]['class_id']: # Only compare bounding box with same class id continue if intersection_over_union(objects[i], objects[j]) > args.iou_threshold: objects[j]['confidence'] = 0 # Drawing objects with respect to the --prob_threshold CLI parameter objects = [obj for obj in objects if obj['confidence'] >= args.prob_threshold] if len(objects) and args.raw_output_message: log.info("\nDetected boxes for batch {}:".format(1)) log.info(" Class ID | Confidence | XMIN | YMIN | XMAX | YMAX | COLOR ") origin_im_size = frame.shape[:-1] for obj in objects: # Validation bbox of detected object if obj['xmax'] > origin_im_size[1] or obj['ymax'] > origin_im_size[0] or obj['xmin'] < 0 or obj['ymin'] < 0: continue color = (int(min(obj['class_id'] * 12.5, 255)), min(obj['class_id'] * 7, 255), min(obj['class_id'] * 5, 255)) det_label = labels_map[obj['class_id']] if labels_map and len(labels_map) >= obj['class_id'] else \ str(obj['class_id']) if args.raw_output_message: log.info( "{:^9} | {:10f} | {:4} | {:4} | {:4} | {:4} | {} ".format(det_label, obj['confidence'], obj['xmin'], obj['ymin'], obj['xmax'], obj['ymax'], color)) cv2.rectangle(frame, (obj['xmin'], obj['ymin']), (obj['xmax'], obj['ymax']), color, 2) cv2.putText(frame, "#" + det_label + ' ' + str(round(obj['confidence'] * 100, 1)) + ' %', (obj['xmin'], obj['ymin'] - 7), cv2.FONT_HERSHEY_COMPLEX, 0.6, color, 1) # Draw performance stats over frame inf_time_message = "Inference time: N\A for async mode" if is_async_mode else \ "Inference time: {:.3f} ms".format(det_time * 1e3) render_time_message = "OpenCV rendering time: {:.3f} ms".format(render_time * 1e3) async_mode_message = "Async mode is on. Processing request {}".format(cur_request_id) if is_async_mode else \ "Async mode is off. Processing request {}".format(cur_request_id) parsing_message = "YOLO parsing time is {:.3f} ms".format(parsing_time * 1e3) cv2.putText(frame, inf_time_message, (15, 15), cv2.FONT_HERSHEY_COMPLEX, 0.5, (200, 10, 10), 1) cv2.putText(frame, render_time_message, (15, 45), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1) cv2.putText(frame, async_mode_message, (10, int(origin_im_size[0] - 20)), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1) cv2.putText(frame, parsing_message, (15, 30), cv2.FONT_HERSHEY_COMPLEX, 0.5, (10, 10, 200), 1) start_time = time() if not args.no_show: cv2.imshow("DetectionResults", frame) render_time = time() - start_time if is_async_mode: cur_request_id, next_request_id = next_request_id, cur_request_id frame = next_frame if not args.no_show: key = cv2.waitKey(wait_key_code) # ESC key if key == 27: break # Tab key if key == 9: exec_net.requests[cur_request_id].wait() is_async_mode = not is_async_mode log.info("Switched to {} mode".format("async" if is_async_mode else "sync")) cv2.destroyAllWindows() if __name__ == '__main__': sys.exit(main() or 0)
You need to change the default in line 35 to the location of your own xml file
7. Detection effect
I will not show my handsome face here. The natural detection effect is very good, which is twice as fast as the previous one. The average detection time of each frame is 0.035s (35ms). According to the calculation, the average frame rate has reached 30 frames (frame rate=1000ms/detection time of each frame)
8. Expansion
(1) When converting the onnx model, the converted onnx model can be simplified. This simplified model has better detection effect than the original model, and can also optimize the later converted IR model. The method is as follows:
① . Install onnx simplifier
pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com/simple onnx-simplifier
② Operation instruction
python -m onnxsim ./yolov5s.onnx ./yolov5s_sim.onnx
You can generate simplified files in the yolov5 root directory
The above./yolov5s.onnx is the location of your own onnx file, and the following is the location saved after the simplified file is generated
(2) The whole process can be used for DIY attendance machine, and we are moving in this direction
(3) . Training your pt model
I won't go into details here. The authoritative and simple methods of training my own pt model can be found in the following links. I have tried many online methods. This is the best one, the simplest one, not so flashy, not so many mistakes, strong Amway!!!! (There is nothing in it that says that the same photos should be placed in the folders where the photos are stored. The same is true for txt files, as shown in the following figure)
https://blog.csdn.net/ylclaire_01/article/details/123082666
The contents of three folders for photos are as follows. Three identical photos are stored in three folders
The same goes for txt files
Several face models can be trained on the attendance machine.