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