1 // Copyright (c) 2021 by Rockchip Electronics Co., Ltd. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 /*-------------------------------------------
16 Includes
17 -------------------------------------------*/
18 #include "opencv2/core/core.hpp"
19 #include "opencv2/imgcodecs.hpp"
20 #include "opencv2/imgproc.hpp"
21 #include "rknn_api.h"
22
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/time.h>
27
28 #include <fstream>
29 #include <iostream>
30
31 using namespace std;
32 using namespace cv;
33
34 /*-------------------------------------------
35 Functions
36 -------------------------------------------*/
37
dump_tensor_attr(rknn_tensor_attr * attr)38 static void dump_tensor_attr(rknn_tensor_attr* attr)
39 {
40 printf(" index=%d, name=%s, n_dims=%d, dims=[%d, %d, %d, %d], n_elems=%d, size=%d, fmt=%s, type=%s, qnt_type=%s, "
41 "zp=%d, scale=%f\n",
42 attr->index, attr->name, attr->n_dims, attr->dims[0], attr->dims[1], attr->dims[2], attr->dims[3],
43 attr->n_elems, attr->size, get_format_string(attr->fmt), get_type_string(attr->type),
44 get_qnt_type_string(attr->qnt_type), attr->zp, attr->scale);
45 }
46
load_model(const char * filename,int * model_size)47 static unsigned char* load_model(const char* filename, int* model_size)
48 {
49 FILE* fp = fopen(filename, "rb");
50 if (fp == nullptr) {
51 printf("fopen %s fail!\n", filename);
52 return NULL;
53 }
54 fseek(fp, 0, SEEK_END);
55 int model_len = ftell(fp);
56 unsigned char* model = (unsigned char*)malloc(model_len);
57 fseek(fp, 0, SEEK_SET);
58 if (model_len != fread(model, 1, model_len, fp)) {
59 printf("fread %s fail!\n", filename);
60 free(model);
61 return NULL;
62 }
63 *model_size = model_len;
64 if (fp) {
65 fclose(fp);
66 }
67 return model;
68 }
69
rknn_GetTop(float * pfProb,float * pfMaxProb,uint32_t * pMaxClass,uint32_t outputCount,uint32_t topNum)70 static int rknn_GetTop(float* pfProb, float* pfMaxProb, uint32_t* pMaxClass, uint32_t outputCount, uint32_t topNum)
71 {
72 uint32_t i, j;
73
74 #define MAX_TOP_NUM 20
75 if (topNum > MAX_TOP_NUM)
76 return 0;
77
78 memset(pfMaxProb, 0, sizeof(float) * topNum);
79 memset(pMaxClass, 0xff, sizeof(float) * topNum);
80
81 for (j = 0; j < topNum; j++) {
82 for (i = 0; i < outputCount; i++) {
83 if ((i == *(pMaxClass + 0)) || (i == *(pMaxClass + 1)) || (i == *(pMaxClass + 2)) || (i == *(pMaxClass + 3)) ||
84 (i == *(pMaxClass + 4))) {
85 continue;
86 }
87
88 if (pfProb[i] > *(pfMaxProb + j)) {
89 *(pfMaxProb + j) = pfProb[i];
90 *(pMaxClass + j) = i;
91 }
92 }
93 }
94
95 return 1;
96 }
97
98 /*-------------------------------------------
99 Main Function
100 -------------------------------------------*/
main(int argc,char ** argv)101 int main(int argc, char** argv)
102 {
103 const int MODEL_IN_WIDTH = 224;
104 const int MODEL_IN_HEIGHT = 224;
105 const int MODEL_IN_CHANNELS = 3;
106
107 rknn_context ctx = 0;
108 int ret;
109 int model_len = 0;
110 unsigned char* model;
111
112 const char* model_path = argv[1];
113 const char* img_path = argv[2];
114
115 if (argc != 3) {
116 printf("Usage: %s <rknn model> <image_path> \n", argv[0]);
117 return -1;
118 }
119
120 // Load image
121 cv::Mat orig_img = imread(img_path, cv::IMREAD_COLOR);
122 if (!orig_img.data) {
123 printf("cv::imread %s fail!\n", img_path);
124 return -1;
125 }
126
127 cv::Mat orig_img_rgb;
128 cv::cvtColor(orig_img, orig_img_rgb, cv::COLOR_BGR2RGB);
129
130 cv::Mat img = orig_img_rgb.clone();
131 if (orig_img.cols != MODEL_IN_WIDTH || orig_img.rows != MODEL_IN_HEIGHT) {
132 printf("resize %d %d to %d %d\n", orig_img.cols, orig_img.rows, MODEL_IN_WIDTH, MODEL_IN_HEIGHT);
133 cv::resize(orig_img, img, cv::Size(MODEL_IN_WIDTH, MODEL_IN_HEIGHT), 0, 0, cv::INTER_LINEAR);
134 }
135
136 // Load RKNN Model
137 model = load_model(model_path, &model_len);
138 ret = rknn_init(&ctx, model, model_len, 0, NULL);
139 if (ret < 0) {
140 printf("rknn_init fail! ret=%d\n", ret);
141 return -1;
142 }
143
144 // Get Model Input Output Info
145 rknn_input_output_num io_num;
146 ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
147 if (ret != RKNN_SUCC) {
148 printf("rknn_query fail! ret=%d\n", ret);
149 return -1;
150 }
151 printf("model input num: %d, output num: %d\n", io_num.n_input, io_num.n_output);
152
153 printf("input tensors:\n");
154 rknn_tensor_attr input_attrs[io_num.n_input];
155 memset(input_attrs, 0, sizeof(input_attrs));
156 for (int i = 0; i < io_num.n_input; i++) {
157 input_attrs[i].index = i;
158 ret = rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &(input_attrs[i]), sizeof(rknn_tensor_attr));
159 if (ret != RKNN_SUCC) {
160 printf("rknn_query fail! ret=%d\n", ret);
161 return -1;
162 }
163 dump_tensor_attr(&(input_attrs[i]));
164 }
165
166 printf("output tensors:\n");
167 rknn_tensor_attr output_attrs[io_num.n_output];
168 memset(output_attrs, 0, sizeof(output_attrs));
169 for (int i = 0; i < io_num.n_output; i++) {
170 output_attrs[i].index = i;
171 ret = rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &(output_attrs[i]), sizeof(rknn_tensor_attr));
172 if (ret != RKNN_SUCC) {
173 printf("rknn_query fail! ret=%d\n", ret);
174 return -1;
175 }
176 dump_tensor_attr(&(output_attrs[i]));
177 }
178
179 // Set Input Data
180 rknn_input inputs[1];
181 memset(inputs, 0, sizeof(inputs));
182 inputs[0].index = 0;
183 inputs[0].type = RKNN_TENSOR_UINT8;
184 inputs[0].size = img.cols * img.rows * img.channels() * sizeof(uint8_t);
185 inputs[0].fmt = RKNN_TENSOR_NHWC;
186 inputs[0].buf = img.data;
187
188 ret = rknn_inputs_set(ctx, io_num.n_input, inputs);
189 if (ret < 0) {
190 printf("rknn_input_set fail! ret=%d\n", ret);
191 return -1;
192 }
193
194 // Run
195 printf("rknn_run\n");
196 ret = rknn_run(ctx, nullptr);
197 if (ret < 0) {
198 printf("rknn_run fail! ret=%d\n", ret);
199 return -1;
200 }
201
202 // Get Output
203 rknn_output outputs[1];
204 memset(outputs, 0, sizeof(outputs));
205 outputs[0].want_float = 1;
206 ret = rknn_outputs_get(ctx, 1, outputs, NULL);
207 if (ret < 0) {
208 printf("rknn_outputs_get fail! ret=%d\n", ret);
209 return -1;
210 }
211
212 // Post Process
213 for (int i = 0; i < io_num.n_output; i++) {
214 uint32_t MaxClass[5];
215 float fMaxProb[5];
216 float* buffer = (float*)outputs[i].buf;
217 uint32_t sz = outputs[i].size / 4;
218
219 rknn_GetTop(buffer, fMaxProb, MaxClass, sz, 5);
220
221 printf(" --- Top5 ---\n");
222 for (int i = 0; i < 5; i++) {
223 printf("%3d: %8.6f\n", MaxClass[i], fMaxProb[i]);
224 }
225 }
226
227 // Release rknn_outputs
228 rknn_outputs_release(ctx, 1, outputs);
229
230 // Release
231 if (ctx > 0)
232 {
233 rknn_destroy(ctx);
234 }
235 if (model) {
236 free(model);
237 }
238 return 0;
239 }
240