You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mat_pixel_affine.cpp 15 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "mat.h"
  15. #if __ARM_NEON
  16. #include <arm_neon.h>
  17. #endif // __ARM_NEON
  18. #include <math.h>
  19. #include "platform.h"
  20. namespace ncnn {
  21. #if NCNN_PIXEL_AFFINE
  22. void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm)
  23. {
  24. angle *= (float)(3.14159265358979323846 / 180);
  25. float alpha = cos(angle) * scale;
  26. float beta = sin(angle) * scale;
  27. tm[0] = alpha;
  28. tm[1] = beta;
  29. tm[2] = (1.f - alpha) * dx - beta * dy;
  30. tm[3] = -beta;
  31. tm[4] = alpha;
  32. tm[5] = beta * dx + (1.f - alpha) * dy;
  33. }
  34. void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm)
  35. {
  36. float ma[4][4] = {{0.f}};
  37. float mb[4] = {0.f};
  38. float mm[4];
  39. for (int i = 0; i < num_point; i++)
  40. {
  41. ma[0][0] += points_from[0] * points_from[0] + points_from[1] * points_from[1];
  42. ma[0][2] += points_from[0];
  43. ma[0][3] += points_from[1];
  44. mb[0] += points_from[0] * points_to[0] + points_from[1] * points_to[1];
  45. mb[1] += points_from[0] * points_to[1] - points_from[1] * points_to[0];
  46. mb[2] += points_to[0];
  47. mb[3] += points_to[1];
  48. points_from += 2;
  49. points_to += 2;
  50. }
  51. ma[1][1] = ma[0][0];
  52. ma[2][1] = ma[1][2] = -ma[0][3];
  53. ma[3][1] = ma[1][3] = ma[2][0] = ma[0][2];
  54. ma[2][2] = ma[3][3] = (float)num_point;
  55. ma[3][0] = ma[0][3];
  56. // MM = inv(A) * B
  57. // matrix 4x4 invert by https://github.com/willnode/N-Matrix-Programmer
  58. // suppose the user provide valid points combination
  59. // I have not taken det == zero into account here :> --- nihui
  60. float mai[4][4];
  61. float det;
  62. // clang-format off
  63. // *INDENT-OFF*
  64. {
  65. float A2323 = ma[2][2] * ma[3][3] - ma[2][3] * ma[3][2];
  66. float A1323 = ma[2][1] * ma[3][3] - ma[2][3] * ma[3][1];
  67. float A1223 = ma[2][1] * ma[3][2] - ma[2][2] * ma[3][1];
  68. float A0323 = ma[2][0] * ma[3][3] - ma[2][3] * ma[3][0];
  69. float A0223 = ma[2][0] * ma[3][2] - ma[2][2] * ma[3][0];
  70. float A0123 = ma[2][0] * ma[3][1] - ma[2][1] * ma[3][0];
  71. float A2313 = ma[1][2] * ma[3][3] - ma[1][3] * ma[3][2];
  72. float A1313 = ma[1][1] * ma[3][3] - ma[1][3] * ma[3][1];
  73. float A1213 = ma[1][1] * ma[3][2] - ma[1][2] * ma[3][1];
  74. float A2312 = ma[1][2] * ma[2][3] - ma[1][3] * ma[2][2];
  75. float A1312 = ma[1][1] * ma[2][3] - ma[1][3] * ma[2][1];
  76. float A1212 = ma[1][1] * ma[2][2] - ma[1][2] * ma[2][1];
  77. float A0313 = ma[1][0] * ma[3][3] - ma[1][3] * ma[3][0];
  78. float A0213 = ma[1][0] * ma[3][2] - ma[1][2] * ma[3][0];
  79. float A0312 = ma[1][0] * ma[2][3] - ma[1][3] * ma[2][0];
  80. float A0212 = ma[1][0] * ma[2][2] - ma[1][2] * ma[2][0];
  81. float A0113 = ma[1][0] * ma[3][1] - ma[1][1] * ma[3][0];
  82. float A0112 = ma[1][0] * ma[2][1] - ma[1][1] * ma[2][0];
  83. det = ma[0][0] * (ma[1][1] * A2323 - ma[1][2] * A1323 + ma[1][3] * A1223)
  84. - ma[0][1] * (ma[1][0] * A2323 - ma[1][2] * A0323 + ma[1][3] * A0223)
  85. + ma[0][2] * (ma[1][0] * A1323 - ma[1][1] * A0323 + ma[1][3] * A0123)
  86. - ma[0][3] * (ma[1][0] * A1223 - ma[1][1] * A0223 + ma[1][2] * A0123);
  87. det = 1.f / det;
  88. mai[0][0] = (ma[1][1] * A2323 - ma[1][2] * A1323 + ma[1][3] * A1223);
  89. mai[0][1] = - (ma[0][1] * A2323 - ma[0][2] * A1323 + ma[0][3] * A1223);
  90. mai[0][2] = (ma[0][1] * A2313 - ma[0][2] * A1313 + ma[0][3] * A1213);
  91. mai[0][3] = - (ma[0][1] * A2312 - ma[0][2] * A1312 + ma[0][3] * A1212);
  92. mai[1][0] = - (ma[1][0] * A2323 - ma[1][2] * A0323 + ma[1][3] * A0223);
  93. mai[1][1] = (ma[0][0] * A2323 - ma[0][2] * A0323 + ma[0][3] * A0223);
  94. mai[1][2] = - (ma[0][0] * A2313 - ma[0][2] * A0313 + ma[0][3] * A0213);
  95. mai[1][3] = (ma[0][0] * A2312 - ma[0][2] * A0312 + ma[0][3] * A0212);
  96. mai[2][0] = (ma[1][0] * A1323 - ma[1][1] * A0323 + ma[1][3] * A0123);
  97. mai[2][1] = - (ma[0][0] * A1323 - ma[0][1] * A0323 + ma[0][3] * A0123);
  98. mai[2][2] = (ma[0][0] * A1313 - ma[0][1] * A0313 + ma[0][3] * A0113);
  99. mai[2][3] = - (ma[0][0] * A1312 - ma[0][1] * A0312 + ma[0][3] * A0112);
  100. mai[3][0] = - (ma[1][0] * A1223 - ma[1][1] * A0223 + ma[1][2] * A0123);
  101. mai[3][1] = (ma[0][0] * A1223 - ma[0][1] * A0223 + ma[0][2] * A0123);
  102. mai[3][2] = - (ma[0][0] * A1213 - ma[0][1] * A0213 + ma[0][2] * A0113);
  103. mai[3][3] = (ma[0][0] * A1212 - ma[0][1] * A0212 + ma[0][2] * A0112);
  104. }
  105. // *INDENT-ON*
  106. // clang-format on
  107. mm[0] = det * (mai[0][0] * mb[0] + mai[0][1] * mb[1] + mai[0][2] * mb[2] + mai[0][3] * mb[3]);
  108. mm[1] = det * (mai[1][0] * mb[0] + mai[1][1] * mb[1] + mai[1][2] * mb[2] + mai[1][3] * mb[3]);
  109. mm[2] = det * (mai[2][0] * mb[0] + mai[2][1] * mb[1] + mai[2][2] * mb[2] + mai[2][3] * mb[3]);
  110. mm[3] = det * (mai[3][0] * mb[0] + mai[3][1] * mb[1] + mai[3][2] * mb[2] + mai[3][3] * mb[3]);
  111. tm[0] = tm[4] = mm[0];
  112. tm[1] = -mm[1];
  113. tm[3] = mm[1];
  114. tm[2] = mm[2];
  115. tm[5] = mm[3];
  116. }
  117. void invert_affine_transform(const float* tm, float* tm_inv)
  118. {
  119. float D = tm[0] * tm[4] - tm[1] * tm[3];
  120. D = D != 0.f ? 1.f / D : 0.f;
  121. float A11 = tm[4] * D;
  122. float A22 = tm[0] * D;
  123. float A12 = -tm[1] * D;
  124. float A21 = -tm[3] * D;
  125. float b1 = -A11 * tm[2] - A12 * tm[5];
  126. float b2 = -A21 * tm[2] - A22 * tm[5];
  127. tm_inv[0] = A11;
  128. tm_inv[1] = A12;
  129. tm_inv[2] = b1;
  130. tm_inv[3] = A21;
  131. tm_inv[4] = A22;
  132. tm_inv[5] = b2;
  133. }
  134. void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int v)
  135. {
  136. return warpaffine_bilinear_c1(src, srcw, srch, srcw, dst, w, h, w, tm, v);
  137. }
  138. void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int v)
  139. {
  140. return warpaffine_bilinear_c2(src, srcw, srch, srcw * 2, dst, w, h, w * 2, tm, v);
  141. }
  142. void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int v)
  143. {
  144. return warpaffine_bilinear_c3(src, srcw, srch, srcw * 3, dst, w, h, w * 3, tm, v);
  145. }
  146. void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int v)
  147. {
  148. return warpaffine_bilinear_c4(src, srcw, srch, srcw * 4, dst, w, h, w * 4, tm, v);
  149. }
  150. void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int v)
  151. {
  152. const unsigned char border_color = (unsigned char)v;
  153. const int wgap = stride - w;
  154. const unsigned char* src0 = src;
  155. unsigned char* dst0 = dst;
  156. int y = 0;
  157. for (; y < h; y++)
  158. {
  159. int x = 0;
  160. for (; x < w; x++)
  161. {
  162. float fx = tm[0] * x + tm[1] * y + tm[2];
  163. float fy = tm[3] * x + tm[4] * y + tm[5];
  164. if (fx < 0 || fx >= srcw - 1 || fy < 0 || fy >= srch - 1)
  165. {
  166. if (v != -233)
  167. {
  168. *dst0 = border_color;
  169. }
  170. }
  171. else
  172. {
  173. // interp at fx fy
  174. int sx = static_cast<int>(floor(fx));
  175. fx -= sx;
  176. int sy = static_cast<int>(floor(fy));
  177. fy -= sy;
  178. const unsigned char* a0 = src0 + srcstride * sy + sx;
  179. const unsigned char* a1 = src0 + srcstride * sy + sx + 1;
  180. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx;
  181. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx + 1;
  182. *dst0 = (unsigned char)((*a0 * (1.f - fx) + *a1 * fx) * (1.f - fy) + (*b0 * (1.f - fx) + *b1 * fx) * fy);
  183. }
  184. dst0 += 1;
  185. }
  186. dst0 += wgap;
  187. }
  188. }
  189. void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int v)
  190. {
  191. const unsigned char border_color = (unsigned char)v;
  192. const int wgap = stride - w * 2;
  193. const unsigned char* src0 = src;
  194. unsigned char* dst0 = dst;
  195. int y = 0;
  196. for (; y < h; y++)
  197. {
  198. int x = 0;
  199. for (; x < w; x++)
  200. {
  201. float fx = tm[0] * x + tm[1] * y + tm[2];
  202. float fy = tm[3] * x + tm[4] * y + tm[5];
  203. if (fx < 0 || fx >= srcw - 1 || fy < 0 || fy >= srch - 1)
  204. {
  205. if (v != -233)
  206. {
  207. dst0[0] = border_color;
  208. dst0[1] = border_color;
  209. }
  210. }
  211. else
  212. {
  213. // interp at fx fy
  214. int sx = static_cast<int>(floor(fx));
  215. fx -= sx;
  216. int sy = static_cast<int>(floor(fy));
  217. fy -= sy;
  218. const unsigned char* a0 = src0 + srcstride * sy + sx * 2;
  219. const unsigned char* a1 = src0 + srcstride * sy + sx * 2 + 2;
  220. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 2;
  221. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 2 + 2;
  222. dst0[0] = (unsigned char)((a0[0] * (1.f - fx) + a1[0] * fx) * (1.f - fy) + (b0[0] * (1.f - fx) + b1[0] * fx) * fy);
  223. dst0[1] = (unsigned char)((a0[1] * (1.f - fx) + a1[1] * fx) * (1.f - fy) + (b0[1] * (1.f - fx) + b1[1] * fx) * fy);
  224. }
  225. dst0 += 2;
  226. }
  227. dst0 += wgap;
  228. }
  229. }
  230. void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int v)
  231. {
  232. const unsigned char border_color = (unsigned char)v;
  233. const int wgap = stride - w * 3;
  234. const unsigned char* src0 = src;
  235. unsigned char* dst0 = dst;
  236. int y = 0;
  237. for (; y < h; y++)
  238. {
  239. int x = 0;
  240. for (; x < w; x++)
  241. {
  242. float fx = tm[0] * x + tm[1] * y + tm[2];
  243. float fy = tm[3] * x + tm[4] * y + tm[5];
  244. if (fx < 0 || fx >= srcw - 1 || fy < 0 || fy >= srch - 1)
  245. {
  246. if (v != -233)
  247. {
  248. dst0[0] = border_color;
  249. dst0[1] = border_color;
  250. dst0[2] = border_color;
  251. }
  252. }
  253. else
  254. {
  255. // interp at fx fy
  256. int sx = static_cast<int>(floor(fx));
  257. fx -= sx;
  258. int sy = static_cast<int>(floor(fy));
  259. fy -= sy;
  260. const unsigned char* a0 = src0 + srcstride * sy + sx * 3;
  261. const unsigned char* a1 = src0 + srcstride * sy + sx * 3 + 3;
  262. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 3;
  263. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 3 + 3;
  264. dst0[0] = (unsigned char)((a0[0] * (1.f - fx) + a1[0] * fx) * (1.f - fy) + (b0[0] * (1.f - fx) + b1[0] * fx) * fy);
  265. dst0[1] = (unsigned char)((a0[1] * (1.f - fx) + a1[1] * fx) * (1.f - fy) + (b0[1] * (1.f - fx) + b1[1] * fx) * fy);
  266. dst0[2] = (unsigned char)((a0[2] * (1.f - fx) + a1[2] * fx) * (1.f - fy) + (b0[2] * (1.f - fx) + b1[2] * fx) * fy);
  267. }
  268. dst0 += 3;
  269. }
  270. dst0 += wgap;
  271. }
  272. }
  273. void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int v)
  274. {
  275. const unsigned char border_color = (unsigned char)v;
  276. const int wgap = stride - w * 4;
  277. const unsigned char* src0 = src;
  278. unsigned char* dst0 = dst;
  279. int y = 0;
  280. for (; y < h; y++)
  281. {
  282. int x = 0;
  283. for (; x < w; x++)
  284. {
  285. float fx = tm[0] * x + tm[1] * y + tm[2];
  286. float fy = tm[3] * x + tm[4] * y + tm[5];
  287. if (fx < 0 || fx >= srcw - 1 || fy < 0 || fy >= srch - 1)
  288. {
  289. if (v != -233)
  290. {
  291. dst0[0] = border_color;
  292. dst0[1] = border_color;
  293. dst0[2] = border_color;
  294. dst0[3] = border_color;
  295. }
  296. }
  297. else
  298. {
  299. // interp at fx fy
  300. int sx = static_cast<int>(floor(fx));
  301. fx -= sx;
  302. int sy = static_cast<int>(floor(fy));
  303. fy -= sy;
  304. const unsigned char* a0 = src0 + srcstride * sy + sx * 4;
  305. const unsigned char* a1 = src0 + srcstride * sy + sx * 4 + 4;
  306. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 4;
  307. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 4 + 4;
  308. dst0[0] = (unsigned char)((a0[0] * (1.f - fx) + a1[0] * fx) * (1.f - fy) + (b0[0] * (1.f - fx) + b1[0] * fx) * fy);
  309. dst0[1] = (unsigned char)((a0[1] * (1.f - fx) + a1[1] * fx) * (1.f - fy) + (b0[1] * (1.f - fx) + b1[1] * fx) * fy);
  310. dst0[2] = (unsigned char)((a0[2] * (1.f - fx) + a1[2] * fx) * (1.f - fy) + (b0[2] * (1.f - fx) + b1[2] * fx) * fy);
  311. dst0[3] = (unsigned char)((a0[3] * (1.f - fx) + a1[3] * fx) * (1.f - fy) + (b0[3] * (1.f - fx) + b1[3] * fx) * fy);
  312. }
  313. dst0 += 4;
  314. }
  315. dst0 += wgap;
  316. }
  317. }
  318. void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int v)
  319. {
  320. // assert srcw % 2 == 0
  321. // assert srch % 2 == 0
  322. // assert w % 2 == 0
  323. // assert h % 2 == 0
  324. const unsigned char* srcY = src;
  325. unsigned char* dstY = dst;
  326. warpaffine_bilinear_c1(srcY, srcw, srch, dstY, w, h, tm, v);
  327. const unsigned char* srcUV = src + srcw * srch;
  328. unsigned char* dstUV = dst + w * h;
  329. warpaffine_bilinear_c2(srcUV, srcw / 2, srch / 2, dstUV, w / 2, h / 2, tm, v);
  330. }
  331. #endif // NCNN_PIXEL_AFFINE
  332. } // namespace ncnn