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