xref: /OK3568_Linux_fs/external/rknpu2/examples/rknn_mobilenet_demo/src/main.cc (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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