1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
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 #ifndef TENSORFLOW_LITE_EXAMPLES_LABEL_CLASSIFY_BITMAP_HELPERS_H
17 #define TENSORFLOW_LITE_EXAMPLES_LABEL_CLASSIFY_BITMAP_HELPERS_H
18 
19 #include "tflite/label_classify/label_classify.h"
20 #include "tensorflow/lite/builtin_op_data.h"
21 #include "tensorflow/lite/interpreter.h"
22 #include "tensorflow/lite/kernels/register.h"
23 #include "tensorflow/lite/string_util.h"
24 #include "log.h"
25 
26 
27 namespace tflite {
28 namespace label_classify {
29 const int INPUT_NUMBER = 2;
30 const int OUPUT_NUMBER = 1;
31 const int INT8_OFFSET_NUMBER = 128;
32 const int BIT_TO_BYTE = 8;
33 const int BLUE_OFFSET = 2;
34 const int GREEN_OFFSET = 1;
35 const int ALPHA_OFFSET = 3;
36 const int HEADER_ADDRESS_OFFSET = 10;
37 const int WIDTH_ADDRESS_OFFSET = 18;
38 const int HEIGHT_ADDRESS_OFFSET = 22;
39 const int BBP_ADDRESS_OFFSET = 28;
40 enum ChannelDim : int {
41     GRAYSCALE_DIM = 1,
42     BGR_DIM = 3,
43     BGRA_DIM = 4
44 };
45 
46 struct BmpAddressOffset {
47     int headerAddressOffset = 0;
48     int widthAddressOffset = 0;
49     int heightAddressOffset = 0;
50     int bbpAddressOffset = 0;
51 };
52 
53 struct ColorChannelOffset {
54     int blueOffset = 0;
55     int greenOffset = 0;
56     int alphaOffset = 0;
57 };
58 
59 struct ImageInfo {
60     int32_t width = 0;
61     int32_t height = 0;
62     int32_t channels = 0;
63 };
64 
65 void ReadBmp(const std::string& input_bmp_name, ImageInfo& imageInfo, Settings* s, std::vector<uint8_t>& input);
66 
67 template <typename T>
Resize(T * out,uint8_t * in,ImageInfo inputImageInfo,ImageInfo wantedImageInfo,Settings * s)68 void Resize(T* out, uint8_t* in, ImageInfo inputImageInfo, ImageInfo wantedImageInfo, Settings* s)
69 {
70     std::unique_ptr<Interpreter> interpreter = std::make_unique<Interpreter>();
71 
72     int32_t baseIndex = 0;
73     int32_t outputIndex = 2;
74 
75     // two inputs: input and new_sizes
76     interpreter->AddTensors(INPUT_NUMBER, &baseIndex);
77     // one output
78     interpreter->AddTensors(OUPUT_NUMBER, &baseIndex);
79     // set input and output tensors
80     interpreter->SetInputs({ 0, 1 });
81     interpreter->SetOutputs({ 2 });
82 
83     // set parameters of tensors
84     TfLiteQuantizationParams quant;
85     interpreter->SetTensorParametersReadWrite(0, kTfLiteFloat32, "input",
86         { 1, inputImageInfo.height, inputImageInfo.width, inputImageInfo.channels }, quant);
87     interpreter->SetTensorParametersReadWrite(1, kTfLiteInt32, "new_size", { 2 }, quant);
88     interpreter->SetTensorParametersReadWrite(outputIndex, kTfLiteFloat32, "output",
89         { 1, wantedImageInfo.height, wantedImageInfo.width, wantedImageInfo.channels }, quant);
90 
91     ops::builtin::BuiltinOpResolver resolver;
92     const TfLiteRegistration* resizeOp = resolver.FindOp(BuiltinOperator_RESIZE_BILINEAR, 1);
93     auto* params = reinterpret_cast<TfLiteResizeBilinearParams*>(malloc(sizeof(TfLiteResizeBilinearParams)));
94     if (params == nullptr) {
95         LOG(ERROR) << "Malloc memory failed in BitmapHelperslmpl.";
96         return;
97     }
98     params->align_corners = false;
99     params->half_pixel_centers = false;
100     interpreter->AddNodeWithParameters({ 0, 1 }, { 2 }, nullptr, 0, params, resizeOp, nullptr);
101     interpreter->AllocateTensors();
102 
103     // fill input image
104     // in[] are integers, cannot do memcpy() directly
105     auto input = interpreter->typed_tensor<float>(0);
106 
107     for (int32_t i = 0; i < inputImageInfo.height * inputImageInfo.width * inputImageInfo.channels; ++i) {
108         input[i] = in[i];
109     }
110 
111     // fill new_sizes
112     interpreter->typed_tensor<int32_t>(1)[0] = wantedImageInfo.height;
113     interpreter->typed_tensor<int32_t>(1)[1] = wantedImageInfo.width;
114     interpreter->Invoke();
115     auto output = interpreter->typed_tensor<float>(2);
116     for (int32_t i = 0; i < wantedImageInfo.height * wantedImageInfo.width * wantedImageInfo.channels; ++i) {
117         switch (s->inputType) {
118             case kTfLiteFloat32:
119                 out[i] = (output[i] - s->inputMean) / s->inputStd;
120                 break;
121             case kTfLiteInt8:
122                 out[i] = static_cast<int8_t>(output[i] - INT8_OFFSET_NUMBER);
123                 break;
124             case kTfLiteUInt8:
125                 out[i] = static_cast<uint8_t>(output[i]);
126                 break;
127             default:
128                 break;
129         }
130     }
131 }
132 
133 // explicit instantiation
134 template void Resize<float>(float*, uint8_t*, ImageInfo, ImageInfo, Settings*);
135 template void Resize<int8_t>(int8_t*, uint8_t*, ImageInfo, ImageInfo, Settings*);
136 template void Resize<uint8_t>(uint8_t*, uint8_t*, ImageInfo, ImageInfo, Settings*);
137 template void Resize<int64_t>(int64_t*, uint8_t*, ImageInfo, ImageInfo, Settings*);
138 }  // namespace label_classify
139 }  // namespace tflite
140 
141 #endif  // TENSORFLOW_LITE_EXAMPLES_LABEL_CLASSIFY_BITMAP_HELPERS_H
142