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.cpp 55 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2017 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. #include <limits.h>
  16. #include <math.h>
  17. #include <algorithm>
  18. #if __ARM_NEON
  19. #include <arm_neon.h>
  20. #endif // __ARM_NEON
  21. #include "platform.h"
  22. namespace ncnn {
  23. #if NCNN_PIXEL
  24. static int from_rgb(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  25. {
  26. m.create(w, h, 3, 4u, allocator);
  27. if (m.empty())
  28. return -100;
  29. const int wgap = stride - w * 3;
  30. if (wgap == 0)
  31. {
  32. w = w * h;
  33. h = 1;
  34. }
  35. float* ptr0 = m.channel(0);
  36. float* ptr1 = m.channel(1);
  37. float* ptr2 = m.channel(2);
  38. for (int y=0; y<h; y++)
  39. {
  40. #if __ARM_NEON
  41. int nn = w >> 3;
  42. int remain = w - (nn << 3);
  43. #else
  44. int remain = w;
  45. #endif // __ARM_NEON
  46. #if __ARM_NEON
  47. #if __aarch64__
  48. for (; nn>0; nn--)
  49. {
  50. uint8x8x3_t _rgb = vld3_u8(rgb);
  51. uint16x8_t _r16 = vmovl_u8(_rgb.val[0]);
  52. uint16x8_t _g16 = vmovl_u8(_rgb.val[1]);
  53. uint16x8_t _b16 = vmovl_u8(_rgb.val[2]);
  54. float32x4_t _rlow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_r16)));
  55. float32x4_t _rhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_r16)));
  56. float32x4_t _glow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_g16)));
  57. float32x4_t _ghigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_g16)));
  58. float32x4_t _blow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_b16)));
  59. float32x4_t _bhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_b16)));
  60. vst1q_f32(ptr0, _rlow);
  61. vst1q_f32(ptr0+4, _rhigh);
  62. vst1q_f32(ptr1, _glow);
  63. vst1q_f32(ptr1+4, _ghigh);
  64. vst1q_f32(ptr2, _blow);
  65. vst1q_f32(ptr2+4, _bhigh);
  66. rgb += 3*8;
  67. ptr0 += 8;
  68. ptr1 += 8;
  69. ptr2 += 8;
  70. }
  71. #else
  72. if (nn > 0)
  73. {
  74. asm volatile(
  75. "0: \n"
  76. "pld [%1, #256] \n"
  77. "vld3.u8 {d0-d2}, [%1]! \n"
  78. "vmovl.u8 q8, d0 \n"
  79. "vmovl.u8 q9, d1 \n"
  80. "vmovl.u8 q10, d2 \n"
  81. "vmovl.u16 q0, d16 \n"
  82. "vmovl.u16 q1, d17 \n"
  83. "vmovl.u16 q2, d18 \n"
  84. "vmovl.u16 q3, d19 \n"
  85. "vmovl.u16 q8, d20 \n"
  86. "vmovl.u16 q9, d21 \n"
  87. "vcvt.f32.u32 q0, q0 \n"
  88. "vcvt.f32.u32 q1, q1 \n"
  89. "vcvt.f32.u32 q2, q2 \n"
  90. "vcvt.f32.u32 q3, q3 \n"
  91. "vcvt.f32.u32 q8, q8 \n"
  92. "subs %0, #1 \n"
  93. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  94. "vcvt.f32.u32 q9, q9 \n"
  95. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  96. "vst1.f32 {d16-d19}, [%4 :128]!\n"
  97. "bne 0b \n"
  98. : "=r"(nn), // %0
  99. "=r"(rgb), // %1
  100. "=r"(ptr0), // %2
  101. "=r"(ptr1), // %3
  102. "=r"(ptr2) // %4
  103. : "0"(nn),
  104. "1"(rgb),
  105. "2"(ptr0),
  106. "3"(ptr1),
  107. "4"(ptr2)
  108. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
  109. );
  110. }
  111. #endif // __aarch64__
  112. #endif // __ARM_NEON
  113. for (; remain>0; remain--)
  114. {
  115. *ptr0 = rgb[0];
  116. *ptr1 = rgb[1];
  117. *ptr2 = rgb[2];
  118. rgb += 3;
  119. ptr0++;
  120. ptr1++;
  121. ptr2++;
  122. }
  123. rgb += wgap;
  124. }
  125. return 0;
  126. }
  127. static void to_rgb(const Mat& m, unsigned char* rgb, int stride)
  128. {
  129. int w = m.w;
  130. int h = m.h;
  131. const int wgap = stride - w * 3;
  132. if (wgap == 0)
  133. {
  134. w = w * h;
  135. h = 1;
  136. }
  137. const float* ptr0 = m.channel(0);
  138. const float* ptr1 = m.channel(1);
  139. const float* ptr2 = m.channel(2);
  140. for (int y=0; y<h; y++)
  141. {
  142. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  143. int remain = w;
  144. for (; remain>0; remain--)
  145. {
  146. rgb[0] = SATURATE_CAST_UCHAR(*ptr0);
  147. rgb[1] = SATURATE_CAST_UCHAR(*ptr1);
  148. rgb[2] = SATURATE_CAST_UCHAR(*ptr2);
  149. rgb += 3;
  150. ptr0++;
  151. ptr1++;
  152. ptr2++;
  153. }
  154. #undef SATURATE_CAST_UCHAR
  155. rgb += wgap;
  156. }
  157. }
  158. static int from_gray(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  159. {
  160. m.create(w, h, 1, 4u, allocator);
  161. if (m.empty())
  162. return -100;
  163. const int wgap = stride - w;
  164. if (wgap == 0)
  165. {
  166. w = w * h;
  167. h = 1;
  168. }
  169. float* ptr = m;
  170. for (int y=0; y<h; y++)
  171. {
  172. #if __ARM_NEON
  173. int nn = w >> 4;
  174. int remain = w - (nn << 4);
  175. #else
  176. int remain = w;
  177. #endif // __ARM_NEON
  178. #if __ARM_NEON
  179. #if __aarch64__
  180. for (; nn>0; nn--)
  181. {
  182. uint8x16_t _gray = vld1q_u8(gray);
  183. uint16x8_t _gray16_0 = vmovl_u8(vget_low_u8(_gray));
  184. uint16x8_t _gray16_1 = vmovl_u8(vget_high_u8(_gray));
  185. float32x4_t _graylow_0 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_0)));
  186. float32x4_t _grayhigh_0 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_0)));
  187. float32x4_t _graylow_1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_1)));
  188. float32x4_t _grayhigh_1 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_1)));
  189. vst1q_f32(ptr, _graylow_0);
  190. vst1q_f32(ptr+4, _grayhigh_0);
  191. vst1q_f32(ptr+8, _graylow_1);
  192. vst1q_f32(ptr+12, _grayhigh_1);
  193. gray += 16;
  194. ptr += 16;
  195. }
  196. #else
  197. if (nn > 0)
  198. {
  199. asm volatile(
  200. "0: \n"
  201. "pld [%1, #128] \n"
  202. "vld1.u8 {d0,d1}, [%1]! \n"
  203. "vmovl.u8 q8, d0 \n"
  204. "vmovl.u8 q9, d1 \n"
  205. "vmovl.u16 q0, d16 \n"
  206. "vmovl.u16 q1, d17 \n"
  207. "vmovl.u16 q2, d18 \n"
  208. "vmovl.u16 q3, d19 \n"
  209. "vcvt.f32.u32 q0, q0 \n"
  210. "vcvt.f32.u32 q1, q1 \n"
  211. "vcvt.f32.u32 q2, q2 \n"
  212. "vcvt.f32.u32 q3, q3 \n"
  213. "subs %0, #1 \n"
  214. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  215. "vst1.f32 {d4-d7}, [%2 :128]! \n"
  216. "bne 0b \n"
  217. : "=r"(nn), // %0
  218. "=r"(gray), // %1
  219. "=r"(ptr) // %2
  220. : "0"(nn),
  221. "1"(gray),
  222. "2"(ptr)
  223. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9"
  224. );
  225. }
  226. #endif // __aarch64__
  227. #endif // __ARM_NEON
  228. for (; remain>0; remain--)
  229. {
  230. *ptr = *gray;
  231. gray++;
  232. ptr++;
  233. }
  234. gray += wgap;
  235. }
  236. return 0;
  237. }
  238. static void to_gray(const Mat& m, unsigned char* gray, int stride)
  239. {
  240. int w = m.w;
  241. int h = m.h;
  242. const int wgap = stride - w;
  243. if (wgap == 0)
  244. {
  245. w = w * h;
  246. h = 1;
  247. }
  248. const float* ptr = m;
  249. for (int y=0; y<h; y++)
  250. {
  251. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  252. int remain = w;
  253. for (; remain>0; remain--)
  254. {
  255. *gray = SATURATE_CAST_UCHAR(*ptr);
  256. gray++;
  257. ptr++;
  258. }
  259. #undef SATURATE_CAST_UCHAR
  260. gray += wgap;
  261. }
  262. }
  263. static int from_rgba(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  264. {
  265. m.create(w, h, 4, 4u, allocator);
  266. if (m.empty())
  267. return -100;
  268. const int wgap = stride - w * 4;
  269. if (wgap == 0)
  270. {
  271. w = w * h;
  272. h = 1;
  273. }
  274. float* ptr0 = m.channel(0);
  275. float* ptr1 = m.channel(1);
  276. float* ptr2 = m.channel(2);
  277. float* ptr3 = m.channel(3);
  278. for (int y=0; y<h; y++)
  279. {
  280. #if __ARM_NEON
  281. int nn = w >> 3;
  282. int remain = w - (nn << 3);
  283. #else
  284. int remain = w;
  285. #endif // __ARM_NEON
  286. #if __ARM_NEON
  287. #if __aarch64__
  288. for (; nn>0; nn--)
  289. {
  290. uint8x8x4_t _rgba = vld4_u8(rgba);
  291. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  292. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  293. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  294. int16x8_t _a16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[3]));
  295. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  296. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  297. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  298. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  299. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  300. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  301. float32x4_t _alow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_a16)));
  302. float32x4_t _ahigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_a16)));
  303. vst1q_f32(ptr0, _rlow);
  304. vst1q_f32(ptr0+4, _rhigh);
  305. vst1q_f32(ptr1, _glow);
  306. vst1q_f32(ptr1+4, _ghigh);
  307. vst1q_f32(ptr2, _blow);
  308. vst1q_f32(ptr2+4, _bhigh);
  309. vst1q_f32(ptr3, _alow);
  310. vst1q_f32(ptr3+4, _ahigh);
  311. rgba += 4*8;
  312. ptr0 += 8;
  313. ptr1 += 8;
  314. ptr2 += 8;
  315. ptr3 += 8;
  316. }
  317. #else
  318. if (nn > 0)
  319. {
  320. asm volatile(
  321. "0: \n"
  322. "pld [%1, #256] \n"
  323. "vld4.u8 {d0-d3}, [%1]! \n"
  324. "vmovl.u8 q8, d0 \n"
  325. "vmovl.u8 q9, d1 \n"
  326. "vmovl.u8 q10, d2 \n"
  327. "vmovl.u8 q11, d3 \n"
  328. "vmovl.u16 q0, d16 \n"
  329. "vmovl.u16 q1, d17 \n"
  330. "vmovl.u16 q2, d18 \n"
  331. "vmovl.u16 q3, d19 \n"
  332. "vmovl.u16 q8, d20 \n"
  333. "vmovl.u16 q9, d21 \n"
  334. "vmovl.u16 q10, d22 \n"
  335. "vmovl.u16 q11, d23 \n"
  336. "vcvt.f32.u32 q0, q0 \n"
  337. "vcvt.f32.u32 q1, q1 \n"
  338. "vcvt.f32.u32 q2, q2 \n"
  339. "vcvt.f32.u32 q3, q3 \n"
  340. "vcvt.f32.u32 q8, q8 \n"
  341. "vcvt.f32.u32 q9, q9 \n"
  342. "subs %0, #1 \n"
  343. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  344. "vcvt.f32.u32 q10, q10 \n"
  345. "vcvt.f32.u32 q11, q11 \n"
  346. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  347. "vst1.f32 {d16-d19}, [%4 :128]!\n"
  348. "vst1.f32 {d20-d23}, [%5 :128]!\n"
  349. "bne 0b \n"
  350. : "=r"(nn), // %0
  351. "=r"(rgba), // %1
  352. "=r"(ptr0), // %2
  353. "=r"(ptr1), // %3
  354. "=r"(ptr2), // %4
  355. "=r"(ptr3) // %5
  356. : "0"(nn),
  357. "1"(rgba),
  358. "2"(ptr0),
  359. "3"(ptr1),
  360. "4"(ptr2),
  361. "5"(ptr3)
  362. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11"
  363. );
  364. }
  365. #endif // __aarch64__
  366. #endif // __ARM_NEON
  367. for (; remain>0; remain--)
  368. {
  369. *ptr0 = rgba[0];
  370. *ptr1 = rgba[1];
  371. *ptr2 = rgba[2];
  372. *ptr3 = rgba[3];
  373. rgba += 4;
  374. ptr0++;
  375. ptr1++;
  376. ptr2++;
  377. ptr3++;
  378. }
  379. rgba += wgap;
  380. }
  381. return 0;
  382. }
  383. static void to_rgba(const Mat& m, unsigned char* rgba, int stride)
  384. {
  385. int w = m.w;
  386. int h = m.h;
  387. const int wgap = stride - w * 4;
  388. if (wgap == 0)
  389. {
  390. w = w * h;
  391. h = 1;
  392. }
  393. const float* ptr0 = m.channel(0);
  394. const float* ptr1 = m.channel(1);
  395. const float* ptr2 = m.channel(2);
  396. const float* ptr3 = m.channel(3);
  397. for (int y=0; y<h; y++)
  398. {
  399. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  400. int remain = w;
  401. for (; remain>0; remain--)
  402. {
  403. rgba[0] = SATURATE_CAST_UCHAR(*ptr0);
  404. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  405. rgba[2] = SATURATE_CAST_UCHAR(*ptr2);
  406. rgba[3] = SATURATE_CAST_UCHAR(*ptr3);
  407. rgba += 4;
  408. ptr0++;
  409. ptr1++;
  410. ptr2++;
  411. ptr3++;
  412. }
  413. #undef SATURATE_CAST_UCHAR
  414. rgba += wgap;
  415. }
  416. }
  417. static int from_rgb2bgr(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  418. {
  419. m.create(w, h, 3, 4u, allocator);
  420. if (m.empty())
  421. return -100;
  422. const int wgap = stride - w * 3;
  423. if (wgap == 0)
  424. {
  425. w = w * h;
  426. h = 1;
  427. }
  428. float* ptr0 = m.channel(0);
  429. float* ptr1 = m.channel(1);
  430. float* ptr2 = m.channel(2);
  431. for (int y=0; y<h; y++)
  432. {
  433. #if __ARM_NEON
  434. int nn = w >> 3;
  435. int remain = w - (nn << 3);
  436. #else
  437. int remain = w;
  438. #endif // __ARM_NEON
  439. #if __ARM_NEON
  440. #if __aarch64__
  441. for (; nn>0; nn--)
  442. {
  443. uint8x8x3_t _rgb = vld3_u8(rgb);
  444. uint16x8_t _r16 = vmovl_u8(_rgb.val[0]);
  445. uint16x8_t _g16 = vmovl_u8(_rgb.val[1]);
  446. uint16x8_t _b16 = vmovl_u8(_rgb.val[2]);
  447. float32x4_t _rlow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_r16)));
  448. float32x4_t _rhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_r16)));
  449. float32x4_t _glow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_g16)));
  450. float32x4_t _ghigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_g16)));
  451. float32x4_t _blow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_b16)));
  452. float32x4_t _bhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_b16)));
  453. vst1q_f32(ptr2, _rlow);
  454. vst1q_f32(ptr2+4, _rhigh);
  455. vst1q_f32(ptr1, _glow);
  456. vst1q_f32(ptr1+4, _ghigh);
  457. vst1q_f32(ptr0, _blow);
  458. vst1q_f32(ptr0+4, _bhigh);
  459. rgb += 3*8;
  460. ptr0 += 8;
  461. ptr1 += 8;
  462. ptr2 += 8;
  463. }
  464. #else
  465. if (nn > 0)
  466. {
  467. asm volatile(
  468. "0: \n"
  469. "pld [%1, #256] \n"
  470. "vld3.u8 {d0-d2}, [%1]! \n"
  471. "vmovl.u8 q8, d0 \n"
  472. "vmovl.u8 q9, d1 \n"
  473. "vmovl.u8 q10, d2 \n"
  474. "vmovl.u16 q0, d16 \n"
  475. "vmovl.u16 q1, d17 \n"
  476. "vmovl.u16 q2, d18 \n"
  477. "vmovl.u16 q3, d19 \n"
  478. "vmovl.u16 q8, d20 \n"
  479. "vmovl.u16 q9, d21 \n"
  480. "vcvt.f32.u32 q0, q0 \n"
  481. "vcvt.f32.u32 q1, q1 \n"
  482. "vcvt.f32.u32 q2, q2 \n"
  483. "vcvt.f32.u32 q3, q3 \n"
  484. "vcvt.f32.u32 q8, q8 \n"
  485. "subs %0, #1 \n"
  486. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  487. "vcvt.f32.u32 q9, q9 \n"
  488. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  489. "vst1.f32 {d16-d19}, [%2 :128]!\n"
  490. "bne 0b \n"
  491. : "=r"(nn), // %0
  492. "=r"(rgb), // %1
  493. "=r"(ptr0), // %2
  494. "=r"(ptr1), // %3
  495. "=r"(ptr2) // %4
  496. : "0"(nn),
  497. "1"(rgb),
  498. "2"(ptr0),
  499. "3"(ptr1),
  500. "4"(ptr2)
  501. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
  502. );
  503. }
  504. #endif // __aarch64__
  505. #endif // __ARM_NEON
  506. for (; remain>0; remain--)
  507. {
  508. *ptr0 = rgb[2];
  509. *ptr1 = rgb[1];
  510. *ptr2 = rgb[0];
  511. rgb += 3;
  512. ptr0++;
  513. ptr1++;
  514. ptr2++;
  515. }
  516. rgb += wgap;
  517. }
  518. return 0;
  519. }
  520. static void to_bgr2rgb(const Mat& m, unsigned char* rgb, int stride)
  521. {
  522. int w = m.w;
  523. int h = m.h;
  524. const int wgap = stride - w * 3;
  525. if (wgap == 0)
  526. {
  527. w = w * h;
  528. h = 1;
  529. }
  530. const float* ptr0 = m.channel(0);
  531. const float* ptr1 = m.channel(1);
  532. const float* ptr2 = m.channel(2);
  533. for (int y=0; y<h; y++)
  534. {
  535. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  536. int remain = w;
  537. for (; remain>0; remain--)
  538. {
  539. rgb[2] = SATURATE_CAST_UCHAR(*ptr0);
  540. rgb[1] = SATURATE_CAST_UCHAR(*ptr1);
  541. rgb[0] = SATURATE_CAST_UCHAR(*ptr2);
  542. rgb += 3;
  543. ptr0++;
  544. ptr1++;
  545. ptr2++;
  546. }
  547. #undef SATURATE_CAST_UCHAR
  548. rgb += wgap;
  549. }
  550. }
  551. static int from_rgb2gray(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  552. {
  553. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  554. const unsigned char Y_shift = 8;//14
  555. const unsigned char R2Y = 77;
  556. const unsigned char G2Y = 150;
  557. const unsigned char B2Y = 29;
  558. m.create(w, h, 1, 4u, allocator);
  559. if (m.empty())
  560. return -100;
  561. const int wgap = stride - w * 3;
  562. if (wgap == 0)
  563. {
  564. w = w * h;
  565. h = 1;
  566. }
  567. float* ptr = m;
  568. for (int y=0; y<h; y++)
  569. {
  570. #if __ARM_NEON
  571. int nn = w >> 3;
  572. int remain = w - (nn << 3);
  573. #else
  574. int remain = w;
  575. #endif // __ARM_NEON
  576. #if __ARM_NEON
  577. #if __aarch64__
  578. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  579. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  580. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  581. for (; nn>0; nn--)
  582. {
  583. uint8x8x3_t _rgb = vld3_u8(rgb);
  584. uint16x8_t _y16 = vmull_u8(_rgb.val[0], _R2Y);
  585. _y16 = vmlal_u8(_y16, _rgb.val[1], _G2Y);
  586. _y16 = vmlal_u8(_y16, _rgb.val[2], _B2Y);
  587. _y16 = vshrq_n_u16(_y16, Y_shift);
  588. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  589. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  590. vst1q_f32(ptr, _ylow);
  591. vst1q_f32(ptr+4, _yhigh);
  592. rgb += 3*8;
  593. ptr += 8;
  594. }
  595. #else
  596. if (nn > 0)
  597. {
  598. asm volatile(
  599. "vdup.u8 d16, %6 \n"
  600. "vdup.u8 d17, %7 \n"
  601. "vdup.u8 d18, %8 \n"
  602. "0: \n"
  603. "pld [%1, #256] \n"
  604. "vld3.u8 {d0-d2}, [%1]! \n"
  605. "vmull.u8 q2, d0, d16 \n"
  606. "vmlal.u8 q2, d1, d17 \n"
  607. "vmlal.u8 q2, d2, d18 \n"
  608. "vshr.u16 q2, q2, #8 \n" // Y_shift
  609. "vmovl.u16 q0, d4 \n"
  610. "vmovl.u16 q1, d5 \n"
  611. "vcvt.f32.u32 q0, q0 \n"
  612. "vcvt.f32.u32 q1, q1 \n"
  613. "subs %0, #1 \n"
  614. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  615. "bne 0b \n"
  616. : "=r"(nn), // %0
  617. "=r"(rgb), // %1
  618. "=r"(ptr) // %2
  619. : "0"(nn),
  620. "1"(rgb),
  621. "2"(ptr),
  622. "r"(R2Y), // %6
  623. "r"(G2Y), // %7
  624. "r"(B2Y) // %8
  625. : "cc", "memory", "q0", "q1", "q2", "q8", "q9"
  626. );
  627. }
  628. #endif // __aarch64__
  629. #endif // __ARM_NEON
  630. for (; remain>0; remain--)
  631. {
  632. *ptr = static_cast<float>((rgb[0] * R2Y + rgb[1] * G2Y + rgb[2] * B2Y) >> Y_shift);
  633. rgb += 3;
  634. ptr++;
  635. }
  636. rgb += wgap;
  637. }
  638. return 0;
  639. }
  640. static int from_rgb2rgba(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  641. {
  642. m.create(w, h, 4, 4u, allocator);
  643. if (m.empty())
  644. return -100;
  645. Mat rgb_channels = m.channel_range(0, 3);
  646. from_rgb(rgb, w, h, stride, rgb_channels, allocator);
  647. Mat alpha_channel = m.channel(3);
  648. alpha_channel.fill(255.f);
  649. return 0;
  650. }
  651. static void to_rgb2rgba(const Mat& m, unsigned char* rgba, int stride)
  652. {
  653. int w = m.w;
  654. int h = m.h;
  655. const int wgap = stride - w * 4;
  656. if (wgap == 0)
  657. {
  658. w = w * h;
  659. h = 1;
  660. }
  661. const float* ptr0 = m.channel(0);
  662. const float* ptr1 = m.channel(1);
  663. const float* ptr2 = m.channel(2);
  664. for (int y=0; y<h; y++)
  665. {
  666. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  667. int remain = w;
  668. for (; remain>0; remain--)
  669. {
  670. rgba[0] = SATURATE_CAST_UCHAR(*ptr0);
  671. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  672. rgba[2] = SATURATE_CAST_UCHAR(*ptr2);
  673. rgba[3] = 255;
  674. rgba += 4;
  675. ptr0++;
  676. ptr1++;
  677. ptr2++;
  678. }
  679. #undef SATURATE_CAST_UCHAR
  680. rgba += wgap;
  681. }
  682. }
  683. static int from_bgr2gray(const unsigned char* bgr, int w, int h, int stride, Mat& m, Allocator* allocator)
  684. {
  685. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  686. const unsigned char Y_shift = 8;//14
  687. const unsigned char R2Y = 77;
  688. const unsigned char G2Y = 150;
  689. const unsigned char B2Y = 29;
  690. m.create(w, h, 1, 4u, allocator);
  691. if (m.empty())
  692. return -100;
  693. const int wgap = stride - w * 3;
  694. if (wgap == 0)
  695. {
  696. w = w * h;
  697. h = 1;
  698. }
  699. float* ptr = m;
  700. for (int y=0; y<h; y++)
  701. {
  702. #if __ARM_NEON
  703. int nn = w >> 3;
  704. int remain = w - (nn << 3);
  705. #else
  706. int remain = w;
  707. #endif // __ARM_NEON
  708. #if __ARM_NEON
  709. #if __aarch64__
  710. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  711. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  712. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  713. for (; nn>0; nn--)
  714. {
  715. uint8x8x3_t _rgb = vld3_u8(bgr);
  716. uint16x8_t _y16 = vmull_u8(_rgb.val[2], _R2Y);
  717. _y16 = vmlal_u8(_y16, _rgb.val[1], _G2Y);
  718. _y16 = vmlal_u8(_y16, _rgb.val[0], _B2Y);
  719. _y16 = vshrq_n_u16(_y16, Y_shift);
  720. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  721. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  722. vst1q_f32(ptr, _ylow);
  723. vst1q_f32(ptr+4, _yhigh);
  724. bgr += 3*8;
  725. ptr += 8;
  726. }
  727. #else
  728. if (nn > 0)
  729. {
  730. asm volatile(
  731. "vdup.u8 d16, %6 \n"
  732. "vdup.u8 d17, %7 \n"
  733. "vdup.u8 d18, %8 \n"
  734. "0: \n"
  735. "pld [%1, #256] \n"
  736. "vld3.u8 {d0-d2}, [%1]! \n"
  737. "vmull.u8 q2, d2, d16 \n"
  738. "vmlal.u8 q2, d1, d17 \n"
  739. "vmlal.u8 q2, d0, d18 \n"
  740. "vshr.u16 q2, q2, #8 \n" // Y_shift
  741. "vmovl.u16 q0, d4 \n"
  742. "vmovl.u16 q1, d5 \n"
  743. "vcvt.f32.u32 q0, q0 \n"
  744. "vcvt.f32.u32 q1, q1 \n"
  745. "subs %0, #1 \n"
  746. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  747. "bne 0b \n"
  748. : "=r"(nn), // %0
  749. "=r"(bgr), // %1
  750. "=r"(ptr) // %2
  751. : "0"(nn),
  752. "1"(bgr),
  753. "2"(ptr),
  754. "r"(R2Y), // %6
  755. "r"(G2Y), // %7
  756. "r"(B2Y) // %8
  757. : "cc", "memory", "q0", "q1", "q2", "q8", "q9"
  758. );
  759. }
  760. #endif // __aarch64__
  761. #endif // __ARM_NEON
  762. for (; remain>0; remain--)
  763. {
  764. *ptr = static_cast<float>((bgr[2] * R2Y + bgr[1] * G2Y + bgr[0] * B2Y) >> Y_shift);
  765. bgr += 3;
  766. ptr++;
  767. }
  768. bgr += wgap;
  769. }
  770. return 0;
  771. }
  772. static int from_bgr2rgba(const unsigned char* bgr, int w, int h, int stride, Mat& m, Allocator* allocator)
  773. {
  774. m.create(w, h, 4, 4u, allocator);
  775. if (m.empty())
  776. return -100;
  777. Mat rgb_channels = m.channel_range(0, 3);
  778. from_rgb2bgr(bgr, w, h, stride, rgb_channels, allocator);
  779. Mat alpha_channel = m.channel(3);
  780. alpha_channel.fill(255.f);
  781. return 0;
  782. }
  783. static void to_bgr2rgba(const Mat& m, unsigned char* rgba, int stride)
  784. {
  785. int w = m.w;
  786. int h = m.h;
  787. const int wgap = stride - w * 4;
  788. if (wgap == 0)
  789. {
  790. w = w * h;
  791. h = 1;
  792. }
  793. const float* ptr0 = m.channel(0);
  794. const float* ptr1 = m.channel(1);
  795. const float* ptr2 = m.channel(2);
  796. for (int y=0; y<h; y++)
  797. {
  798. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  799. int remain = w;
  800. for (; remain>0; remain--)
  801. {
  802. rgba[0] = SATURATE_CAST_UCHAR(*ptr2);
  803. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  804. rgba[2] = SATURATE_CAST_UCHAR(*ptr0);
  805. rgba[3] = 255;
  806. rgba += 4;
  807. ptr0++;
  808. ptr1++;
  809. ptr2++;
  810. }
  811. #undef SATURATE_CAST_UCHAR
  812. rgba += wgap;
  813. }
  814. }
  815. static int from_gray2rgb(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  816. {
  817. m.create(w, h, 3, 4u, allocator);
  818. if (m.empty())
  819. return -100;
  820. const int wgap = stride - w;
  821. if (wgap == 0)
  822. {
  823. w = w * h;
  824. h = 1;
  825. }
  826. float* ptr0 = m.channel(0);
  827. float* ptr1 = m.channel(1);
  828. float* ptr2 = m.channel(2);
  829. for (int y=0; y<h; y++)
  830. {
  831. #if __ARM_NEON
  832. int nn = w >> 4;
  833. int remain = w - (nn << 4);
  834. #else
  835. int remain = w;
  836. #endif // __ARM_NEON
  837. #if __ARM_NEON
  838. #if __aarch64__
  839. for (; nn>0; nn--)
  840. {
  841. uint8x16_t _gray = vld1q_u8(gray);
  842. uint16x8_t _gray16_0 = vmovl_u8(vget_low_u8(_gray));
  843. uint16x8_t _gray16_1 = vmovl_u8(vget_high_u8(_gray));
  844. float32x4_t _graylow_0 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_0)));
  845. float32x4_t _grayhigh_0 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_0)));
  846. float32x4_t _graylow_1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_1)));
  847. float32x4_t _grayhigh_1 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_1)));
  848. vst1q_f32(ptr0, _graylow_0);
  849. vst1q_f32(ptr0+4, _grayhigh_0);
  850. vst1q_f32(ptr0+8, _graylow_1);
  851. vst1q_f32(ptr0+12, _grayhigh_1);
  852. vst1q_f32(ptr1, _graylow_0);
  853. vst1q_f32(ptr1+4, _grayhigh_0);
  854. vst1q_f32(ptr1+8, _graylow_1);
  855. vst1q_f32(ptr1+12, _grayhigh_1);
  856. vst1q_f32(ptr2, _graylow_0);
  857. vst1q_f32(ptr2+4, _grayhigh_0);
  858. vst1q_f32(ptr2+8, _graylow_1);
  859. vst1q_f32(ptr2+12, _grayhigh_1);
  860. gray += 16;
  861. ptr0 += 16;
  862. ptr1 += 16;
  863. ptr2 += 16;
  864. }
  865. #else
  866. if (nn > 0)
  867. {
  868. asm volatile(
  869. "0: \n"
  870. "pld [%1, #128] \n"
  871. "vld1.u8 {d0,d1}, [%1]! \n"
  872. "vmovl.u8 q8, d0 \n"
  873. "vmovl.u8 q9, d1 \n"
  874. "vmovl.u16 q0, d16 \n"
  875. "vmovl.u16 q1, d17 \n"
  876. "vmovl.u16 q2, d18 \n"
  877. "vmovl.u16 q3, d19 \n"
  878. "vcvt.f32.u32 q0, q0 \n"
  879. "vcvt.f32.u32 q1, q1 \n"
  880. "vcvt.f32.u32 q2, q2 \n"
  881. "vcvt.f32.u32 q3, q3 \n"
  882. "subs %0, #1 \n"
  883. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  884. "vst1.f32 {d4-d7}, [%2 :128]! \n"
  885. "vst1.f32 {d0-d3}, [%3 :128]! \n"
  886. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  887. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  888. "vst1.f32 {d4-d7}, [%4 :128]! \n"
  889. "bne 0b \n"
  890. : "=r"(nn), // %0
  891. "=r"(gray), // %1
  892. "=r"(ptr0), // %2
  893. "=r"(ptr1), // %3
  894. "=r"(ptr2) // %4
  895. : "0"(nn),
  896. "1"(gray),
  897. "2"(ptr0),
  898. "3"(ptr1),
  899. "4"(ptr2)
  900. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9"
  901. );
  902. }
  903. #endif // __aarch64__
  904. #endif // __ARM_NEON
  905. for (; remain>0; remain--)
  906. {
  907. *ptr0 = *gray;
  908. *ptr1 = *gray;
  909. *ptr2 = *gray;
  910. gray++;
  911. ptr0++;
  912. ptr1++;
  913. ptr2++;
  914. }
  915. gray += wgap;
  916. }
  917. return 0;
  918. }
  919. static int from_gray2rgba(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  920. {
  921. m.create(w, h, 4, 4u, allocator);
  922. if (m.empty())
  923. return -100;
  924. Mat rgb_channels = m.channel_range(0, 3);
  925. from_gray2rgb(gray, w, h, stride, rgb_channels, allocator);
  926. Mat alpha_channel = m.channel(3);
  927. alpha_channel.fill(255.f);
  928. return 0;
  929. }
  930. static void to_gray2rgba(const Mat& m, unsigned char* rgba, int stride)
  931. {
  932. int w = m.w;
  933. int h = m.h;
  934. const int wgap = stride - w * 4;
  935. if (wgap == 0)
  936. {
  937. w = w * h;
  938. h = 1;
  939. }
  940. const float* ptr = m;
  941. for (int y=0; y<h; y++)
  942. {
  943. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  944. int remain = w;
  945. for (; remain>0; remain--)
  946. {
  947. unsigned char gray = SATURATE_CAST_UCHAR(*ptr);
  948. rgba[0] = gray;
  949. rgba[1] = gray;
  950. rgba[2] = gray;
  951. rgba[3] = 255;
  952. rgba += 4;
  953. ptr++;
  954. }
  955. #undef SATURATE_CAST_UCHAR
  956. rgba += wgap;
  957. }
  958. }
  959. static int from_rgba2rgb(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  960. {
  961. m.create(w, h, 3, 4u, allocator);
  962. if (m.empty())
  963. return -100;
  964. const int wgap = stride - w * 4;
  965. if (wgap == 0)
  966. {
  967. w = w * h;
  968. h = 1;
  969. }
  970. float* ptr0 = m.channel(0);
  971. float* ptr1 = m.channel(1);
  972. float* ptr2 = m.channel(2);
  973. for (int y=0; y<h; y++)
  974. {
  975. #if __ARM_NEON
  976. int nn = w >> 3;
  977. int remain = w - (nn << 3);
  978. #else
  979. int remain = w;
  980. #endif // __ARM_NEON
  981. #if __ARM_NEON
  982. #if __aarch64__
  983. for (; nn>0; nn--)
  984. {
  985. uint8x8x4_t _rgba = vld4_u8(rgba);
  986. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  987. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  988. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  989. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  990. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  991. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  992. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  993. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  994. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  995. vst1q_f32(ptr0, _rlow);
  996. vst1q_f32(ptr0+4, _rhigh);
  997. vst1q_f32(ptr1, _glow);
  998. vst1q_f32(ptr1+4, _ghigh);
  999. vst1q_f32(ptr2, _blow);
  1000. vst1q_f32(ptr2+4, _bhigh);
  1001. rgba += 4*8;
  1002. ptr0 += 8;
  1003. ptr1 += 8;
  1004. ptr2 += 8;
  1005. }
  1006. #else
  1007. if (nn > 0)
  1008. {
  1009. asm volatile(
  1010. "0: \n"
  1011. "pld [%1, #256] \n"
  1012. "vld4.u8 {d0-d3}, [%1]! \n"
  1013. "vmovl.u8 q8, d0 \n"
  1014. "vmovl.u8 q9, d1 \n"
  1015. "vmovl.u8 q10, d2 \n"
  1016. "vmovl.u16 q0, d16 \n"
  1017. "vmovl.u16 q1, d17 \n"
  1018. "vmovl.u16 q2, d18 \n"
  1019. "vmovl.u16 q3, d19 \n"
  1020. "vmovl.u16 q8, d20 \n"
  1021. "vmovl.u16 q9, d21 \n"
  1022. "vcvt.f32.u32 q0, q0 \n"
  1023. "vcvt.f32.u32 q1, q1 \n"
  1024. "vcvt.f32.u32 q2, q2 \n"
  1025. "vcvt.f32.u32 q3, q3 \n"
  1026. "vcvt.f32.u32 q8, q8 \n"
  1027. "subs %0, #1 \n"
  1028. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1029. "vcvt.f32.u32 q9, q9 \n"
  1030. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1031. "vst1.f32 {d16-d19}, [%4 :128]!\n"
  1032. "bne 0b \n"
  1033. : "=r"(nn), // %0
  1034. "=r"(rgba), // %1
  1035. "=r"(ptr0), // %2
  1036. "=r"(ptr1), // %3
  1037. "=r"(ptr2) // %4
  1038. : "0"(nn),
  1039. "1"(rgba),
  1040. "2"(ptr0),
  1041. "3"(ptr1),
  1042. "4"(ptr2)
  1043. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9"
  1044. );
  1045. }
  1046. #endif // __aarch64__
  1047. #endif // __ARM_NEON
  1048. for (; remain>0; remain--)
  1049. {
  1050. *ptr0 = rgba[0];
  1051. *ptr1 = rgba[1];
  1052. *ptr2 = rgba[2];
  1053. rgba += 4;
  1054. ptr0++;
  1055. ptr1++;
  1056. ptr2++;
  1057. }
  1058. rgba += wgap;
  1059. }
  1060. return 0;
  1061. }
  1062. static int from_rgba2bgr(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1063. {
  1064. m.create(w, h, 3, 4u, allocator);
  1065. if (m.empty())
  1066. return -100;
  1067. const int wgap = stride - w * 4;
  1068. if (wgap == 0)
  1069. {
  1070. w = w * h;
  1071. h = 1;
  1072. }
  1073. float* ptr0 = m.channel(0);
  1074. float* ptr1 = m.channel(1);
  1075. float* ptr2 = m.channel(2);
  1076. for (int y=0; y<h; y++)
  1077. {
  1078. #if __ARM_NEON
  1079. int nn = w >> 3;
  1080. int remain = w - (nn << 3);
  1081. #else
  1082. int remain = w;
  1083. #endif // __ARM_NEON
  1084. #if __ARM_NEON
  1085. #if __aarch64__
  1086. for (; nn>0; nn--)
  1087. {
  1088. uint8x8x4_t _rgba = vld4_u8(rgba);
  1089. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  1090. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  1091. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  1092. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  1093. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  1094. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  1095. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  1096. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  1097. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  1098. vst1q_f32(ptr2, _rlow);
  1099. vst1q_f32(ptr2+4, _rhigh);
  1100. vst1q_f32(ptr1, _glow);
  1101. vst1q_f32(ptr1+4, _ghigh);
  1102. vst1q_f32(ptr0, _blow);
  1103. vst1q_f32(ptr0+4, _bhigh);
  1104. rgba += 4*8;
  1105. ptr0 += 8;
  1106. ptr1 += 8;
  1107. ptr2 += 8;
  1108. }
  1109. #else
  1110. if (nn > 0)
  1111. {
  1112. asm volatile(
  1113. "0: \n"
  1114. "pld [%1, #256] \n"
  1115. "vld4.u8 {d0-d3}, [%1]! \n"
  1116. "vmovl.u8 q8, d0 \n"
  1117. "vmovl.u8 q9, d1 \n"
  1118. "vmovl.u8 q10, d2 \n"
  1119. "vmovl.u16 q0, d16 \n"
  1120. "vmovl.u16 q1, d17 \n"
  1121. "vmovl.u16 q2, d18 \n"
  1122. "vmovl.u16 q3, d19 \n"
  1123. "vmovl.u16 q8, d20 \n"
  1124. "vmovl.u16 q9, d21 \n"
  1125. "vcvt.f32.u32 q0, q0 \n"
  1126. "vcvt.f32.u32 q1, q1 \n"
  1127. "vcvt.f32.u32 q2, q2 \n"
  1128. "vcvt.f32.u32 q3, q3 \n"
  1129. "vcvt.f32.u32 q8, q8 \n"
  1130. "subs %0, #1 \n"
  1131. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  1132. "vcvt.f32.u32 q9, q9 \n"
  1133. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1134. "vst1.f32 {d16-d19}, [%2 :128]!\n"
  1135. "bne 0b \n"
  1136. : "=r"(nn), // %0
  1137. "=r"(rgba), // %1
  1138. "=r"(ptr0), // %2
  1139. "=r"(ptr1), // %3
  1140. "=r"(ptr2) // %4
  1141. : "0"(nn),
  1142. "1"(rgba),
  1143. "2"(ptr0),
  1144. "3"(ptr1),
  1145. "4"(ptr2)
  1146. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
  1147. );
  1148. }
  1149. #endif // __aarch64__
  1150. #endif // __ARM_NEON
  1151. for (; remain>0; remain--)
  1152. {
  1153. *ptr0 = rgba[2];
  1154. *ptr1 = rgba[1];
  1155. *ptr2 = rgba[0];
  1156. rgba += 4;
  1157. ptr0++;
  1158. ptr1++;
  1159. ptr2++;
  1160. }
  1161. rgba += wgap;
  1162. }
  1163. return 0;
  1164. }
  1165. static int from_rgba2gray(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1166. {
  1167. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  1168. const unsigned char Y_shift = 8;//14
  1169. const unsigned char R2Y = 77;
  1170. const unsigned char G2Y = 150;
  1171. const unsigned char B2Y = 29;
  1172. m.create(w, h, 1, 4u, allocator);
  1173. if (m.empty())
  1174. return -100;
  1175. const int wgap = stride - w * 4;
  1176. if (wgap == 0)
  1177. {
  1178. w = w * h;
  1179. h = 1;
  1180. }
  1181. float* ptr = m;
  1182. for (int y=0; y<h; y++)
  1183. {
  1184. #if __ARM_NEON
  1185. int nn = w >> 3;
  1186. int remain = w - (nn << 3);
  1187. #else
  1188. int remain = w;
  1189. #endif // __ARM_NEON
  1190. #if __ARM_NEON
  1191. #if __aarch64__
  1192. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  1193. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  1194. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  1195. for (; nn>0; nn--)
  1196. {
  1197. uint8x8x4_t _rgba = vld4_u8(rgba);
  1198. uint16x8_t _y16 = vmull_u8(_rgba.val[0], _R2Y);
  1199. _y16 = vmlal_u8(_y16, _rgba.val[1], _G2Y);
  1200. _y16 = vmlal_u8(_y16, _rgba.val[2], _B2Y);
  1201. _y16 = vshrq_n_u16(_y16, Y_shift);
  1202. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  1203. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  1204. vst1q_f32(ptr, _ylow);
  1205. vst1q_f32(ptr+4, _yhigh);
  1206. rgba += 4*8;
  1207. ptr += 8;
  1208. }
  1209. #else
  1210. if (nn > 0)
  1211. {
  1212. asm volatile(
  1213. "vdup.u8 d16, %6 \n"
  1214. "vdup.u8 d17, %7 \n"
  1215. "vdup.u8 d18, %8 \n"
  1216. "0: \n"
  1217. "pld [%1, #256] \n"
  1218. "vld4.u8 {d0-d3}, [%1]! \n"
  1219. "vmull.u8 q2, d0, d16 \n"
  1220. "vmlal.u8 q2, d1, d17 \n"
  1221. "vmlal.u8 q2, d2, d18 \n"
  1222. "vshr.u16 q2, q2, #8 \n" // Y_shift
  1223. "vmovl.u16 q0, d4 \n"
  1224. "vmovl.u16 q1, d5 \n"
  1225. "vcvt.f32.u32 q0, q0 \n"
  1226. "vcvt.f32.u32 q1, q1 \n"
  1227. "subs %0, #1 \n"
  1228. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1229. "bne 0b \n"
  1230. : "=r"(nn), // %0
  1231. "=r"(rgba), // %1
  1232. "=r"(ptr) // %2
  1233. : "0"(nn),
  1234. "1"(rgba),
  1235. "2"(ptr),
  1236. "r"(R2Y), // %6
  1237. "r"(G2Y), // %7
  1238. "r"(B2Y) // %8
  1239. : "cc", "memory", "q0", "q1", "q2", "q8", "q9"
  1240. );
  1241. }
  1242. #endif // __aarch64__
  1243. #endif // __ARM_NEON
  1244. for (; remain>0; remain--)
  1245. {
  1246. *ptr = static_cast<float>((rgba[0] * R2Y + rgba[1] * G2Y + rgba[2] * B2Y) >> Y_shift);
  1247. rgba += 4;
  1248. ptr++;
  1249. }
  1250. rgba += wgap;
  1251. }
  1252. return 0;
  1253. }
  1254. void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb)
  1255. {
  1256. const unsigned char* yptr = yuv420sp;
  1257. const unsigned char* vuptr = yuv420sp + w * h;
  1258. #if __ARM_NEON
  1259. uint8x8_t _v128 = vdup_n_u8(128);
  1260. int8x8_t _v90 = vdup_n_s8(90);
  1261. int8x8_t _v46 = vdup_n_s8(46);
  1262. int8x8_t _v22 = vdup_n_s8(22);
  1263. int8x8_t _v113 = vdup_n_s8(113);
  1264. #endif // __ARM_NEON
  1265. for (int y=0; y<h; y+=2)
  1266. {
  1267. const unsigned char* yptr0 = yptr;
  1268. const unsigned char* yptr1 = yptr + w;
  1269. unsigned char* rgb0 = rgb;
  1270. unsigned char* rgb1 = rgb + w*3;
  1271. #if __ARM_NEON
  1272. int nn = w >> 3;
  1273. int remain = w - (nn << 3);
  1274. #else
  1275. int remain = w;
  1276. #endif // __ARM_NEON
  1277. #if __ARM_NEON
  1278. #if __aarch64__
  1279. for (; nn>0; nn--)
  1280. {
  1281. int16x8_t _yy0 = vreinterpretq_s16_u16(vshll_n_u8(vld1_u8(yptr0), 6));
  1282. int16x8_t _yy1 = vreinterpretq_s16_u16(vshll_n_u8(vld1_u8(yptr1), 6));
  1283. int8x8_t _vvuu = vreinterpret_s8_u8(vsub_u8(vld1_u8(vuptr), _v128));
  1284. int8x8x2_t _vvvvuuuu = vtrn_s8(_vvuu, _vvuu);
  1285. int8x8_t _vv = _vvvvuuuu.val[0];
  1286. int8x8_t _uu = _vvvvuuuu.val[1];
  1287. int16x8_t _r0 = vmlal_s8(_yy0, _vv, _v90);
  1288. int16x8_t _g0 = vmlsl_s8(_yy0, _vv, _v46);
  1289. _g0 = vmlsl_s8(_g0, _uu, _v22);
  1290. int16x8_t _b0 = vmlal_s8(_yy0, _uu, _v113);
  1291. int16x8_t _r1 = vmlal_s8(_yy1, _vv, _v90);
  1292. int16x8_t _g1 = vmlsl_s8(_yy1, _vv, _v46);
  1293. _g1 = vmlsl_s8(_g1, _uu, _v22);
  1294. int16x8_t _b1 = vmlal_s8(_yy1, _uu, _v113);
  1295. uint8x8x3_t _rgb0;
  1296. _rgb0.val[0] = vqshrun_n_s16(_r0, 6);
  1297. _rgb0.val[1] = vqshrun_n_s16(_g0, 6);
  1298. _rgb0.val[2] = vqshrun_n_s16(_b0, 6);
  1299. uint8x8x3_t _rgb1;
  1300. _rgb1.val[0] = vqshrun_n_s16(_r1, 6);
  1301. _rgb1.val[1] = vqshrun_n_s16(_g1, 6);
  1302. _rgb1.val[2] = vqshrun_n_s16(_b1, 6);
  1303. vst3_u8(rgb0, _rgb0);
  1304. vst3_u8(rgb1, _rgb1);
  1305. yptr0 += 8;
  1306. yptr1 += 8;
  1307. vuptr += 8;
  1308. rgb0 += 24;
  1309. rgb1 += 24;
  1310. }
  1311. #else
  1312. if (nn > 0)
  1313. {
  1314. asm volatile(
  1315. "pld [%3, #128] \n"
  1316. "vld1.u8 {d2}, [%3]! \n"
  1317. "vsub.s8 d2, d2, %12 \n"
  1318. "0: \n"
  1319. "pld [%1, #128] \n"
  1320. "vld1.u8 {d0}, [%1]! \n"
  1321. "pld [%2, #128] \n"
  1322. "vld1.u8 {d1}, [%2]! \n"
  1323. "vshll.u8 q2, d0, #6 \n"
  1324. "vorr d3, d2, d2 \n"
  1325. "vshll.u8 q3, d1, #6 \n"
  1326. "vorr q9, q2, q2 \n"
  1327. "vtrn.s8 d2, d3 \n"
  1328. "vorr q11, q3, q3 \n"
  1329. "vmlsl.s8 q9, d2, %14 \n"
  1330. "vorr q8, q2, q2 \n"
  1331. "vmlsl.s8 q11, d2, %14 \n"
  1332. "vorr q10, q3, q3 \n"
  1333. "vmlal.s8 q8, d2, %13 \n"
  1334. "vmlal.s8 q2, d3, %16 \n"
  1335. "vmlal.s8 q10, d2, %13 \n"
  1336. "vmlsl.s8 q9, d3, %15 \n"
  1337. "vmlal.s8 q3, d3, %16 \n"
  1338. "vmlsl.s8 q11, d3, %15 \n"
  1339. "vqshrun.s16 d24, q8, #6 \n"
  1340. "vqshrun.s16 d26, q2, #6 \n"
  1341. "vqshrun.s16 d4, q10, #6 \n"
  1342. "vqshrun.s16 d25, q9, #6 \n"
  1343. "vqshrun.s16 d6, q3, #6 \n"
  1344. "vqshrun.s16 d5, q11, #6 \n"
  1345. "pld [%3, #128] \n"
  1346. "vld1.u8 {d2}, [%3]! \n"
  1347. "subs %0, #1 \n"
  1348. "vst3.u8 {d24-d26}, [%4]! \n"
  1349. "vsub.s8 d2, d2, %12 \n"
  1350. "vst3.u8 {d4-d6}, [%5]! \n"
  1351. "bne 0b \n"
  1352. "sub %3, #8 \n"
  1353. : "=r"(nn), // %0
  1354. "=r"(yptr0), // %1
  1355. "=r"(yptr1), // %2
  1356. "=r"(vuptr), // %3
  1357. "=r"(rgb0), // %4
  1358. "=r"(rgb1) // %5
  1359. : "0"(nn),
  1360. "1"(yptr0),
  1361. "2"(yptr1),
  1362. "3"(vuptr),
  1363. "4"(rgb0),
  1364. "5"(rgb1),
  1365. "w"(_v128), // %12
  1366. "w"(_v90), // %13
  1367. "w"(_v46), // %14
  1368. "w"(_v22), // %15
  1369. "w"(_v113) // %16
  1370. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "d26"
  1371. );
  1372. }
  1373. #endif // __aarch64__
  1374. #endif // __ARM_NEON
  1375. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  1376. for (; remain>0; remain-=2)
  1377. {
  1378. // R = 1.164 * yy + 1.596 * vv
  1379. // G = 1.164 * yy - 0.813 * vv - 0.391 * uu
  1380. // B = 1.164 * yy + 2.018 * uu
  1381. // R = Y + (1.370705 * (V-128))
  1382. // G = Y - (0.698001 * (V-128)) - (0.337633 * (U-128))
  1383. // B = Y + (1.732446 * (U-128))
  1384. // R = ((Y << 6) + 87.72512 * (V-128)) >> 6
  1385. // G = ((Y << 6) - 44.672064 * (V-128) - 21.608512 * (U-128)) >> 6
  1386. // B = ((Y << 6) + 110.876544 * (U-128)) >> 6
  1387. // R = ((Y << 6) + 90 * (V-128)) >> 6
  1388. // G = ((Y << 6) - 46 * (V-128) - 22 * (U-128)) >> 6
  1389. // B = ((Y << 6) + 113 * (U-128)) >> 6
  1390. // R = (yy + 90 * vv) >> 6
  1391. // G = (yy - 46 * vv - 22 * uu) >> 6
  1392. // B = (yy + 113 * uu) >> 6
  1393. int v = vuptr[0] - 128;
  1394. int u = vuptr[1] - 128;
  1395. int ruv = 90 * v;
  1396. int guv = -46 * v + -22 * u;
  1397. int buv = 113 * u;
  1398. int y00 = yptr0[0] << 6;
  1399. rgb0[0] = SATURATE_CAST_UCHAR((y00 + ruv) >> 6);
  1400. rgb0[1] = SATURATE_CAST_UCHAR((y00 + guv) >> 6);
  1401. rgb0[2] = SATURATE_CAST_UCHAR((y00 + buv) >> 6);
  1402. int y01 = yptr0[1] << 6;
  1403. rgb0[3] = SATURATE_CAST_UCHAR((y01 + ruv) >> 6);
  1404. rgb0[4] = SATURATE_CAST_UCHAR((y01 + guv) >> 6);
  1405. rgb0[5] = SATURATE_CAST_UCHAR((y01 + buv) >> 6);
  1406. int y10 = yptr1[0] << 6;
  1407. rgb1[0] = SATURATE_CAST_UCHAR((y10 + ruv) >> 6);
  1408. rgb1[1] = SATURATE_CAST_UCHAR((y10 + guv) >> 6);
  1409. rgb1[2] = SATURATE_CAST_UCHAR((y10 + buv) >> 6);
  1410. int y11 = yptr1[1] << 6;
  1411. rgb1[3] = SATURATE_CAST_UCHAR((y11 + ruv) >> 6);
  1412. rgb1[4] = SATURATE_CAST_UCHAR((y11 + guv) >> 6);
  1413. rgb1[5] = SATURATE_CAST_UCHAR((y11 + buv) >> 6);
  1414. yptr0 += 2;
  1415. yptr1 += 2;
  1416. vuptr += 2;
  1417. rgb0 += 6;
  1418. rgb1 += 6;
  1419. }
  1420. #undef SATURATE_CAST_UCHAR
  1421. yptr += 2*w;
  1422. rgb += 2*3*w;
  1423. }
  1424. }
  1425. Mat Mat::from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator)
  1426. {
  1427. int type_from = type & PIXEL_FORMAT_MASK;
  1428. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  1429. {
  1430. return Mat::from_pixels(pixels, type, w, h, w * 3, allocator);
  1431. }
  1432. else if (type_from == PIXEL_GRAY)
  1433. {
  1434. return Mat::from_pixels(pixels, type, w, h, w * 1, allocator);
  1435. }
  1436. else if (type_from == PIXEL_RGBA)
  1437. {
  1438. return Mat::from_pixels(pixels, type, w, h, w * 4, allocator);
  1439. }
  1440. // unknown convert type
  1441. return Mat();
  1442. }
  1443. Mat Mat::from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator)
  1444. {
  1445. Mat m;
  1446. if (type & PIXEL_CONVERT_MASK)
  1447. {
  1448. switch (type)
  1449. {
  1450. case PIXEL_RGB2BGR:
  1451. case PIXEL_BGR2RGB:
  1452. from_rgb2bgr(pixels, w, h, stride, m, allocator);
  1453. break;
  1454. case PIXEL_RGB2GRAY:
  1455. from_rgb2gray(pixels, w, h, stride, m, allocator);
  1456. break;
  1457. case PIXEL_RGB2RGBA:
  1458. from_rgb2rgba(pixels, w, h, stride, m, allocator);
  1459. break;
  1460. case PIXEL_BGR2GRAY:
  1461. from_bgr2gray(pixels, w, h, stride, m, allocator);
  1462. break;
  1463. case PIXEL_BGR2RGBA:
  1464. from_bgr2rgba(pixels, w, h, stride, m, allocator);
  1465. break;
  1466. case PIXEL_GRAY2RGB:
  1467. case PIXEL_GRAY2BGR:
  1468. from_gray2rgb(pixels, w, h, stride, m, allocator);
  1469. break;
  1470. case PIXEL_GRAY2RGBA:
  1471. from_gray2rgba(pixels, w, h, stride, m, allocator);
  1472. break;
  1473. case PIXEL_RGBA2RGB:
  1474. from_rgba2rgb(pixels, w, h, stride, m, allocator);
  1475. break;
  1476. case PIXEL_RGBA2BGR:
  1477. from_rgba2bgr(pixels, w, h, stride, m, allocator);
  1478. break;
  1479. case PIXEL_RGBA2GRAY:
  1480. from_rgba2gray(pixels, w, h, stride, m, allocator);
  1481. break;
  1482. default:
  1483. // unimplemented convert type
  1484. break;
  1485. }
  1486. }
  1487. else
  1488. {
  1489. if (type == PIXEL_RGB || type == PIXEL_BGR)
  1490. from_rgb(pixels, w, h, stride, m, allocator);
  1491. if (type == PIXEL_GRAY)
  1492. from_gray(pixels, w, h, stride, m, allocator);
  1493. if (type == PIXEL_RGBA)
  1494. from_rgba(pixels, w, h, stride, m, allocator);
  1495. }
  1496. return m;
  1497. }
  1498. Mat Mat::from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator)
  1499. {
  1500. int type_from = type & PIXEL_FORMAT_MASK;
  1501. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  1502. {
  1503. return Mat::from_pixels_resize(pixels, type, w, h, w * 3, target_width, target_height, allocator);
  1504. }
  1505. else if (type_from == PIXEL_GRAY)
  1506. {
  1507. return Mat::from_pixels_resize(pixels, type, w, h, w * 1, target_width, target_height, allocator);
  1508. }
  1509. else if (type_from == PIXEL_RGBA)
  1510. {
  1511. return Mat::from_pixels_resize(pixels, type, w, h, w * 4, target_width, target_height, allocator);
  1512. }
  1513. // unknown convert type
  1514. return Mat();
  1515. }
  1516. Mat Mat::from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int stride, int target_width, int target_height, Allocator* allocator)
  1517. {
  1518. if (w == target_width && h == target_height)
  1519. return Mat::from_pixels(pixels, type, w, h, stride, allocator);
  1520. int type_from = type & PIXEL_FORMAT_MASK;
  1521. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  1522. {
  1523. Mat dst(target_width, target_height, (size_t)3u, 3);
  1524. resize_bilinear_c3(pixels, w, h, stride, dst, target_width, target_height, target_width * 3);
  1525. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  1526. }
  1527. else if (type_from == PIXEL_GRAY)
  1528. {
  1529. Mat dst(target_width, target_height, (size_t)1u, 1);
  1530. resize_bilinear_c1(pixels, w, h, stride, dst, target_width, target_height, target_width * 1);
  1531. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  1532. }
  1533. else if (type_from == PIXEL_RGBA)
  1534. {
  1535. Mat dst(target_width, target_height, (size_t)4u, 4);
  1536. resize_bilinear_c4(pixels, w, h, stride, dst, target_width, target_height, target_width * 4);
  1537. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  1538. }
  1539. // unknown convert type
  1540. return Mat();
  1541. }
  1542. void Mat::to_pixels(unsigned char* pixels, int type) const
  1543. {
  1544. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  1545. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  1546. {
  1547. to_pixels(pixels, type, w * 3);
  1548. }
  1549. else if (type_to == PIXEL_GRAY)
  1550. {
  1551. to_pixels(pixels, type, w * 1);
  1552. }
  1553. else if (type_to == PIXEL_RGBA)
  1554. {
  1555. to_pixels(pixels, type, w * 4);
  1556. }
  1557. }
  1558. void Mat::to_pixels(unsigned char* pixels, int type, int stride) const
  1559. {
  1560. if (type & PIXEL_CONVERT_MASK)
  1561. {
  1562. switch (type)
  1563. {
  1564. case PIXEL_RGB2BGR:
  1565. case PIXEL_BGR2RGB:
  1566. to_bgr2rgb(*this, pixels, stride);
  1567. break;
  1568. case PIXEL_RGB2RGBA:
  1569. to_rgb2rgba(*this, pixels, stride);
  1570. break;
  1571. case PIXEL_BGR2RGBA:
  1572. to_bgr2rgba(*this, pixels, stride);
  1573. break;
  1574. case PIXEL_GRAY2RGBA:
  1575. to_gray2rgba(*this, pixels, stride);
  1576. break;
  1577. default:
  1578. // unimplemented convert type
  1579. break;
  1580. }
  1581. }
  1582. else
  1583. {
  1584. if (type == PIXEL_RGB || type == PIXEL_BGR)
  1585. to_rgb(*this, pixels, stride);
  1586. if (type == PIXEL_GRAY)
  1587. to_gray(*this, pixels, stride);
  1588. if (type == PIXEL_RGBA)
  1589. to_rgba(*this, pixels, stride);
  1590. }
  1591. }
  1592. void Mat::to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const
  1593. {
  1594. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  1595. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  1596. {
  1597. to_pixels_resize(pixels, type, target_width, target_height, target_width * 3);
  1598. }
  1599. else if (type_to == PIXEL_GRAY)
  1600. {
  1601. to_pixels_resize(pixels, type, target_width, target_height, target_width * 1);
  1602. }
  1603. else if (type_to == PIXEL_RGBA)
  1604. {
  1605. to_pixels_resize(pixels, type, target_width, target_height, target_width * 4);
  1606. }
  1607. }
  1608. void Mat::to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const
  1609. {
  1610. if (w == target_width && h == target_height)
  1611. return to_pixels(pixels, type);
  1612. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  1613. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  1614. {
  1615. Mat src(w, h, (size_t)3u, 3);
  1616. to_pixels(src, type);
  1617. resize_bilinear_c3(src, w, h, w * 3, pixels, target_width, target_height, target_stride);
  1618. }
  1619. else if (type_to == PIXEL_GRAY)
  1620. {
  1621. Mat src(w, h, (size_t)1u, 1);
  1622. to_pixels(src, type);
  1623. resize_bilinear_c1(src, w, h, w * 1, pixels, target_width, target_height, target_stride);
  1624. }
  1625. else if (type_to == PIXEL_RGBA)
  1626. {
  1627. Mat src(w, h, (size_t)4u, 4);
  1628. to_pixels(src, type);
  1629. resize_bilinear_c4(src, w, h, w * 4, pixels, target_width, target_height, target_stride);
  1630. }
  1631. }
  1632. #endif // NCNN_PIXEL
  1633. } // namespace ncnn