Upload 32 files
Browse files- .gitattributes +8 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/README.md +56 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/CMakeLists.txt +31 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/run_test.cpp +485 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/run_test.py +134 -0
- model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/utils.py +124 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/README.md +56 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/CMakeLists.txt +31 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/run_test.cpp +484 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/models/cutoff_yolov8s-seg_fp16.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/run_test.py +134 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/utils.py +124 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/README.md +56 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/CMakeLists.txt +31 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/run_test.cpp +484 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/models/cutoff_yolov8s-seg_w8a16.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/run_test.py +134 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/utils.py +124 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/README.md +56 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/CMakeLists.txt +31 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/run_test.cpp +484 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/run_test.py +134 -0
- model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/utils.py +124 -0
.gitattributes
CHANGED
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
37 |
+
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
38 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
39 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
40 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
41 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
42 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
43 |
+
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/bus.jpg filter=lfs diff=lfs merge=lfs -text
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
## Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 11.27M
|
5 |
+
- Model size: 45.22M
|
6 |
+
- Output shape: 1x32x160x160, 1x116x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: INT8
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: FV01 QCS6490
|
15 |
+
|
16 |
+
## Inference with AidLite SDK
|
17 |
+
|
18 |
+
### SDK installation
|
19 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
20 |
+
|
21 |
+
- Install AidLite SDK
|
22 |
+
|
23 |
+
```bash
|
24 |
+
# Install the appropriate version of the aidlite sdk
|
25 |
+
sudo aid-pkg update
|
26 |
+
sudo aid-pkg install aidlite-sdk
|
27 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
28 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
29 |
+
```
|
30 |
+
|
31 |
+
- Verify AidLite SDK
|
32 |
+
|
33 |
+
```bash
|
34 |
+
# aidlite sdk c++ check
|
35 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
36 |
+
|
37 |
+
# aidlite sdk python check
|
38 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
39 |
+
```
|
40 |
+
|
41 |
+
### Run demo
|
42 |
+
#### python
|
43 |
+
```bash
|
44 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite
|
45 |
+
python3 ./python/run_test.py --target_model ./models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
46 |
+
```
|
47 |
+
|
48 |
+
#### cpp
|
49 |
+
```bash
|
50 |
+
cd yolov8s_seg/model_farm_yolov5s_qcs6490_qnn2.16_int8_aidlite/cpp
|
51 |
+
mkdir build && cd build
|
52 |
+
cmake ..
|
53 |
+
make
|
54 |
+
./run_test
|
55 |
+
```
|
56 |
+
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/run_test.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
pthread
|
31 |
+
)
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/cpp/run_test.cpp
ADDED
@@ -0,0 +1,485 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <cstring> // 用于 memcpy
|
6 |
+
#include <opencv2/opencv.hpp>
|
7 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
8 |
+
#include <vector>
|
9 |
+
#include <numeric>
|
10 |
+
|
11 |
+
const float INPUT_WIDTH = 640.0;
|
12 |
+
const float INPUT_HEIGHT = 640.0;
|
13 |
+
const float SCORE_THRESHOLD = 0.25;
|
14 |
+
const float NMS_THRESHOLD = 0.45;
|
15 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
16 |
+
const uint32_t size = 640;
|
17 |
+
const uint32_t out_size = 8400;
|
18 |
+
|
19 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
20 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
21 |
+
|
22 |
+
const float FONT_SCALE = 0.75;
|
23 |
+
const int THICKNESS = 1;
|
24 |
+
|
25 |
+
const std::vector<std::string> class_list = {
|
26 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
27 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
28 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
29 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
30 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
31 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
32 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
33 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
34 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
35 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
36 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
37 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
38 |
+
};
|
39 |
+
|
40 |
+
using namespace cv;
|
41 |
+
using namespace std;
|
42 |
+
using namespace Aidlux::Aidlite;
|
43 |
+
|
44 |
+
struct Args {
|
45 |
+
std::string target_model = "../../models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin";
|
46 |
+
std::string imgs = "../bus.jpg";
|
47 |
+
int invoke_nums = 10;
|
48 |
+
std::string model_type = "QNN";
|
49 |
+
};
|
50 |
+
|
51 |
+
Args parse_args(int argc, char* argv[]) {
|
52 |
+
Args args;
|
53 |
+
for (int i = 1; i < argc; ++i) {
|
54 |
+
std::string arg = argv[i];
|
55 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
56 |
+
args.target_model = argv[++i];
|
57 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
58 |
+
args.imgs = argv[++i];
|
59 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
60 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
61 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
62 |
+
args.model_type = argv[++i];
|
63 |
+
}
|
64 |
+
}
|
65 |
+
return args;
|
66 |
+
}
|
67 |
+
|
68 |
+
std::string to_lower(const std::string& str) {
|
69 |
+
std::string lower_str = str;
|
70 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
71 |
+
return std::tolower(c);
|
72 |
+
});
|
73 |
+
return lower_str;
|
74 |
+
}
|
75 |
+
|
76 |
+
// concatenate_3(80_class_data, 4_pos_data , 32_canc_data, 1, 8400, 80, 4,32, qnn_concat);
|
77 |
+
void concatenate_3(float* qnn_trans_data, float* qnn_mul_data, float* qnn_canc_data, int batch, int num_elements, int trans_dim, int mul_dim, int canc_dim,std::vector<float>& output) {
|
78 |
+
// int out_dim = trans_dim + mul_dim + canc_dim + 1; //117
|
79 |
+
int out_dim = trans_dim + mul_dim + canc_dim; //116
|
80 |
+
output.resize(batch * num_elements * out_dim);
|
81 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
82 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
83 |
+
std::memcpy(&output[i * out_dim + mul_dim], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
84 |
+
std::memcpy(&output[i * out_dim + mul_dim + trans_dim], &qnn_canc_data[i * canc_dim], canc_dim * sizeof(float));
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
// 4*8400
|
89 |
+
void transformData(const float* input, float* output, int C, int N) {
|
90 |
+
for (int c = 0; c < C; ++c) {
|
91 |
+
for (int n = 0; n < N; ++n) {
|
92 |
+
output[n * C + c] = input[c * N + n];
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
98 |
+
cv::Mat img_processed = frame.clone();
|
99 |
+
int height = img_processed.rows;
|
100 |
+
int width = img_processed.cols;
|
101 |
+
int length = std::max(height, width);
|
102 |
+
double scala = static_cast<double>(length) / size;
|
103 |
+
|
104 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
105 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
106 |
+
|
107 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
108 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
109 |
+
|
110 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
111 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
112 |
+
img_input.convertTo(img_input, CV_32FC3);
|
113 |
+
img_input = (img_input - mean_data) / std_data;
|
114 |
+
return scala;
|
115 |
+
}
|
116 |
+
|
117 |
+
|
118 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
119 |
+
static const std::vector<std::string> hex_colors = {
|
120 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
121 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
122 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
123 |
+
"FF95C8", "FF37C7"
|
124 |
+
};
|
125 |
+
|
126 |
+
int num = hex_colors.size();
|
127 |
+
std::string hex = hex_colors[i % num];
|
128 |
+
|
129 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
130 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
131 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
132 |
+
|
133 |
+
if (bgr)
|
134 |
+
return cv::Scalar(b, g, r);
|
135 |
+
else
|
136 |
+
return cv::Scalar(r, g, b);
|
137 |
+
}
|
138 |
+
|
139 |
+
float sigmoid_function(float a)
|
140 |
+
{
|
141 |
+
float b = 1. / (1. + exp(-a));
|
142 |
+
return b;
|
143 |
+
}
|
144 |
+
|
145 |
+
int transpose(float* src, unsigned int* src_dims, unsigned int* tsp_dims, float* dest){
|
146 |
+
|
147 |
+
int current_coordinate[4] = {0, 0, 0, 0};
|
148 |
+
for(int a = 0; a < src_dims[0]; ++a){
|
149 |
+
current_coordinate[0] = a;
|
150 |
+
for(int b = 0; b < src_dims[1]; ++b){
|
151 |
+
current_coordinate[1] = b;
|
152 |
+
for(int c = 0; c < src_dims[2]; ++c){
|
153 |
+
current_coordinate[2] = c;
|
154 |
+
for(int d = 0; d < src_dims[3]; ++d){
|
155 |
+
current_coordinate[3] = d;
|
156 |
+
|
157 |
+
int old_index = current_coordinate[0]*src_dims[1]*src_dims[2]*src_dims[3] +
|
158 |
+
current_coordinate[1]*src_dims[2]*src_dims[3] +
|
159 |
+
current_coordinate[2]*src_dims[3] +
|
160 |
+
current_coordinate[3];
|
161 |
+
|
162 |
+
int new_index = current_coordinate[tsp_dims[0]]*src_dims[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
163 |
+
current_coordinate[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
164 |
+
current_coordinate[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
165 |
+
current_coordinate[tsp_dims[3]];
|
166 |
+
|
167 |
+
dest[new_index] = src[old_index];
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
return EXIT_SUCCESS;
|
174 |
+
}
|
175 |
+
|
176 |
+
|
177 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
178 |
+
{
|
179 |
+
int baseLine;
|
180 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
181 |
+
int y = top - label_size.height - baseLine;
|
182 |
+
if (y < 0) {
|
183 |
+
y = top ;
|
184 |
+
}
|
185 |
+
cv::Point tlc(left, y);
|
186 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
187 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
188 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
189 |
+
}
|
190 |
+
|
191 |
+
|
192 |
+
cv::Mat post_process(cv::Mat &frame, std::vector<float> &outputs, const std::vector<std::string> &class_name,
|
193 |
+
const double ratio, float* protos_data, float* qnn_canc)
|
194 |
+
{
|
195 |
+
cv::Mat input_image = frame.clone();
|
196 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
197 |
+
std::vector<int> class_ids;
|
198 |
+
std::vector<float> confidences;
|
199 |
+
std::vector<cv::Rect> boxes;
|
200 |
+
std::vector<cv::Mat> masks;
|
201 |
+
std::vector<float> class_scores;
|
202 |
+
cv::RNG rng;
|
203 |
+
cv::Mat masked_img;
|
204 |
+
|
205 |
+
unsigned int src_dims[4] = {1, 32,160,160};
|
206 |
+
unsigned int tsp_dims[4] = {0,3,1,2};
|
207 |
+
unsigned int stride_data_num = 1*32*160*160;
|
208 |
+
float* format_data = new float[stride_data_num];
|
209 |
+
transpose(protos_data, src_dims, tsp_dims, format_data);
|
210 |
+
cv::Mat proto_buffer(32, 160*160, CV_32F, format_data);
|
211 |
+
std::cout << "proto_buffer 维度: " << proto_buffer.rows << "x" << proto_buffer.cols << std::endl;
|
212 |
+
|
213 |
+
for (int i = 0; i < outputs.size(); i+=116)
|
214 |
+
{
|
215 |
+
auto start = outputs.begin() + i + 4;
|
216 |
+
auto end = outputs.begin() + i + 84;
|
217 |
+
float max_val = *std::max_element(start, end);
|
218 |
+
float confidence = max_val;
|
219 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
220 |
+
{
|
221 |
+
auto start = outputs.begin() + i + 4;
|
222 |
+
auto end = outputs.begin() + i + 84;
|
223 |
+
std::vector<float> middle_data;
|
224 |
+
middle_data.assign(start, end);
|
225 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
226 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, middle_data.data());
|
227 |
+
cv::Point class_id;
|
228 |
+
double max_class_score;
|
229 |
+
|
230 |
+
// For multi-label, check each class score
|
231 |
+
for (int c = 0; c < class_name.size(); c++) {
|
232 |
+
float class_score = scores.at<float>(0, c);
|
233 |
+
// If class score is above threshold, consider this class for the box
|
234 |
+
if (class_score > SCORE_THRESHOLD) {
|
235 |
+
std::vector<float> last32_data;
|
236 |
+
auto st_32= outputs.begin() + i + 84;
|
237 |
+
auto ed_32 = outputs.begin() + i + 116;
|
238 |
+
last32_data.assign(st_32, ed_32);
|
239 |
+
cv::Mat mask(1, 32, CV_32FC1, last32_data.data());
|
240 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
241 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
242 |
+
class_ids.push_back(c); // class index
|
243 |
+
// Center and box dimension.
|
244 |
+
float cx = outputs[i];
|
245 |
+
float cy = outputs[i+1];
|
246 |
+
float w = outputs[i+2];
|
247 |
+
float h = outputs[i+3];
|
248 |
+
|
249 |
+
int left = int((cx - 0.5 * w) * ratio);
|
250 |
+
int top = int((cy - 0.48 * h) * ratio);
|
251 |
+
int width = int(w * ratio);
|
252 |
+
int height = int(h * ratio);
|
253 |
+
|
254 |
+
// Store good detections in the boxes vector.
|
255 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
256 |
+
masks.push_back(mask);
|
257 |
+
}
|
258 |
+
}
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
std::cout << "boxes.size(): " << boxes.size() << ",confidences.size():" << confidences.size() << std::endl;
|
263 |
+
|
264 |
+
// Perform Non Maximum Suppression and draw predictions.
|
265 |
+
std::vector<int> indices;
|
266 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
267 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
268 |
+
cv::Mat rgb_mask = cv::Mat::zeros(input_image.size(), input_image.type());
|
269 |
+
|
270 |
+
// Loop over NMS results and draw bounding boxes
|
271 |
+
for (int i = 0; i < indices.size(); i++)
|
272 |
+
{
|
273 |
+
int idx = indices[i];
|
274 |
+
cv::Rect box = boxes[idx];
|
275 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
276 |
+
|
277 |
+
int x1 = std::max(0, box.x);
|
278 |
+
int y1 = std::max(0, box.y);
|
279 |
+
int x2 = std::max(0, box.br().x);
|
280 |
+
int y2 = std::max(0, box.br().y);
|
281 |
+
cv::Mat ms = masks[idx];
|
282 |
+
// 维度验证
|
283 |
+
if (ms.cols != proto_buffer.rows) {
|
284 |
+
cerr << "维度不匹配: mask.cols=" << ms.cols
|
285 |
+
<< ", proto_buffer.rows=" << proto_buffer.rows << endl;
|
286 |
+
continue;
|
287 |
+
}
|
288 |
+
cv::Mat m = ms * proto_buffer;
|
289 |
+
for (int col = 0; col < m.cols; col++) {
|
290 |
+
m.at<float>(0, col) = sigmoid_function(m.at<float>(0, col));
|
291 |
+
}
|
292 |
+
cv::Mat m1 = m.reshape(1, 160); // 1x25600 -> 160x160
|
293 |
+
|
294 |
+
float ratio2 = 160.0/640.0;
|
295 |
+
int mx1 = std::max(0, int((x1 * ratio2)));
|
296 |
+
int mx2 = std::max(0, int((x2 * ratio2)));
|
297 |
+
int my1 = std::max(0, int((y1 * ratio2)));
|
298 |
+
int my2 = std::max(0, int((y2 * ratio2)));
|
299 |
+
cv::Mat mask_roi = m1(cv::Range(my1, my2), cv::Range(mx1, mx2));
|
300 |
+
cv::Mat rm, det_mask;
|
301 |
+
cv::resize(mask_roi, rm, cv::Size(x2 - x1, y2 - y1));
|
302 |
+
for (int r = 0; r < rm.rows; r++) {
|
303 |
+
for (int c = 0; c < rm.cols; c++) {
|
304 |
+
float pv = rm.at<float>(r, c);
|
305 |
+
if (pv > 0.5) {
|
306 |
+
rm.at<float>(r, c) = 1.0;
|
307 |
+
}
|
308 |
+
else {
|
309 |
+
rm.at<float>(r, c) = 0.0;
|
310 |
+
}
|
311 |
+
}
|
312 |
+
}
|
313 |
+
rm = rm * rng.uniform(0, 255);
|
314 |
+
rm.convertTo(det_mask, CV_8UC1);
|
315 |
+
if ((y1 + det_mask.rows) >= input_image.rows) {
|
316 |
+
y2 = input_image.rows - 1;
|
317 |
+
}
|
318 |
+
if ((x1 + det_mask.cols) >= input_image.cols) {
|
319 |
+
x2 = input_image.cols - 1;
|
320 |
+
}
|
321 |
+
|
322 |
+
cv::Mat mask = cv::Mat::zeros(cv::Size(input_image.cols, input_image.rows), CV_8UC1);
|
323 |
+
det_mask(cv::Range(0, y2 - y1), cv::Range(0, x2 - x1)).copyTo(mask(cv::Range(y1, y2), cv::Range(x1, x2)));
|
324 |
+
add(rgb_mask, cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), rgb_mask, mask);
|
325 |
+
if (input_image.size() != rgb_mask.size()) {
|
326 |
+
cv::resize(rgb_mask, rgb_mask, input_image.size());
|
327 |
+
}
|
328 |
+
|
329 |
+
cv::rectangle(input_image, boxes[idx], color, 2, 8);
|
330 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
331 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
332 |
+
cv::putText(input_image, label, cv::Point(boxes[idx].tl().x, boxes[idx].tl().y - 10), cv::FONT_HERSHEY_SIMPLEX, .5, color);
|
333 |
+
cv::addWeighted(input_image, 0.5, rgb_mask, 0.5, 0, masked_img);
|
334 |
+
|
335 |
+
}
|
336 |
+
printf("Processing finished.\n");
|
337 |
+
return masked_img;
|
338 |
+
}
|
339 |
+
|
340 |
+
|
341 |
+
|
342 |
+
int invoke(const Args& args) {
|
343 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
344 |
+
<< "Image Path: " << args.imgs << "\n"
|
345 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
346 |
+
<< "Model Type: " << args.model_type << "\n";
|
347 |
+
Model* model = Model::create_instance(args.target_model);
|
348 |
+
if(model == nullptr){
|
349 |
+
printf("Create model failed !\n");
|
350 |
+
return EXIT_FAILURE;
|
351 |
+
}
|
352 |
+
Config* config = Config::create_instance();
|
353 |
+
if(config == nullptr){
|
354 |
+
printf("Create config failed !\n");
|
355 |
+
return EXIT_FAILURE;
|
356 |
+
}
|
357 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
358 |
+
std::string model_type_lower = to_lower(args.model_type);
|
359 |
+
if (model_type_lower == "qnn"){
|
360 |
+
config->framework_type = FrameworkType::TYPE_QNN216;
|
361 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
362 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
363 |
+
}
|
364 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
365 |
+
config->is_quantify_model = 1;
|
366 |
+
|
367 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, size, size, 3}};
|
368 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1,32,8400},{1,4,8400},{1,80,8400},{1,160, 160,32}};
|
369 |
+
model->set_model_properties(input_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32, output_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32);
|
370 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
371 |
+
if(fast_interpreter == nullptr){
|
372 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
373 |
+
return EXIT_FAILURE;
|
374 |
+
}
|
375 |
+
int result = fast_interpreter->init();
|
376 |
+
if(result != EXIT_SUCCESS){
|
377 |
+
printf("interpreter->init() failed !\n");
|
378 |
+
return EXIT_FAILURE;
|
379 |
+
}
|
380 |
+
// load model
|
381 |
+
fast_interpreter->load_model();
|
382 |
+
if(result != EXIT_SUCCESS){
|
383 |
+
printf("interpreter->load_model() failed !\n");
|
384 |
+
return EXIT_FAILURE;
|
385 |
+
}
|
386 |
+
printf("detect model load success!\n");
|
387 |
+
|
388 |
+
cv::Mat frame = cv::imread(args.imgs);
|
389 |
+
if (frame.empty()) {
|
390 |
+
printf("detect image load failed!\n");
|
391 |
+
return 1;
|
392 |
+
}
|
393 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
394 |
+
cv::Mat input_img;
|
395 |
+
double scale = img_process(frame, input_img, size);
|
396 |
+
if (input_img.empty()) {
|
397 |
+
printf("detect input_img load failed!\n");
|
398 |
+
return 1;
|
399 |
+
}
|
400 |
+
|
401 |
+
float *qnn_seg_data = nullptr;
|
402 |
+
float *qnn_trans_data = nullptr;
|
403 |
+
float *qnn_mul_data = nullptr;
|
404 |
+
float *qnn_canc_data = nullptr;
|
405 |
+
|
406 |
+
std::vector<float> invoke_time;
|
407 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
408 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
409 |
+
if(result != EXIT_SUCCESS){
|
410 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
411 |
+
return EXIT_FAILURE;
|
412 |
+
}
|
413 |
+
// 开始计时
|
414 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
415 |
+
result = fast_interpreter->invoke();
|
416 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
417 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
418 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
419 |
+
if(result != EXIT_SUCCESS){
|
420 |
+
printf("interpreter->invoke() failed !\n");
|
421 |
+
return EXIT_FAILURE;
|
422 |
+
}
|
423 |
+
uint32_t out_data_1 = 0;
|
424 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_canc_data, &out_data_1);
|
425 |
+
if(result != EXIT_SUCCESS){
|
426 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
427 |
+
return EXIT_FAILURE;
|
428 |
+
}
|
429 |
+
|
430 |
+
uint32_t out_data_4 = 0;
|
431 |
+
result = fast_interpreter->get_output_tensor(2, (void**)&qnn_trans_data, &out_data_4);
|
432 |
+
if(result != EXIT_SUCCESS){
|
433 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
434 |
+
return EXIT_FAILURE;
|
435 |
+
}
|
436 |
+
|
437 |
+
uint32_t out_data_2 = 0;
|
438 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_seg_data, &out_data_2);
|
439 |
+
if(result != EXIT_SUCCESS){
|
440 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
441 |
+
return EXIT_FAILURE;
|
442 |
+
}
|
443 |
+
|
444 |
+
uint32_t out_data_80 = 0;
|
445 |
+
result = fast_interpreter->get_output_tensor(3, (void**)&qnn_mul_data, &out_data_80);
|
446 |
+
if(result != EXIT_SUCCESS){
|
447 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
448 |
+
return EXIT_FAILURE;
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
453 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
454 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
455 |
+
float var_invoketime = 0.0f;
|
456 |
+
for (auto time : invoke_time) {
|
457 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
458 |
+
}
|
459 |
+
var_invoketime /= args.invoke_nums;
|
460 |
+
printf("=======================================\n");
|
461 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
462 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
463 |
+
printf("=======================================\n");
|
464 |
+
|
465 |
+
float* pos_data = new float[4 * out_size];
|
466 |
+
float* class_data = new float[80 * out_size];
|
467 |
+
float* canc_data = new float[32 * out_size];
|
468 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
469 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
470 |
+
transformData(qnn_canc_data, canc_data, 32, out_size);
|
471 |
+
|
472 |
+
// post process
|
473 |
+
std::vector<float> qnn_concat;
|
474 |
+
concatenate_3(class_data, pos_data, canc_data , 1, out_size, 80, 4, 32, qnn_concat);
|
475 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale, qnn_seg_data, qnn_canc_data);
|
476 |
+
cv::imwrite("./results.png", img);
|
477 |
+
fast_interpreter->destory();
|
478 |
+
return 0;
|
479 |
+
}
|
480 |
+
|
481 |
+
|
482 |
+
int main(int argc, char* argv[]) {
|
483 |
+
Args args = parse_args(argc, argv);
|
484 |
+
return invoke(args);
|
485 |
+
}
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:48497c146c2f745ed415a5a079396443152caadc4fa5d34740e5e8b8a9c6b4a1
|
3 |
+
size 12515768
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS, process_mask, masks2segments, draw_detect_res
|
5 |
+
import os
|
6 |
+
import time
|
7 |
+
import argparse
|
8 |
+
import onnxruntime
|
9 |
+
|
10 |
+
# 定义相似度函数
|
11 |
+
def get_acc(onnx_out,other_out):
|
12 |
+
cosine_similarity=np.dot(np.array(onnx_out),np.array(other_out))/(np.linalg.norm(np.array(onnx_out)) * np.linalg.norm(np.array(other_out)))
|
13 |
+
return cosine_similarity
|
14 |
+
|
15 |
+
|
16 |
+
class qnn_predict(object):
|
17 |
+
def __init__(self,args) -> None:
|
18 |
+
# aidlite.set_log_level(aidlite.LogLevel.INFO)
|
19 |
+
# aidlite.log_to_stderr()
|
20 |
+
# print(f"Aidlite library version : {aidlite.get_library_version()}")
|
21 |
+
# print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
22 |
+
config = aidlite.Config.create_instance()
|
23 |
+
if config is None:
|
24 |
+
print("Create model failed !")
|
25 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
26 |
+
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
27 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
28 |
+
config.is_quantify_model = 1
|
29 |
+
|
30 |
+
model = aidlite.Model.create_instance(args.target_model)
|
31 |
+
if model is None:
|
32 |
+
print("Create model failed !")
|
33 |
+
|
34 |
+
self.conf = args.conf_thres
|
35 |
+
self.iou=args.iou_thres
|
36 |
+
self.width = args.width
|
37 |
+
self.height = args.height
|
38 |
+
self.class_num = args.class_num
|
39 |
+
self.input_shape = [[1,self.height,self.width,3]]
|
40 |
+
self.blocks = int(self.height * self.width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
41 |
+
self.maskw = int(self.width / 4)
|
42 |
+
self.maskh = int(self.height / 4)
|
43 |
+
self.output_shape = [[1,32,self.blocks],[1,4,self.blocks],[1,self.class_num,self.blocks],[1,self.maskh, self.maskw,32]]
|
44 |
+
|
45 |
+
model.set_model_properties(self.input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
46 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
47 |
+
if self.interpreter is None:
|
48 |
+
print("build_interpretper_from_model_and_config failed !")
|
49 |
+
result = self.interpreter.init()
|
50 |
+
if result != 0:
|
51 |
+
print(f"interpreter init failed !")
|
52 |
+
result = self.interpreter.load_model()
|
53 |
+
if result != 0:
|
54 |
+
print("interpreter load model failed !")
|
55 |
+
print("detect model load success!")
|
56 |
+
|
57 |
+
def pretreat_img(self,frame):
|
58 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
59 |
+
img = img / 255
|
60 |
+
img = img.astype(np.float32)
|
61 |
+
return img,scale
|
62 |
+
|
63 |
+
def qnn_run(self, orig_imgs,args):
|
64 |
+
input_img_f,scale=self.pretreat_img(orig_imgs) # 图片resize HWC
|
65 |
+
input_img = np.expand_dims(input_img_f, 0)
|
66 |
+
|
67 |
+
invoke_time=[]
|
68 |
+
for i in range(args.invoke_nums):
|
69 |
+
self.interpreter.set_input_tensor(0, input_img.data)
|
70 |
+
t0 = time.time()
|
71 |
+
self.interpreter.invoke()
|
72 |
+
t1 = time.time()
|
73 |
+
cost_time=(t1-t0)*1000
|
74 |
+
invoke_time.append(cost_time)
|
75 |
+
|
76 |
+
input0_data = self.interpreter.get_output_tensor(2).reshape(1,4,self.blocks)
|
77 |
+
input1_data = self.interpreter.get_output_tensor(3).reshape(1,self.class_num,self.blocks)
|
78 |
+
input2_data = self.interpreter.get_output_tensor(1).reshape(1,32,self.blocks)
|
79 |
+
protos = self.interpreter.get_output_tensor(0).reshape(1,self.maskh, self.maskw,32).transpose(0,3,1,2)
|
80 |
+
|
81 |
+
boxes = np.concatenate([input0_data, input1_data, input2_data], axis = 1)
|
82 |
+
x = boxes.transpose(0,2,1)
|
83 |
+
x = x[np.amax(x[..., 4:-32], axis=-1) > self.conf]
|
84 |
+
if len(x) < 1:
|
85 |
+
return None, None
|
86 |
+
|
87 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:-32], axis=-1), np.argmax(x[..., 4:-32], axis=-1), x[..., -32:]]
|
88 |
+
|
89 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
90 |
+
index = NMS(x[:, :4], x[:, 4], self.iou)
|
91 |
+
out_boxes = x[index]
|
92 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
93 |
+
|
94 |
+
masks = process_mask(protos[0], out_boxes[:, -32:], out_boxes[:, :4], orig_imgs.shape)
|
95 |
+
segments = masks2segments(masks)
|
96 |
+
|
97 |
+
## time 统计
|
98 |
+
max_invoke_time = max(invoke_time)
|
99 |
+
min_invoke_time = min(invoke_time)
|
100 |
+
mean_invoke_time = sum(invoke_time)/args.invoke_nums
|
101 |
+
var_invoketime=np.var(invoke_time)
|
102 |
+
print("========================================")
|
103 |
+
print(f"QNN inference {args.invoke_nums} times :\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
104 |
+
print("========================================")
|
105 |
+
|
106 |
+
return out_boxes, segments
|
107 |
+
|
108 |
+
|
109 |
+
def parser_args():
|
110 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
111 |
+
parser.add_argument('--target_model',type=str,default='/home/aidlux/modelfarm/yolov8s_seg/model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin',help="inference model path")
|
112 |
+
parser.add_argument('--imgs',type=str,default='/home/aidlux/modelfarm/yolov8s_seg/model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/bus.jpg',help="Predict images path")
|
113 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
114 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
115 |
+
parser.add_argument('--width',type=int,default=640,help="Model input size")
|
116 |
+
parser.add_argument('--height',type=int,default=640,help="Model input size")
|
117 |
+
parser.add_argument('--conf_thres',type=float,default=0.45,help="confidence threshold for filtering the annotations")
|
118 |
+
parser.add_argument('--iou_thres',type=float,default=0.45,help="Iou threshold for filtering the annotations")
|
119 |
+
parser.add_argument('--class_num',type=int,default=80,help="Iou threshold for filtering the annotations")
|
120 |
+
args = parser.parse_args()
|
121 |
+
return args
|
122 |
+
|
123 |
+
def main(args):
|
124 |
+
model = qnn_predict(args)
|
125 |
+
frame = cv2.imread(args.imgs)
|
126 |
+
qnn_out_boxes, qnn_segments = model.qnn_run(frame,args)
|
127 |
+
result = draw_detect_res(frame, qnn_out_boxes, qnn_segments)
|
128 |
+
cv2.imwrite("./bus_result.jpg", result)
|
129 |
+
|
130 |
+
if __name__ == "__main__":
|
131 |
+
args = parser_args()
|
132 |
+
main(args)
|
133 |
+
|
134 |
+
|
model_farm_yolov8s_seg_qsc6490_qnn2.16_int8_aidlite/python/utils.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
def draw_detect_res(img, det_pred, segments):
|
72 |
+
'''
|
73 |
+
检测结果绘制
|
74 |
+
'''
|
75 |
+
if det_pred is None:
|
76 |
+
return img
|
77 |
+
|
78 |
+
img = img.astype(np.uint8)
|
79 |
+
im_canvas = img.copy()
|
80 |
+
color_step = int(255/len(CLASSES))
|
81 |
+
for i in range(len(det_pred)):
|
82 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
83 |
+
cls_id = int(det_pred[i][5])
|
84 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
85 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
86 |
+
if len(segments[i]) > 0:
|
87 |
+
cv2.polylines(img, np.int32([segments[i]]), True, (0, int(cls_id*color_step), int(255-cls_id*color_step)), 2)
|
88 |
+
cv2.fillPoly(img, np.int32([segments[i]]), (0, int(cls_id*color_step), int(255-cls_id*color_step)))
|
89 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
90 |
+
return img
|
91 |
+
|
92 |
+
def scale_mask(masks, im0_shape):
|
93 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
94 |
+
interpolation=cv2.INTER_LINEAR)
|
95 |
+
if len(masks.shape) == 2:
|
96 |
+
masks = masks[:, :, None]
|
97 |
+
return masks
|
98 |
+
|
99 |
+
def crop_mask(masks, boxes):
|
100 |
+
n, h, w = masks.shape
|
101 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
102 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
103 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
104 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
105 |
+
|
106 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
107 |
+
c, mh, mw = protos.shape
|
108 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
109 |
+
masks = np.ascontiguousarray(masks)
|
110 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
111 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
112 |
+
masks = crop_mask(masks, bboxes)
|
113 |
+
return np.greater(masks, 0.5)
|
114 |
+
|
115 |
+
def masks2segments(masks):
|
116 |
+
segments = []
|
117 |
+
for x in masks.astype('uint8'):
|
118 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
119 |
+
if c:
|
120 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
121 |
+
else:
|
122 |
+
c = np.zeros((0, 2)) # no segments found
|
123 |
+
segments.append(c.astype('float32'))
|
124 |
+
return segments
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
## Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 11.27M
|
5 |
+
- Model size: 45.22M
|
6 |
+
- Output shape: 1x32x160x160, 1x116x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: FP16
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: SNM972 QCS8550
|
15 |
+
|
16 |
+
## Inference with AidLite SDK
|
17 |
+
|
18 |
+
### SDK installation
|
19 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
20 |
+
|
21 |
+
- Install AidLite SDK
|
22 |
+
|
23 |
+
```bash
|
24 |
+
# Install the appropriate version of the aidlite sdk
|
25 |
+
sudo aid-pkg update
|
26 |
+
sudo aid-pkg install aidlite-sdk
|
27 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
28 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
29 |
+
```
|
30 |
+
|
31 |
+
- Verify AidLite SDK
|
32 |
+
|
33 |
+
```bash
|
34 |
+
# aidlite sdk c++ check
|
35 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
36 |
+
|
37 |
+
# aidlite sdk python check
|
38 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
39 |
+
```
|
40 |
+
|
41 |
+
### Run demo
|
42 |
+
#### python
|
43 |
+
```bash
|
44 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite
|
45 |
+
python3 ./python/run_test.py --target_model ./models/cutoff_yolov8s-seg_fp16.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
46 |
+
```
|
47 |
+
|
48 |
+
#### cpp
|
49 |
+
```bash
|
50 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp
|
51 |
+
mkdir build && cd build
|
52 |
+
cmake ..
|
53 |
+
make
|
54 |
+
./run_test
|
55 |
+
```
|
56 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/run_test.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
pthread
|
31 |
+
)
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/cpp/run_test.cpp
ADDED
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <cstring> // 用于 memcpy
|
6 |
+
#include <opencv2/opencv.hpp>
|
7 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
8 |
+
#include <vector>
|
9 |
+
#include <numeric>
|
10 |
+
|
11 |
+
const float INPUT_WIDTH = 640.0;
|
12 |
+
const float INPUT_HEIGHT = 640.0;
|
13 |
+
const float SCORE_THRESHOLD = 0.25;
|
14 |
+
const float NMS_THRESHOLD = 0.45;
|
15 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
16 |
+
const int out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace cv;
|
40 |
+
using namespace std;
|
41 |
+
using namespace Aidlux::Aidlite;
|
42 |
+
|
43 |
+
struct Args {
|
44 |
+
std::string target_model = "../../models/cutoff_yolov8s-seg_fp16.qnn216.ctx.bin";
|
45 |
+
std::string imgs = "../bus.jpg";
|
46 |
+
int invoke_nums = 10;
|
47 |
+
std::string model_type = "QNN";
|
48 |
+
};
|
49 |
+
|
50 |
+
Args parse_args(int argc, char* argv[]) {
|
51 |
+
Args args;
|
52 |
+
for (int i = 1; i < argc; ++i) {
|
53 |
+
std::string arg = argv[i];
|
54 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
55 |
+
args.target_model = argv[++i];
|
56 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
57 |
+
args.imgs = argv[++i];
|
58 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
59 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
60 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
61 |
+
args.model_type = argv[++i];
|
62 |
+
}
|
63 |
+
}
|
64 |
+
return args;
|
65 |
+
}
|
66 |
+
|
67 |
+
std::string to_lower(const std::string& str) {
|
68 |
+
std::string lower_str = str;
|
69 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
70 |
+
return std::tolower(c);
|
71 |
+
});
|
72 |
+
return lower_str;
|
73 |
+
}
|
74 |
+
|
75 |
+
// concatenate_3(80_class_data, 4_pos_data , 32_canc_data, 1, 8400, 80, 4,32, qnn_concat);
|
76 |
+
void concatenate_3(float* qnn_trans_data, float* qnn_mul_data, float* qnn_canc_data, int batch, int num_elements, int trans_dim, int mul_dim, int canc_dim,std::vector<float>& output) {
|
77 |
+
// int out_dim = trans_dim + mul_dim + canc_dim + 1; //117
|
78 |
+
int out_dim = trans_dim + mul_dim + canc_dim; //116
|
79 |
+
output.resize(batch * num_elements * out_dim);
|
80 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
81 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
82 |
+
std::memcpy(&output[i * out_dim + mul_dim], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
83 |
+
std::memcpy(&output[i * out_dim + mul_dim + trans_dim], &qnn_canc_data[i * canc_dim], canc_dim * sizeof(float));
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
// 4*8400
|
88 |
+
void transformData(const float* input, float* output, int C, int N) {
|
89 |
+
for (int c = 0; c < C; ++c) {
|
90 |
+
for (int n = 0; n < N; ++n) {
|
91 |
+
output[n * C + c] = input[c * N + n];
|
92 |
+
}
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
97 |
+
cv::Mat img_processed = frame.clone();
|
98 |
+
int height = img_processed.rows;
|
99 |
+
int width = img_processed.cols;
|
100 |
+
int length = std::max(height, width);
|
101 |
+
double scala = static_cast<double>(length) / size;
|
102 |
+
|
103 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
104 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
105 |
+
|
106 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
107 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
108 |
+
|
109 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
110 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
111 |
+
img_input.convertTo(img_input, CV_32FC3);
|
112 |
+
img_input = (img_input - mean_data) / std_data;
|
113 |
+
return scala;
|
114 |
+
}
|
115 |
+
|
116 |
+
|
117 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
118 |
+
static const std::vector<std::string> hex_colors = {
|
119 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
120 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
121 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
122 |
+
"FF95C8", "FF37C7"
|
123 |
+
};
|
124 |
+
|
125 |
+
int num = hex_colors.size();
|
126 |
+
std::string hex = hex_colors[i % num];
|
127 |
+
|
128 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
129 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
130 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
131 |
+
|
132 |
+
if (bgr)
|
133 |
+
return cv::Scalar(b, g, r);
|
134 |
+
else
|
135 |
+
return cv::Scalar(r, g, b);
|
136 |
+
}
|
137 |
+
|
138 |
+
float sigmoid_function(float a)
|
139 |
+
{
|
140 |
+
float b = 1. / (1. + exp(-a));
|
141 |
+
return b;
|
142 |
+
}
|
143 |
+
|
144 |
+
int transpose(float* src, unsigned int* src_dims, unsigned int* tsp_dims, float* dest){
|
145 |
+
|
146 |
+
int current_coordinate[4] = {0, 0, 0, 0};
|
147 |
+
for(int a = 0; a < src_dims[0]; ++a){
|
148 |
+
current_coordinate[0] = a;
|
149 |
+
for(int b = 0; b < src_dims[1]; ++b){
|
150 |
+
current_coordinate[1] = b;
|
151 |
+
for(int c = 0; c < src_dims[2]; ++c){
|
152 |
+
current_coordinate[2] = c;
|
153 |
+
for(int d = 0; d < src_dims[3]; ++d){
|
154 |
+
current_coordinate[3] = d;
|
155 |
+
|
156 |
+
int old_index = current_coordinate[0]*src_dims[1]*src_dims[2]*src_dims[3] +
|
157 |
+
current_coordinate[1]*src_dims[2]*src_dims[3] +
|
158 |
+
current_coordinate[2]*src_dims[3] +
|
159 |
+
current_coordinate[3];
|
160 |
+
|
161 |
+
int new_index = current_coordinate[tsp_dims[0]]*src_dims[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
162 |
+
current_coordinate[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
163 |
+
current_coordinate[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
164 |
+
current_coordinate[tsp_dims[3]];
|
165 |
+
|
166 |
+
dest[new_index] = src[old_index];
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
return EXIT_SUCCESS;
|
173 |
+
}
|
174 |
+
|
175 |
+
|
176 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
177 |
+
{
|
178 |
+
int baseLine;
|
179 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
180 |
+
int y = top - label_size.height - baseLine;
|
181 |
+
if (y < 0) {
|
182 |
+
y = top ;
|
183 |
+
}
|
184 |
+
cv::Point tlc(left, y);
|
185 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
186 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
187 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
188 |
+
}
|
189 |
+
|
190 |
+
|
191 |
+
cv::Mat post_process(cv::Mat &frame, std::vector<float> &outputs, const std::vector<std::string> &class_name,
|
192 |
+
const double ratio, float* protos_data, float* qnn_canc)
|
193 |
+
{
|
194 |
+
cv::Mat input_image = frame.clone();
|
195 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
196 |
+
std::vector<int> class_ids;
|
197 |
+
std::vector<float> confidences;
|
198 |
+
std::vector<cv::Rect> boxes;
|
199 |
+
std::vector<cv::Mat> masks;
|
200 |
+
std::vector<float> class_scores;
|
201 |
+
cv::RNG rng;
|
202 |
+
cv::Mat masked_img;
|
203 |
+
|
204 |
+
unsigned int src_dims[4] = {1, 32,160,160};
|
205 |
+
unsigned int tsp_dims[4] = {0,3,1,2};
|
206 |
+
unsigned int stride_data_num = 1*32*160*160;
|
207 |
+
float* format_data = new float[stride_data_num];
|
208 |
+
transpose(protos_data, src_dims, tsp_dims, format_data);
|
209 |
+
cv::Mat proto_buffer(32, 160*160, CV_32F, format_data);
|
210 |
+
std::cout << "proto_buffer 维度: " << proto_buffer.rows << "x" << proto_buffer.cols << std::endl;
|
211 |
+
|
212 |
+
for (int i = 0; i < outputs.size(); i+=116)
|
213 |
+
{
|
214 |
+
auto start = outputs.begin() + i + 4;
|
215 |
+
auto end = outputs.begin() + i + 84;
|
216 |
+
float max_val = *std::max_element(start, end);
|
217 |
+
float confidence = max_val;
|
218 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
219 |
+
{
|
220 |
+
auto start = outputs.begin() + i + 4;
|
221 |
+
auto end = outputs.begin() + i + 84;
|
222 |
+
std::vector<float> middle_data;
|
223 |
+
middle_data.assign(start, end);
|
224 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
225 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, middle_data.data());
|
226 |
+
cv::Point class_id;
|
227 |
+
double max_class_score;
|
228 |
+
|
229 |
+
// For multi-label, check each class score
|
230 |
+
for (int c = 0; c < class_name.size(); c++) {
|
231 |
+
float class_score = scores.at<float>(0, c);
|
232 |
+
// If class score is above threshold, consider this class for the box
|
233 |
+
if (class_score > SCORE_THRESHOLD) {
|
234 |
+
std::vector<float> last32_data;
|
235 |
+
auto st_32= outputs.begin() + i + 84;
|
236 |
+
auto ed_32 = outputs.begin() + i + 116;
|
237 |
+
last32_data.assign(st_32, ed_32);
|
238 |
+
cv::Mat mask(1, 32, CV_32FC1, last32_data.data());
|
239 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
240 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
241 |
+
class_ids.push_back(c); // class index
|
242 |
+
// Center and box dimension.
|
243 |
+
float cx = outputs[i];
|
244 |
+
float cy = outputs[i+1];
|
245 |
+
float w = outputs[i+2];
|
246 |
+
float h = outputs[i+3];
|
247 |
+
|
248 |
+
int left = int((cx - 0.5 * w) * ratio);
|
249 |
+
int top = int((cy - 0.48 * h) * ratio);
|
250 |
+
int width = int(w * ratio);
|
251 |
+
int height = int(h * ratio);
|
252 |
+
|
253 |
+
// Store good detections in the boxes vector.
|
254 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
255 |
+
masks.push_back(mask);
|
256 |
+
}
|
257 |
+
}
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
std::cout << "boxes.size(): " << boxes.size() << ",confidences.size():" << confidences.size() << std::endl;
|
262 |
+
|
263 |
+
// Perform Non Maximum Suppression and draw predictions.
|
264 |
+
std::vector<int> indices;
|
265 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
266 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
267 |
+
cv::Mat rgb_mask = cv::Mat::zeros(input_image.size(), input_image.type());
|
268 |
+
|
269 |
+
// Loop over NMS results and draw bounding boxes
|
270 |
+
for (int i = 0; i < indices.size(); i++)
|
271 |
+
{
|
272 |
+
int idx = indices[i];
|
273 |
+
cv::Rect box = boxes[idx];
|
274 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
275 |
+
|
276 |
+
int x1 = std::max(0, box.x);
|
277 |
+
int y1 = std::max(0, box.y);
|
278 |
+
int x2 = std::max(0, box.br().x);
|
279 |
+
int y2 = std::max(0, box.br().y);
|
280 |
+
cv::Mat ms = masks[idx];
|
281 |
+
// 维度验证
|
282 |
+
if (ms.cols != proto_buffer.rows) {
|
283 |
+
cerr << "维度不匹配: mask.cols=" << ms.cols
|
284 |
+
<< ", proto_buffer.rows=" << proto_buffer.rows << endl;
|
285 |
+
continue;
|
286 |
+
}
|
287 |
+
cv::Mat m = ms * proto_buffer;
|
288 |
+
for (int col = 0; col < m.cols; col++) {
|
289 |
+
m.at<float>(0, col) = sigmoid_function(m.at<float>(0, col));
|
290 |
+
}
|
291 |
+
cv::Mat m1 = m.reshape(1, 160); // 1x25600 -> 160x160
|
292 |
+
|
293 |
+
float ratio2 = 160.0/640.0;
|
294 |
+
int mx1 = std::max(0, int((x1 * ratio2)));
|
295 |
+
int mx2 = std::max(0, int((x2 * ratio2)));
|
296 |
+
int my1 = std::max(0, int((y1 * ratio2)));
|
297 |
+
int my2 = std::max(0, int((y2 * ratio2)));
|
298 |
+
cv::Mat mask_roi = m1(cv::Range(my1, my2), cv::Range(mx1, mx2));
|
299 |
+
cv::Mat rm, det_mask;
|
300 |
+
cv::resize(mask_roi, rm, cv::Size(x2 - x1, y2 - y1));
|
301 |
+
for (int r = 0; r < rm.rows; r++) {
|
302 |
+
for (int c = 0; c < rm.cols; c++) {
|
303 |
+
float pv = rm.at<float>(r, c);
|
304 |
+
if (pv > 0.5) {
|
305 |
+
rm.at<float>(r, c) = 1.0;
|
306 |
+
}
|
307 |
+
else {
|
308 |
+
rm.at<float>(r, c) = 0.0;
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
rm = rm * rng.uniform(0, 255);
|
313 |
+
rm.convertTo(det_mask, CV_8UC1);
|
314 |
+
if ((y1 + det_mask.rows) >= input_image.rows) {
|
315 |
+
y2 = input_image.rows - 1;
|
316 |
+
}
|
317 |
+
if ((x1 + det_mask.cols) >= input_image.cols) {
|
318 |
+
x2 = input_image.cols - 1;
|
319 |
+
}
|
320 |
+
|
321 |
+
cv::Mat mask = cv::Mat::zeros(cv::Size(input_image.cols, input_image.rows), CV_8UC1);
|
322 |
+
det_mask(cv::Range(0, y2 - y1), cv::Range(0, x2 - x1)).copyTo(mask(cv::Range(y1, y2), cv::Range(x1, x2)));
|
323 |
+
add(rgb_mask, cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), rgb_mask, mask);
|
324 |
+
if (input_image.size() != rgb_mask.size()) {
|
325 |
+
cv::resize(rgb_mask, rgb_mask, input_image.size());
|
326 |
+
}
|
327 |
+
|
328 |
+
cv::rectangle(input_image, boxes[idx], color, 2, 8);
|
329 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
330 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
331 |
+
cv::putText(input_image, label, cv::Point(boxes[idx].tl().x, boxes[idx].tl().y - 10), cv::FONT_HERSHEY_SIMPLEX, .5, color);
|
332 |
+
cv::addWeighted(input_image, 0.5, rgb_mask, 0.5, 0, masked_img);
|
333 |
+
|
334 |
+
}
|
335 |
+
printf("Processing finished.\n");
|
336 |
+
return masked_img;
|
337 |
+
}
|
338 |
+
|
339 |
+
|
340 |
+
|
341 |
+
int invoke(const Args& args) {
|
342 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
343 |
+
<< "Image Path: " << args.imgs << "\n"
|
344 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
345 |
+
<< "Model Type: " << args.model_type << "\n";
|
346 |
+
Model* model = Model::create_instance(args.target_model);
|
347 |
+
if(model == nullptr){
|
348 |
+
printf("Create model failed !\n");
|
349 |
+
return EXIT_FAILURE;
|
350 |
+
}
|
351 |
+
Config* config = Config::create_instance();
|
352 |
+
if(config == nullptr){
|
353 |
+
printf("Create config failed !\n");
|
354 |
+
return EXIT_FAILURE;
|
355 |
+
}
|
356 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
357 |
+
std::string model_type_lower = to_lower(args.model_type);
|
358 |
+
if (model_type_lower == "qnn"){
|
359 |
+
config->framework_type = FrameworkType::TYPE_QNN;
|
360 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
361 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
362 |
+
}
|
363 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
364 |
+
config->is_quantify_model = 1;
|
365 |
+
|
366 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, 640, 640, 3}};
|
367 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1,32,8400},{1,4,8400},{1,80,8400},{1,160, 160,32}};
|
368 |
+
model->set_model_properties(input_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32, output_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32);
|
369 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
370 |
+
if(fast_interpreter == nullptr){
|
371 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
372 |
+
return EXIT_FAILURE;
|
373 |
+
}
|
374 |
+
int result = fast_interpreter->init();
|
375 |
+
if(result != EXIT_SUCCESS){
|
376 |
+
printf("interpreter->init() failed !\n");
|
377 |
+
return EXIT_FAILURE;
|
378 |
+
}
|
379 |
+
// load model
|
380 |
+
fast_interpreter->load_model();
|
381 |
+
if(result != EXIT_SUCCESS){
|
382 |
+
printf("interpreter->load_model() failed !\n");
|
383 |
+
return EXIT_FAILURE;
|
384 |
+
}
|
385 |
+
printf("detect model load success!\n");
|
386 |
+
|
387 |
+
cv::Mat frame = cv::imread(args.imgs);
|
388 |
+
if (frame.empty()) {
|
389 |
+
printf("detect image load failed!\n");
|
390 |
+
return 1;
|
391 |
+
}
|
392 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
393 |
+
cv::Mat input_img;
|
394 |
+
double scale = img_process(frame, input_img, 640);
|
395 |
+
if (input_img.empty()) {
|
396 |
+
printf("detect input_img load failed!\n");
|
397 |
+
return 1;
|
398 |
+
}
|
399 |
+
|
400 |
+
float *qnn_seg_data = nullptr;
|
401 |
+
float *qnn_trans_data = nullptr;
|
402 |
+
float *qnn_mul_data = nullptr;
|
403 |
+
float *qnn_canc_data = nullptr;
|
404 |
+
|
405 |
+
std::vector<float> invoke_time;
|
406 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
407 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
408 |
+
if(result != EXIT_SUCCESS){
|
409 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
410 |
+
return EXIT_FAILURE;
|
411 |
+
}
|
412 |
+
// 开始计时
|
413 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
414 |
+
result = fast_interpreter->invoke();
|
415 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
416 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
417 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
418 |
+
if(result != EXIT_SUCCESS){
|
419 |
+
printf("interpreter->invoke() failed !\n");
|
420 |
+
return EXIT_FAILURE;
|
421 |
+
}
|
422 |
+
uint32_t out_data_1 = 0;
|
423 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_canc_data, &out_data_1);
|
424 |
+
if(result != EXIT_SUCCESS){
|
425 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
426 |
+
return EXIT_FAILURE;
|
427 |
+
}
|
428 |
+
|
429 |
+
uint32_t out_data_4 = 0;
|
430 |
+
result = fast_interpreter->get_output_tensor(2, (void**)&qnn_trans_data, &out_data_4);
|
431 |
+
if(result != EXIT_SUCCESS){
|
432 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
433 |
+
return EXIT_FAILURE;
|
434 |
+
}
|
435 |
+
|
436 |
+
uint32_t out_data_2 = 0;
|
437 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_seg_data, &out_data_2);
|
438 |
+
if(result != EXIT_SUCCESS){
|
439 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
440 |
+
return EXIT_FAILURE;
|
441 |
+
}
|
442 |
+
|
443 |
+
uint32_t out_data_80 = 0;
|
444 |
+
result = fast_interpreter->get_output_tensor(3, (void**)&qnn_mul_data, &out_data_80);
|
445 |
+
if(result != EXIT_SUCCESS){
|
446 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
447 |
+
return EXIT_FAILURE;
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
452 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
453 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
454 |
+
float var_invoketime = 0.0f;
|
455 |
+
for (auto time : invoke_time) {
|
456 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
457 |
+
}
|
458 |
+
var_invoketime /= args.invoke_nums;
|
459 |
+
printf("=======================================\n");
|
460 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
461 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
462 |
+
printf("=======================================\n");
|
463 |
+
|
464 |
+
float* pos_data = new float[4 * out_size];
|
465 |
+
float* class_data = new float[80 * out_size];
|
466 |
+
float* canc_data = new float[32 * out_size];
|
467 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
468 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
469 |
+
transformData(qnn_canc_data, canc_data, 32, out_size);
|
470 |
+
|
471 |
+
// post process
|
472 |
+
std::vector<float> qnn_concat;
|
473 |
+
concatenate_3(class_data, pos_data, canc_data , 1, out_size, 80, 4, 32, qnn_concat);
|
474 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale, qnn_seg_data, qnn_canc_data);
|
475 |
+
cv::imwrite("./results.png", img);
|
476 |
+
fast_interpreter->destory();
|
477 |
+
return 0;
|
478 |
+
}
|
479 |
+
|
480 |
+
|
481 |
+
int main(int argc, char* argv[]) {
|
482 |
+
Args args = parse_args(argc, argv);
|
483 |
+
return invoke(args);
|
484 |
+
}
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/models/cutoff_yolov8s-seg_fp16.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0e45c04396d4e658baad5bf5db76fea2ea8e1cb7694bfb17b5a2677cb92af0a0
|
3 |
+
size 24361344
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS, process_mask, masks2segments, draw_detect_res
|
5 |
+
import os
|
6 |
+
import time
|
7 |
+
import argparse
|
8 |
+
import onnxruntime
|
9 |
+
|
10 |
+
# 定义相似度函数
|
11 |
+
def get_acc(onnx_out,other_out):
|
12 |
+
cosine_similarity=np.dot(np.array(onnx_out),np.array(other_out))/(np.linalg.norm(np.array(onnx_out)) * np.linalg.norm(np.array(other_out)))
|
13 |
+
return cosine_similarity
|
14 |
+
|
15 |
+
|
16 |
+
class qnn_predict(object):
|
17 |
+
def __init__(self,args) -> None:
|
18 |
+
# aidlite.set_log_level(aidlite.LogLevel.INFO)
|
19 |
+
# aidlite.log_to_stderr()
|
20 |
+
# print(f"Aidlite library version : {aidlite.get_library_version()}")
|
21 |
+
# print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
22 |
+
config = aidlite.Config.create_instance()
|
23 |
+
if config is None:
|
24 |
+
print("Create model failed !")
|
25 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
26 |
+
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
27 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
28 |
+
config.is_quantify_model = 1
|
29 |
+
|
30 |
+
model = aidlite.Model.create_instance(args.target_model)
|
31 |
+
if model is None:
|
32 |
+
print("Create model failed !")
|
33 |
+
|
34 |
+
self.conf = args.conf_thres
|
35 |
+
self.iou=args.iou_thres
|
36 |
+
self.width = args.width
|
37 |
+
self.height = args.height
|
38 |
+
self.class_num = args.class_num
|
39 |
+
self.input_shape = [[1,self.height,self.width,3]]
|
40 |
+
self.blocks = int(self.height * self.width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
41 |
+
self.maskw = int(self.width / 4)
|
42 |
+
self.maskh = int(self.height / 4)
|
43 |
+
self.output_shape = [[1,32,self.blocks],[1,4,self.blocks],[1,self.class_num,self.blocks],[1,self.maskh, self.maskw,32]]
|
44 |
+
|
45 |
+
model.set_model_properties(self.input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
46 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
47 |
+
if self.interpreter is None:
|
48 |
+
print("build_interpretper_from_model_and_config failed !")
|
49 |
+
result = self.interpreter.init()
|
50 |
+
if result != 0:
|
51 |
+
print(f"interpreter init failed !")
|
52 |
+
result = self.interpreter.load_model()
|
53 |
+
if result != 0:
|
54 |
+
print("interpreter load model failed !")
|
55 |
+
print("detect model load success!")
|
56 |
+
|
57 |
+
def pretreat_img(self,frame):
|
58 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
59 |
+
img = img / 255
|
60 |
+
img = img.astype(np.float32)
|
61 |
+
return img,scale
|
62 |
+
|
63 |
+
def qnn_run(self, orig_imgs,args):
|
64 |
+
input_img_f,scale=self.pretreat_img(orig_imgs) # 图片resize HWC
|
65 |
+
input_img = np.expand_dims(input_img_f, 0)
|
66 |
+
|
67 |
+
invoke_time=[]
|
68 |
+
for i in range(args.invoke_nums):
|
69 |
+
self.interpreter.set_input_tensor(0, input_img.data)
|
70 |
+
t0 = time.time()
|
71 |
+
self.interpreter.invoke()
|
72 |
+
t1 = time.time()
|
73 |
+
cost_time=(t1-t0)*1000
|
74 |
+
invoke_time.append(cost_time)
|
75 |
+
|
76 |
+
input0_data = self.interpreter.get_output_tensor(2).reshape(1,4,self.blocks)
|
77 |
+
input1_data = self.interpreter.get_output_tensor(3).reshape(1,self.class_num,self.blocks)
|
78 |
+
input2_data = self.interpreter.get_output_tensor(1).reshape(1,32,self.blocks)
|
79 |
+
protos = self.interpreter.get_output_tensor(0).reshape(1,self.maskh, self.maskw,32).transpose(0,3,1,2)
|
80 |
+
|
81 |
+
boxes = np.concatenate([input0_data, input1_data, input2_data], axis = 1)
|
82 |
+
x = boxes.transpose(0,2,1)
|
83 |
+
x = x[np.amax(x[..., 4:-32], axis=-1) > self.conf]
|
84 |
+
if len(x) < 1:
|
85 |
+
return None, None
|
86 |
+
|
87 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:-32], axis=-1), np.argmax(x[..., 4:-32], axis=-1), x[..., -32:]]
|
88 |
+
|
89 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
90 |
+
index = NMS(x[:, :4], x[:, 4], self.iou)
|
91 |
+
out_boxes = x[index]
|
92 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
93 |
+
|
94 |
+
masks = process_mask(protos[0], out_boxes[:, -32:], out_boxes[:, :4], orig_imgs.shape)
|
95 |
+
segments = masks2segments(masks)
|
96 |
+
|
97 |
+
## time 统计
|
98 |
+
max_invoke_time = max(invoke_time)
|
99 |
+
min_invoke_time = min(invoke_time)
|
100 |
+
mean_invoke_time = sum(invoke_time)/args.invoke_nums
|
101 |
+
var_invoketime=np.var(invoke_time)
|
102 |
+
print("========================================")
|
103 |
+
print(f"QNN inference {args.invoke_nums} times :\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
104 |
+
print("========================================")
|
105 |
+
|
106 |
+
return out_boxes, segments
|
107 |
+
|
108 |
+
|
109 |
+
def parser_args():
|
110 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
111 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s-seg_fp16.qnn216.ctx.bin',help="inference model path")
|
112 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
113 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
114 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
115 |
+
parser.add_argument('--width',type=int,default=640,help="Model input size")
|
116 |
+
parser.add_argument('--height',type=int,default=640,help="Model input size")
|
117 |
+
parser.add_argument('--conf_thres',type=float,default=0.45,help="confidence threshold for filtering the annotations")
|
118 |
+
parser.add_argument('--iou_thres',type=float,default=0.45,help="Iou threshold for filtering the annotations")
|
119 |
+
parser.add_argument('--class_num',type=int,default=80,help="Iou threshold for filtering the annotations")
|
120 |
+
args = parser.parse_args()
|
121 |
+
return args
|
122 |
+
|
123 |
+
def main(args):
|
124 |
+
model = qnn_predict(args)
|
125 |
+
frame = cv2.imread(args.imgs)
|
126 |
+
qnn_out_boxes, qnn_segments = model.qnn_run(frame,args)
|
127 |
+
result = draw_detect_res(frame, qnn_out_boxes, qnn_segments)
|
128 |
+
cv2.imwrite("./python/bus_result.jpg", result)
|
129 |
+
|
130 |
+
if __name__ == "__main__":
|
131 |
+
args = parser_args()
|
132 |
+
main(args)
|
133 |
+
|
134 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_fp16_aidlite/python/utils.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
def draw_detect_res(img, det_pred, segments):
|
72 |
+
'''
|
73 |
+
检测结果绘制
|
74 |
+
'''
|
75 |
+
if det_pred is None:
|
76 |
+
return img
|
77 |
+
|
78 |
+
img = img.astype(np.uint8)
|
79 |
+
im_canvas = img.copy()
|
80 |
+
color_step = int(255/len(CLASSES))
|
81 |
+
for i in range(len(det_pred)):
|
82 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
83 |
+
cls_id = int(det_pred[i][5])
|
84 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
85 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
86 |
+
if len(segments[i]) > 0:
|
87 |
+
cv2.polylines(img, np.int32([segments[i]]), True, (0, int(cls_id*color_step), int(255-cls_id*color_step)), 2)
|
88 |
+
cv2.fillPoly(img, np.int32([segments[i]]), (0, int(cls_id*color_step), int(255-cls_id*color_step)))
|
89 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
90 |
+
return img
|
91 |
+
|
92 |
+
def scale_mask(masks, im0_shape):
|
93 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
94 |
+
interpolation=cv2.INTER_LINEAR)
|
95 |
+
if len(masks.shape) == 2:
|
96 |
+
masks = masks[:, :, None]
|
97 |
+
return masks
|
98 |
+
|
99 |
+
def crop_mask(masks, boxes):
|
100 |
+
n, h, w = masks.shape
|
101 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
102 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
103 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
104 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
105 |
+
|
106 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
107 |
+
c, mh, mw = protos.shape
|
108 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
109 |
+
masks = np.ascontiguousarray(masks)
|
110 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
111 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
112 |
+
masks = crop_mask(masks, bboxes)
|
113 |
+
return np.greater(masks, 0.5)
|
114 |
+
|
115 |
+
def masks2segments(masks):
|
116 |
+
segments = []
|
117 |
+
for x in masks.astype('uint8'):
|
118 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
119 |
+
if c:
|
120 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
121 |
+
else:
|
122 |
+
c = np.zeros((0, 2)) # no segments found
|
123 |
+
segments.append(c.astype('float32'))
|
124 |
+
return segments
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
## Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 11.27M
|
5 |
+
- Model size: 45.22M
|
6 |
+
- Output shape: 1x32x160x160, 1x116x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: W8A16
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: SNM972 QCS8550
|
15 |
+
|
16 |
+
## Inference with AidLite SDK
|
17 |
+
|
18 |
+
### SDK installation
|
19 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
20 |
+
|
21 |
+
- Install AidLite SDK
|
22 |
+
|
23 |
+
```bash
|
24 |
+
# Install the appropriate version of the aidlite sdk
|
25 |
+
sudo aid-pkg update
|
26 |
+
sudo aid-pkg install aidlite-sdk
|
27 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
28 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
29 |
+
```
|
30 |
+
|
31 |
+
- Verify AidLite SDK
|
32 |
+
|
33 |
+
```bash
|
34 |
+
# aidlite sdk c++ check
|
35 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
36 |
+
|
37 |
+
# aidlite sdk python check
|
38 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
39 |
+
```
|
40 |
+
|
41 |
+
### Run demo
|
42 |
+
#### python
|
43 |
+
```bash
|
44 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite
|
45 |
+
python3 ./python/run_test.py --target_model ./models/cutoff_yolov8s-seg_w8a16.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
46 |
+
```
|
47 |
+
|
48 |
+
#### cpp
|
49 |
+
```bash
|
50 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp
|
51 |
+
mkdir build && cd build
|
52 |
+
cmake ..
|
53 |
+
make
|
54 |
+
./run_test
|
55 |
+
```
|
56 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/run_test.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
pthread
|
31 |
+
)
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/cpp/run_test.cpp
ADDED
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <cstring> // 用于 memcpy
|
6 |
+
#include <opencv2/opencv.hpp>
|
7 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
8 |
+
#include <vector>
|
9 |
+
#include <numeric>
|
10 |
+
|
11 |
+
const float INPUT_WIDTH = 640.0;
|
12 |
+
const float INPUT_HEIGHT = 640.0;
|
13 |
+
const float SCORE_THRESHOLD = 0.25;
|
14 |
+
const float NMS_THRESHOLD = 0.45;
|
15 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
16 |
+
const uint32_t out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace cv;
|
40 |
+
using namespace std;
|
41 |
+
using namespace Aidlux::Aidlite;
|
42 |
+
|
43 |
+
struct Args {
|
44 |
+
std::string target_model = "../../models/cutoff_yolov8s-seg_w8a16.qnn216.ctx.bin";
|
45 |
+
std::string imgs = "../bus.jpg";
|
46 |
+
int invoke_nums = 10;
|
47 |
+
std::string model_type = "QNN";
|
48 |
+
};
|
49 |
+
|
50 |
+
Args parse_args(int argc, char* argv[]) {
|
51 |
+
Args args;
|
52 |
+
for (int i = 1; i < argc; ++i) {
|
53 |
+
std::string arg = argv[i];
|
54 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
55 |
+
args.target_model = argv[++i];
|
56 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
57 |
+
args.imgs = argv[++i];
|
58 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
59 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
60 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
61 |
+
args.model_type = argv[++i];
|
62 |
+
}
|
63 |
+
}
|
64 |
+
return args;
|
65 |
+
}
|
66 |
+
|
67 |
+
std::string to_lower(const std::string& str) {
|
68 |
+
std::string lower_str = str;
|
69 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
70 |
+
return std::tolower(c);
|
71 |
+
});
|
72 |
+
return lower_str;
|
73 |
+
}
|
74 |
+
|
75 |
+
// concatenate_3(80_class_data, 4_pos_data , 32_canc_data, 1, 8400, 80, 4,32, qnn_concat);
|
76 |
+
void concatenate_3(float* qnn_trans_data, float* qnn_mul_data, float* qnn_canc_data, int batch, int num_elements, int trans_dim, int mul_dim, int canc_dim,std::vector<float>& output) {
|
77 |
+
// int out_dim = trans_dim + mul_dim + canc_dim + 1; //117
|
78 |
+
int out_dim = trans_dim + mul_dim + canc_dim; //116
|
79 |
+
output.resize(batch * num_elements * out_dim);
|
80 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
81 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
82 |
+
std::memcpy(&output[i * out_dim + mul_dim], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
83 |
+
std::memcpy(&output[i * out_dim + mul_dim + trans_dim], &qnn_canc_data[i * canc_dim], canc_dim * sizeof(float));
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
// 4*8400
|
88 |
+
void transformData(const float* input, float* output, int C, int N) {
|
89 |
+
for (int c = 0; c < C; ++c) {
|
90 |
+
for (int n = 0; n < N; ++n) {
|
91 |
+
output[n * C + c] = input[c * N + n];
|
92 |
+
}
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
97 |
+
cv::Mat img_processed = frame.clone();
|
98 |
+
int height = img_processed.rows;
|
99 |
+
int width = img_processed.cols;
|
100 |
+
int length = std::max(height, width);
|
101 |
+
double scala = static_cast<double>(length) / size;
|
102 |
+
|
103 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
104 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
105 |
+
|
106 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
107 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
108 |
+
|
109 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
110 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
111 |
+
img_input.convertTo(img_input, CV_32FC3);
|
112 |
+
img_input = (img_input - mean_data) / std_data;
|
113 |
+
return scala;
|
114 |
+
}
|
115 |
+
|
116 |
+
|
117 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
118 |
+
static const std::vector<std::string> hex_colors = {
|
119 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
120 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
121 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
122 |
+
"FF95C8", "FF37C7"
|
123 |
+
};
|
124 |
+
|
125 |
+
int num = hex_colors.size();
|
126 |
+
std::string hex = hex_colors[i % num];
|
127 |
+
|
128 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
129 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
130 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
131 |
+
|
132 |
+
if (bgr)
|
133 |
+
return cv::Scalar(b, g, r);
|
134 |
+
else
|
135 |
+
return cv::Scalar(r, g, b);
|
136 |
+
}
|
137 |
+
|
138 |
+
float sigmoid_function(float a)
|
139 |
+
{
|
140 |
+
float b = 1. / (1. + exp(-a));
|
141 |
+
return b;
|
142 |
+
}
|
143 |
+
|
144 |
+
int transpose(float* src, unsigned int* src_dims, unsigned int* tsp_dims, float* dest){
|
145 |
+
|
146 |
+
int current_coordinate[4] = {0, 0, 0, 0};
|
147 |
+
for(int a = 0; a < src_dims[0]; ++a){
|
148 |
+
current_coordinate[0] = a;
|
149 |
+
for(int b = 0; b < src_dims[1]; ++b){
|
150 |
+
current_coordinate[1] = b;
|
151 |
+
for(int c = 0; c < src_dims[2]; ++c){
|
152 |
+
current_coordinate[2] = c;
|
153 |
+
for(int d = 0; d < src_dims[3]; ++d){
|
154 |
+
current_coordinate[3] = d;
|
155 |
+
|
156 |
+
int old_index = current_coordinate[0]*src_dims[1]*src_dims[2]*src_dims[3] +
|
157 |
+
current_coordinate[1]*src_dims[2]*src_dims[3] +
|
158 |
+
current_coordinate[2]*src_dims[3] +
|
159 |
+
current_coordinate[3];
|
160 |
+
|
161 |
+
int new_index = current_coordinate[tsp_dims[0]]*src_dims[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
162 |
+
current_coordinate[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
163 |
+
current_coordinate[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
164 |
+
current_coordinate[tsp_dims[3]];
|
165 |
+
|
166 |
+
dest[new_index] = src[old_index];
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
return EXIT_SUCCESS;
|
173 |
+
}
|
174 |
+
|
175 |
+
|
176 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
177 |
+
{
|
178 |
+
int baseLine;
|
179 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
180 |
+
int y = top - label_size.height - baseLine;
|
181 |
+
if (y < 0) {
|
182 |
+
y = top ;
|
183 |
+
}
|
184 |
+
cv::Point tlc(left, y);
|
185 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
186 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
187 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
188 |
+
}
|
189 |
+
|
190 |
+
|
191 |
+
cv::Mat post_process(cv::Mat &frame, std::vector<float> &outputs, const std::vector<std::string> &class_name,
|
192 |
+
const double ratio, float* protos_data, float* qnn_canc)
|
193 |
+
{
|
194 |
+
cv::Mat input_image = frame.clone();
|
195 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
196 |
+
std::vector<int> class_ids;
|
197 |
+
std::vector<float> confidences;
|
198 |
+
std::vector<cv::Rect> boxes;
|
199 |
+
std::vector<cv::Mat> masks;
|
200 |
+
std::vector<float> class_scores;
|
201 |
+
cv::RNG rng;
|
202 |
+
cv::Mat masked_img;
|
203 |
+
|
204 |
+
unsigned int src_dims[4] = {1, 32,160,160};
|
205 |
+
unsigned int tsp_dims[4] = {0,3,1,2};
|
206 |
+
unsigned int stride_data_num = 1*32*160*160;
|
207 |
+
float* format_data = new float[stride_data_num];
|
208 |
+
transpose(protos_data, src_dims, tsp_dims, format_data);
|
209 |
+
cv::Mat proto_buffer(32, 160*160, CV_32F, format_data);
|
210 |
+
std::cout << "proto_buffer 维度: " << proto_buffer.rows << "x" << proto_buffer.cols << std::endl;
|
211 |
+
|
212 |
+
for (int i = 0; i < outputs.size(); i+=116)
|
213 |
+
{
|
214 |
+
auto start = outputs.begin() + i + 4;
|
215 |
+
auto end = outputs.begin() + i + 84;
|
216 |
+
float max_val = *std::max_element(start, end);
|
217 |
+
float confidence = max_val;
|
218 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
219 |
+
{
|
220 |
+
auto start = outputs.begin() + i + 4;
|
221 |
+
auto end = outputs.begin() + i + 84;
|
222 |
+
std::vector<float> middle_data;
|
223 |
+
middle_data.assign(start, end);
|
224 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
225 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, middle_data.data());
|
226 |
+
cv::Point class_id;
|
227 |
+
double max_class_score;
|
228 |
+
|
229 |
+
// For multi-label, check each class score
|
230 |
+
for (int c = 0; c < class_name.size(); c++) {
|
231 |
+
float class_score = scores.at<float>(0, c);
|
232 |
+
// If class score is above threshold, consider this class for the box
|
233 |
+
if (class_score > SCORE_THRESHOLD) {
|
234 |
+
std::vector<float> last32_data;
|
235 |
+
auto st_32= outputs.begin() + i + 84;
|
236 |
+
auto ed_32 = outputs.begin() + i + 116;
|
237 |
+
last32_data.assign(st_32, ed_32);
|
238 |
+
cv::Mat mask(1, 32, CV_32FC1, last32_data.data());
|
239 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
240 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
241 |
+
class_ids.push_back(c); // class index
|
242 |
+
// Center and box dimension.
|
243 |
+
float cx = outputs[i];
|
244 |
+
float cy = outputs[i+1];
|
245 |
+
float w = outputs[i+2];
|
246 |
+
float h = outputs[i+3];
|
247 |
+
|
248 |
+
int left = int((cx - 0.5 * w) * ratio);
|
249 |
+
int top = int((cy - 0.48 * h) * ratio);
|
250 |
+
int width = int(w * ratio);
|
251 |
+
int height = int(h * ratio);
|
252 |
+
|
253 |
+
// Store good detections in the boxes vector.
|
254 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
255 |
+
masks.push_back(mask);
|
256 |
+
}
|
257 |
+
}
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
std::cout << "boxes.size(): " << boxes.size() << ",confidences.size():" << confidences.size() << std::endl;
|
262 |
+
|
263 |
+
// Perform Non Maximum Suppression and draw predictions.
|
264 |
+
std::vector<int> indices;
|
265 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
266 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
267 |
+
cv::Mat rgb_mask = cv::Mat::zeros(input_image.size(), input_image.type());
|
268 |
+
|
269 |
+
// Loop over NMS results and draw bounding boxes
|
270 |
+
for (int i = 0; i < indices.size(); i++)
|
271 |
+
{
|
272 |
+
int idx = indices[i];
|
273 |
+
cv::Rect box = boxes[idx];
|
274 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
275 |
+
|
276 |
+
int x1 = std::max(0, box.x);
|
277 |
+
int y1 = std::max(0, box.y);
|
278 |
+
int x2 = std::max(0, box.br().x);
|
279 |
+
int y2 = std::max(0, box.br().y);
|
280 |
+
cv::Mat ms = masks[idx];
|
281 |
+
// 维度验证
|
282 |
+
if (ms.cols != proto_buffer.rows) {
|
283 |
+
cerr << "维度不匹配: mask.cols=" << ms.cols
|
284 |
+
<< ", proto_buffer.rows=" << proto_buffer.rows << endl;
|
285 |
+
continue;
|
286 |
+
}
|
287 |
+
cv::Mat m = ms * proto_buffer;
|
288 |
+
for (int col = 0; col < m.cols; col++) {
|
289 |
+
m.at<float>(0, col) = sigmoid_function(m.at<float>(0, col));
|
290 |
+
}
|
291 |
+
cv::Mat m1 = m.reshape(1, 160); // 1x25600 -> 160x160
|
292 |
+
|
293 |
+
float ratio2 = 160.0/640.0;
|
294 |
+
int mx1 = std::max(0, int((x1 * ratio2)));
|
295 |
+
int mx2 = std::max(0, int((x2 * ratio2)));
|
296 |
+
int my1 = std::max(0, int((y1 * ratio2)));
|
297 |
+
int my2 = std::max(0, int((y2 * ratio2)));
|
298 |
+
cv::Mat mask_roi = m1(cv::Range(my1, my2), cv::Range(mx1, mx2));
|
299 |
+
cv::Mat rm, det_mask;
|
300 |
+
cv::resize(mask_roi, rm, cv::Size(x2 - x1, y2 - y1));
|
301 |
+
for (int r = 0; r < rm.rows; r++) {
|
302 |
+
for (int c = 0; c < rm.cols; c++) {
|
303 |
+
float pv = rm.at<float>(r, c);
|
304 |
+
if (pv > 0.5) {
|
305 |
+
rm.at<float>(r, c) = 1.0;
|
306 |
+
}
|
307 |
+
else {
|
308 |
+
rm.at<float>(r, c) = 0.0;
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
rm = rm * rng.uniform(0, 255);
|
313 |
+
rm.convertTo(det_mask, CV_8UC1);
|
314 |
+
if ((y1 + det_mask.rows) >= input_image.rows) {
|
315 |
+
y2 = input_image.rows - 1;
|
316 |
+
}
|
317 |
+
if ((x1 + det_mask.cols) >= input_image.cols) {
|
318 |
+
x2 = input_image.cols - 1;
|
319 |
+
}
|
320 |
+
|
321 |
+
cv::Mat mask = cv::Mat::zeros(cv::Size(input_image.cols, input_image.rows), CV_8UC1);
|
322 |
+
det_mask(cv::Range(0, y2 - y1), cv::Range(0, x2 - x1)).copyTo(mask(cv::Range(y1, y2), cv::Range(x1, x2)));
|
323 |
+
add(rgb_mask, cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), rgb_mask, mask);
|
324 |
+
if (input_image.size() != rgb_mask.size()) {
|
325 |
+
cv::resize(rgb_mask, rgb_mask, input_image.size());
|
326 |
+
}
|
327 |
+
|
328 |
+
cv::rectangle(input_image, boxes[idx], color, 2, 8);
|
329 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
330 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
331 |
+
cv::putText(input_image, label, cv::Point(boxes[idx].tl().x, boxes[idx].tl().y - 10), cv::FONT_HERSHEY_SIMPLEX, .5, color);
|
332 |
+
cv::addWeighted(input_image, 0.5, rgb_mask, 0.5, 0, masked_img);
|
333 |
+
|
334 |
+
}
|
335 |
+
printf("Processing finished.\n");
|
336 |
+
return masked_img;
|
337 |
+
}
|
338 |
+
|
339 |
+
|
340 |
+
|
341 |
+
int invoke(const Args& args) {
|
342 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
343 |
+
<< "Image Path: " << args.imgs << "\n"
|
344 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
345 |
+
<< "Model Type: " << args.model_type << "\n";
|
346 |
+
Model* model = Model::create_instance(args.target_model);
|
347 |
+
if(model == nullptr){
|
348 |
+
printf("Create model failed !\n");
|
349 |
+
return EXIT_FAILURE;
|
350 |
+
}
|
351 |
+
Config* config = Config::create_instance();
|
352 |
+
if(config == nullptr){
|
353 |
+
printf("Create config failed !\n");
|
354 |
+
return EXIT_FAILURE;
|
355 |
+
}
|
356 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
357 |
+
std::string model_type_lower = to_lower(args.model_type);
|
358 |
+
if (model_type_lower == "qnn"){
|
359 |
+
config->framework_type = FrameworkType::TYPE_QNN216;
|
360 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
361 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
362 |
+
}
|
363 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
364 |
+
config->is_quantify_model = 1;
|
365 |
+
|
366 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, 640, 640, 3}};
|
367 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1,32,8400},{1,4,8400},{1,80,8400},{1,160, 160,32}};
|
368 |
+
model->set_model_properties(input_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32, output_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32);
|
369 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
370 |
+
if(fast_interpreter == nullptr){
|
371 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
372 |
+
return EXIT_FAILURE;
|
373 |
+
}
|
374 |
+
int result = fast_interpreter->init();
|
375 |
+
if(result != EXIT_SUCCESS){
|
376 |
+
printf("interpreter->init() failed !\n");
|
377 |
+
return EXIT_FAILURE;
|
378 |
+
}
|
379 |
+
// load model
|
380 |
+
fast_interpreter->load_model();
|
381 |
+
if(result != EXIT_SUCCESS){
|
382 |
+
printf("interpreter->load_model() failed !\n");
|
383 |
+
return EXIT_FAILURE;
|
384 |
+
}
|
385 |
+
printf("detect model load success!\n");
|
386 |
+
|
387 |
+
cv::Mat frame = cv::imread(args.imgs);
|
388 |
+
if (frame.empty()) {
|
389 |
+
printf("detect image load failed!\n");
|
390 |
+
return 1;
|
391 |
+
}
|
392 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
393 |
+
cv::Mat input_img;
|
394 |
+
double scale = img_process(frame, input_img, 640);
|
395 |
+
if (input_img.empty()) {
|
396 |
+
printf("detect input_img load failed!\n");
|
397 |
+
return 1;
|
398 |
+
}
|
399 |
+
|
400 |
+
float *qnn_seg_data = nullptr;
|
401 |
+
float *qnn_trans_data = nullptr;
|
402 |
+
float *qnn_mul_data = nullptr;
|
403 |
+
float *qnn_canc_data = nullptr;
|
404 |
+
|
405 |
+
std::vector<float> invoke_time;
|
406 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
407 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
408 |
+
if(result != EXIT_SUCCESS){
|
409 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
410 |
+
return EXIT_FAILURE;
|
411 |
+
}
|
412 |
+
// 开始计时
|
413 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
414 |
+
result = fast_interpreter->invoke();
|
415 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
416 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
417 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
418 |
+
if(result != EXIT_SUCCESS){
|
419 |
+
printf("interpreter->invoke() failed !\n");
|
420 |
+
return EXIT_FAILURE;
|
421 |
+
}
|
422 |
+
uint32_t out_data_1 = 0;
|
423 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_canc_data, &out_data_1);
|
424 |
+
if(result != EXIT_SUCCESS){
|
425 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
426 |
+
return EXIT_FAILURE;
|
427 |
+
}
|
428 |
+
|
429 |
+
uint32_t out_data_4 = 0;
|
430 |
+
result = fast_interpreter->get_output_tensor(2, (void**)&qnn_trans_data, &out_data_4);
|
431 |
+
if(result != EXIT_SUCCESS){
|
432 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
433 |
+
return EXIT_FAILURE;
|
434 |
+
}
|
435 |
+
|
436 |
+
uint32_t out_data_2 = 0;
|
437 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_seg_data, &out_data_2);
|
438 |
+
if(result != EXIT_SUCCESS){
|
439 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
440 |
+
return EXIT_FAILURE;
|
441 |
+
}
|
442 |
+
|
443 |
+
uint32_t out_data_80 = 0;
|
444 |
+
result = fast_interpreter->get_output_tensor(3, (void**)&qnn_mul_data, &out_data_80);
|
445 |
+
if(result != EXIT_SUCCESS){
|
446 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
447 |
+
return EXIT_FAILURE;
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
452 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
453 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
454 |
+
float var_invoketime = 0.0f;
|
455 |
+
for (auto time : invoke_time) {
|
456 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
457 |
+
}
|
458 |
+
var_invoketime /= args.invoke_nums;
|
459 |
+
printf("=======================================\n");
|
460 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
461 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
462 |
+
printf("=======================================\n");
|
463 |
+
|
464 |
+
float* pos_data = new float[4 * out_size];
|
465 |
+
float* class_data = new float[80 * out_size];
|
466 |
+
float* canc_data = new float[32 * out_size];
|
467 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
468 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
469 |
+
transformData(qnn_canc_data, canc_data, 32, out_size);
|
470 |
+
|
471 |
+
// post process
|
472 |
+
std::vector<float> qnn_concat;
|
473 |
+
concatenate_3(class_data, pos_data, canc_data , 1, out_size, 80, 4, 32, qnn_concat);
|
474 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale, qnn_seg_data, qnn_canc_data);
|
475 |
+
cv::imwrite("./results.png", img);
|
476 |
+
fast_interpreter->destory();
|
477 |
+
return 0;
|
478 |
+
}
|
479 |
+
|
480 |
+
|
481 |
+
int main(int argc, char* argv[]) {
|
482 |
+
Args args = parse_args(argc, argv);
|
483 |
+
return invoke(args);
|
484 |
+
}
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/models/cutoff_yolov8s-seg_w8a16.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:a91723cbfce181aa057abc23ff0884dc8bb9d81a1acad745a62b6d9d22c7b9ab
|
3 |
+
size 12765624
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS, process_mask, masks2segments, draw_detect_res
|
5 |
+
import os
|
6 |
+
import time
|
7 |
+
import argparse
|
8 |
+
import onnxruntime
|
9 |
+
|
10 |
+
# 定义相似度函数
|
11 |
+
def get_acc(onnx_out,other_out):
|
12 |
+
cosine_similarity=np.dot(np.array(onnx_out),np.array(other_out))/(np.linalg.norm(np.array(onnx_out)) * np.linalg.norm(np.array(other_out)))
|
13 |
+
return cosine_similarity
|
14 |
+
|
15 |
+
|
16 |
+
class qnn_predict(object):
|
17 |
+
def __init__(self,args) -> None:
|
18 |
+
# aidlite.set_log_level(aidlite.LogLevel.INFO)
|
19 |
+
# aidlite.log_to_stderr()
|
20 |
+
# print(f"Aidlite library version : {aidlite.get_library_version()}")
|
21 |
+
# print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
22 |
+
config = aidlite.Config.create_instance()
|
23 |
+
if config is None:
|
24 |
+
print("Create model failed !")
|
25 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
26 |
+
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
27 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
28 |
+
config.is_quantify_model = 1
|
29 |
+
|
30 |
+
model = aidlite.Model.create_instance(args.target_model)
|
31 |
+
if model is None:
|
32 |
+
print("Create model failed !")
|
33 |
+
|
34 |
+
self.conf = args.conf_thres
|
35 |
+
self.iou=args.iou_thres
|
36 |
+
self.width = args.width
|
37 |
+
self.height = args.height
|
38 |
+
self.class_num = args.class_num
|
39 |
+
self.input_shape = [[1,self.height,self.width,3]]
|
40 |
+
self.blocks = int(self.height * self.width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
41 |
+
self.maskw = int(self.width / 4)
|
42 |
+
self.maskh = int(self.height / 4)
|
43 |
+
self.output_shape = [[1,32,self.blocks],[1,4,self.blocks],[1,self.class_num,self.blocks],[1,self.maskh, self.maskw,32]]
|
44 |
+
|
45 |
+
model.set_model_properties(self.input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
46 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
47 |
+
if self.interpreter is None:
|
48 |
+
print("build_interpretper_from_model_and_config failed !")
|
49 |
+
result = self.interpreter.init()
|
50 |
+
if result != 0:
|
51 |
+
print(f"interpreter init failed !")
|
52 |
+
result = self.interpreter.load_model()
|
53 |
+
if result != 0:
|
54 |
+
print("interpreter load model failed !")
|
55 |
+
print("detect model load success!")
|
56 |
+
|
57 |
+
def pretreat_img(self,frame):
|
58 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
59 |
+
img = img / 255
|
60 |
+
img = img.astype(np.float32)
|
61 |
+
return img,scale
|
62 |
+
|
63 |
+
def qnn_run(self, orig_imgs,args):
|
64 |
+
input_img_f,scale=self.pretreat_img(orig_imgs) # 图片resize HWC
|
65 |
+
input_img = np.expand_dims(input_img_f, 0)
|
66 |
+
|
67 |
+
invoke_time=[]
|
68 |
+
for i in range(args.invoke_nums):
|
69 |
+
self.interpreter.set_input_tensor(0, input_img.data)
|
70 |
+
t0 = time.time()
|
71 |
+
self.interpreter.invoke()
|
72 |
+
t1 = time.time()
|
73 |
+
cost_time=(t1-t0)*1000
|
74 |
+
invoke_time.append(cost_time)
|
75 |
+
|
76 |
+
input0_data = self.interpreter.get_output_tensor(2).reshape(1,4,self.blocks)
|
77 |
+
input1_data = self.interpreter.get_output_tensor(3).reshape(1,self.class_num,self.blocks)
|
78 |
+
input2_data = self.interpreter.get_output_tensor(1).reshape(1,32,self.blocks)
|
79 |
+
protos = self.interpreter.get_output_tensor(0).reshape(1,self.maskh, self.maskw,32).transpose(0,3,1,2)
|
80 |
+
|
81 |
+
boxes = np.concatenate([input0_data, input1_data, input2_data], axis = 1)
|
82 |
+
x = boxes.transpose(0,2,1)
|
83 |
+
x = x[np.amax(x[..., 4:-32], axis=-1) > self.conf]
|
84 |
+
if len(x) < 1:
|
85 |
+
return None, None
|
86 |
+
|
87 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:-32], axis=-1), np.argmax(x[..., 4:-32], axis=-1), x[..., -32:]]
|
88 |
+
|
89 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
90 |
+
index = NMS(x[:, :4], x[:, 4], self.iou)
|
91 |
+
out_boxes = x[index]
|
92 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
93 |
+
|
94 |
+
masks = process_mask(protos[0], out_boxes[:, -32:], out_boxes[:, :4], orig_imgs.shape)
|
95 |
+
segments = masks2segments(masks)
|
96 |
+
|
97 |
+
## time 统计
|
98 |
+
max_invoke_time = max(invoke_time)
|
99 |
+
min_invoke_time = min(invoke_time)
|
100 |
+
mean_invoke_time = sum(invoke_time)/args.invoke_nums
|
101 |
+
var_invoketime=np.var(invoke_time)
|
102 |
+
print("========================================")
|
103 |
+
print(f"QNN inference {args.invoke_nums} times :\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
104 |
+
print("========================================")
|
105 |
+
|
106 |
+
return out_boxes, segments
|
107 |
+
|
108 |
+
|
109 |
+
def parser_args():
|
110 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
111 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s-seg_w8a16.qnn216.ctx.bin',help="inference model path")
|
112 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
113 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
114 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
115 |
+
parser.add_argument('--width',type=int,default=640,help="Model input size")
|
116 |
+
parser.add_argument('--height',type=int,default=640,help="Model input size")
|
117 |
+
parser.add_argument('--conf_thres',type=float,default=0.45,help="confidence threshold for filtering the annotations")
|
118 |
+
parser.add_argument('--iou_thres',type=float,default=0.45,help="Iou threshold for filtering the annotations")
|
119 |
+
parser.add_argument('--class_num',type=int,default=80,help="Iou threshold for filtering the annotations")
|
120 |
+
args = parser.parse_args()
|
121 |
+
return args
|
122 |
+
|
123 |
+
def main(args):
|
124 |
+
model = qnn_predict(args)
|
125 |
+
frame = cv2.imread(args.imgs)
|
126 |
+
qnn_out_boxes, qnn_segments = model.qnn_run(frame,args)
|
127 |
+
result = draw_detect_res(frame, qnn_out_boxes, qnn_segments)
|
128 |
+
cv2.imwrite("./python/bus_result.jpg", result)
|
129 |
+
|
130 |
+
if __name__ == "__main__":
|
131 |
+
args = parser_args()
|
132 |
+
main(args)
|
133 |
+
|
134 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int16_aidlite/python/utils.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
def draw_detect_res(img, det_pred, segments):
|
72 |
+
'''
|
73 |
+
检测结果绘制
|
74 |
+
'''
|
75 |
+
if det_pred is None:
|
76 |
+
return img
|
77 |
+
|
78 |
+
img = img.astype(np.uint8)
|
79 |
+
im_canvas = img.copy()
|
80 |
+
color_step = int(255/len(CLASSES))
|
81 |
+
for i in range(len(det_pred)):
|
82 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
83 |
+
cls_id = int(det_pred[i][5])
|
84 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
85 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
86 |
+
if len(segments[i]) > 0:
|
87 |
+
cv2.polylines(img, np.int32([segments[i]]), True, (0, int(cls_id*color_step), int(255-cls_id*color_step)), 2)
|
88 |
+
cv2.fillPoly(img, np.int32([segments[i]]), (0, int(cls_id*color_step), int(255-cls_id*color_step)))
|
89 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
90 |
+
return img
|
91 |
+
|
92 |
+
def scale_mask(masks, im0_shape):
|
93 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
94 |
+
interpolation=cv2.INTER_LINEAR)
|
95 |
+
if len(masks.shape) == 2:
|
96 |
+
masks = masks[:, :, None]
|
97 |
+
return masks
|
98 |
+
|
99 |
+
def crop_mask(masks, boxes):
|
100 |
+
n, h, w = masks.shape
|
101 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
102 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
103 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
104 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
105 |
+
|
106 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
107 |
+
c, mh, mw = protos.shape
|
108 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
109 |
+
masks = np.ascontiguousarray(masks)
|
110 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
111 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
112 |
+
masks = crop_mask(masks, bboxes)
|
113 |
+
return np.greater(masks, 0.5)
|
114 |
+
|
115 |
+
def masks2segments(masks):
|
116 |
+
segments = []
|
117 |
+
for x in masks.astype('uint8'):
|
118 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
119 |
+
if c:
|
120 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
121 |
+
else:
|
122 |
+
c = np.zeros((0, 2)) # no segments found
|
123 |
+
segments.append(c.astype('float32'))
|
124 |
+
return segments
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
## Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 11.27M
|
5 |
+
- Model size: 45.22M
|
6 |
+
- Output shape: 1x32x160x160, 1x116x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: INT8
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: SNM972 QCS8550
|
15 |
+
|
16 |
+
## Inference with AidLite SDK
|
17 |
+
|
18 |
+
### SDK installation
|
19 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
20 |
+
|
21 |
+
- Install AidLite SDK
|
22 |
+
|
23 |
+
```bash
|
24 |
+
# Install the appropriate version of the aidlite sdk
|
25 |
+
sudo aid-pkg update
|
26 |
+
sudo aid-pkg install aidlite-sdk
|
27 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
28 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
29 |
+
```
|
30 |
+
|
31 |
+
- Verify AidLite SDK
|
32 |
+
|
33 |
+
```bash
|
34 |
+
# aidlite sdk c++ check
|
35 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
36 |
+
|
37 |
+
# aidlite sdk python check
|
38 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
39 |
+
```
|
40 |
+
|
41 |
+
### Run demo
|
42 |
+
#### python
|
43 |
+
```bash
|
44 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite
|
45 |
+
python3 ./python/run_test.py --target_model ./models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
46 |
+
```
|
47 |
+
|
48 |
+
#### cpp
|
49 |
+
```bash
|
50 |
+
cd yolov8s_seg/model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp
|
51 |
+
mkdir build && cd build
|
52 |
+
cmake ..
|
53 |
+
make
|
54 |
+
./run_test
|
55 |
+
```
|
56 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/run_test.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
pthread
|
31 |
+
)
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/cpp/run_test.cpp
ADDED
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <cstring> // 用于 memcpy
|
6 |
+
#include <opencv2/opencv.hpp>
|
7 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
8 |
+
#include <vector>
|
9 |
+
#include <numeric>
|
10 |
+
|
11 |
+
const float INPUT_WIDTH = 640.0;
|
12 |
+
const float INPUT_HEIGHT = 640.0;
|
13 |
+
const float SCORE_THRESHOLD = 0.25;
|
14 |
+
const float NMS_THRESHOLD = 0.45;
|
15 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
16 |
+
const uint32_t out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace cv;
|
40 |
+
using namespace std;
|
41 |
+
using namespace Aidlux::Aidlite;
|
42 |
+
|
43 |
+
struct Args {
|
44 |
+
std::string target_model = "../../models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin";
|
45 |
+
std::string imgs = "../bus.jpg";
|
46 |
+
int invoke_nums = 10;
|
47 |
+
std::string model_type = "QNN";
|
48 |
+
};
|
49 |
+
|
50 |
+
Args parse_args(int argc, char* argv[]) {
|
51 |
+
Args args;
|
52 |
+
for (int i = 1; i < argc; ++i) {
|
53 |
+
std::string arg = argv[i];
|
54 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
55 |
+
args.target_model = argv[++i];
|
56 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
57 |
+
args.imgs = argv[++i];
|
58 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
59 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
60 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
61 |
+
args.model_type = argv[++i];
|
62 |
+
}
|
63 |
+
}
|
64 |
+
return args;
|
65 |
+
}
|
66 |
+
|
67 |
+
std::string to_lower(const std::string& str) {
|
68 |
+
std::string lower_str = str;
|
69 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
70 |
+
return std::tolower(c);
|
71 |
+
});
|
72 |
+
return lower_str;
|
73 |
+
}
|
74 |
+
|
75 |
+
// concatenate_3(80_class_data, 4_pos_data , 32_canc_data, 1, 8400, 80, 4,32, qnn_concat);
|
76 |
+
void concatenate_3(float* qnn_trans_data, float* qnn_mul_data, float* qnn_canc_data, int batch, int num_elements, int trans_dim, int mul_dim, int canc_dim,std::vector<float>& output) {
|
77 |
+
// int out_dim = trans_dim + mul_dim + canc_dim + 1; //117
|
78 |
+
int out_dim = trans_dim + mul_dim + canc_dim; //116
|
79 |
+
output.resize(batch * num_elements * out_dim);
|
80 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
81 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
82 |
+
std::memcpy(&output[i * out_dim + mul_dim], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
83 |
+
std::memcpy(&output[i * out_dim + mul_dim + trans_dim], &qnn_canc_data[i * canc_dim], canc_dim * sizeof(float));
|
84 |
+
}
|
85 |
+
}
|
86 |
+
|
87 |
+
// 4*8400
|
88 |
+
void transformData(const float* input, float* output, int C, int N) {
|
89 |
+
for (int c = 0; c < C; ++c) {
|
90 |
+
for (int n = 0; n < N; ++n) {
|
91 |
+
output[n * C + c] = input[c * N + n];
|
92 |
+
}
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
97 |
+
cv::Mat img_processed = frame.clone();
|
98 |
+
int height = img_processed.rows;
|
99 |
+
int width = img_processed.cols;
|
100 |
+
int length = std::max(height, width);
|
101 |
+
double scala = static_cast<double>(length) / size;
|
102 |
+
|
103 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
104 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
105 |
+
|
106 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
107 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
108 |
+
|
109 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
110 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
111 |
+
img_input.convertTo(img_input, CV_32FC3);
|
112 |
+
img_input = (img_input - mean_data) / std_data;
|
113 |
+
return scala;
|
114 |
+
}
|
115 |
+
|
116 |
+
|
117 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
118 |
+
static const std::vector<std::string> hex_colors = {
|
119 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
120 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
121 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
122 |
+
"FF95C8", "FF37C7"
|
123 |
+
};
|
124 |
+
|
125 |
+
int num = hex_colors.size();
|
126 |
+
std::string hex = hex_colors[i % num];
|
127 |
+
|
128 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
129 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
130 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
131 |
+
|
132 |
+
if (bgr)
|
133 |
+
return cv::Scalar(b, g, r);
|
134 |
+
else
|
135 |
+
return cv::Scalar(r, g, b);
|
136 |
+
}
|
137 |
+
|
138 |
+
float sigmoid_function(float a)
|
139 |
+
{
|
140 |
+
float b = 1. / (1. + exp(-a));
|
141 |
+
return b;
|
142 |
+
}
|
143 |
+
|
144 |
+
int transpose(float* src, unsigned int* src_dims, unsigned int* tsp_dims, float* dest){
|
145 |
+
|
146 |
+
int current_coordinate[4] = {0, 0, 0, 0};
|
147 |
+
for(int a = 0; a < src_dims[0]; ++a){
|
148 |
+
current_coordinate[0] = a;
|
149 |
+
for(int b = 0; b < src_dims[1]; ++b){
|
150 |
+
current_coordinate[1] = b;
|
151 |
+
for(int c = 0; c < src_dims[2]; ++c){
|
152 |
+
current_coordinate[2] = c;
|
153 |
+
for(int d = 0; d < src_dims[3]; ++d){
|
154 |
+
current_coordinate[3] = d;
|
155 |
+
|
156 |
+
int old_index = current_coordinate[0]*src_dims[1]*src_dims[2]*src_dims[3] +
|
157 |
+
current_coordinate[1]*src_dims[2]*src_dims[3] +
|
158 |
+
current_coordinate[2]*src_dims[3] +
|
159 |
+
current_coordinate[3];
|
160 |
+
|
161 |
+
int new_index = current_coordinate[tsp_dims[0]]*src_dims[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
162 |
+
current_coordinate[tsp_dims[1]]*src_dims[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
163 |
+
current_coordinate[tsp_dims[2]]*src_dims[tsp_dims[3]] +
|
164 |
+
current_coordinate[tsp_dims[3]];
|
165 |
+
|
166 |
+
dest[new_index] = src[old_index];
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
return EXIT_SUCCESS;
|
173 |
+
}
|
174 |
+
|
175 |
+
|
176 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
177 |
+
{
|
178 |
+
int baseLine;
|
179 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
180 |
+
int y = top - label_size.height - baseLine;
|
181 |
+
if (y < 0) {
|
182 |
+
y = top ;
|
183 |
+
}
|
184 |
+
cv::Point tlc(left, y);
|
185 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
186 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
187 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
188 |
+
}
|
189 |
+
|
190 |
+
|
191 |
+
cv::Mat post_process(cv::Mat &frame, std::vector<float> &outputs, const std::vector<std::string> &class_name,
|
192 |
+
const double ratio, float* protos_data, float* qnn_canc)
|
193 |
+
{
|
194 |
+
cv::Mat input_image = frame.clone();
|
195 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
196 |
+
std::vector<int> class_ids;
|
197 |
+
std::vector<float> confidences;
|
198 |
+
std::vector<cv::Rect> boxes;
|
199 |
+
std::vector<cv::Mat> masks;
|
200 |
+
std::vector<float> class_scores;
|
201 |
+
cv::RNG rng;
|
202 |
+
cv::Mat masked_img;
|
203 |
+
|
204 |
+
unsigned int src_dims[4] = {1, 32,160,160};
|
205 |
+
unsigned int tsp_dims[4] = {0,3,1,2};
|
206 |
+
unsigned int stride_data_num = 1*32*160*160;
|
207 |
+
float* format_data = new float[stride_data_num];
|
208 |
+
transpose(protos_data, src_dims, tsp_dims, format_data);
|
209 |
+
cv::Mat proto_buffer(32, 160*160, CV_32F, format_data);
|
210 |
+
std::cout << "proto_buffer 维度: " << proto_buffer.rows << "x" << proto_buffer.cols << std::endl;
|
211 |
+
|
212 |
+
for (int i = 0; i < outputs.size(); i+=116)
|
213 |
+
{
|
214 |
+
auto start = outputs.begin() + i + 4;
|
215 |
+
auto end = outputs.begin() + i + 84;
|
216 |
+
float max_val = *std::max_element(start, end);
|
217 |
+
float confidence = max_val;
|
218 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
219 |
+
{
|
220 |
+
auto start = outputs.begin() + i + 4;
|
221 |
+
auto end = outputs.begin() + i + 84;
|
222 |
+
std::vector<float> middle_data;
|
223 |
+
middle_data.assign(start, end);
|
224 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
225 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, middle_data.data());
|
226 |
+
cv::Point class_id;
|
227 |
+
double max_class_score;
|
228 |
+
|
229 |
+
// For multi-label, check each class score
|
230 |
+
for (int c = 0; c < class_name.size(); c++) {
|
231 |
+
float class_score = scores.at<float>(0, c);
|
232 |
+
// If class score is above threshold, consider this class for the box
|
233 |
+
if (class_score > SCORE_THRESHOLD) {
|
234 |
+
std::vector<float> last32_data;
|
235 |
+
auto st_32= outputs.begin() + i + 84;
|
236 |
+
auto ed_32 = outputs.begin() + i + 116;
|
237 |
+
last32_data.assign(st_32, ed_32);
|
238 |
+
cv::Mat mask(1, 32, CV_32FC1, last32_data.data());
|
239 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
240 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
241 |
+
class_ids.push_back(c); // class index
|
242 |
+
// Center and box dimension.
|
243 |
+
float cx = outputs[i];
|
244 |
+
float cy = outputs[i+1];
|
245 |
+
float w = outputs[i+2];
|
246 |
+
float h = outputs[i+3];
|
247 |
+
|
248 |
+
int left = int((cx - 0.5 * w) * ratio);
|
249 |
+
int top = int((cy - 0.5 * h) * ratio);
|
250 |
+
int width = int(w * ratio);
|
251 |
+
int height = int(h * ratio);
|
252 |
+
|
253 |
+
// Store good detections in the boxes vector.
|
254 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
255 |
+
masks.push_back(mask);
|
256 |
+
}
|
257 |
+
}
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
std::cout << "boxes.size(): " << boxes.size() << ",confidences.size():" << confidences.size() << std::endl;
|
262 |
+
|
263 |
+
// Perform Non Maximum Suppression and draw predictions.
|
264 |
+
std::vector<int> indices;
|
265 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
266 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
267 |
+
cv::Mat rgb_mask = cv::Mat::zeros(input_image.size(), input_image.type());
|
268 |
+
|
269 |
+
// Loop over NMS results and draw bounding boxes
|
270 |
+
for (int i = 0; i < indices.size(); i++)
|
271 |
+
{
|
272 |
+
int idx = indices[i];
|
273 |
+
cv::Rect box = boxes[idx];
|
274 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
275 |
+
|
276 |
+
int x1 = std::max(0, box.x);
|
277 |
+
int y1 = std::max(0, box.y);
|
278 |
+
int x2 = std::max(0, box.br().x);
|
279 |
+
int y2 = std::max(0, box.br().y);
|
280 |
+
cv::Mat ms = masks[idx];
|
281 |
+
// 维度验证
|
282 |
+
if (ms.cols != proto_buffer.rows) {
|
283 |
+
cerr << "维度不匹配: mask.cols=" << ms.cols
|
284 |
+
<< ", proto_buffer.rows=" << proto_buffer.rows << endl;
|
285 |
+
continue;
|
286 |
+
}
|
287 |
+
cv::Mat m = ms * proto_buffer;
|
288 |
+
for (int col = 0; col < m.cols; col++) {
|
289 |
+
m.at<float>(0, col) = sigmoid_function(m.at<float>(0, col));
|
290 |
+
}
|
291 |
+
cv::Mat m1 = m.reshape(1, 160); // 1x25600 -> 160x160
|
292 |
+
|
293 |
+
float ratio2 = 160.0/640.0;
|
294 |
+
int mx1 = std::max(0, int((x1 * ratio2)));
|
295 |
+
int mx2 = std::max(0, int((x2 * ratio2)));
|
296 |
+
int my1 = std::max(0, int((y1 * ratio2)));
|
297 |
+
int my2 = std::max(0, int((y2 * ratio2)));
|
298 |
+
cv::Mat mask_roi = m1(cv::Range(my1, my2), cv::Range(mx1, mx2));
|
299 |
+
cv::Mat rm, det_mask;
|
300 |
+
cv::resize(mask_roi, rm, cv::Size(x2 - x1, y2 - y1));
|
301 |
+
for (int r = 0; r < rm.rows; r++) {
|
302 |
+
for (int c = 0; c < rm.cols; c++) {
|
303 |
+
float pv = rm.at<float>(r, c);
|
304 |
+
if (pv > 0.5) {
|
305 |
+
rm.at<float>(r, c) = 1.0;
|
306 |
+
}
|
307 |
+
else {
|
308 |
+
rm.at<float>(r, c) = 0.0;
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
rm = rm * rng.uniform(0, 255);
|
313 |
+
rm.convertTo(det_mask, CV_8UC1);
|
314 |
+
if ((y1 + det_mask.rows) >= input_image.rows) {
|
315 |
+
y2 = input_image.rows - 1;
|
316 |
+
}
|
317 |
+
if ((x1 + det_mask.cols) >= input_image.cols) {
|
318 |
+
x2 = input_image.cols - 1;
|
319 |
+
}
|
320 |
+
|
321 |
+
cv::Mat mask = cv::Mat::zeros(cv::Size(input_image.cols, input_image.rows), CV_8UC1);
|
322 |
+
det_mask(cv::Range(0, y2 - y1), cv::Range(0, x2 - x1)).copyTo(mask(cv::Range(y1, y2), cv::Range(x1, x2)));
|
323 |
+
add(rgb_mask, cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), rgb_mask, mask);
|
324 |
+
if (input_image.size() != rgb_mask.size()) {
|
325 |
+
cv::resize(rgb_mask, rgb_mask, input_image.size());
|
326 |
+
}
|
327 |
+
|
328 |
+
cv::rectangle(input_image, boxes[idx], color, 2, 8);
|
329 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
330 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
331 |
+
cv::putText(input_image, label, cv::Point(boxes[idx].tl().x, boxes[idx].tl().y - 10), cv::FONT_HERSHEY_SIMPLEX, .5, color);
|
332 |
+
cv::addWeighted(input_image, 0.5, rgb_mask, 0.5, 0, masked_img);
|
333 |
+
|
334 |
+
}
|
335 |
+
printf("Processing finished.\n");
|
336 |
+
return masked_img;
|
337 |
+
}
|
338 |
+
|
339 |
+
|
340 |
+
|
341 |
+
int invoke(const Args& args) {
|
342 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
343 |
+
<< "Image Path: " << args.imgs << "\n"
|
344 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
345 |
+
<< "Model Type: " << args.model_type << "\n";
|
346 |
+
Model* model = Model::create_instance(args.target_model);
|
347 |
+
if(model == nullptr){
|
348 |
+
printf("Create model failed !\n");
|
349 |
+
return EXIT_FAILURE;
|
350 |
+
}
|
351 |
+
Config* config = Config::create_instance();
|
352 |
+
if(config == nullptr){
|
353 |
+
printf("Create config failed !\n");
|
354 |
+
return EXIT_FAILURE;
|
355 |
+
}
|
356 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
357 |
+
std::string model_type_lower = to_lower(args.model_type);
|
358 |
+
if (model_type_lower == "qnn"){
|
359 |
+
config->framework_type = FrameworkType::TYPE_QNN;
|
360 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
361 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
362 |
+
}
|
363 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
364 |
+
config->is_quantify_model = 1;
|
365 |
+
|
366 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, 640, 640, 3}};
|
367 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1,32,8400},{1,4,8400},{1,80,8400},{1,160, 160,32}};
|
368 |
+
model->set_model_properties(input_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32, output_shapes, Aidlux::Aidlite::DataType::TYPE_FLOAT32);
|
369 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
370 |
+
if(fast_interpreter == nullptr){
|
371 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
372 |
+
return EXIT_FAILURE;
|
373 |
+
}
|
374 |
+
int result = fast_interpreter->init();
|
375 |
+
if(result != EXIT_SUCCESS){
|
376 |
+
printf("interpreter->init() failed !\n");
|
377 |
+
return EXIT_FAILURE;
|
378 |
+
}
|
379 |
+
// load model
|
380 |
+
fast_interpreter->load_model();
|
381 |
+
if(result != EXIT_SUCCESS){
|
382 |
+
printf("interpreter->load_model() failed !\n");
|
383 |
+
return EXIT_FAILURE;
|
384 |
+
}
|
385 |
+
printf("detect model load success!\n");
|
386 |
+
|
387 |
+
cv::Mat frame = cv::imread(args.imgs);
|
388 |
+
if (frame.empty()) {
|
389 |
+
printf("detect image load failed!\n");
|
390 |
+
return 1;
|
391 |
+
}
|
392 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
393 |
+
cv::Mat input_img;
|
394 |
+
double scale = img_process(frame, input_img, 640);
|
395 |
+
if (input_img.empty()) {
|
396 |
+
printf("detect input_img load failed!\n");
|
397 |
+
return 1;
|
398 |
+
}
|
399 |
+
|
400 |
+
float *qnn_seg_data = nullptr;
|
401 |
+
float *qnn_trans_data = nullptr;
|
402 |
+
float *qnn_mul_data = nullptr;
|
403 |
+
float *qnn_canc_data = nullptr;
|
404 |
+
|
405 |
+
std::vector<float> invoke_time;
|
406 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
407 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
408 |
+
if(result != EXIT_SUCCESS){
|
409 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
410 |
+
return EXIT_FAILURE;
|
411 |
+
}
|
412 |
+
// 开始计时
|
413 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
414 |
+
result = fast_interpreter->invoke();
|
415 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
416 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
417 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
418 |
+
if(result != EXIT_SUCCESS){
|
419 |
+
printf("interpreter->invoke() failed !\n");
|
420 |
+
return EXIT_FAILURE;
|
421 |
+
}
|
422 |
+
uint32_t out_data_1 = 0;
|
423 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_canc_data, &out_data_1);
|
424 |
+
if(result != EXIT_SUCCESS){
|
425 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
426 |
+
return EXIT_FAILURE;
|
427 |
+
}
|
428 |
+
|
429 |
+
uint32_t out_data_4 = 0;
|
430 |
+
result = fast_interpreter->get_output_tensor(2, (void**)&qnn_trans_data, &out_data_4);
|
431 |
+
if(result != EXIT_SUCCESS){
|
432 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
433 |
+
return EXIT_FAILURE;
|
434 |
+
}
|
435 |
+
|
436 |
+
uint32_t out_data_2 = 0;
|
437 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_seg_data, &out_data_2);
|
438 |
+
if(result != EXIT_SUCCESS){
|
439 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
440 |
+
return EXIT_FAILURE;
|
441 |
+
}
|
442 |
+
|
443 |
+
uint32_t out_data_80 = 0;
|
444 |
+
result = fast_interpreter->get_output_tensor(3, (void**)&qnn_mul_data, &out_data_80);
|
445 |
+
if(result != EXIT_SUCCESS){
|
446 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
447 |
+
return EXIT_FAILURE;
|
448 |
+
}
|
449 |
+
}
|
450 |
+
|
451 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
452 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
453 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
454 |
+
float var_invoketime = 0.0f;
|
455 |
+
for (auto time : invoke_time) {
|
456 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
457 |
+
}
|
458 |
+
var_invoketime /= args.invoke_nums;
|
459 |
+
printf("=======================================\n");
|
460 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
461 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
462 |
+
printf("=======================================\n");
|
463 |
+
|
464 |
+
float* pos_data = new float[4 * out_size];
|
465 |
+
float* class_data = new float[80 * out_size];
|
466 |
+
float* canc_data = new float[32 * out_size];
|
467 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
468 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
469 |
+
transformData(qnn_canc_data, canc_data, 32, out_size);
|
470 |
+
|
471 |
+
// post process
|
472 |
+
std::vector<float> qnn_concat;
|
473 |
+
concatenate_3(class_data, pos_data, canc_data , 1, out_size, 80, 4, 32, qnn_concat);
|
474 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale, qnn_seg_data, qnn_canc_data);
|
475 |
+
cv::imwrite("./results.png", img);
|
476 |
+
fast_interpreter->destory();
|
477 |
+
return 0;
|
478 |
+
}
|
479 |
+
|
480 |
+
|
481 |
+
int main(int argc, char* argv[]) {
|
482 |
+
Args args = parse_args(argc, argv);
|
483 |
+
return invoke(args);
|
484 |
+
}
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c79839a3aaf6e1447ef583d55854f5255a5bdfb477526b7de3b8ff4357e0b63d
|
3 |
+
size 12384696
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS, process_mask, masks2segments, draw_detect_res
|
5 |
+
import os
|
6 |
+
import time
|
7 |
+
import argparse
|
8 |
+
import onnxruntime
|
9 |
+
|
10 |
+
# 定义相似度函数
|
11 |
+
def get_acc(onnx_out,other_out):
|
12 |
+
cosine_similarity=np.dot(np.array(onnx_out),np.array(other_out))/(np.linalg.norm(np.array(onnx_out)) * np.linalg.norm(np.array(other_out)))
|
13 |
+
return cosine_similarity
|
14 |
+
|
15 |
+
|
16 |
+
class qnn_predict(object):
|
17 |
+
def __init__(self,args) -> None:
|
18 |
+
# aidlite.set_log_level(aidlite.LogLevel.INFO)
|
19 |
+
# aidlite.log_to_stderr()
|
20 |
+
# print(f"Aidlite library version : {aidlite.get_library_version()}")
|
21 |
+
# print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
22 |
+
config = aidlite.Config.create_instance()
|
23 |
+
if config is None:
|
24 |
+
print("Create model failed !")
|
25 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
26 |
+
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
27 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
28 |
+
config.is_quantify_model = 1
|
29 |
+
|
30 |
+
model = aidlite.Model.create_instance(args.target_model)
|
31 |
+
if model is None:
|
32 |
+
print("Create model failed !")
|
33 |
+
|
34 |
+
self.conf = args.conf_thres
|
35 |
+
self.iou=args.iou_thres
|
36 |
+
self.width = args.width
|
37 |
+
self.height = args.height
|
38 |
+
self.class_num = args.class_num
|
39 |
+
self.input_shape = [[1,self.height,self.width,3]]
|
40 |
+
self.blocks = int(self.height * self.width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
41 |
+
self.maskw = int(self.width / 4)
|
42 |
+
self.maskh = int(self.height / 4)
|
43 |
+
self.output_shape = [[1,32,self.blocks],[1,4,self.blocks],[1,self.class_num,self.blocks],[1,self.maskh, self.maskw,32]]
|
44 |
+
|
45 |
+
model.set_model_properties(self.input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
46 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
47 |
+
if self.interpreter is None:
|
48 |
+
print("build_interpretper_from_model_and_config failed !")
|
49 |
+
result = self.interpreter.init()
|
50 |
+
if result != 0:
|
51 |
+
print(f"interpreter init failed !")
|
52 |
+
result = self.interpreter.load_model()
|
53 |
+
if result != 0:
|
54 |
+
print("interpreter load model failed !")
|
55 |
+
print("detect model load success!")
|
56 |
+
|
57 |
+
def pretreat_img(self,frame):
|
58 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
59 |
+
img = img / 255
|
60 |
+
img = img.astype(np.float32)
|
61 |
+
return img,scale
|
62 |
+
|
63 |
+
def qnn_run(self, orig_imgs,args):
|
64 |
+
input_img_f,scale=self.pretreat_img(orig_imgs) # 图片resize HWC
|
65 |
+
input_img = np.expand_dims(input_img_f, 0)
|
66 |
+
|
67 |
+
invoke_time=[]
|
68 |
+
for i in range(args.invoke_nums):
|
69 |
+
self.interpreter.set_input_tensor(0, input_img.data)
|
70 |
+
t0 = time.time()
|
71 |
+
self.interpreter.invoke()
|
72 |
+
t1 = time.time()
|
73 |
+
cost_time=(t1-t0)*1000
|
74 |
+
invoke_time.append(cost_time)
|
75 |
+
|
76 |
+
input0_data = self.interpreter.get_output_tensor(2).reshape(1,4,self.blocks)
|
77 |
+
input1_data = self.interpreter.get_output_tensor(3).reshape(1,self.class_num,self.blocks)
|
78 |
+
input2_data = self.interpreter.get_output_tensor(1).reshape(1,32,self.blocks)
|
79 |
+
protos = self.interpreter.get_output_tensor(0).reshape(1,self.maskh, self.maskw,32).transpose(0,3,1,2)
|
80 |
+
|
81 |
+
boxes = np.concatenate([input0_data, input1_data, input2_data], axis = 1)
|
82 |
+
x = boxes.transpose(0,2,1)
|
83 |
+
x = x[np.amax(x[..., 4:-32], axis=-1) > self.conf]
|
84 |
+
if len(x) < 1:
|
85 |
+
return None, None
|
86 |
+
|
87 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:-32], axis=-1), np.argmax(x[..., 4:-32], axis=-1), x[..., -32:]]
|
88 |
+
|
89 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
90 |
+
index = NMS(x[:, :4], x[:, 4], self.iou)
|
91 |
+
out_boxes = x[index]
|
92 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
93 |
+
|
94 |
+
masks = process_mask(protos[0], out_boxes[:, -32:], out_boxes[:, :4], orig_imgs.shape)
|
95 |
+
segments = masks2segments(masks)
|
96 |
+
|
97 |
+
## time 统计
|
98 |
+
max_invoke_time = max(invoke_time)
|
99 |
+
min_invoke_time = min(invoke_time)
|
100 |
+
mean_invoke_time = sum(invoke_time)/args.invoke_nums
|
101 |
+
var_invoketime=np.var(invoke_time)
|
102 |
+
print("========================================")
|
103 |
+
print(f"QNN inference {args.invoke_nums} times :\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
104 |
+
print("========================================")
|
105 |
+
|
106 |
+
return out_boxes, segments
|
107 |
+
|
108 |
+
|
109 |
+
def parser_args():
|
110 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
111 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s-seg_w8a8.qnn216.ctx.bin',help="inference model path")
|
112 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
113 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
114 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
115 |
+
parser.add_argument('--width',type=int,default=640,help="Model input size")
|
116 |
+
parser.add_argument('--height',type=int,default=640,help="Model input size")
|
117 |
+
parser.add_argument('--conf_thres',type=float,default=0.45,help="confidence threshold for filtering the annotations")
|
118 |
+
parser.add_argument('--iou_thres',type=float,default=0.45,help="Iou threshold for filtering the annotations")
|
119 |
+
parser.add_argument('--class_num',type=int,default=80,help="Iou threshold for filtering the annotations")
|
120 |
+
args = parser.parse_args()
|
121 |
+
return args
|
122 |
+
|
123 |
+
def main(args):
|
124 |
+
model = qnn_predict(args)
|
125 |
+
frame = cv2.imread(args.imgs)
|
126 |
+
qnn_out_boxes, qnn_segments = model.qnn_run(frame,args)
|
127 |
+
result = draw_detect_res(frame, qnn_out_boxes, qnn_segments)
|
128 |
+
cv2.imwrite("./python/bus_result.jpg", result)
|
129 |
+
|
130 |
+
if __name__ == "__main__":
|
131 |
+
args = parser_args()
|
132 |
+
main(args)
|
133 |
+
|
134 |
+
|
model_farm_yolov8s_seg_qsc8550_qnn2.16_int8_aidlite/python/utils.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
def draw_detect_res(img, det_pred, segments):
|
72 |
+
'''
|
73 |
+
检测结果绘制
|
74 |
+
'''
|
75 |
+
if det_pred is None:
|
76 |
+
return img
|
77 |
+
|
78 |
+
img = img.astype(np.uint8)
|
79 |
+
im_canvas = img.copy()
|
80 |
+
color_step = int(255/len(CLASSES))
|
81 |
+
for i in range(len(det_pred)):
|
82 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
83 |
+
cls_id = int(det_pred[i][5])
|
84 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
85 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
86 |
+
if len(segments[i]) > 0:
|
87 |
+
cv2.polylines(img, np.int32([segments[i]]), True, (0, int(cls_id*color_step), int(255-cls_id*color_step)), 2)
|
88 |
+
cv2.fillPoly(img, np.int32([segments[i]]), (0, int(cls_id*color_step), int(255-cls_id*color_step)))
|
89 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
90 |
+
return img
|
91 |
+
|
92 |
+
def scale_mask(masks, im0_shape):
|
93 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
94 |
+
interpolation=cv2.INTER_LINEAR)
|
95 |
+
if len(masks.shape) == 2:
|
96 |
+
masks = masks[:, :, None]
|
97 |
+
return masks
|
98 |
+
|
99 |
+
def crop_mask(masks, boxes):
|
100 |
+
n, h, w = masks.shape
|
101 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
102 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
103 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
104 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
105 |
+
|
106 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
107 |
+
c, mh, mw = protos.shape
|
108 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
109 |
+
masks = np.ascontiguousarray(masks)
|
110 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
111 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
112 |
+
masks = crop_mask(masks, bboxes)
|
113 |
+
return np.greater(masks, 0.5)
|
114 |
+
|
115 |
+
def masks2segments(masks):
|
116 |
+
segments = []
|
117 |
+
for x in masks.astype('uint8'):
|
118 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
119 |
+
if c:
|
120 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
121 |
+
else:
|
122 |
+
c = np.zeros((0, 2)) # no segments found
|
123 |
+
segments.append(c.astype('float32'))
|
124 |
+
return segments
|