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