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