• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2023 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "minddata/dataset/kernels/image/lite_cv/image_process.h"
18 
19 #include <cfloat>
20 #include <climits>
21 #include <cmath>
22 #include <cstring>
23 #include <limits>
24 #include <random>
25 #include <utility>
26 #include <vector>
27 
28 #ifdef ENABLE_NEON
29 #include <arm_neon.h>
30 #endif
31 
32 namespace mindspore {
33 namespace dataset {
34 constexpr uint32_t kR2Gray = 9798;
35 constexpr uint32_t kG2Gray = 19235;
36 constexpr uint32_t kB2Gray = 3735;
37 constexpr int32_t kGrayShift = 15;
38 constexpr int32_t kGrayShiftDelta = 1 << (kGrayShift - 1);
39 constexpr int32_t kYScale = 0x0101;
40 constexpr int32_t kU2B = -128;
41 constexpr int32_t kU2G = 25;
42 constexpr int32_t kV2R = -102;
43 constexpr int32_t kV2G = 52;
44 constexpr int32_t kY2G = 18997;
45 constexpr int32_t kY2GB = -1160;
46 constexpr int32_t kB2B = kU2B * 128 + kY2GB;
47 constexpr int32_t kB2G = kU2G * 128 + kV2G * 128 + kY2GB;
48 constexpr int32_t kB2R = kV2R * 128 + kY2GB;
49 constexpr int32_t kChannelThree = 3;
50 
Equal(const float & a,const float & b)51 static bool Equal(const float &a, const float &b) { return std::fabs(a - b) < 1e-6; }
52 
InitBilinearWeight(int * data_ptr,int16_t * weight_ptr,double scale,int dst_length,int src_length,int a)53 static inline bool InitBilinearWeight(int *data_ptr, int16_t *weight_ptr, double scale, int dst_length, int src_length,
54                                       int a) {
55   const int RESIZE_SCALE = 1 << 11;
56   if (data_ptr == nullptr || weight_ptr == nullptr) {
57     return false;
58   }
59 
60   int *data_start_ptr = data_ptr;
61   int16_t *weight_start_ptr = weight_ptr;
62 
63   for (unsigned int i = 0; i < dst_length; i++) {
64     auto src_f_x = static_cast<float>((i + 0.5) * scale - 0.5);
65     int src_u_x = static_cast<int>(floor(src_f_x));
66     src_f_x -= src_u_x;
67     if (src_u_x < 0) {
68       src_u_x = 0;
69       src_f_x = 0.0f;
70     }
71     if (src_u_x >= src_length - 1) {
72       src_u_x = src_length - 2;
73       src_f_x = 1.0f;
74     }
75     data_start_ptr[i] = src_u_x * a;
76     int16_t t0 = INT16_CAST((1.0f - src_f_x) * RESIZE_SCALE);
77     int16_t t1 = INT16_CAST(src_f_x * RESIZE_SCALE);
78 
79     weight_start_ptr[i * 2] = t0;
80     weight_start_ptr[i * 2 + 1] = t1;
81   }
82   return true;
83 }
84 
ResizeBilinear3C(const unsigned char * src,int src_width,int src_height,unsigned char * dst,int dst_width,int dst_height)85 static bool ResizeBilinear3C(const unsigned char *src, int src_width, int src_height, unsigned char *dst, int dst_width,
86                              int dst_height) {
87   double scale_width = static_cast<double>(src_width) / dst_width;
88   double scale_height = static_cast<double>(src_height) / dst_height;
89 
90   if (dst_height >= (INT_MAX / 2 - dst_width)) {
91     return false;
92   }
93   if (dst_height >= (INT_MAX / 3 / dst_width)) {
94     return false;
95   }
96 
97   // The allocate memory cannot exceed 2GB.
98   if ((2 * sizeof(int) * (2 * dst_width + dst_height)) > INT_MAX) {
99     return false;
100   }
101   int *data_buf = new (std::nothrow) int[2 * sizeof(int) * (2 * dst_width + dst_height)];
102   if (data_buf == nullptr) {
103     return false;
104   }
105 
106   int *x_offset = data_buf;
107   int *y_offset = data_buf + dst_width + dst_width;
108 
109   auto *x_weight = reinterpret_cast<int16_t *>(data_buf + dst_width);
110   auto *y_weight = reinterpret_cast<int16_t *>(data_buf + dst_width + dst_width + dst_height);
111 
112   if (!InitBilinearWeight(x_offset, x_weight, scale_width, dst_width, src_width, 3)) {
113     delete[] data_buf;
114     return false;
115   }
116   if (!InitBilinearWeight(y_offset, y_weight, scale_height, dst_height, src_height, 1)) {
117     delete[] data_buf;
118     return false;
119   }
120 
121   LiteMat x_tmp_buf0(dst_width * 3 + 1, LDataType::UINT16);
122   LiteMat x_tmp_buf1(dst_width * 3 + 1, LDataType::UINT16);
123   int16_t *row0_ptr = reinterpret_cast<int16_t *>(x_tmp_buf0.data_ptr_);
124   int16_t *row1_ptr = reinterpret_cast<int16_t *>(x_tmp_buf1.data_ptr_);
125 
126   int prev_height = -2;
127 
128   for (int y = 0; y < dst_height; y++) {
129     int y_span = y_offset[y];
130 
131     if (y_span == prev_height) {
132     } else if (y_span == prev_height + 1) {
133       int16_t *tmp = row0_ptr;
134       row0_ptr = row1_ptr;
135       row1_ptr = tmp;
136       const unsigned char *src_start = src + 3 * src_width * (y_span + 1);
137       const int16_t *x_weight_p = x_weight;
138       int16_t *row1_ptr1 = row1_ptr;
139       for (int x = 0; x < dst_width; x++) {
140         const unsigned char *src_start_p = src_start + x_offset[x];
141         row1_ptr1[0] = (src_start_p[0] * x_weight_p[0] + src_start_p[3] * x_weight_p[1]) >> 4;
142         row1_ptr1[1] = (src_start_p[1] * x_weight_p[0] + src_start_p[4] * x_weight_p[1]) >> 4;
143         row1_ptr1[2] = (src_start_p[2] * x_weight_p[0] + src_start_p[5] * x_weight_p[1]) >> 4;
144         x_weight_p += 2;
145         row1_ptr1 += 3;
146       }
147     } else {
148       const unsigned char *src0 = src + 3 * src_width * (y_span);
149       const unsigned char *src1 = src + 3 * src_width * (y_span + 1);
150 
151       const int16_t *x_weight_ptr = x_weight;
152       int16_t *row0_ptr0 = row0_ptr;
153       int16_t *row1_ptr1 = row1_ptr;
154       for (int x = 0; x < dst_width; x++) {
155         const unsigned char *src0_ptr = src0 + x_offset[x];
156         const unsigned char *src1_ptr = src1 + x_offset[x];
157 
158         for (int c = 0; c < 3; c++) {
159           row0_ptr0[c] = (src0_ptr[c] * x_weight_ptr[0] + src0_ptr[c + 3] * x_weight_ptr[1]) >> 4;
160           row1_ptr1[c] = (src1_ptr[c] * x_weight_ptr[0] + src1_ptr[c + 3] * x_weight_ptr[1]) >> 4;
161         }
162 
163         x_weight_ptr += 2;
164         row0_ptr0 += 3;
165         row1_ptr1 += 3;
166       }
167     }
168     prev_height = y_span;
169 
170     int16_t *row0_ptr0 = row0_ptr;
171     int16_t *row1_ptr1 = row1_ptr;
172     unsigned char *dst_ptr = dst + dst_width * 3 * (y);
173 
174     for (int k = 0; k < dst_width * 3; k++) {
175       auto t0 = static_cast<int16_t>((y_weight[0] * static_cast<int16_t>(*row0_ptr0++)) >> 16);
176       auto t1 = static_cast<int16_t>((y_weight[1] * static_cast<int16_t>(*row1_ptr1++)) >> 16);
177       *dst_ptr++ = static_cast<unsigned char>((t0 + t1 + 2) >> 2);
178     }
179     y_weight += 2;
180   }
181   delete[] data_buf;
182   return true;
183 }
184 
ResizeBilinear1C(const unsigned char * src,int src_width,int src_height,unsigned char * dst,int dst_width,int dst_height)185 static bool ResizeBilinear1C(const unsigned char *src, int src_width, int src_height, unsigned char *dst, int dst_width,
186                              int dst_height) {
187   double scale_width = static_cast<double>(src_width) / dst_width;
188   double scale_height = static_cast<double>(src_height) / dst_height;
189 
190   if (dst_height >= (INT_MAX / 2 - dst_width)) {
191     return false;
192   }
193   if (dst_height >= (INT_MAX / dst_width)) {
194     return false;
195   }
196 
197   // The allocate memory cannot exceed 2GB.
198   if ((2 * sizeof(int) * (2 * dst_width + dst_height)) > INT_MAX) {
199     return false;
200   }
201   int *data_buf = new (std::nothrow) int[2 * sizeof(int) * (2 * dst_width + dst_height)];
202   if (data_buf == nullptr) {
203     return false;
204   }
205 
206   int *x_offset = data_buf;
207   int *y_offset = data_buf + dst_width + dst_width;
208 
209   auto *x_weight = reinterpret_cast<int16_t *>(data_buf + dst_width);
210   auto *y_weight = reinterpret_cast<int16_t *>(data_buf + dst_width + dst_width + dst_height);
211 
212   if (!InitBilinearWeight(x_offset, x_weight, scale_width, dst_width, src_width, 1)) {
213     delete[] data_buf;
214     return false;
215   }
216   if (!InitBilinearWeight(y_offset, y_weight, scale_height, dst_height, src_height, 1)) {
217     delete[] data_buf;
218     return false;
219   }
220 
221   LiteMat x_tmp_buf0(dst_width, LDataType::UINT16);
222   LiteMat x_tmp_buf1(dst_width, LDataType::UINT16);
223   int16_t *row0_ptr = reinterpret_cast<int16_t *>(x_tmp_buf0.data_ptr_);
224   int16_t *row1_ptr = reinterpret_cast<int16_t *>(x_tmp_buf1.data_ptr_);
225 
226   int prev_height = -2;
227 
228   for (int y = 0; y < dst_height; y++) {
229     int y_span = y_offset[y];
230 
231     if (y_span == prev_height) {
232     } else if (y_span == prev_height + 1) {
233       int16_t *tmp = row0_ptr;
234       row0_ptr = row1_ptr;
235       row1_ptr = tmp;
236       const unsigned char *src_start = src + src_width * (y_span + 1);
237       const int16_t *x_weight_p = x_weight;
238       int16_t *row1_ptr1 = row1_ptr;
239       for (int x = 0; x < dst_width; x++) {
240         const unsigned char *src_start_p = src_start + x_offset[x];
241         if ((src_start_p + 3 - src) >= (src_width * src_height)) {
242           continue;
243         }
244         row1_ptr1[x] = (src_start_p[0] * x_weight_p[0] + src_start_p[3] * x_weight_p[1]) >> 4;
245         x_weight_p += 2;
246       }
247     } else {
248       const unsigned char *src0 = src + src_width * (y_span);
249       const unsigned char *src1 = src + src_width * (y_span + 1);
250 
251       const int16_t *x_weight_ptr = x_weight;
252       int16_t *row0_ptr0 = row0_ptr;
253       int16_t *row1_ptr1 = row1_ptr;
254       for (int x = 0; x < dst_width; x++) {
255         const unsigned char *src0_ptr = src0 + x_offset[x];
256         const unsigned char *src1_ptr = src1 + x_offset[x];
257 
258         row0_ptr0[x] = (src0_ptr[0] * x_weight_ptr[0] + src0_ptr[3] * x_weight_ptr[1]) >> 4;
259         row1_ptr1[x] = (src1_ptr[0] * x_weight_ptr[0] + src1_ptr[3] * x_weight_ptr[1]) >> 4;
260 
261         x_weight_ptr += 2;
262       }
263     }
264     prev_height = y_span;
265 
266     int16_t *row0_ptr0 = row0_ptr;
267     int16_t *row1_ptr1 = row1_ptr;
268     unsigned char *dst_ptr = dst + dst_width * (y);
269 
270     for (int k = 0; k < dst_width; k++) {
271       auto t0 = static_cast<int16_t>((y_weight[0] * static_cast<int16_t>(*row0_ptr0++)) >> 16);
272       auto t1 = static_cast<int16_t>((y_weight[1] * static_cast<int16_t>(*row1_ptr1++)) >> 16);
273       *dst_ptr++ = static_cast<unsigned char>((t0 + t1 + 2) >> 2);
274     }
275 
276     y_weight += 2;
277   }
278   delete[] data_buf;
279   return true;
280 }
281 
clip(float value)282 static inline uint8_t clip(float value) {
283   int int_val = static_cast<int>(roundf(value));
284   return std::max<int32_t>(std::numeric_limits<uint8_t>::min(),
285                            std::min<int32_t>(std::numeric_limits<uint8_t>::max(), int_val));
286 }
287 
288 template <typename T1, typename T2>
Conv2DImplement(const LiteMat & src,const LiteMat & kernel,T2 * dst,LDataType dst_type,PaddBorderType pad_type)289 static bool Conv2DImplement(const LiteMat &src, const LiteMat &kernel, T2 *dst, LDataType dst_type,
290                             PaddBorderType pad_type) {
291   int border_x = static_cast<int>(kernel.width_ / 2);
292   int border_y = static_cast<int>(kernel.height_ / 2);
293 
294   LiteMat pad_mat;
295 
296   if ((border_x > INT_MAX / 2) || (src.width_ > INT_MAX - 2 * border_x)) {
297     return false;
298   }
299   if ((border_y > INT_MAX / 2) || (src.height_ > INT_MAX - 2 * border_y)) {
300     return false;
301   }
302 
303   pad_mat.Init(src.width_ + 2 * border_x, src.height_ + 2 * border_y, src.channel_, src.data_type_);
304   RETURN_FALSE_IF_LITEMAT_EMPTY(pad_mat);
305 
306   if (!Pad(src, pad_mat, border_y, border_y, border_x, border_x, pad_type)) {
307     return false;
308   }
309 
310   const T1 *pad_ptr = pad_mat;
311   const float *kernel_ptr = kernel;
312 
313   int pad_step = pad_mat.width_ * pad_mat.channel_;
314   int dst_step = src.width_ * src.channel_;
315 
316   if (src.channel_ == 1) {
317     for (int y = border_y; y < pad_mat.height_ - border_y; y++) {
318       for (int x = border_x; x < pad_mat.width_ - border_x; x++) {
319         float conv_sum = 0;
320         for (int i = -border_y; i < -border_y + kernel.height_; i++) {
321           for (int j = -border_x; j < -border_x + kernel.width_; j++) {
322             conv_sum += pad_ptr[(y + i) * pad_step + (x + j) * pad_mat.channel_] *
323                         kernel_ptr[(i + border_y) * kernel.width_ + (j + border_x)];
324           }
325         }
326         if (dst_type == LDataType::UINT8) {
327           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_] = clip(conv_sum);
328         } else {
329           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_] = conv_sum;
330         }
331       }
332     }
333   } else if (src.channel_ == 3) {
334     for (int y = border_y; y < pad_mat.height_ - border_y; y++) {
335       for (int x = border_x; x < pad_mat.width_ - border_x; x++) {
336         float conv_sum_b = 0;
337         float conv_sum_g = 0;
338         float conv_sum_r = 0;
339         for (int i = -border_y; i < -border_y + kernel.height_; i++) {
340           for (int j = -border_x; j < -border_x + kernel.width_; j++) {
341             conv_sum_b += pad_ptr[(y + i) * pad_step + (x + j) * pad_mat.channel_] *
342                           kernel_ptr[(i + border_y) * kernel.width_ + (j + border_x)];
343             conv_sum_g += pad_ptr[(y + i) * pad_step + (x + j) * pad_mat.channel_ + 1] *
344                           kernel_ptr[(i + border_y) * kernel.width_ + (j + border_x)];
345             conv_sum_r += pad_ptr[(y + i) * pad_step + (x + j) * pad_mat.channel_ + 2] *
346                           kernel_ptr[(i + border_y) * kernel.width_ + (j + border_x)];
347           }
348         }
349         if (dst_type == LDataType::UINT8) {
350           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_] = clip(conv_sum_b);
351           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_ + 1] = clip(conv_sum_g);
352           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_ + 2] = clip(conv_sum_r);
353         } else {
354           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_] = conv_sum_b;
355           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_ + 1] = conv_sum_g;
356           dst[(y - border_y) * dst_step + (x - border_x) * src.channel_ + 2] = conv_sum_r;
357         }
358       }
359     }
360   } else {
361     return false;
362   }
363   return true;
364 }
365 
Conv2D(const LiteMat & src,const LiteMat & kernel,LiteMat & dst,LDataType dst_type,PaddBorderType pad_type)366 bool Conv2D(const LiteMat &src, const LiteMat &kernel, LiteMat &dst, LDataType dst_type, PaddBorderType pad_type) {
367   if (src.IsEmpty() || kernel.IsEmpty()) {
368     return false;
369   }
370   if ((dst_type != LDataType::UINT8 && dst_type != LDataType::FLOAT32) || kernel.data_type_ != LDataType::FLOAT32) {
371     return false;
372   }
373   if (dst.IsEmpty() || dst.width_ != src.width_ || dst.height_ != src.height_ || dst.channel_ != src.channel_ ||
374       dst.data_type_ != dst_type) {
375     dst.Init(src.width_, src.height_, src.channel_, dst_type);
376     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
377   }
378 
379   if (src.data_type_ == LDataType::UINT8 && dst.data_type_ == LDataType::UINT8) {
380     return Conv2DImplement<uint8_t, uint8_t>(src, kernel, dst, dst_type, pad_type);
381   } else if (src.data_type_ == LDataType::UINT8 && dst.data_type_ == LDataType::FLOAT32) {
382     return Conv2DImplement<uint8_t, float>(src, kernel, dst, dst_type, pad_type);
383   } else if (src.data_type_ == LDataType::FLOAT32 && dst.data_type_ == LDataType::UINT8) {
384     return Conv2DImplement<float, uint8_t>(src, kernel, dst, dst_type, pad_type);
385   } else if (src.data_type_ == LDataType::FLOAT32 && dst.data_type_ == LDataType::FLOAT32) {
386     return Conv2DImplement<float, float>(src, kernel, dst, dst_type, pad_type);
387   } else {
388     return false;
389   }
390 }
391 
ConvRowCol(const LiteMat & src,const LiteMat & kx,const LiteMat & ky,LiteMat & dst,LDataType dst_type,PaddBorderType pad_type)392 bool ConvRowCol(const LiteMat &src, const LiteMat &kx, const LiteMat &ky, LiteMat &dst, LDataType dst_type,
393                 PaddBorderType pad_type) {
394   if (src.IsEmpty() || kx.IsEmpty() || ky.IsEmpty()) {
395     return false;
396   }
397   if (dst_type != LDataType::UINT8 && dst_type != LDataType::FLOAT32) {
398     return false;
399   }
400   if (dst.IsEmpty() || dst.width_ != src.width_ || dst.height_ != src.height_ || dst.channel_ != src.channel_ ||
401       dst.data_type_ != dst_type) {
402     dst.Init(src.width_, src.height_, src.channel_, dst_type);
403     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
404   }
405 
406   LiteMat mid;
407   bool ret = Conv2D(src, kx, mid, LDataType::FLOAT32, pad_type) && Conv2D(mid, ky, dst, dst_type, pad_type);
408   return ret;
409 }
410 
ResizeBilinear(const LiteMat & src,LiteMat & dst,int dst_w,int dst_h)411 bool ResizeBilinear(const LiteMat &src, LiteMat &dst, int dst_w, int dst_h) {
412   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
413   if (dst_h <= 0 || dst_w <= 0) {
414     return false;
415   }
416   if (src.data_type_ != LDataType::UINT8) {
417     return false;
418   }
419   if (src.channel_ != 3 && src.channel_ != 1) {
420     return false;
421   }
422   if (dst.IsEmpty()) {
423     dst.Init(dst_w, dst_h, src.channel_, LDataType::UINT8);
424     if (dst.IsEmpty()) {
425       return false;
426     }
427   }
428   if (dst.height_ != dst_h || dst.width_ != dst_w || dst.channel_ != src.channel_) {
429     return false;
430   }
431   if (dst.data_type_ != LDataType::UINT8) {
432     return false;
433   }
434 
435   if (src.channel_ == 3) {
436     const unsigned char *src_start_p = src;
437     unsigned char *dst_start_p = dst;
438     return ResizeBilinear3C(src_start_p, src.width_, src.height_, dst_start_p, dst_w, dst_h);
439   } else {  // channel == 1
440     const unsigned char *src_start_p = src;
441     unsigned char *dst_start_p = dst;
442     return ResizeBilinear1C(src_start_p, src.width_, src.height_, dst_start_p, dst_w, dst_h);
443   }
444 }
445 
ConvertBGR(const unsigned char * data,LDataType data_type,int w,int h,LiteMat & mat)446 static bool ConvertBGR(const unsigned char *data, LDataType data_type, int w, int h, LiteMat &mat) {
447   if (data_type == LDataType::UINT8) {
448     mat.Init(w, h, kChannelThree, LDataType::UINT8);
449     RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
450     unsigned char *dst_ptr = mat;
451     // mindspore lite version, there is no securec lib
452     memcpy(dst_ptr, data, w * h * kChannelThree * sizeof(unsigned char));
453   } else {
454     return false;
455   }
456   return true;
457 }
458 
ConvertRGBAToBGR(const unsigned char * data,LDataType data_type,int w,int h,LiteMat & mat)459 static bool ConvertRGBAToBGR(const unsigned char *data, LDataType data_type, int w, int h, LiteMat &mat) {
460   if (data_type == LDataType::UINT8) {
461     mat.Init(w, h, kChannelThree, LDataType::UINT8);
462     RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
463     unsigned char *ptr = mat;
464     const unsigned char *data_ptr = data;
465     for (int y = 0; y < h; y++) {
466       for (int x = 0; x < w; x++) {
467         ptr[0] = data_ptr[2];
468         ptr[1] = data_ptr[1];
469         ptr[2] = data_ptr[0];
470         ptr += 3;
471         data_ptr += 4;
472       }
473     }
474   } else {
475     return false;
476   }
477   return true;
478 }
479 
ConvertRGBAToRGB(const unsigned char * data,LDataType data_type,int w,int h,LiteMat & mat)480 static bool ConvertRGBAToRGB(const unsigned char *data, LDataType data_type, int w, int h, LiteMat &mat) {
481   if (data_type == LDataType::UINT8) {
482     mat.Init(w, h, kChannelThree, LDataType::UINT8);
483     RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
484     unsigned char *ptr = mat;
485     const unsigned char *data_ptr = data;
486     for (int y = 0; y < h; y++) {
487       for (int x = 0; x < w; x++) {
488         ptr[0] = data_ptr[0];
489         ptr[1] = data_ptr[1];
490         ptr[2] = data_ptr[2];
491         ptr += 3;
492         data_ptr += 4;
493       }
494     }
495   } else {
496     return false;
497   }
498   return true;
499 }
500 
ConvertYUV420SPToBGR(const uint8_t * data,LDataType data_type,bool flag,int w,int h,LiteMat & mat)501 static bool ConvertYUV420SPToBGR(const uint8_t *data, LDataType data_type, bool flag, int w, int h, LiteMat &mat) {
502   if (data == nullptr || w <= 0 || h <= 0) {
503     return false;
504   }
505   if (data_type == LDataType::UINT8) {
506     mat.Init(w, h, kChannelThree, LDataType::UINT8);
507     RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
508     const uint8_t *y_ptr = data;
509     const uint8_t *uv_ptr = y_ptr + w * h;
510     uint8_t *bgr_ptr = mat;
511     const int bgr_stride = 3 * w;
512 
513     for (uint64_t y = 0; y < h; ++y) {
514       uint8_t *bgr_buf = bgr_ptr;
515       const uint8_t *uv_buf = uv_ptr;
516       const uint8_t *y_buf = y_ptr;
517       uint8_t u;
518       uint8_t v;
519       for (int x = 0; x < w - 1; x += 2) {
520         if (flag) {
521           // NV21
522           u = uv_buf[1];
523           v = uv_buf[0];
524         } else {
525           // NV12
526           u = uv_buf[0];
527           v = uv_buf[1];
528         }
529         uint32_t tmp_y = (uint32_t)(y_buf[0] * kYScale * kY2G) >> 16;
530         // b
531         bgr_buf[0] = std::clamp((int32_t)(-(u * kU2B) + tmp_y + kB2B) >> 6, 0, 255);
532         // g
533         bgr_buf[1] = std::clamp((int32_t)(-(u * kU2G + v * kV2G) + tmp_y + kB2G) >> 6, 0, 255);
534         // r
535         bgr_buf[2] = std::clamp((int32_t)(-(v * kV2R) + tmp_y + kB2R) >> 6, 0, 255);
536 
537         tmp_y = (uint32_t)(y_buf[1] * kYScale * kY2G) >> 16;
538         bgr_buf[3] = std::clamp((int32_t)(-(u * kU2B) + tmp_y + kB2B) >> 6, 0, 255);
539         bgr_buf[4] = std::clamp((int32_t)(-(u * kU2G + v * kV2G) + tmp_y + kB2G) >> 6, 0, 255);
540         bgr_buf[5] = std::clamp((int32_t)(-(v * kV2R) + tmp_y + kB2R) >> 6, 0, 255);
541 
542         y_buf += 2;
543         uv_buf += 2;
544         bgr_buf += 6;
545       }
546       if (w & 1) {
547         if (flag) {
548           // NV21
549           u = uv_buf[1];
550           v = uv_buf[0];
551         } else {
552           // NV12
553           u = uv_buf[0];
554           v = uv_buf[1];
555         }
556         uint32_t tmp_y = (uint32_t)(y_buf[0] * kYScale * kY2G) >> 16;
557         bgr_buf[0] = std::clamp((int32_t)(-(u * kU2B) + tmp_y + kB2B) >> 6, 0, 255);
558         bgr_buf[1] = std::clamp((int32_t)(-(u * kU2G + v * kV2G) + tmp_y + kB2G) >> 6, 0, 255);
559         bgr_buf[2] = std::clamp((int32_t)(-(v * kV2R) + tmp_y + kB2R) >> 6, 0, 255);
560       }
561 
562       bgr_ptr += bgr_stride;
563       y_ptr += w;
564       if (y & 1) {
565         uv_ptr += w;
566       }
567     }
568   }
569   return true;
570 }
571 
ConvertRGBAToGRAY(const unsigned char * data,LDataType data_type,int w,int h,LiteMat & mat)572 static bool ConvertRGBAToGRAY(const unsigned char *data, LDataType data_type, int w, int h, LiteMat &mat) {
573   if (data_type == LDataType::UINT8) {
574     mat.Init(w, h, 1, LDataType::UINT8);
575     if (mat.IsEmpty()) {
576       return false;
577     }
578     unsigned char *ptr = mat;
579     const unsigned char *data_ptr = data;
580     for (int y = 0; y < h; y++) {
581       for (int x = 0; x < w; x++) {
582         *ptr = (data_ptr[2] * kB2Gray + data_ptr[1] * kG2Gray + data_ptr[0] * kR2Gray + kGrayShiftDelta) >> kGrayShift;
583         ptr++;
584         data_ptr += 4;
585       }
586     }
587   } else {
588     return false;
589   }
590   return true;
591 }
592 
InitFromPixel(const unsigned char * data,LPixelType pixel_type,LDataType data_type,int w,int h,LiteMat & m)593 bool InitFromPixel(const unsigned char *data, LPixelType pixel_type, LDataType data_type, int w, int h, LiteMat &m) {
594   if (data == nullptr) {
595     return false;
596   }
597   if (w <= 0 || h <= 0) {
598     return false;
599   }
600 
601   if (data_type != LDataType::UINT8) {
602     return false;
603   }
604   if (pixel_type == LPixelType::RGBA2BGR) {
605     return ConvertRGBAToBGR(data, data_type, w, h, m);
606   } else if (pixel_type == LPixelType::RGBA2GRAY) {
607     return ConvertRGBAToGRAY(data, data_type, w, h, m);
608   } else if (pixel_type == LPixelType::RGBA2RGB) {
609     return ConvertRGBAToRGB(data, data_type, w, h, m);
610   } else if (pixel_type == LPixelType::NV212BGR) {
611     return ConvertYUV420SPToBGR(data, data_type, true, w, h, m);
612   } else if (pixel_type == LPixelType::NV122BGR) {
613     return ConvertYUV420SPToBGR(data, data_type, false, w, h, m);
614   } else if (pixel_type == LPixelType::BGR) {
615     return ConvertBGR(data, data_type, w, h, m);
616   } else if (pixel_type == LPixelType::RGB) {
617     return ConvertBGR(data, data_type, w, h, m);
618   } else {
619     return false;
620   }
621 }
622 
ConvertTo(const LiteMat & src,LiteMat & dst,double scale)623 bool ConvertTo(const LiteMat &src, LiteMat &dst, double scale) {
624   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
625   if (src.data_type_ != LDataType::UINT8) {
626     return false;
627   }
628 
629   if (scale < 0.0 || scale > 100) {
630     return false;
631   }
632 
633   if (dst.IsEmpty()) {
634     dst.Init(src.width_, src.height_, src.channel_, LDataType::FLOAT32);
635     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
636   } else if (src.width_ != dst.width_ || src.height_ != dst.height_ || src.channel_ != dst.channel_ ||
637              dst.data_type_ != LDataType::FLOAT32) {
638     return false;
639   }
640 
641   const auto *src_ptr = reinterpret_cast<const uint8_t *>(src.data_ptr_);
642   auto *dst_ptr = reinterpret_cast<float *>(dst.data_ptr_);
643   int64_t total_size = src.height_ * src.width_ * src.channel_;
644   int64_t x = 0;
645 #ifdef ENABLE_NEON
646   float32x4_t v_scale = vdupq_n_f32(static_cast<float>(scale));
647   float32x4_t v_c = vdupq_n_f32(0.0f);
648   const int64_t step = 16;
649   for (; x <= total_size - step; x += step) {
650     uint8x16_t v_src = vld1q_u8(src_ptr + x);
651     uint8x16_t v_dst;
652 
653     uint16x8_t v_l_16x8 = vmovl_u8(vget_low_u8(v_src));
654     uint16x8_t v_h_16x8 = vmovl_u8(vget_high_u8(v_src));
655 
656     float32x4_t v_ll_f32x4 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_l_16x8)));
657     float32x4_t v_lh_f32x4 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_l_16x8)));
658     float32x4_t v_hl_f32x4 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_h_16x8)));
659     float32x4_t v_hh_f32x4 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_h_16x8)));
660 
661 #if defined(__aarch64__) || defined(_M_ARM64)
662     v_ll_f32x4 = vfmaq_f32(v_c, v_ll_f32x4, v_scale);
663     v_lh_f32x4 = vfmaq_f32(v_c, v_lh_f32x4, v_scale);
664     v_hl_f32x4 = vfmaq_f32(v_c, v_hl_f32x4, v_scale);
665     v_hh_f32x4 = vfmaq_f32(v_c, v_hh_f32x4, v_scale);
666 #else
667     v_ll_f32x4 = vmlaq_f32(v_c, v_ll_f32x4, v_scale);
668     v_lh_f32x4 = vmlaq_f32(v_c, v_lh_f32x4, v_scale);
669     v_hl_f32x4 = vmlaq_f32(v_c, v_hl_f32x4, v_scale);
670     v_hh_f32x4 = vmlaq_f32(v_c, v_hh_f32x4, v_scale);
671 #endif
672 
673     vst1q_f32(dst_ptr + x, v_ll_f32x4);
674     vst1q_f32(dst_ptr + x + 4, v_lh_f32x4);
675     vst1q_f32(dst_ptr + x + 8, v_hl_f32x4);
676     vst1q_f32(dst_ptr + x + 12, v_hh_f32x4);
677   }
678 #endif
679   for (; x < total_size; x++) {
680     dst_ptr[x] = static_cast<float>(src_ptr[x] * scale);
681   }
682   return true;
683 }
684 
685 template <typename T>
CropInternal(const LiteMat & src,LiteMat & dst,int x,int y,int w,int h)686 static bool CropInternal(const LiteMat &src, LiteMat &dst, int x, int y, int w, int h) {
687   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
688   int dst_h = h;
689   int dst_w = w;
690   int dst_c = src.channel_;
691   if (dst.IsEmpty()) {
692     dst.Init(dst_w, dst_h, dst_c, src.data_type_);
693     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
694   }
695   if (dst.height_ != h || dst.width_ != w || dst.channel_ != src.channel_) {
696     return false;
697   }
698   if (dst.data_type_ != src.data_type_) {
699     return false;
700   }
701   const T *src_start_p = src;
702   T *dst_start_p = dst;
703   for (int i_h = 0; i_h < dst_h; i_h++) {
704     const T *src_index_p = src_start_p + (y + i_h) * src.width_ * dst_c + x * dst_c;
705     T *dst_index_p = dst_start_p + i_h * dst_w * dst_c;
706     // mindspore lite version, there is no securec lib
707     memcpy(dst_index_p, src_index_p, dst_w * dst_c * sizeof(T));
708   }
709   return true;
710 }
711 
Crop(const LiteMat & src,LiteMat & dst,int x,int y,int w,int h)712 bool Crop(const LiteMat &src, LiteMat &dst, int x, int y, int w, int h) {
713   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
714   if (x < 0 || y < 0 || w <= 0 || h <= 0) {
715     return false;
716   }
717   if (y > src.height_ - h || x > src.width_ - w) {
718     return false;
719   }
720 
721   if (src.data_type_ == LDataType::UINT8) {
722     return CropInternal<uint8_t>(src, dst, x, y, w, h);
723   } else if (src.data_type_ == LDataType::FLOAT32) {
724     return CropInternal<float>(src, dst, x, y, w, h);
725   } else {
726     return false;
727   }
728 }
729 
CheckZero(const std::vector<float> & vs)730 static bool CheckZero(const std::vector<float> &vs) {
731   return std::any_of(vs.begin(), vs.end(), [](const float &v) { return Equal(v, 0.0f); });
732 }
733 
CheckZero(const std::vector<size_t> & vs)734 static bool CheckZero(const std::vector<size_t> &vs) {
735   return std::any_of(vs.begin(), vs.end(), [](const float &v) { return v == 0; });
736 }
737 
CheckMeanAndStd(const LiteMat & src,LiteMat & dst,int channel,const std::vector<float> & mean,const std::vector<float> & std)738 static bool CheckMeanAndStd(const LiteMat &src, LiteMat &dst, int channel, const std::vector<float> &mean,
739                             const std::vector<float> &std) {
740   if (mean.empty() && std.empty()) {
741     return false;
742   }
743   if (src.data_type_ != LDataType::FLOAT32 && src.data_type_ != LDataType::UINT8) {
744     return false;
745   }
746   if (!mean.empty()) {
747     if (mean.size() != channel) {
748       return false;
749     }
750   }
751   if (!std.empty()) {
752     if (CheckZero(std)) {
753       return false;
754     }
755     if (std.size() != channel) {
756       return false;
757     }
758   }
759   if (dst.IsEmpty()) {
760     dst.Init(src.width_, src.height_, src.channel_, LDataType::FLOAT32);
761     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
762   }
763   if (dst.height_ != src.height_ || dst.width_ != src.width_ || dst.channel_ != src.channel_) {
764     return false;
765   }
766   if (dst.data_type_ != LDataType::FLOAT32) {
767     return false;
768   }
769   return true;
770 }
771 
SubStractMeanNormalize(const LiteMat & src,LiteMat & dst,const std::vector<float> & mean,const std::vector<float> & std)772 bool SubStractMeanNormalize(const LiteMat &src, LiteMat &dst, const std::vector<float> &mean,
773                             const std::vector<float> &std) {
774   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
775   if (!CheckMeanAndStd(src, dst, src.channel_, mean, std)) {
776     return false;
777   }
778   LiteMat src_f;
779   if (src.data_type_ == LDataType::UINT8) {
780     ConvertTo(src, src_f, 1.0);
781   } else {
782     src_f = src;
783   }
784 
785   const float *src_start_p = src_f;
786   float *dst_start_p = dst;
787   if ((!mean.empty()) && std.empty()) {
788     for (int h = 0; h < src_f.height_; h++) {
789       for (int w = 0; w < src_f.width_; w++) {
790         uint32_t src_start = (h * src_f.width_ + w) * src_f.channel_;
791         for (int c = 0; c < src_f.channel_; c++) {
792           uint32_t index = src_start + c;
793           dst_start_p[index] = src_start_p[index] - mean[c];
794         }
795       }
796     }
797   } else if (mean.empty() && (!std.empty())) {
798     for (int h = 0; h < src_f.height_; h++) {
799       for (int w = 0; w < src_f.width_; w++) {
800         uint32_t src_start = (h * src_f.width_ + w) * src_f.channel_;
801         for (int c = 0; c < src_f.channel_; c++) {
802           uint32_t index = src_start + c;
803           dst_start_p[index] = src_start_p[index] / std[c];
804         }
805       }
806     }
807   } else if ((!mean.empty()) && (!std.empty())) {
808     for (int h = 0; h < src_f.height_; h++) {
809       for (int w = 0; w < src_f.width_; w++) {
810         uint32_t src_start = (h * src_f.width_ + w) * src_f.channel_;
811         for (int c = 0; c < src_f.channel_; c++) {
812           uint32_t index = src_start + c;
813           dst_start_p[index] = (src_start_p[index] - mean[c]) / std[c];
814         }
815       }
816     }
817   } else {
818     return false;
819   }
820   return true;
821 }
822 
823 template <typename T>
PadWithConstant(const LiteMat & src,LiteMat & dst,const int top,const int bottom,const int left,const int right,const PaddBorderType pad_type,uint8_t fill_b_or_gray,uint8_t fill_g,uint8_t fill_r)824 static void PadWithConstant(const LiteMat &src, LiteMat &dst, const int top, const int bottom, const int left,
825                             const int right, const PaddBorderType pad_type, uint8_t fill_b_or_gray, uint8_t fill_g,
826                             uint8_t fill_r) {
827   std::vector<uint8_t> row_buffer(dst.width_ * dst.channel_ * dst.elem_size_);
828   T *const_ptr = reinterpret_cast<T *>(row_buffer.data());
829   int src_step = src.width_ * src.channel_ * src.elem_size_;
830   int dst_step = dst.width_ * dst.channel_ * dst.elem_size_;
831   if (dst.channel_ == 1) {
832     for (int i = 0; i < dst_step; i++) {
833       const_ptr[i] = fill_b_or_gray;
834     }
835   } else if (dst.channel_ == 3) {
836     for (int i = 0; i < dst.width_; i++) {
837       const_ptr[i * dst.channel_] = fill_b_or_gray;
838       const_ptr[i * dst.channel_ + 1] = fill_g;
839       const_ptr[i * dst.channel_ + 2] = fill_r;
840     }
841   }
842 
843   auto *dst_ptr = reinterpret_cast<uint8_t *>(dst.data_ptr_);
844   auto *src_ptr = reinterpret_cast<uint8_t *>(src.data_ptr_);
845   for (int i = 0; i < top; i++) {
846     // mindspore lite version, there is no securec lib
847     memcpy(dst_ptr + i * dst_step, const_ptr, dst_step);
848   }
849 
850   int left_size = left * dst.channel_ * dst.elem_size_;
851   int right_size = right * dst.channel_ * dst.elem_size_;
852   uint8_t *dst_raw_data = dst_ptr + static_cast<ptrdiff_t>(top * dst_step + left_size);
853   for (int i = 0; i < src.height_; i++, dst_raw_data += dst_step, src_ptr += src_step) {
854     // mindspore lite version, there is no securec lib
855     memcpy(dst_raw_data, src_ptr, src_step);
856     memcpy(dst_raw_data - left_size, const_ptr, left_size);
857     memcpy(dst_raw_data + src_step, const_ptr, right_size);
858   }
859 
860   for (int i = dst.height_ - bottom; i < dst.height_; i++) {
861     // mindspore lite version, there is no securec lib
862     memcpy(dst_ptr + i * dst_step, const_ptr, dst_step);
863   }
864 }
865 
PadFromPos(int p,int len,PaddBorderType pad_type)866 static int PadFromPos(int p, int len, PaddBorderType pad_type) {
867   constexpr auto pixel_factor = 2;
868   if (p >= 0 && p < len) {
869     return p;
870   }
871   if (pad_type == PaddBorderType::PADD_BORDER_REPLICATE) {
872     return p < 0 ? 0 : len - 1;
873   } else {
874     // calculate the position of pixel in reflect mode like edcb|abcdef|edcb
875     while (p < 0 || p >= len) {
876       if (p < 0) {
877         p = -p;
878       } else {
879         p = pixel_factor * len - p - pixel_factor;
880       }
881     }
882     return p;
883   }
884 }
885 
886 template <typename T>
PadImplement(const LiteMat & src,LiteMat & dst,const int top,const int bottom,const int left,const int right,const PaddBorderType pad_type)887 static void PadImplement(const LiteMat &src, LiteMat &dst, const int top, const int bottom, const int left,
888                          const int right, const PaddBorderType pad_type) {
889   int src_step = src.width_ * src.channel_;
890   int dst_step = dst.width_ * dst.channel_;
891 
892   auto *src_data_ptr = reinterpret_cast<uint8_t *>(src.data_ptr_);
893   auto *dst_data_ptr = reinterpret_cast<uint8_t *>(dst.data_ptr_);
894   for (int i = 0; i < src.height_; i++) {
895     // mindspore lite version, there is no securec lib
896     memcpy(dst_data_ptr + (i + top) * dst.steps_[0] + left * dst.steps_[1], src_data_ptr + i * src.steps_[0],
897            src.steps_[0]);
898   }
899 
900   const T *src_ptr = src;
901   T *dst_ptr = dst;
902   for (int y = 0; y < dst.height_; y++) {
903     for (int x = 0; x < dst.width_; x++) {
904       if (y < top || y >= dst.height_ - bottom || x < left || x >= dst.width_ - right) {
905         int src_y = PadFromPos(y - top, src.height_, pad_type);
906         int src_x = PadFromPos(x - left, src.width_, pad_type);
907         for (int cn = 0; cn < dst.channel_; cn++) {
908           dst_ptr[y * dst_step + x * dst.channel_ + cn] = src_ptr[src_y * src_step + src_x * src.channel_ + cn];
909         }
910       }
911     }
912   }
913 }
914 
915 template <typename T>
ExtractChannelImpl(const T * src_ptr,T * dst_ptr,int height,int width,int channel,int col)916 void ExtractChannelImpl(const T *src_ptr, T *dst_ptr, int height, int width, int channel, int col) {
917   int total = height * width;
918   int i = 0;
919   int src_idx = col;
920   for (; i < total; i++, src_idx += channel) {
921     dst_ptr[i] = src_ptr[src_idx];
922   }
923 }
924 
ExtractChannel(LiteMat & src,LiteMat & dst,int col)925 bool ExtractChannel(LiteMat &src, LiteMat &dst, int col) {
926   if (src.IsEmpty() || col < 0 || col > src.channel_ - 1) {
927     return false;
928   }
929 
930   if (src.data_type_ == LDataType::FLOAT32 || src.data_type_ == LDataType::UINT8) {
931     if (dst.IsEmpty() || dst.width_ != src.width_ || dst.height_ != src.height_ || dst.channel_ != 1 ||
932         dst.data_type_ != src.data_type_) {
933       dst.Init(src.width_, src.height_, 1, src.data_type_);
934       RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
935     }
936   }
937 
938   if (src.data_type_ == LDataType::FLOAT32) {
939     ExtractChannelImpl<float>(src, dst, src.height_, src.width_, src.channel_, col);
940   } else if (src.data_type_ == LDataType::UINT8) {
941     ExtractChannelImpl<uint8_t>(src, dst, src.height_, src.width_, src.channel_, col);
942   } else {
943     return false;
944   }
945   return true;
946 }
947 
Split(const LiteMat & src,std::vector<LiteMat> & mv)948 bool Split(const LiteMat &src, std::vector<LiteMat> &mv) {
949   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
950   if (src.data_type_ == LDataType::FLOAT32) {
951     const float *src_start_p = src;
952     for (int c = 0; c < src.channel_; c++) {
953       LiteMat dst;
954       dst.Init(src.width_, src.height_, 1, src.data_type_);
955       RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
956       float *dst_start_p = dst;
957       for (int h = 0; h < src.height_; h++) {
958         uint32_t src_start = h * src.width_ * src.channel_;
959         uint32_t dst_start = h * dst.width_;
960         for (int w = 0; w < src.width_; w++) {
961           uint32_t src_index = src_start + w * src.channel_ + c;
962           uint32_t dst_index = dst_start + w;
963           dst_start_p[dst_index] = src_start_p[src_index];
964         }
965       }
966       mv.emplace_back(dst);
967     }
968     return true;
969   } else if (src.data_type_ == LDataType::UINT8) {
970     const uint8_t *src_start_p = src;
971     for (int c = 0; c < src.channel_; c++) {
972       LiteMat dst;
973       dst.Init(src.width_, src.height_, 1, src.data_type_);
974       RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
975       uint8_t *dst_start_p = dst;
976       for (int h = 0; h < src.height_; h++) {
977         uint32_t src_start = h * src.width_ * src.channel_;
978         uint32_t dst_start = h * dst.width_;
979         for (int w = 0; w < src.width_; w++) {
980           uint32_t src_index = src_start + w * src.channel_ + c;
981           uint32_t dst_index = dst_start + w;
982           dst_start_p[dst_index] = src_start_p[src_index];
983         }
984       }
985       mv.emplace_back(dst);
986     }
987     return true;
988   } else {
989     return false;
990   }
991 }
992 
993 template <typename T>
MergeImpl(const std::vector<LiteMat> & mv,T * dst_ptr,int height,int width,int channel)994 inline void MergeImpl(const std::vector<LiteMat> &mv, T *dst_ptr, int height, int width, int channel) {
995   T *mv_ptr[4];
996   int area = height * width;
997   for (int c = 0; c < channel; c++) {
998     mv_ptr[c] = reinterpret_cast<T *>(mv[c].data_ptr_);
999   }
1000   for (int i = 0; i < area; i++) {
1001     for (int c = 0; c < channel; c++) {
1002       dst_ptr[c] = *mv_ptr[c];
1003       mv_ptr[c]++;
1004     }
1005     dst_ptr += channel;
1006   }
1007 }
1008 
Merge(const std::vector<LiteMat> & mv,LiteMat & dst)1009 bool Merge(const std::vector<LiteMat> &mv, LiteMat &dst) {
1010   constexpr int64_t mv_size_three = 3;
1011   constexpr int64_t mv_size_four = 4;
1012   if (mv.size() != 1 && mv.size() != mv_size_three && mv.size() != mv_size_four) {
1013     return false;
1014   }
1015 
1016   int width = mv[0].width_;
1017   int height = mv[0].height_;
1018   int channel = static_cast<int>(mv.size());
1019   LDataType data_type = mv[0].data_type_;
1020 
1021   // The arrays in list must be single-channel
1022   if (std::any_of(mv.begin(), mv.end(), [](const LiteMat &m) { return m.IsEmpty() || m.channel_ != 1; })) {
1023     return false;
1024   }
1025 
1026   for (int i = 1; i < mv.size(); i++) {
1027     if (width != mv[i].width_ || height != mv[i].height_ || data_type != mv[i].data_type_) {
1028       return false;
1029     }
1030   }
1031 
1032   if (dst.IsEmpty() || dst.width_ != width || dst.height_ != height || dst.channel_ != channel ||
1033       dst.data_type_ != data_type) {
1034     dst.Init(width, height, channel, data_type);
1035     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
1036   }
1037 
1038   if (dst.data_type_ == LDataType::FLOAT32) {
1039     MergeImpl<float>(mv, dst, height, width, channel);
1040   } else if (dst.data_type_ == LDataType::UINT8) {
1041     MergeImpl<uint8_t>(mv, dst, height, width, channel);
1042   } else {
1043     return false;
1044   }
1045   return true;
1046 }
1047 
CheckInt(const std::vector<int> & nums)1048 inline bool CheckInt(const std::vector<int> &nums) {
1049   if (std::any_of(nums.begin(), nums.end(), [](const auto &num) { return num < 0; })) {
1050     return false;
1051   }
1052   return true;
1053 }
1054 
Pad(const LiteMat & src,LiteMat & dst,int top,int bottom,int left,int right,PaddBorderType pad_type,uint8_t fill_b_or_gray,uint8_t fill_g,uint8_t fill_r)1055 bool Pad(const LiteMat &src, LiteMat &dst, int top, int bottom, int left, int right, PaddBorderType pad_type,
1056          uint8_t fill_b_or_gray, uint8_t fill_g, uint8_t fill_r) {
1057   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
1058   if (!CheckInt({top, bottom, left, right})) {
1059     return false;
1060   }
1061   if (src.width_ > std::numeric_limits<int>::max() - left ||
1062       src.width_ + left > std::numeric_limits<int>::max() - right) {
1063     return false;
1064   }
1065   if (src.height_ > std::numeric_limits<int>::max() - top ||
1066       src.height_ + top > std::numeric_limits<int>::max() - bottom) {
1067     return false;
1068   }
1069   int dst_width = src.width_ + left + right;
1070   int dst_height = src.height_ + top + bottom;
1071   if (dst.IsEmpty()) {
1072     dst.Init(dst_width, dst_height, src.channel_, src.data_type_);
1073     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
1074   }
1075   if (dst.width_ != dst_width || dst.height_ != dst_height || src.channel_ != dst.channel_) {
1076     return false;
1077   }
1078   if (src.data_type_ != dst.data_type_) {
1079     return false;
1080   }
1081   if (pad_type == PADD_BORDER_CONSTANT && src.data_type_ == LDataType::FLOAT32) {
1082     PadWithConstant<float>(src, dst, top, bottom, left, right, pad_type, fill_b_or_gray, fill_g, fill_r);
1083   } else if (pad_type == PADD_BORDER_CONSTANT && src.data_type_ == LDataType::UINT8) {
1084     PadWithConstant<uint8_t>(src, dst, top, bottom, left, right, pad_type, fill_b_or_gray, fill_g, fill_r);
1085   } else if (src.data_type_ == LDataType::FLOAT32) {
1086     PadImplement<float>(src, dst, top, bottom, left, right, pad_type);
1087   } else if (src.data_type_ == LDataType::UINT8) {
1088     PadImplement<uint8_t>(src, dst, top, bottom, left, right, pad_type);
1089   } else {
1090     return false;
1091   }
1092   return true;
1093 }
1094 
GetDefaultBoxes(const BoxesConfig & config)1095 std::vector<std::vector<float>> GetDefaultBoxes(const BoxesConfig &config) {
1096   size_t size = config.num_default.size();
1097   if (size <= 1 || config.feature_size.size() != size || config.steps.size() != size ||
1098       config.aspect_rations.size() != size) {
1099     return {};
1100   }
1101   if (config.max_scale < config.min_scale) {
1102     return {};
1103   }
1104   std::vector<float> fk;
1105   auto num = static_cast<float>(config.img_shape[0]);
1106   for (auto step : config.steps) {
1107     if (step == 0) {
1108       return {};
1109     }
1110     fk.push_back(num / static_cast<float>(step));
1111   }
1112   float scale_rate = (config.max_scale - config.min_scale) / static_cast<float>(config.num_default.size() - 1);
1113   std::vector<float> scales(config.num_default.size());
1114   for (int i = 0; i < scales.size(); i++) {
1115     scales[i] = config.min_scale + scale_rate * static_cast<float>(i);
1116   }
1117   scales.push_back(1.0f);
1118   std::vector<std::vector<float>> default_boxes;
1119   for (auto i = 0; i < config.feature_size.size(); i++) {
1120     float sk1 = scales[i];
1121     float sk2 = scales[i + 1];
1122     float sk3 = std::sqrt(sk1 * sk2);
1123     std::vector<std::vector<float>> all_sizes;
1124     float w;
1125     float h;
1126     constexpr int32_t kRation = 2;
1127     if (i == 0) {
1128       // Multiplying the square root by sk1
1129       w = sk1 * sqrtf(kRation);
1130       // Divide sk2 by the square root
1131       h = sk1 / sqrtf(kRation);
1132       all_sizes = {{0.1, 0.1}, {w, h}, {h, w}};
1133     } else {
1134       all_sizes = {{sk1, sk1}};
1135       for (float ration : config.aspect_rations[i]) {
1136         w = sk1 * sqrtf(ration);
1137         h = sk1 / sqrtf(ration);
1138         all_sizes.push_back({w, h});
1139         all_sizes.push_back({h, w});
1140       }
1141       all_sizes.push_back({sk3, sk3});
1142     }
1143 
1144     for (int j = 0; j < config.feature_size[i]; j++) {
1145       for (int k = 0; k < config.feature_size[i]; k++) {
1146         for (auto &all_size : all_sizes) {
1147           float cx = (static_cast<float>(k) + 0.5F) / fk[i];
1148           float cy = (static_cast<float>(j) + 0.5F) / fk[i];
1149           default_boxes.push_back({cy, cx, all_size[1], all_size[0]});
1150         }
1151       }
1152     }
1153   }
1154   return default_boxes;
1155 }
1156 
ConvertBoxes(std::vector<std::vector<float>> & boxes,const std::vector<std::vector<float>> & default_boxes,const BoxesConfig & config)1157 void ConvertBoxes(std::vector<std::vector<float>> &boxes, const std::vector<std::vector<float>> &default_boxes,
1158                   const BoxesConfig &config) {
1159   constexpr int64_t prior_scaling_size = 2;
1160   if (boxes.size() != default_boxes.size() || config.prior_scaling.size() != prior_scaling_size) {
1161     boxes = {};
1162     return;
1163   }
1164   for (int i = 0; i < default_boxes.size(); i++) {
1165     if (boxes[i].size() != 4 || default_boxes[i].size() != 4) {
1166       boxes = {};
1167       return;
1168     }
1169     // 0, 1, 2, 3 is the vector index of boxes and default_boxes
1170     boxes[i][0] = boxes[i][0] * config.prior_scaling[0] * default_boxes[i][2] + default_boxes[i][0];
1171     boxes[i][1] = boxes[i][1] * config.prior_scaling[0] * default_boxes[i][3] + default_boxes[i][1];
1172     boxes[i][2] = expf(boxes[i][2] * config.prior_scaling[1]) * default_boxes[i][2];
1173     boxes[i][3] = expf(boxes[i][3] * config.prior_scaling[1]) * default_boxes[i][3];
1174   }
1175 }
1176 
ApplyNms(const std::vector<std::vector<float>> & all_boxes,std::vector<float> & all_scores,float thres,int max_boxes)1177 std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std::vector<float> &all_scores, float thres,
1178                           int max_boxes) {
1179   if (all_boxes.size() != all_scores.size()) {
1180     return {};
1181   }
1182   size_t boxes_num = all_boxes.size();
1183   std::vector<float> areas(boxes_num);
1184   std::vector<int> order(boxes_num);
1185   for (auto i = 0; i < boxes_num; i++) {
1186     if (all_boxes[i].size() < 4) {
1187       return {};
1188     }
1189     areas[i] = (all_boxes[i][3] - all_boxes[i][1] + 1) * (all_boxes[i][2] - all_boxes[i][0] + 1);
1190     order[i] = i;
1191   }
1192 
1193   std::sort(order.begin(), order.end(),
1194             [&all_scores](int pos1, int pos2) { return (all_scores[pos1] > all_scores[pos2]); });
1195   std::vector<int> keep;
1196   while (!order.empty()) {
1197     int i = order[0];
1198     keep.push_back(i);
1199     if (keep.size() >= max_boxes) {
1200       break;
1201     }
1202     int len = static_cast<int>(order.size() - 1);
1203     std::vector<float> ovr(len);
1204     for (int j = 0; j < len; j++) {
1205       float xx1 = std::max(all_boxes[i][1], all_boxes[order[j + 1]][1]);
1206       float yy1 = std::max(all_boxes[i][0], all_boxes[order[j + 1]][0]);
1207       float xx2 = std::min(all_boxes[i][3], all_boxes[order[j + 1]][3]);
1208       float yy2 = std::min(all_boxes[i][2], all_boxes[order[j + 1]][2]);
1209 
1210       float w = std::max(0.0f, xx2 - xx1 + 1);
1211       float h = std::max(0.0f, yy2 - yy1 + 1);
1212       float inter = w * h;
1213       ovr[j] = inter / (areas[i] + areas[order[j + 1]] - inter);
1214     }
1215     std::vector<int> inds;
1216     for (int j = 0; j < len; j++) {
1217       if (ovr[j] <= thres) {
1218         inds.push_back(j + 1);
1219       }
1220     }
1221     std::vector<int> new_order;
1222     new_order.reserve(inds.size());
1223     (void)std::transform(inds.begin(), inds.end(), std::back_inserter(new_order),
1224                          [&order](int index) -> int { return order[index]; });
1225     order = new_order;
1226   }
1227   return keep;
1228 }
1229 
1230 template <typename Pixel_Type>
ImplementAffine(LiteMat & src,LiteMat & out_img,const double M[6],std::vector<size_t> & dsize,Pixel_Type borderValue)1231 bool ImplementAffine(LiteMat &src, LiteMat &out_img, const double M[6], std::vector<size_t> &dsize,
1232                      Pixel_Type borderValue) {
1233   if (src.IsEmpty() || dsize.size() != 2 || CheckZero(dsize)) {
1234     return false;
1235   }
1236 
1237   double IM[6];
1238   for (int i = 0; i < 6; i++) {
1239     IM[i] = M[i];
1240   }
1241 
1242   double D = IM[0] * IM[4] - IM[1] * IM[3];
1243   D = std::fabs(D) > std::numeric_limits<double>::epsilon() ? 1.0f / D : 0;
1244   double A11 = IM[4] * D, A22 = IM[0] * D;
1245   IM[0] = A11;
1246   IM[1] *= -D;
1247   IM[3] *= -D;
1248   IM[4] = A22;
1249   double b1 = -IM[0] * IM[2] - IM[1] * IM[5];
1250   double b2 = -IM[3] * IM[2] - IM[4] * IM[5];
1251   IM[2] = b1;
1252   IM[5] = b2;
1253   if (out_img.IsEmpty()) {
1254     out_img.Init(static_cast<int>(dsize[0]), static_cast<int>(dsize[1]), sizeof(Pixel_Type), src.data_type_);
1255     RETURN_FALSE_IF_LITEMAT_EMPTY(out_img);
1256   } else if (out_img.height_ != dsize[1] || out_img.width_ != dsize[0] || out_img.channel_ != src.channel_) {
1257     return false;
1258   } else if (out_img.data_type_ != src.data_type_) {
1259     return false;
1260   }
1261 
1262   for (int y = 0; y < out_img.height_; y++) {
1263     for (int x = 0; x < out_img.width_; x++) {
1264       int src_x = IM[0] * x + IM[1] * y + IM[2];
1265       int src_y = IM[3] * x + IM[4] * y + IM[5];
1266       if (src_x >= 0 && src_y >= 0 && src_x < src.width_ && src_y < src.height_) {
1267         Pixel_Type src_pixel = static_cast<Pixel_Type *>(src.data_ptr_)[src_y * src.width_ + src_x];
1268         static_cast<Pixel_Type *>(out_img.data_ptr_)[y * out_img.width_ + x] = src_pixel;
1269       } else {
1270         static_cast<Pixel_Type *>(out_img.data_ptr_)[y * out_img.width_ + x] = borderValue;
1271       }
1272     }
1273   }
1274 
1275   return true;
1276 }
1277 
Affine(LiteMat & src,LiteMat & out_img,const double M[6],std::vector<size_t> dsize,UINT8_C1 borderValue)1278 bool Affine(LiteMat &src, LiteMat &out_img, const double M[6], std::vector<size_t> dsize, UINT8_C1 borderValue) {
1279   if (src.channel_ == 1 && src.data_type_ == LDataType::UINT8) {
1280     return ImplementAffine(src, out_img, M, dsize, borderValue);
1281   } else {
1282     return false;
1283   }
1284 }
1285 
Affine(LiteMat & src,LiteMat & out_img,const double M[6],std::vector<size_t> dsize,UINT8_C3 borderValue)1286 bool Affine(LiteMat &src, LiteMat &out_img, const double M[6], std::vector<size_t> dsize, UINT8_C3 borderValue) {
1287   if (src.channel_ == 3 && src.data_type_ == LDataType::UINT8) {
1288     return ImplementAffine(src, out_img, M, dsize, borderValue);
1289   } else {
1290     return false;
1291   }
1292 }
1293 
Affine(LiteMat & src,LiteMat & out_img,const double M[6],std::vector<size_t> dsize,FLOAT32_C1 borderValue)1294 bool Affine(LiteMat &src, LiteMat &out_img, const double M[6], std::vector<size_t> dsize, FLOAT32_C1 borderValue) {
1295   if (src.channel_ == 1 && src.data_type_ == LDataType::FLOAT32) {
1296     return ImplementAffine(src, out_img, M, dsize, borderValue);
1297   } else {
1298     return false;
1299   }
1300 }
1301 
Affine(LiteMat & src,LiteMat & out_img,const double M[6],std::vector<size_t> dsize,FLOAT32_C3 borderValue)1302 bool Affine(LiteMat &src, LiteMat &out_img, const double M[6], std::vector<size_t> dsize, FLOAT32_C3 borderValue) {
1303   constexpr int64_t channel = 3;
1304   if (src.channel_ == channel && src.data_type_ == LDataType::FLOAT32) {
1305     return ImplementAffine(src, out_img, M, dsize, borderValue);
1306   } else {
1307     return false;
1308   }
1309 }
1310 
RotationMatrix2DImpl(float x,float y,double angle,double scale,LiteMat & M)1311 inline void RotationMatrix2DImpl(float x, float y, double angle, double scale, LiteMat &M) {
1312   angle *= CV_PI / 180;
1313   double alpha = std::cos(angle) * scale;
1314   double beta = std::sin(angle) * scale;
1315 
1316   M.ptr<double>(0)[0] = alpha;
1317   M.ptr<double>(0)[1] = beta;
1318   M.ptr<double>(0)[2] = (1 - alpha) * x - beta * y;
1319   M.ptr<double>(1)[0] = -beta;
1320   M.ptr<double>(1)[1] = alpha;
1321   M.ptr<double>(1)[2] = beta * x + (1 - alpha) * y;
1322 }
1323 
GetRotationMatrix2D(float x,float y,double angle,double scale,LiteMat & M)1324 bool GetRotationMatrix2D(float x, float y, double angle, double scale, LiteMat &M) {
1325   M.Init(3, 2, LDataType(LDataType::DOUBLE));
1326   RETURN_FALSE_IF_LITEMAT_EMPTY(M);
1327   RotationMatrix2DImpl(x, y, angle, scale, M);
1328   return true;
1329 }
1330 
1331 template <typename T>
TransposeImpl(const LiteMat & src,LiteMat & dst)1332 bool TransposeImpl(const LiteMat &src, LiteMat &dst) {
1333   int m = src.width_;
1334   int n = src.height_;
1335 
1336   dst.Init(n, m, src.data_type_);
1337   RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
1338   for (int i = 0; i < m; i++) {
1339     for (int j = 0; j < n; j++) {
1340       dst.ptr<T>(i)[j] = src.ptr<T>(j)[i];
1341     }
1342   }
1343 
1344   return true;
1345 }
1346 
Transpose(const LiteMat & src,LiteMat & dst)1347 bool Transpose(const LiteMat &src, LiteMat &dst) {
1348   if (src.IsEmpty()) {
1349     return false;
1350   }
1351   if (src.data_type_ == LDataType::DOUBLE) {
1352     return TransposeImpl<double>(src, dst);
1353   } else if (src.data_type_ == LDataType::FLOAT32) {
1354     return TransposeImpl<float>(src, dst);
1355   } else {
1356     return false;
1357   }
1358 }
1359 
1360 template <typename T>
Hypot_(T a,T b)1361 static inline T Hypot_(T a, T b) {
1362   a = std::abs(a);
1363   b = std::abs(b);
1364   if (a > b) {
1365     b /= a;
1366     return a * std::sqrt(1 + b * b);
1367   }
1368 
1369   if (b > 0) {
1370     a /= b;
1371     return b * std::sqrt(1 + a * a);
1372   }
1373   return 0;
1374 }
1375 
1376 template <typename T>
Calculation(int n,int m,std::vector<double> & W,LiteMat & A,LiteMat & V,const T eps)1377 void Calculation(int n, int m, std::vector<double> &W, LiteMat &A, LiteMat &V, const T eps) {
1378   int max_iter = std::max(m, 30);
1379   for (int iter = 0; iter < max_iter; iter++) {
1380     bool change = false;
1381     T c;
1382     T s;
1383 
1384     for (int i = 0; i < n - 1; i++) {
1385       for (int j = i + 1; j < n; j++) {
1386         T *Ai = A.ptr<T>(i);
1387         T *Aj = A.ptr<T>(j);
1388         double a = W[i];
1389         double p = 0;
1390         double b = W[j];
1391 
1392         for (int k = 0; k < m; k++) {
1393           p += static_cast<double>(Ai[k] * Aj[k]);
1394         }
1395 
1396         if (std::abs(p) <= eps * std::sqrt(static_cast<double>(a * b))) {
1397           continue;
1398         }
1399 
1400         p *= 2;
1401         double beta = a - b;
1402         double gamma = Hypot_(static_cast<double>(p), beta);
1403 
1404         if (beta < 0) {
1405           double delta = (gamma - beta) * 0.5;
1406           s = (T)std::sqrt(delta / gamma);
1407           c = (T)(p / (gamma * s * 2));
1408         } else {
1409           c = (T)std::sqrt((gamma + beta) / (gamma * 2));
1410           s = (T)(p / (gamma * c * 2));
1411         }
1412 
1413         a = 0;
1414         b = 0;
1415         for (int k = 0; k < m; k++) {
1416           T t0 = c * Ai[k] + s * Aj[k];
1417           T t1 = -s * Ai[k] + c * Aj[k];
1418           Ai[k] = t0;
1419           Aj[k] = t1;
1420           a += static_cast<double>(t0 * t0);
1421           b += static_cast<double>(t1 * t1);
1422         }
1423         W[i] = a;
1424         W[j] = b;
1425         change = true;
1426         T *Vi = V.ptr<T>(i);
1427         T *Vj = V.ptr<T>(j);
1428 
1429         for (int k = 0; k < n; k++) {
1430           T t0 = c * Vi[k] + s * Vj[k];
1431           T t1 = -s * Vi[k] + c * Vj[k];
1432           Vi[k] = t0;
1433           Vj[k] = t1;
1434         }
1435       }
1436     }
1437 
1438     if (!change) {
1439       break;
1440     }
1441   }
1442 }
1443 
1444 template <typename T>
CalculationMatrix(int n,int m,std::vector<double> & W,LiteMat & A,LiteMat & V,const T eps)1445 void CalculationMatrix(int n, int m, std::vector<double> &W, LiteMat &A, LiteMat &V, const T eps) {
1446   for (int i = 0; i < n; i++) {
1447     double sd = 0.;
1448     for (int j = 0; j < m; j++) {
1449       T t = A.ptr<T>(i)[j];
1450       sd += static_cast<double>(t * t);
1451     }
1452     W[i] = sd;
1453 
1454     for (int k = 0; k < n; k++) {
1455       V.ptr<T>(i)[k] = 0;
1456     }
1457     V.ptr<T>(i)[i] = 1;
1458   }
1459 
1460   Calculation<T>(n, m, W, A, V, eps);
1461   for (int i = 0; i < n; i++) {
1462     double sd = 0;
1463     for (int k = 0; k < m; k++) {
1464       T t = A.ptr<T>(i)[k];
1465       sd += static_cast<double>(t * t);
1466     }
1467     W[i] = std::sqrt(sd);
1468   }
1469 
1470   for (int i = 0; i < n - 1; i++) {
1471     int mid = i;
1472     for (int j = i + 1; j < n; j++) {
1473       if (W[mid] < W[j]) {
1474         mid = j;
1475       }
1476     }
1477 
1478     if (i != mid) {
1479       std::swap(W[i], W[mid]);
1480       for (int j = 0; j < m; j++) {
1481         std::swap(A.ptr<T>(i)[j], A.ptr<T>(mid)[j]);
1482       }
1483 
1484       for (int j = 0; j < n; j++) {
1485         std::swap(V.ptr<T>(i)[j], V.ptr<T>(mid)[j]);
1486       }
1487     }
1488   }
1489 }
1490 
1491 template <typename T>
JacobiSVD(LiteMat & A,LiteMat & _W,LiteMat & V)1492 void JacobiSVD(LiteMat &A, LiteMat &_W, LiteMat &V) {
1493   double min_val = FLT_MIN;
1494   T eps = (T)(FLT_EPSILON * 2);
1495   int m = A.width_;
1496   int n = _W.height_;
1497   int urows = m;
1498   std::vector<double> W(n, 0.);
1499 
1500   CalculationMatrix<T>(n, m, W, A, V, eps);
1501   for (int i = 0; i < n; i++) {
1502     _W.ptr<T>(i)[0] = (T)W[i];
1503   }
1504 
1505   std::random_device rd;
1506   std::mt19937 gen(rd());
1507   std::uniform_int_distribution<unsigned int> dis(0, 4294967294);
1508 
1509   for (int i = 0; i < urows; i++) {
1510     double mid = i < n ? W[i] : 0;
1511     for (int ii = 0; ii < 100 && mid <= min_val; ii++) {
1512       const T val0 = (T)(1. / m);
1513       for (int k = 0; k < m; k++) {
1514         unsigned int rng = dis(gen);
1515         T val = (rng & 256) != 0 ? val0 : -val0;
1516         A.ptr<T>(i)[k] = val;
1517       }
1518 
1519       for (int inner = 0; inner < 2; inner++) {
1520         for (int j = 0; j < i; j++) {
1521           mid = 0;
1522           for (int k = 0; k < m; k++) {
1523             mid += A.ptr<T>(i)[k] * A.ptr<T>(j)[k];
1524           }
1525           T asum = 0;
1526           for (int k = 0; k < m; k++) {
1527             T t = (T)(A.ptr<T>(i)[k] - mid * A.ptr<T>(j)[k]);
1528             A.ptr<T>(i)[k] = t;
1529             asum += std::abs(t);
1530           }
1531 
1532           asum = asum > eps * 100 ? 1 / asum : 0;
1533           for (int k = 0; k < m; k++) {
1534             A.ptr<T>(i)[k] *= asum;
1535           }
1536         }
1537       }
1538 
1539       mid = 0;
1540       for (int k = 0; k < m; k++) {
1541         T t = A.ptr<T>(i)[k];
1542         mid += static_cast<double>(t * t);
1543       }
1544       mid = std::sqrt(mid);
1545     }
1546 
1547     T s = (T)(mid > min_val ? 1 / mid : 0.);
1548     for (int k = 0; k < m; k++) {
1549       A.ptr<T>(i)[k] *= s;
1550     }
1551   }
1552 }
1553 
1554 template <typename T>
SVBkSb(int m,int n,LiteMat w,LiteMat u,LiteMat v,const LiteMat src2,LiteMat dst)1555 void SVBkSb(int m, int n, LiteMat w, LiteMat u, LiteMat v, const LiteMat src2, LiteMat dst) {
1556   T eps = DBL_EPSILON * 2;
1557   double thresgold = 0;
1558   int nm = std::min(m, n);
1559 
1560   for (int i = 0; i < n; i++) {
1561     dst.ptr<T>(i)[0] = 0;
1562   }
1563 
1564   for (int i = 0; i < nm; i++) {
1565     for (int j = 0; j < w.width_; j++) {
1566       thresgold += w.ptr<T>(i)[j];
1567     }
1568   }
1569   thresgold *= eps;
1570 
1571   for (int i = 0; i < nm; i++) {
1572     double wi = w.ptr<T>(i)[0];
1573     if (static_cast<double>(std::abs(wi)) < thresgold) {
1574       continue;
1575     }
1576     wi = 1 / wi;
1577     double s = 0;
1578     for (int j = 0; j < n; j++) {
1579       s += u.ptr<T>(i)[j] * src2.ptr<T>(j)[0];
1580     }
1581 
1582     s *= wi;
1583     for (int j = 0; j < n; j++) {
1584       dst.ptr<T>(j)[0] = dst.ptr<T>(j)[0] + s * v.ptr<T>(i)[j];
1585     }
1586   }
1587 }
1588 
GetPerspectiveTransformImpl(const LiteMat & src1,const LiteMat & src2,const LiteMat & dst)1589 bool GetPerspectiveTransformImpl(const LiteMat &src1, const LiteMat &src2, const LiteMat &dst) {
1590   LDataType type = src1.data_type_;
1591   int m = src1.height_;
1592   int m_ = m;
1593   int n = src1.width_;
1594 
1595   if (m < n) {
1596     return false;
1597   }
1598 
1599   double val_a[64] = {0};
1600   double val_v[64] = {0};
1601   double val_w[8] = {0};
1602   LiteMat a(m_, n, val_a, type);
1603   Transpose(src1, a);
1604   LiteMat w(1, n, val_w, type);
1605   LiteMat v(n, n, val_v, type);
1606   LiteMat u;
1607 
1608   JacobiSVD<double>(a, w, v);
1609   u = a;
1610 
1611   SVBkSb<double>(m_, n, w, u, v, src2, dst);
1612   return true;
1613 }
1614 
GetPerspectiveTransform(std::vector<Point> src_point,std::vector<Point> dst_point,LiteMat & M)1615 bool GetPerspectiveTransform(std::vector<Point> src_point, std::vector<Point> dst_point, LiteMat &M) {
1616   if (src_point.size() != 4 || dst_point.size() != 4) {
1617     return false;
1618   }
1619   double m[8][8];
1620   double n[8];
1621   LiteMat src1(8, 8, m, LDataType(LDataType::DOUBLE));
1622   LiteMat src2(1, 8, n, LDataType(LDataType::DOUBLE));
1623 
1624   for (int i = 0; i < 4; ++i) {
1625     m[i][0] = m[i + 4][3] = src_point[i].x;
1626     m[i][1] = m[i + 4][4] = src_point[i].y;
1627     m[i][2] = m[i + 4][5] = 1;
1628     m[i][3] = m[i][4] = m[i][5] = m[i + 4][0] = m[i + 4][1] = m[i + 4][2] = 0;
1629     m[i][6] = -src_point[i].x * dst_point[i].x;
1630     m[i][7] = -src_point[i].y * dst_point[i].x;
1631     m[i + 4][6] = -src_point[i].x * dst_point[i].y;
1632     m[i + 4][7] = -src_point[i].y * dst_point[i].y;
1633     n[i] = dst_point[i].x;
1634     n[i + 4] = dst_point[i].y;
1635   }
1636 
1637   M.Init(3, 3, LDataType(LDataType::DOUBLE));
1638   RETURN_FALSE_IF_LITEMAT_EMPTY(M);
1639   LiteMat dst(1, 8, M.data_ptr_, LDataType(LDataType::DOUBLE));
1640 
1641   GetPerspectiveTransformImpl(src1, src2, dst);
1642   M.ptr<double>(2)[2] = 1;
1643   return true;
1644 }
1645 
GetAffineTransformImpl(LiteMat & src,LiteMat & dst)1646 bool GetAffineTransformImpl(LiteMat &src, LiteMat &dst) {
1647   int m = src.height_;
1648   int n = dst.width_;
1649   for (int i = 0; i < m; i++) {
1650     int k = i;
1651     for (int j = i + 1; j < m; j++) {
1652       if (std::abs(src.ptr<double>(j)[i]) > std::abs(src.ptr<double>(k)[i])) {
1653         k = j;
1654       }
1655     }
1656 
1657     if (std::abs(src.ptr<double>(k)[i]) < DBL_EPSILON * 100) {
1658       dst.Init(1, 6, LDataType(LDataType::DOUBLE));
1659       RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
1660       (void)memset(dst.data_ptr_, 0, 6 * sizeof(double));
1661       RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
1662       return false;
1663     }
1664     if (k != i) {
1665       for (int j = i; j < m; j++) {
1666         std::swap(src.ptr<double>(i)[j], src.ptr<double>(k)[j]);
1667       }
1668 
1669       if (dst.data_ptr_) {
1670         for (int j = 0; j < n; j++) {
1671           std::swap(dst.ptr<double>(i)[j], dst.ptr<double>(k)[j]);
1672         }
1673       }
1674     }
1675 
1676     const double d = -1 / src.ptr<double>(i)[i];
1677     for (int j = i + 1; j < m; j++) {
1678       double alpha = src.ptr<double>(j)[i] * d;
1679       for (k = i + 1; k < m; k++) {
1680         src.ptr<double>(j)[k] += alpha * src.ptr<double>(i)[k];
1681       }
1682 
1683       if (dst.data_ptr_) {
1684         for (k = 0; k < n; k++) {
1685           dst.ptr<double>(j)[k] += alpha * dst.ptr<double>(i)[k];
1686         }
1687       }
1688     }
1689   }
1690 
1691   if (dst.data_ptr_) {
1692     for (int i = m - 1; i >= 0; i--) {
1693       for (int j = 0; j < n; j++) {
1694         double s = dst.ptr<double>(i)[j];
1695         for (int k = i + 1; k < m; k++) {
1696           s -= src.ptr<double>(i)[k] * dst.ptr<double>(k)[j];
1697         }
1698         dst.ptr<double>(i)[j] = s / src.ptr<double>(i)[i];
1699       }
1700     }
1701   }
1702 
1703   return true;
1704 }
1705 
GetAffineTransform(std::vector<Point> src_point,std::vector<Point> dst_point,LiteMat & M)1706 bool GetAffineTransform(std::vector<Point> src_point, std::vector<Point> dst_point, LiteMat &M) {
1707   if (src_point.size() != 3 || dst_point.size() != 3) {
1708     return false;
1709   }
1710   double m[6 * 6];
1711   double n[6];
1712   LiteMat src1(6, 6, m, LDataType(LDataType::DOUBLE));
1713   LiteMat src2(1, 6, n, LDataType(LDataType::DOUBLE));
1714   RETURN_FALSE_IF_LITEMAT_EMPTY(src1);
1715   RETURN_FALSE_IF_LITEMAT_EMPTY(src2);
1716 
1717   for (int i = 0; i < 3; i++) {
1718     int j = i * 12;
1719     int k = i * 12 + 6;
1720     m[j] = m[k + 3] = src_point[i].x;
1721     m[j + 1] = m[k + 4] = src_point[i].y;
1722     m[j + 2] = m[k + 5] = 1;
1723     m[j + 3] = m[j + 4] = m[j + 5] = 0;
1724     m[k] = m[k + 1] = m[k + 2] = 0;
1725     n[i * 2] = dst_point[i].x;
1726     n[i * 2 + 1] = dst_point[i].y;
1727   }
1728 
1729   GetAffineTransformImpl(src1, src2);
1730   M.Init(3, 2, 1, LDataType(LDataType::DOUBLE));
1731   RETURN_FALSE_IF_LITEMAT_EMPTY(M);
1732   for (int i = 0; i < M.height_; i++) {
1733     for (int j = 0; j < M.width_; j++) {
1734       M.ptr<double>(i)[j] = src2.ptr<double>(i * M.width_ + j)[0];
1735     }
1736   }
1737   return true;
1738 }
1739 
ConvertRgbToBgr(const LiteMat & src,const LDataType & data_type,int w,int h,LiteMat & mat)1740 bool ConvertRgbToBgr(const LiteMat &src, const LDataType &data_type, int w, int h, LiteMat &mat) {
1741   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
1742   if (data_type == LDataType::UINT8) {
1743     if (src.IsEmpty()) {
1744       return false;
1745     }
1746     if (mat.IsEmpty()) {
1747       mat.Init(w, h, 3, LDataType::UINT8);
1748       RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
1749     }
1750     if (mat.channel_ != 3) {
1751       return false;
1752     }
1753     if ((src.width_ != w) || (src.height_ != h)) {
1754       return false;
1755     }
1756     unsigned char *ptr = mat;
1757     const unsigned char *data_ptr = src;
1758     for (int y = 0; y < h; y++) {
1759       for (int x = 0; x < w; x++) {
1760         ptr[0] = data_ptr[2];
1761         ptr[1] = data_ptr[1];
1762         ptr[2] = data_ptr[0];
1763 
1764         ptr += 3;
1765         data_ptr += 3;
1766       }
1767     }
1768   } else {
1769     return false;
1770   }
1771   return true;
1772 }
1773 
ConvertRgbToGray(const LiteMat & src,LDataType data_type,int w,int h,LiteMat & mat)1774 bool ConvertRgbToGray(const LiteMat &src, LDataType data_type, int w, int h, LiteMat &mat) {
1775   RETURN_FALSE_IF_LITEMAT_EMPTY(src);
1776   if (data_type == LDataType::UINT8) {
1777     if (src.IsEmpty()) {
1778       return false;
1779     }
1780     if (mat.IsEmpty()) {
1781       mat.Init(w, h, 1, LDataType::UINT8);
1782       RETURN_FALSE_IF_LITEMAT_EMPTY(mat);
1783     }
1784     if (mat.channel_ != 1) {
1785       return false;
1786     }
1787     if ((src.width_ != w) || (src.height_ != h)) {
1788       return false;
1789     }
1790     unsigned char *ptr = mat;
1791     const unsigned char *data_ptr = src;
1792     for (int y = 0; y < h; y++) {
1793       for (int x = 0; x < w; x++) {
1794         *ptr = (data_ptr[2] * kB2Gray + data_ptr[1] * kG2Gray + data_ptr[0] * kR2Gray + kGrayShiftDelta) >> kGrayShift;
1795         ptr++;
1796         data_ptr += 3;
1797       }
1798     }
1799   } else {
1800     return false;
1801   }
1802   return true;
1803 }
1804 
UpdateOrientationAfineMat(const LiteMat & src,int * rotationDstWidth,int * rotationDstHeight,float (* varM)[2][3],int img_orientation)1805 void UpdateOrientationAfineMat(const LiteMat &src, int *rotationDstWidth, int *rotationDstHeight, float (*varM)[2][3],
1806                                int img_orientation) {
1807   int srcOrientation = img_orientation;
1808   if (IM_TOOL_EXIF_ORIENTATION_0_DEG_MIRROR == srcOrientation) {
1809     // 0, 2 is the matrix index of varM
1810     (*varM)[0][0] *= -1;
1811     (*varM)[0][2] += static_cast<float>(*rotationDstWidth - 1);
1812   } else if ((IM_TOOL_EXIF_ORIENTATION_180_DEG == srcOrientation) ||
1813              (IM_TOOL_EXIF_ORIENTATION_180_DEG_MIRROR == srcOrientation)) {
1814     // 0, 1, 2 is the matrix index of varM
1815     (*varM)[0][0] = -1;
1816     (*varM)[0][1] = 0;
1817     (*varM)[0][2] = static_cast<float>(*rotationDstWidth - 1);
1818     (*varM)[1][0] = 0;
1819     (*varM)[1][1] = -1;
1820     (*varM)[1][2] = static_cast<float>(*rotationDstHeight - 1);
1821     if (IM_TOOL_EXIF_ORIENTATION_180_DEG_MIRROR == srcOrientation) {
1822       /* with (*varM)irror */
1823       (*varM)[0][0] *= -1;
1824       (*varM)[0][2] -= static_cast<float>(*rotationDstWidth - 1);
1825     }
1826   } else if ((IM_TOOL_EXIF_ORIENTATION_90_DEG_MIRROR == srcOrientation) ||
1827              (IM_TOOL_EXIF_ORIENTATION_90_DEG == srcOrientation)) {
1828     /* 90 Deg rotation */
1829     *rotationDstWidth = src.height_;
1830     *rotationDstHeight = src.width_;
1831     (*varM)[0][0] = 0;
1832     (*varM)[0][1] = -1;
1833     (*varM)[0][2] = static_cast<float>(*rotationDstWidth - 1);
1834     (*varM)[1][0] = 1;
1835     (*varM)[1][1] = 0;
1836     (*varM)[1][2] = 0;
1837     if (IM_TOOL_EXIF_ORIENTATION_90_DEG_MIRROR == srcOrientation) {
1838       /* with Mirror */
1839       (*varM)[0][1] *= -1;
1840       (*varM)[0][2] -= static_cast<float>(*rotationDstWidth - 1);
1841     }
1842   } else if ((IM_TOOL_EXIF_ORIENTATION_270_DEG_MIRROR == srcOrientation) ||
1843              (IM_TOOL_EXIF_ORIENTATION_270_DEG == srcOrientation)) {
1844     /* 270 Deg rotation */
1845     *rotationDstWidth = src.height_;
1846     *rotationDstHeight = src.width_;
1847     (*varM)[0][0] = 0;
1848     (*varM)[0][1] = 1;
1849     (*varM)[0][2] = 0;
1850     (*varM)[1][0] = -1;
1851     (*varM)[1][1] = 0;
1852     (*varM)[1][2] = static_cast<float>(*rotationDstHeight - 1);
1853     if (IM_TOOL_EXIF_ORIENTATION_270_DEG_MIRROR == srcOrientation) {
1854       /* with Mirror */
1855       (*varM)[0][1] *= -1;
1856       (*varM)[0][2] += static_cast<float>(*rotationDstWidth - 1);
1857     }
1858   }
1859 }
1860 
ImageToolsConvertImage(const LiteMat & src,const LiteMat & dst,imageToolsImage_t * imageIn,imageToolsImage_t * imageOut)1861 void ImageToolsConvertImage(const LiteMat &src, const LiteMat &dst, imageToolsImage_t *imageIn,
1862                             imageToolsImage_t *imageOut) {
1863   imageIn->image_buff = src.data_ptr_;
1864   imageIn->h = src.height_;
1865   imageIn->w = src.width_;
1866   imageIn->stride = src.width_;
1867   imageIn->dataType = IM_TOOL_DATA_TYPE_UINT8;
1868 
1869   imageOut->image_buff = dst.data_ptr_;
1870   imageOut->h = dst.height_;
1871   imageOut->w = dst.width_;
1872   imageOut->stride = dst.width_;
1873   imageOut->dataType = IM_TOOL_DATA_TYPE_FLOAT;
1874 }
1875 
InvAffine2x3(float M[2][3],float invM[][3])1876 int InvAffine2x3(float M[2][3], float invM[][3]) {
1877   float inv_det = M[0][0] * M[1][1] - M[1][0] * M[0][1];
1878   if (std::fabs(inv_det) <= std::numeric_limits<float>::epsilon()) {
1879     return IM_TOOL_RETURN_STATUS_FAILED;
1880   }
1881   invM[1][1] = M[0][0] / inv_det;
1882   invM[0][1] = -M[0][1] / inv_det;
1883   invM[1][0] = -M[1][0] / inv_det;
1884   invM[0][0] = M[1][1] / inv_det;
1885   invM[0][2] = (M[0][1] * M[1][2] - M[1][1] * M[0][2]) / inv_det;
1886   invM[1][2] = -(M[0][0] * M[1][2] - M[1][0] * M[0][2]) / inv_det;
1887   return IM_TOOL_RETURN_STATUS_SUCCESS;
1888 }
1889 
CalDst(float * dst,float v1,float v2,float v3)1890 static float *CalDst(float *dst, float v1, float v2, float v3) {
1891   *dst++ = v1;
1892   *dst++ = v2;
1893   *dst++ = v3;
1894   return dst;
1895 }
1896 
ImageWarpAffineHWCFloat(imageToolsImage_t image,imageToolsImage_t warped_image,float invM[2][3])1897 static void ImageWarpAffineHWCFloat(imageToolsImage_t image, imageToolsImage_t warped_image, float invM[2][3]) {
1898   // 3 is r, g, b
1899   warped_image.stride *= 3;
1900   image.stride *= 3;
1901 
1902   auto *warped_image_buff = reinterpret_cast<float *>(warped_image.image_buff);
1903 
1904   auto *image_buff = reinterpret_cast<float *>(image.image_buff);
1905   for (int y0 = 0; y0 < warped_image.h; y0++) {
1906     // Init pointers to start of rows
1907     float *dst = warped_image_buff + y0 * warped_image.stride;
1908 
1909     for (int x0 = 0; x0 < warped_image.w; x0++) {
1910       // number 0, 1, 2 is the index of MATRIX 'invM'
1911       float fPosx = (static_cast<float>(x0) * invM[0][0]) + (static_cast<float>(y0) * invM[0][1]) + invM[0][2];
1912       float fPosy = (static_cast<float>(x0) * invM[1][0]) + (static_cast<float>(y0) * invM[1][1]) + invM[1][2];
1913       int iPosy = static_cast<int>(fPosy + 2) - 2;  // for floor like result until -2.
1914       int iPosx = static_cast<int>(fPosx + 2) - 2;  // for floor like result until -2.
1915       if ((iPosx < -1) || (iPosx >= image.w) || (iPosy < -1) || (iPosy >= image.h)) {
1916         dst = CalDst(dst, 0.0f, 0.0f, 0.0f);
1917         continue;
1918       }
1919       float fRsiduy = fPosy - static_cast<float>(iPosy);
1920       float fRsidux = fPosx - static_cast<float>(iPosx);
1921       float fOut0 = 0;
1922       float fOut1 = 0;
1923       float fOut2 = 0;
1924       float *fTopeLeft = image_buff + iPosy * image.stride + iPosx * 3;
1925       float fCoeff = 1 - fRsidux - fRsiduy + fRsidux * fRsiduy;
1926       if ((iPosx >= 0) && (iPosy >= 0)) {
1927         // number 0, 1, 2 is the index of MATRIX 'fTopeLeft'
1928         fOut0 += fCoeff * fTopeLeft[0];
1929         fOut1 += fCoeff * fTopeLeft[1];
1930         fOut2 += fCoeff * fTopeLeft[2];
1931       }
1932       float fSum = fCoeff;
1933       fCoeff = fRsiduy - fRsidux * fRsiduy;
1934       if ((iPosx >= 0) && (iPosy < image.h - 1)) {
1935         // Image channel G and B could be accessed by adding number of 1, 2
1936         fOut0 += fCoeff * fTopeLeft[image.stride];
1937         fOut1 += fCoeff * fTopeLeft[image.stride + 1];
1938         fOut2 += fCoeff * fTopeLeft[image.stride + 2];
1939       }
1940       fSum += fCoeff;
1941       fCoeff = fRsidux - fRsidux * fRsiduy;
1942       if ((iPosx < image.w - 1) && (iPosy >= 0)) {
1943         // Image channel G and B could be accessed by adding number of 1, 2
1944         fOut0 += fCoeff * fTopeLeft[3];
1945         fOut1 += fCoeff * fTopeLeft[3 + 1];
1946         fOut2 += fCoeff * fTopeLeft[3 + 2];
1947       }
1948       fSum += fCoeff;
1949       if ((iPosx < image.w - 1) && (iPosy < image.h - 1)) {
1950         // Image channel G and B could be accessed by adding number of 1, 2
1951         fOut0 += (1 - fSum) * fTopeLeft[image.stride + 3];
1952         fOut1 += (1 - fSum) * fTopeLeft[image.stride + 3 + 1];
1953         fOut2 += (1 - fSum) * fTopeLeft[image.stride + 3 + 2];
1954       }
1955       dst = CalDst(dst, fOut0, fOut1, fOut2);
1956     }
1957   }
1958 }
1959 
ImageWarpAffineHWCUint8(imageToolsImage_t image,imageToolsImage_t warped_image,float invM[2][3])1960 static void ImageWarpAffineHWCUint8(imageToolsImage_t image, imageToolsImage_t warped_image, float invM[2][3]) {
1961   // 3 is r, g, b
1962   warped_image.stride *= 3;
1963   image.stride *= 3;
1964   auto *warped_image_buff = reinterpret_cast<float *>(warped_image.image_buff);
1965 
1966   auto *image_buff = reinterpret_cast<uint8_t *>(image.image_buff);
1967   for (int y0 = 0; y0 < warped_image.h; y0++) {
1968     // Init pointers to start of rows
1969     float *dst = warped_image_buff + y0 * warped_image.stride;
1970 
1971     for (int x0 = 0; x0 < warped_image.w; x0++) {
1972       float fPosx = (static_cast<float>(x0) * invM[0][0]) + (static_cast<float>(y0) * invM[0][1]) + invM[0][2];
1973       float fPosy = (static_cast<float>(x0) * invM[1][0]) + (static_cast<float>(y0) * invM[1][1]) + invM[1][2];
1974 
1975       int iPosy = static_cast<int>(fPosy + 2) - 2;  // for floor like result until -2.
1976       int iPosx = static_cast<int>(fPosx + 2) - 2;  // for floor like result until -2.
1977       if ((iPosx < -1) || (iPosx >= image.w) || (iPosy < -1) || (iPosy >= image.h)) {
1978         dst = CalDst(dst, 0.0f, 0.0f, 0.0f);
1979         continue;
1980       }
1981       float fRsiduy = fPosy - static_cast<float>(iPosy);
1982       float fRsidux = fPosx - static_cast<float>(iPosx);
1983       float fOut0 = 0;
1984       float fOut1 = 0;
1985       float fOut2 = 0;
1986       uint8_t *uiTopeLeft = image_buff + iPosy * image.stride + iPosx * 3;
1987       float fCoeff = 1 - fRsidux - fRsiduy + fRsidux * fRsiduy;
1988       if ((iPosx >= 0) && (iPosy >= 0)) {
1989         // number 0, 1, 2 is the index of MATRIX round.
1990         fOut0 += fCoeff * static_cast<float>(uiTopeLeft[0]);
1991         fOut1 += fCoeff * static_cast<float>(uiTopeLeft[1]);
1992         fOut2 += fCoeff * static_cast<float>(uiTopeLeft[2]);
1993       }
1994       float fSum = fCoeff;
1995       fCoeff = fRsiduy - fRsidux * fRsiduy;
1996       if ((iPosx >= 0) && (iPosy < image.h - 1)) {
1997         fOut0 += fCoeff * static_cast<float>(uiTopeLeft[image.stride]);
1998         fOut1 += fCoeff * static_cast<float>(uiTopeLeft[image.stride + 1]);
1999         fOut2 += fCoeff * static_cast<float>(uiTopeLeft[image.stride + 2]);
2000       }
2001       fSum += fCoeff;
2002       fCoeff = fRsidux - fRsidux * fRsiduy;
2003       if ((iPosx < image.w - 1) && (iPosy >= 0)) {
2004         fOut0 += fCoeff * static_cast<float>(uiTopeLeft[3]);
2005         fOut1 += fCoeff * static_cast<float>(uiTopeLeft[3 + 1]);
2006         fOut2 += fCoeff * static_cast<float>(uiTopeLeft[3 + 2]);
2007       }
2008       fSum += fCoeff;
2009       if ((iPosx < image.w - 1) && (iPosy < image.h - 1)) {
2010         fOut0 += (1 - fSum) * static_cast<float>(uiTopeLeft[image.stride + 3]);
2011         fOut1 += (1 - fSum) * static_cast<float>(uiTopeLeft[image.stride + 3 + 1]);
2012         fOut2 += (1 - fSum) * static_cast<float>(uiTopeLeft[image.stride + 3 + 2]);
2013       }
2014       dst = CalDst(dst, fOut0, fOut1, fOut2);
2015     }
2016   }
2017 }
2018 
ImageWarpAffineHWC(imageToolsImage_t image,imageToolsImage_t warped_image,float M[2][3],bool bIsMInv)2019 int ImageWarpAffineHWC(imageToolsImage_t image, imageToolsImage_t warped_image, float M[2][3], bool bIsMInv) {
2020   if ((IM_TOOL_DATA_TYPE_FLOAT != warped_image.dataType) ||
2021       ((IM_TOOL_DATA_TYPE_FLOAT != image.dataType) && (IM_TOOL_DATA_TYPE_UINT8 != image.dataType))) {
2022     return IM_TOOL_RETURN_STATUS_INVALID_INPUT;
2023   }
2024   float invM[2][3];
2025   if (bIsMInv) {
2026     for (int iy = 0; iy < 2; iy++) {
2027       for (int ix = 0; ix < 3; ix++) {
2028         invM[iy][ix] = M[iy][ix];
2029       }
2030     }
2031   } else {
2032     if (InvAffine2x3(M, invM) != IM_TOOL_RETURN_STATUS_SUCCESS) {
2033       return IM_TOOL_RETURN_STATUS_FAILED;
2034     }
2035   }
2036 
2037   if (IM_TOOL_DATA_TYPE_FLOAT == image.dataType) {
2038     ImageWarpAffineHWCFloat(image, warped_image, invM);
2039   } else {
2040     ImageWarpAffineHWCUint8(image, warped_image, invM);
2041   }
2042   return IM_TOOL_RETURN_STATUS_SUCCESS;
2043 }
2044 
ResizePreserveARWithFiller(LiteMat & src,LiteMat & dst,int h,int w,float (* ratioShiftWShiftH)[3],float (* invM)[2][3],int img_orientation)2045 bool ResizePreserveARWithFiller(LiteMat &src, LiteMat &dst, int h, int w, float (*ratioShiftWShiftH)[3],
2046                                 float (*invM)[2][3], int img_orientation) {
2047   if (src.IsEmpty() || src.channel_ != 3 || h <= 0 || w <= 0 || h > 10000 || w > 10000) {
2048     return false;
2049   }
2050   if (ratioShiftWShiftH == nullptr || invM == nullptr) {
2051     return false;
2052   }
2053   if (dst.IsEmpty()) {
2054     dst.Init(w, h, src.channel_, LDataType::FLOAT32);
2055     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
2056   }
2057 
2058   float varM[2][3] = {{1.0, 0, 0}, {0, 1.0, 0}};
2059   const float divisor = 2.0;
2060   int rotationDstWidth = src.width_;
2061   int rotationDstHeight = src.height_;
2062   if (rotationDstWidth == 0 || rotationDstHeight == 0) {
2063     return false;
2064   }
2065 
2066   if (dst.height_ == 0) {
2067     return false;
2068   }
2069 
2070   if (img_orientation > IM_TOOL_EXIF_ORIENTATION_0_DEG) {
2071     UpdateOrientationAfineMat(src, &rotationDstWidth, &rotationDstHeight, &varM, img_orientation);
2072   }
2073 
2074   /* Resize after orientation fix */
2075   float srcAR = static_cast<float>(rotationDstWidth) / static_cast<float>(rotationDstHeight);
2076   float dstAR = static_cast<float>(dst.width_) / static_cast<float>(dst.height_);
2077   auto dstActiveWidth = static_cast<float>(dst.width_);
2078   auto dstActiveHeight = static_cast<float>(dst.height_);
2079   float ratio, shiftW, shiftH;
2080   if (srcAR < dstAR) {
2081     ratio = static_cast<float>(dst.height_) / static_cast<float>(rotationDstHeight);
2082     dstActiveWidth = static_cast<float>(rotationDstWidth) * ratio;
2083   } else {
2084     ratio = static_cast<float>(dst.width_) / static_cast<float>(rotationDstWidth);
2085     dstActiveHeight = static_cast<float>(rotationDstHeight) * ratio;
2086   }
2087   shiftW = (static_cast<float>(dst.width_) - dstActiveWidth) / divisor;
2088   shiftH = (static_cast<float>(dst.height_) - dstActiveHeight) / divisor;
2089   for (auto &iy : varM) {
2090     for (float &ix : iy) {
2091       // cppcheck-suppress useStlAlgorithm
2092       ix *= ratio;
2093     }
2094   }
2095 
2096   varM[0][2] += shiftW;
2097   varM[1][2] += shiftH;
2098   /* Resize and shift by affine transform  */
2099   imageToolsImage_t imageIn, imageOut;
2100   ImageToolsConvertImage(src, dst, &imageIn, &imageOut);
2101   if (InvAffine2x3(varM, *invM) != IM_TOOL_RETURN_STATUS_SUCCESS) {
2102     return false;
2103   }
2104   int retVal = ImageWarpAffineHWC(imageIn, imageOut, *invM, true);
2105   if (retVal != 0) {
2106     return false;
2107   }
2108 
2109   // 0, 1, 2 is the index of corresponding elem in ratioShiftWShiftH
2110   (*ratioShiftWShiftH)[0] = ratio;
2111   (*ratioShiftWShiftH)[1] = shiftW;
2112   (*ratioShiftWShiftH)[2] = shiftH;
2113 
2114   return true;
2115 }
2116 
2117 template <typename T>
HWC2CHWImpl(const T * src_ptr,T * dst_ptr,int height,int width,int channel)2118 void HWC2CHWImpl(const T *src_ptr, T *dst_ptr, int height, int width, int channel) {
2119   int stride = width * height;
2120   for (int i = 0; i != stride; ++i) {
2121     for (int c = 0; c != channel; ++c) {
2122       dst_ptr[c * stride + i] = src_ptr[i * channel + c];
2123     }
2124   }
2125 }
2126 
HWC2CHW(LiteMat & src,LiteMat & dst)2127 bool HWC2CHW(LiteMat &src, LiteMat &dst) {
2128   if (src.IsEmpty()) {
2129     return false;
2130   }
2131   if (dst.IsEmpty() || dst.width_ != src.height_ || dst.height_ != src.channel_ || dst.channel_ != src.width_ ||
2132       dst.data_type_ != src.data_type_) {
2133     dst.Init(src.height_, src.channel_, src.width_, src.data_type_);
2134     RETURN_FALSE_IF_LITEMAT_EMPTY(dst);
2135   }
2136   if (src.data_type_ == LDataType::FLOAT32) {
2137     HWC2CHWImpl<float>(src, dst, src.height_, src.width_, src.channel_);
2138   } else if (src.data_type_ == LDataType::UINT8) {
2139     HWC2CHWImpl<uint8_t>(src, dst, src.height_, src.width_, src.channel_);
2140   } else if (src.data_type_ == LDataType::INT16) {
2141     HWC2CHWImpl<int16_t>(src, dst, src.height_, src.width_, src.channel_);
2142   } else if (src.data_type_ == LDataType::INT32) {
2143     HWC2CHWImpl<int32_t>(src, dst, src.height_, src.width_, src.channel_);
2144   } else if (src.data_type_ == LDataType::INT64) {
2145     HWC2CHWImpl<int64_t>(src, dst, src.height_, src.width_, src.channel_);
2146   } else if (src.data_type_ == LDataType::UINT16) {
2147     HWC2CHWImpl<uint16_t>(src, dst, src.height_, src.width_, src.channel_);
2148   } else if (src.data_type_ == LDataType::UINT32) {
2149     HWC2CHWImpl<uint32_t>(src, dst, src.height_, src.width_, src.channel_);
2150   } else if (src.data_type_ == LDataType::UINT64) {
2151     HWC2CHWImpl<uint64_t>(src, dst, src.height_, src.width_, src.channel_);
2152   } else if (src.data_type_ == LDataType::DOUBLE) {
2153     HWC2CHWImpl<double>(src, dst, src.height_, src.width_, src.channel_);
2154   } else {
2155     return false;
2156   }
2157   return true;
2158 }
2159 }  // namespace dataset
2160 }  // namespace mindspore
2161