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 78 kB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520
  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 <algorithm>
  16. #include <limits.h>
  17. #include <math.h>
  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. #endif // __aarch64__
  111. #endif // __ARM_NEON
  112. for (; remain > 0; remain--)
  113. {
  114. *ptr0 = rgb[0];
  115. *ptr1 = rgb[1];
  116. *ptr2 = rgb[2];
  117. rgb += 3;
  118. ptr0++;
  119. ptr1++;
  120. ptr2++;
  121. }
  122. rgb += wgap;
  123. }
  124. return 0;
  125. }
  126. static void to_rgb(const Mat& m, unsigned char* rgb, int stride)
  127. {
  128. int w = m.w;
  129. int h = m.h;
  130. const int wgap = stride - w * 3;
  131. if (wgap == 0)
  132. {
  133. w = w * h;
  134. h = 1;
  135. }
  136. const float* ptr0 = m.channel(0);
  137. const float* ptr1 = m.channel(1);
  138. const float* ptr2 = m.channel(2);
  139. for (int y = 0; y < h; y++)
  140. {
  141. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  142. #if __ARM_NEON
  143. int nn = w >> 3;
  144. int remain = w - (nn << 3);
  145. #else
  146. int remain = w;
  147. #endif // __ARM_NEON
  148. #if __ARM_NEON
  149. for (; nn > 0; nn--)
  150. {
  151. float32x4_t _rlow = vld1q_f32(ptr0);
  152. float32x4_t _rhigh = vld1q_f32(ptr0 + 4);
  153. float32x4_t _glow = vld1q_f32(ptr1);
  154. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  155. float32x4_t _blow = vld1q_f32(ptr2);
  156. float32x4_t _bhigh = vld1q_f32(ptr2 + 4);
  157. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  158. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  159. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  160. uint8x8x3_t _rgb;
  161. _rgb.val[0] = vqmovun_s16(_r16);
  162. _rgb.val[1] = vqmovun_s16(_g16);
  163. _rgb.val[2] = vqmovun_s16(_b16);
  164. vst3_u8(rgb, _rgb);
  165. rgb += 3 * 8;
  166. ptr0 += 8;
  167. ptr1 += 8;
  168. ptr2 += 8;
  169. }
  170. #endif // __ARM_NEON
  171. for (; remain > 0; remain--)
  172. {
  173. rgb[0] = SATURATE_CAST_UCHAR(*ptr0);
  174. rgb[1] = SATURATE_CAST_UCHAR(*ptr1);
  175. rgb[2] = SATURATE_CAST_UCHAR(*ptr2);
  176. rgb += 3;
  177. ptr0++;
  178. ptr1++;
  179. ptr2++;
  180. }
  181. #undef SATURATE_CAST_UCHAR
  182. rgb += wgap;
  183. }
  184. }
  185. static int from_gray(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  186. {
  187. m.create(w, h, 1, 4u, allocator);
  188. if (m.empty())
  189. return -100;
  190. const int wgap = stride - w;
  191. if (wgap == 0)
  192. {
  193. w = w * h;
  194. h = 1;
  195. }
  196. float* ptr = m;
  197. for (int y = 0; y < h; y++)
  198. {
  199. #if __ARM_NEON
  200. int nn = w >> 4;
  201. int remain = w - (nn << 4);
  202. #else
  203. int remain = w;
  204. #endif // __ARM_NEON
  205. #if __ARM_NEON
  206. #if __aarch64__
  207. for (; nn > 0; nn--)
  208. {
  209. uint8x16_t _gray = vld1q_u8(gray);
  210. uint16x8_t _gray16_0 = vmovl_u8(vget_low_u8(_gray));
  211. uint16x8_t _gray16_1 = vmovl_u8(vget_high_u8(_gray));
  212. float32x4_t _graylow_0 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_0)));
  213. float32x4_t _grayhigh_0 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_0)));
  214. float32x4_t _graylow_1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_1)));
  215. float32x4_t _grayhigh_1 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_1)));
  216. vst1q_f32(ptr, _graylow_0);
  217. vst1q_f32(ptr + 4, _grayhigh_0);
  218. vst1q_f32(ptr + 8, _graylow_1);
  219. vst1q_f32(ptr + 12, _grayhigh_1);
  220. gray += 16;
  221. ptr += 16;
  222. }
  223. #else
  224. if (nn > 0)
  225. {
  226. asm volatile(
  227. "0: \n"
  228. "pld [%1, #128] \n"
  229. "vld1.u8 {d0,d1}, [%1]! \n"
  230. "vmovl.u8 q8, d0 \n"
  231. "vmovl.u8 q9, d1 \n"
  232. "vmovl.u16 q0, d16 \n"
  233. "vmovl.u16 q1, d17 \n"
  234. "vmovl.u16 q2, d18 \n"
  235. "vmovl.u16 q3, d19 \n"
  236. "vcvt.f32.u32 q0, q0 \n"
  237. "vcvt.f32.u32 q1, q1 \n"
  238. "vcvt.f32.u32 q2, q2 \n"
  239. "vcvt.f32.u32 q3, q3 \n"
  240. "subs %0, #1 \n"
  241. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  242. "vst1.f32 {d4-d7}, [%2 :128]! \n"
  243. "bne 0b \n"
  244. : "=r"(nn), // %0
  245. "=r"(gray), // %1
  246. "=r"(ptr) // %2
  247. : "0"(nn),
  248. "1"(gray),
  249. "2"(ptr)
  250. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9");
  251. }
  252. #endif // __aarch64__
  253. #endif // __ARM_NEON
  254. for (; remain > 0; remain--)
  255. {
  256. *ptr = *gray;
  257. gray++;
  258. ptr++;
  259. }
  260. gray += wgap;
  261. }
  262. return 0;
  263. }
  264. static void to_gray(const Mat& m, unsigned char* gray, int stride)
  265. {
  266. int w = m.w;
  267. int h = m.h;
  268. const int wgap = stride - w;
  269. if (wgap == 0)
  270. {
  271. w = w * h;
  272. h = 1;
  273. }
  274. const float* ptr = m;
  275. for (int y = 0; y < h; y++)
  276. {
  277. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  278. #if __ARM_NEON
  279. int nn = w >> 3;
  280. int remain = w - (nn << 3);
  281. #else
  282. int remain = w;
  283. #endif // __ARM_NEON
  284. #if __ARM_NEON
  285. for (; nn > 0; nn--)
  286. {
  287. float32x4_t _glow = vld1q_f32(ptr);
  288. float32x4_t _ghigh = vld1q_f32(ptr + 4);
  289. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  290. uint8x8_t _gray = vqmovun_s16(_g16);
  291. vst1_u8(gray, _gray);
  292. gray += 8;
  293. ptr += 8;
  294. }
  295. #endif // __ARM_NEON
  296. for (; remain > 0; remain--)
  297. {
  298. *gray = SATURATE_CAST_UCHAR(*ptr);
  299. gray++;
  300. ptr++;
  301. }
  302. #undef SATURATE_CAST_UCHAR
  303. gray += wgap;
  304. }
  305. }
  306. static int from_rgba(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  307. {
  308. m.create(w, h, 4, 4u, allocator);
  309. if (m.empty())
  310. return -100;
  311. const int wgap = stride - w * 4;
  312. if (wgap == 0)
  313. {
  314. w = w * h;
  315. h = 1;
  316. }
  317. float* ptr0 = m.channel(0);
  318. float* ptr1 = m.channel(1);
  319. float* ptr2 = m.channel(2);
  320. float* ptr3 = m.channel(3);
  321. for (int y = 0; y < h; y++)
  322. {
  323. #if __ARM_NEON
  324. int nn = w >> 3;
  325. int remain = w - (nn << 3);
  326. #else
  327. int remain = w;
  328. #endif // __ARM_NEON
  329. #if __ARM_NEON
  330. #if __aarch64__
  331. for (; nn > 0; nn--)
  332. {
  333. uint8x8x4_t _rgba = vld4_u8(rgba);
  334. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  335. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  336. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  337. int16x8_t _a16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[3]));
  338. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  339. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  340. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  341. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  342. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  343. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  344. float32x4_t _alow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_a16)));
  345. float32x4_t _ahigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_a16)));
  346. vst1q_f32(ptr0, _rlow);
  347. vst1q_f32(ptr0 + 4, _rhigh);
  348. vst1q_f32(ptr1, _glow);
  349. vst1q_f32(ptr1 + 4, _ghigh);
  350. vst1q_f32(ptr2, _blow);
  351. vst1q_f32(ptr2 + 4, _bhigh);
  352. vst1q_f32(ptr3, _alow);
  353. vst1q_f32(ptr3 + 4, _ahigh);
  354. rgba += 4 * 8;
  355. ptr0 += 8;
  356. ptr1 += 8;
  357. ptr2 += 8;
  358. ptr3 += 8;
  359. }
  360. #else
  361. if (nn > 0)
  362. {
  363. asm volatile(
  364. "0: \n"
  365. "pld [%1, #256] \n"
  366. "vld4.u8 {d0-d3}, [%1]! \n"
  367. "vmovl.u8 q8, d0 \n"
  368. "vmovl.u8 q9, d1 \n"
  369. "vmovl.u8 q10, d2 \n"
  370. "vmovl.u8 q11, d3 \n"
  371. "vmovl.u16 q0, d16 \n"
  372. "vmovl.u16 q1, d17 \n"
  373. "vmovl.u16 q2, d18 \n"
  374. "vmovl.u16 q3, d19 \n"
  375. "vmovl.u16 q8, d20 \n"
  376. "vmovl.u16 q9, d21 \n"
  377. "vmovl.u16 q10, d22 \n"
  378. "vmovl.u16 q11, d23 \n"
  379. "vcvt.f32.u32 q0, q0 \n"
  380. "vcvt.f32.u32 q1, q1 \n"
  381. "vcvt.f32.u32 q2, q2 \n"
  382. "vcvt.f32.u32 q3, q3 \n"
  383. "vcvt.f32.u32 q8, q8 \n"
  384. "vcvt.f32.u32 q9, q9 \n"
  385. "subs %0, #1 \n"
  386. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  387. "vcvt.f32.u32 q10, q10 \n"
  388. "vcvt.f32.u32 q11, q11 \n"
  389. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  390. "vst1.f32 {d16-d19}, [%4 :128]!\n"
  391. "vst1.f32 {d20-d23}, [%5 :128]!\n"
  392. "bne 0b \n"
  393. : "=r"(nn), // %0
  394. "=r"(rgba), // %1
  395. "=r"(ptr0), // %2
  396. "=r"(ptr1), // %3
  397. "=r"(ptr2), // %4
  398. "=r"(ptr3) // %5
  399. : "0"(nn),
  400. "1"(rgba),
  401. "2"(ptr0),
  402. "3"(ptr1),
  403. "4"(ptr2),
  404. "5"(ptr3)
  405. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11");
  406. }
  407. #endif // __aarch64__
  408. #endif // __ARM_NEON
  409. for (; remain > 0; remain--)
  410. {
  411. *ptr0 = rgba[0];
  412. *ptr1 = rgba[1];
  413. *ptr2 = rgba[2];
  414. *ptr3 = rgba[3];
  415. rgba += 4;
  416. ptr0++;
  417. ptr1++;
  418. ptr2++;
  419. ptr3++;
  420. }
  421. rgba += wgap;
  422. }
  423. return 0;
  424. }
  425. static void to_rgba(const Mat& m, unsigned char* rgba, int stride)
  426. {
  427. int w = m.w;
  428. int h = m.h;
  429. const int wgap = stride - w * 4;
  430. if (wgap == 0)
  431. {
  432. w = w * h;
  433. h = 1;
  434. }
  435. const float* ptr0 = m.channel(0);
  436. const float* ptr1 = m.channel(1);
  437. const float* ptr2 = m.channel(2);
  438. const float* ptr3 = m.channel(3);
  439. for (int y = 0; y < h; y++)
  440. {
  441. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  442. #if __ARM_NEON
  443. int nn = w >> 3;
  444. int remain = w - (nn << 3);
  445. #else
  446. int remain = w;
  447. #endif // __ARM_NEON
  448. #if __ARM_NEON
  449. for (; nn > 0; nn--)
  450. {
  451. float32x4_t _rlow = vld1q_f32(ptr0);
  452. float32x4_t _rhigh = vld1q_f32(ptr0 + 4);
  453. float32x4_t _glow = vld1q_f32(ptr1);
  454. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  455. float32x4_t _blow = vld1q_f32(ptr2);
  456. float32x4_t _bhigh = vld1q_f32(ptr2 + 4);
  457. float32x4_t _alow = vld1q_f32(ptr3);
  458. float32x4_t _ahigh = vld1q_f32(ptr3 + 4);
  459. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  460. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  461. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  462. int16x8_t _a16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_alow)), vmovn_s32(vcvtq_s32_f32(_ahigh)));
  463. uint8x8x4_t _rgba;
  464. _rgba.val[0] = vqmovun_s16(_r16);
  465. _rgba.val[1] = vqmovun_s16(_g16);
  466. _rgba.val[2] = vqmovun_s16(_b16);
  467. _rgba.val[3] = vqmovun_s16(_a16);
  468. vst4_u8(rgba, _rgba);
  469. rgba += 4 * 8;
  470. ptr0 += 8;
  471. ptr1 += 8;
  472. ptr2 += 8;
  473. ptr3 += 8;
  474. }
  475. #endif // __ARM_NEON
  476. for (; remain > 0; remain--)
  477. {
  478. rgba[0] = SATURATE_CAST_UCHAR(*ptr0);
  479. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  480. rgba[2] = SATURATE_CAST_UCHAR(*ptr2);
  481. rgba[3] = SATURATE_CAST_UCHAR(*ptr3);
  482. rgba += 4;
  483. ptr0++;
  484. ptr1++;
  485. ptr2++;
  486. ptr3++;
  487. }
  488. #undef SATURATE_CAST_UCHAR
  489. rgba += wgap;
  490. }
  491. }
  492. static int from_rgb2bgr(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  493. {
  494. m.create(w, h, 3, 4u, allocator);
  495. if (m.empty())
  496. return -100;
  497. const int wgap = stride - w * 3;
  498. if (wgap == 0)
  499. {
  500. w = w * h;
  501. h = 1;
  502. }
  503. float* ptr0 = m.channel(0);
  504. float* ptr1 = m.channel(1);
  505. float* ptr2 = m.channel(2);
  506. for (int y = 0; y < h; y++)
  507. {
  508. #if __ARM_NEON
  509. int nn = w >> 3;
  510. int remain = w - (nn << 3);
  511. #else
  512. int remain = w;
  513. #endif // __ARM_NEON
  514. #if __ARM_NEON
  515. #if __aarch64__
  516. for (; nn > 0; nn--)
  517. {
  518. uint8x8x3_t _rgb = vld3_u8(rgb);
  519. uint16x8_t _r16 = vmovl_u8(_rgb.val[0]);
  520. uint16x8_t _g16 = vmovl_u8(_rgb.val[1]);
  521. uint16x8_t _b16 = vmovl_u8(_rgb.val[2]);
  522. float32x4_t _rlow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_r16)));
  523. float32x4_t _rhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_r16)));
  524. float32x4_t _glow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_g16)));
  525. float32x4_t _ghigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_g16)));
  526. float32x4_t _blow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_b16)));
  527. float32x4_t _bhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_b16)));
  528. vst1q_f32(ptr2, _rlow);
  529. vst1q_f32(ptr2 + 4, _rhigh);
  530. vst1q_f32(ptr1, _glow);
  531. vst1q_f32(ptr1 + 4, _ghigh);
  532. vst1q_f32(ptr0, _blow);
  533. vst1q_f32(ptr0 + 4, _bhigh);
  534. rgb += 3 * 8;
  535. ptr0 += 8;
  536. ptr1 += 8;
  537. ptr2 += 8;
  538. }
  539. #else
  540. if (nn > 0)
  541. {
  542. asm volatile(
  543. "0: \n"
  544. "pld [%1, #256] \n"
  545. "vld3.u8 {d0-d2}, [%1]! \n"
  546. "vmovl.u8 q8, d0 \n"
  547. "vmovl.u8 q9, d1 \n"
  548. "vmovl.u8 q10, d2 \n"
  549. "vmovl.u16 q0, d16 \n"
  550. "vmovl.u16 q1, d17 \n"
  551. "vmovl.u16 q2, d18 \n"
  552. "vmovl.u16 q3, d19 \n"
  553. "vmovl.u16 q8, d20 \n"
  554. "vmovl.u16 q9, d21 \n"
  555. "vcvt.f32.u32 q0, q0 \n"
  556. "vcvt.f32.u32 q1, q1 \n"
  557. "vcvt.f32.u32 q2, q2 \n"
  558. "vcvt.f32.u32 q3, q3 \n"
  559. "vcvt.f32.u32 q8, q8 \n"
  560. "subs %0, #1 \n"
  561. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  562. "vcvt.f32.u32 q9, q9 \n"
  563. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  564. "vst1.f32 {d16-d19}, [%2 :128]!\n"
  565. "bne 0b \n"
  566. : "=r"(nn), // %0
  567. "=r"(rgb), // %1
  568. "=r"(ptr0), // %2
  569. "=r"(ptr1), // %3
  570. "=r"(ptr2) // %4
  571. : "0"(nn),
  572. "1"(rgb),
  573. "2"(ptr0),
  574. "3"(ptr1),
  575. "4"(ptr2)
  576. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10");
  577. }
  578. #endif // __aarch64__
  579. #endif // __ARM_NEON
  580. for (; remain > 0; remain--)
  581. {
  582. *ptr0 = rgb[2];
  583. *ptr1 = rgb[1];
  584. *ptr2 = rgb[0];
  585. rgb += 3;
  586. ptr0++;
  587. ptr1++;
  588. ptr2++;
  589. }
  590. rgb += wgap;
  591. }
  592. return 0;
  593. }
  594. static void to_bgr2rgb(const Mat& m, unsigned char* rgb, int stride)
  595. {
  596. int w = m.w;
  597. int h = m.h;
  598. const int wgap = stride - w * 3;
  599. if (wgap == 0)
  600. {
  601. w = w * h;
  602. h = 1;
  603. }
  604. const float* ptr0 = m.channel(0);
  605. const float* ptr1 = m.channel(1);
  606. const float* ptr2 = m.channel(2);
  607. for (int y = 0; y < h; y++)
  608. {
  609. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  610. #if __ARM_NEON
  611. int nn = w >> 3;
  612. int remain = w - (nn << 3);
  613. #else
  614. int remain = w;
  615. #endif // __ARM_NEON
  616. #if __ARM_NEON
  617. for (; nn > 0; nn--)
  618. {
  619. float32x4_t _rlow = vld1q_f32(ptr2);
  620. float32x4_t _rhigh = vld1q_f32(ptr2 + 4);
  621. float32x4_t _glow = vld1q_f32(ptr1);
  622. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  623. float32x4_t _blow = vld1q_f32(ptr0);
  624. float32x4_t _bhigh = vld1q_f32(ptr0 + 4);
  625. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  626. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  627. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  628. uint8x8x3_t _rgb;
  629. _rgb.val[0] = vqmovun_s16(_r16);
  630. _rgb.val[1] = vqmovun_s16(_g16);
  631. _rgb.val[2] = vqmovun_s16(_b16);
  632. vst3_u8(rgb, _rgb);
  633. rgb += 3 * 8;
  634. ptr0 += 8;
  635. ptr1 += 8;
  636. ptr2 += 8;
  637. }
  638. #endif // __ARM_NEON
  639. for (; remain > 0; remain--)
  640. {
  641. rgb[2] = SATURATE_CAST_UCHAR(*ptr0);
  642. rgb[1] = SATURATE_CAST_UCHAR(*ptr1);
  643. rgb[0] = SATURATE_CAST_UCHAR(*ptr2);
  644. rgb += 3;
  645. ptr0++;
  646. ptr1++;
  647. ptr2++;
  648. }
  649. #undef SATURATE_CAST_UCHAR
  650. rgb += wgap;
  651. }
  652. }
  653. static int from_rgb2gray(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  654. {
  655. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  656. const unsigned char Y_shift = 8; //14
  657. const unsigned char R2Y = 77;
  658. const unsigned char G2Y = 150;
  659. const unsigned char B2Y = 29;
  660. m.create(w, h, 1, 4u, allocator);
  661. if (m.empty())
  662. return -100;
  663. const int wgap = stride - w * 3;
  664. if (wgap == 0)
  665. {
  666. w = w * h;
  667. h = 1;
  668. }
  669. float* ptr = m;
  670. for (int y = 0; y < h; y++)
  671. {
  672. #if __ARM_NEON
  673. int nn = w >> 3;
  674. int remain = w - (nn << 3);
  675. #else
  676. int remain = w;
  677. #endif // __ARM_NEON
  678. #if __ARM_NEON
  679. #if __aarch64__
  680. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  681. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  682. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  683. for (; nn > 0; nn--)
  684. {
  685. uint8x8x3_t _rgb = vld3_u8(rgb);
  686. uint16x8_t _y16 = vmull_u8(_rgb.val[0], _R2Y);
  687. _y16 = vmlal_u8(_y16, _rgb.val[1], _G2Y);
  688. _y16 = vmlal_u8(_y16, _rgb.val[2], _B2Y);
  689. _y16 = vshrq_n_u16(_y16, Y_shift);
  690. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  691. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  692. vst1q_f32(ptr, _ylow);
  693. vst1q_f32(ptr + 4, _yhigh);
  694. rgb += 3 * 8;
  695. ptr += 8;
  696. }
  697. #else
  698. if (nn > 0)
  699. {
  700. asm volatile(
  701. "vdup.u8 d16, %6 \n"
  702. "vdup.u8 d17, %7 \n"
  703. "vdup.u8 d18, %8 \n"
  704. "0: \n"
  705. "pld [%1, #256] \n"
  706. "vld3.u8 {d0-d2}, [%1]! \n"
  707. "vmull.u8 q2, d0, d16 \n"
  708. "vmlal.u8 q2, d1, d17 \n"
  709. "vmlal.u8 q2, d2, d18 \n"
  710. "vshr.u16 q2, q2, #8 \n" // Y_shift
  711. "vmovl.u16 q0, d4 \n"
  712. "vmovl.u16 q1, d5 \n"
  713. "vcvt.f32.u32 q0, q0 \n"
  714. "vcvt.f32.u32 q1, q1 \n"
  715. "subs %0, #1 \n"
  716. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  717. "bne 0b \n"
  718. : "=r"(nn), // %0
  719. "=r"(rgb), // %1
  720. "=r"(ptr) // %2
  721. : "0"(nn),
  722. "1"(rgb),
  723. "2"(ptr),
  724. "r"(R2Y), // %6
  725. "r"(G2Y), // %7
  726. "r"(B2Y) // %8
  727. : "cc", "memory", "q0", "q1", "q2", "q8", "q9");
  728. }
  729. #endif // __aarch64__
  730. #endif // __ARM_NEON
  731. for (; remain > 0; remain--)
  732. {
  733. *ptr = static_cast<float>((rgb[0] * R2Y + rgb[1] * G2Y + rgb[2] * B2Y) >> Y_shift);
  734. rgb += 3;
  735. ptr++;
  736. }
  737. rgb += wgap;
  738. }
  739. return 0;
  740. }
  741. static int from_rgb2rgba(const unsigned char* rgb, int w, int h, int stride, Mat& m, Allocator* allocator)
  742. {
  743. m.create(w, h, 4, 4u, allocator);
  744. if (m.empty())
  745. return -100;
  746. Mat rgb_channels = m.channel_range(0, 3);
  747. from_rgb(rgb, w, h, stride, rgb_channels, allocator);
  748. Mat alpha_channel = m.channel(3);
  749. alpha_channel.fill(255.f);
  750. return 0;
  751. }
  752. static void to_rgb2rgba(const Mat& m, unsigned char* rgba, int stride)
  753. {
  754. int w = m.w;
  755. int h = m.h;
  756. const int wgap = stride - w * 4;
  757. if (wgap == 0)
  758. {
  759. w = w * h;
  760. h = 1;
  761. }
  762. const float* ptr0 = m.channel(0);
  763. const float* ptr1 = m.channel(1);
  764. const float* ptr2 = m.channel(2);
  765. for (int y = 0; y < h; y++)
  766. {
  767. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  768. #if __ARM_NEON
  769. int nn = w >> 3;
  770. int remain = w - (nn << 3);
  771. #else
  772. int remain = w;
  773. #endif // __ARM_NEON
  774. #if __ARM_NEON
  775. uint8x8_t _a = vdup_n_u8(255);
  776. for (; nn > 0; nn--)
  777. {
  778. float32x4_t _rlow = vld1q_f32(ptr0);
  779. float32x4_t _rhigh = vld1q_f32(ptr0 + 4);
  780. float32x4_t _glow = vld1q_f32(ptr1);
  781. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  782. float32x4_t _blow = vld1q_f32(ptr2);
  783. float32x4_t _bhigh = vld1q_f32(ptr2 + 4);
  784. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  785. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  786. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  787. uint8x8x4_t _rgba;
  788. _rgba.val[0] = vqmovun_s16(_r16);
  789. _rgba.val[1] = vqmovun_s16(_g16);
  790. _rgba.val[2] = vqmovun_s16(_b16);
  791. _rgba.val[3] = _a;
  792. vst4_u8(rgba, _rgba);
  793. rgba += 4 * 8;
  794. ptr0 += 8;
  795. ptr1 += 8;
  796. ptr2 += 8;
  797. }
  798. #endif // __ARM_NEON
  799. for (; remain > 0; remain--)
  800. {
  801. rgba[0] = SATURATE_CAST_UCHAR(*ptr0);
  802. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  803. rgba[2] = SATURATE_CAST_UCHAR(*ptr2);
  804. rgba[3] = 255;
  805. rgba += 4;
  806. ptr0++;
  807. ptr1++;
  808. ptr2++;
  809. }
  810. #undef SATURATE_CAST_UCHAR
  811. rgba += wgap;
  812. }
  813. }
  814. static int from_bgr2gray(const unsigned char* bgr, int w, int h, int stride, Mat& m, Allocator* allocator)
  815. {
  816. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  817. const unsigned char Y_shift = 8; //14
  818. const unsigned char R2Y = 77;
  819. const unsigned char G2Y = 150;
  820. const unsigned char B2Y = 29;
  821. m.create(w, h, 1, 4u, allocator);
  822. if (m.empty())
  823. return -100;
  824. const int wgap = stride - w * 3;
  825. if (wgap == 0)
  826. {
  827. w = w * h;
  828. h = 1;
  829. }
  830. float* ptr = m;
  831. for (int y = 0; y < h; y++)
  832. {
  833. #if __ARM_NEON
  834. int nn = w >> 3;
  835. int remain = w - (nn << 3);
  836. #else
  837. int remain = w;
  838. #endif // __ARM_NEON
  839. #if __ARM_NEON
  840. #if __aarch64__
  841. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  842. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  843. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  844. for (; nn > 0; nn--)
  845. {
  846. uint8x8x3_t _rgb = vld3_u8(bgr);
  847. uint16x8_t _y16 = vmull_u8(_rgb.val[2], _R2Y);
  848. _y16 = vmlal_u8(_y16, _rgb.val[1], _G2Y);
  849. _y16 = vmlal_u8(_y16, _rgb.val[0], _B2Y);
  850. _y16 = vshrq_n_u16(_y16, Y_shift);
  851. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  852. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  853. vst1q_f32(ptr, _ylow);
  854. vst1q_f32(ptr + 4, _yhigh);
  855. bgr += 3 * 8;
  856. ptr += 8;
  857. }
  858. #else
  859. if (nn > 0)
  860. {
  861. asm volatile(
  862. "vdup.u8 d16, %6 \n"
  863. "vdup.u8 d17, %7 \n"
  864. "vdup.u8 d18, %8 \n"
  865. "0: \n"
  866. "pld [%1, #256] \n"
  867. "vld3.u8 {d0-d2}, [%1]! \n"
  868. "vmull.u8 q2, d2, d16 \n"
  869. "vmlal.u8 q2, d1, d17 \n"
  870. "vmlal.u8 q2, d0, d18 \n"
  871. "vshr.u16 q2, q2, #8 \n" // Y_shift
  872. "vmovl.u16 q0, d4 \n"
  873. "vmovl.u16 q1, d5 \n"
  874. "vcvt.f32.u32 q0, q0 \n"
  875. "vcvt.f32.u32 q1, q1 \n"
  876. "subs %0, #1 \n"
  877. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  878. "bne 0b \n"
  879. : "=r"(nn), // %0
  880. "=r"(bgr), // %1
  881. "=r"(ptr) // %2
  882. : "0"(nn),
  883. "1"(bgr),
  884. "2"(ptr),
  885. "r"(R2Y), // %6
  886. "r"(G2Y), // %7
  887. "r"(B2Y) // %8
  888. : "cc", "memory", "q0", "q1", "q2", "q8", "q9");
  889. }
  890. #endif // __aarch64__
  891. #endif // __ARM_NEON
  892. for (; remain > 0; remain--)
  893. {
  894. *ptr = static_cast<float>((bgr[2] * R2Y + bgr[1] * G2Y + bgr[0] * B2Y) >> Y_shift);
  895. bgr += 3;
  896. ptr++;
  897. }
  898. bgr += wgap;
  899. }
  900. return 0;
  901. }
  902. static int from_bgr2rgba(const unsigned char* bgr, int w, int h, int stride, Mat& m, Allocator* allocator)
  903. {
  904. m.create(w, h, 4, 4u, allocator);
  905. if (m.empty())
  906. return -100;
  907. Mat rgb_channels = m.channel_range(0, 3);
  908. from_rgb2bgr(bgr, w, h, stride, rgb_channels, allocator);
  909. Mat alpha_channel = m.channel(3);
  910. alpha_channel.fill(255.f);
  911. return 0;
  912. }
  913. static void to_bgr2rgba(const Mat& m, unsigned char* rgba, int stride)
  914. {
  915. int w = m.w;
  916. int h = m.h;
  917. const int wgap = stride - w * 4;
  918. if (wgap == 0)
  919. {
  920. w = w * h;
  921. h = 1;
  922. }
  923. const float* ptr0 = m.channel(0);
  924. const float* ptr1 = m.channel(1);
  925. const float* ptr2 = m.channel(2);
  926. for (int y = 0; y < h; y++)
  927. {
  928. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  929. #if __ARM_NEON
  930. int nn = w >> 3;
  931. int remain = w - (nn << 3);
  932. #else
  933. int remain = w;
  934. #endif // __ARM_NEON
  935. #if __ARM_NEON
  936. uint8x8_t _a = vdup_n_u8(255);
  937. for (; nn > 0; nn--)
  938. {
  939. float32x4_t _rlow = vld1q_f32(ptr2);
  940. float32x4_t _rhigh = vld1q_f32(ptr2 + 4);
  941. float32x4_t _glow = vld1q_f32(ptr1);
  942. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  943. float32x4_t _blow = vld1q_f32(ptr0);
  944. float32x4_t _bhigh = vld1q_f32(ptr0 + 4);
  945. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  946. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  947. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  948. uint8x8x4_t _rgba;
  949. _rgba.val[0] = vqmovun_s16(_r16);
  950. _rgba.val[1] = vqmovun_s16(_g16);
  951. _rgba.val[2] = vqmovun_s16(_b16);
  952. _rgba.val[3] = _a;
  953. vst4_u8(rgba, _rgba);
  954. rgba += 4 * 8;
  955. ptr0 += 8;
  956. ptr1 += 8;
  957. ptr2 += 8;
  958. }
  959. #endif // __ARM_NEON
  960. for (; remain > 0; remain--)
  961. {
  962. rgba[0] = SATURATE_CAST_UCHAR(*ptr2);
  963. rgba[1] = SATURATE_CAST_UCHAR(*ptr1);
  964. rgba[2] = SATURATE_CAST_UCHAR(*ptr0);
  965. rgba[3] = 255;
  966. rgba += 4;
  967. ptr0++;
  968. ptr1++;
  969. ptr2++;
  970. }
  971. #undef SATURATE_CAST_UCHAR
  972. rgba += wgap;
  973. }
  974. }
  975. static int from_gray2rgb(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  976. {
  977. m.create(w, h, 3, 4u, allocator);
  978. if (m.empty())
  979. return -100;
  980. const int wgap = stride - w;
  981. if (wgap == 0)
  982. {
  983. w = w * h;
  984. h = 1;
  985. }
  986. float* ptr0 = m.channel(0);
  987. float* ptr1 = m.channel(1);
  988. float* ptr2 = m.channel(2);
  989. for (int y = 0; y < h; y++)
  990. {
  991. #if __ARM_NEON
  992. int nn = w >> 4;
  993. int remain = w - (nn << 4);
  994. #else
  995. int remain = w;
  996. #endif // __ARM_NEON
  997. #if __ARM_NEON
  998. #if __aarch64__
  999. for (; nn > 0; nn--)
  1000. {
  1001. uint8x16_t _gray = vld1q_u8(gray);
  1002. uint16x8_t _gray16_0 = vmovl_u8(vget_low_u8(_gray));
  1003. uint16x8_t _gray16_1 = vmovl_u8(vget_high_u8(_gray));
  1004. float32x4_t _graylow_0 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_0)));
  1005. float32x4_t _grayhigh_0 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_0)));
  1006. float32x4_t _graylow_1 = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_gray16_1)));
  1007. float32x4_t _grayhigh_1 = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_gray16_1)));
  1008. vst1q_f32(ptr0, _graylow_0);
  1009. vst1q_f32(ptr0 + 4, _grayhigh_0);
  1010. vst1q_f32(ptr0 + 8, _graylow_1);
  1011. vst1q_f32(ptr0 + 12, _grayhigh_1);
  1012. vst1q_f32(ptr1, _graylow_0);
  1013. vst1q_f32(ptr1 + 4, _grayhigh_0);
  1014. vst1q_f32(ptr1 + 8, _graylow_1);
  1015. vst1q_f32(ptr1 + 12, _grayhigh_1);
  1016. vst1q_f32(ptr2, _graylow_0);
  1017. vst1q_f32(ptr2 + 4, _grayhigh_0);
  1018. vst1q_f32(ptr2 + 8, _graylow_1);
  1019. vst1q_f32(ptr2 + 12, _grayhigh_1);
  1020. gray += 16;
  1021. ptr0 += 16;
  1022. ptr1 += 16;
  1023. ptr2 += 16;
  1024. }
  1025. #else
  1026. if (nn > 0)
  1027. {
  1028. asm volatile(
  1029. "0: \n"
  1030. "pld [%1, #128] \n"
  1031. "vld1.u8 {d0,d1}, [%1]! \n"
  1032. "vmovl.u8 q8, d0 \n"
  1033. "vmovl.u8 q9, d1 \n"
  1034. "vmovl.u16 q0, d16 \n"
  1035. "vmovl.u16 q1, d17 \n"
  1036. "vmovl.u16 q2, d18 \n"
  1037. "vmovl.u16 q3, d19 \n"
  1038. "vcvt.f32.u32 q0, q0 \n"
  1039. "vcvt.f32.u32 q1, q1 \n"
  1040. "vcvt.f32.u32 q2, q2 \n"
  1041. "vcvt.f32.u32 q3, q3 \n"
  1042. "subs %0, #1 \n"
  1043. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1044. "vst1.f32 {d4-d7}, [%2 :128]! \n"
  1045. "vst1.f32 {d0-d3}, [%3 :128]! \n"
  1046. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1047. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  1048. "vst1.f32 {d4-d7}, [%4 :128]! \n"
  1049. "bne 0b \n"
  1050. : "=r"(nn), // %0
  1051. "=r"(gray), // %1
  1052. "=r"(ptr0), // %2
  1053. "=r"(ptr1), // %3
  1054. "=r"(ptr2) // %4
  1055. : "0"(nn),
  1056. "1"(gray),
  1057. "2"(ptr0),
  1058. "3"(ptr1),
  1059. "4"(ptr2)
  1060. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9");
  1061. }
  1062. #endif // __aarch64__
  1063. #endif // __ARM_NEON
  1064. for (; remain > 0; remain--)
  1065. {
  1066. *ptr0 = *gray;
  1067. *ptr1 = *gray;
  1068. *ptr2 = *gray;
  1069. gray++;
  1070. ptr0++;
  1071. ptr1++;
  1072. ptr2++;
  1073. }
  1074. gray += wgap;
  1075. }
  1076. return 0;
  1077. }
  1078. static int from_gray2rgba(const unsigned char* gray, int w, int h, int stride, Mat& m, Allocator* allocator)
  1079. {
  1080. m.create(w, h, 4, 4u, allocator);
  1081. if (m.empty())
  1082. return -100;
  1083. Mat rgb_channels = m.channel_range(0, 3);
  1084. from_gray2rgb(gray, w, h, stride, rgb_channels, allocator);
  1085. Mat alpha_channel = m.channel(3);
  1086. alpha_channel.fill(255.f);
  1087. return 0;
  1088. }
  1089. static void to_gray2rgba(const Mat& m, unsigned char* rgba, int stride)
  1090. {
  1091. int w = m.w;
  1092. int h = m.h;
  1093. const int wgap = stride - w * 4;
  1094. if (wgap == 0)
  1095. {
  1096. w = w * h;
  1097. h = 1;
  1098. }
  1099. const float* ptr = m;
  1100. for (int y = 0; y < h; y++)
  1101. {
  1102. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  1103. #if __ARM_NEON
  1104. int nn = w >> 3;
  1105. int remain = w - (nn << 3);
  1106. #else
  1107. int remain = w;
  1108. #endif // __ARM_NEON
  1109. #if __ARM_NEON
  1110. uint8x8_t _a = vdup_n_u8(255);
  1111. for (; nn > 0; nn--)
  1112. {
  1113. float32x4_t _glow = vld1q_f32(ptr);
  1114. float32x4_t _ghigh = vld1q_f32(ptr + 4);
  1115. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  1116. uint8x8_t _gray = vqmovun_s16(_g16);
  1117. uint8x8x4_t _rgba;
  1118. _rgba.val[0] = _gray;
  1119. _rgba.val[1] = _gray;
  1120. _rgba.val[2] = _gray;
  1121. _rgba.val[3] = _a;
  1122. vst4_u8(rgba, _rgba);
  1123. rgba += 4 * 8;
  1124. ptr += 8;
  1125. }
  1126. #endif // __ARM_NEON
  1127. for (; remain > 0; remain--)
  1128. {
  1129. unsigned char gray = SATURATE_CAST_UCHAR(*ptr);
  1130. rgba[0] = gray;
  1131. rgba[1] = gray;
  1132. rgba[2] = gray;
  1133. rgba[3] = 255;
  1134. rgba += 4;
  1135. ptr++;
  1136. }
  1137. #undef SATURATE_CAST_UCHAR
  1138. rgba += wgap;
  1139. }
  1140. }
  1141. static int from_rgba2rgb(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1142. {
  1143. m.create(w, h, 3, 4u, allocator);
  1144. if (m.empty())
  1145. return -100;
  1146. const int wgap = stride - w * 4;
  1147. if (wgap == 0)
  1148. {
  1149. w = w * h;
  1150. h = 1;
  1151. }
  1152. float* ptr0 = m.channel(0);
  1153. float* ptr1 = m.channel(1);
  1154. float* ptr2 = m.channel(2);
  1155. for (int y = 0; y < h; y++)
  1156. {
  1157. #if __ARM_NEON
  1158. int nn = w >> 3;
  1159. int remain = w - (nn << 3);
  1160. #else
  1161. int remain = w;
  1162. #endif // __ARM_NEON
  1163. #if __ARM_NEON
  1164. #if __aarch64__
  1165. for (; nn > 0; nn--)
  1166. {
  1167. uint8x8x4_t _rgba = vld4_u8(rgba);
  1168. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  1169. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  1170. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  1171. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  1172. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  1173. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  1174. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  1175. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  1176. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  1177. vst1q_f32(ptr0, _rlow);
  1178. vst1q_f32(ptr0 + 4, _rhigh);
  1179. vst1q_f32(ptr1, _glow);
  1180. vst1q_f32(ptr1 + 4, _ghigh);
  1181. vst1q_f32(ptr2, _blow);
  1182. vst1q_f32(ptr2 + 4, _bhigh);
  1183. rgba += 4 * 8;
  1184. ptr0 += 8;
  1185. ptr1 += 8;
  1186. ptr2 += 8;
  1187. }
  1188. #else
  1189. if (nn > 0)
  1190. {
  1191. asm volatile(
  1192. "0: \n"
  1193. "pld [%1, #256] \n"
  1194. "vld4.u8 {d0-d3}, [%1]! \n"
  1195. "vmovl.u8 q8, d0 \n"
  1196. "vmovl.u8 q9, d1 \n"
  1197. "vmovl.u8 q10, d2 \n"
  1198. "vmovl.u16 q0, d16 \n"
  1199. "vmovl.u16 q1, d17 \n"
  1200. "vmovl.u16 q2, d18 \n"
  1201. "vmovl.u16 q3, d19 \n"
  1202. "vmovl.u16 q8, d20 \n"
  1203. "vmovl.u16 q9, d21 \n"
  1204. "vcvt.f32.u32 q0, q0 \n"
  1205. "vcvt.f32.u32 q1, q1 \n"
  1206. "vcvt.f32.u32 q2, q2 \n"
  1207. "vcvt.f32.u32 q3, q3 \n"
  1208. "vcvt.f32.u32 q8, q8 \n"
  1209. "subs %0, #1 \n"
  1210. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1211. "vcvt.f32.u32 q9, q9 \n"
  1212. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1213. "vst1.f32 {d16-d19}, [%4 :128]!\n"
  1214. "bne 0b \n"
  1215. : "=r"(nn), // %0
  1216. "=r"(rgba), // %1
  1217. "=r"(ptr0), // %2
  1218. "=r"(ptr1), // %3
  1219. "=r"(ptr2) // %4
  1220. : "0"(nn),
  1221. "1"(rgba),
  1222. "2"(ptr0),
  1223. "3"(ptr1),
  1224. "4"(ptr2)
  1225. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9");
  1226. }
  1227. #endif // __aarch64__
  1228. #endif // __ARM_NEON
  1229. for (; remain > 0; remain--)
  1230. {
  1231. *ptr0 = rgba[0];
  1232. *ptr1 = rgba[1];
  1233. *ptr2 = rgba[2];
  1234. rgba += 4;
  1235. ptr0++;
  1236. ptr1++;
  1237. ptr2++;
  1238. }
  1239. rgba += wgap;
  1240. }
  1241. return 0;
  1242. }
  1243. static int from_rgba2bgr(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1244. {
  1245. m.create(w, h, 3, 4u, allocator);
  1246. if (m.empty())
  1247. return -100;
  1248. const int wgap = stride - w * 4;
  1249. if (wgap == 0)
  1250. {
  1251. w = w * h;
  1252. h = 1;
  1253. }
  1254. float* ptr0 = m.channel(0);
  1255. float* ptr1 = m.channel(1);
  1256. float* ptr2 = m.channel(2);
  1257. for (int y = 0; y < h; y++)
  1258. {
  1259. #if __ARM_NEON
  1260. int nn = w >> 3;
  1261. int remain = w - (nn << 3);
  1262. #else
  1263. int remain = w;
  1264. #endif // __ARM_NEON
  1265. #if __ARM_NEON
  1266. #if __aarch64__
  1267. for (; nn > 0; nn--)
  1268. {
  1269. uint8x8x4_t _rgba = vld4_u8(rgba);
  1270. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  1271. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  1272. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  1273. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  1274. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  1275. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  1276. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  1277. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  1278. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  1279. vst1q_f32(ptr2, _rlow);
  1280. vst1q_f32(ptr2 + 4, _rhigh);
  1281. vst1q_f32(ptr1, _glow);
  1282. vst1q_f32(ptr1 + 4, _ghigh);
  1283. vst1q_f32(ptr0, _blow);
  1284. vst1q_f32(ptr0 + 4, _bhigh);
  1285. rgba += 4 * 8;
  1286. ptr0 += 8;
  1287. ptr1 += 8;
  1288. ptr2 += 8;
  1289. }
  1290. #else
  1291. if (nn > 0)
  1292. {
  1293. asm volatile(
  1294. "0: \n"
  1295. "pld [%1, #256] \n"
  1296. "vld4.u8 {d0-d3}, [%1]! \n"
  1297. "vmovl.u8 q8, d0 \n"
  1298. "vmovl.u8 q9, d1 \n"
  1299. "vmovl.u8 q10, d2 \n"
  1300. "vmovl.u16 q0, d16 \n"
  1301. "vmovl.u16 q1, d17 \n"
  1302. "vmovl.u16 q2, d18 \n"
  1303. "vmovl.u16 q3, d19 \n"
  1304. "vmovl.u16 q8, d20 \n"
  1305. "vmovl.u16 q9, d21 \n"
  1306. "vcvt.f32.u32 q0, q0 \n"
  1307. "vcvt.f32.u32 q1, q1 \n"
  1308. "vcvt.f32.u32 q2, q2 \n"
  1309. "vcvt.f32.u32 q3, q3 \n"
  1310. "vcvt.f32.u32 q8, q8 \n"
  1311. "subs %0, #1 \n"
  1312. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  1313. "vcvt.f32.u32 q9, q9 \n"
  1314. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1315. "vst1.f32 {d16-d19}, [%2 :128]!\n"
  1316. "bne 0b \n"
  1317. : "=r"(nn), // %0
  1318. "=r"(rgba), // %1
  1319. "=r"(ptr0), // %2
  1320. "=r"(ptr1), // %3
  1321. "=r"(ptr2) // %4
  1322. : "0"(nn),
  1323. "1"(rgba),
  1324. "2"(ptr0),
  1325. "3"(ptr1),
  1326. "4"(ptr2)
  1327. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10");
  1328. }
  1329. #endif // __aarch64__
  1330. #endif // __ARM_NEON
  1331. for (; remain > 0; remain--)
  1332. {
  1333. *ptr0 = rgba[2];
  1334. *ptr1 = rgba[1];
  1335. *ptr2 = rgba[0];
  1336. rgba += 4;
  1337. ptr0++;
  1338. ptr1++;
  1339. ptr2++;
  1340. }
  1341. rgba += wgap;
  1342. }
  1343. return 0;
  1344. }
  1345. static int from_rgba2gray(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1346. {
  1347. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  1348. const unsigned char Y_shift = 8; //14
  1349. const unsigned char R2Y = 77;
  1350. const unsigned char G2Y = 150;
  1351. const unsigned char B2Y = 29;
  1352. m.create(w, h, 1, 4u, allocator);
  1353. if (m.empty())
  1354. return -100;
  1355. const int wgap = stride - w * 4;
  1356. if (wgap == 0)
  1357. {
  1358. w = w * h;
  1359. h = 1;
  1360. }
  1361. float* ptr = m;
  1362. for (int y = 0; y < h; y++)
  1363. {
  1364. #if __ARM_NEON
  1365. int nn = w >> 3;
  1366. int remain = w - (nn << 3);
  1367. #else
  1368. int remain = w;
  1369. #endif // __ARM_NEON
  1370. #if __ARM_NEON
  1371. #if __aarch64__
  1372. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  1373. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  1374. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  1375. for (; nn > 0; nn--)
  1376. {
  1377. uint8x8x4_t _rgba = vld4_u8(rgba);
  1378. uint16x8_t _y16 = vmull_u8(_rgba.val[0], _R2Y);
  1379. _y16 = vmlal_u8(_y16, _rgba.val[1], _G2Y);
  1380. _y16 = vmlal_u8(_y16, _rgba.val[2], _B2Y);
  1381. _y16 = vshrq_n_u16(_y16, Y_shift);
  1382. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  1383. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  1384. vst1q_f32(ptr, _ylow);
  1385. vst1q_f32(ptr + 4, _yhigh);
  1386. rgba += 4 * 8;
  1387. ptr += 8;
  1388. }
  1389. #else
  1390. if (nn > 0)
  1391. {
  1392. asm volatile(
  1393. "vdup.u8 d16, %6 \n"
  1394. "vdup.u8 d17, %7 \n"
  1395. "vdup.u8 d18, %8 \n"
  1396. "0: \n"
  1397. "pld [%1, #256] \n"
  1398. "vld4.u8 {d0-d3}, [%1]! \n"
  1399. "vmull.u8 q2, d0, d16 \n"
  1400. "vmlal.u8 q2, d1, d17 \n"
  1401. "vmlal.u8 q2, d2, d18 \n"
  1402. "vshr.u16 q2, q2, #8 \n" // Y_shift
  1403. "vmovl.u16 q0, d4 \n"
  1404. "vmovl.u16 q1, d5 \n"
  1405. "vcvt.f32.u32 q0, q0 \n"
  1406. "vcvt.f32.u32 q1, q1 \n"
  1407. "subs %0, #1 \n"
  1408. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1409. "bne 0b \n"
  1410. : "=r"(nn), // %0
  1411. "=r"(rgba), // %1
  1412. "=r"(ptr) // %2
  1413. : "0"(nn),
  1414. "1"(rgba),
  1415. "2"(ptr),
  1416. "r"(R2Y), // %6
  1417. "r"(G2Y), // %7
  1418. "r"(B2Y) // %8
  1419. : "cc", "memory", "q0", "q1", "q2", "q8", "q9");
  1420. }
  1421. #endif // __aarch64__
  1422. #endif // __ARM_NEON
  1423. for (; remain > 0; remain--)
  1424. {
  1425. *ptr = static_cast<float>((rgba[0] * R2Y + rgba[1] * G2Y + rgba[2] * B2Y) >> Y_shift);
  1426. rgba += 4;
  1427. ptr++;
  1428. }
  1429. rgba += wgap;
  1430. }
  1431. return 0;
  1432. }
  1433. static int from_rgba2bgra(const unsigned char* rgba, int w, int h, int stride, Mat& m, Allocator* allocator)
  1434. {
  1435. m.create(w, h, 4, 4u, allocator);
  1436. if (m.empty())
  1437. return -100;
  1438. const int wgap = stride - w * 4;
  1439. if (wgap == 0)
  1440. {
  1441. w = w * h;
  1442. h = 1;
  1443. }
  1444. float* ptr0 = m.channel(0);
  1445. float* ptr1 = m.channel(1);
  1446. float* ptr2 = m.channel(2);
  1447. float* ptr3 = m.channel(3);
  1448. for (int y = 0; y < h; y++)
  1449. {
  1450. #if __ARM_NEON
  1451. int nn = w >> 3;
  1452. int remain = w - (nn << 3);
  1453. #else
  1454. int remain = w;
  1455. #endif // __ARM_NEON
  1456. #if __ARM_NEON
  1457. #if __aarch64__
  1458. for (; nn > 0; nn--)
  1459. {
  1460. uint8x8x4_t _rgba = vld4_u8(rgba);
  1461. int16x8_t _r16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[0]));
  1462. int16x8_t _g16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[1]));
  1463. int16x8_t _b16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[2]));
  1464. int16x8_t _a16 = vreinterpretq_s16_u16(vmovl_u8(_rgba.val[3]));
  1465. float32x4_t _rlow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_r16)));
  1466. float32x4_t _rhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_r16)));
  1467. float32x4_t _glow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_g16)));
  1468. float32x4_t _ghigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_g16)));
  1469. float32x4_t _blow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_b16)));
  1470. float32x4_t _bhigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_b16)));
  1471. float32x4_t _alow = vcvtq_f32_s32(vmovl_s16(vget_low_s16(_a16)));
  1472. float32x4_t _ahigh = vcvtq_f32_s32(vmovl_s16(vget_high_s16(_a16)));
  1473. vst1q_f32(ptr2, _rlow);
  1474. vst1q_f32(ptr2 + 4, _rhigh);
  1475. vst1q_f32(ptr1, _glow);
  1476. vst1q_f32(ptr1 + 4, _ghigh);
  1477. vst1q_f32(ptr0, _blow);
  1478. vst1q_f32(ptr0 + 4, _bhigh);
  1479. vst1q_f32(ptr3, _alow);
  1480. vst1q_f32(ptr3 + 4, _ahigh);
  1481. rgba += 4 * 8;
  1482. ptr0 += 8;
  1483. ptr1 += 8;
  1484. ptr2 += 8;
  1485. ptr3 += 8;
  1486. }
  1487. #else
  1488. if (nn > 0)
  1489. {
  1490. asm volatile(
  1491. "0: \n"
  1492. "pld [%1, #256] \n"
  1493. "vld4.u8 {d0-d3}, [%1]! \n"
  1494. "vmovl.u8 q8, d0 \n"
  1495. "vmovl.u8 q9, d1 \n"
  1496. "vmovl.u8 q10, d2 \n"
  1497. "vmovl.u8 q11, d3 \n"
  1498. "vmovl.u16 q0, d16 \n"
  1499. "vmovl.u16 q1, d17 \n"
  1500. "vmovl.u16 q2, d18 \n"
  1501. "vmovl.u16 q3, d19 \n"
  1502. "vmovl.u16 q8, d20 \n"
  1503. "vmovl.u16 q9, d21 \n"
  1504. "vmovl.u16 q10, d22 \n"
  1505. "vmovl.u16 q11, d23 \n"
  1506. "vcvt.f32.u32 q0, q0 \n"
  1507. "vcvt.f32.u32 q1, q1 \n"
  1508. "vcvt.f32.u32 q2, q2 \n"
  1509. "vcvt.f32.u32 q3, q3 \n"
  1510. "vcvt.f32.u32 q8, q8 \n"
  1511. "subs %0, #1 \n"
  1512. "vst1.f32 {d0-d3}, [%4 :128]! \n"
  1513. "vcvt.f32.u32 q9, q9 \n"
  1514. "vcvt.f32.u32 q10, q10 \n"
  1515. "vst1.f32 {d4-d7}, [%3 :128]! \n"
  1516. "vcvt.f32.u32 q11, q11 \n"
  1517. "vst1.f32 {d16-d19}, [%2 :128]!\n"
  1518. "vst1.f32 {d20-d23}, [%5 :128]!\n"
  1519. "bne 0b \n"
  1520. : "=r"(nn), // %0
  1521. "=r"(rgba), // %1
  1522. "=r"(ptr0), // %2
  1523. "=r"(ptr1), // %3
  1524. "=r"(ptr2), // %4
  1525. "=r"(ptr3) // %5
  1526. : "0"(nn),
  1527. "1"(rgba),
  1528. "2"(ptr0),
  1529. "3"(ptr1),
  1530. "4"(ptr2),
  1531. "5"(ptr3)
  1532. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11");
  1533. }
  1534. #endif // __aarch64__
  1535. #endif // __ARM_NEON
  1536. for (; remain > 0; remain--)
  1537. {
  1538. *ptr0 = rgba[2];
  1539. *ptr1 = rgba[1];
  1540. *ptr2 = rgba[0];
  1541. *ptr3 = rgba[3];
  1542. rgba += 4;
  1543. ptr0++;
  1544. ptr1++;
  1545. ptr2++;
  1546. ptr3++;
  1547. }
  1548. rgba += wgap;
  1549. }
  1550. return 0;
  1551. }
  1552. static void to_rgba2bgra(const Mat& m, unsigned char* bgra, int stride)
  1553. {
  1554. int w = m.w;
  1555. int h = m.h;
  1556. const int wgap = stride - w * 4;
  1557. if (wgap == 0)
  1558. {
  1559. w = w * h;
  1560. h = 1;
  1561. }
  1562. const float* ptr0 = m.channel(0);
  1563. const float* ptr1 = m.channel(1);
  1564. const float* ptr2 = m.channel(2);
  1565. const float* ptr3 = m.channel(3);
  1566. for (int y = 0; y < h; y++)
  1567. {
  1568. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  1569. #if __ARM_NEON
  1570. int nn = w >> 3;
  1571. int remain = w - (nn << 3);
  1572. #else
  1573. int remain = w;
  1574. #endif // __ARM_NEON
  1575. #if __ARM_NEON
  1576. for (; nn > 0; nn--)
  1577. {
  1578. float32x4_t _rlow = vld1q_f32(ptr0);
  1579. float32x4_t _rhigh = vld1q_f32(ptr0 + 4);
  1580. float32x4_t _glow = vld1q_f32(ptr1);
  1581. float32x4_t _ghigh = vld1q_f32(ptr1 + 4);
  1582. float32x4_t _blow = vld1q_f32(ptr2);
  1583. float32x4_t _bhigh = vld1q_f32(ptr2 + 4);
  1584. float32x4_t _alow = vld1q_f32(ptr3);
  1585. float32x4_t _ahigh = vld1q_f32(ptr3 + 4);
  1586. int16x8_t _r16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_rlow)), vmovn_s32(vcvtq_s32_f32(_rhigh)));
  1587. int16x8_t _g16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_glow)), vmovn_s32(vcvtq_s32_f32(_ghigh)));
  1588. int16x8_t _b16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_blow)), vmovn_s32(vcvtq_s32_f32(_bhigh)));
  1589. int16x8_t _a16 = vcombine_s16(vmovn_s32(vcvtq_s32_f32(_alow)), vmovn_s32(vcvtq_s32_f32(_ahigh)));
  1590. uint8x8x4_t _bgra;
  1591. _bgra.val[0] = vqmovun_s16(_b16);
  1592. _bgra.val[1] = vqmovun_s16(_g16);
  1593. _bgra.val[2] = vqmovun_s16(_r16);
  1594. _bgra.val[3] = vqmovun_s16(_a16);
  1595. vst4_u8(bgra, _bgra);
  1596. bgra += 4 * 8;
  1597. ptr0 += 8;
  1598. ptr1 += 8;
  1599. ptr2 += 8;
  1600. ptr3 += 8;
  1601. }
  1602. #endif // __ARM_NEON
  1603. for (; remain > 0; remain--)
  1604. {
  1605. bgra[0] = SATURATE_CAST_UCHAR(*ptr2);
  1606. bgra[1] = SATURATE_CAST_UCHAR(*ptr1);
  1607. bgra[2] = SATURATE_CAST_UCHAR(*ptr0);
  1608. bgra[3] = SATURATE_CAST_UCHAR(*ptr3);
  1609. bgra += 4;
  1610. ptr0++;
  1611. ptr1++;
  1612. ptr2++;
  1613. ptr3++;
  1614. }
  1615. #undef SATURATE_CAST_UCHAR
  1616. bgra += wgap;
  1617. }
  1618. }
  1619. static int from_bgra2gray(const unsigned char* bgra, int w, int h, int stride, Mat& m, Allocator* allocator)
  1620. {
  1621. // coeffs for r g b = 0.299f, 0.587f, 0.114f
  1622. const unsigned char Y_shift = 8; //14
  1623. const unsigned char R2Y = 77;
  1624. const unsigned char G2Y = 150;
  1625. const unsigned char B2Y = 29;
  1626. m.create(w, h, 1, 4u, allocator);
  1627. if (m.empty())
  1628. return -100;
  1629. const int wgap = stride - w * 4;
  1630. if (wgap == 0)
  1631. {
  1632. w = w * h;
  1633. h = 1;
  1634. }
  1635. float* ptr = m;
  1636. for (int y = 0; y < h; y++)
  1637. {
  1638. #if __ARM_NEON
  1639. int nn = w >> 3;
  1640. int remain = w - (nn << 3);
  1641. #else
  1642. int remain = w;
  1643. #endif // __ARM_NEON
  1644. #if __ARM_NEON
  1645. #if __aarch64__
  1646. uint8x8_t _R2Y = vdup_n_u8(R2Y);
  1647. uint8x8_t _G2Y = vdup_n_u8(G2Y);
  1648. uint8x8_t _B2Y = vdup_n_u8(B2Y);
  1649. for (; nn > 0; nn--)
  1650. {
  1651. uint8x8x4_t _bgra = vld4_u8(bgra);
  1652. uint16x8_t _y16 = vmull_u8(_bgra.val[2], _R2Y);
  1653. _y16 = vmlal_u8(_y16, _bgra.val[1], _G2Y);
  1654. _y16 = vmlal_u8(_y16, _bgra.val[0], _B2Y);
  1655. _y16 = vshrq_n_u16(_y16, Y_shift);
  1656. float32x4_t _ylow = vcvtq_f32_u32(vmovl_u16(vget_low_u16(_y16)));
  1657. float32x4_t _yhigh = vcvtq_f32_u32(vmovl_u16(vget_high_u16(_y16)));
  1658. vst1q_f32(ptr, _ylow);
  1659. vst1q_f32(ptr + 4, _yhigh);
  1660. bgra += 4 * 8;
  1661. ptr += 8;
  1662. }
  1663. #else
  1664. if (nn > 0)
  1665. {
  1666. asm volatile(
  1667. "vdup.u8 d16, %6 \n"
  1668. "vdup.u8 d17, %7 \n"
  1669. "vdup.u8 d18, %8 \n"
  1670. "0: \n"
  1671. "pld [%1, #256] \n"
  1672. "vld4.u8 {d0-d3}, [%1]! \n"
  1673. "vmull.u8 q2, d2, d16 \n"
  1674. "vmlal.u8 q2, d1, d17 \n"
  1675. "vmlal.u8 q2, d0, d18 \n"
  1676. "vshr.u16 q2, q2, #8 \n" // Y_shift
  1677. "vmovl.u16 q0, d4 \n"
  1678. "vmovl.u16 q1, d5 \n"
  1679. "vcvt.f32.u32 q0, q0 \n"
  1680. "vcvt.f32.u32 q1, q1 \n"
  1681. "subs %0, #1 \n"
  1682. "vst1.f32 {d0-d3}, [%2 :128]! \n"
  1683. "bne 0b \n"
  1684. : "=r"(nn), // %0
  1685. "=r"(bgra), // %1
  1686. "=r"(ptr) // %2
  1687. : "0"(nn),
  1688. "1"(bgra),
  1689. "2"(ptr),
  1690. "r"(R2Y), // %6
  1691. "r"(G2Y), // %7
  1692. "r"(B2Y) // %8
  1693. : "cc", "memory", "q0", "q1", "q2", "q8", "q9");
  1694. }
  1695. #endif // __aarch64__
  1696. #endif // __ARM_NEON
  1697. for (; remain > 0; remain--)
  1698. {
  1699. *ptr = static_cast<float>((bgra[2] * R2Y + bgra[1] * G2Y + bgra[0] * B2Y) >> Y_shift);
  1700. bgra += 4;
  1701. ptr++;
  1702. }
  1703. bgra += wgap;
  1704. }
  1705. return 0;
  1706. }
  1707. void yuv420sp2rgb(const unsigned char* yuv420sp, int w, int h, unsigned char* rgb)
  1708. {
  1709. const unsigned char* yptr = yuv420sp;
  1710. const unsigned char* vuptr = yuv420sp + w * h;
  1711. #if __ARM_NEON
  1712. uint8x8_t _v128 = vdup_n_u8(128);
  1713. int8x8_t _v90 = vdup_n_s8(90);
  1714. int8x8_t _v46 = vdup_n_s8(46);
  1715. int8x8_t _v22 = vdup_n_s8(22);
  1716. int8x8_t _v113 = vdup_n_s8(113);
  1717. #endif // __ARM_NEON
  1718. for (int y = 0; y < h; y += 2)
  1719. {
  1720. const unsigned char* yptr0 = yptr;
  1721. const unsigned char* yptr1 = yptr + w;
  1722. unsigned char* rgb0 = rgb;
  1723. unsigned char* rgb1 = rgb + w * 3;
  1724. #if __ARM_NEON
  1725. int nn = w >> 3;
  1726. int remain = w - (nn << 3);
  1727. #else
  1728. int remain = w;
  1729. #endif // __ARM_NEON
  1730. #if __ARM_NEON
  1731. #if __aarch64__
  1732. for (; nn > 0; nn--)
  1733. {
  1734. int16x8_t _yy0 = vreinterpretq_s16_u16(vshll_n_u8(vld1_u8(yptr0), 6));
  1735. int16x8_t _yy1 = vreinterpretq_s16_u16(vshll_n_u8(vld1_u8(yptr1), 6));
  1736. int8x8_t _vvuu = vreinterpret_s8_u8(vsub_u8(vld1_u8(vuptr), _v128));
  1737. int8x8x2_t _vvvvuuuu = vtrn_s8(_vvuu, _vvuu);
  1738. int8x8_t _vv = _vvvvuuuu.val[0];
  1739. int8x8_t _uu = _vvvvuuuu.val[1];
  1740. int16x8_t _r0 = vmlal_s8(_yy0, _vv, _v90);
  1741. int16x8_t _g0 = vmlsl_s8(_yy0, _vv, _v46);
  1742. _g0 = vmlsl_s8(_g0, _uu, _v22);
  1743. int16x8_t _b0 = vmlal_s8(_yy0, _uu, _v113);
  1744. int16x8_t _r1 = vmlal_s8(_yy1, _vv, _v90);
  1745. int16x8_t _g1 = vmlsl_s8(_yy1, _vv, _v46);
  1746. _g1 = vmlsl_s8(_g1, _uu, _v22);
  1747. int16x8_t _b1 = vmlal_s8(_yy1, _uu, _v113);
  1748. uint8x8x3_t _rgb0;
  1749. _rgb0.val[0] = vqshrun_n_s16(_r0, 6);
  1750. _rgb0.val[1] = vqshrun_n_s16(_g0, 6);
  1751. _rgb0.val[2] = vqshrun_n_s16(_b0, 6);
  1752. uint8x8x3_t _rgb1;
  1753. _rgb1.val[0] = vqshrun_n_s16(_r1, 6);
  1754. _rgb1.val[1] = vqshrun_n_s16(_g1, 6);
  1755. _rgb1.val[2] = vqshrun_n_s16(_b1, 6);
  1756. vst3_u8(rgb0, _rgb0);
  1757. vst3_u8(rgb1, _rgb1);
  1758. yptr0 += 8;
  1759. yptr1 += 8;
  1760. vuptr += 8;
  1761. rgb0 += 24;
  1762. rgb1 += 24;
  1763. }
  1764. #else
  1765. if (nn > 0)
  1766. {
  1767. asm volatile(
  1768. "pld [%3, #128] \n"
  1769. "vld1.u8 {d2}, [%3]! \n"
  1770. "vsub.s8 d2, d2, %12 \n"
  1771. "0: \n"
  1772. "pld [%1, #128] \n"
  1773. "vld1.u8 {d0}, [%1]! \n"
  1774. "pld [%2, #128] \n"
  1775. "vld1.u8 {d1}, [%2]! \n"
  1776. "vshll.u8 q2, d0, #6 \n"
  1777. "vorr d3, d2, d2 \n"
  1778. "vshll.u8 q3, d1, #6 \n"
  1779. "vorr q9, q2, q2 \n"
  1780. "vtrn.s8 d2, d3 \n"
  1781. "vorr q11, q3, q3 \n"
  1782. "vmlsl.s8 q9, d2, %14 \n"
  1783. "vorr q8, q2, q2 \n"
  1784. "vmlsl.s8 q11, d2, %14 \n"
  1785. "vorr q10, q3, q3 \n"
  1786. "vmlal.s8 q8, d2, %13 \n"
  1787. "vmlal.s8 q2, d3, %16 \n"
  1788. "vmlal.s8 q10, d2, %13 \n"
  1789. "vmlsl.s8 q9, d3, %15 \n"
  1790. "vmlal.s8 q3, d3, %16 \n"
  1791. "vmlsl.s8 q11, d3, %15 \n"
  1792. "vqshrun.s16 d24, q8, #6 \n"
  1793. "vqshrun.s16 d26, q2, #6 \n"
  1794. "vqshrun.s16 d4, q10, #6 \n"
  1795. "vqshrun.s16 d25, q9, #6 \n"
  1796. "vqshrun.s16 d6, q3, #6 \n"
  1797. "vqshrun.s16 d5, q11, #6 \n"
  1798. "pld [%3, #128] \n"
  1799. "vld1.u8 {d2}, [%3]! \n"
  1800. "subs %0, #1 \n"
  1801. "vst3.u8 {d24-d26}, [%4]! \n"
  1802. "vsub.s8 d2, d2, %12 \n"
  1803. "vst3.u8 {d4-d6}, [%5]! \n"
  1804. "bne 0b \n"
  1805. "sub %3, #8 \n"
  1806. : "=r"(nn), // %0
  1807. "=r"(yptr0), // %1
  1808. "=r"(yptr1), // %2
  1809. "=r"(vuptr), // %3
  1810. "=r"(rgb0), // %4
  1811. "=r"(rgb1) // %5
  1812. : "0"(nn),
  1813. "1"(yptr0),
  1814. "2"(yptr1),
  1815. "3"(vuptr),
  1816. "4"(rgb0),
  1817. "5"(rgb1),
  1818. "w"(_v128), // %12
  1819. "w"(_v90), // %13
  1820. "w"(_v46), // %14
  1821. "w"(_v22), // %15
  1822. "w"(_v113) // %16
  1823. : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12", "d26");
  1824. }
  1825. #endif // __aarch64__
  1826. #endif // __ARM_NEON
  1827. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  1828. for (; remain > 0; remain -= 2)
  1829. {
  1830. // R = 1.164 * yy + 1.596 * vv
  1831. // G = 1.164 * yy - 0.813 * vv - 0.391 * uu
  1832. // B = 1.164 * yy + 2.018 * uu
  1833. // R = Y + (1.370705 * (V-128))
  1834. // G = Y - (0.698001 * (V-128)) - (0.337633 * (U-128))
  1835. // B = Y + (1.732446 * (U-128))
  1836. // R = ((Y << 6) + 87.72512 * (V-128)) >> 6
  1837. // G = ((Y << 6) - 44.672064 * (V-128) - 21.608512 * (U-128)) >> 6
  1838. // B = ((Y << 6) + 110.876544 * (U-128)) >> 6
  1839. // R = ((Y << 6) + 90 * (V-128)) >> 6
  1840. // G = ((Y << 6) - 46 * (V-128) - 22 * (U-128)) >> 6
  1841. // B = ((Y << 6) + 113 * (U-128)) >> 6
  1842. // R = (yy + 90 * vv) >> 6
  1843. // G = (yy - 46 * vv - 22 * uu) >> 6
  1844. // B = (yy + 113 * uu) >> 6
  1845. int v = vuptr[0] - 128;
  1846. int u = vuptr[1] - 128;
  1847. int ruv = 90 * v;
  1848. int guv = -46 * v + -22 * u;
  1849. int buv = 113 * u;
  1850. int y00 = yptr0[0] << 6;
  1851. rgb0[0] = SATURATE_CAST_UCHAR((y00 + ruv) >> 6);
  1852. rgb0[1] = SATURATE_CAST_UCHAR((y00 + guv) >> 6);
  1853. rgb0[2] = SATURATE_CAST_UCHAR((y00 + buv) >> 6);
  1854. int y01 = yptr0[1] << 6;
  1855. rgb0[3] = SATURATE_CAST_UCHAR((y01 + ruv) >> 6);
  1856. rgb0[4] = SATURATE_CAST_UCHAR((y01 + guv) >> 6);
  1857. rgb0[5] = SATURATE_CAST_UCHAR((y01 + buv) >> 6);
  1858. int y10 = yptr1[0] << 6;
  1859. rgb1[0] = SATURATE_CAST_UCHAR((y10 + ruv) >> 6);
  1860. rgb1[1] = SATURATE_CAST_UCHAR((y10 + guv) >> 6);
  1861. rgb1[2] = SATURATE_CAST_UCHAR((y10 + buv) >> 6);
  1862. int y11 = yptr1[1] << 6;
  1863. rgb1[3] = SATURATE_CAST_UCHAR((y11 + ruv) >> 6);
  1864. rgb1[4] = SATURATE_CAST_UCHAR((y11 + guv) >> 6);
  1865. rgb1[5] = SATURATE_CAST_UCHAR((y11 + buv) >> 6);
  1866. yptr0 += 2;
  1867. yptr1 += 2;
  1868. vuptr += 2;
  1869. rgb0 += 6;
  1870. rgb1 += 6;
  1871. }
  1872. #undef SATURATE_CAST_UCHAR
  1873. yptr += 2 * w;
  1874. rgb += 2 * 3 * w;
  1875. }
  1876. }
  1877. void yuv420sp2rgb_half(const unsigned char* yuv, int w, int h, unsigned char* rgb)
  1878. {
  1879. const unsigned char* puv = yuv + w * h;
  1880. const unsigned char *py0 = yuv, *py1 = yuv + w;
  1881. const int hstep = h / 2;
  1882. #if __ARM_NEON
  1883. const int wstep = w / 16, tailstep = (w - wstep * 16) / 2;
  1884. uint8x8_t _u128 = vdup_n_u8(128);
  1885. int8x8_t _s90 = vdup_n_s8(90);
  1886. int8x8_t _sn46 = vdup_n_s8(-46);
  1887. int8x8_t _s113 = vdup_n_s8(113);
  1888. int8x8_t _sn22 = vdup_n_s8(-22);
  1889. int16x8_t _s0 = vdupq_n_s16(0);
  1890. int16x8_t _s16320 = vdupq_n_s16(16320); // 255 << 6
  1891. #else
  1892. const int tailstep = w / 2;
  1893. #endif
  1894. for (int i = 0; i < hstep; ++i)
  1895. {
  1896. #if __ARM_NEON
  1897. for (int j = 0; j < wstep; ++j)
  1898. {
  1899. uint8x16_t y0 = vld1q_u8(py0);
  1900. uint8x16_t y1 = vld1q_u8(py1);
  1901. // first 8 Y
  1902. uint16x8_t low = vaddl_u8(vget_low_u8(y0), vget_low_u8(y1));
  1903. uint16x4_t low_sum = vpadd_u16(vget_low_u16(low), vget_high_u16(low));
  1904. // last 8 Y
  1905. uint16x8_t high = vaddl_u8(vget_high_u8(y0), vget_high_u8(y1));
  1906. uint16x4_t high_sum = vpadd_u16(vget_low_u16(high), vget_high_u16(high));
  1907. uint16x8_t y8_sum = vcombine_u16(low_sum, high_sum);
  1908. // y8 = (y8_sum >> 2) << 6 = y8_sum << 4;
  1909. int16x8_t y8 = vreinterpretq_s16_u16(vshlq_n_u16(y8_sum, 4));
  1910. // prepare uv
  1911. uint8x8x2_t vu = vld2_u8(puv);
  1912. int8x8_t v = vreinterpret_s8_u8(vsub_u8(vu.val[0], _u128));
  1913. int8x8_t u = vreinterpret_s8_u8(vsub_u8(vu.val[1], _u128));
  1914. int16x8_t r_acc = vmlal_s8(y8, v, _s90);
  1915. int16x8_t g_acc = vmlal_s8(y8, v, _sn46);
  1916. g_acc = vmlal_s8(g_acc, u, _sn22);
  1917. int16x8_t b_acc = vmlal_s8(y8, u, _s113);
  1918. #define SHIFT_6_SATURATE(FROM, TO) \
  1919. FROM = vmaxq_s16(vminq_s16((FROM), _s16320), _s0); \
  1920. uint8x8_t TO = vshrn_n_u16(vreinterpretq_u16_s16((FROM)), 6);
  1921. SHIFT_6_SATURATE(b_acc, b_out)
  1922. SHIFT_6_SATURATE(g_acc, g_out)
  1923. SHIFT_6_SATURATE(r_acc, r_out)
  1924. #undef SHIFT_6_SATURATE
  1925. uint8x8x3_t _rgb;
  1926. _rgb.val[0] = r_out;
  1927. _rgb.val[1] = g_out;
  1928. _rgb.val[2] = b_out;
  1929. vst3_u8(rgb, _rgb);
  1930. rgb += 24;
  1931. py0 += 16;
  1932. py1 += 16;
  1933. puv += 16;
  1934. }
  1935. #endif
  1936. for (int idx = 0; idx < tailstep; ++idx)
  1937. {
  1938. int y = (static_cast<int>(py0[0]) + py0[1] + py1[2] + py1[1]) << 4;
  1939. int v = static_cast<int>(puv[0]) - 128;
  1940. int u = static_cast<int>(puv[1]) - 128;
  1941. int ruv = 90 * v;
  1942. int guv = -46 * v + -22 * u;
  1943. int buv = 113 * u;
  1944. #define SATURATE_CAST_UCHAR(X) (unsigned char)::std::min(::std::max((int)(X), 0), 255);
  1945. rgb[0] = SATURATE_CAST_UCHAR((y + ruv) >> 6);
  1946. rgb[1] = SATURATE_CAST_UCHAR((y + guv) >> 6);
  1947. rgb[2] = SATURATE_CAST_UCHAR((y + buv) >> 6);
  1948. #undef SATURATE_CAST_UCHAR
  1949. rgb += 3;
  1950. py0 += 2;
  1951. py1 += 2;
  1952. puv += 2;
  1953. }
  1954. // next two row
  1955. py0 = py1;
  1956. py1 = py0 + w;
  1957. }
  1958. }
  1959. Mat Mat::from_pixels(const unsigned char* pixels, int type, int w, int h, Allocator* allocator)
  1960. {
  1961. int type_from = type & PIXEL_FORMAT_MASK;
  1962. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  1963. {
  1964. return Mat::from_pixels(pixels, type, w, h, w * 3, allocator);
  1965. }
  1966. else if (type_from == PIXEL_GRAY)
  1967. {
  1968. return Mat::from_pixels(pixels, type, w, h, w * 1, allocator);
  1969. }
  1970. else if (type_from == PIXEL_RGBA || type_from == PIXEL_BGRA)
  1971. {
  1972. return Mat::from_pixels(pixels, type, w, h, w * 4, allocator);
  1973. }
  1974. // unknown convert type
  1975. NCNN_LOGE("unknown convert type %d", type);
  1976. return Mat();
  1977. }
  1978. Mat Mat::from_pixels(const unsigned char* pixels, int type, int w, int h, int stride, Allocator* allocator)
  1979. {
  1980. Mat m;
  1981. if (type & PIXEL_CONVERT_MASK)
  1982. {
  1983. switch (type)
  1984. {
  1985. case PIXEL_RGB2BGR:
  1986. case PIXEL_BGR2RGB:
  1987. from_rgb2bgr(pixels, w, h, stride, m, allocator);
  1988. break;
  1989. case PIXEL_RGB2GRAY:
  1990. from_rgb2gray(pixels, w, h, stride, m, allocator);
  1991. break;
  1992. case PIXEL_RGB2RGBA:
  1993. case PIXEL_BGR2BGRA:
  1994. from_rgb2rgba(pixels, w, h, stride, m, allocator);
  1995. break;
  1996. case PIXEL_BGR2GRAY:
  1997. from_bgr2gray(pixels, w, h, stride, m, allocator);
  1998. break;
  1999. case PIXEL_BGR2RGBA:
  2000. case PIXEL_RGB2BGRA:
  2001. from_bgr2rgba(pixels, w, h, stride, m, allocator);
  2002. break;
  2003. case PIXEL_GRAY2RGB:
  2004. case PIXEL_GRAY2BGR:
  2005. from_gray2rgb(pixels, w, h, stride, m, allocator);
  2006. break;
  2007. case PIXEL_GRAY2RGBA:
  2008. case PIXEL_GRAY2BGRA:
  2009. from_gray2rgba(pixels, w, h, stride, m, allocator);
  2010. break;
  2011. case PIXEL_RGBA2RGB:
  2012. case PIXEL_BGRA2BGR:
  2013. from_rgba2rgb(pixels, w, h, stride, m, allocator);
  2014. break;
  2015. case PIXEL_RGBA2BGR:
  2016. case PIXEL_BGRA2RGB:
  2017. from_rgba2bgr(pixels, w, h, stride, m, allocator);
  2018. break;
  2019. case PIXEL_RGBA2GRAY:
  2020. from_rgba2gray(pixels, w, h, stride, m, allocator);
  2021. break;
  2022. case PIXEL_RGBA2BGRA:
  2023. case PIXEL_BGRA2RGBA:
  2024. from_rgba2bgra(pixels, w, h, stride, m, allocator);
  2025. break;
  2026. case PIXEL_BGRA2GRAY:
  2027. from_bgra2gray(pixels, w, h, stride, m, allocator);
  2028. break;
  2029. default:
  2030. // unimplemented convert type
  2031. NCNN_LOGE("unimplemented convert type %d", type);
  2032. break;
  2033. }
  2034. }
  2035. else
  2036. {
  2037. if (type == PIXEL_RGB || type == PIXEL_BGR)
  2038. from_rgb(pixels, w, h, stride, m, allocator);
  2039. if (type == PIXEL_GRAY)
  2040. from_gray(pixels, w, h, stride, m, allocator);
  2041. if (type == PIXEL_RGBA || type == PIXEL_BGRA)
  2042. from_rgba(pixels, w, h, stride, m, allocator);
  2043. }
  2044. return m;
  2045. }
  2046. Mat Mat::from_pixels_resize(const unsigned char* pixels, int type, int w, int h, int target_width, int target_height, Allocator* allocator)
  2047. {
  2048. int type_from = type & PIXEL_FORMAT_MASK;
  2049. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  2050. {
  2051. return Mat::from_pixels_resize(pixels, type, w, h, w * 3, target_width, target_height, allocator);
  2052. }
  2053. else if (type_from == PIXEL_GRAY)
  2054. {
  2055. return Mat::from_pixels_resize(pixels, type, w, h, w * 1, target_width, target_height, allocator);
  2056. }
  2057. else if (type_from == PIXEL_RGBA || type_from == PIXEL_BGRA)
  2058. {
  2059. return Mat::from_pixels_resize(pixels, type, w, h, w * 4, target_width, target_height, allocator);
  2060. }
  2061. // unknown convert type
  2062. NCNN_LOGE("unknown convert type %d", type);
  2063. return Mat();
  2064. }
  2065. 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)
  2066. {
  2067. if (w == target_width && h == target_height)
  2068. return Mat::from_pixels(pixels, type, w, h, stride, allocator);
  2069. int type_from = type & PIXEL_FORMAT_MASK;
  2070. if (type_from == PIXEL_RGB || type_from == PIXEL_BGR)
  2071. {
  2072. Mat dst(target_width, target_height, (size_t)3u, 3);
  2073. resize_bilinear_c3(pixels, w, h, stride, dst, target_width, target_height, target_width * 3);
  2074. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  2075. }
  2076. else if (type_from == PIXEL_GRAY)
  2077. {
  2078. Mat dst(target_width, target_height, (size_t)1u, 1);
  2079. resize_bilinear_c1(pixels, w, h, stride, dst, target_width, target_height, target_width * 1);
  2080. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  2081. }
  2082. else if (type_from == PIXEL_RGBA || type_from == PIXEL_BGRA)
  2083. {
  2084. Mat dst(target_width, target_height, (size_t)4u, 4);
  2085. resize_bilinear_c4(pixels, w, h, stride, dst, target_width, target_height, target_width * 4);
  2086. return Mat::from_pixels(dst, type, target_width, target_height, allocator);
  2087. }
  2088. // unknown convert type
  2089. NCNN_LOGE("unknown convert type %d", type);
  2090. return Mat();
  2091. }
  2092. void Mat::to_pixels(unsigned char* pixels, int type) const
  2093. {
  2094. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  2095. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  2096. {
  2097. to_pixels(pixels, type, w * 3);
  2098. }
  2099. else if (type_to == PIXEL_GRAY)
  2100. {
  2101. to_pixels(pixels, type, w * 1);
  2102. }
  2103. else if (type_to == PIXEL_RGBA || type_to == PIXEL_BGRA)
  2104. {
  2105. to_pixels(pixels, type, w * 4);
  2106. }
  2107. }
  2108. void Mat::to_pixels(unsigned char* pixels, int type, int stride) const
  2109. {
  2110. if (type & PIXEL_CONVERT_MASK)
  2111. {
  2112. switch (type)
  2113. {
  2114. case PIXEL_RGB2BGR:
  2115. case PIXEL_BGR2RGB:
  2116. to_bgr2rgb(*this, pixels, stride);
  2117. break;
  2118. case PIXEL_RGB2RGBA:
  2119. case PIXEL_BGR2BGRA:
  2120. to_rgb2rgba(*this, pixels, stride);
  2121. break;
  2122. case PIXEL_BGR2RGBA:
  2123. case PIXEL_RGB2BGRA:
  2124. to_bgr2rgba(*this, pixels, stride);
  2125. break;
  2126. case PIXEL_GRAY2RGBA:
  2127. case PIXEL_GRAY2BGRA:
  2128. to_gray2rgba(*this, pixels, stride);
  2129. break;
  2130. case PIXEL_RGBA2BGRA:
  2131. case PIXEL_BGRA2RGBA:
  2132. to_rgba2bgra(*this, pixels, stride);
  2133. break;
  2134. default:
  2135. // unimplemented convert type
  2136. NCNN_LOGE("unimplemented convert type %d", type);
  2137. break;
  2138. }
  2139. }
  2140. else
  2141. {
  2142. if (type == PIXEL_RGB || type == PIXEL_BGR)
  2143. to_rgb(*this, pixels, stride);
  2144. if (type == PIXEL_GRAY)
  2145. to_gray(*this, pixels, stride);
  2146. if (type == PIXEL_RGBA || type == PIXEL_BGRA)
  2147. to_rgba(*this, pixels, stride);
  2148. }
  2149. }
  2150. void Mat::to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height) const
  2151. {
  2152. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  2153. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  2154. {
  2155. to_pixels_resize(pixels, type, target_width, target_height, target_width * 3);
  2156. }
  2157. else if (type_to == PIXEL_GRAY)
  2158. {
  2159. to_pixels_resize(pixels, type, target_width, target_height, target_width * 1);
  2160. }
  2161. else if (type_to == PIXEL_RGBA || type_to == PIXEL_BGRA)
  2162. {
  2163. to_pixels_resize(pixels, type, target_width, target_height, target_width * 4);
  2164. }
  2165. }
  2166. void Mat::to_pixels_resize(unsigned char* pixels, int type, int target_width, int target_height, int target_stride) const
  2167. {
  2168. if (w == target_width && h == target_height)
  2169. return to_pixels(pixels, type);
  2170. int type_to = (type & PIXEL_CONVERT_MASK) ? (type >> PIXEL_CONVERT_SHIFT) : (type & PIXEL_FORMAT_MASK);
  2171. if (type_to == PIXEL_RGB || type_to == PIXEL_BGR)
  2172. {
  2173. Mat src(w, h, (size_t)3u, 3);
  2174. to_pixels(src, type);
  2175. resize_bilinear_c3(src, w, h, w * 3, pixels, target_width, target_height, target_stride);
  2176. }
  2177. else if (type_to == PIXEL_GRAY)
  2178. {
  2179. Mat src(w, h, (size_t)1u, 1);
  2180. to_pixels(src, type);
  2181. resize_bilinear_c1(src, w, h, w * 1, pixels, target_width, target_height, target_stride);
  2182. }
  2183. else if (type_to == PIXEL_RGBA || type_to == PIXEL_BGRA)
  2184. {
  2185. Mat src(w, h, (size_t)4u, 4);
  2186. to_pixels(src, type);
  2187. resize_bilinear_c4(src, w, h, w * 4, pixels, target_width, target_height, target_stride);
  2188. }
  2189. }
  2190. #endif // NCNN_PIXEL
  2191. } // namespace ncnn