HDMI输入直至Yolov5识别全流程代码
This commit is contained in:
162
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/.gitignore
vendored
Normal file
162
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/.gitignore
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
*.mp4
|
||||
201
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/LICENSE
Normal file
201
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
36
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/README.md
Normal file
36
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 简介
|
||||
* 使用多线程异步操作rknn模型, 提高rk3588/rk3588s的NPU使用率, 进而提高推理帧数(rk3568之类修改后应该也能使用, 但是作者本人并没有rk3568开发板......)
|
||||
* 此分支使用模型[yolov5s_relu_tk2_RK3588_i8.rknn](https://github.com/airockchip/rknn_model_zoo), 将yolov5s模型的激活函数silu修改为为relu,在损失一点精度的情况下获得较大性能提升,详情见于[rknn_model_zoo](https://github.com/airockchip/rknn_model_zoo/tree/main/models/CV/object_detection/yolo)
|
||||
* 此项目的[c++](https://github.com/leafqycc/rknn-cpp-Multithreading)实现
|
||||
|
||||
# 更新说明
|
||||
* 无
|
||||
|
||||
|
||||
# 使用说明
|
||||
### 演示
|
||||
* 将仓库拉取至本地, 并将Releases中的演示视频放于项目根目录下, 运行main.py查看演示示例
|
||||
* 切换至root用户运行performance.sh可以进行定频操作(约等于开启性能模式)
|
||||
* 运行rkcat.sh可以查看当前温度与NPU占用
|
||||
### 部署应用
|
||||
* 修改main.py下的modelPath为你自己的模型所在路径
|
||||
* 修改main.py下的cap为你想要运行的视频/摄像头
|
||||
* 修改main.py下的TPEs为你想要的线程数, 具体可参考下表
|
||||
* 修改func.py为你自己需要的推理函数, 具体可查看myFunc函数
|
||||
|
||||
# 多线程模型帧率测试
|
||||
* 使用performance.sh进行CPU/NPU定频尽量减少误差
|
||||
* 测试模型为[yolov5s_relu_tk2_RK3588_i8.rknn](https://github.com/airockchip/rknn_model_zoo)
|
||||
* 测试视频见于Releases
|
||||
|
||||
| 模型\线程数 | 1 | 2 | 3 | 4 | 5 | 6 |
|
||||
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
||||
| yolov5s | 27.4491 | 49.0747 | 65.3673 | 63.3204 | 71.8407 | 72.0590 |
|
||||
|
||||
# 补充
|
||||
* 多线程下CPU, NPU占用较高, **核心温度相应增高**, 请做好散热。推荐开1, 2, 3线程, 实测小铜片散热下运行三分钟温度约为56°, 64°, 69°
|
||||
|
||||
# Acknowledgements
|
||||
* https://github.com/ultralytics/yolov5
|
||||
* https://github.com/rockchip-linux/rknn-toolkit2
|
||||
* https://github.com/airockchip/rknn_model_zoo
|
||||
221
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/func.py
Normal file
221
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/func.py
Normal file
@@ -0,0 +1,221 @@
|
||||
#以下代码改自https://github.com/rockchip-linux/rknn-toolkit2/tree/master/examples/onnx/yolov5
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
OBJ_THRESH, NMS_THRESH, IMG_SIZE = 0.25, 0.45, 640
|
||||
|
||||
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
||||
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
||||
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
||||
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
||||
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
||||
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
||||
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
||||
|
||||
|
||||
#
|
||||
# def sigmoid(x):
|
||||
# return 1 / (1 + np.exp(-x))
|
||||
|
||||
|
||||
def xywh2xyxy(x):
|
||||
# Convert [x, y, w, h] to [x1, y1, x2, y2]
|
||||
y = np.copy(x)
|
||||
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
||||
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
||||
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
||||
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
||||
return y
|
||||
|
||||
|
||||
def process(input, mask, anchors):
|
||||
|
||||
anchors = [anchors[i] for i in mask]
|
||||
grid_h, grid_w = map(int, input.shape[0:2])
|
||||
|
||||
box_confidence = input[..., 4]
|
||||
box_confidence = np.expand_dims(box_confidence, axis=-1)
|
||||
|
||||
box_class_probs = input[..., 5:]
|
||||
|
||||
box_xy = input[..., :2] *2 - 0.5
|
||||
|
||||
col = np.tile(np.arange(0, grid_w), grid_w).reshape(-1, grid_w)
|
||||
row = np.tile(np.arange(0, grid_h).reshape(-1, 1), grid_h)
|
||||
col = col.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
|
||||
row = row.reshape(grid_h, grid_w, 1, 1).repeat(3, axis=-2)
|
||||
grid = np.concatenate((col, row), axis=-1)
|
||||
box_xy += grid
|
||||
box_xy *= int(IMG_SIZE/grid_h)
|
||||
|
||||
box_wh = pow(input[..., 2:4] *2, 2)
|
||||
box_wh = box_wh * anchors
|
||||
|
||||
return np.concatenate((box_xy, box_wh), axis=-1), box_confidence, box_class_probs
|
||||
|
||||
|
||||
def filter_boxes(boxes, box_confidences, box_class_probs):
|
||||
"""Filter boxes with box threshold. It's a bit different with origin yolov5 post process!
|
||||
|
||||
# Arguments
|
||||
boxes: ndarray, boxes of objects.
|
||||
box_confidences: ndarray, confidences of objects.
|
||||
box_class_probs: ndarray, class_probs of objects.
|
||||
|
||||
# Returns
|
||||
boxes: ndarray, filtered boxes.
|
||||
classes: ndarray, classes for boxes.
|
||||
scores: ndarray, scores for boxes.
|
||||
"""
|
||||
boxes = boxes.reshape(-1, 4)
|
||||
box_confidences = box_confidences.reshape(-1)
|
||||
box_class_probs = box_class_probs.reshape(-1, box_class_probs.shape[-1])
|
||||
|
||||
_box_pos = np.where(box_confidences >= OBJ_THRESH)
|
||||
boxes = boxes[_box_pos]
|
||||
box_confidences = box_confidences[_box_pos]
|
||||
box_class_probs = box_class_probs[_box_pos]
|
||||
|
||||
class_max_score = np.max(box_class_probs, axis=-1)
|
||||
classes = np.argmax(box_class_probs, axis=-1)
|
||||
_class_pos = np.where(class_max_score >= OBJ_THRESH)
|
||||
|
||||
return boxes[_class_pos], classes[_class_pos], (class_max_score * box_confidences)[_class_pos]
|
||||
|
||||
|
||||
def nms_boxes(boxes, scores):
|
||||
"""Suppress non-maximal boxes.
|
||||
|
||||
# Arguments
|
||||
boxes: ndarray, boxes of objects.
|
||||
scores: ndarray, scores of objects.
|
||||
|
||||
# Returns
|
||||
keep: ndarray, index of effective boxes.
|
||||
"""
|
||||
x = boxes[:, 0]
|
||||
y = boxes[:, 1]
|
||||
w = boxes[:, 2] - boxes[:, 0]
|
||||
h = boxes[:, 3] - boxes[:, 1]
|
||||
|
||||
areas = w * h
|
||||
order = scores.argsort()[::-1]
|
||||
|
||||
keep = []
|
||||
while order.size > 0:
|
||||
i = order[0]
|
||||
keep.append(i)
|
||||
|
||||
xx1 = np.maximum(x[i], x[order[1:]])
|
||||
yy1 = np.maximum(y[i], y[order[1:]])
|
||||
xx2 = np.minimum(x[i] + w[i], x[order[1:]] + w[order[1:]])
|
||||
yy2 = np.minimum(y[i] + h[i], y[order[1:]] + h[order[1:]])
|
||||
|
||||
w1 = np.maximum(0.0, xx2 - xx1 + 0.00001)
|
||||
h1 = np.maximum(0.0, yy2 - yy1 + 0.00001)
|
||||
inter = w1 * h1
|
||||
|
||||
ovr = inter / (areas[i] + areas[order[1:]] - inter)
|
||||
inds = np.where(ovr <= NMS_THRESH)[0]
|
||||
order = order[inds + 1]
|
||||
return np.array(keep)
|
||||
|
||||
|
||||
def yolov5_post_process(input_data):
|
||||
masks = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
|
||||
anchors = [[10, 13], [16, 30], [33, 23], [30, 61], [62, 45],
|
||||
[59, 119], [116, 90], [156, 198], [373, 326]]
|
||||
|
||||
boxes, classes, scores = [], [], []
|
||||
for input, mask in zip(input_data, masks):
|
||||
b, c, s = process(input, mask, anchors)
|
||||
b, c, s = filter_boxes(b, c, s)
|
||||
boxes.append(b)
|
||||
classes.append(c)
|
||||
scores.append(s)
|
||||
|
||||
boxes = np.concatenate(boxes)
|
||||
boxes = xywh2xyxy(boxes)
|
||||
classes = np.concatenate(classes)
|
||||
scores = np.concatenate(scores)
|
||||
|
||||
nboxes, nclasses, nscores = [], [], []
|
||||
for c in set(classes):
|
||||
inds = np.where(classes == c)
|
||||
b = boxes[inds]
|
||||
c = classes[inds]
|
||||
s = scores[inds]
|
||||
|
||||
keep = nms_boxes(b, s)
|
||||
|
||||
nboxes.append(b[keep])
|
||||
nclasses.append(c[keep])
|
||||
nscores.append(s[keep])
|
||||
|
||||
if not nclasses and not nscores:
|
||||
return None, None, None
|
||||
|
||||
return np.concatenate(nboxes), np.concatenate(nclasses), np.concatenate(nscores)
|
||||
|
||||
|
||||
def draw(image, boxes, scores, classes):
|
||||
for box, score, cl in zip(boxes, scores, classes):
|
||||
top, left, right, bottom = box
|
||||
# print('class: {}, score: {}'.format(CLASSES[cl], score))
|
||||
# print('box coordinate left,top,right,down: [{}, {}, {}, {}]'.format(top, left, right, bottom))
|
||||
top = int(top)
|
||||
left = int(left)
|
||||
|
||||
cv2.rectangle(image, (top, left), (int(right), int(bottom)), (255, 0, 0), 2)
|
||||
cv2.putText(image, '{0} {1:.2f}'.format(CLASSES[cl], score),
|
||||
(top, left - 6),
|
||||
cv2.FONT_HERSHEY_SIMPLEX,
|
||||
0.6, (0, 0, 255), 2)
|
||||
|
||||
def letterbox(im, new_shape=(640, 640), color=(0, 0, 0)):
|
||||
shape = im.shape[:2] # current shape [height, width]
|
||||
if isinstance(new_shape, int):
|
||||
new_shape = (new_shape, new_shape)
|
||||
|
||||
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
|
||||
|
||||
ratio = r, r # width, height ratios
|
||||
new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
|
||||
dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - \
|
||||
new_unpad[1] # wh padding
|
||||
|
||||
dw /= 2 # divide padding into 2 sides
|
||||
dh /= 2
|
||||
|
||||
if shape[::-1] != new_unpad: # resize
|
||||
im = cv2.resize(im, 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))
|
||||
im = cv2.copyMakeBorder(im, top, bottom, left, right,
|
||||
cv2.BORDER_CONSTANT, value=color) # add border
|
||||
return im
|
||||
# return im, ratio, (dw, dh)
|
||||
|
||||
def myFunc(rknn_lite, IMG):
|
||||
IMG = cv2.cvtColor(IMG, cv2.COLOR_BGR2RGB)
|
||||
# 等比例缩放
|
||||
# IMG = letterbox(IMG)
|
||||
# 强制放缩
|
||||
IMG = cv2.resize(IMG, (IMG_SIZE, IMG_SIZE))
|
||||
outputs = rknn_lite.inference(inputs=[IMG])
|
||||
|
||||
input0_data = outputs[0].reshape([3, -1]+list(outputs[0].shape[-2:]))
|
||||
input1_data = outputs[1].reshape([3, -1]+list(outputs[1].shape[-2:]))
|
||||
input2_data = outputs[2].reshape([3, -1]+list(outputs[2].shape[-2:]))
|
||||
|
||||
input_data = list()
|
||||
input_data.append(np.transpose(input0_data, (2, 3, 0, 1)))
|
||||
input_data.append(np.transpose(input1_data, (2, 3, 0, 1)))
|
||||
input_data.append(np.transpose(input2_data, (2, 3, 0, 1)))
|
||||
|
||||
boxes, classes, scores = yolov5_post_process(input_data)
|
||||
|
||||
IMG = cv2.cvtColor(IMG, cv2.COLOR_RGB2BGR)
|
||||
if boxes is not None:
|
||||
draw(IMG, boxes, scores, classes)
|
||||
return IMG
|
||||
49
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/main.py
Normal file
49
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/main.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import cv2
|
||||
import time
|
||||
from rknnpool import rknnPoolExecutor
|
||||
# 图像处理函数,实际应用过程中需要自行修改
|
||||
from func import myFunc
|
||||
|
||||
cap = cv2.VideoCapture('./test.mp4')
|
||||
# cap = cv2.VideoCapture(0)
|
||||
modelPath = "./rknnModel/yolov5s_relu_tk2_RK3588_i8.rknn"
|
||||
# 线程数, 增大可提高帧率
|
||||
TPEs = 3
|
||||
# 初始化rknn池
|
||||
pool = rknnPoolExecutor(
|
||||
rknnModel=modelPath,
|
||||
TPEs=TPEs,
|
||||
func=myFunc)
|
||||
|
||||
# 初始化异步所需要的帧
|
||||
if (cap.isOpened()):
|
||||
for i in range(TPEs + 1):
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
cap.release()
|
||||
del pool
|
||||
exit(-1)
|
||||
pool.put(frame)
|
||||
|
||||
frames, loopTime, initTime = 0, time.time(), time.time()
|
||||
while (cap.isOpened()):
|
||||
frames += 1
|
||||
ret, frame = cap.read()
|
||||
if not ret:
|
||||
break
|
||||
pool.put(frame)
|
||||
frame, flag = pool.get()
|
||||
if flag == False:
|
||||
break
|
||||
cv2.imshow('test', frame)
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
break
|
||||
if frames % 30 == 0:
|
||||
print("30帧平均帧率:\t", 30 / (time.time() - loopTime), "帧")
|
||||
loopTime = time.time()
|
||||
|
||||
print("总平均帧率\t", frames / (time.time() - initTime))
|
||||
# 释放cap和rknn线程池
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
pool.release()
|
||||
60
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/main_hdmi_in.py
Normal file
60
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/main_hdmi_in.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import cv2
|
||||
import time
|
||||
import numpy as np
|
||||
from rknnpool import rknnPoolExecutor
|
||||
# 图像处理函数,实际应用过程中需要自行修改
|
||||
from func import myFunc
|
||||
|
||||
cap = cv2.VideoCapture('/dev/video10')
|
||||
# cap = cv2.VideoCapture(0)
|
||||
modelPath = "./rknnModel/yolov5s_relu_tk2_RK3588_i8.rknn"
|
||||
# 线程数, 增大可提高帧率
|
||||
TPEs = 3
|
||||
# 初始化rknn池
|
||||
pool = rknnPoolExecutor(
|
||||
rknnModel=modelPath,
|
||||
TPEs=TPEs,
|
||||
func=myFunc)
|
||||
|
||||
# 初始化异步所需要的帧
|
||||
if (cap.isOpened()):
|
||||
for i in range(TPEs + 1):
|
||||
ret, frame = cap.read()
|
||||
# 检查帧数据是否需要重塑
|
||||
if frame.size == 1280 * 720 * 3: # 检查是否为扁平化数据
|
||||
frame = frame.reshape((720, 1280, 3)).astype(np.uint8)
|
||||
else:
|
||||
print(f"Unexpected frame shape: {frame.shape}")
|
||||
if not ret:
|
||||
cap.release()
|
||||
del pool
|
||||
exit(-1)
|
||||
pool.put(frame)
|
||||
|
||||
frames, loopTime, initTime = 0, time.time(), time.time()
|
||||
while (cap.isOpened()):
|
||||
frames += 1
|
||||
ret, frame = cap.read()
|
||||
# 检查帧数据是否需要重塑
|
||||
if frame.size == 1280 * 720 * 3: # 检查是否为扁平化数据
|
||||
frame = frame.reshape((720, 1280, 3)).astype(np.uint8)
|
||||
else:
|
||||
print(f"Unexpected frame shape: {frame.shape}")
|
||||
if not ret:
|
||||
break
|
||||
pool.put(frame)
|
||||
frame, flag = pool.get()
|
||||
if flag == False:
|
||||
break
|
||||
cv2.imshow('test', frame)
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
break
|
||||
if frames % 30 == 0:
|
||||
print("30帧平均帧率:\t", 30 / (time.time() - loopTime), "帧")
|
||||
loopTime = time.time()
|
||||
|
||||
print("总平均帧率\t", frames / (time.time() - initTime))
|
||||
# 释放cap和rknn线程池
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
pool.release()
|
||||
31
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/performance.sh
Normal file
31
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/performance.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
# 请切换到root用户
|
||||
|
||||
# CPU定频
|
||||
echo "CPU0-3 可用频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
|
||||
sudo echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
|
||||
sudo echo 1800000 > /sys/devices/system/cpu/cpufreq/policy0/scaling_setspeed
|
||||
echo "CPU0-3 当前频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq
|
||||
|
||||
echo "CPU4-5 可用频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy4/scaling_available_frequencies
|
||||
sudo echo userspace > /sys/devices/system/cpu/cpufreq/policy4/scaling_governor
|
||||
sudo echo 2400000 > /sys/devices/system/cpu/cpufreq/policy4/scaling_setspeed
|
||||
echo "CPU4-5 当前频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy4/cpuinfo_cur_freq
|
||||
|
||||
echo "CPU6-7 可用频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy6/scaling_available_frequencies
|
||||
sudo echo userspace > /sys/devices/system/cpu/cpufreq/policy6/scaling_governor
|
||||
sudo echo 2400000 > /sys/devices/system/cpu/cpufreq/policy6/scaling_setspeed
|
||||
echo "CPU6-7 当前频率:"
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy6/cpuinfo_cur_freq
|
||||
|
||||
# NPU定频
|
||||
echo "NPU 可用频率:"
|
||||
sudo cat /sys/class/devfreq/fdab0000.npu/available_frequencies
|
||||
sudo echo userspace > /sys/class/devfreq/fdab0000.npu/governor
|
||||
sudo echo 1000000000 > /sys/class/devfreq/fdab0000.npu/userspace/set_freq
|
||||
echo "NPU 当前频率:"
|
||||
sudo cat /sys/class/devfreq/fdab0000.npu/cur_freq
|
||||
5
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/rkcat.sh
Normal file
5
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/rkcat.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
# 查看温度
|
||||
sensors
|
||||
# 查看NPU占用
|
||||
echo "当前NPU占用:"
|
||||
sudo cat /sys/kernel/debug/rknpu/load
|
||||
Binary file not shown.
59
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/rknnpool.py
Normal file
59
NpuYoloV5/05_rknn-multi-threaded-nosigmoid/rknnpool.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from queue import Queue
|
||||
from rknnlite.api import RKNNLite
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
|
||||
def initRKNN(rknnModel="./rknnModel/yolov5s.rknn", id=0):
|
||||
rknn_lite = RKNNLite()
|
||||
ret = rknn_lite.load_rknn(rknnModel)
|
||||
if ret != 0:
|
||||
print("Load RKNN rknnModel failed")
|
||||
exit(ret)
|
||||
if id == 0:
|
||||
ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0)
|
||||
elif id == 1:
|
||||
ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_1)
|
||||
elif id == 2:
|
||||
ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_2)
|
||||
elif id == -1:
|
||||
ret = rknn_lite.init_runtime(core_mask=RKNNLite.NPU_CORE_0_1_2)
|
||||
else:
|
||||
ret = rknn_lite.init_runtime()
|
||||
if ret != 0:
|
||||
print("Init runtime environment failed")
|
||||
exit(ret)
|
||||
print(rknnModel, "\t\tdone")
|
||||
return rknn_lite
|
||||
|
||||
|
||||
def initRKNNs(rknnModel="./rknnModel/yolov5s.rknn", TPEs=1):
|
||||
rknn_list = []
|
||||
for i in range(TPEs):
|
||||
rknn_list.append(initRKNN(rknnModel, i % 3))
|
||||
return rknn_list
|
||||
|
||||
|
||||
class rknnPoolExecutor():
|
||||
def __init__(self, rknnModel, TPEs, func):
|
||||
self.TPEs = TPEs
|
||||
self.queue = Queue()
|
||||
self.rknnPool = initRKNNs(rknnModel, TPEs)
|
||||
self.pool = ThreadPoolExecutor(max_workers=TPEs)
|
||||
self.func = func
|
||||
self.num = 0
|
||||
|
||||
def put(self, frame):
|
||||
self.queue.put(self.pool.submit(
|
||||
self.func, self.rknnPool[self.num % self.TPEs], frame))
|
||||
self.num += 1
|
||||
|
||||
def get(self):
|
||||
if self.queue.empty():
|
||||
return None, False
|
||||
fut = self.queue.get()
|
||||
return fut.result(), True
|
||||
|
||||
def release(self):
|
||||
self.pool.shutdown()
|
||||
for rknn_lite in self.rknnPool:
|
||||
rknn_lite.release()
|
||||
Reference in New Issue
Block a user