Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

martins.js 1.2MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837
  1. /*!
  2. * MARTINS.js Free Edition version 0.1.1
  3. * GPU-accelerated Augmented Reality for the web
  4. * Copyright 2022 Alexandre Martins <alemartf(at)gmail.com> (https://github.com/alemart)
  5. * https://github.com/alemart/martins-js
  6. *
  7. * @license AGPL-3.0-only
  8. * Date: 2022-04-28T23:26:33.373Z
  9. */
  10. (function webpackUniversalModuleDefinition(root, factory) {
  11. if(typeof exports === 'object' && typeof module === 'object')
  12. module.exports = factory();
  13. else if(typeof define === 'function' && define.amd)
  14. define([], factory);
  15. else if(typeof exports === 'object')
  16. exports["Martins"] = factory();
  17. else
  18. root["Martins"] = factory();
  19. })(self, function() {
  20. return /******/ (() => { // webpackBootstrap
  21. /******/ var __webpack_modules__ = ({
  22. /***/ 528:
  23. /***/ ((module) => {
  24. /*!
  25. * Speedy Vision version 0.9.0-wip
  26. * GPU-accelerated Computer Vision for JavaScript
  27. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com> (https://github.com/alemart)
  28. * https://github.com/alemart/speedy-vision
  29. *
  30. * @license Apache-2.0
  31. * Date: 2022-04-19T18:11:01.441Z
  32. */
  33. (function webpackUniversalModuleDefinition(root, factory) {
  34. if(true)
  35. module.exports = factory();
  36. else {}
  37. })(self, function() {
  38. return /******/ (() => { // webpackBootstrap
  39. /******/ var __webpack_modules__ = ({
  40. /***/ "./src/core/pipeline/factories/filter-factory.js":
  41. /*!*******************************************************!*\
  42. !*** ./src/core/pipeline/factories/filter-factory.js ***!
  43. \*******************************************************/
  44. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_1027__) => {
  45. "use strict";
  46. __nested_webpack_require_1027__.r(__webpack_exports__);
  47. /* harmony export */ __nested_webpack_require_1027__.d(__webpack_exports__, {
  48. /* harmony export */ "SpeedyPipelineFilterFactory": () => (/* binding */ SpeedyPipelineFilterFactory)
  49. /* harmony export */ });
  50. /* harmony import */ var _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_1027__(/*! ../../speedy-namespace */ "./src/core/speedy-namespace.js");
  51. /* harmony import */ var _nodes_filters_greyscale__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_1027__(/*! ../nodes/filters/greyscale */ "./src/core/pipeline/nodes/filters/greyscale.js");
  52. /* harmony import */ var _nodes_filters_gaussian_blur__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_1027__(/*! ../nodes/filters/gaussian-blur */ "./src/core/pipeline/nodes/filters/gaussian-blur.js");
  53. /* harmony import */ var _nodes_filters_simple_blur__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_1027__(/*! ../nodes/filters/simple-blur */ "./src/core/pipeline/nodes/filters/simple-blur.js");
  54. /* harmony import */ var _nodes_filters_median_blur__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_1027__(/*! ../nodes/filters/median-blur */ "./src/core/pipeline/nodes/filters/median-blur.js");
  55. /* harmony import */ var _nodes_filters_convolution__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_1027__(/*! ../nodes/filters/convolution */ "./src/core/pipeline/nodes/filters/convolution.js");
  56. /* harmony import */ var _nodes_filters_nightvision__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_1027__(/*! ../nodes/filters/nightvision */ "./src/core/pipeline/nodes/filters/nightvision.js");
  57. /* harmony import */ var _nodes_filters_normalize__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_1027__(/*! ../nodes/filters/normalize */ "./src/core/pipeline/nodes/filters/normalize.js");
  58. /*
  59. * speedy-vision.js
  60. * GPU-accelerated Computer Vision for JavaScript
  61. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  62. *
  63. * Licensed under the Apache License, Version 2.0 (the "License");
  64. * you may not use this file except in compliance with the License.
  65. * You may obtain a copy of the License at
  66. *
  67. * http://www.apache.org/licenses/LICENSE-2.0
  68. *
  69. * Unless required by applicable law or agreed to in writing, software
  70. * distributed under the License is distributed on an "AS IS" BASIS,
  71. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  72. * See the License for the specific language governing permissions and
  73. * limitations under the License.
  74. *
  75. * filter-factory.js
  76. * Image filters
  77. */
  78. /**
  79. * Image filters
  80. */
  81. class SpeedyPipelineFilterFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  82. {
  83. /**
  84. * Convert image to greyscale
  85. * @param {string} [name]
  86. * @returns {SpeedyPipelineNodeGreyscale}
  87. */
  88. static Greyscale(name = undefined)
  89. {
  90. return new _nodes_filters_greyscale__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeGreyscale(name);
  91. }
  92. /**
  93. * Gaussian Blur
  94. * @param {string} [name]
  95. * @returns {SpeedyPipelineNodeGaussianBlur}
  96. */
  97. static GaussianBlur(name = undefined)
  98. {
  99. return new _nodes_filters_gaussian_blur__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeGaussianBlur(name);
  100. }
  101. /**
  102. * Simple Blur (Box Filter)
  103. * @param {string} [name]
  104. * @returns {SpeedyPipelineNodeSimpleBlur}
  105. */
  106. static SimpleBlur(name = undefined)
  107. {
  108. return new _nodes_filters_simple_blur__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeSimpleBlur(name);
  109. }
  110. /**
  111. * Median Blur
  112. * @param {string} [name]
  113. * @returns {SpeedyPipelineNodeMedianBlur}
  114. */
  115. static MedianBlur(name = undefined)
  116. {
  117. return new _nodes_filters_median_blur__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineNodeMedianBlur(name);
  118. }
  119. /**
  120. * Image Convolution
  121. * @param {string} [name]
  122. * @returns {SpeedyPipelineNodeConvolution}
  123. */
  124. static Convolution(name = undefined)
  125. {
  126. return new _nodes_filters_convolution__WEBPACK_IMPORTED_MODULE_5__.SpeedyPipelineNodeConvolution(name);
  127. }
  128. /**
  129. * Nightvision
  130. * @param {string} [name]
  131. * @returns {SpeedyPipelineNodeNightvision}
  132. */
  133. static Nightvision(name = undefined)
  134. {
  135. return new _nodes_filters_nightvision__WEBPACK_IMPORTED_MODULE_6__.SpeedyPipelineNodeNightvision(name);
  136. }
  137. /**
  138. * Normalize image
  139. * @param {string} [name]
  140. * @returns {SpeedyPipelineNodeNormalize}
  141. */
  142. static Normalize(name = undefined)
  143. {
  144. return new _nodes_filters_normalize__WEBPACK_IMPORTED_MODULE_7__.SpeedyPipelineNodeNormalize(name);
  145. }
  146. }
  147. /***/ }),
  148. /***/ "./src/core/pipeline/factories/image-factory.js":
  149. /*!******************************************************!*\
  150. !*** ./src/core/pipeline/factories/image-factory.js ***!
  151. \******************************************************/
  152. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_5965__) => {
  153. "use strict";
  154. __nested_webpack_require_5965__.r(__webpack_exports__);
  155. /* harmony export */ __nested_webpack_require_5965__.d(__webpack_exports__, {
  156. /* harmony export */ "SpeedyPipelineImagePortalFactory": () => (/* binding */ SpeedyPipelineImagePortalFactory),
  157. /* harmony export */ "SpeedyPipelineImageFactory": () => (/* binding */ SpeedyPipelineImageFactory)
  158. /* harmony export */ });
  159. /* harmony import */ var _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_5965__(/*! ../../speedy-namespace */ "./src/core/speedy-namespace.js");
  160. /* harmony import */ var _nodes_images_source__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_5965__(/*! ../nodes/images/source */ "./src/core/pipeline/nodes/images/source.js");
  161. /* harmony import */ var _nodes_images_sink__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_5965__(/*! ../nodes/images/sink */ "./src/core/pipeline/nodes/images/sink.js");
  162. /* harmony import */ var _nodes_images_multiplexer__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_5965__(/*! ../nodes/images/multiplexer */ "./src/core/pipeline/nodes/images/multiplexer.js");
  163. /* harmony import */ var _nodes_images_buffer__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_5965__(/*! ../nodes/images/buffer */ "./src/core/pipeline/nodes/images/buffer.js");
  164. /* harmony import */ var _nodes_images_pyramid__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_5965__(/*! ../nodes/images/pyramid */ "./src/core/pipeline/nodes/images/pyramid.js");
  165. /* harmony import */ var _nodes_images_mixer__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_5965__(/*! ../nodes/images/mixer */ "./src/core/pipeline/nodes/images/mixer.js");
  166. /* harmony import */ var _nodes_images_portal__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_5965__(/*! ../nodes/images/portal */ "./src/core/pipeline/nodes/images/portal.js");
  167. /*
  168. * speedy-vision.js
  169. * GPU-accelerated Computer Vision for JavaScript
  170. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  171. *
  172. * Licensed under the Apache License, Version 2.0 (the "License");
  173. * you may not use this file except in compliance with the License.
  174. * You may obtain a copy of the License at
  175. *
  176. * http://www.apache.org/licenses/LICENSE-2.0
  177. *
  178. * Unless required by applicable law or agreed to in writing, software
  179. * distributed under the License is distributed on an "AS IS" BASIS,
  180. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  181. * See the License for the specific language governing permissions and
  182. * limitations under the License.
  183. *
  184. * image-factory.js
  185. * Image-related nodes
  186. */
  187. /**
  188. * Portal nodes
  189. */
  190. class SpeedyPipelineImagePortalFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  191. {
  192. /**
  193. * Create an image portal source
  194. * @param {string} [name] name of the node
  195. * @returns {SpeedyPipelineNodeImagePortalSource}
  196. */
  197. static Source(name = undefined)
  198. {
  199. return new _nodes_images_portal__WEBPACK_IMPORTED_MODULE_7__.SpeedyPipelineNodeImagePortalSource(name);
  200. }
  201. /**
  202. * Create an image portal sink
  203. * @param {string} [name] name of the node
  204. * @returns {SpeedyPipelineNodeImagePortalSink}
  205. */
  206. static Sink(name = undefined)
  207. {
  208. return new _nodes_images_portal__WEBPACK_IMPORTED_MODULE_7__.SpeedyPipelineNodeImagePortalSink(name);
  209. }
  210. }
  211. /**
  212. * Image nodes
  213. */
  214. class SpeedyPipelineImageFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  215. {
  216. /**
  217. * Create an image source
  218. * @param {string} [name] name of the node
  219. * @returns {SpeedyPipelineNodeImageSource}
  220. */
  221. static Source(name = undefined)
  222. {
  223. return new _nodes_images_source__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeImageSource(name);
  224. }
  225. /**
  226. * Create an image sink
  227. * @param {string} [name] name of the node
  228. * @returns {SpeedyPipelineNodeImageSink}
  229. */
  230. static Sink(name = undefined)
  231. {
  232. return new _nodes_images_sink__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeImageSink(name);
  233. }
  234. /**
  235. * Create an image multiplexer
  236. * @param {string} [name] name of the node
  237. * @returns {SpeedyPipelineNodeImageMultiplexer}
  238. */
  239. static Multiplexer(name = undefined)
  240. {
  241. return new _nodes_images_multiplexer__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeImageMultiplexer(name);
  242. }
  243. /**
  244. * Create an image buffer
  245. * @param {string} [name] name of the node
  246. * @returns {SpeedyPipelineNodeImageBuffer}
  247. */
  248. static Buffer(name = undefined)
  249. {
  250. return new _nodes_images_buffer__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineNodeImageBuffer(name);
  251. }
  252. /**
  253. * Image Pyramid
  254. * @param {string} [name] name of the node
  255. * @returns {SpeedyPipelineNodeImagePyramid}
  256. */
  257. static Pyramid(name = undefined)
  258. {
  259. return new _nodes_images_pyramid__WEBPACK_IMPORTED_MODULE_5__.SpeedyPipelineNodeImagePyramid(name);
  260. }
  261. /**
  262. * Image Mixer (blending)
  263. * @param {string} [name] name of the node
  264. * @returns {SpeedyPipelineNodeImageMixer}
  265. */
  266. static Mixer(name = undefined)
  267. {
  268. return new _nodes_images_mixer__WEBPACK_IMPORTED_MODULE_6__.SpeedyPipelineNodeImageMixer(name);
  269. }
  270. /**
  271. * Image Portals
  272. * @returns {typeof SpeedyPipelineImagePortalFactory}
  273. */
  274. static get Portal()
  275. {
  276. return SpeedyPipelineImagePortalFactory;
  277. }
  278. }
  279. /***/ }),
  280. /***/ "./src/core/pipeline/factories/keypoint-factory.js":
  281. /*!*********************************************************!*\
  282. !*** ./src/core/pipeline/factories/keypoint-factory.js ***!
  283. \*********************************************************/
  284. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_11666__) => {
  285. "use strict";
  286. __nested_webpack_require_11666__.r(__webpack_exports__);
  287. /* harmony export */ __nested_webpack_require_11666__.d(__webpack_exports__, {
  288. /* harmony export */ "SpeedyPipelineKeypointPortalFactory": () => (/* binding */ SpeedyPipelineKeypointPortalFactory),
  289. /* harmony export */ "SpeedyPipelineKeypointFactory": () => (/* binding */ SpeedyPipelineKeypointFactory)
  290. /* harmony export */ });
  291. /* harmony import */ var _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_11666__(/*! ../../speedy-namespace */ "./src/core/speedy-namespace.js");
  292. /* harmony import */ var _nodes_keypoints_source__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/source */ "./src/core/pipeline/nodes/keypoints/source.js");
  293. /* harmony import */ var _nodes_keypoints_sink__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/sink */ "./src/core/pipeline/nodes/keypoints/sink.js");
  294. /* harmony import */ var _nodes_keypoints_clipper__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/clipper */ "./src/core/pipeline/nodes/keypoints/clipper.js");
  295. /* harmony import */ var _nodes_keypoints_border_clipper__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/border-clipper */ "./src/core/pipeline/nodes/keypoints/border-clipper.js");
  296. /* harmony import */ var _nodes_keypoints_buffer__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/buffer */ "./src/core/pipeline/nodes/keypoints/buffer.js");
  297. /* harmony import */ var _nodes_keypoints_mixer__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/mixer */ "./src/core/pipeline/nodes/keypoints/mixer.js");
  298. /* harmony import */ var _nodes_keypoints_shuffler__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/shuffler */ "./src/core/pipeline/nodes/keypoints/shuffler.js");
  299. /* harmony import */ var _nodes_keypoints_multiplexer__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/multiplexer */ "./src/core/pipeline/nodes/keypoints/multiplexer.js");
  300. /* harmony import */ var _nodes_keypoints_transformer__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/transformer */ "./src/core/pipeline/nodes/keypoints/transformer.js");
  301. /* harmony import */ var _nodes_keypoints_subpixel__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/subpixel */ "./src/core/pipeline/nodes/keypoints/subpixel.js");
  302. /* harmony import */ var _nodes_keypoints_detectors_fast__WEBPACK_IMPORTED_MODULE_11__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/detectors/fast */ "./src/core/pipeline/nodes/keypoints/detectors/fast.js");
  303. /* harmony import */ var _nodes_keypoints_detectors_harris__WEBPACK_IMPORTED_MODULE_12__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/detectors/harris */ "./src/core/pipeline/nodes/keypoints/detectors/harris.js");
  304. /* harmony import */ var _nodes_keypoints_descriptors_orb__WEBPACK_IMPORTED_MODULE_13__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/descriptors/orb */ "./src/core/pipeline/nodes/keypoints/descriptors/orb.js");
  305. /* harmony import */ var _nodes_keypoints_trackers_lk__WEBPACK_IMPORTED_MODULE_14__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/trackers/lk */ "./src/core/pipeline/nodes/keypoints/trackers/lk.js");
  306. /* harmony import */ var _nodes_keypoints_matchers_lsh_static_tables__WEBPACK_IMPORTED_MODULE_15__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/matchers/lsh-static-tables */ "./src/core/pipeline/nodes/keypoints/matchers/lsh-static-tables.js");
  307. /* harmony import */ var _nodes_keypoints_matchers_lsh_knn__WEBPACK_IMPORTED_MODULE_16__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/matchers/lsh-knn */ "./src/core/pipeline/nodes/keypoints/matchers/lsh-knn.js");
  308. /* harmony import */ var _nodes_keypoints_matchers_bf_knn__WEBPACK_IMPORTED_MODULE_17__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/matchers/bf-knn */ "./src/core/pipeline/nodes/keypoints/matchers/bf-knn.js");
  309. /* harmony import */ var _nodes_keypoints_distance_filter__WEBPACK_IMPORTED_MODULE_18__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/distance-filter */ "./src/core/pipeline/nodes/keypoints/distance-filter.js");
  310. /* harmony import */ var _nodes_keypoints_hamming_distance_filter__WEBPACK_IMPORTED_MODULE_19__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/hamming-distance-filter */ "./src/core/pipeline/nodes/keypoints/hamming-distance-filter.js");
  311. /* harmony import */ var _nodes_keypoints_portal__WEBPACK_IMPORTED_MODULE_20__ = __nested_webpack_require_11666__(/*! ../nodes/keypoints/portal */ "./src/core/pipeline/nodes/keypoints/portal.js");
  312. /*
  313. * speedy-vision.js
  314. * GPU-accelerated Computer Vision for JavaScript
  315. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  316. *
  317. * Licensed under the Apache License, Version 2.0 (the "License");
  318. * you may not use this file except in compliance with the License.
  319. * You may obtain a copy of the License at
  320. *
  321. * http://www.apache.org/licenses/LICENSE-2.0
  322. *
  323. * Unless required by applicable law or agreed to in writing, software
  324. * distributed under the License is distributed on an "AS IS" BASIS,
  325. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  326. * See the License for the specific language governing permissions and
  327. * limitations under the License.
  328. *
  329. * keypoint-factory.js
  330. * Keypoint-related nodes
  331. */
  332. /**
  333. * Keypoint detectors
  334. */
  335. class SpeedyPipelineKeypointDetectorFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  336. {
  337. /**
  338. * FAST corner detector
  339. * @param {string} [name]
  340. * @returns {SpeedyPipelineNodeFASTKeypointDetector}
  341. */
  342. static FAST(name = undefined)
  343. {
  344. return new _nodes_keypoints_detectors_fast__WEBPACK_IMPORTED_MODULE_11__.SpeedyPipelineNodeFASTKeypointDetector(name);
  345. }
  346. /**
  347. * Harris corner detector
  348. * @param {string} [name]
  349. * @returns {SpeedyPipelineNodeHarrisKeypointDetector}
  350. */
  351. static Harris(name = undefined)
  352. {
  353. return new _nodes_keypoints_detectors_harris__WEBPACK_IMPORTED_MODULE_12__.SpeedyPipelineNodeHarrisKeypointDetector(name);
  354. }
  355. }
  356. /**
  357. * Keypoint descriptors
  358. */
  359. class SpeedyPipelineKeypointDescriptorFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  360. {
  361. /**
  362. * ORB descriptors
  363. * @param {string} [name]
  364. * @returns {SpeedyPipelineNodeORBKeypointDescriptor}
  365. */
  366. static ORB(name = undefined)
  367. {
  368. return new _nodes_keypoints_descriptors_orb__WEBPACK_IMPORTED_MODULE_13__.SpeedyPipelineNodeORBKeypointDescriptor(name);
  369. }
  370. }
  371. /**
  372. * Keypoint trackers
  373. */
  374. class SpeedyPipelineKeypointTrackerFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  375. {
  376. /**
  377. * LK optical-flow
  378. * @param {string} [name]
  379. * @returns {SpeedyPipelineNodeLKKeypointTracker}
  380. */
  381. static LK(name = undefined)
  382. {
  383. return new _nodes_keypoints_trackers_lk__WEBPACK_IMPORTED_MODULE_14__.SpeedyPipelineNodeLKKeypointTracker(name);
  384. }
  385. }
  386. /**
  387. * Keypoint matchers
  388. */
  389. class SpeedyPipelineKeypointMatcherFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  390. {
  391. /**
  392. * Static LSH tables
  393. * @param {string} [name]
  394. * @returns {SpeedyPipelineNodeStaticLSHTables}
  395. */
  396. static StaticLSHTables(name = undefined)
  397. {
  398. return new _nodes_keypoints_matchers_lsh_static_tables__WEBPACK_IMPORTED_MODULE_15__.SpeedyPipelineNodeStaticLSHTables(name);
  399. }
  400. /**
  401. * LSH-based K-approximate nearest neighbors
  402. * @param {string} [name]
  403. * @returns {SpeedyPipelineNodeLSHKNNMatcher}
  404. */
  405. static LSHKNN(name = undefined)
  406. {
  407. return new _nodes_keypoints_matchers_lsh_knn__WEBPACK_IMPORTED_MODULE_16__.SpeedyPipelineNodeLSHKNNMatcher(name);
  408. }
  409. /**
  410. * Brute-force K-nearest neighbors keypoint matcher
  411. * @param {string} [name]
  412. * @returns {SpeedyPipelineNodeBruteForceKNNKeypointMatcher}
  413. */
  414. static BFKNN(name = undefined)
  415. {
  416. return new _nodes_keypoints_matchers_bf_knn__WEBPACK_IMPORTED_MODULE_17__.SpeedyPipelineNodeBruteForceKNNKeypointMatcher(name);
  417. }
  418. }
  419. /**
  420. * Portal nodes
  421. */
  422. class SpeedyPipelineKeypointPortalFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  423. {
  424. /**
  425. * Create an image portal source
  426. * @param {string} [name] name of the node
  427. * @returns {SpeedyPipelineNodeKeypointPortalSource}
  428. */
  429. static Source(name = undefined)
  430. {
  431. return new _nodes_keypoints_portal__WEBPACK_IMPORTED_MODULE_20__.SpeedyPipelineNodeKeypointPortalSource(name);
  432. }
  433. /**
  434. * Create an image portal sink
  435. * @param {string} [name] name of the node
  436. * @returns {SpeedyPipelineNodeKeypointPortalSink}
  437. */
  438. static Sink(name = undefined)
  439. {
  440. return new _nodes_keypoints_portal__WEBPACK_IMPORTED_MODULE_20__.SpeedyPipelineNodeKeypointPortalSink(name);
  441. }
  442. }
  443. /**
  444. * Keypoint-related nodes
  445. */
  446. class SpeedyPipelineKeypointFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  447. {
  448. /**
  449. * Keypoint detectors
  450. * @returns {typeof SpeedyPipelineKeypointDetectorFactory}
  451. */
  452. static get Detector()
  453. {
  454. return SpeedyPipelineKeypointDetectorFactory;
  455. }
  456. /**
  457. * Keypoint descriptors
  458. * @returns {typeof SpeedyPipelineKeypointDescriptorFactory}
  459. */
  460. static get Descriptor()
  461. {
  462. return SpeedyPipelineKeypointDescriptorFactory;
  463. }
  464. /**
  465. * Keypoint trackers
  466. * @returns {typeof SpeedyPipelineKeypointTrackerFactory}
  467. */
  468. static get Tracker()
  469. {
  470. return SpeedyPipelineKeypointTrackerFactory;
  471. }
  472. /**
  473. * Keypoint matchers
  474. * @returns {typeof SpeedyPipelineKeypointMatcherFactory}
  475. */
  476. static get Matcher()
  477. {
  478. return SpeedyPipelineKeypointMatcherFactory;
  479. }
  480. /**
  481. * Keypoint Portals
  482. * @returns {typeof SpeedyPipelineKeypointPortalFactory}
  483. */
  484. static get Portal()
  485. {
  486. return SpeedyPipelineKeypointPortalFactory;
  487. }
  488. /**
  489. * Create a keypoint source
  490. * @param {string} [name]
  491. * @returns {SpeedyPipelineNodeKeypointSource}
  492. */
  493. static Source(name = undefined)
  494. {
  495. return new _nodes_keypoints_source__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointSource(name);
  496. }
  497. /**
  498. * Create a keypoint sink
  499. * @param {string} [name]
  500. * @returns {SpeedyPipelineNodeKeypointSink}
  501. */
  502. static Sink(name = undefined)
  503. {
  504. return new _nodes_keypoints_sink__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeKeypointSink(name);
  505. }
  506. /**
  507. * Create a sink of tracked keypoints
  508. * @param {string} [name]
  509. * @returns {SpeedyPipelineNodeTrackedKeypointSink}
  510. */
  511. static SinkOfTrackedKeypoints(name = undefined)
  512. {
  513. return new _nodes_keypoints_sink__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeTrackedKeypointSink(name);
  514. }
  515. /**
  516. * Create a sink of matched keypoints
  517. * @param {string} [name]
  518. * @returns {SpeedyPipelineNodeMatchedKeypointSink}
  519. */
  520. static SinkOfMatchedKeypoints(name = undefined)
  521. {
  522. return new _nodes_keypoints_sink__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeMatchedKeypointSink(name);
  523. }
  524. /**
  525. * Keypoint clipper
  526. * @param {string} [name]
  527. * @returns {SpeedyPipelineNodeKeypointClipper}
  528. */
  529. static Clipper(name = undefined)
  530. {
  531. return new _nodes_keypoints_clipper__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeKeypointClipper(name);
  532. }
  533. /**
  534. * Border Clipper
  535. * @param {string} [name]
  536. * @returns {SpeedyPipelineNodeKeypointBorderClipper}
  537. */
  538. static BorderClipper(name = undefined)
  539. {
  540. return new _nodes_keypoints_border_clipper__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineNodeKeypointBorderClipper(name);
  541. }
  542. /**
  543. * Create a keypoint buffer
  544. * @param {string} [name]
  545. * @returns {SpeedyPipelineNodeKeypointBuffer}
  546. */
  547. static Buffer(name = undefined)
  548. {
  549. return new _nodes_keypoints_buffer__WEBPACK_IMPORTED_MODULE_5__.SpeedyPipelineNodeKeypointBuffer(name);
  550. }
  551. /**
  552. * Create a keypoint mixer
  553. * @param {string} [name]
  554. * @returns {SpeedyPipelineNodeKeypointMixer}
  555. */
  556. static Mixer(name = undefined)
  557. {
  558. return new _nodes_keypoints_mixer__WEBPACK_IMPORTED_MODULE_6__.SpeedyPipelineNodeKeypointMixer(name);
  559. }
  560. /**
  561. * Create a keypoint shuffler
  562. * @param {string} [name]
  563. * @returns {SpeedyPipelineNodeKeypointShuffler}
  564. */
  565. static Shuffler(name = undefined)
  566. {
  567. return new _nodes_keypoints_shuffler__WEBPACK_IMPORTED_MODULE_7__.SpeedyPipelineNodeKeypointShuffler(name);
  568. }
  569. /**
  570. * Create a keypoint multiplexer
  571. * @param {string} [name]
  572. * @returns {SpeedyPipelineNodeKeypointMultiplexer}
  573. */
  574. static Multiplexer(name = undefined)
  575. {
  576. return new _nodes_keypoints_multiplexer__WEBPACK_IMPORTED_MODULE_8__.SpeedyPipelineNodeKeypointMultiplexer(name);
  577. }
  578. /**
  579. * Create a keypoint transformer
  580. * @param {string} [name]
  581. * @returns {SpeedyPipelineNodeKeypointTransformer}
  582. */
  583. static Transformer(name = undefined)
  584. {
  585. return new _nodes_keypoints_transformer__WEBPACK_IMPORTED_MODULE_9__.SpeedyPipelineNodeKeypointTransformer(name);
  586. }
  587. /**
  588. * Create a subpixel refiner of keypoint locations
  589. * @param {string} [name]
  590. * @returns {SpeedyPipelineNodeKeypointSubpixelRefiner}
  591. */
  592. static SubpixelRefiner(name = undefined)
  593. {
  594. return new _nodes_keypoints_subpixel__WEBPACK_IMPORTED_MODULE_10__.SpeedyPipelineNodeKeypointSubpixelRefiner(name);
  595. }
  596. /**
  597. * Distance filter
  598. * @param {string} [name]
  599. * @returns {SpeedyPipelineNodeDistanceFilter}
  600. */
  601. static DistanceFilter(name = undefined)
  602. {
  603. return new _nodes_keypoints_distance_filter__WEBPACK_IMPORTED_MODULE_18__.SpeedyPipelineNodeKeypointDistanceFilter(name);
  604. }
  605. /**
  606. * Hamming distance filter
  607. * @param {string} [name]
  608. * @returns {SpeedyPipelineNodeHammingDistanceFilter}
  609. */
  610. static HammingDistanceFilter(name = undefined)
  611. {
  612. return new _nodes_keypoints_hamming_distance_filter__WEBPACK_IMPORTED_MODULE_19__.SpeedyPipelineNodeKeypointHammingDistanceFilter(name);
  613. }
  614. }
  615. /***/ }),
  616. /***/ "./src/core/pipeline/factories/transform-factory.js":
  617. /*!**********************************************************!*\
  618. !*** ./src/core/pipeline/factories/transform-factory.js ***!
  619. \**********************************************************/
  620. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_26355__) => {
  621. "use strict";
  622. __nested_webpack_require_26355__.r(__webpack_exports__);
  623. /* harmony export */ __nested_webpack_require_26355__.d(__webpack_exports__, {
  624. /* harmony export */ "SpeedyPipelineTransformFactory": () => (/* binding */ SpeedyPipelineTransformFactory)
  625. /* harmony export */ });
  626. /* harmony import */ var _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_26355__(/*! ../../speedy-namespace */ "./src/core/speedy-namespace.js");
  627. /* harmony import */ var _nodes_transforms_perspective_warp__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_26355__(/*! ../nodes/transforms/perspective-warp */ "./src/core/pipeline/nodes/transforms/perspective-warp.js");
  628. /* harmony import */ var _nodes_transforms_resize__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_26355__(/*! ../nodes/transforms/resize */ "./src/core/pipeline/nodes/transforms/resize.js");
  629. /*
  630. * speedy-vision.js
  631. * GPU-accelerated Computer Vision for JavaScript
  632. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  633. *
  634. * Licensed under the Apache License, Version 2.0 (the "License");
  635. * you may not use this file except in compliance with the License.
  636. * You may obtain a copy of the License at
  637. *
  638. * http://www.apache.org/licenses/LICENSE-2.0
  639. *
  640. * Unless required by applicable law or agreed to in writing, software
  641. * distributed under the License is distributed on an "AS IS" BASIS,
  642. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  643. * See the License for the specific language governing permissions and
  644. * limitations under the License.
  645. *
  646. * transform-factory.js
  647. * Image transforms
  648. */
  649. /**
  650. * Image transforms
  651. */
  652. class SpeedyPipelineTransformFactory extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  653. {
  654. /**
  655. * Resize image
  656. * @param {string} [name]
  657. * @returns {SpeedyPipelineNodeResize}
  658. */
  659. static Resize(name = undefined)
  660. {
  661. return new _nodes_transforms_resize__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeResize(name);
  662. }
  663. /**
  664. * Warp an image using a perspective transformation
  665. * @param {string} [name]
  666. * @returns {SpeedyPipelineNodePerspectiveWarp}
  667. */
  668. static PerspectiveWarp(name = undefined)
  669. {
  670. return new _nodes_transforms_perspective_warp__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodePerspectiveWarp(name);
  671. }
  672. }
  673. /***/ }),
  674. /***/ "./src/core/pipeline/factories/vector2-factory.js":
  675. /*!********************************************************!*\
  676. !*** ./src/core/pipeline/factories/vector2-factory.js ***!
  677. \********************************************************/
  678. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_29001__) => {
  679. "use strict";
  680. __nested_webpack_require_29001__.r(__webpack_exports__);
  681. /* harmony export */ __nested_webpack_require_29001__.d(__webpack_exports__, {
  682. /* harmony export */ "SpeedyPipelineVector2Factory": () => (/* binding */ SpeedyPipelineVector2Factory)
  683. /* harmony export */ });
  684. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_29001__(/*! ../../speedy-vector */ "./src/core/speedy-vector.js");
  685. /* harmony import */ var _nodes_vector2_sink__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_29001__(/*! ../nodes/vector2/sink */ "./src/core/pipeline/nodes/vector2/sink.js");
  686. /*
  687. * speedy-vision.js
  688. * GPU-accelerated Computer Vision for JavaScript
  689. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  690. *
  691. * Licensed under the Apache License, Version 2.0 (the "License");
  692. * you may not use this file except in compliance with the License.
  693. * You may obtain a copy of the License at
  694. *
  695. * http://www.apache.org/licenses/LICENSE-2.0
  696. *
  697. * Unless required by applicable law or agreed to in writing, software
  698. * distributed under the License is distributed on an "AS IS" BASIS,
  699. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  700. * See the License for the specific language governing permissions and
  701. * limitations under the License.
  702. *
  703. * vector2-factory.js
  704. * 2D vectors
  705. */
  706. /**
  707. * 2D vectors
  708. */
  709. class SpeedyPipelineVector2Factory extends Function
  710. {
  711. /**
  712. * Constructor
  713. */
  714. constructor()
  715. {
  716. // This factory can be invoked as a function
  717. super('...args', 'return this._create(...args)');
  718. return this.bind(this);
  719. }
  720. /**
  721. * @private
  722. *
  723. * Create a 2D vector
  724. * @param {number} x x-coordinate
  725. * @param {number} y y-coordinate
  726. * @returns {SpeedyVector2}
  727. */
  728. _create(x, y)
  729. {
  730. return new _speedy_vector__WEBPACK_IMPORTED_MODULE_0__.SpeedyVector2(x, y);
  731. }
  732. /**
  733. * Create a Vector2 sink
  734. * @param {string} [name]
  735. * @returns {SpeedyPipelineNodeVector2Sink}
  736. */
  737. Sink(name = undefined)
  738. {
  739. return new _nodes_vector2_sink__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeVector2Sink(name);
  740. }
  741. }
  742. /***/ }),
  743. /***/ "./src/core/pipeline/nodes/filters/convolution.js":
  744. /*!********************************************************!*\
  745. !*** ./src/core/pipeline/nodes/filters/convolution.js ***!
  746. \********************************************************/
  747. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_31499__) => {
  748. "use strict";
  749. __nested_webpack_require_31499__.r(__webpack_exports__);
  750. /* harmony export */ __nested_webpack_require_31499__.d(__webpack_exports__, {
  751. /* harmony export */ "SpeedyPipelineNodeConvolution": () => (/* binding */ SpeedyPipelineNodeConvolution)
  752. /* harmony export */ });
  753. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_31499__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  754. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_31499__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  755. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_31499__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  756. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_31499__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  757. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_31499__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  758. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_31499__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  759. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_31499__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  760. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_31499__(/*! ../../../../utils/types */ "./src/utils/types.js");
  761. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_31499__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  762. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_31499__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  763. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_31499__(/*! ../../../speedy-matrix */ "./src/core/speedy-matrix.js");
  764. /*
  765. * speedy-vision.js
  766. * GPU-accelerated Computer Vision for JavaScript
  767. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  768. *
  769. * Licensed under the Apache License, Version 2.0 (the "License");
  770. * you may not use this file except in compliance with the License.
  771. * You may obtain a copy of the License at
  772. *
  773. * http://www.apache.org/licenses/LICENSE-2.0
  774. *
  775. * Unless required by applicable law or agreed to in writing, software
  776. * distributed under the License is distributed on an "AS IS" BASIS,
  777. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  778. * See the License for the specific language governing permissions and
  779. * limitations under the License.
  780. *
  781. * convolution.js
  782. * Image convolution
  783. */
  784. // 2D convolution programs
  785. const CONVOLUTION = {
  786. 3: 'convolution3',
  787. 5: 'convolution5',
  788. 7: 'convolution7',
  789. };
  790. /**
  791. * Image convolution
  792. */
  793. class SpeedyPipelineNodeConvolution extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  794. {
  795. /**
  796. * Constructor
  797. * @param {string} [name] name of the node
  798. */
  799. constructor(name = undefined)
  800. {
  801. super(name, 1, [
  802. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  803. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  804. ]);
  805. /** @type {SpeedyMatrix} convolution kernel (square matrix) */
  806. this._kernel = _speedy_matrix__WEBPACK_IMPORTED_MODULE_10__.SpeedyMatrix.Create(3, 3, [0, 0, 0, 0, 1, 0, 0, 0, 0]); // identity transform
  807. }
  808. /**
  809. * Convolution kernel
  810. * @returns {SpeedyMatrix}
  811. */
  812. get kernel()
  813. {
  814. return this._kernel;
  815. }
  816. /**
  817. * Convolution kernel
  818. * @param {SpeedyMatrix} kernel
  819. */
  820. set kernel(kernel)
  821. {
  822. if(kernel.rows != kernel.columns)
  823. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Use a square kernel`);
  824. else if(!(kernel.rows == 3 || kernel.rows == 5 || kernel.rows == 7))
  825. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Invalid kernel size. Supported sizes: 3x3, 5x5, 7x7`);
  826. this._kernel = kernel;
  827. }
  828. /**
  829. * Run the specific task of this node
  830. * @param {SpeedyGPU} gpu
  831. * @returns {void|SpeedyPromise<void>}
  832. */
  833. _run(gpu)
  834. {
  835. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  836. const width = image.width, height = image.height;
  837. const outputTexture = this._tex[0];
  838. const ksize = this._kernel.rows;
  839. const conv = CONVOLUTION[ksize];
  840. const kernel = this._kernel.read();
  841. (gpu.programs.filters[conv]
  842. .outputs(width, height, outputTexture)
  843. )(image, kernel);
  844. this.output().swrite(outputTexture, format);
  845. }
  846. }
  847. /***/ }),
  848. /***/ "./src/core/pipeline/nodes/filters/gaussian-blur.js":
  849. /*!**********************************************************!*\
  850. !*** ./src/core/pipeline/nodes/filters/gaussian-blur.js ***!
  851. \**********************************************************/
  852. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_36861__) => {
  853. "use strict";
  854. __nested_webpack_require_36861__.r(__webpack_exports__);
  855. /* harmony export */ __nested_webpack_require_36861__.d(__webpack_exports__, {
  856. /* harmony export */ "SpeedyPipelineNodeGaussianBlur": () => (/* binding */ SpeedyPipelineNodeGaussianBlur)
  857. /* harmony export */ });
  858. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_36861__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  859. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_36861__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  860. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_36861__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  861. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_36861__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  862. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_36861__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  863. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_36861__(/*! ../../../speedy-vector */ "./src/core/speedy-vector.js");
  864. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_36861__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  865. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_36861__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  866. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_36861__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  867. /*
  868. * speedy-vision.js
  869. * GPU-accelerated Computer Vision for JavaScript
  870. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  871. *
  872. * Licensed under the Apache License, Version 2.0 (the "License");
  873. * you may not use this file except in compliance with the License.
  874. * You may obtain a copy of the License at
  875. *
  876. * http://www.apache.org/licenses/LICENSE-2.0
  877. *
  878. * Unless required by applicable law or agreed to in writing, software
  879. * distributed under the License is distributed on an "AS IS" BASIS,
  880. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  881. * See the License for the specific language governing permissions and
  882. * limitations under the License.
  883. *
  884. * gaussian-blur.js
  885. * Gaussian Blur
  886. */
  887. /**
  888. * Default kernels for different sizes: 3x3, 5x5, 7x7... (use sigma_x = sigma_y)
  889. * Heuristics: in order to pick a sigma, we set radius = 2 * sigma. Since
  890. * ksize = 1 + 2 * radius, it follows that sigma = (ksize - 1) / 4. When
  891. * ksize is 3, we set sigma = 1. Therefore, sigma = max(1, (ksize - 1) / 4).
  892. */
  893. const DEFAULT_KERNEL = Object.freeze({
  894. 3: [ 0.27901008925473514, 0.44197982149052983, 0.27901008925473514 ], // 1D convolution (sigma = 1)
  895. 5: [ 0.06135959781344021, 0.2447701955296099, 0.3877404133138998, 0.2447701955296099, 0.06135959781344021 ], // 1D convolution (separable kernel)
  896. 7: [ 0.03873542500847274, 0.11308485700794121, 0.2150068609928349, 0.26634571398150225, 0.2150068609928349, 0.11308485700794121, 0.03873542500847274 ],
  897. 9: [ 0.028532262603370988, 0.067234535494912, 0.12400932997922749, 0.17904386461741617, 0.20236001461014655, 0.17904386461741617, 0.12400932997922749, 0.067234535494912, 0.028532262603370988 ],
  898. 11:[ 0.022656882730580346, 0.04610857898527292, 0.08012661469398517, 0.11890414969751599, 0.15067709325491124, 0.16305336127546846, 0.15067709325491124, 0.11890414969751599, 0.08012661469398517, 0.04610857898527292, 0.022656882730580346 ],
  899. 13:[ 0.018815730430644363, 0.03447396964662016, 0.05657737457255748, 0.08317258170844948, 0.10952340502389682, 0.12918787500405662, 0.13649812722755, 0.12918787500405662, 0.10952340502389682, 0.08317258170844948, 0.05657737457255748, 0.03447396964662016, 0.018815730430644363 ],
  900. 15:[ 0.016100340991695383, 0.027272329212157102, 0.042598338587449644, 0.06135478775568558, 0.08148767614129326, 0.09979838342934616, 0.11270444144735056, 0.11736740487004466, 0.11270444144735056, 0.09979838342934616, 0.08148767614129326, 0.06135478775568558, 0.042598338587449644, 0.027272329212157102, 0.016100340991695383 ],
  901. //3: [ 0.25, 0.5, 0.25 ],
  902. //5: [ 0.05, 0.25, 0.4, 0.25, 0.05 ],
  903. });
  904. /** Zero vector. When we set sigma_x = sigma_y = 0, we use the default rule to compute the actual sigma */
  905. const DEFAULT_SIGMA = new _speedy_vector__WEBPACK_IMPORTED_MODULE_5__.SpeedyVector2(0,0);
  906. /** convolution programs (x-axis) */
  907. const CONVOLUTION_X = Object.freeze({
  908. 3: 'convolution3x',
  909. 5: 'convolution5x',
  910. 7: 'convolution7x',
  911. 9: 'convolution9x',
  912. 11: 'convolution11x',
  913. 13: 'convolution13x',
  914. 15: 'convolution15x',
  915. });
  916. /** convolution programs (y-axis) */
  917. const CONVOLUTION_Y = Object.freeze({
  918. 3: 'convolution3y',
  919. 5: 'convolution5y',
  920. 7: 'convolution7y',
  921. 9: 'convolution9y',
  922. 11: 'convolution11y',
  923. 13: 'convolution13y',
  924. 15: 'convolution15y',
  925. });
  926. /**
  927. * @typedef {object} SeparableConvolutionKernel
  928. * @property {number[]} x
  929. * @property {number[]} y
  930. */
  931. /**
  932. * Gaussian Blur
  933. */
  934. class SpeedyPipelineNodeGaussianBlur extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  935. {
  936. /**
  937. * Constructor
  938. * @param {string} [name] name of the node
  939. */
  940. constructor(name = undefined)
  941. {
  942. super(name, 2, [
  943. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  944. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  945. ]);
  946. /** @type {SpeedySize} size of the kernel */
  947. this._kernelSize = new _speedy_size__WEBPACK_IMPORTED_MODULE_4__.SpeedySize(5,5);
  948. /** @type {SpeedyVector2} sigma of the Gaussian kernel (0 means: use default settings) */
  949. this._sigma = DEFAULT_SIGMA;
  950. /** @type {SeparableConvolutionKernel} convolution kernel */
  951. this._kernel = {
  952. x: DEFAULT_KERNEL[this._kernelSize.width],
  953. y: DEFAULT_KERNEL[this._kernelSize.height]
  954. };
  955. }
  956. /**
  957. * Size of the kernel
  958. * @returns {SpeedySize}
  959. */
  960. get kernelSize()
  961. {
  962. return this._kernelSize;
  963. }
  964. /**
  965. * Size of the kernel
  966. * @param {SpeedySize} kernelSize
  967. */
  968. set kernelSize(kernelSize)
  969. {
  970. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(kernelSize instanceof _speedy_size__WEBPACK_IMPORTED_MODULE_4__.SpeedySize);
  971. const kw = kernelSize.width, kh = kernelSize.height;
  972. if(kw < 3 || kh < 3 || kw > 15 || kh > 15 || kw % 2 == 0 || kh % 2 == 0)
  973. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.NotSupportedError(`Unsupported kernel size: ${kw}x${kh}`);
  974. this._kernelSize = kernelSize;
  975. this._updateKernel();
  976. }
  977. /**
  978. * Sigma of the Gaussian kernel
  979. * @returns {SpeedyVector2}
  980. */
  981. get sigma()
  982. {
  983. return this._sigma;
  984. }
  985. /**
  986. * Sigma of the Gaussian kernel
  987. * @param {SpeedyVector2} sigma
  988. */
  989. set sigma(sigma)
  990. {
  991. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(sigma instanceof _speedy_vector__WEBPACK_IMPORTED_MODULE_5__.SpeedyVector2, `Sigma must be a SpeedyVector2`);
  992. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(sigma.x >= 0 && sigma.y >= 0);
  993. this._sigma = sigma;
  994. this._updateKernel();
  995. }
  996. /**
  997. * Run the specific task of this node
  998. * @param {SpeedyGPU} gpu
  999. * @returns {void|SpeedyPromise<void>}
  1000. */
  1001. _run(gpu)
  1002. {
  1003. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1004. const width = image.width, height = image.height;
  1005. const kernX = this._kernel.x;
  1006. const kernY = this._kernel.y;
  1007. const convX = CONVOLUTION_X[this._kernelSize.width];
  1008. const convY = CONVOLUTION_Y[this._kernelSize.height];
  1009. const tex = this._tex[0];
  1010. const outputTexture = this._tex[1];
  1011. (gpu.programs.filters[convX]
  1012. .outputs(width, height, tex)
  1013. )(image, kernX);
  1014. (gpu.programs.filters[convY]
  1015. .outputs(width, height, outputTexture)
  1016. )(tex, kernY);
  1017. this.output().swrite(outputTexture, format);
  1018. }
  1019. /**
  1020. * Update the internal kernel to match
  1021. * sigma and kernelSize
  1022. */
  1023. _updateKernel()
  1024. {
  1025. if(this._sigma.x == DEFAULT_SIGMA.x)
  1026. this._kernel.x = DEFAULT_KERNEL[this._kernelSize.width];
  1027. else
  1028. this._kernel.x = _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.gaussianKernel(this._sigma.x, this._kernelSize.width, true);
  1029. if(this._sigma.y == DEFAULT_SIGMA.y)
  1030. this._kernel.y = DEFAULT_KERNEL[this._kernelSize.height];
  1031. else
  1032. this._kernel.y = _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.gaussianKernel(this._sigma.y, this._kernelSize.height, true);
  1033. }
  1034. }
  1035. /***/ }),
  1036. /***/ "./src/core/pipeline/nodes/filters/greyscale.js":
  1037. /*!******************************************************!*\
  1038. !*** ./src/core/pipeline/nodes/filters/greyscale.js ***!
  1039. \******************************************************/
  1040. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_46305__) => {
  1041. "use strict";
  1042. __nested_webpack_require_46305__.r(__webpack_exports__);
  1043. /* harmony export */ __nested_webpack_require_46305__.d(__webpack_exports__, {
  1044. /* harmony export */ "SpeedyPipelineNodeGreyscale": () => (/* binding */ SpeedyPipelineNodeGreyscale)
  1045. /* harmony export */ });
  1046. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_46305__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1047. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_46305__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1048. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_46305__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1049. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_46305__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1050. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_46305__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1051. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_46305__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1052. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_46305__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1053. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_46305__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1054. /*
  1055. * speedy-vision.js
  1056. * GPU-accelerated Computer Vision for JavaScript
  1057. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1058. *
  1059. * Licensed under the Apache License, Version 2.0 (the "License");
  1060. * you may not use this file except in compliance with the License.
  1061. * You may obtain a copy of the License at
  1062. *
  1063. * http://www.apache.org/licenses/LICENSE-2.0
  1064. *
  1065. * Unless required by applicable law or agreed to in writing, software
  1066. * distributed under the License is distributed on an "AS IS" BASIS,
  1067. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1068. * See the License for the specific language governing permissions and
  1069. * limitations under the License.
  1070. *
  1071. * greyscale.js
  1072. * Convert an image to greyscale
  1073. */
  1074. /**
  1075. * Convert an image to greyscale
  1076. */
  1077. class SpeedyPipelineNodeGreyscale extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1078. {
  1079. /**
  1080. * Constructor
  1081. * @param {string} [name] name of the node
  1082. */
  1083. constructor(name = undefined)
  1084. {
  1085. super(name, 1, [
  1086. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1087. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1088. ]);
  1089. }
  1090. /**
  1091. * Run the specific task of this node
  1092. * @param {SpeedyGPU} gpu
  1093. * @returns {void|SpeedyPromise<void>}
  1094. */
  1095. _run(gpu)
  1096. {
  1097. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1098. const width = image.width, height = image.height;
  1099. const outputTexture = this._tex[0];
  1100. const filters = gpu.programs.filters;
  1101. filters.rgb2grey.outputs(width, height, outputTexture);
  1102. filters.rgb2grey(image);
  1103. this.output().swrite(outputTexture, _utils_types__WEBPACK_IMPORTED_MODULE_6__.ImageFormat.GREY);
  1104. }
  1105. }
  1106. /***/ }),
  1107. /***/ "./src/core/pipeline/nodes/filters/median-blur.js":
  1108. /*!********************************************************!*\
  1109. !*** ./src/core/pipeline/nodes/filters/median-blur.js ***!
  1110. \********************************************************/
  1111. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_50196__) => {
  1112. "use strict";
  1113. __nested_webpack_require_50196__.r(__webpack_exports__);
  1114. /* harmony export */ __nested_webpack_require_50196__.d(__webpack_exports__, {
  1115. /* harmony export */ "SpeedyPipelineNodeMedianBlur": () => (/* binding */ SpeedyPipelineNodeMedianBlur)
  1116. /* harmony export */ });
  1117. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_50196__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1118. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_50196__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1119. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_50196__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1120. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_50196__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1121. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_50196__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1122. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_50196__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  1123. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_50196__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1124. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_50196__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1125. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_50196__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1126. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_50196__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1127. /*
  1128. * speedy-vision.js
  1129. * GPU-accelerated Computer Vision for JavaScript
  1130. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1131. *
  1132. * Licensed under the Apache License, Version 2.0 (the "License");
  1133. * you may not use this file except in compliance with the License.
  1134. * You may obtain a copy of the License at
  1135. *
  1136. * http://www.apache.org/licenses/LICENSE-2.0
  1137. *
  1138. * Unless required by applicable law or agreed to in writing, software
  1139. * distributed under the License is distributed on an "AS IS" BASIS,
  1140. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1141. * See the License for the specific language governing permissions and
  1142. * limitations under the License.
  1143. *
  1144. * median-blur.js
  1145. * Median Blur
  1146. */
  1147. // Median programs
  1148. const MEDIAN = {
  1149. 3: 'median3',
  1150. 5: 'median5',
  1151. 7: 'median7',
  1152. };
  1153. /**
  1154. * Median Blur
  1155. */
  1156. class SpeedyPipelineNodeMedianBlur extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1157. {
  1158. /**
  1159. * Constructor
  1160. * @param {string} [name] name of the node
  1161. */
  1162. constructor(name = undefined)
  1163. {
  1164. super(name, 1, [
  1165. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  1166. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  1167. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_7__.ImageFormat.GREY
  1168. ),
  1169. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1170. ]);
  1171. /** @type {SpeedySize} size of the kernel (assumed to be square) */
  1172. this._kernelSize = new _speedy_size__WEBPACK_IMPORTED_MODULE_5__.SpeedySize(5,5);
  1173. }
  1174. /**
  1175. * Size of the kernel
  1176. * @returns {SpeedySize}
  1177. */
  1178. get kernelSize()
  1179. {
  1180. return this._kernelSize;
  1181. }
  1182. /**
  1183. * Size of the kernel
  1184. * @param {SpeedySize} kernelSize
  1185. */
  1186. set kernelSize(kernelSize)
  1187. {
  1188. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(kernelSize instanceof _speedy_size__WEBPACK_IMPORTED_MODULE_5__.SpeedySize);
  1189. const ksize = kernelSize.width;
  1190. if(!(ksize == 3 || ksize == 5 || ksize == 7))
  1191. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Supported kernel sizes: 3x3, 5x5, 7x7`);
  1192. else if(kernelSize.width != kernelSize.height)
  1193. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Use a square kernel`);
  1194. this._kernelSize = kernelSize;
  1195. }
  1196. /**
  1197. * Run the specific task of this node
  1198. * @param {SpeedyGPU} gpu
  1199. * @returns {void|SpeedyPromise<void>}
  1200. */
  1201. _run(gpu)
  1202. {
  1203. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1204. const width = image.width, height = image.height;
  1205. const ksize = this._kernelSize.width;
  1206. const med = MEDIAN[ksize];
  1207. const outputTexture = this._tex[0];
  1208. (gpu.programs.filters[med]
  1209. .outputs(width, height, outputTexture)
  1210. )(image);
  1211. this.output().swrite(outputTexture, format);
  1212. }
  1213. }
  1214. /***/ }),
  1215. /***/ "./src/core/pipeline/nodes/filters/nightvision.js":
  1216. /*!********************************************************!*\
  1217. !*** ./src/core/pipeline/nodes/filters/nightvision.js ***!
  1218. \********************************************************/
  1219. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_55621__) => {
  1220. "use strict";
  1221. __nested_webpack_require_55621__.r(__webpack_exports__);
  1222. /* harmony export */ __nested_webpack_require_55621__.d(__webpack_exports__, {
  1223. /* harmony export */ "SpeedyPipelineNodeNightvision": () => (/* binding */ SpeedyPipelineNodeNightvision)
  1224. /* harmony export */ });
  1225. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_55621__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1226. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_55621__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1227. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_55621__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1228. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_55621__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1229. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_55621__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1230. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_55621__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1231. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_55621__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1232. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_55621__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1233. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_55621__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1234. /*
  1235. * speedy-vision.js
  1236. * GPU-accelerated Computer Vision for JavaScript
  1237. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1238. *
  1239. * Licensed under the Apache License, Version 2.0 (the "License");
  1240. * you may not use this file except in compliance with the License.
  1241. * You may obtain a copy of the License at
  1242. *
  1243. * http://www.apache.org/licenses/LICENSE-2.0
  1244. *
  1245. * Unless required by applicable law or agreed to in writing, software
  1246. * distributed under the License is distributed on an "AS IS" BASIS,
  1247. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1248. * See the License for the specific language governing permissions and
  1249. * limitations under the License.
  1250. *
  1251. * nightvision.js
  1252. * Nightvision filter
  1253. */
  1254. /**
  1255. * @typedef {"high"|"medium"|"low"} NightvisionQualityLevel
  1256. */
  1257. /**
  1258. * Nightvision filter: "see in the dark"
  1259. */
  1260. class SpeedyPipelineNodeNightvision extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1261. {
  1262. /**
  1263. * Constructor
  1264. * @param {string} [name] name of the node
  1265. */
  1266. constructor(name = undefined)
  1267. {
  1268. super(name, 3, [
  1269. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  1270. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  1271. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_7__.ImageFormat.RGBA ||
  1272. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_7__.ImageFormat.GREY
  1273. ),
  1274. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1275. ]);
  1276. /** @type {number} a value typically in [0,1]: larger number => higher contrast */
  1277. this._gain = 0.5;
  1278. /** @type {number} a value typically in [0,1]: controls brightness */
  1279. this._offset = 0.5;
  1280. /** @type {number} gain decay, a value in [0,1] */
  1281. this._decay = 0.0;
  1282. /** @type {NightvisionQualityLevel} quality level */
  1283. this._quality = 'medium';
  1284. }
  1285. /**
  1286. * Gain, a value typically in [0,1]: larger number => higher contrast
  1287. * @returns {number}
  1288. */
  1289. get gain()
  1290. {
  1291. return this._gain;
  1292. }
  1293. /**
  1294. * Gain, a value typically in [0,1]: larger number => higher contrast
  1295. * @param {number} gain
  1296. */
  1297. set gain(gain)
  1298. {
  1299. this._gain = +gain;
  1300. }
  1301. /**
  1302. * Offset, a value typically in [0,1] that controls the brightness
  1303. * @returns {number}
  1304. */
  1305. get offset()
  1306. {
  1307. return this._offset;
  1308. }
  1309. /**
  1310. * Offset, a value typically in [0,1] that controls the brightness
  1311. * @param {number} offset
  1312. */
  1313. set offset(offset)
  1314. {
  1315. this._offset = +offset;
  1316. }
  1317. /**
  1318. * Gain decay, a value in [0,1] that controls how the gain decays from the center of the image
  1319. * @returns {number}
  1320. */
  1321. get decay()
  1322. {
  1323. return this._decay;
  1324. }
  1325. /**
  1326. * Gain decay, a value in [0,1] that controls how the gain decays from the center of the image
  1327. * @param {number} decay
  1328. */
  1329. set decay(decay)
  1330. {
  1331. this._decay = Math.max(0.0, Math.min(+decay, 1.0));
  1332. }
  1333. /**
  1334. * Quality level of the filter
  1335. * @returns {NightvisionQualityLevel}
  1336. */
  1337. get quality()
  1338. {
  1339. return this._quality;
  1340. }
  1341. /**
  1342. * Quality level of the filter
  1343. * @param {NightvisionQualityLevel} quality
  1344. */
  1345. set quality(quality)
  1346. {
  1347. if(quality === 'high' || quality === 'medium' || quality === 'low')
  1348. this._quality = quality;
  1349. else
  1350. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_6__.IllegalArgumentError(`Invalid quality level for the Nightvision filter: "${quality}"`);
  1351. }
  1352. /**
  1353. * Run the specific task of this node
  1354. * @param {SpeedyGPU} gpu
  1355. * @returns {void|SpeedyPromise<void>}
  1356. */
  1357. _run(gpu)
  1358. {
  1359. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1360. const width = image.width, height = image.height;
  1361. const gain = this._gain;
  1362. const offset = this._offset;
  1363. const decay = this._decay;
  1364. const quality = this._quality;
  1365. const filters = gpu.programs.filters;
  1366. const tmp = this._tex[0];
  1367. const illuminationMap = this._tex[1];
  1368. const outputTexture = this._tex[2];
  1369. // compute illumination map
  1370. if(quality == 'medium') {
  1371. filters.illuminationMapX.outputs(width, height, tmp);
  1372. filters.illuminationMapY.outputs(width, height, illuminationMap);
  1373. filters.illuminationMapX(image);
  1374. filters.illuminationMapY(tmp);
  1375. }
  1376. else if(quality == 'high') {
  1377. filters.illuminationMapHiX.outputs(width, height, tmp);
  1378. filters.illuminationMapHiY.outputs(width, height, illuminationMap);
  1379. filters.illuminationMapHiX(image);
  1380. filters.illuminationMapHiY(tmp);
  1381. }
  1382. else if(quality == 'low') {
  1383. filters.illuminationMapLoX.outputs(width, height, tmp);
  1384. filters.illuminationMapLoY.outputs(width, height, illuminationMap);
  1385. filters.illuminationMapLoX(image);
  1386. filters.illuminationMapLoY(tmp);
  1387. }
  1388. // run nightvision
  1389. if(format === _utils_types__WEBPACK_IMPORTED_MODULE_7__.ImageFormat.GREY) {
  1390. filters.nightvisionGreyscale.outputs(width, height, outputTexture);
  1391. filters.nightvisionGreyscale(image, illuminationMap, gain, offset, decay);
  1392. }
  1393. else if(format === _utils_types__WEBPACK_IMPORTED_MODULE_7__.ImageFormat.RGBA) {
  1394. filters.nightvision.outputs(width, height, outputTexture);
  1395. filters.nightvision(image, illuminationMap, gain, offset, decay);
  1396. }
  1397. // done!
  1398. this.output().swrite(outputTexture, format);
  1399. }
  1400. }
  1401. /***/ }),
  1402. /***/ "./src/core/pipeline/nodes/filters/normalize.js":
  1403. /*!******************************************************!*\
  1404. !*** ./src/core/pipeline/nodes/filters/normalize.js ***!
  1405. \******************************************************/
  1406. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_63648__) => {
  1407. "use strict";
  1408. __nested_webpack_require_63648__.r(__webpack_exports__);
  1409. /* harmony export */ __nested_webpack_require_63648__.d(__webpack_exports__, {
  1410. /* harmony export */ "SpeedyPipelineNodeNormalize": () => (/* binding */ SpeedyPipelineNodeNormalize)
  1411. /* harmony export */ });
  1412. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_63648__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1413. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_63648__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1414. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_63648__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1415. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_63648__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1416. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_63648__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1417. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_63648__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1418. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_63648__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1419. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_63648__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1420. /*
  1421. * speedy-vision.js
  1422. * GPU-accelerated Computer Vision for JavaScript
  1423. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1424. *
  1425. * Licensed under the Apache License, Version 2.0 (the "License");
  1426. * you may not use this file except in compliance with the License.
  1427. * You may obtain a copy of the License at
  1428. *
  1429. * http://www.apache.org/licenses/LICENSE-2.0
  1430. *
  1431. * Unless required by applicable law or agreed to in writing, software
  1432. * distributed under the License is distributed on an "AS IS" BASIS,
  1433. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1434. * See the License for the specific language governing permissions and
  1435. * limitations under the License.
  1436. *
  1437. * normalize.js
  1438. * Normalize image to a range
  1439. */
  1440. /**
  1441. * Normalize image to a range
  1442. */
  1443. class SpeedyPipelineNodeNormalize extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1444. {
  1445. /**
  1446. * Constructor
  1447. * @param {string} [name] name of the node
  1448. */
  1449. constructor(name = undefined)
  1450. {
  1451. super(name, 4, [
  1452. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  1453. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  1454. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_6__.ImageFormat.GREY
  1455. ),
  1456. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1457. ]);
  1458. /** @type {number} a value in [0,255] */
  1459. this._minValue = 0;
  1460. /** @type {number} a value in [0,255] */
  1461. this._maxValue = 255;
  1462. }
  1463. /**
  1464. * Minimum intensity in the output image, a value in [0,255]
  1465. * @returns {number}
  1466. */
  1467. get minValue()
  1468. {
  1469. return this._minValue;
  1470. }
  1471. /**
  1472. * Minimum intensity in the output image, a value in [0,255]
  1473. * @param {number} minValue
  1474. */
  1475. set minValue(minValue)
  1476. {
  1477. this._minValue = Math.max(0, Math.min(+minValue, 255));
  1478. }
  1479. /**
  1480. * Maximum intensity in the output image, a value in [0,255]
  1481. * @returns {number}
  1482. */
  1483. get maxValue()
  1484. {
  1485. return this._maxValue;
  1486. }
  1487. /**
  1488. * Maximum intensity in the output image, a value in [0,255]
  1489. * @param {number} maxValue
  1490. */
  1491. set maxValue(maxValue)
  1492. {
  1493. this._maxValue = Math.max(0, Math.min(+maxValue, 255));
  1494. }
  1495. /**
  1496. * Run the specific task of this node
  1497. * @param {SpeedyGPU} gpu
  1498. * @returns {void|SpeedyPromise<void>}
  1499. */
  1500. _run(gpu)
  1501. {
  1502. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1503. const width = image.width, height = image.height;
  1504. const outputTexture = this._tex[3];
  1505. let minValue = this._minValue;
  1506. let maxValue = this._maxValue;
  1507. if(minValue > maxValue)
  1508. minValue = maxValue = (minValue + maxValue) / 2;
  1509. const minmax = this._scanMinMax(gpu, image, _utils_types__WEBPACK_IMPORTED_MODULE_6__.PixelComponent.GREEN);
  1510. gpu.programs.filters.normalizeGreyscale.outputs(width, height, outputTexture);
  1511. gpu.programs.filters.normalizeGreyscale(minmax, minValue, maxValue);
  1512. this.output().swrite(outputTexture, format);
  1513. }
  1514. /**
  1515. * Scan a single component in all pixels of the image and find the min & max intensities
  1516. * @param {SpeedyGPU} gpu
  1517. * @param {SpeedyTexture} image input image
  1518. * @param {PixelComponent} pixelComponent a single PixelComponent flag
  1519. * @returns {SpeedyDrawableTexture} RGBA = (max, min, max - min, original_pixel)
  1520. */
  1521. _scanMinMax(gpu, image, pixelComponent)
  1522. {
  1523. const tex = this._tex;
  1524. const program = gpu.programs.utils;
  1525. const width = image.width, height = image.height;
  1526. const numIterations = Math.ceil(Math.log2(Math.max(width, height))) | 0;
  1527. _utils_utils__WEBPACK_IMPORTED_MODULE_5__.Utils.assert(_utils_types__WEBPACK_IMPORTED_MODULE_6__.ColorComponentId[pixelComponent] !== undefined);
  1528. program.copyComponents.outputs(width, height, tex[2]);
  1529. program.scanMinMax2D.outputs(width, height, tex[0], tex[1]);
  1530. let texture = program.copyComponents(image, image, _utils_types__WEBPACK_IMPORTED_MODULE_6__.PixelComponent.ALL, _utils_types__WEBPACK_IMPORTED_MODULE_6__.ColorComponentId[pixelComponent]);
  1531. for(let i = 0; i < numIterations; i++)
  1532. texture = program.scanMinMax2D(texture, i);
  1533. return texture;
  1534. }
  1535. }
  1536. /***/ }),
  1537. /***/ "./src/core/pipeline/nodes/filters/simple-blur.js":
  1538. /*!********************************************************!*\
  1539. !*** ./src/core/pipeline/nodes/filters/simple-blur.js ***!
  1540. \********************************************************/
  1541. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_70155__) => {
  1542. "use strict";
  1543. __nested_webpack_require_70155__.r(__webpack_exports__);
  1544. /* harmony export */ __nested_webpack_require_70155__.d(__webpack_exports__, {
  1545. /* harmony export */ "SpeedyPipelineNodeSimpleBlur": () => (/* binding */ SpeedyPipelineNodeSimpleBlur)
  1546. /* harmony export */ });
  1547. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_70155__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1548. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_70155__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1549. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_70155__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1550. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_70155__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1551. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_70155__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1552. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_70155__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  1553. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_70155__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1554. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_70155__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1555. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_70155__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1556. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_70155__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1557. /*
  1558. * speedy-vision.js
  1559. * GPU-accelerated Computer Vision for JavaScript
  1560. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1561. *
  1562. * Licensed under the Apache License, Version 2.0 (the "License");
  1563. * you may not use this file except in compliance with the License.
  1564. * You may obtain a copy of the License at
  1565. *
  1566. * http://www.apache.org/licenses/LICENSE-2.0
  1567. *
  1568. * Unless required by applicable law or agreed to in writing, software
  1569. * distributed under the License is distributed on an "AS IS" BASIS,
  1570. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1571. * See the License for the specific language governing permissions and
  1572. * limitations under the License.
  1573. *
  1574. * simple-blur.js
  1575. * Simple Blur (Box Filter)
  1576. */
  1577. /** 1D convolution filters */
  1578. const BOX_FILTER = Object.freeze({
  1579. 3: (new Array(3)).fill(1/3),
  1580. 5: (new Array(5)).fill(1/5),
  1581. 7: (new Array(7)).fill(1/7),
  1582. 9: (new Array(9)).fill(1/9),
  1583. 11: (new Array(11)).fill(1/11),
  1584. 13: (new Array(13)).fill(1/13),
  1585. 15: (new Array(15)).fill(1/15),
  1586. });
  1587. /** convolution programs (x-axis) */
  1588. const CONVOLUTION_X = Object.freeze({
  1589. 3: 'convolution3x',
  1590. 5: 'convolution5x',
  1591. 7: 'convolution7x',
  1592. 9: 'convolution9x',
  1593. 11: 'convolution11x',
  1594. 13: 'convolution13x',
  1595. 15: 'convolution15x',
  1596. });
  1597. /** convolution programs (y-axis) */
  1598. const CONVOLUTION_Y = Object.freeze({
  1599. 3: 'convolution3y',
  1600. 5: 'convolution5y',
  1601. 7: 'convolution7y',
  1602. 9: 'convolution9y',
  1603. 11: 'convolution11y',
  1604. 13: 'convolution13y',
  1605. 15: 'convolution15y',
  1606. });
  1607. /**
  1608. * @typedef {object} SeparableConvolutionKernel
  1609. * @property {number[]} x
  1610. * @property {number[]} y
  1611. */
  1612. /**
  1613. * Simple Blur (Box Filter)
  1614. */
  1615. class SpeedyPipelineNodeSimpleBlur extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1616. {
  1617. /**
  1618. * Constructor
  1619. * @param {string} [name] name of the node
  1620. */
  1621. constructor(name = undefined)
  1622. {
  1623. super(name, 2, [
  1624. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1625. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1626. ]);
  1627. /** @type {SpeedySize} size of the kernel */
  1628. this._kernelSize = new _speedy_size__WEBPACK_IMPORTED_MODULE_5__.SpeedySize(5,5);
  1629. /** @type {SeparableConvolutionKernel} convolution kernel */
  1630. this._kernel = {
  1631. x: BOX_FILTER[this._kernelSize.width],
  1632. y: BOX_FILTER[this._kernelSize.height]
  1633. };
  1634. }
  1635. /**
  1636. * Size of the kernel
  1637. * @returns {SpeedySize}
  1638. */
  1639. get kernelSize()
  1640. {
  1641. return this._kernelSize;
  1642. }
  1643. /**
  1644. * Size of the kernel
  1645. * @param {SpeedySize} kernelSize
  1646. */
  1647. set kernelSize(kernelSize)
  1648. {
  1649. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(kernelSize instanceof _speedy_size__WEBPACK_IMPORTED_MODULE_5__.SpeedySize);
  1650. const kw = kernelSize.width, kh = kernelSize.height;
  1651. if(kw < 3 || kh < 3 || kw > 15 || kh > 15 || kw % 2 == 0 || kh % 2 == 0)
  1652. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Unsupported kernel size: ${kw}x${kh}`);
  1653. this._kernelSize = kernelSize;
  1654. this._kernel.x = BOX_FILTER[this._kernelSize.width];
  1655. this._kernel.y = BOX_FILTER[this._kernelSize.height];
  1656. }
  1657. /**
  1658. * Run the specific task of this node
  1659. * @param {SpeedyGPU} gpu
  1660. * @returns {void|SpeedyPromise<void>}
  1661. */
  1662. _run(gpu)
  1663. {
  1664. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1665. const width = image.width, height = image.height;
  1666. const kernX = this._kernel.x;
  1667. const kernY = this._kernel.y;
  1668. const convX = CONVOLUTION_X[this._kernelSize.width];
  1669. const convY = CONVOLUTION_Y[this._kernelSize.height];
  1670. const tex = this._tex[0];
  1671. const outputTexture = this._tex[1];
  1672. (gpu.programs.filters[convX]
  1673. .outputs(width, height, tex)
  1674. )(image, kernX);
  1675. (gpu.programs.filters[convY]
  1676. .outputs(width, height, outputTexture)
  1677. )(tex, kernY);
  1678. this.output().swrite(outputTexture, format);
  1679. }
  1680. }
  1681. /***/ }),
  1682. /***/ "./src/core/pipeline/nodes/images/buffer.js":
  1683. /*!**************************************************!*\
  1684. !*** ./src/core/pipeline/nodes/images/buffer.js ***!
  1685. \**************************************************/
  1686. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_76678__) => {
  1687. "use strict";
  1688. __nested_webpack_require_76678__.r(__webpack_exports__);
  1689. /* harmony export */ __nested_webpack_require_76678__.d(__webpack_exports__, {
  1690. /* harmony export */ "SpeedyPipelineNodeImageBuffer": () => (/* binding */ SpeedyPipelineNodeImageBuffer)
  1691. /* harmony export */ });
  1692. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_76678__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1693. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_76678__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1694. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_76678__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1695. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_76678__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1696. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_76678__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1697. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_76678__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1698. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_76678__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1699. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_76678__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1700. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_76678__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1701. /*
  1702. * speedy-vision.js
  1703. * GPU-accelerated Computer Vision for JavaScript
  1704. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1705. *
  1706. * Licensed under the Apache License, Version 2.0 (the "License");
  1707. * you may not use this file except in compliance with the License.
  1708. * You may obtain a copy of the License at
  1709. *
  1710. * http://www.apache.org/licenses/LICENSE-2.0
  1711. *
  1712. * Unless required by applicable law or agreed to in writing, software
  1713. * distributed under the License is distributed on an "AS IS" BASIS,
  1714. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1715. * See the License for the specific language governing permissions and
  1716. * limitations under the License.
  1717. *
  1718. * buffer.js
  1719. * Image Buffer
  1720. */
  1721. /**
  1722. * Image Buffer: a node with memory.
  1723. * At time t, it outputs the image received at time t-1
  1724. */
  1725. class SpeedyPipelineNodeImageBuffer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1726. {
  1727. /**
  1728. * Constructor
  1729. * @param {string} [name] name of the node
  1730. */
  1731. constructor(name = undefined)
  1732. {
  1733. super(name, 2, [
  1734. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1735. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image)
  1736. ]);
  1737. /** @type {number} current page: 0 or 1 */
  1738. this._pageIndex = 0;
  1739. /** @type {boolean} first run? */
  1740. this._initialized = false;
  1741. /** @type {ImageFormat} previous image format */
  1742. this._previousFormat = _utils_types__WEBPACK_IMPORTED_MODULE_3__.ImageFormat.RGBA;
  1743. /** @type {boolean} frozen buffer? */
  1744. this._frozen = false;
  1745. }
  1746. /**
  1747. * A frozen buffer discards the input, effectively increasing the buffering time
  1748. * @returns {boolean}
  1749. */
  1750. get frozen()
  1751. {
  1752. return this._frozen;
  1753. }
  1754. /**
  1755. * A frozen buffer discards the input, effectively increasing the buffering time
  1756. * @param {boolean} value
  1757. */
  1758. set frozen(value)
  1759. {
  1760. this._frozen = Boolean(value);
  1761. }
  1762. /**
  1763. * Releases this node
  1764. * @param {SpeedyGPU} gpu
  1765. */
  1766. release(gpu)
  1767. {
  1768. this._initialized = false;
  1769. super.release(gpu);
  1770. }
  1771. /**
  1772. * Run the specific task of this node
  1773. * @param {SpeedyGPU} gpu
  1774. * @returns {void|SpeedyPromise<void>}
  1775. */
  1776. _run(gpu)
  1777. {
  1778. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  1779. const previousFormat = this._previousFormat;
  1780. const page = this._tex;
  1781. const previousInputTexture = page[1 - this._pageIndex];
  1782. const outputTexture = page[this._pageIndex];
  1783. // can't store pyramids
  1784. if(image.hasMipmaps())
  1785. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.NotSupportedError(`${this.fullName} can't bufferize a pyramid`);
  1786. // bufferize
  1787. if(!this._frozen || !this._initialized) {
  1788. // store input
  1789. this._previousFormat = format;
  1790. previousInputTexture.resize(image.width, image.height);
  1791. image.copyTo(previousInputTexture);
  1792. // page flipping
  1793. this._pageIndex = 1 - this._pageIndex;
  1794. }
  1795. // first run?
  1796. if(!this._initialized) {
  1797. this._initialized = true;
  1798. this.output().swrite(previousInputTexture, format);
  1799. return;
  1800. }
  1801. // done!
  1802. this.output().swrite(outputTexture, previousFormat);
  1803. }
  1804. }
  1805. /***/ }),
  1806. /***/ "./src/core/pipeline/nodes/images/mixer.js":
  1807. /*!*************************************************!*\
  1808. !*** ./src/core/pipeline/nodes/images/mixer.js ***!
  1809. \*************************************************/
  1810. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_82338__) => {
  1811. "use strict";
  1812. __nested_webpack_require_82338__.r(__webpack_exports__);
  1813. /* harmony export */ __nested_webpack_require_82338__.d(__webpack_exports__, {
  1814. /* harmony export */ "SpeedyPipelineNodeImageMixer": () => (/* binding */ SpeedyPipelineNodeImageMixer)
  1815. /* harmony export */ });
  1816. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_82338__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1817. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_82338__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1818. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_82338__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1819. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_82338__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1820. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_82338__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1821. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_82338__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1822. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_82338__(/*! ../../../../utils/types */ "./src/utils/types.js");
  1823. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_82338__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1824. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_82338__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1825. /*
  1826. * speedy-vision.js
  1827. * GPU-accelerated Computer Vision for JavaScript
  1828. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1829. *
  1830. * Licensed under the Apache License, Version 2.0 (the "License");
  1831. * you may not use this file except in compliance with the License.
  1832. * You may obtain a copy of the License at
  1833. *
  1834. * http://www.apache.org/licenses/LICENSE-2.0
  1835. *
  1836. * Unless required by applicable law or agreed to in writing, software
  1837. * distributed under the License is distributed on an "AS IS" BASIS,
  1838. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1839. * See the License for the specific language governing permissions and
  1840. * limitations under the License.
  1841. *
  1842. * mixer.js
  1843. * Image Mixer
  1844. */
  1845. /**
  1846. * Image Mixer
  1847. */
  1848. class SpeedyPipelineNodeImageMixer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1849. {
  1850. /**
  1851. * Constructor
  1852. * @param {string} [name] name of the node
  1853. */
  1854. constructor(name = undefined)
  1855. {
  1856. super(name, 1, [
  1857. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('in0').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1858. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('in1').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1859. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1860. ]);
  1861. /** @type {number} alpha coefficient (applied to image0) */
  1862. this._alpha = 0.5;
  1863. /** @type {number} beta coefficient (applied to image1) */
  1864. this._beta = 0.5;
  1865. /** @type {number} gamma coefficient (brightness control) */
  1866. this._gamma = 0.0;
  1867. }
  1868. /**
  1869. * Alpha coefficient (applied to image0)
  1870. * @returns {number}
  1871. */
  1872. get alpha()
  1873. {
  1874. return this._alpha;
  1875. }
  1876. /**
  1877. * Alpha coefficient (applied to image0)
  1878. * @param {number} value
  1879. */
  1880. set alpha(value)
  1881. {
  1882. this._alpha = +value;
  1883. }
  1884. /**
  1885. * Beta coefficient (applied to image1)
  1886. * @returns {number}
  1887. */
  1888. get beta()
  1889. {
  1890. return this._beta;
  1891. }
  1892. /**
  1893. * Beta coefficient (applied to image1)
  1894. * @param {number} value
  1895. */
  1896. set beta(value)
  1897. {
  1898. this._beta = +value;
  1899. }
  1900. /**
  1901. * Gamma coefficient (brightness control)
  1902. * @returns {number}
  1903. */
  1904. get gamma()
  1905. {
  1906. return this._gamma;
  1907. }
  1908. /**
  1909. * Gamma coefficient (brightness control)
  1910. * @param {number} value
  1911. */
  1912. set gamma(value)
  1913. {
  1914. this._gamma = +value;
  1915. }
  1916. /**
  1917. * Run the specific task of this node
  1918. * @param {SpeedyGPU} gpu
  1919. * @returns {void|SpeedyPromise<void>}
  1920. */
  1921. _run(gpu)
  1922. {
  1923. const in0 = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('in0').read() );
  1924. const in1 = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('in1').read() );
  1925. const image0 = in0.image, image1 = in1.image;
  1926. const format0 = in0.format, format1 = in1.format;
  1927. const width = Math.max(image0.width, image1.width);
  1928. const height = Math.max(image0.height, image1.height);
  1929. const alpha = this._alpha, beta = this._beta, gamma = this._gamma;
  1930. const outputTexture = this._tex[0];
  1931. if(format0 != format1)
  1932. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Can't mix images of different formats`);
  1933. gpu.programs.transforms.additiveMix.outputs(width, height, outputTexture);
  1934. gpu.programs.transforms.additiveMix(image0, image1, alpha, beta, gamma);
  1935. this.output().swrite(outputTexture, format0);
  1936. }
  1937. }
  1938. /***/ }),
  1939. /***/ "./src/core/pipeline/nodes/images/multiplexer.js":
  1940. /*!*******************************************************!*\
  1941. !*** ./src/core/pipeline/nodes/images/multiplexer.js ***!
  1942. \*******************************************************/
  1943. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_88155__) => {
  1944. "use strict";
  1945. __nested_webpack_require_88155__.r(__webpack_exports__);
  1946. /* harmony export */ __nested_webpack_require_88155__.d(__webpack_exports__, {
  1947. /* harmony export */ "SpeedyPipelineNodeImageMultiplexer": () => (/* binding */ SpeedyPipelineNodeImageMultiplexer)
  1948. /* harmony export */ });
  1949. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_88155__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  1950. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_88155__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  1951. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_88155__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  1952. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_88155__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  1953. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_88155__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  1954. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_88155__(/*! ../../../speedy-media */ "./src/core/speedy-media.js");
  1955. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_88155__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  1956. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_88155__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  1957. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_88155__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  1958. /*
  1959. * speedy-vision.js
  1960. * GPU-accelerated Computer Vision for JavaScript
  1961. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  1962. *
  1963. * Licensed under the Apache License, Version 2.0 (the "License");
  1964. * you may not use this file except in compliance with the License.
  1965. * You may obtain a copy of the License at
  1966. *
  1967. * http://www.apache.org/licenses/LICENSE-2.0
  1968. *
  1969. * Unless required by applicable law or agreed to in writing, software
  1970. * distributed under the License is distributed on an "AS IS" BASIS,
  1971. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1972. * See the License for the specific language governing permissions and
  1973. * limitations under the License.
  1974. *
  1975. * multiplexer.js
  1976. * Image multiplexer
  1977. */
  1978. /** @type {string[]} the names of the input ports indexed by their number */
  1979. const INPUT_PORT = [ 'in0', 'in1' ];
  1980. /**
  1981. * Image multiplexer
  1982. */
  1983. class SpeedyPipelineNodeImageMultiplexer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  1984. {
  1985. /**
  1986. * Constructor
  1987. * @param {string} [name] name of the node
  1988. */
  1989. constructor(name = undefined)
  1990. {
  1991. super(name, 0, [
  1992. ...(INPUT_PORT.map(portName => (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)(portName).expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image))),
  1993. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  1994. ]);
  1995. /** @type {number} which port should be linked to the output? */
  1996. this._port = 0;
  1997. }
  1998. /**
  1999. * The number of the port that should be linked to the output
  2000. * @returns {number}
  2001. */
  2002. get port()
  2003. {
  2004. return this._port;
  2005. }
  2006. /**
  2007. * The number of the port that should be linked to the output
  2008. * @param {number} port
  2009. */
  2010. set port(port)
  2011. {
  2012. if(port < 0 || port >= INPUT_PORT.length)
  2013. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Invalid port: ${port}`);
  2014. this._port = port | 0;
  2015. }
  2016. /**
  2017. * Run the specific task of this node
  2018. * @param {SpeedyGPU} gpu
  2019. * @returns {void|SpeedyPromise<void>}
  2020. */
  2021. _run(gpu)
  2022. {
  2023. const message = this.input(INPUT_PORT[this._port]).read();
  2024. this.output().write(message);
  2025. }
  2026. }
  2027. /***/ }),
  2028. /***/ "./src/core/pipeline/nodes/images/portal.js":
  2029. /*!**************************************************!*\
  2030. !*** ./src/core/pipeline/nodes/images/portal.js ***!
  2031. \**************************************************/
  2032. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_92576__) => {
  2033. "use strict";
  2034. __nested_webpack_require_92576__.r(__webpack_exports__);
  2035. /* harmony export */ __nested_webpack_require_92576__.d(__webpack_exports__, {
  2036. /* harmony export */ "SpeedyPipelineNodeImagePortalSink": () => (/* binding */ SpeedyPipelineNodeImagePortalSink),
  2037. /* harmony export */ "SpeedyPipelineNodeImagePortalSource": () => (/* binding */ SpeedyPipelineNodeImagePortalSource)
  2038. /* harmony export */ });
  2039. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_92576__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2040. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_92576__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2041. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_92576__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2042. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_92576__(/*! ../../../../utils/types */ "./src/utils/types.js");
  2043. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_92576__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2044. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_92576__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2045. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_92576__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2046. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_92576__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  2047. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_92576__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2048. /*
  2049. * speedy-vision.js
  2050. * GPU-accelerated Computer Vision for JavaScript
  2051. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2052. *
  2053. * Licensed under the Apache License, Version 2.0 (the "License");
  2054. * you may not use this file except in compliance with the License.
  2055. * You may obtain a copy of the License at
  2056. *
  2057. * http://www.apache.org/licenses/LICENSE-2.0
  2058. *
  2059. * Unless required by applicable law or agreed to in writing, software
  2060. * distributed under the License is distributed on an "AS IS" BASIS,
  2061. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2062. * See the License for the specific language governing permissions and
  2063. * limitations under the License.
  2064. *
  2065. * portal.js
  2066. * Image Portals
  2067. */
  2068. /**
  2069. * A sink of an Image Portal
  2070. * This is not a pipeline sink - it doesn't export any data!
  2071. */
  2072. class SpeedyPipelineNodeImagePortalSink extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2073. {
  2074. /**
  2075. * Constructor
  2076. * @param {string} [name] name of the node
  2077. */
  2078. constructor(name = undefined)
  2079. {
  2080. super(name, 1, [
  2081. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  2082. ]);
  2083. /** @type {ImageFormat} stored image format */
  2084. this._format = _utils_types__WEBPACK_IMPORTED_MODULE_3__.ImageFormat.RGBA;
  2085. /** @type {boolean} is this node initialized? */
  2086. this._initialized = false;
  2087. }
  2088. /**
  2089. * Stored image
  2090. * @returns {SpeedyTexture}
  2091. */
  2092. get image()
  2093. {
  2094. if(!this._initialized)
  2095. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  2096. return this._tex[0];
  2097. }
  2098. /**
  2099. * Stored image format
  2100. * @returns {ImageFormat}
  2101. */
  2102. get format()
  2103. {
  2104. if(!this._initialized)
  2105. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  2106. return this._format;
  2107. }
  2108. /**
  2109. * Initializes this node
  2110. * @param {SpeedyGPU} gpu
  2111. */
  2112. init(gpu)
  2113. {
  2114. super.init(gpu);
  2115. this._tex[0].resize(1, 1).clear(); // initial texture
  2116. this._format = _utils_types__WEBPACK_IMPORTED_MODULE_3__.ImageFormat.RGBA;
  2117. this._initialized = true;
  2118. }
  2119. /**
  2120. * Releases this node
  2121. * @param {SpeedyGPU} gpu
  2122. */
  2123. release(gpu)
  2124. {
  2125. this._initialized = false;
  2126. super.release(gpu);
  2127. }
  2128. /**
  2129. * Run the specific task of this node
  2130. * @param {SpeedyGPU} gpu
  2131. * @returns {void|SpeedyPromise<void>}
  2132. */
  2133. _run(gpu)
  2134. {
  2135. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  2136. const tex = this._tex[0];
  2137. // can't store pyramids
  2138. if(image.hasMipmaps())
  2139. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.NotSupportedError(`${this.fullName} can't store a pyramid`);
  2140. // copy input
  2141. this._format = format;
  2142. tex.resize(image.width, image.height);
  2143. image.copyTo(tex);
  2144. }
  2145. }
  2146. /**
  2147. * A source of an Image Portal
  2148. */
  2149. class SpeedyPipelineNodeImagePortalSource extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSourceNode
  2150. {
  2151. /**
  2152. * Constructor
  2153. * @param {string} [name] name of the node
  2154. */
  2155. constructor(name = undefined)
  2156. {
  2157. super(name, 0, [
  2158. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  2159. ]);
  2160. /** @type {SpeedyPipelineNodeImagePortalSink|null} portal sink */
  2161. this._source = null;
  2162. }
  2163. /**
  2164. * Data source
  2165. * @returns {SpeedyPipelineNodeImagePortalSink|null}
  2166. */
  2167. get source()
  2168. {
  2169. return this._source;
  2170. }
  2171. /**
  2172. * Data source
  2173. * @param {SpeedyPipelineNodeImagePortalSink|null} node
  2174. */
  2175. set source(node)
  2176. {
  2177. if(node !== null && !(node instanceof SpeedyPipelineNodeImagePortalSink))
  2178. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Incompatible source for ${this.fullName}`);
  2179. this._source = node;
  2180. }
  2181. /**
  2182. * Run the specific task of this node
  2183. * @param {SpeedyGPU} gpu
  2184. * @returns {void|SpeedyPromise<void>}
  2185. */
  2186. _run(gpu)
  2187. {
  2188. if(this._source == null)
  2189. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`${this.fullName} has no source`);
  2190. this.output().swrite(this._source.image, this._source.format);
  2191. }
  2192. }
  2193. /***/ }),
  2194. /***/ "./src/core/pipeline/nodes/images/pyramid.js":
  2195. /*!***************************************************!*\
  2196. !*** ./src/core/pipeline/nodes/images/pyramid.js ***!
  2197. \***************************************************/
  2198. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_99417__) => {
  2199. "use strict";
  2200. __nested_webpack_require_99417__.r(__webpack_exports__);
  2201. /* harmony export */ __nested_webpack_require_99417__.d(__webpack_exports__, {
  2202. /* harmony export */ "SpeedyPipelineNodeImagePyramid": () => (/* binding */ SpeedyPipelineNodeImagePyramid)
  2203. /* harmony export */ });
  2204. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_99417__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2205. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_99417__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2206. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_99417__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2207. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_99417__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2208. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_99417__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2209. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_99417__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2210. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_99417__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  2211. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_99417__(/*! ../../../../utils/types */ "./src/utils/types.js");
  2212. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_99417__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2213. /*
  2214. * speedy-vision.js
  2215. * GPU-accelerated Computer Vision for JavaScript
  2216. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2217. *
  2218. * Licensed under the Apache License, Version 2.0 (the "License");
  2219. * you may not use this file except in compliance with the License.
  2220. * You may obtain a copy of the License at
  2221. *
  2222. * http://www.apache.org/licenses/LICENSE-2.0
  2223. *
  2224. * Unless required by applicable law or agreed to in writing, software
  2225. * distributed under the License is distributed on an "AS IS" BASIS,
  2226. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2227. * See the License for the specific language governing permissions and
  2228. * limitations under the License.
  2229. *
  2230. * pyramid.js
  2231. * Generate pyramid
  2232. */
  2233. // Constants
  2234. const MAX_LEVELS = _utils_globals__WEBPACK_IMPORTED_MODULE_6__.PYRAMID_MAX_LEVELS; //14; // supposing image size <= 8K = 2^13 (downto 1)
  2235. const MAX_TEXTURES = 2 * MAX_LEVELS; //MAX_LEVELS;
  2236. /**
  2237. * Generate pyramid
  2238. */
  2239. class SpeedyPipelineNodeImagePyramid extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2240. {
  2241. /**
  2242. * Constructor
  2243. * @param {string} [name] name of the node
  2244. */
  2245. constructor(name = undefined)
  2246. {
  2247. super(name, MAX_TEXTURES + 1, [
  2248. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  2249. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  2250. ]);
  2251. }
  2252. /**
  2253. * Run the specific task of this node
  2254. * @param {SpeedyGPU} gpu
  2255. * @returns {void|SpeedyPromise<void>}
  2256. */
  2257. _run(gpu)
  2258. {
  2259. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  2260. const outputTexture = this._tex[0];
  2261. const pyramids = gpu.programs.pyramids;
  2262. let width = image.width, height = image.height;
  2263. // number of mipmap levels according to the OpenGL ES 3.0 spec (sec 3.8.10.4)
  2264. const mipLevels = 1 + Math.floor(Math.log2(Math.max(width, height)));
  2265. // get work textures
  2266. const mip = new Array(MAX_TEXTURES + 1);
  2267. for(let i = MAX_TEXTURES; i >= 1; i--)
  2268. mip[i-1] = this._tex[i];
  2269. // get a copy of the input image
  2270. mip[0].resize(width, height);
  2271. image.copyTo(mip[0]);
  2272. // generate gaussian pyramid
  2273. const numLevels = Math.min(mipLevels, MAX_LEVELS);
  2274. for(let level = 1; level < numLevels; level++) {
  2275. // use max(1, floor(size / 2^lod)), in accordance to
  2276. // the OpenGL ES 3.0 spec sec 3.8.10.4 (Mipmapping)
  2277. const halfWidth = Math.max(1, width >>> 1);
  2278. const halfHeight = Math.max(1, height >>> 1);
  2279. // reduce operation
  2280. const tmp = (level - 1) + MAX_LEVELS;
  2281. (pyramids.smoothX.outputs(width, height, mip[tmp]))(mip[level-1]);
  2282. (pyramids.smoothY.outputs(width, height, mip[level-1]))(mip[tmp]);
  2283. (pyramids.downsample2.outputs(halfWidth, halfHeight, mip[level]))(mip[level-1]);
  2284. /*
  2285. (pyramids.reduce.outputs(width, height, mip[tmp]))(mip[level-1]);
  2286. (pyramids.downsample2.outputs(halfWidth, halfHeight, mip[level]))(mip[tmp]);
  2287. */
  2288. // flush
  2289. gpu.gl.flush();
  2290. // next level
  2291. width = halfWidth;
  2292. height = halfHeight;
  2293. /*
  2294. // debug: view pyramid
  2295. const view = mip[level-1];
  2296. const canvas = gpu.renderToCanvas(view);
  2297. if(!window._ww) document.body.appendChild(canvas);
  2298. window._ww = 1;
  2299. */
  2300. }
  2301. // copy to output & set mipmap
  2302. outputTexture.resize(image.width, image.height);
  2303. outputTexture.clear();
  2304. image.copyTo(outputTexture);
  2305. outputTexture.generateMipmaps(mip.slice(0, numLevels));
  2306. // done!
  2307. this.output().swrite(outputTexture, format);
  2308. }
  2309. }
  2310. /***/ }),
  2311. /***/ "./src/core/pipeline/nodes/images/sink.js":
  2312. /*!************************************************!*\
  2313. !*** ./src/core/pipeline/nodes/images/sink.js ***!
  2314. \************************************************/
  2315. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_105489__) => {
  2316. "use strict";
  2317. __nested_webpack_require_105489__.r(__webpack_exports__);
  2318. /* harmony export */ __nested_webpack_require_105489__.d(__webpack_exports__, {
  2319. /* harmony export */ "SpeedyPipelineNodeImageSink": () => (/* binding */ SpeedyPipelineNodeImageSink)
  2320. /* harmony export */ });
  2321. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_105489__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2322. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_105489__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2323. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_105489__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2324. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_105489__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2325. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_105489__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2326. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_105489__(/*! ../../../speedy-media */ "./src/core/speedy-media.js");
  2327. /* harmony import */ var _speedy_media_source__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_105489__(/*! ../../../speedy-media-source */ "./src/core/speedy-media-source.js");
  2328. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_105489__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2329. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_105489__(/*! ../../../../utils/types */ "./src/utils/types.js");
  2330. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_105489__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2331. /*
  2332. * speedy-vision.js
  2333. * GPU-accelerated Computer Vision for JavaScript
  2334. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2335. *
  2336. * Licensed under the Apache License, Version 2.0 (the "License");
  2337. * you may not use this file except in compliance with the License.
  2338. * You may obtain a copy of the License at
  2339. *
  2340. * http://www.apache.org/licenses/LICENSE-2.0
  2341. *
  2342. * Unless required by applicable law or agreed to in writing, software
  2343. * distributed under the License is distributed on an "AS IS" BASIS,
  2344. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2345. * See the License for the specific language governing permissions and
  2346. * limitations under the License.
  2347. *
  2348. * image-output.js
  2349. * Gets an image out of a pipeline
  2350. */
  2351. /**
  2352. * Gets an image out of a pipeline
  2353. */
  2354. class SpeedyPipelineNodeImageSink extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSinkNode
  2355. {
  2356. /**
  2357. * Constructor
  2358. * @param {string} [name] name of the node
  2359. */
  2360. constructor(name = 'image')
  2361. {
  2362. super(name, 0, [
  2363. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image)
  2364. ]);
  2365. /** @type {ImageBitmap} output bitmap */
  2366. this._bitmap = null;
  2367. /** @type {ImageFormat} output format */
  2368. this._format = _utils_types__WEBPACK_IMPORTED_MODULE_8__.ImageFormat.RGBA;
  2369. }
  2370. /**
  2371. * Export data from this node to the user
  2372. * @returns {SpeedyPromise<SpeedyMedia>}
  2373. */
  2374. export()
  2375. {
  2376. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.assert(this._bitmap != null);
  2377. return _speedy_media__WEBPACK_IMPORTED_MODULE_5__.SpeedyMedia.load(this._bitmap, { format: this._format }, false);
  2378. }
  2379. /**
  2380. * Run the specific task of this node
  2381. * @param {SpeedyGPU} gpu
  2382. * @returns {void|SpeedyPromise<void>}
  2383. */
  2384. _run(gpu)
  2385. {
  2386. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  2387. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_9__.SpeedyPromise(resolve => {
  2388. const canvas = gpu.renderToCanvas(image);
  2389. createImageBitmap(canvas, 0, canvas.height - image.height, image.width, image.height).then(bitmap => {
  2390. this._bitmap = bitmap;
  2391. this._format = format;
  2392. resolve();
  2393. });
  2394. });
  2395. }
  2396. }
  2397. /***/ }),
  2398. /***/ "./src/core/pipeline/nodes/images/source.js":
  2399. /*!**************************************************!*\
  2400. !*** ./src/core/pipeline/nodes/images/source.js ***!
  2401. \**************************************************/
  2402. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_110114__) => {
  2403. "use strict";
  2404. __nested_webpack_require_110114__.r(__webpack_exports__);
  2405. /* harmony export */ __nested_webpack_require_110114__.d(__webpack_exports__, {
  2406. /* harmony export */ "SpeedyPipelineNodeImageSource": () => (/* binding */ SpeedyPipelineNodeImageSource)
  2407. /* harmony export */ });
  2408. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_110114__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2409. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_110114__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2410. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_110114__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2411. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_110114__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2412. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_110114__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2413. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_110114__(/*! ../../../speedy-media */ "./src/core/speedy-media.js");
  2414. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_110114__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2415. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_110114__(/*! ../../../../utils/types */ "./src/utils/types.js");
  2416. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_110114__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  2417. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_110114__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2418. /*
  2419. * speedy-vision.js
  2420. * GPU-accelerated Computer Vision for JavaScript
  2421. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2422. *
  2423. * Licensed under the Apache License, Version 2.0 (the "License");
  2424. * you may not use this file except in compliance with the License.
  2425. * You may obtain a copy of the License at
  2426. *
  2427. * http://www.apache.org/licenses/LICENSE-2.0
  2428. *
  2429. * Unless required by applicable law or agreed to in writing, software
  2430. * distributed under the License is distributed on an "AS IS" BASIS,
  2431. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2432. * See the License for the specific language governing permissions and
  2433. * limitations under the License.
  2434. *
  2435. * image-input.js
  2436. * Gets an image into a pipeline
  2437. */
  2438. // Constants
  2439. const UPLOAD_BUFFER_SIZE = 2; // how many textures we allocate for uploading data
  2440. /**
  2441. * Gets an image into a pipeline
  2442. */
  2443. class SpeedyPipelineNodeImageSource extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSourceNode
  2444. {
  2445. /**
  2446. * Constructor
  2447. * @param {string} [name] name of the node
  2448. */
  2449. constructor(name = undefined)
  2450. {
  2451. super(name, UPLOAD_BUFFER_SIZE, [
  2452. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image)
  2453. ]);
  2454. /** @type {SpeedyMedia|null} source media */
  2455. this._media = null;
  2456. /** @type {number} texture index */
  2457. this._textureIndex = 0;
  2458. }
  2459. /**
  2460. * Source media
  2461. * @returns {SpeedyMedia|null}
  2462. */
  2463. get media()
  2464. {
  2465. return this._media;
  2466. }
  2467. /**
  2468. * Source media
  2469. * @param {SpeedyMedia|null} media
  2470. */
  2471. set media(media)
  2472. {
  2473. if(media !== null && !(media instanceof _speedy_media__WEBPACK_IMPORTED_MODULE_5__.SpeedyMedia))
  2474. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Not a SpeedyMedia: ${media}`);
  2475. this._media = media;
  2476. }
  2477. /**
  2478. * Run the specific task of this node
  2479. * @param {SpeedyGPU} gpu
  2480. * @returns {void|SpeedyPromise<void>}
  2481. */
  2482. _run(gpu)
  2483. {
  2484. if(this._media == null)
  2485. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalOperationError(`Did you forget to set the media of ${this.fullName}?`);
  2486. // use round-robin to mitigate WebGL's implicit synchronization
  2487. // and maybe minimize texture upload times
  2488. this._textureIndex = (this._textureIndex + 1) % this._tex.length;
  2489. // upload texture
  2490. const outputTexture = this._tex[this._textureIndex];
  2491. gpu.upload(this._media._source, outputTexture);
  2492. this.output().swrite(outputTexture, this._media._format);
  2493. }
  2494. }
  2495. /***/ }),
  2496. /***/ "./src/core/pipeline/nodes/keypoints/border-clipper.js":
  2497. /*!*************************************************************!*\
  2498. !*** ./src/core/pipeline/nodes/keypoints/border-clipper.js ***!
  2499. \*************************************************************/
  2500. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_115060__) => {
  2501. "use strict";
  2502. __nested_webpack_require_115060__.r(__webpack_exports__);
  2503. /* harmony export */ __nested_webpack_require_115060__.d(__webpack_exports__, {
  2504. /* harmony export */ "SpeedyPipelineNodeKeypointBorderClipper": () => (/* binding */ SpeedyPipelineNodeKeypointBorderClipper)
  2505. /* harmony export */ });
  2506. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_115060__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2507. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_115060__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  2508. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_115060__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2509. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_115060__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2510. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_115060__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2511. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_115060__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  2512. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_115060__(/*! ../../../speedy-vector */ "./src/core/speedy-vector.js");
  2513. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_115060__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2514. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_115060__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2515. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_115060__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  2516. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_115060__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  2517. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_11__ = __nested_webpack_require_115060__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2518. /*
  2519. * speedy-vision.js
  2520. * GPU-accelerated Computer Vision for JavaScript
  2521. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2522. *
  2523. * Licensed under the Apache License, Version 2.0 (the "License");
  2524. * you may not use this file except in compliance with the License.
  2525. * You may obtain a copy of the License at
  2526. *
  2527. * http://www.apache.org/licenses/LICENSE-2.0
  2528. *
  2529. * Unless required by applicable law or agreed to in writing, software
  2530. * distributed under the License is distributed on an "AS IS" BASIS,
  2531. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2532. * See the License for the specific language governing permissions and
  2533. * limitations under the License.
  2534. *
  2535. * border-clipper.js
  2536. * Keypoint Border Clipper
  2537. */
  2538. /**
  2539. * The Border Clipper removes all keypoints within a border of the edges of an image
  2540. */
  2541. class SpeedyPipelineNodeKeypointBorderClipper extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2542. {
  2543. /**
  2544. * Constructor
  2545. * @param {string} [name] name of the node
  2546. */
  2547. constructor(name = undefined)
  2548. {
  2549. super(name, 5, [
  2550. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  2551. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  2552. ]);
  2553. /** @type {SpeedySize} image size, in pixels */
  2554. this._imageSize = new _speedy_size__WEBPACK_IMPORTED_MODULE_5__.SpeedySize(0,0);
  2555. /** @type {SpeedyVector2} border size, in pixels */
  2556. this._borderSize = new _speedy_vector__WEBPACK_IMPORTED_MODULE_6__.SpeedyVector2(0,0);
  2557. }
  2558. /**
  2559. * Image size, in pixels
  2560. * @returns {SpeedySize}
  2561. */
  2562. get imageSize()
  2563. {
  2564. return this._imageSize;
  2565. }
  2566. /**
  2567. * Image size, in pixels
  2568. * @param {SpeedySize} imageSize
  2569. */
  2570. set imageSize(imageSize)
  2571. {
  2572. this._imageSize = imageSize;
  2573. }
  2574. /**
  2575. * Border size, in pixels
  2576. * @returns {SpeedyVector2}
  2577. */
  2578. get borderSize()
  2579. {
  2580. return this._borderSize;
  2581. }
  2582. /**
  2583. * Border size, in pixels
  2584. * @param {SpeedyVector2} borderSize
  2585. */
  2586. set borderSize(borderSize)
  2587. {
  2588. this._borderSize = borderSize;
  2589. }
  2590. /**
  2591. * Run the specific task of this node
  2592. * @param {SpeedyGPU} gpu
  2593. * @returns {void|SpeedyPromise<void>}
  2594. */
  2595. _run(gpu)
  2596. {
  2597. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  2598. const keypoints = gpu.programs.keypoints;
  2599. const imageSize = this._imageSize;
  2600. const borderSize = this._borderSize;
  2601. const imageWidth = imageSize.width, imageHeight = imageSize.height;
  2602. const borderLeft = borderSize.x, borderRight = borderSize.x;
  2603. const borderTop = borderSize.y, borderBottom = borderSize.y;
  2604. const tex = this._tex;
  2605. // validate
  2606. if(imageWidth == 0 || imageHeight == 0)
  2607. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_9__.IllegalOperationError(`BorderClipper: did you forget to set the image size?`);
  2608. // find the capacity of the keypoint stream
  2609. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  2610. const mixEncoderLength = Math.max(1, Math.ceil(Math.sqrt(capacity)));
  2611. // prepare programs
  2612. keypoints.clipBorder.outputs(encoderLength, encoderLength, tex[0]);
  2613. keypoints.mixKeypointsInit.outputs(mixEncoderLength, mixEncoderLength, tex[1]);
  2614. keypoints.mixKeypointsSort.outputs(mixEncoderLength, mixEncoderLength, tex[2], tex[3]);
  2615. keypoints.mixKeypointsApply.outputs(encoderLength, encoderLength, tex[4]);
  2616. // clip keypoints
  2617. let clippedKeypoints = keypoints.clipBorder(
  2618. imageWidth, imageHeight,
  2619. borderTop, borderRight, borderBottom, borderLeft,
  2620. encodedKeypoints, descriptorSize, extraSize, encoderLength
  2621. );
  2622. // sort keypoints
  2623. let sortedKeypoints = keypoints.mixKeypointsInit(
  2624. clippedKeypoints, descriptorSize, extraSize, encoderLength, capacity
  2625. );
  2626. for(let b = 1; b < capacity; b *= 2)
  2627. sortedKeypoints = keypoints.mixKeypointsSort(sortedKeypoints, b);
  2628. clippedKeypoints = keypoints.mixKeypointsApply(
  2629. sortedKeypoints, clippedKeypoints, descriptorSize, extraSize, encoderLength
  2630. );
  2631. /*
  2632. // debug: view keypoints
  2633. keypoints.mixKeypointsView.outputs(mixEncoderLength, mixEncoderLength, tex[1]);
  2634. this._visualize(gpu, keypoints.mixKeypointsView(sortedKeypoints));
  2635. */
  2636. // done!
  2637. this.output().swrite(clippedKeypoints, descriptorSize, extraSize, encoderLength);
  2638. }
  2639. }
  2640. /***/ }),
  2641. /***/ "./src/core/pipeline/nodes/keypoints/buffer.js":
  2642. /*!*****************************************************!*\
  2643. !*** ./src/core/pipeline/nodes/keypoints/buffer.js ***!
  2644. \*****************************************************/
  2645. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_122606__) => {
  2646. "use strict";
  2647. __nested_webpack_require_122606__.r(__webpack_exports__);
  2648. /* harmony export */ __nested_webpack_require_122606__.d(__webpack_exports__, {
  2649. /* harmony export */ "SpeedyPipelineNodeKeypointBuffer": () => (/* binding */ SpeedyPipelineNodeKeypointBuffer)
  2650. /* harmony export */ });
  2651. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_122606__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2652. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_122606__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  2653. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_122606__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2654. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_122606__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2655. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_122606__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2656. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_122606__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2657. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_122606__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2658. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_122606__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2659. /*
  2660. * speedy-vision.js
  2661. * GPU-accelerated Computer Vision for JavaScript
  2662. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2663. *
  2664. * Licensed under the Apache License, Version 2.0 (the "License");
  2665. * you may not use this file except in compliance with the License.
  2666. * You may obtain a copy of the License at
  2667. *
  2668. * http://www.apache.org/licenses/LICENSE-2.0
  2669. *
  2670. * Unless required by applicable law or agreed to in writing, software
  2671. * distributed under the License is distributed on an "AS IS" BASIS,
  2672. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2673. * See the License for the specific language governing permissions and
  2674. * limitations under the License.
  2675. *
  2676. * buffer.js
  2677. * Keypoint Buffer
  2678. */
  2679. /**
  2680. * Keypoint Buffer: a node with memory.
  2681. * At time t, it outputs the keypoints received at time t-1
  2682. */
  2683. class SpeedyPipelineNodeKeypointBuffer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2684. {
  2685. /**
  2686. * Constructor
  2687. * @param {string} [name] name of the node
  2688. */
  2689. constructor(name = undefined)
  2690. {
  2691. super(name, 2, [
  2692. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  2693. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  2694. ]);
  2695. /** @type {number} current page: 0 or 1 */
  2696. this._pageIndex = 0;
  2697. /** @type {boolean} first run? */
  2698. this._initialized = false;
  2699. /** @type {number} previous descriptor size, in bytes */
  2700. this._previousDescriptorSize = 0;
  2701. /** @type {number} previous extra size, in bytes */
  2702. this._previousExtraSize = 0;
  2703. /** @type {number} previous encoder length */
  2704. this._previousEncoderLength = 0;
  2705. /** @type {boolean} frozen buffer? */
  2706. this._frozen = false;
  2707. }
  2708. /**
  2709. * A frozen buffer discards the input, effectively increasing the buffering time
  2710. * @returns {boolean}
  2711. */
  2712. get frozen()
  2713. {
  2714. return this._frozen;
  2715. }
  2716. /**
  2717. * A frozen buffer discards the input, effectively increasing the buffering time
  2718. * @param {boolean} value
  2719. */
  2720. set frozen(value)
  2721. {
  2722. this._frozen = Boolean(value);
  2723. }
  2724. /**
  2725. * Releases this node
  2726. * @param {SpeedyGPU} gpu
  2727. */
  2728. release(gpu)
  2729. {
  2730. this._initialized = false;
  2731. super.release(gpu);
  2732. }
  2733. /**
  2734. * Run the specific task of this node
  2735. * @param {SpeedyGPU} gpu
  2736. * @returns {void|SpeedyPromise<void>}
  2737. */
  2738. _run(gpu)
  2739. {
  2740. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  2741. const previousDescriptorSize = this._previousDescriptorSize;
  2742. const previousExtraSize = this._previousExtraSize;
  2743. const previousEncoderLength = this._previousEncoderLength;
  2744. const page = this._tex;
  2745. const previousInputTexture = page[1 - this._pageIndex];
  2746. const outputTexture = page[this._pageIndex];
  2747. // bufferize
  2748. if(!this._frozen || !this._initialized) {
  2749. // store input
  2750. this._previousDescriptorSize = descriptorSize;
  2751. this._previousExtraSize = extraSize;
  2752. this._previousEncoderLength = encoderLength;
  2753. previousInputTexture.resize(encoderLength, encoderLength);
  2754. encodedKeypoints.copyTo(previousInputTexture);
  2755. // page flipping
  2756. this._pageIndex = 1 - this._pageIndex;
  2757. }
  2758. // first run?
  2759. if(!this._initialized) {
  2760. this._initialized = true;
  2761. this.output().swrite(previousInputTexture, descriptorSize, extraSize, encoderLength);
  2762. return;
  2763. }
  2764. // done!
  2765. this.output().swrite(outputTexture, previousDescriptorSize, previousExtraSize, previousEncoderLength);
  2766. }
  2767. }
  2768. /***/ }),
  2769. /***/ "./src/core/pipeline/nodes/keypoints/clipper.js":
  2770. /*!******************************************************!*\
  2771. !*** ./src/core/pipeline/nodes/keypoints/clipper.js ***!
  2772. \******************************************************/
  2773. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_128575__) => {
  2774. "use strict";
  2775. __nested_webpack_require_128575__.r(__webpack_exports__);
  2776. /* harmony export */ __nested_webpack_require_128575__.d(__webpack_exports__, {
  2777. /* harmony export */ "SpeedyPipelineNodeKeypointClipper": () => (/* binding */ SpeedyPipelineNodeKeypointClipper)
  2778. /* harmony export */ });
  2779. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_128575__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2780. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_128575__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  2781. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_128575__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2782. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_128575__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2783. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_128575__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2784. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_128575__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2785. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_128575__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  2786. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_128575__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  2787. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_128575__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  2788. /*
  2789. * speedy-vision.js
  2790. * GPU-accelerated Computer Vision for JavaScript
  2791. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2792. *
  2793. * Licensed under the Apache License, Version 2.0 (the "License");
  2794. * you may not use this file except in compliance with the License.
  2795. * You may obtain a copy of the License at
  2796. *
  2797. * http://www.apache.org/licenses/LICENSE-2.0
  2798. *
  2799. * Unless required by applicable law or agreed to in writing, software
  2800. * distributed under the License is distributed on an "AS IS" BASIS,
  2801. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2802. * See the License for the specific language governing permissions and
  2803. * limitations under the License.
  2804. *
  2805. * clipper.js
  2806. * Keypoint clipper
  2807. */
  2808. // Constants
  2809. const LOG2_STRIDE = 5;
  2810. const MAX_SIZE = _utils_globals__WEBPACK_IMPORTED_MODULE_7__.MAX_ENCODER_CAPACITY;
  2811. /**
  2812. * Keypoint clipper: filters the best keypoints from a stream
  2813. */
  2814. class SpeedyPipelineNodeKeypointClipper extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2815. {
  2816. /**
  2817. * Constructor
  2818. * @param {string} [name] name of the node
  2819. */
  2820. constructor(name = undefined)
  2821. {
  2822. super(name, 4, [
  2823. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  2824. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  2825. ]);
  2826. /** @type {number} the maximum number of keypoints in the output */
  2827. this._size = MAX_SIZE;
  2828. }
  2829. /**
  2830. * The maximum number of keypoints in the output
  2831. * @returns {number}
  2832. */
  2833. get size()
  2834. {
  2835. return this._size;
  2836. }
  2837. /**
  2838. * The maximum number of keypoints in the output
  2839. * @param {number} size
  2840. */
  2841. set size(size)
  2842. {
  2843. this._size = Math.max(0, Math.min(size | 0, MAX_SIZE));
  2844. }
  2845. /**
  2846. * Run the specific task of this node
  2847. * @param {SpeedyGPU} gpu
  2848. * @returns {void|SpeedyPromise<void>}
  2849. */
  2850. _run(gpu)
  2851. {
  2852. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  2853. const keypoints = gpu.programs.keypoints;
  2854. const clipValue = this._size;
  2855. const tex = this._tex;
  2856. const outputTexture = this._tex[3];
  2857. // find the minimum power of 2 pot such that pot >= capacity
  2858. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  2859. //const pot = 1 << (Math.ceil(Math.log2(capacity)) | 0);
  2860. // find the dimensions of the sorting shaders
  2861. const stride = 1 << LOG2_STRIDE; // must be a power of 2
  2862. //const height = Math.max(1, pot >>> LOG2_STRIDE); // this is also a power of 2
  2863. const height = Math.ceil(capacity / stride); // more economical, maybe not a power of 2
  2864. const numberOfPixels = stride * height;
  2865. // find the dimensions of the output texture
  2866. const newCapacity = Math.min(capacity, clipValue);
  2867. const newEncoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderLength(newCapacity, descriptorSize, extraSize);
  2868. // generate permutation of keypoints
  2869. keypoints.sortCreatePermutation.outputs(stride, height, tex[0]);
  2870. let permutation = keypoints.sortCreatePermutation(encodedKeypoints, descriptorSize, extraSize, encoderLength);
  2871. // sort permutation
  2872. const numPasses = Math.ceil(Math.log2(numberOfPixels));
  2873. keypoints.sortMergePermutation.outputs(stride, height, tex[1], tex[2]);
  2874. for(let i = 1; i <= numPasses; i++) {
  2875. const blockSize = 1 << i; // 2, 4, 8...
  2876. const dblLog2BlockSize = i << 1; // 2 * log2(blockSize)
  2877. permutation = keypoints.sortMergePermutation(permutation, blockSize, dblLog2BlockSize);
  2878. }
  2879. // apply permutation
  2880. keypoints.sortApplyPermutation.outputs(newEncoderLength, newEncoderLength, outputTexture);
  2881. keypoints.sortApplyPermutation(permutation, newCapacity, encodedKeypoints, descriptorSize, extraSize);
  2882. /*
  2883. // debug (read the contents of the permutation)
  2884. const pixels = this._inspect(gpu, permutation), debug = [];
  2885. for(let i = 0; i < pixels.length; i += 4) {
  2886. let id = pixels[i] | (pixels[i+1] << 8);
  2887. let score = pixels[i+2] / 255.0;
  2888. let valid = pixels[i+3] / 255.0;
  2889. debug.push([ id, valid, score, ].join(', '));
  2890. }
  2891. console.log(debug);
  2892. */
  2893. // done!
  2894. this.output().swrite(outputTexture, descriptorSize, extraSize, newEncoderLength);
  2895. }
  2896. }
  2897. /***/ }),
  2898. /***/ "./src/core/pipeline/nodes/keypoints/descriptors/descriptor.js":
  2899. /*!*********************************************************************!*\
  2900. !*** ./src/core/pipeline/nodes/keypoints/descriptors/descriptor.js ***!
  2901. \*********************************************************************/
  2902. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_135597__) => {
  2903. "use strict";
  2904. __nested_webpack_require_135597__.r(__webpack_exports__);
  2905. /* harmony export */ __nested_webpack_require_135597__.d(__webpack_exports__, {
  2906. /* harmony export */ "SpeedyPipelineNodeKeypointDescriptor": () => (/* binding */ SpeedyPipelineNodeKeypointDescriptor)
  2907. /* harmony export */ });
  2908. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_135597__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2909. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_135597__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2910. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_135597__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2911. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_135597__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2912. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_135597__(/*! ../detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  2913. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_135597__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  2914. /*
  2915. * speedy-vision.js
  2916. * GPU-accelerated Computer Vision for JavaScript
  2917. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  2918. *
  2919. * Licensed under the Apache License, Version 2.0 (the "License");
  2920. * you may not use this file except in compliance with the License.
  2921. * You may obtain a copy of the License at
  2922. *
  2923. * http://www.apache.org/licenses/LICENSE-2.0
  2924. *
  2925. * Unless required by applicable law or agreed to in writing, software
  2926. * distributed under the License is distributed on an "AS IS" BASIS,
  2927. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  2928. * See the License for the specific language governing permissions and
  2929. * limitations under the License.
  2930. *
  2931. * descriptor.js
  2932. * Abstract keypoint descriptor
  2933. */
  2934. /**
  2935. * Abstract keypoint descriptor
  2936. * @abstract
  2937. */
  2938. class SpeedyPipelineNodeKeypointDescriptor extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  2939. {
  2940. /**
  2941. * Constructor
  2942. * @param {string} [name] name of the node
  2943. * @param {number} [texCount] number of work textures
  2944. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  2945. */
  2946. constructor(name = undefined, texCount = 0, portBuilders = undefined)
  2947. {
  2948. super(name, texCount + 1, portBuilders);
  2949. }
  2950. /**
  2951. *
  2952. * Allocate space for keypoint descriptors
  2953. * @param {SpeedyGPU} gpu
  2954. * @param {number} inputDescriptorSize should be 0
  2955. * @param {number} inputExtraSize must be non-negative
  2956. * @param {number} outputDescriptorSize in bytes, must be a multiple of 4
  2957. * @param {number} outputExtraSize must be inputExtraSize
  2958. * @param {SpeedyTexture} inputEncodedKeypoints input with no descriptors
  2959. * @returns {SpeedyDrawableTexture} encodedKeypoints
  2960. */
  2961. _allocateDescriptors(gpu, inputDescriptorSize, inputExtraSize, outputDescriptorSize, outputExtraSize, inputEncodedKeypoints)
  2962. {
  2963. _utils_utils__WEBPACK_IMPORTED_MODULE_5__.Utils.assert(inputDescriptorSize >= 0 && inputExtraSize >= 0);
  2964. _utils_utils__WEBPACK_IMPORTED_MODULE_5__.Utils.assert(outputDescriptorSize >= 0 && outputDescriptorSize % 4 === 0 && outputExtraSize === inputExtraSize);
  2965. const inputEncoderLength = inputEncodedKeypoints.width;
  2966. const inputEncoderCapacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(inputDescriptorSize, inputExtraSize, inputEncoderLength);
  2967. const outputEncoderCapacity = inputEncoderCapacity;
  2968. const outputEncoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineNodeKeypointDetector.encoderLength(outputEncoderCapacity, outputDescriptorSize, outputExtraSize);
  2969. const tex = this._tex[this._tex.length - 1];
  2970. return (gpu.programs.keypoints.allocateDescriptors
  2971. .outputs(outputEncoderLength, outputEncoderLength, tex)
  2972. )(inputEncodedKeypoints, inputDescriptorSize, inputExtraSize, inputEncoderLength, outputDescriptorSize, outputExtraSize, outputEncoderLength);
  2973. }
  2974. }
  2975. /***/ }),
  2976. /***/ "./src/core/pipeline/nodes/keypoints/descriptors/orb.js":
  2977. /*!**************************************************************!*\
  2978. !*** ./src/core/pipeline/nodes/keypoints/descriptors/orb.js ***!
  2979. \**************************************************************/
  2980. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_140270__) => {
  2981. "use strict";
  2982. __nested_webpack_require_140270__.r(__webpack_exports__);
  2983. /* harmony export */ __nested_webpack_require_140270__.d(__webpack_exports__, {
  2984. /* harmony export */ "SpeedyPipelineNodeORBKeypointDescriptor": () => (/* binding */ SpeedyPipelineNodeORBKeypointDescriptor)
  2985. /* harmony export */ });
  2986. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_140270__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  2987. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_140270__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  2988. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_140270__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  2989. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_140270__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  2990. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_140270__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  2991. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_140270__(/*! ../../../../../utils/types */ "./src/utils/types.js");
  2992. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_140270__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  2993. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_140270__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  2994. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_140270__(/*! ../detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  2995. /* harmony import */ var _descriptor__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_140270__(/*! ./descriptor */ "./src/core/pipeline/nodes/keypoints/descriptors/descriptor.js");
  2996. /*
  2997. * speedy-vision.js
  2998. * GPU-accelerated Computer Vision for JavaScript
  2999. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3000. *
  3001. * Licensed under the Apache License, Version 2.0 (the "License");
  3002. * you may not use this file except in compliance with the License.
  3003. * You may obtain a copy of the License at
  3004. *
  3005. * http://www.apache.org/licenses/LICENSE-2.0
  3006. *
  3007. * Unless required by applicable law or agreed to in writing, software
  3008. * distributed under the License is distributed on an "AS IS" BASIS,
  3009. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3010. * See the License for the specific language governing permissions and
  3011. * limitations under the License.
  3012. *
  3013. * orb.js
  3014. * ORB descriptors
  3015. */
  3016. // Constants
  3017. const DESCRIPTOR_SIZE = 32; // 256 bits
  3018. /**
  3019. * ORB descriptors
  3020. */
  3021. class SpeedyPipelineNodeORBKeypointDescriptor extends _descriptor__WEBPACK_IMPORTED_MODULE_9__.SpeedyPipelineNodeKeypointDescriptor
  3022. {
  3023. /**
  3024. * Constructor
  3025. * @param {string} [name] name of the node
  3026. */
  3027. constructor(name = undefined)
  3028. {
  3029. super(name, 3, [
  3030. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('image').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  3031. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  3032. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_5__.ImageFormat.GREY
  3033. ),
  3034. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('keypoints').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3035. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3036. ]);
  3037. }
  3038. /**
  3039. * Run the specific task of this node
  3040. * @param {SpeedyGPU} gpu
  3041. * @returns {void|SpeedyPromise<void>}
  3042. */
  3043. _run(gpu)
  3044. {
  3045. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('keypoints').read() );
  3046. const image = ( /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('image').read() ) ).image;
  3047. const tex = this._tex;
  3048. const outputTexture = this._tex[2];
  3049. // compute orientation
  3050. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_8__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  3051. const orientationEncoderLength = Math.max(1, Math.ceil(Math.sqrt(capacity))); // 1 pixel per keypoint
  3052. const encodedOrientations = (gpu.programs.keypoints.orbOrientation
  3053. .outputs(orientationEncoderLength, orientationEncoderLength, tex[0])
  3054. )(image, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  3055. const orientedKeypoints = (gpu.programs.keypoints.transferOrientation
  3056. .outputs(encoderLength, encoderLength, tex[1])
  3057. )(encodedOrientations, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  3058. // allocate space
  3059. const encodedKps = this._allocateDescriptors(gpu, descriptorSize, extraSize, DESCRIPTOR_SIZE, extraSize, orientedKeypoints);
  3060. const newEncoderLength = encodedKps.width;
  3061. // compute descriptors (it's a good idea to blur the image)
  3062. const describedKeypoints = (gpu.programs.keypoints.orbDescriptor
  3063. .outputs(newEncoderLength, newEncoderLength, outputTexture)
  3064. )(image, encodedKps, extraSize, newEncoderLength);
  3065. // done!
  3066. this.output().swrite(describedKeypoints, DESCRIPTOR_SIZE, extraSize, newEncoderLength);
  3067. }
  3068. }
  3069. /***/ }),
  3070. /***/ "./src/core/pipeline/nodes/keypoints/detectors/detector.js":
  3071. /*!*****************************************************************!*\
  3072. !*** ./src/core/pipeline/nodes/keypoints/detectors/detector.js ***!
  3073. \*****************************************************************/
  3074. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_146307__) => {
  3075. "use strict";
  3076. __nested_webpack_require_146307__.r(__webpack_exports__);
  3077. /* harmony export */ __nested_webpack_require_146307__.d(__webpack_exports__, {
  3078. /* harmony export */ "SpeedyPipelineNodeKeypointDetector": () => (/* binding */ SpeedyPipelineNodeKeypointDetector),
  3079. /* harmony export */ "SpeedyPipelineNodeMultiscaleKeypointDetector": () => (/* binding */ SpeedyPipelineNodeMultiscaleKeypointDetector)
  3080. /* harmony export */ });
  3081. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_146307__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  3082. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_146307__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3083. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_146307__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3084. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_146307__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3085. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_146307__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3086. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_146307__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  3087. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_146307__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  3088. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_146307__(/*! ../../../../../utils/globals */ "./src/utils/globals.js");
  3089. /*
  3090. * speedy-vision.js
  3091. * GPU-accelerated Computer Vision for JavaScript
  3092. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3093. *
  3094. * Licensed under the Apache License, Version 2.0 (the "License");
  3095. * you may not use this file except in compliance with the License.
  3096. * You may obtain a copy of the License at
  3097. *
  3098. * http://www.apache.org/licenses/LICENSE-2.0
  3099. *
  3100. * Unless required by applicable law or agreed to in writing, software
  3101. * distributed under the License is distributed on an "AS IS" BASIS,
  3102. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3103. * See the License for the specific language governing permissions and
  3104. * limitations under the License.
  3105. *
  3106. * detector.js
  3107. * Abstract keypoint detectors
  3108. */
  3109. // Constants
  3110. const MAX_CAPACITY = _utils_globals__WEBPACK_IMPORTED_MODULE_7__.MAX_ENCODER_CAPACITY; // maximum capacity of the encoder (up to this many keypoints can be stored)
  3111. const DEFAULT_CAPACITY = _utils_globals__WEBPACK_IMPORTED_MODULE_7__.DEFAULT_ENCODER_CAPACITY; // default capacity of the encoder
  3112. const DEFAULT_SCALE_FACTOR = 1.4142135623730951; // sqrt(2)
  3113. const NUMBER_OF_RGBA16_TEXTURES = 2;
  3114. // legacy constants
  3115. const NUMBER_OF_INTERNAL_TEXTURES = 0; //5; // number of internal textures used to encode the keypoints
  3116. const ENCODER_PASSES = 4; // number of passes of the keypoint encoder: directly impacts performance
  3117. const LONG_SKIP_OFFSET_PASSES = 2; // number of passes of the long skip offsets shader
  3118. /**
  3119. * Abstract keypoint detector
  3120. * @abstract
  3121. */
  3122. class SpeedyPipelineNodeKeypointDetector extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  3123. {
  3124. /**
  3125. * Constructor
  3126. * @param {string} [name] name of the node
  3127. * @param {number} [texCount] number of work textures
  3128. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  3129. */
  3130. constructor(name = undefined, texCount = 0, portBuilders = undefined)
  3131. {
  3132. super(name, texCount + NUMBER_OF_INTERNAL_TEXTURES, portBuilders);
  3133. /** @type {number} encoder capacity */
  3134. this._capacity = DEFAULT_CAPACITY; // must not be greater than MAX_ENCODER_CAPACITY
  3135. /** @type {GLint} auxiliary storage */
  3136. this._oldWrapS = 0;
  3137. /** @type {SpeedyDrawableTexture[]} textures with 8-bytes per pixel */
  3138. this._tex16 = new Array(NUMBER_OF_RGBA16_TEXTURES).fill(null);
  3139. }
  3140. /**
  3141. * Initialize this node
  3142. * @param {SpeedyGPU} gpu
  3143. */
  3144. init(gpu)
  3145. {
  3146. // initialize
  3147. super.init(gpu);
  3148. // encodeKeypointSkipOffsets() relies on this
  3149. this._oldWrapS = this._setupSpecialTexture(gpu.gl.TEXTURE_WRAP_S, gpu.gl.REPEAT);
  3150. // allocate RGBA16 textures
  3151. this._allocateTex16(gpu);
  3152. gpu.subscribe(this._allocateTex16, this, gpu);
  3153. }
  3154. /**
  3155. * Release this node
  3156. * @param {SpeedyGPU} gpu
  3157. */
  3158. release(gpu)
  3159. {
  3160. // deallocate RGBA16 textures
  3161. gpu.unsubscribe(this._allocateTex16, this);
  3162. this._deallocateTex16(gpu);
  3163. // we need to restore the texture parameter because textures come from a pool!
  3164. this._setupSpecialTexture(gpu.gl.TEXTURE_WRAP_S, this._oldWrapS);
  3165. // release
  3166. super.release(gpu);
  3167. }
  3168. /**
  3169. * Set a parameter of the special texture
  3170. * @param {GLenum} pname
  3171. * @param {GLint} param new value
  3172. * @returns {GLint} old value of param
  3173. */
  3174. _setupSpecialTexture(pname, param)
  3175. {
  3176. if(NUMBER_OF_INTERNAL_TEXTURES == 0)
  3177. return;
  3178. // legacy code
  3179. const texture = this._tex[this._tex.length - 1];
  3180. const gl = texture.gl;
  3181. gl.bindTexture(gl.TEXTURE_2D, texture.glTexture);
  3182. const oldval = gl.getTexParameter(gl.TEXTURE_2D, pname);
  3183. gl.texParameteri(gl.TEXTURE_2D, pname, param);
  3184. gl.bindTexture(gl.TEXTURE_2D, null);
  3185. return oldval;
  3186. }
  3187. /**
  3188. * We can encode up to this many keypoints. If you find a
  3189. * tight bound for this, download times will be faster.
  3190. * @returns {number}
  3191. */
  3192. get capacity()
  3193. {
  3194. return this._capacity;
  3195. }
  3196. /**
  3197. * We can encode up to this many keypoints. If you find a
  3198. * tight bound for this, download times will be faster.
  3199. * @param {number} capacity
  3200. */
  3201. set capacity(capacity)
  3202. {
  3203. this._capacity = Math.min(Math.max(0, capacity | 0), MAX_CAPACITY);
  3204. }
  3205. /**
  3206. * Create a tiny texture with encoded keypoints out of
  3207. * an encoded corners texture
  3208. * @param {SpeedyGPU} gpu
  3209. * @param {SpeedyTexture} corners input
  3210. * @param {SpeedyDrawableTexture} encodedKeypoints output
  3211. * @param {number} [descriptorSize] in bytes
  3212. * @param {number} [extraSize] in bytes
  3213. * @returns {SpeedyDrawableTexture} encodedKeypoints
  3214. */
  3215. _encodeKeypoints(gpu, corners, encodedKeypoints, descriptorSize = 0, extraSize = 0)
  3216. {
  3217. const encoderCapacity = this._capacity;
  3218. const encoderLength = SpeedyPipelineNodeKeypointDetector.encoderLength(encoderCapacity, descriptorSize, extraSize);
  3219. const width = 1 << (Math.ceil(Math.log2(corners.width * corners.height)) >>> 1); // power of two
  3220. const height = Math.ceil(corners.width * corners.height / width); // probabilistic approach in Parallel Ale Sort 2D
  3221. //const width = corners.width, height = corners.height; // independent texture reads approach in Parallel Ale Sort 2D
  3222. const maxSize = Math.max(width, height);
  3223. const keypoints = gpu.programs.keypoints;
  3224. // prepare programs
  3225. keypoints.initLookupTable.outputs(width, height, this._tex16[1]);
  3226. keypoints.sortLookupTable.outputs(width, height, this._tex16[0], this._tex16[1]);
  3227. keypoints.encodeKeypoints.outputs(encoderLength, encoderLength, encodedKeypoints);
  3228. // compute lookup table
  3229. let lookupTable = keypoints.initLookupTable(corners);
  3230. for(let b = 1; b < maxSize; b *= 2)
  3231. lookupTable = keypoints.sortLookupTable(lookupTable, b, width, height);
  3232. /*
  3233. // debug: view texture
  3234. const lookupView = (keypoints.viewLookupTable.outputs(
  3235. width, height, this._tex[0]
  3236. ))(lookupTable);
  3237. const canvas = gpu.renderToCanvas(lookupView);
  3238. if(!this._ww) document.body.appendChild(canvas);
  3239. this._ww = 1;
  3240. */
  3241. // encode keypoints
  3242. return keypoints.encodeKeypoints(corners, lookupTable, width, descriptorSize, extraSize, encoderLength, encoderCapacity);
  3243. }
  3244. _encodeKeypointsOLD(gpu, corners, encodedKeypoints, descriptorSize = 0, extraSize = 0)
  3245. {
  3246. const capacity = this._capacity;
  3247. const encoderLength = SpeedyPipelineNodeKeypointDetector.encoderLength(capacity, descriptorSize, extraSize);
  3248. const width = corners.width, height = corners.height;
  3249. const imageSize = [ width, height ];
  3250. const tex = this._tex.slice(this._tex.length - NUMBER_OF_INTERNAL_TEXTURES); // array of internal textures
  3251. const keypoints = gpu.programs.keypoints;
  3252. const specialTexture = tex.pop(); // gl.TEXTURE_WRAP_S is set to gl.REPEAT
  3253. // prepare programs
  3254. keypoints.encodeKeypointSkipOffsets.outputs(width, height, tex[0]);
  3255. keypoints.encodeKeypointLongSkipOffsets.outputs(width, height, tex[1], tex[0]);
  3256. keypoints.encodeKeypointPositions.outputs(encoderLength, encoderLength, tex[2], tex[3]);
  3257. keypoints.encodeKeypointProperties.outputs(encoderLength, encoderLength, encodedKeypoints);
  3258. // copy the input corners to a special texture
  3259. // that is needed by encodeKeypointSkipOffsets()
  3260. corners = (gpu.programs.utils.copy
  3261. .outputs(width, height, specialTexture)
  3262. )(corners);
  3263. // encode skip offsets
  3264. let offsets = keypoints.encodeKeypointSkipOffsets(corners, imageSize);
  3265. for(let i = 0; i < LONG_SKIP_OFFSET_PASSES; i++) { // to boost performance
  3266. // the maximum skip offset of pass p=1,2,3... is 7 * (1+m)^p,
  3267. // where m = MAX_ITERATIONS of encodeKeypointLongSkipOffsets()
  3268. offsets = keypoints.encodeKeypointLongSkipOffsets(offsets, imageSize); // **bottleneck**
  3269. }
  3270. /*
  3271. // debug: view corners
  3272. let cornerview = offsets;
  3273. const canvas = gpu.renderToCanvas(cornerview);
  3274. if(!window._ww) document.body.appendChild(canvas);
  3275. window._ww = 1;
  3276. */
  3277. // encode keypoint positions
  3278. let encodedKps = tex[3].clear();
  3279. for(let j = 0; j < ENCODER_PASSES; j++)
  3280. encodedKps = keypoints.encodeKeypointPositions(offsets, imageSize, j, ENCODER_PASSES, capacity, encodedKps, descriptorSize, extraSize, encoderLength);
  3281. // encode keypoint properties
  3282. return keypoints.encodeKeypointProperties(corners, encodedKps, descriptorSize, extraSize, encoderLength);
  3283. }
  3284. /**
  3285. * Create a tiny texture with zero encoded keypoints
  3286. * @param {SpeedyGPU} gpu
  3287. * @param {SpeedyDrawableTexture} encodedKeypoints output texture
  3288. * @param {number} [descriptorSize] in bytes
  3289. * @param {number} [extraSize] in bytes
  3290. * @returns {SpeedyDrawableTexture} encodedKeypoints
  3291. */
  3292. _encodeZeroKeypoints(gpu, encodedKeypoints, descriptorSize = 0, extraSize = 0)
  3293. {
  3294. const capacity = 0;
  3295. const encoderLength = SpeedyPipelineNodeKeypointDetector.encoderLength(capacity, descriptorSize, extraSize);
  3296. const keypoints = gpu.programs.keypoints;
  3297. keypoints.encodeNullKeypoints.outputs(encoderLength, encoderLength, encodedKeypoints);
  3298. return keypoints.encodeNullKeypoints();
  3299. }
  3300. /**
  3301. * Allocate RGBA16 textures
  3302. * @param {SpeedyGPU} gpu
  3303. */
  3304. _allocateTex16(gpu)
  3305. {
  3306. const gl = gpu.gl;
  3307. // RGBA16UI is color renderable according to the OpenGL ES 3 spec
  3308. for(let i = 0; i < this._tex16.length; i++)
  3309. this._tex16[i] = new _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__.SpeedyDrawableTexture(gl, 1, 1, gl.RGBA_INTEGER, gl.RGBA16UI, gl.UNSIGNED_SHORT, gl.NEAREST, gl.CLAMP_TO_EDGE);
  3310. }
  3311. /**
  3312. * Deallocate RGBA16 textures
  3313. * @param {SpeedyGPU} gpu
  3314. */
  3315. _deallocateTex16(gpu)
  3316. {
  3317. for(let i = 0; i < this._tex16.length; i++)
  3318. this._tex16[i] = this._tex16[i].release();
  3319. }
  3320. /**
  3321. * Compute the length of the keypoint encoder, given its capacity
  3322. * @param {number} encoderCapacity how many keypoints can we fit?
  3323. * @param {number} descriptorSize in bytes
  3324. * @param {number} extraSize in bytes
  3325. */
  3326. static encoderLength(encoderCapacity, descriptorSize, extraSize)
  3327. {
  3328. const pixelsPerKeypoint = Math.ceil((_utils_globals__WEBPACK_IMPORTED_MODULE_7__.MIN_KEYPOINT_SIZE + descriptorSize + extraSize) / 4);
  3329. const numberOfPixels = encoderCapacity * pixelsPerKeypoint;
  3330. return Math.max(_utils_globals__WEBPACK_IMPORTED_MODULE_7__.MIN_ENCODER_LENGTH, Math.ceil(Math.sqrt(numberOfPixels)));
  3331. }
  3332. /**
  3333. * The maximum number of keypoints we can store using
  3334. * a particular configuration of a keypoint encoder
  3335. * @param {number} descriptorSize in bytes
  3336. * @param {number} extraSize in bytes
  3337. * @param {number} encoderLength
  3338. */
  3339. static encoderCapacity(descriptorSize, extraSize, encoderLength)
  3340. {
  3341. const pixelsPerKeypoint = Math.ceil((_utils_globals__WEBPACK_IMPORTED_MODULE_7__.MIN_KEYPOINT_SIZE + descriptorSize + extraSize) / 4);
  3342. const numberOfPixels = encoderLength * encoderLength;
  3343. return Math.floor(numberOfPixels / pixelsPerKeypoint);
  3344. }
  3345. }
  3346. /**
  3347. * Abstract scale-space keypoint detector
  3348. * @abstract
  3349. */
  3350. class SpeedyPipelineNodeMultiscaleKeypointDetector extends SpeedyPipelineNodeKeypointDetector
  3351. {
  3352. /**
  3353. * Constructor
  3354. * @param {string} [name] name of the node
  3355. * @param {number} [texCount] number of work textures
  3356. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  3357. */
  3358. constructor(name = undefined, texCount = undefined, portBuilders = undefined)
  3359. {
  3360. super(name, texCount, portBuilders);
  3361. /** @type {number} number of pyramid levels */
  3362. this._levels = 1;
  3363. /** @type {number} scale factor between two pyramid levels */
  3364. this._scaleFactor = DEFAULT_SCALE_FACTOR;
  3365. }
  3366. /**
  3367. * Number of pyramid levels
  3368. * @returns {number}
  3369. */
  3370. get levels()
  3371. {
  3372. return this._levels;
  3373. }
  3374. /**
  3375. * Number of pyramid levels
  3376. * @param {number} levels
  3377. */
  3378. set levels(levels)
  3379. {
  3380. this._levels = Math.max(1, levels | 0);
  3381. }
  3382. /**
  3383. * Scale factor between two pyramid levels
  3384. * @returns {number}
  3385. */
  3386. get scaleFactor()
  3387. {
  3388. return this._scaleFactor;
  3389. }
  3390. /**
  3391. * Scale factor between two pyramid levels
  3392. * @param {number} scaleFactor should be greater than 1
  3393. */
  3394. set scaleFactor(scaleFactor)
  3395. {
  3396. this._scaleFactor = Math.max(1.0, Math.min(+scaleFactor, 2.0));
  3397. }
  3398. }
  3399. /***/ }),
  3400. /***/ "./src/core/pipeline/nodes/keypoints/detectors/fast.js":
  3401. /*!*************************************************************!*\
  3402. !*** ./src/core/pipeline/nodes/keypoints/detectors/fast.js ***!
  3403. \*************************************************************/
  3404. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_161364__) => {
  3405. "use strict";
  3406. __nested_webpack_require_161364__.r(__webpack_exports__);
  3407. /* harmony export */ __nested_webpack_require_161364__.d(__webpack_exports__, {
  3408. /* harmony export */ "SpeedyPipelineNodeFASTKeypointDetector": () => (/* binding */ SpeedyPipelineNodeFASTKeypointDetector)
  3409. /* harmony export */ });
  3410. /* harmony import */ var _detector__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_161364__(/*! ./detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  3411. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_161364__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3412. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_161364__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3413. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_161364__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3414. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_161364__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3415. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_161364__(/*! ../../../../../utils/types */ "./src/utils/types.js");
  3416. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_161364__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  3417. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_161364__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  3418. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_161364__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  3419. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_161364__(/*! ../../../../../utils/globals */ "./src/utils/globals.js");
  3420. /*
  3421. * speedy-vision.js
  3422. * GPU-accelerated Computer Vision for JavaScript
  3423. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3424. *
  3425. * Licensed under the Apache License, Version 2.0 (the "License");
  3426. * you may not use this file except in compliance with the License.
  3427. * You may obtain a copy of the License at
  3428. *
  3429. * http://www.apache.org/licenses/LICENSE-2.0
  3430. *
  3431. * Unless required by applicable law or agreed to in writing, software
  3432. * distributed under the License is distributed on an "AS IS" BASIS,
  3433. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3434. * See the License for the specific language governing permissions and
  3435. * limitations under the License.
  3436. *
  3437. * fast.js
  3438. * FAST corner detector
  3439. */
  3440. // Constants
  3441. const DEFAULT_THRESHOLD = 20;
  3442. /**
  3443. * FAST corner detector
  3444. */
  3445. class SpeedyPipelineNodeFASTKeypointDetector extends _detector__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNodeMultiscaleKeypointDetector
  3446. {
  3447. /**
  3448. * Constructor
  3449. * @param {string} [name] name of the node
  3450. */
  3451. constructor(name = undefined)
  3452. {
  3453. super(name, 5, [
  3454. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  3455. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  3456. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_5__.ImageFormat.GREY
  3457. ),
  3458. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3459. ]);
  3460. /** @type {number} FAST threshold in [0,255] */
  3461. this._threshold = DEFAULT_THRESHOLD;
  3462. }
  3463. /**
  3464. * FAST threshold in [0,255]
  3465. * @returns {number}
  3466. */
  3467. get threshold()
  3468. {
  3469. return this._threshold;
  3470. }
  3471. /**
  3472. * FAST threshold in [0,255]
  3473. * @param {number} threshold
  3474. */
  3475. set threshold(threshold)
  3476. {
  3477. this._threshold = Math.max(0, Math.min(threshold | 0, 255));
  3478. }
  3479. /**
  3480. * Run the specific task of this node
  3481. * @param {SpeedyGPU} gpu
  3482. * @returns {void|SpeedyPromise<void>}
  3483. */
  3484. _run(gpu)
  3485. {
  3486. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  3487. const width = image.width, height = image.height;
  3488. const tex = this._tex;
  3489. const capacity = this._capacity;
  3490. const threshold = this._threshold;
  3491. const lodStep = Math.log2(this.scaleFactor);
  3492. const levels = this.levels;
  3493. // validate pyramid
  3494. if(!(levels == 1 || image.hasMipmaps()))
  3495. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Expected a pyramid in ${this.fullName}`);
  3496. // skip if the capacity is zero
  3497. if(capacity == 0) {
  3498. const encodedKeypoints = this._encodeZeroKeypoints(gpu, tex[4]);
  3499. const encoderLength = encodedKeypoints.width;
  3500. this.output().swrite(encodedKeypoints, 0, 0, encoderLength);
  3501. return;
  3502. }
  3503. // FAST
  3504. gpu.programs.keypoints.fast9_16.outputs(width, height, tex[0], tex[1]);
  3505. gpu.programs.keypoints.nonmaxSpace.outputs(width, height, tex[2]);
  3506. let corners = tex[1].clear();
  3507. let numPasses = Math.max(1, Math.min(levels, (_utils_globals__WEBPACK_IMPORTED_MODULE_9__.PYRAMID_MAX_LEVELS / lodStep) | 0));
  3508. for(let lod = lodStep * (numPasses - 1); numPasses-- > 0; lod -= lodStep) {
  3509. corners = gpu.programs.keypoints.fast9_16(corners, image, lod, threshold);
  3510. //corners = gpu.programs.keypoints.nonmaxSpace(corners); // see below*
  3511. }
  3512. // Same-scale non-maximum suppression
  3513. // *nicer results inside the loop; faster outside
  3514. // Hard to notice a difference when using FAST
  3515. corners = gpu.programs.keypoints.nonmaxSpace(corners);
  3516. // Multi-scale non-maximum suppression
  3517. // (doesn't seem to remove many keypoints)
  3518. if(levels > 1) {
  3519. corners = (gpu.programs.keypoints.nonmaxScaleSimple
  3520. .outputs(width, height, tex[1])
  3521. )(corners, image, lodStep);
  3522. }
  3523. // encode keypoints
  3524. let encodedKeypoints = this._encodeKeypoints(gpu, corners, tex[3]);
  3525. const encoderLength = encodedKeypoints.width;
  3526. // scale refinement
  3527. if(levels > 1) {
  3528. encodedKeypoints = (gpu.programs.keypoints.refineScaleFAST916
  3529. .outputs(encoderLength, encoderLength, tex[4])
  3530. )(image, lodStep, encodedKeypoints, 0, 0, encoderLength, threshold);
  3531. }
  3532. // done!
  3533. this.output().swrite(encodedKeypoints, 0, 0, encoderLength);
  3534. }
  3535. }
  3536. /***/ }),
  3537. /***/ "./src/core/pipeline/nodes/keypoints/detectors/harris.js":
  3538. /*!***************************************************************!*\
  3539. !*** ./src/core/pipeline/nodes/keypoints/detectors/harris.js ***!
  3540. \***************************************************************/
  3541. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_168397__) => {
  3542. "use strict";
  3543. __nested_webpack_require_168397__.r(__webpack_exports__);
  3544. /* harmony export */ __nested_webpack_require_168397__.d(__webpack_exports__, {
  3545. /* harmony export */ "SpeedyPipelineNodeHarrisKeypointDetector": () => (/* binding */ SpeedyPipelineNodeHarrisKeypointDetector)
  3546. /* harmony export */ });
  3547. /* harmony import */ var _detector__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_168397__(/*! ./detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  3548. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_168397__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3549. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_168397__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3550. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_168397__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3551. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_168397__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3552. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_168397__(/*! ../../../../../utils/types */ "./src/utils/types.js");
  3553. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_168397__(/*! ../../../../speedy-size */ "./src/core/speedy-size.js");
  3554. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_168397__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  3555. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_168397__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  3556. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_168397__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  3557. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_168397__(/*! ../../../../../utils/globals */ "./src/utils/globals.js");
  3558. /*
  3559. * speedy-vision.js
  3560. * GPU-accelerated Computer Vision for JavaScript
  3561. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3562. *
  3563. * Licensed under the Apache License, Version 2.0 (the "License");
  3564. * you may not use this file except in compliance with the License.
  3565. * You may obtain a copy of the License at
  3566. *
  3567. * http://www.apache.org/licenses/LICENSE-2.0
  3568. *
  3569. * Unless required by applicable law or agreed to in writing, software
  3570. * distributed under the License is distributed on an "AS IS" BASIS,
  3571. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3572. * See the License for the specific language governing permissions and
  3573. * limitations under the License.
  3574. *
  3575. * harris.js
  3576. * Harris corner detector
  3577. */
  3578. /** Window size helper */
  3579. const HARRIS = Object.freeze({
  3580. 1: 'harris1',
  3581. 3: 'harris3',
  3582. 5: 'harris5',
  3583. 7: 'harris7',
  3584. });
  3585. /**
  3586. * Harris corner detector
  3587. */
  3588. class SpeedyPipelineNodeHarrisKeypointDetector extends _detector__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNodeMultiscaleKeypointDetector
  3589. {
  3590. /**
  3591. * Constructor
  3592. * @param {string} [name] name of the node
  3593. */
  3594. constructor(name = undefined)
  3595. {
  3596. super(name, 6, [
  3597. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image).satisfying(
  3598. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  3599. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_5__.ImageFormat.GREY
  3600. ),
  3601. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3602. ]);
  3603. /** @type {SpeedySize} neighborhood size */
  3604. this._windowSize = new _speedy_size__WEBPACK_IMPORTED_MODULE_6__.SpeedySize(3, 3);
  3605. /** @type {number} min corner quality in [0,1] */
  3606. this._quality = 0.1;
  3607. }
  3608. /**
  3609. * Minimum corner quality in [0,1] - this is a fraction of
  3610. * the largest min. eigenvalue of the autocorrelation matrix
  3611. * over the entire image
  3612. * @returns {number}
  3613. */
  3614. get quality()
  3615. {
  3616. return this._quality;
  3617. }
  3618. /**
  3619. * Minimum corner quality in [0,1]
  3620. * @param {number} quality
  3621. */
  3622. set quality(quality)
  3623. {
  3624. this._quality = Math.max(0.0, Math.min(+quality, 1.0));
  3625. }
  3626. /**
  3627. * Neighborhood size
  3628. * @returns {SpeedySize}
  3629. */
  3630. get windowSize()
  3631. {
  3632. return this._windowSize;
  3633. }
  3634. /**
  3635. * Neighborhood size
  3636. * @param {SpeedySize} windowSize
  3637. */
  3638. set windowSize(windowSize)
  3639. {
  3640. const d = windowSize.width;
  3641. if(!((d == windowSize.height) && (d == 1 || d == 3 || d == 5 || d == 7)))
  3642. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Invalid window: ${windowSize}. Acceptable sizes: 1x1, 3x3, 5x5, 7x7`);
  3643. this._windowSize = windowSize;
  3644. }
  3645. /**
  3646. * Run the specific task of this node
  3647. * @param {SpeedyGPU} gpu
  3648. * @returns {void|SpeedyPromise<void>}
  3649. */
  3650. _run(gpu)
  3651. {
  3652. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  3653. const width = image.width, height = image.height;
  3654. const capacity = this._capacity;
  3655. const quality = this._quality;
  3656. const windowSize = this._windowSize.width;
  3657. const levels = this.levels;
  3658. const lodStep = Math.log2(this.scaleFactor);
  3659. const intFactor = levels > 1 ? this.scaleFactor : 1;
  3660. const harris = gpu.programs.keypoints[HARRIS[windowSize]];
  3661. const tex = this._tex;
  3662. // validate pyramid
  3663. if(!(levels == 1 || image.hasMipmaps()))
  3664. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalOperationError(`Expected a pyramid in ${this.fullName}`);
  3665. // skip if the capacity is zero
  3666. if(capacity == 0) {
  3667. const encodedKeypoints = this._encodeZeroKeypoints(gpu, tex[5]);
  3668. const encoderLength = encodedKeypoints.width;
  3669. this.output().swrite(encodedKeypoints, 0, 0, encoderLength);
  3670. return;
  3671. }
  3672. // compute corner response map
  3673. harris.outputs(width, height, tex[0], tex[1]);
  3674. gpu.programs.utils.sobelDerivatives.outputs(width, height, tex[2]);
  3675. gpu.programs.keypoints.nonmaxSpace.outputs(width, height, tex[3]);
  3676. let corners = tex[1].clear();
  3677. let numPasses = Math.max(1, Math.min(levels, (_utils_globals__WEBPACK_IMPORTED_MODULE_10__.PYRAMID_MAX_LEVELS / lodStep) | 0));
  3678. for(let lod = lodStep * (numPasses - 1); numPasses-- > 0; lod -= lodStep) {
  3679. const gaussian = _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.gaussianKernel(intFactor * (1 + lod), windowSize);
  3680. const derivatives = gpu.programs.utils.sobelDerivatives(image, lod);
  3681. corners = harris(corners, image, derivatives, lod, lodStep, gaussian);
  3682. corners = gpu.programs.keypoints.nonmaxSpace(corners); // see below*
  3683. }
  3684. // Same-scale non-maximum suppression
  3685. // *performs better inside the loop
  3686. //corners = gpu.programs.keypoints.nonmaxSpace(corners);
  3687. // Multi-scale non-maximum suppression
  3688. // (doesn't seem to remove many keypoints)
  3689. if(levels > 1) {
  3690. const laplacian = (gpu.programs.keypoints.laplacian
  3691. .outputs(width, height, tex[0])
  3692. )(corners, image, lodStep, 0);
  3693. corners = (gpu.programs.keypoints.nonmaxScale
  3694. .outputs(width, height, tex[2])
  3695. )(corners, image, laplacian, lodStep);
  3696. }
  3697. // find the maximum corner response over the entire image
  3698. gpu.programs.keypoints.harrisScoreFindMax.outputs(width, height, tex[0], tex[1]);
  3699. numPasses = Math.ceil(Math.log2(Math.max(width, height)));
  3700. let maxScore = corners;
  3701. for(let j = 0; j < numPasses; j++)
  3702. maxScore = gpu.programs.keypoints.harrisScoreFindMax(maxScore, j);
  3703. // discard corners below a quality level
  3704. corners = (gpu.programs.keypoints.harrisScoreCutoff
  3705. .outputs(width, height, maxScore == tex[0] ? tex[1] : tex[0])
  3706. )(corners, maxScore, quality);
  3707. // encode keypoints
  3708. let encodedKeypoints = this._encodeKeypoints(gpu, corners, tex[4]);
  3709. const encoderLength = encodedKeypoints.width;
  3710. // scale refinement
  3711. if(levels > 1) {
  3712. encodedKeypoints = (gpu.programs.keypoints.refineScaleLoG
  3713. .outputs(encoderLength, encoderLength, tex[5])
  3714. )(image, lodStep, encodedKeypoints, 0, 0, encoderLength);
  3715. }
  3716. // done!
  3717. this.output().swrite(encodedKeypoints, 0, 0, encoderLength);
  3718. }
  3719. }
  3720. /***/ }),
  3721. /***/ "./src/core/pipeline/nodes/keypoints/distance-filter.js":
  3722. /*!**************************************************************!*\
  3723. !*** ./src/core/pipeline/nodes/keypoints/distance-filter.js ***!
  3724. \**************************************************************/
  3725. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_177632__) => {
  3726. "use strict";
  3727. __nested_webpack_require_177632__.r(__webpack_exports__);
  3728. /* harmony export */ __nested_webpack_require_177632__.d(__webpack_exports__, {
  3729. /* harmony export */ "SpeedyPipelineNodeKeypointDistanceFilter": () => (/* binding */ SpeedyPipelineNodeKeypointDistanceFilter)
  3730. /* harmony export */ });
  3731. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_177632__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  3732. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_177632__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3733. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_177632__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3734. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_177632__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3735. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_177632__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3736. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_177632__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  3737. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_177632__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  3738. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_177632__(/*! ../../../speedy-matrix */ "./src/core/speedy-matrix.js");
  3739. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_177632__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  3740. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_177632__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  3741. /*
  3742. * speedy-vision.js
  3743. * GPU-accelerated Computer Vision for JavaScript
  3744. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3745. *
  3746. * Licensed under the Apache License, Version 2.0 (the "License");
  3747. * you may not use this file except in compliance with the License.
  3748. * You may obtain a copy of the License at
  3749. *
  3750. * http://www.apache.org/licenses/LICENSE-2.0
  3751. *
  3752. * Unless required by applicable law or agreed to in writing, software
  3753. * distributed under the License is distributed on an "AS IS" BASIS,
  3754. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3755. * See the License for the specific language governing permissions and
  3756. * limitations under the License.
  3757. *
  3758. * distance-filter.js
  3759. * Given a set of pairs of keypoints, discard all pairs whose distance is
  3760. * above a user-defined threshold. Useful for bidirectional optical-flow.
  3761. */
  3762. /**
  3763. * Given a set of pairs of keypoints, discard all pairs whose distance is
  3764. * above a user-defined threshold. Useful for bidirectional optical-flow.
  3765. *
  3766. * The pairs of keypoints are provided as two separate sets, "in" and
  3767. * "reference". Keypoints that are kept will have their data extracted
  3768. * from the "in" set.
  3769. */
  3770. class SpeedyPipelineNodeKeypointDistanceFilter extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  3771. {
  3772. /**
  3773. * Constructor
  3774. * @param {string} [name] name of the node
  3775. */
  3776. constructor(name = undefined)
  3777. {
  3778. super(name, 1, [
  3779. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('in').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3780. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('reference').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  3781. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints)
  3782. ]);
  3783. /** @type {number} maximum accepted distance */
  3784. this._threshold = _utils_globals__WEBPACK_IMPORTED_MODULE_9__.MAX_TEXTURE_LENGTH + 1;
  3785. }
  3786. /**
  3787. * Maximum accepted distance
  3788. * @returns {number}
  3789. */
  3790. get threshold()
  3791. {
  3792. return this._threshold;
  3793. }
  3794. /**
  3795. * Maximum accepted distance
  3796. * @param {number} value
  3797. */
  3798. set threshold(value)
  3799. {
  3800. this._threshold = Math.max(0, +value);
  3801. }
  3802. /**
  3803. * Run the specific task of this node
  3804. * @param {SpeedyGPU} gpu
  3805. * @returns {void|SpeedyPromise<void>}
  3806. */
  3807. _run(gpu)
  3808. {
  3809. const set0 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('in').read() );
  3810. const set1 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('reference').read() );
  3811. const threshold = this._threshold;
  3812. // validate shapes
  3813. if(set0.descriptorSize != set1.descriptorSize || set0.extraSize != set1.extraSize)
  3814. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalOperationError(`The distance filter requires two compatible shapes of keypoint streams`);
  3815. // calculate the shape of the output
  3816. const outputTexture = this._tex[0];
  3817. const encoderLength = Math.max(set0.encoderLength, set1.encoderLength);
  3818. const descriptorSize = set0.descriptorSize;
  3819. const extraSize = set0.extraSize;
  3820. // apply the distance filter
  3821. (gpu.programs.keypoints.distanceFilter
  3822. .outputs(encoderLength, encoderLength, outputTexture)
  3823. )(set0.encodedKeypoints, set0.encoderLength, set1.encodedKeypoints, set1.encoderLength, descriptorSize, extraSize, encoderLength, threshold);
  3824. // done!
  3825. this.output().swrite(outputTexture, descriptorSize, extraSize, encoderLength);
  3826. }
  3827. }
  3828. /***/ }),
  3829. /***/ "./src/core/pipeline/nodes/keypoints/hamming-distance-filter.js":
  3830. /*!**********************************************************************!*\
  3831. !*** ./src/core/pipeline/nodes/keypoints/hamming-distance-filter.js ***!
  3832. \**********************************************************************/
  3833. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_183722__) => {
  3834. "use strict";
  3835. __nested_webpack_require_183722__.r(__webpack_exports__);
  3836. /* harmony export */ __nested_webpack_require_183722__.d(__webpack_exports__, {
  3837. /* harmony export */ "SpeedyPipelineNodeKeypointHammingDistanceFilter": () => (/* binding */ SpeedyPipelineNodeKeypointHammingDistanceFilter)
  3838. /* harmony export */ });
  3839. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_183722__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  3840. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_183722__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3841. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_183722__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3842. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_183722__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3843. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_183722__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3844. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_183722__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  3845. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_183722__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  3846. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_183722__(/*! ../../../speedy-matrix */ "./src/core/speedy-matrix.js");
  3847. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_183722__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  3848. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_183722__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  3849. /*
  3850. * speedy-vision.js
  3851. * GPU-accelerated Computer Vision for JavaScript
  3852. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3853. *
  3854. * Licensed under the Apache License, Version 2.0 (the "License");
  3855. * you may not use this file except in compliance with the License.
  3856. * You may obtain a copy of the License at
  3857. *
  3858. * http://www.apache.org/licenses/LICENSE-2.0
  3859. *
  3860. * Unless required by applicable law or agreed to in writing, software
  3861. * distributed under the License is distributed on an "AS IS" BASIS,
  3862. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3863. * See the License for the specific language governing permissions and
  3864. * limitations under the License.
  3865. *
  3866. * hamming-distance-filter.js
  3867. * Given a set of pairs of keypoints, discard all pairs whose hamming
  3868. * distance (of descriptor) is above a user-defined threshold
  3869. */
  3870. /** @type {Object<number,string>} Program names */
  3871. const PROGRAM_NAME = {
  3872. 32: 'hammingDistanceFilter32',
  3873. 64: 'hammingDistanceFilter64',
  3874. };
  3875. /**
  3876. * Given a set of pairs of keypoints, discard all pairs whose hamming
  3877. * distance (of descriptor) is above a user-defined threshold
  3878. *
  3879. * The pairs of keypoints are provided as two separate sets, "in" and
  3880. * "reference". Keypoints that are kept will have their data extracted
  3881. * from the "in" set.
  3882. */
  3883. class SpeedyPipelineNodeKeypointHammingDistanceFilter extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  3884. {
  3885. /**
  3886. * Constructor
  3887. * @param {string} [name] name of the node
  3888. */
  3889. constructor(name = undefined)
  3890. {
  3891. super(name, 1, [
  3892. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('in').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints).satisfying(
  3893. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  3894. msg.descriptorSize > 0
  3895. ),
  3896. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('reference').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints).satisfying(
  3897. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  3898. msg.descriptorSize > 0
  3899. ),
  3900. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints)
  3901. ]);
  3902. /** @type {number} distance threshold, an integer */
  3903. this._threshold = _utils_globals__WEBPACK_IMPORTED_MODULE_9__.MAX_DESCRIPTOR_SIZE * 8; // convert from bytes to bits
  3904. }
  3905. /**
  3906. * Distance threshold, an integer
  3907. * @returns {number}
  3908. */
  3909. get threshold()
  3910. {
  3911. return this._threshold;
  3912. }
  3913. /**
  3914. * Distance threshold, an integer
  3915. * @param {number} value
  3916. */
  3917. set threshold(value)
  3918. {
  3919. this._threshold = Math.max(0, value | 0);
  3920. }
  3921. /**
  3922. * Run the specific task of this node
  3923. * @param {SpeedyGPU} gpu
  3924. * @returns {void|SpeedyPromise<void>}
  3925. */
  3926. _run(gpu)
  3927. {
  3928. const set0 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('in').read() );
  3929. const set1 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('reference').read() );
  3930. const threshold = this._threshold;
  3931. // validate shapes
  3932. if(set0.descriptorSize != set1.descriptorSize || set0.extraSize != set1.extraSize)
  3933. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalOperationError(`The Hamming distance filter requires two compatible shapes of keypoint streams`);
  3934. // validate descriptor size
  3935. if(!Object.prototype.hasOwnProperty.call(PROGRAM_NAME, set0.descriptorSize))
  3936. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.NotSupportedError(`Hamming distance filter - invalid descriptor size: ${set0.descriptorSize}`);
  3937. // calculate the shape of the output
  3938. const outputTexture = this._tex[0];
  3939. const encoderLength = Math.max(set0.encoderLength, set1.encoderLength);
  3940. const descriptorSize = set0.descriptorSize;
  3941. const extraSize = set0.extraSize;
  3942. // apply the distance filter
  3943. const program = PROGRAM_NAME[set0.descriptorSize];
  3944. (gpu.programs.keypoints[program]
  3945. .outputs(encoderLength, encoderLength, outputTexture)
  3946. )(set0.encodedKeypoints, set0.encoderLength, set1.encodedKeypoints, set1.encoderLength, descriptorSize, extraSize, encoderLength, threshold);
  3947. // done!
  3948. this.output().swrite(outputTexture, descriptorSize, extraSize, encoderLength);
  3949. }
  3950. }
  3951. /***/ }),
  3952. /***/ "./src/core/pipeline/nodes/keypoints/matchers/bf-knn.js":
  3953. /*!**************************************************************!*\
  3954. !*** ./src/core/pipeline/nodes/keypoints/matchers/bf-knn.js ***!
  3955. \**************************************************************/
  3956. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_190610__) => {
  3957. "use strict";
  3958. __nested_webpack_require_190610__.r(__webpack_exports__);
  3959. /* harmony export */ __nested_webpack_require_190610__.d(__webpack_exports__, {
  3960. /* harmony export */ "SpeedyPipelineNodeBruteForceKNNKeypointMatcher": () => (/* binding */ SpeedyPipelineNodeBruteForceKNNKeypointMatcher)
  3961. /* harmony export */ });
  3962. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_190610__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  3963. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_190610__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  3964. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_190610__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  3965. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_190610__(/*! ../detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  3966. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_190610__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  3967. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_190610__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  3968. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_190610__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  3969. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_190610__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  3970. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_190610__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  3971. /*
  3972. * speedy-vision.js
  3973. * GPU-accelerated Computer Vision for JavaScript
  3974. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  3975. *
  3976. * Licensed under the Apache License, Version 2.0 (the "License");
  3977. * you may not use this file except in compliance with the License.
  3978. * You may obtain a copy of the License at
  3979. *
  3980. * http://www.apache.org/licenses/LICENSE-2.0
  3981. *
  3982. * Unless required by applicable law or agreed to in writing, software
  3983. * distributed under the License is distributed on an "AS IS" BASIS,
  3984. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  3985. * See the License for the specific language governing permissions and
  3986. * limitations under the License.
  3987. *
  3988. * bf-knn.js
  3989. * Brute Force KNN Keypoint Matcher
  3990. */
  3991. /** @type {Object<number,string>} program name indexed by descriptor size */
  3992. const PROGRAM_NAME = {
  3993. 32: 'bfMatcher32',
  3994. 64: 'bfMatcher64',
  3995. };
  3996. /**
  3997. * Brute Force KNN Keypoint Matcher. Make sure to use a Keypoint Clipper before
  3998. * invoking this (use a database of 50 keypoints or so - your mileage may vary)
  3999. */
  4000. class SpeedyPipelineNodeBruteForceKNNKeypointMatcher extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4001. {
  4002. /**
  4003. * Constructor
  4004. * @param {string} [name] name of the node
  4005. */
  4006. constructor(name = undefined)
  4007. {
  4008. super(name, 6, [
  4009. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('keypoints').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints).satisfying(
  4010. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  4011. msg.descriptorSize > 0
  4012. ),
  4013. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('database').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints).satisfying(
  4014. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  4015. msg.descriptorSize > 0
  4016. ),
  4017. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.KeypointMatches),
  4018. ]);
  4019. /** @type {number} number of matches per keypoint (the "k" of knn) */
  4020. this._matchesPerKeypoint = 1;
  4021. }
  4022. /**
  4023. * Number of matches per keypoint
  4024. * @returns {number}
  4025. */
  4026. get k()
  4027. {
  4028. return this._matchesPerKeypoint;
  4029. }
  4030. /**
  4031. * Number of matches per keypoint
  4032. * @param {number} value
  4033. */
  4034. set k(value)
  4035. {
  4036. this._matchesPerKeypoint = Math.max(1, value | 0);
  4037. }
  4038. /**
  4039. * Run the specific task of this node
  4040. * @param {SpeedyGPU} gpu
  4041. * @returns {void|SpeedyPromise<void>}
  4042. */
  4043. _run(gpu)
  4044. {
  4045. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('keypoints').read() );
  4046. const database = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('database').read() );
  4047. const candidatesA = this._tex[0];
  4048. const candidatesB = this._tex[1];
  4049. const candidatesC = this._tex[2];
  4050. const encodedFiltersA = this._tex[3];
  4051. const encodedMatchesA = this._tex[4];
  4052. const encodedMatchesB = this._tex[5];
  4053. const matchesPerKeypoint = this._matchesPerKeypoint;
  4054. const keypoints = gpu.programs.keypoints;
  4055. // validate parameters
  4056. if(descriptorSize !== database.descriptorSize)
  4057. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Incompatible descriptors in ${this.fullName}`);
  4058. else if(!Object.prototype.hasOwnProperty.call(PROGRAM_NAME, descriptorSize))
  4059. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.NotSupportedError(`Unsupported descriptor size (${descriptorSize}) in ${this.fullName}`);
  4060. // prepare the brute force matching
  4061. const bfMatcher = keypoints[PROGRAM_NAME[descriptorSize]];
  4062. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  4063. const dbCapacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(database.descriptorSize, database.extraSize, database.encoderLength);
  4064. const numberOfKeypointsPerPass = bfMatcher.definedConstant('NUMBER_OF_KEYPOINTS_PER_PASS');
  4065. const numberOfPasses = Math.ceil(dbCapacity / numberOfKeypointsPerPass);
  4066. const partialMatcherLength = Math.max(1, Math.ceil(Math.sqrt(capacity)));
  4067. const matcherLength = Math.max(1, Math.ceil(Math.sqrt(capacity * matchesPerKeypoint)));
  4068. keypoints.bfMatcherTransfer.outputs(matcherLength, matcherLength, encodedMatchesA, encodedMatchesB);
  4069. keypoints.bfMatcherInitCandidates.outputs(partialMatcherLength, partialMatcherLength, candidatesC);
  4070. keypoints.bfMatcherInitFilters.outputs(partialMatcherLength, partialMatcherLength, encodedFiltersA);
  4071. bfMatcher.outputs(partialMatcherLength, partialMatcherLength, candidatesA, candidatesB);
  4072. // match keypoints
  4073. let encodedMatches = encodedMatchesB.clear(); // will hold all best matches
  4074. let encodedFilters = keypoints.bfMatcherInitFilters();
  4075. for(let k = 0; k < matchesPerKeypoint; k++) {
  4076. let encodedPartialMatches = keypoints.bfMatcherInitCandidates(); // hold the (k+1)-th best matches
  4077. // find the (k+1)-th best match
  4078. for(let passId = 0; passId < numberOfPasses; passId++) {
  4079. encodedPartialMatches = bfMatcher(
  4080. encodedPartialMatches, encodedFilters, partialMatcherLength,
  4081. database.encodedKeypoints, database.descriptorSize, database.extraSize, database.encoderLength,
  4082. encodedKeypoints, descriptorSize, extraSize, encoderLength,
  4083. passId
  4084. );
  4085. gpu.gl.flush();
  4086. }
  4087. //gpu.gl.flush();
  4088. // copy the (k+1)-th best match to the filter
  4089. if(matchesPerKeypoint > 1)
  4090. encodedPartialMatches.copyTo(encodedFilters);
  4091. // aggregate matches
  4092. encodedMatches = keypoints.bfMatcherTransfer(
  4093. encodedMatches, encodedPartialMatches, matchesPerKeypoint, k
  4094. );
  4095. }
  4096. // done!
  4097. this.output().swrite(encodedMatches, matchesPerKeypoint);
  4098. }
  4099. }
  4100. /***/ }),
  4101. /***/ "./src/core/pipeline/nodes/keypoints/matchers/lsh-knn.js":
  4102. /*!***************************************************************!*\
  4103. !*** ./src/core/pipeline/nodes/keypoints/matchers/lsh-knn.js ***!
  4104. \***************************************************************/
  4105. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_199268__) => {
  4106. "use strict";
  4107. __nested_webpack_require_199268__.r(__webpack_exports__);
  4108. /* harmony export */ __nested_webpack_require_199268__.d(__webpack_exports__, {
  4109. /* harmony export */ "SpeedyPipelineNodeLSHKNNMatcher": () => (/* binding */ SpeedyPipelineNodeLSHKNNMatcher)
  4110. /* harmony export */ });
  4111. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_199268__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4112. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_199268__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4113. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_199268__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4114. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_199268__(/*! ../detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  4115. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_199268__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4116. /* harmony import */ var _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_199268__(/*! ../../../../../gpu/speedy-lsh */ "./src/gpu/speedy-lsh.js");
  4117. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_199268__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  4118. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_199268__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  4119. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_199268__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  4120. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_199268__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  4121. /*
  4122. * speedy-vision.js
  4123. * GPU-accelerated Computer Vision for JavaScript
  4124. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4125. *
  4126. * Licensed under the Apache License, Version 2.0 (the "License");
  4127. * you may not use this file except in compliance with the License.
  4128. * You may obtain a copy of the License at
  4129. *
  4130. * http://www.apache.org/licenses/LICENSE-2.0
  4131. *
  4132. * Unless required by applicable law or agreed to in writing, software
  4133. * distributed under the License is distributed on an "AS IS" BASIS,
  4134. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4135. * See the License for the specific language governing permissions and
  4136. * limitations under the License.
  4137. *
  4138. * lsh-knn.js
  4139. * K approximate nearest neighbors matcher
  4140. */
  4141. /** @typedef {'fastest' | 'default' | 'demanding'} LSHKNNQualityLevel quality of the approximate matching */
  4142. /** @type {number} how many neighbors to search for, by default */
  4143. const DEFAULT_K = 1;
  4144. /** @type {LSHKNNQualityLevel} default quality level */
  4145. const DEFAULT_QUALITY = 'default';
  4146. /** @type {{ [key in LSHKNNQualityLevel]: number }} maps quality level to bit swaps */
  4147. const NUMBER_OF_BIT_SWAPS = {
  4148. 'fastest': 0,
  4149. 'default': 1,
  4150. 'demanding': 2,
  4151. };
  4152. /** @type {object} program names indexed as LSH_KNN[descriptorSize][hashSize][level] */
  4153. const LSH_KNN = (fd => _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_5__.LSH_ACCEPTABLE_DESCRIPTOR_SIZES.reduce((o,d) => ((o[d] = fd(d)), o), {}))(
  4154. d => ((fh => _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_5__.LSH_ACCEPTABLE_HASH_SIZES.reduce((o,h) => ((o[h] = fh(h)), o), {}))(
  4155. h => ((fl => [0,1,2].reduce((o,l) => ((o[l] = fl(l)), o), {}))(
  4156. l => `lshKnn${d}h${h}lv${l}`
  4157. ))
  4158. ))
  4159. );
  4160. /**
  4161. * K approximate nearest neighbors matcher
  4162. */
  4163. class SpeedyPipelineNodeLSHKNNMatcher extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4164. {
  4165. /**
  4166. * Constructor
  4167. * @param {string} [name] name of the node
  4168. */
  4169. constructor(name = undefined)
  4170. {
  4171. super(name, 6, [
  4172. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('keypoints').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints).satisfying(
  4173. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  4174. msg.descriptorSize > 0
  4175. ),
  4176. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)('lsh').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.LSHTables),
  4177. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.KeypointMatches),
  4178. ]);
  4179. /** @type {number} how many neighbors do you want? */
  4180. this._k = DEFAULT_K;
  4181. /** @type {LSHKNNQualityLevel} quality of the matching */
  4182. this._quality = DEFAULT_QUALITY;
  4183. }
  4184. /**
  4185. * How many neighbors do you want?
  4186. * @returns {number}
  4187. */
  4188. get k()
  4189. {
  4190. return this._k;
  4191. }
  4192. /**
  4193. * How many neighbors do you want?
  4194. * @param {number} k number of neighbors
  4195. */
  4196. set k(k)
  4197. {
  4198. this._k = Math.max(1, k | 0);
  4199. }
  4200. /**
  4201. * Quality of the matching
  4202. * @returns {LSHKNNQualityLevel}
  4203. */
  4204. get quality()
  4205. {
  4206. return this._quality;
  4207. }
  4208. /**
  4209. * Quality of the matching
  4210. * @param {LSHKNNQualityLevel} quality
  4211. */
  4212. set quality(quality)
  4213. {
  4214. if(!Object.prototype.hasOwnProperty.call(NUMBER_OF_BIT_SWAPS, quality))
  4215. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Invalid quality level: "${quality}"`);
  4216. this._quality = quality;
  4217. }
  4218. /**
  4219. * Run the specific task of this node
  4220. * @param {SpeedyGPU} gpu
  4221. * @returns {void|SpeedyPromise<void>}
  4222. */
  4223. _run(gpu)
  4224. {
  4225. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('keypoints').read() );
  4226. /** @type {SpeedyLSH} */ const lsh = this.input('lsh').read().lsh;
  4227. const keypoints = gpu.programs.keypoints;
  4228. const tables = lsh.tables;
  4229. const descriptorDB = lsh.descriptorDB;
  4230. const tablesStride = tables.width;
  4231. const descriptorDBStride = descriptorDB.width;
  4232. const tableCount = lsh.tableCount;
  4233. const hashSize = lsh.hashSize;
  4234. const bucketCapacity = lsh.bucketCapacity;
  4235. const bucketsPerTable = lsh.bucketsPerTable;
  4236. const sequences = lsh.sequences;
  4237. const candidatesA = this._tex[0];
  4238. const candidatesB = this._tex[1];
  4239. const candidatesC = this._tex[2];
  4240. const filters = this._tex[3];
  4241. const transferA = this._tex[4];
  4242. const transferB = this._tex[5];
  4243. const level = NUMBER_OF_BIT_SWAPS[this._quality];
  4244. const matchesPerKeypoint = this._k;
  4245. // validate parameters
  4246. if(descriptorSize !== lsh.descriptorSize)
  4247. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Can't match different types of descriptors in ${this.fullName}`);
  4248. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.assert(LSH_KNN[descriptorSize] != undefined);
  4249. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.assert(LSH_KNN[descriptorSize][hashSize] != undefined);
  4250. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.assert(LSH_KNN[descriptorSize][hashSize][level] != undefined);
  4251. // configure the output texture
  4252. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  4253. const matcherLength = Math.max(1, Math.ceil(Math.sqrt(capacity * matchesPerKeypoint)));
  4254. let encodedMatches = transferB;
  4255. keypoints.lshKnnTransfer.outputs(matcherLength, matcherLength, transferA, transferB);
  4256. // prepare the LSH matching
  4257. const kthMatcherLength = Math.max(1, Math.ceil(Math.sqrt(capacity)));
  4258. keypoints.lshKnnInitCandidates.outputs(kthMatcherLength, kthMatcherLength, candidatesA);
  4259. keypoints.lshKnnInitFilters.outputs(kthMatcherLength, kthMatcherLength, filters);
  4260. const lshKnn = keypoints[LSH_KNN[descriptorSize][hashSize][level]];
  4261. lshKnn.outputs(kthMatcherLength, kthMatcherLength, candidatesB, candidatesC);
  4262. lshKnn.setUBO('LSHSequences', sequences);
  4263. // match keypoints
  4264. encodedMatches.clear();
  4265. keypoints.lshKnnInitFilters();
  4266. for(let i = 0; i < matchesPerKeypoint; i++) {
  4267. // find the (i+1)-th best match
  4268. let candidates = keypoints.lshKnnInitCandidates();
  4269. for(let tableIndex = 0; tableIndex < tableCount; tableIndex++) {
  4270. candidates = lshKnn(candidates, filters, kthMatcherLength, tables, descriptorDB, tableIndex, bucketCapacity, bucketsPerTable, tablesStride, descriptorDBStride, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  4271. gpu.gl.flush();
  4272. }
  4273. candidates.copyTo(filters);
  4274. // transfer matches to an encoded matches texture
  4275. encodedMatches = keypoints.lshKnnTransfer(encodedMatches, candidates, matchesPerKeypoint, i);
  4276. }
  4277. // done
  4278. this.output().swrite(encodedMatches, matchesPerKeypoint);
  4279. /*
  4280. // debug
  4281. let data = this._inspect32(filters), debug = [];
  4282. for(let i = 0; i < data.length; i++) {
  4283. const bits = MATCH_INDEX_BITS;
  4284. const mask = (1 << bits) - 1;
  4285. const u32 = data[i];
  4286. const index = u32 & mask, distance = u32 >>> bits;
  4287. //debug.push('|'+[ u32 ].toString());
  4288. debug.push('|'+[ index, distance ].toString());
  4289. }
  4290. console.log(debug.join(','));
  4291. */
  4292. }
  4293. }
  4294. /***/ }),
  4295. /***/ "./src/core/pipeline/nodes/keypoints/matchers/lsh-static-tables.js":
  4296. /*!*************************************************************************!*\
  4297. !*** ./src/core/pipeline/nodes/keypoints/matchers/lsh-static-tables.js ***!
  4298. \*************************************************************************/
  4299. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_209466__) => {
  4300. "use strict";
  4301. __nested_webpack_require_209466__.r(__webpack_exports__);
  4302. /* harmony export */ __nested_webpack_require_209466__.d(__webpack_exports__, {
  4303. /* harmony export */ "SpeedyPipelineNodeStaticLSHTables": () => (/* binding */ SpeedyPipelineNodeStaticLSHTables)
  4304. /* harmony export */ });
  4305. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_209466__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4306. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_209466__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4307. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_209466__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4308. /* harmony import */ var _speedy_keypoint__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_209466__(/*! ../../../../speedy-keypoint */ "./src/core/speedy-keypoint.js");
  4309. /* harmony import */ var _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_209466__(/*! ../../../../speedy-keypoint-descriptor */ "./src/core/speedy-keypoint-descriptor.js");
  4310. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_209466__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4311. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_209466__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  4312. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_209466__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  4313. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_209466__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  4314. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_209466__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  4315. /* harmony import */ var _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_209466__(/*! ../../../../../gpu/speedy-lsh */ "./src/gpu/speedy-lsh.js");
  4316. /*
  4317. * speedy-vision.js
  4318. * GPU-accelerated Computer Vision for JavaScript
  4319. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4320. *
  4321. * Licensed under the Apache License, Version 2.0 (the "License");
  4322. * you may not use this file except in compliance with the License.
  4323. * You may obtain a copy of the License at
  4324. *
  4325. * http://www.apache.org/licenses/LICENSE-2.0
  4326. *
  4327. * Unless required by applicable law or agreed to in writing, software
  4328. * distributed under the License is distributed on an "AS IS" BASIS,
  4329. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4330. * See the License for the specific language governing permissions and
  4331. * limitations under the License.
  4332. *
  4333. * lsh-static-tables.js
  4334. * Static LSH tables
  4335. */
  4336. /**
  4337. * Static LSH tables
  4338. */
  4339. class SpeedyPipelineNodeStaticLSHTables extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSourceNode
  4340. {
  4341. /**
  4342. * Constructor
  4343. * @param {string} [name] name of the node
  4344. */
  4345. constructor(name = undefined)
  4346. {
  4347. super(name, 2, [
  4348. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.LSHTables)
  4349. ]);
  4350. /** @type {SpeedyKeypoint[]} "training" keypoints */
  4351. this._keypoints = [];
  4352. /** @type {SpeedyKeypoint[]} internal copy of the "training" keypoints */
  4353. this._keypointsCopy = [];
  4354. /** @type {number} number of tables in the LSH data structure */
  4355. this._numberOfTables = _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_DEFAULT_NUMBER_OF_TABLES;
  4356. /** @type {number} number of bits of a hash */
  4357. this._hashSize = _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_DEFAULT_HASH_SIZE;
  4358. /** @type {SpeedyLSH|null} LSH data structure */
  4359. this._lsh = null;
  4360. }
  4361. /**
  4362. * "Training" keypoints
  4363. * @returns {SpeedyKeypoint[]}
  4364. */
  4365. get keypoints()
  4366. {
  4367. return this._keypoints;
  4368. }
  4369. /**
  4370. * "Training" keypoints
  4371. * @param {SpeedyKeypoint[]} keypoints
  4372. */
  4373. set keypoints(keypoints)
  4374. {
  4375. if(!Array.isArray(keypoints) || keypoints.find(keypoint => !(keypoint instanceof _speedy_keypoint__WEBPACK_IMPORTED_MODULE_3__.SpeedyKeypoint)))
  4376. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Static LSH tables: an invalid set of keypoints has been provided`);
  4377. if(this._keypoints !== keypoints) {
  4378. this._keypoints = keypoints; // update internal pointer
  4379. this._keypointsCopy = keypoints.slice(0); // clone the array, so it won't be modified externally
  4380. this._lsh = null; // (re)train the model
  4381. }
  4382. }
  4383. /**
  4384. * Number of tables in the LSH data structure
  4385. * @returns {number}
  4386. */
  4387. get numberOfTables()
  4388. {
  4389. return this._numberOfTables;
  4390. }
  4391. /**
  4392. * Number of tables in the LSH data structure
  4393. * @param {number} n
  4394. */
  4395. set numberOfTables(n)
  4396. {
  4397. if(!_gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_ACCEPTABLE_NUMBER_OF_TABLES.includes(n))
  4398. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Invalid number of tables: ${n}. Acceptable values: ${_gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_ACCEPTABLE_NUMBER_OF_TABLES.join(', ')}`);
  4399. if(n !== this._numberOfTables) {
  4400. this._numberOfTables = n | 0;
  4401. this._lsh = null; // need to retrain the model
  4402. }
  4403. }
  4404. /**
  4405. * Number of bits of a hash
  4406. * @returns {number}
  4407. */
  4408. get hashSize()
  4409. {
  4410. return this._hashSize;
  4411. }
  4412. /**
  4413. * Number of bits of a hash
  4414. * @param {number} h
  4415. */
  4416. set hashSize(h)
  4417. {
  4418. if(!_gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_ACCEPTABLE_HASH_SIZES.includes(h))
  4419. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Invalid hash size: ${h}. Acceptable values: ${_gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.LSH_ACCEPTABLE_HASH_SIZES.join(', ')}`);
  4420. if(h !== this._hashSize) {
  4421. this._hashSize = h | 0;
  4422. this._lsh = null; // need to retrain the model
  4423. }
  4424. }
  4425. /**
  4426. * Run the specific task of this node
  4427. * @param {SpeedyGPU} gpu
  4428. * @returns {void|SpeedyPromise<void>}
  4429. */
  4430. _run(gpu)
  4431. {
  4432. // Need to train the model?
  4433. if(this._lsh == null) {
  4434. // internal work textures are only available after initialization,
  4435. // i.e., after calling this._init()
  4436. this._lsh = this._train();
  4437. }
  4438. // Pass it forward
  4439. this.output().swrite(this._lsh);
  4440. }
  4441. /**
  4442. * Train the model
  4443. * @returns {SpeedyLSH}
  4444. */
  4445. _train()
  4446. {
  4447. const keypoints = this._keypointsCopy;
  4448. const numberOfTables = this._numberOfTables;
  4449. const hashSize = this._hashSize;
  4450. if(keypoints.find(keypoint => keypoint.descriptor == null))
  4451. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Static LSH tables: can't train the model with no keypoint descriptors!`);
  4452. const descriptors = keypoints.map(keypoint => keypoint.descriptor.data);
  4453. const lshTables = this._tex[0];
  4454. const descriptorDB = this._tex[1];
  4455. return new _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_10__.SpeedyLSH(lshTables, descriptorDB, descriptors, numberOfTables, hashSize);
  4456. }
  4457. }
  4458. /***/ }),
  4459. /***/ "./src/core/pipeline/nodes/keypoints/mixer.js":
  4460. /*!****************************************************!*\
  4461. !*** ./src/core/pipeline/nodes/keypoints/mixer.js ***!
  4462. \****************************************************/
  4463. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_217333__) => {
  4464. "use strict";
  4465. __nested_webpack_require_217333__.r(__webpack_exports__);
  4466. /* harmony export */ __nested_webpack_require_217333__.d(__webpack_exports__, {
  4467. /* harmony export */ "SpeedyPipelineNodeKeypointMixer": () => (/* binding */ SpeedyPipelineNodeKeypointMixer)
  4468. /* harmony export */ });
  4469. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_217333__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4470. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_217333__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  4471. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_217333__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4472. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_217333__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4473. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_217333__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4474. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_217333__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  4475. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_217333__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  4476. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_217333__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  4477. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_217333__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  4478. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_217333__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  4479. /*
  4480. * speedy-vision.js
  4481. * GPU-accelerated Computer Vision for JavaScript
  4482. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4483. *
  4484. * Licensed under the Apache License, Version 2.0 (the "License");
  4485. * you may not use this file except in compliance with the License.
  4486. * You may obtain a copy of the License at
  4487. *
  4488. * http://www.apache.org/licenses/LICENSE-2.0
  4489. *
  4490. * Unless required by applicable law or agreed to in writing, software
  4491. * distributed under the License is distributed on an "AS IS" BASIS,
  4492. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4493. * See the License for the specific language governing permissions and
  4494. * limitations under the License.
  4495. *
  4496. * mixer.js
  4497. * Keypoint Mixer
  4498. */
  4499. /**
  4500. * Keypoint Mixer: merges two sets of keypoints
  4501. */
  4502. class SpeedyPipelineNodeKeypointMixer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4503. {
  4504. /**
  4505. * Constructor
  4506. * @param {string} [name] name of the node
  4507. */
  4508. constructor(name = undefined)
  4509. {
  4510. super(name, 5, [
  4511. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('in0').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  4512. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('in1').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  4513. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  4514. ]);
  4515. }
  4516. /**
  4517. * Run the specific task of this node
  4518. * @param {SpeedyGPU} gpu
  4519. * @returns {void|SpeedyPromise<void>}
  4520. */
  4521. _run(gpu)
  4522. {
  4523. const kps0 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('in0').read() );
  4524. const kps1 = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('in1').read() );
  4525. const descriptorSize = kps0.descriptorSize;
  4526. const extraSize = kps0.extraSize;
  4527. const keypoints = gpu.programs.keypoints;
  4528. const tex = this._tex;
  4529. // ensure that the format of kps0 equals the format of kps1
  4530. if(!(kps0.descriptorSize === kps1.descriptorSize && kps0.extraSize === kps0.extraSize))
  4531. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Can't merge two sets of keypoints that have different formats`);
  4532. // find the capacity of kps0 + kps1
  4533. const cap0 = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(kps0.descriptorSize, kps0.extraSize, kps0.encoderLength);
  4534. const cap1 = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(kps1.descriptorSize, kps1.extraSize, kps1.encoderLength);
  4535. const capacity = cap0 + cap1;
  4536. // find the dimensions of the output texture
  4537. const encoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderLength(capacity, descriptorSize, extraSize);
  4538. const mixEncoderLength = Math.max(1, Math.ceil(Math.sqrt(capacity)));
  4539. // prepare programs
  4540. keypoints.mixKeypointsPreInit.outputs(encoderLength, encoderLength, tex[0]);
  4541. keypoints.mixKeypointsInit.outputs(mixEncoderLength, mixEncoderLength, tex[1]);
  4542. keypoints.mixKeypointsSort.outputs(mixEncoderLength, mixEncoderLength, tex[2], tex[3]);
  4543. keypoints.mixKeypointsApply.outputs(encoderLength, encoderLength, tex[4]);
  4544. // mix keypoints
  4545. let mixedKeypoints = keypoints.mixKeypointsPreInit(
  4546. kps0.encodedKeypoints, kps1.encodedKeypoints,
  4547. kps0.encoderLength, kps1.encoderLength,
  4548. cap0, cap1,
  4549. descriptorSize,
  4550. extraSize,
  4551. encoderLength
  4552. );
  4553. let sortedKeypoints = keypoints.mixKeypointsInit(
  4554. mixedKeypoints, descriptorSize, extraSize, encoderLength, capacity
  4555. );
  4556. for(let b = 1; b < capacity; b *= 2)
  4557. sortedKeypoints = keypoints.mixKeypointsSort(sortedKeypoints, b);
  4558. mixedKeypoints = keypoints.mixKeypointsApply(
  4559. sortedKeypoints, mixedKeypoints, descriptorSize, extraSize, encoderLength
  4560. );
  4561. /*
  4562. // debug: view keypoints
  4563. keypoints.mixKeypointsView.outputs(mixEncoderLength, mixEncoderLength, tex[1]);
  4564. this._visualize(gpu, keypoints.mixKeypointsView(sortedKeypoints));
  4565. */
  4566. this.output().swrite(mixedKeypoints, descriptorSize, extraSize, encoderLength);
  4567. }
  4568. }
  4569. /***/ }),
  4570. /***/ "./src/core/pipeline/nodes/keypoints/multiplexer.js":
  4571. /*!**********************************************************!*\
  4572. !*** ./src/core/pipeline/nodes/keypoints/multiplexer.js ***!
  4573. \**********************************************************/
  4574. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_224170__) => {
  4575. "use strict";
  4576. __nested_webpack_require_224170__.r(__webpack_exports__);
  4577. /* harmony export */ __nested_webpack_require_224170__.d(__webpack_exports__, {
  4578. /* harmony export */ "SpeedyPipelineNodeKeypointMultiplexer": () => (/* binding */ SpeedyPipelineNodeKeypointMultiplexer)
  4579. /* harmony export */ });
  4580. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_224170__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4581. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_224170__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4582. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_224170__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4583. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_224170__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4584. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_224170__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  4585. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_224170__(/*! ../../../speedy-media */ "./src/core/speedy-media.js");
  4586. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_224170__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  4587. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_224170__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  4588. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_224170__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  4589. /*
  4590. * speedy-vision.js
  4591. * GPU-accelerated Computer Vision for JavaScript
  4592. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4593. *
  4594. * Licensed under the Apache License, Version 2.0 (the "License");
  4595. * you may not use this file except in compliance with the License.
  4596. * You may obtain a copy of the License at
  4597. *
  4598. * http://www.apache.org/licenses/LICENSE-2.0
  4599. *
  4600. * Unless required by applicable law or agreed to in writing, software
  4601. * distributed under the License is distributed on an "AS IS" BASIS,
  4602. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4603. * See the License for the specific language governing permissions and
  4604. * limitations under the License.
  4605. *
  4606. * multiplexer.js
  4607. * Keypoint multiplexer
  4608. */
  4609. /** @type {string[]} the names of the input ports indexed by their number */
  4610. const INPUT_PORT = [ 'in0', 'in1' ];
  4611. /**
  4612. * Keypoint multiplexer
  4613. */
  4614. class SpeedyPipelineNodeKeypointMultiplexer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4615. {
  4616. /**
  4617. * Constructor
  4618. * @param {string} [name] name of the node
  4619. */
  4620. constructor(name = undefined)
  4621. {
  4622. super(name, 0, [
  4623. ...(INPUT_PORT.map(portName => (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)(portName).expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints))),
  4624. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  4625. ]);
  4626. /** @type {number} which port should be linked to the output? */
  4627. this._port = 0;
  4628. }
  4629. /**
  4630. * The number of the port that should be linked to the output
  4631. * @returns {number}
  4632. */
  4633. get port()
  4634. {
  4635. return this._port;
  4636. }
  4637. /**
  4638. * The number of the port that should be linked to the output
  4639. * @param {number} port
  4640. */
  4641. set port(port)
  4642. {
  4643. if(port < 0 || port >= INPUT_PORT.length)
  4644. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Invalid port: ${port}`);
  4645. this._port = port | 0;
  4646. }
  4647. /**
  4648. * Run the specific task of this node
  4649. * @param {SpeedyGPU} gpu
  4650. * @returns {void|SpeedyPromise<void>}
  4651. */
  4652. _run(gpu)
  4653. {
  4654. const message = this.input(INPUT_PORT[this._port]).read();
  4655. this.output().write(message);
  4656. }
  4657. }
  4658. /***/ }),
  4659. /***/ "./src/core/pipeline/nodes/keypoints/portal.js":
  4660. /*!*****************************************************!*\
  4661. !*** ./src/core/pipeline/nodes/keypoints/portal.js ***!
  4662. \*****************************************************/
  4663. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_228626__) => {
  4664. "use strict";
  4665. __nested_webpack_require_228626__.r(__webpack_exports__);
  4666. /* harmony export */ __nested_webpack_require_228626__.d(__webpack_exports__, {
  4667. /* harmony export */ "SpeedyPipelineNodeKeypointPortalSink": () => (/* binding */ SpeedyPipelineNodeKeypointPortalSink),
  4668. /* harmony export */ "SpeedyPipelineNodeKeypointPortalSource": () => (/* binding */ SpeedyPipelineNodeKeypointPortalSource)
  4669. /* harmony export */ });
  4670. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_228626__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4671. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_228626__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4672. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_228626__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  4673. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_228626__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4674. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_228626__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4675. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_228626__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  4676. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_228626__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  4677. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_228626__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  4678. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_228626__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  4679. /*
  4680. * speedy-vision.js
  4681. * GPU-accelerated Computer Vision for JavaScript
  4682. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4683. *
  4684. * Licensed under the Apache License, Version 2.0 (the "License");
  4685. * you may not use this file except in compliance with the License.
  4686. * You may obtain a copy of the License at
  4687. *
  4688. * http://www.apache.org/licenses/LICENSE-2.0
  4689. *
  4690. * Unless required by applicable law or agreed to in writing, software
  4691. * distributed under the License is distributed on an "AS IS" BASIS,
  4692. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4693. * See the License for the specific language governing permissions and
  4694. * limitations under the License.
  4695. *
  4696. * portal.js
  4697. * Keypoint Portals
  4698. */
  4699. /**
  4700. * A sink of a Keypoint Portal
  4701. * This is not a pipeline sink - it doesn't export any data!
  4702. */
  4703. class SpeedyPipelineNodeKeypointPortalSink extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4704. {
  4705. /**
  4706. * Constructor
  4707. * @param {string} [name] name of the node
  4708. */
  4709. constructor(name = undefined)
  4710. {
  4711. super(name, 1, [
  4712. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  4713. ]);
  4714. /** @type {number} descriptor size, in bytes */
  4715. this._descriptorSize = 0;
  4716. /** @type {number} extra size, in bytes */
  4717. this._extraSize = 0;
  4718. /** @type {number} extra size */
  4719. this._encoderLength = 0;
  4720. /** @type {boolean} is this node initialized? */
  4721. this._initialized = false;
  4722. }
  4723. /**
  4724. * Encoded keypoints
  4725. * @returns {SpeedyTexture}
  4726. */
  4727. get encodedKeypoints()
  4728. {
  4729. if(!this._initialized)
  4730. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  4731. return this._tex[0];
  4732. }
  4733. /**
  4734. * Descriptor size, in bytes
  4735. * @returns {number}
  4736. */
  4737. get descriptorSize()
  4738. {
  4739. if(!this._initialized)
  4740. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  4741. return this._descriptorSize;
  4742. }
  4743. /**
  4744. * Extra size, in bytes
  4745. * @returns {number}
  4746. */
  4747. get extraSize()
  4748. {
  4749. if(!this._initialized)
  4750. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  4751. return this._extraSize;
  4752. }
  4753. /**
  4754. * Encoder length
  4755. * @returns {number}
  4756. */
  4757. get encoderLength()
  4758. {
  4759. if(!this._initialized)
  4760. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`Portal error: ${this.fullName} holds no data`);
  4761. return this._encoderLength;
  4762. }
  4763. /**
  4764. * Initializes this node
  4765. * @param {SpeedyGPU} gpu
  4766. */
  4767. init(gpu)
  4768. {
  4769. super.init(gpu);
  4770. const encoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineNodeKeypointDetector.encoderLength(0, 0, 0);
  4771. this._tex[0].resize(encoderLength, encoderLength).clearToColor(1,1,1,1); // initial texture
  4772. this._descriptorSize = this._extraSize = 0;
  4773. this._encoderLength = encoderLength;
  4774. this._initialized = true;
  4775. }
  4776. /**
  4777. * Releases this node
  4778. * @param {SpeedyGPU} gpu
  4779. */
  4780. release(gpu)
  4781. {
  4782. this._initialized = false;
  4783. super.release(gpu);
  4784. }
  4785. /**
  4786. * Run the specific task of this node
  4787. * @param {SpeedyGPU} gpu
  4788. * @returns {void|SpeedyPromise<void>}
  4789. */
  4790. _run(gpu)
  4791. {
  4792. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  4793. const tex = this._tex[0];
  4794. // copy input
  4795. tex.resize(encodedKeypoints.width, encodedKeypoints.height);
  4796. encodedKeypoints.copyTo(tex);
  4797. this._descriptorSize = descriptorSize;
  4798. this._extraSize = extraSize;
  4799. this._encoderLength = encoderLength;
  4800. }
  4801. }
  4802. /**
  4803. * A source of a Keypoint Portal
  4804. */
  4805. class SpeedyPipelineNodeKeypointPortalSource extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSourceNode
  4806. {
  4807. /**
  4808. * Constructor
  4809. * @param {string} [name] name of the node
  4810. */
  4811. constructor(name = undefined)
  4812. {
  4813. super(name, 0, [
  4814. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  4815. ]);
  4816. /** @type {SpeedyPipelineNodeKeypointPortalSink|null} portal sink */
  4817. this._source = null;
  4818. }
  4819. /**
  4820. * Data source
  4821. * @returns {SpeedyPipelineNodeKeypointPortalSink|null}
  4822. */
  4823. get source()
  4824. {
  4825. return this._source;
  4826. }
  4827. /**
  4828. * Data source
  4829. * @param {SpeedyPipelineNodeKeypointPortalSink|null} node
  4830. */
  4831. set source(node)
  4832. {
  4833. if(node !== null && !(node instanceof SpeedyPipelineNodeKeypointPortalSink))
  4834. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Incompatible source for ${this.fullName}`);
  4835. this._source = node;
  4836. }
  4837. /**
  4838. * Run the specific task of this node
  4839. * @param {SpeedyGPU} gpu
  4840. * @returns {void|SpeedyPromise<void>}
  4841. */
  4842. _run(gpu)
  4843. {
  4844. if(this._source == null)
  4845. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalOperationError(`${this.fullName} has no source`);
  4846. this.output().swrite(this._source.encodedKeypoints, this._source.descriptorSize, this._source.extraSize, this._source.encoderLength);
  4847. }
  4848. }
  4849. /***/ }),
  4850. /***/ "./src/core/pipeline/nodes/keypoints/shuffler.js":
  4851. /*!*******************************************************!*\
  4852. !*** ./src/core/pipeline/nodes/keypoints/shuffler.js ***!
  4853. \*******************************************************/
  4854. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_236567__) => {
  4855. "use strict";
  4856. __nested_webpack_require_236567__.r(__webpack_exports__);
  4857. /* harmony export */ __nested_webpack_require_236567__.d(__webpack_exports__, {
  4858. /* harmony export */ "SpeedyPipelineNodeKeypointShuffler": () => (/* binding */ SpeedyPipelineNodeKeypointShuffler)
  4859. /* harmony export */ });
  4860. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_236567__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4861. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_236567__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  4862. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_236567__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  4863. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_236567__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  4864. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_236567__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  4865. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_236567__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  4866. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_236567__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  4867. /*
  4868. * speedy-vision.js
  4869. * GPU-accelerated Computer Vision for JavaScript
  4870. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  4871. *
  4872. * Licensed under the Apache License, Version 2.0 (the "License");
  4873. * you may not use this file except in compliance with the License.
  4874. * You may obtain a copy of the License at
  4875. *
  4876. * http://www.apache.org/licenses/LICENSE-2.0
  4877. *
  4878. * Unless required by applicable law or agreed to in writing, software
  4879. * distributed under the License is distributed on an "AS IS" BASIS,
  4880. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  4881. * See the License for the specific language governing permissions and
  4882. * limitations under the License.
  4883. *
  4884. * shuffler.js
  4885. * Keypoint Shuffler
  4886. */
  4887. /**
  4888. * The Keypoint Shuffler shuffles a list of keypoints
  4889. */
  4890. class SpeedyPipelineNodeKeypointShuffler extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  4891. {
  4892. /**
  4893. * Constructor
  4894. * @param {string} [name] name of the node
  4895. */
  4896. constructor(name = undefined)
  4897. {
  4898. super(name, 6, [
  4899. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  4900. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  4901. ]);
  4902. /** @type {number} maximum number of keypoints */
  4903. this._maxKeypoints = Number.NaN;
  4904. }
  4905. /**
  4906. * Maximum number of keypoints (optional)
  4907. * @returns {number}
  4908. */
  4909. get maxKeypoints()
  4910. {
  4911. return this._maxKeypoints;
  4912. }
  4913. /**
  4914. * Maximum number of keypoints (optional)
  4915. * @param {number} value
  4916. */
  4917. set maxKeypoints(value)
  4918. {
  4919. if(!Number.isNaN(value))
  4920. this._maxKeypoints = Math.max(0, value | 0);
  4921. else
  4922. this._maxKeypoints = Number.NaN;
  4923. }
  4924. /**
  4925. * Run the specific task of this node
  4926. * @param {SpeedyGPU} gpu
  4927. * @returns {void|SpeedyPromise<void>}
  4928. */
  4929. _run(gpu)
  4930. {
  4931. let { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  4932. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  4933. const maxKeypoints = this._maxKeypoints;
  4934. // shuffle the keypoints (including nulls)
  4935. const permutationMaxLength = gpu.programs.keypoints.shuffle.definedConstant('PERMUTATION_MAXLEN');
  4936. const permutationLength = Math.min(permutationMaxLength, capacity);
  4937. const permutation = this._generatePermutation(permutationLength, permutationMaxLength);
  4938. encodedKeypoints = (gpu.programs.keypoints.shuffle
  4939. .setUBO('Permutation', permutation)
  4940. .outputs(encoderLength, encoderLength, this._tex[0])
  4941. )(encodedKeypoints, descriptorSize, extraSize, encoderLength);
  4942. // sort the keypoints
  4943. gpu.programs.keypoints.mixKeypointsInit.outputs(encoderLength, encoderLength, this._tex[1]);
  4944. gpu.programs.keypoints.mixKeypointsSort.outputs(encoderLength, encoderLength, this._tex[2], this._tex[3]);
  4945. gpu.programs.keypoints.mixKeypointsApply.outputs(encoderLength, encoderLength, this._tex[4]);
  4946. let sortedKeypoints = gpu.programs.keypoints.mixKeypointsInit(
  4947. encodedKeypoints, descriptorSize, extraSize, encoderLength, capacity
  4948. );
  4949. for(let b = 1; b < capacity; b *= 2)
  4950. sortedKeypoints = gpu.programs.keypoints.mixKeypointsSort(sortedKeypoints, b);
  4951. encodedKeypoints = gpu.programs.keypoints.mixKeypointsApply(
  4952. sortedKeypoints, encodedKeypoints, descriptorSize, extraSize, encoderLength
  4953. );
  4954. // clip the output?
  4955. if(!Number.isNaN(maxKeypoints) && maxKeypoints < capacity) {
  4956. const newEncoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderLength(maxKeypoints, descriptorSize, extraSize);
  4957. encodedKeypoints = (gpu.programs.keypoints.clip
  4958. .outputs(newEncoderLength, newEncoderLength, this._tex[5])
  4959. )(encodedKeypoints, descriptorSize, extraSize, encoderLength, maxKeypoints);
  4960. encoderLength = newEncoderLength;
  4961. }
  4962. // done!
  4963. this.output().swrite(encodedKeypoints, descriptorSize, extraSize, encoderLength);
  4964. }
  4965. /**
  4966. * Generate a permutation p of { 0, 1, ..., n-1 } such that p(p(x)) = x for all x
  4967. * @param {number} n positive integer
  4968. * @param {number} [bufsize] size of the output array
  4969. * @returns {Int32Array} permutation
  4970. */
  4971. _generatePermutation(n, bufsize = n)
  4972. {
  4973. const array = new Int32Array(bufsize);
  4974. const p = array.subarray(0, n).fill(-1);
  4975. const q = _utils_utils__WEBPACK_IMPORTED_MODULE_5__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_5__.Utils.range(n));
  4976. for(let i = 0, j = 0; i < n; i++) {
  4977. if(p[i] < 0) {
  4978. do { p[i] = q[j++]; } while(p[i] < i);
  4979. p[p[i]] = i;
  4980. }
  4981. }
  4982. return array; // padded with zeros
  4983. }
  4984. }
  4985. /***/ }),
  4986. /***/ "./src/core/pipeline/nodes/keypoints/sink.js":
  4987. /*!***************************************************!*\
  4988. !*** ./src/core/pipeline/nodes/keypoints/sink.js ***!
  4989. \***************************************************/
  4990. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_243606__) => {
  4991. "use strict";
  4992. __nested_webpack_require_243606__.r(__webpack_exports__);
  4993. /* harmony export */ __nested_webpack_require_243606__.d(__webpack_exports__, {
  4994. /* harmony export */ "SpeedyPipelineNodeKeypointSink": () => (/* binding */ SpeedyPipelineNodeKeypointSink),
  4995. /* harmony export */ "SpeedyPipelineNodeTrackedKeypointSink": () => (/* binding */ SpeedyPipelineNodeTrackedKeypointSink),
  4996. /* harmony export */ "SpeedyPipelineNodeMatchedKeypointSink": () => (/* binding */ SpeedyPipelineNodeMatchedKeypointSink)
  4997. /* harmony export */ });
  4998. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_243606__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  4999. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_243606__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  5000. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_243606__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  5001. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_243606__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  5002. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_243606__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  5003. /* harmony import */ var _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_243606__(/*! ../../../../gpu/speedy-texture-reader */ "./src/gpu/speedy-texture-reader.js");
  5004. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_243606__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  5005. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_243606__(/*! ../../../speedy-media */ "./src/core/speedy-media.js");
  5006. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_243606__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  5007. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_243606__(/*! ../../../../utils/types */ "./src/utils/types.js");
  5008. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_243606__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  5009. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_11__ = __nested_webpack_require_243606__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  5010. /* harmony import */ var _speedy_keypoint__WEBPACK_IMPORTED_MODULE_12__ = __nested_webpack_require_243606__(/*! ../../../speedy-keypoint */ "./src/core/speedy-keypoint.js");
  5011. /* harmony import */ var _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_13__ = __nested_webpack_require_243606__(/*! ../../../speedy-keypoint-descriptor */ "./src/core/speedy-keypoint-descriptor.js");
  5012. /* harmony import */ var _speedy_keypoint_match__WEBPACK_IMPORTED_MODULE_14__ = __nested_webpack_require_243606__(/*! ../../../speedy-keypoint-match */ "./src/core/speedy-keypoint-match.js");
  5013. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_15__ = __nested_webpack_require_243606__(/*! ../../../speedy-vector */ "./src/core/speedy-vector.js");
  5014. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_16__ = __nested_webpack_require_243606__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  5015. /*
  5016. * speedy-vision.js
  5017. * GPU-accelerated Computer Vision for JavaScript
  5018. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  5019. *
  5020. * Licensed under the Apache License, Version 2.0 (the "License");
  5021. * you may not use this file except in compliance with the License.
  5022. * You may obtain a copy of the License at
  5023. *
  5024. * http://www.apache.org/licenses/LICENSE-2.0
  5025. *
  5026. * Unless required by applicable law or agreed to in writing, software
  5027. * distributed under the License is distributed on an "AS IS" BASIS,
  5028. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5029. * See the License for the specific language governing permissions and
  5030. * limitations under the License.
  5031. *
  5032. * sink.js
  5033. * Gets keypoints out of the pipeline
  5034. */
  5035. /** next power of 2 */
  5036. const nextPot = x => x > 1 ? 1 << Math.ceil(Math.log2(x)) : 1;
  5037. /** empty array of bytes */
  5038. const ZERO_BYTES = new Uint8Array([]);
  5039. /**
  5040. * Gets keypoints out of the pipeline
  5041. * @template {SpeedyKeypoint} T
  5042. * @abstract
  5043. */
  5044. class SpeedyPipelineNodeAbstractKeypointSink extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSinkNode
  5045. {
  5046. /**
  5047. * Constructor
  5048. * @param {string} [name] name of the node
  5049. * @param {number} [texCount]
  5050. * @param {SpeedyPipelinePortBuilder[]} [portBuilders]
  5051. */
  5052. constructor(name = 'keypoints', texCount = 0, portBuilders = [])
  5053. {
  5054. super(name, texCount + 2, portBuilders);
  5055. /** @type {Array<T|null>} keypoints (output) */
  5056. this._keypoints = [];
  5057. /** @type {SpeedyTextureReader} texture reader */
  5058. this._textureReader = new _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_5__.SpeedyTextureReader();
  5059. /** @type {number} page flipping index */
  5060. this._page = 0;
  5061. /** @type {boolean} accelerate GPU-CPU transfers */
  5062. this._turbo = false;
  5063. /** @type {boolean} should discarded keypoints be exported as null or dropped altogether? */
  5064. this._includeDiscarded = false;
  5065. }
  5066. /**
  5067. * Accelerate GPU-CPU transfers
  5068. * @returns {boolean}
  5069. */
  5070. get turbo()
  5071. {
  5072. return this._turbo;
  5073. }
  5074. /**
  5075. * Accelerate GPU-CPU transfers
  5076. * @param {boolean} value
  5077. */
  5078. set turbo(value)
  5079. {
  5080. this._turbo = Boolean(value);
  5081. }
  5082. /**
  5083. * Should discarded keypoints be exported as null or dropped altogether?
  5084. * @returns {boolean}
  5085. */
  5086. get includeDiscarded()
  5087. {
  5088. return this._includeDiscarded;
  5089. }
  5090. /**
  5091. * Should discarded keypoints be exported as null or dropped altogether?
  5092. * @param {boolean} value
  5093. */
  5094. set includeDiscarded(value)
  5095. {
  5096. this._includeDiscarded = Boolean(value);
  5097. }
  5098. /**
  5099. * Initializes this node
  5100. * @param {SpeedyGPU} gpu
  5101. */
  5102. init(gpu)
  5103. {
  5104. super.init(gpu);
  5105. this._textureReader.init(gpu);
  5106. }
  5107. /**
  5108. * Releases this node
  5109. * @param {SpeedyGPU} gpu
  5110. */
  5111. release(gpu)
  5112. {
  5113. this._textureReader.release(gpu);
  5114. super.release(gpu);
  5115. }
  5116. /**
  5117. * Export data from this node to the user
  5118. * @returns {SpeedyPromise<Array<T|null>>}
  5119. */
  5120. export()
  5121. {
  5122. return _speedy_promise__WEBPACK_IMPORTED_MODULE_11__.SpeedyPromise.resolve(this._keypoints);
  5123. }
  5124. /**
  5125. * Run the specific task of this node
  5126. * @param {SpeedyGPU} gpu
  5127. * @returns {void|SpeedyPromise<void>}
  5128. */
  5129. _run(gpu)
  5130. {
  5131. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  5132. return this._download(gpu, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  5133. }
  5134. /**
  5135. * Download and decode keypoints from the GPU
  5136. * @param {SpeedyGPU} gpu
  5137. * @param {SpeedyDrawableTexture} encodedKeypoints
  5138. * @param {number} descriptorSize
  5139. * @param {number} extraSize
  5140. * @param {number} encoderLength
  5141. * @returns {SpeedyPromise<void>}
  5142. */
  5143. _download(gpu, encodedKeypoints, descriptorSize, extraSize, encoderLength)
  5144. {
  5145. const useBufferedDownloads = this._turbo;
  5146. /*
  5147. I have found experimentally that, in Firefox, readPixelsAsync()
  5148. performs MUCH better if the width of the target texture is a power
  5149. of two. I have no idea why this is the case, nor if it's related to
  5150. some interaction with the GL drivers, somehow. This seems to make no
  5151. difference on Chrome, however. In any case, let's convert the input
  5152. texture to POT.
  5153. */
  5154. const encoderWidth = nextPot(encoderLength);
  5155. //const encoderHeight = nextPot(Math.ceil(encoderLength * encoderLength / encoderWidth));
  5156. const encoderHeight = Math.ceil(encoderLength * encoderLength / encoderWidth);
  5157. //const encoderWidth=encoderLength,encoderHeight=encoderLength;
  5158. // copy the set of keypoints to an internal texture
  5159. const copiedTexture = this._tex[(this._tex.length - 1) - this._page];
  5160. (gpu.programs.utils.copyKeypoints
  5161. .outputs(encoderWidth, encoderHeight, copiedTexture)
  5162. )(encodedKeypoints);
  5163. // flip page
  5164. this._page = 1 - this._page;
  5165. // download the internal texture
  5166. return this._textureReader.readPixelsAsync(copiedTexture, 0, 0, copiedTexture.width, copiedTexture.height, useBufferedDownloads).then(pixels => {
  5167. // decode the keypoints and store them in this._keypoints
  5168. this._keypoints = this._decode(pixels, descriptorSize, extraSize, encoderWidth, encoderHeight);
  5169. });
  5170. }
  5171. /**
  5172. * Decode a sequence of keypoints, given a flattened image of encoded pixels
  5173. * @param {Uint8Array} pixels pixels in the [r,g,b,a,...] format
  5174. * @param {number} descriptorSize in bytes
  5175. * @param {number} extraSize in bytes
  5176. * @param {number} encoderWidth
  5177. * @param {number} encoderHeight
  5178. * @returns {Array<T|null>} keypoints
  5179. */
  5180. _decode(pixels, descriptorSize, extraSize, encoderWidth, encoderHeight)
  5181. {
  5182. const bytesPerKeypoint = _utils_globals__WEBPACK_IMPORTED_MODULE_16__.MIN_KEYPOINT_SIZE + descriptorSize + extraSize;
  5183. const m = _utils_globals__WEBPACK_IMPORTED_MODULE_16__.LOG2_PYRAMID_MAX_SCALE, h = _utils_globals__WEBPACK_IMPORTED_MODULE_16__.PYRAMID_MAX_LEVELS;
  5184. const piOver255 = Math.PI / 255.0;
  5185. const keypoints = /** @type {Array<T|null>} */ ( [] );
  5186. const includeDiscarded = this._includeDiscarded;
  5187. let descriptorBytes = ZERO_BYTES, extraBytes = ZERO_BYTES;
  5188. let x, y, z, w, lod, rotation, score;
  5189. let keypoint;
  5190. // validate
  5191. if(descriptorSize % 4 != 0 || extraSize % 4 != 0)
  5192. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_10__.IllegalArgumentError(`Invalid descriptorSize (${descriptorSize}) / extraSize (${extraSize})`);
  5193. // how many bytes should we read?
  5194. const e2 = encoderWidth * encoderHeight * 4;
  5195. const size = pixels.byteLength;
  5196. if(size != e2)
  5197. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.warning(`Expected ${e2} bytes when decoding a set of keypoints, found ${size}`);
  5198. // copy the data (we use shared buffers when receiving pixels[])
  5199. if(descriptorSize + extraSize > 0)
  5200. pixels = new Uint8Array(pixels);
  5201. // for each encoded keypoint
  5202. for(let i = 0; i < size; i += bytesPerKeypoint) {
  5203. // extract encoded header
  5204. x = (pixels[i+1] << 8) | pixels[i];
  5205. y = (pixels[i+3] << 8) | pixels[i+2];
  5206. z = (pixels[i+5] << 8) | pixels[i+4];
  5207. w = (pixels[i+7] << 8) | pixels[i+6];
  5208. // the keypoint is "null": we have reached the end of the list
  5209. if(x == 0xFFFF && y == 0xFFFF)
  5210. break;
  5211. // the header is zero: discard the keypoint
  5212. if(x + y + z + w == 0) {
  5213. if(includeDiscarded)
  5214. keypoints.push(null);
  5215. continue;
  5216. }
  5217. // extract extra & descriptor bytes
  5218. if(extraSize > 0) {
  5219. extraBytes = pixels.subarray(8 + i, 8 + i + extraSize);
  5220. if(extraBytes.byteLength < extraSize) {
  5221. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.warning(`KeypointSink: expected ${extraSize} extra bytes when decoding the ${i/bytesPerKeypoint}-th keypoint, found ${extraBytes.byteLength} instead`);
  5222. continue; // something is off here; discard
  5223. }
  5224. }
  5225. if(descriptorSize > 0) {
  5226. descriptorBytes = pixels.subarray(8 + i + extraSize, 8 + i + extraSize + descriptorSize);
  5227. if(descriptorBytes.byteLength < descriptorSize) {
  5228. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.warning(`KeypointSink: expected ${descriptorSize} descriptor bytes when decoding the ${i/bytesPerKeypoint}-th keypoint, found ${descriptorBytes.byteLength} instead`);
  5229. continue; // something is off here; discard
  5230. }
  5231. }
  5232. // decode position: convert from fixed-point
  5233. x /= _utils_globals__WEBPACK_IMPORTED_MODULE_16__.FIX_RESOLUTION;
  5234. y /= _utils_globals__WEBPACK_IMPORTED_MODULE_16__.FIX_RESOLUTION;
  5235. // decode level-of-detail
  5236. lod = (pixels[i+4] < 255) ? -m + ((m + h) * pixels[i+4]) / 255.0 : 0.0;
  5237. // decode orientation
  5238. rotation = (2 * pixels[i+5] - 255) * piOver255;
  5239. // decode score
  5240. score = _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.decodeFloat16(w);
  5241. // create keypoint
  5242. keypoint = this._createKeypoint(x, y, lod, rotation, score, descriptorBytes, extraBytes);
  5243. // register keypoint
  5244. keypoints.push(keypoint);
  5245. }
  5246. // done!
  5247. return keypoints;
  5248. }
  5249. /**
  5250. * Instantiate a new keypoint
  5251. * @param {number} x
  5252. * @param {number} y
  5253. * @param {number} lod
  5254. * @param {number} rotation
  5255. * @param {number} score
  5256. * @param {Uint8Array} descriptorBytes
  5257. * @param {Uint8Array} extraBytes
  5258. * @returns {T}
  5259. */
  5260. _createKeypoint(x, y, lod, rotation, score, descriptorBytes, extraBytes)
  5261. {
  5262. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_10__.AbstractMethodError();
  5263. }
  5264. /**
  5265. * Allocate extra soace
  5266. * @param {SpeedyGPU} gpu
  5267. * @param {SpeedyDrawableTexture} output output texture
  5268. * @param {SpeedyTexture} inputEncodedKeypoints input with no extra space
  5269. * @param {number} inputDescriptorSize in bytes, must be positive
  5270. * @param {number} inputExtraSize must be 0
  5271. * @param {number} outputDescriptorSize must be inputDescriptorSize
  5272. * @param {number} outputExtraSize in bytes, must be positive and a multiple of 4
  5273. * @returns {SpeedyDrawableTexture} encodedKeypoints with extra space
  5274. */
  5275. _allocateExtra(gpu, output, inputEncodedKeypoints, inputDescriptorSize, inputExtraSize, outputDescriptorSize, outputExtraSize)
  5276. {
  5277. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(inputExtraSize === 0);
  5278. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(outputDescriptorSize === inputDescriptorSize && outputExtraSize > 0 && outputExtraSize % 4 === 0);
  5279. const inputEncoderLength = inputEncodedKeypoints.width;
  5280. const inputEncoderCapacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(inputDescriptorSize, inputExtraSize, inputEncoderLength);
  5281. const outputEncoderCapacity = inputEncoderCapacity;
  5282. const outputEncoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderLength(outputEncoderCapacity, outputDescriptorSize, outputExtraSize);
  5283. return (gpu.programs.keypoints.allocateExtra
  5284. .outputs(outputEncoderLength, outputEncoderLength, output)
  5285. )(inputEncodedKeypoints, inputDescriptorSize, inputExtraSize, inputEncoderLength, outputDescriptorSize, outputExtraSize, outputEncoderLength);
  5286. }
  5287. }
  5288. /**
  5289. * Gets standard keypoints out of the pipeline
  5290. * @extends {SpeedyPipelineNodeAbstractKeypointSink<SpeedyKeypoint>}
  5291. */
  5292. class SpeedyPipelineNodeKeypointSink extends SpeedyPipelineNodeAbstractKeypointSink
  5293. {
  5294. /**
  5295. * Constructor
  5296. * @param {string} [name] name of the node
  5297. */
  5298. constructor(name = 'keypoints')
  5299. {
  5300. super(name, 0, [
  5301. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  5302. ]);
  5303. }
  5304. /**
  5305. * Instantiate a new keypoint
  5306. * @param {number} x
  5307. * @param {number} y
  5308. * @param {number} lod
  5309. * @param {number} rotation
  5310. * @param {number} score
  5311. * @param {Uint8Array} descriptorBytes
  5312. * @param {Uint8Array} extraBytes
  5313. * @returns {SpeedyKeypoint}
  5314. */
  5315. _createKeypoint(x, y, lod, rotation, score, descriptorBytes, extraBytes)
  5316. {
  5317. const descriptorSize = descriptorBytes.byteLength;
  5318. // read descriptor, if any
  5319. const descriptor = descriptorSize > 0 ? new _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_13__.SpeedyKeypointDescriptor(descriptorBytes) : null;
  5320. // create keypoint
  5321. return new _speedy_keypoint__WEBPACK_IMPORTED_MODULE_12__.SpeedyKeypoint(x, y, lod, rotation, score, descriptor);
  5322. }
  5323. }
  5324. /**
  5325. * Gets tracked keypoints out of the pipeline
  5326. * @extends {SpeedyPipelineNodeAbstractKeypointSink<SpeedyTrackedKeypoint>}
  5327. */
  5328. class SpeedyPipelineNodeTrackedKeypointSink extends SpeedyPipelineNodeAbstractKeypointSink
  5329. {
  5330. /**
  5331. * Constructor
  5332. * @param {string} [name] name of the node
  5333. */
  5334. constructor(name = 'keypoints')
  5335. {
  5336. super(name, 2, [
  5337. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints).satisfying(
  5338. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  5339. msg.extraSize == 0
  5340. ),
  5341. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('flow').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Vector2)
  5342. ]);
  5343. }
  5344. /**
  5345. * Run the specific task of this node
  5346. * @param {SpeedyGPU} gpu
  5347. * @returns {void|SpeedyPromise<void>}
  5348. */
  5349. _run(gpu)
  5350. {
  5351. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  5352. const { vectors } = /** @type {SpeedyPipelineMessageWith2DVectors} */ ( this.input('flow').read() );
  5353. // allocate extra space
  5354. const newDescriptorSize = descriptorSize;
  5355. const newExtraSize = 4; // 1 pixel per flow vector per keypoint
  5356. const encodedKeypointsWithExtraSpace = this._allocateExtra(gpu, this._tex[0], encodedKeypoints, descriptorSize, extraSize, newDescriptorSize, newExtraSize);
  5357. // attach flow vectors
  5358. const newEncoderLength = encodedKeypointsWithExtraSpace.width;
  5359. const newEncodedKeypoints = (gpu.programs.keypoints.transferToExtra
  5360. .outputs(newEncoderLength, newEncoderLength, this._tex[1])
  5361. )(vectors, vectors.width, encodedKeypointsWithExtraSpace, newDescriptorSize, newExtraSize, newEncoderLength);
  5362. // done!
  5363. return this._download(gpu, newEncodedKeypoints, newDescriptorSize, newExtraSize, newEncoderLength);
  5364. }
  5365. /**
  5366. * Instantiate a new keypoint
  5367. * @param {number} x
  5368. * @param {number} y
  5369. * @param {number} lod
  5370. * @param {number} rotation
  5371. * @param {number} score
  5372. * @param {Uint8Array} descriptorBytes
  5373. * @param {Uint8Array} extraBytes
  5374. * @returns {SpeedyTrackedKeypoint}
  5375. */
  5376. _createKeypoint(x, y, lod, rotation, score, descriptorBytes, extraBytes)
  5377. {
  5378. const descriptorSize = descriptorBytes.byteLength;
  5379. const extraSize = extraBytes.byteLength;
  5380. // read descriptor, if any
  5381. const descriptor = descriptorSize > 0 ? new _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_13__.SpeedyKeypointDescriptor(descriptorBytes) : null;
  5382. // read flow vector
  5383. const fx = _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.decodeFloat16((extraBytes[1] << 8) | extraBytes[0]);
  5384. const fy = _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.decodeFloat16((extraBytes[3] << 8) | extraBytes[2]);
  5385. const flow = new _speedy_vector__WEBPACK_IMPORTED_MODULE_15__.SpeedyVector2(fx, fy);
  5386. // create keypoint
  5387. return new _speedy_keypoint__WEBPACK_IMPORTED_MODULE_12__.SpeedyTrackedKeypoint(x, y, lod, rotation, score, descriptor, flow);
  5388. }
  5389. }
  5390. /**
  5391. * Gets matched keypoints out of the pipeline
  5392. * @extends SpeedyPipelineNodeAbstractKeypointSink<SpeedyMatchedKeypoint>
  5393. */
  5394. class SpeedyPipelineNodeMatchedKeypointSink extends SpeedyPipelineNodeAbstractKeypointSink
  5395. {
  5396. /**
  5397. * Constructor
  5398. * @param {string} [name] name of the node
  5399. */
  5400. constructor(name = 'keypoints')
  5401. {
  5402. super(name, 2, [
  5403. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints).satisfying(
  5404. ( /** @type {SpeedyPipelineMessageWithKeypoints} */ msg ) =>
  5405. msg.extraSize == 0
  5406. ),
  5407. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('matches').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.KeypointMatches)
  5408. ]);
  5409. }
  5410. /**
  5411. * Run the specific task of this node
  5412. * @param {SpeedyGPU} gpu
  5413. * @returns {void|SpeedyPromise<void>}
  5414. */
  5415. _run(gpu)
  5416. {
  5417. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  5418. const { encodedMatches, matchesPerKeypoint } = /** @type {SpeedyPipelineMessageWithKeypointMatches} */ ( this.input('matches').read() );
  5419. // allocate space for the matches
  5420. const newDescriptorSize = descriptorSize;
  5421. const newExtraSize = matchesPerKeypoint * 4; // 4 bytes per pixel
  5422. const encodedKeypointsWithExtraSpace = this._allocateExtra(gpu, this._tex[0], encodedKeypoints, descriptorSize, extraSize, newDescriptorSize, newExtraSize);
  5423. // transfer matches to a new texture
  5424. const newEncoderLength = encodedKeypointsWithExtraSpace.width;
  5425. const newEncodedKeypoints = (gpu.programs.keypoints.transferToExtra
  5426. .outputs(newEncoderLength, newEncoderLength, this._tex[1])
  5427. )(encodedMatches, encodedMatches.width, encodedKeypointsWithExtraSpace, newDescriptorSize, newExtraSize, newEncoderLength);
  5428. // done!
  5429. return this._download(gpu, newEncodedKeypoints, newDescriptorSize, newExtraSize, newEncoderLength);
  5430. }
  5431. /**
  5432. * Instantiate a new keypoint
  5433. * @param {number} x
  5434. * @param {number} y
  5435. * @param {number} lod
  5436. * @param {number} rotation
  5437. * @param {number} score
  5438. * @param {Uint8Array} descriptorBytes
  5439. * @param {Uint8Array} extraBytes
  5440. * @returns {SpeedyMatchedKeypoint}
  5441. */
  5442. _createKeypoint(x, y, lod, rotation, score, descriptorBytes, extraBytes)
  5443. {
  5444. const descriptorSize = descriptorBytes.byteLength;
  5445. const extraSize = extraBytes.byteLength;
  5446. // read descriptor, if any
  5447. const descriptor = descriptorSize > 0 ? new _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_13__.SpeedyKeypointDescriptor(descriptorBytes) : null;
  5448. // decode matches
  5449. const matchesPerKeypoint = extraSize / 4;
  5450. const matches = /** @type {SpeedyKeypointMatch[]} */ ( new Array(matchesPerKeypoint) );
  5451. for(let matchIndex = 0; matchIndex < matchesPerKeypoint; matchIndex++) {
  5452. const base = matchIndex * 4;
  5453. const u32 = extraBytes[base] | (extraBytes[base+1] << 8) | (extraBytes[base+2] << 16) | (extraBytes[base+3] << 24);
  5454. const match = new _speedy_keypoint_match__WEBPACK_IMPORTED_MODULE_14__.SpeedyKeypointMatch(u32 & _utils_globals__WEBPACK_IMPORTED_MODULE_16__.MATCH_INDEX_MASK, u32 >>> _utils_globals__WEBPACK_IMPORTED_MODULE_16__.MATCH_INDEX_BITS);
  5455. matches[matchIndex] = match;
  5456. }
  5457. // done!
  5458. return new _speedy_keypoint__WEBPACK_IMPORTED_MODULE_12__.SpeedyMatchedKeypoint(x, y, lod, rotation, score, descriptor, matches);
  5459. }
  5460. }
  5461. /***/ }),
  5462. /***/ "./src/core/pipeline/nodes/keypoints/source.js":
  5463. /*!*****************************************************!*\
  5464. !*** ./src/core/pipeline/nodes/keypoints/source.js ***!
  5465. \*****************************************************/
  5466. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_267803__) => {
  5467. "use strict";
  5468. __nested_webpack_require_267803__.r(__webpack_exports__);
  5469. /* harmony export */ __nested_webpack_require_267803__.d(__webpack_exports__, {
  5470. /* harmony export */ "SpeedyPipelineNodeKeypointSource": () => (/* binding */ SpeedyPipelineNodeKeypointSource)
  5471. /* harmony export */ });
  5472. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_267803__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  5473. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_267803__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  5474. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_267803__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  5475. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_267803__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  5476. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_267803__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  5477. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_267803__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  5478. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_267803__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  5479. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_267803__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  5480. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_267803__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  5481. /* harmony import */ var _speedy_keypoint__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_267803__(/*! ../../../speedy-keypoint */ "./src/core/speedy-keypoint.js");
  5482. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_267803__(/*! ../../../../utils/globals */ "./src/utils/globals.js");
  5483. /*
  5484. * speedy-vision.js
  5485. * GPU-accelerated Computer Vision for JavaScript
  5486. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  5487. *
  5488. * Licensed under the Apache License, Version 2.0 (the "License");
  5489. * you may not use this file except in compliance with the License.
  5490. * You may obtain a copy of the License at
  5491. *
  5492. * http://www.apache.org/licenses/LICENSE-2.0
  5493. *
  5494. * Unless required by applicable law or agreed to in writing, software
  5495. * distributed under the License is distributed on an "AS IS" BASIS,
  5496. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5497. * See the License for the specific language governing permissions and
  5498. * limitations under the License.
  5499. *
  5500. * source.js
  5501. * Gets keypoints into the pipeline
  5502. */
  5503. // Constants
  5504. const UBO_MAX_BYTES = 16384; // UBOs can hold at least 16KB of data: gl.MAX_UNIFORM_BLOCK_SIZE >= 16384 according to the GL ES 3 reference
  5505. const BUFFER_SIZE = 1024; // how many keypoints we can upload in one pass of the shader (as defined in the shader program)
  5506. const SIZEOF_VEC4 = Float32Array.BYTES_PER_ELEMENT * 4; // 16 bytes
  5507. /**
  5508. * Gets keypoints into the pipeline
  5509. */
  5510. class SpeedyPipelineNodeKeypointSource extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSourceNode
  5511. {
  5512. /**
  5513. * Constructor
  5514. * @param {string} [name] name of the node
  5515. */
  5516. constructor(name = undefined)
  5517. {
  5518. super(name, 2, [
  5519. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints)
  5520. ]);
  5521. /** @type {SpeedyKeypoint[]} keypoints to be uploaded to the GPU */
  5522. this._keypoints = [];
  5523. /** @type {Float32Array} upload buffer (UBO) */
  5524. this._buffer = SpeedyPipelineNodeKeypointSource._createUploadBuffer(BUFFER_SIZE);
  5525. /** @type {number} maximum number of keypoints */
  5526. this._capacity = _utils_globals__WEBPACK_IMPORTED_MODULE_10__.DEFAULT_ENCODER_CAPACITY;
  5527. }
  5528. /**
  5529. * Keypoints to be uploaded
  5530. * @returns {SpeedyKeypoint[]}
  5531. */
  5532. get keypoints()
  5533. {
  5534. return this._keypoints;
  5535. }
  5536. /**
  5537. * Keypoints to be uploaded
  5538. * @param {SpeedyKeypoint[]} keypoints
  5539. */
  5540. set keypoints(keypoints)
  5541. {
  5542. if(!Array.isArray(keypoints))
  5543. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_7__.IllegalArgumentError(`Not an array of keypoints`);
  5544. this._keypoints = keypoints;
  5545. }
  5546. /**
  5547. * The maximum number of keypoints we'll accept.
  5548. * This should be a tight bound for better performance.
  5549. * @returns {number}
  5550. */
  5551. get capacity()
  5552. {
  5553. return this._capacity;
  5554. }
  5555. /**
  5556. * The maximum number of keypoints we'll accept.
  5557. * This should be a tight bound for better performance.
  5558. * @param {number} capacity
  5559. */
  5560. set capacity(capacity)
  5561. {
  5562. this._capacity = Math.min(Math.max(0, capacity | 0), _utils_globals__WEBPACK_IMPORTED_MODULE_10__.MAX_ENCODER_CAPACITY);
  5563. }
  5564. /**
  5565. * Run the specific task of this node
  5566. * @param {SpeedyGPU} gpu
  5567. * @returns {void|SpeedyPromise<void>}
  5568. */
  5569. _run(gpu)
  5570. {
  5571. // Orientation, descriptors and extra bytes will be lost
  5572. const descriptorSize = 0, extraSize = 0;
  5573. const keypoints = this._keypoints;
  5574. const maxKeypoints = this._capacity;
  5575. const numKeypoints = Math.min(keypoints.length, maxKeypoints);
  5576. const numPasses = Math.max(1, Math.ceil(numKeypoints / BUFFER_SIZE));
  5577. const buffer = this._buffer;
  5578. const uploadKeypoints = gpu.programs.keypoints.uploadKeypoints;
  5579. const encoderLength = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderLength(maxKeypoints, descriptorSize, extraSize); // we're using maxKeypoints to avoid constant texture resize (slow on Firefox)
  5580. uploadKeypoints.outputs(encoderLength, encoderLength, this._tex[0], this._tex[1]);
  5581. let startIndex = 0, encodedKeypoints = uploadKeypoints.clear();
  5582. for(let i = 0; i < numPasses; i++) {
  5583. const n = Math.min(BUFFER_SIZE, numKeypoints - startIndex);
  5584. const endIndex = startIndex + n;
  5585. uploadKeypoints.setUBO('KeypointBuffer', SpeedyPipelineNodeKeypointSource._fillUploadBuffer(buffer, keypoints, startIndex, endIndex));
  5586. encodedKeypoints = uploadKeypoints(encodedKeypoints, startIndex, endIndex, descriptorSize, extraSize, encoderLength);
  5587. startIndex = endIndex;
  5588. }
  5589. this.output().swrite(encodedKeypoints, descriptorSize, extraSize, encoderLength);
  5590. }
  5591. /**
  5592. * Create an upload buffer
  5593. * @param {number} bufferSize number of keypoints
  5594. * @returns {Float32Array}
  5595. */
  5596. static _createUploadBuffer(bufferSize)
  5597. {
  5598. const internalBuffer = new ArrayBuffer(SIZEOF_VEC4 * bufferSize);
  5599. _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.assert(internalBuffer.byteLength <= UBO_MAX_BYTES);
  5600. return new Float32Array(internalBuffer);
  5601. }
  5602. /**
  5603. * Fill upload buffer with keypoint data
  5604. * @param {Float32Array} buffer
  5605. * @param {SpeedyKeypoint[]} keypoints
  5606. * @param {number} start index, inclusive
  5607. * @param {number} end index, exclusive
  5608. * @returns {Float32Array} buffer
  5609. */
  5610. static _fillUploadBuffer(buffer, keypoints, start, end)
  5611. {
  5612. const n = end - start;
  5613. for(let i = 0; i < n; i++) {
  5614. const keypoint = keypoints[start + i];
  5615. const hasPos = keypoint.position !== undefined;
  5616. const j = i * 4;
  5617. // Format data as follows:
  5618. // vec4(xpos, ypos, lod, score)
  5619. buffer[j] = +(hasPos ? keypoint.position.x : keypoint.x) || 0;
  5620. buffer[j+1] = +(hasPos ? keypoint.position.y : keypoint.y) || 0;
  5621. buffer[j+2] = +(keypoint.lod) || 0;
  5622. buffer[j+3] = +(keypoint.score) || 0;
  5623. }
  5624. // done!
  5625. return buffer;
  5626. }
  5627. }
  5628. /***/ }),
  5629. /***/ "./src/core/pipeline/nodes/keypoints/subpixel.js":
  5630. /*!*******************************************************!*\
  5631. !*** ./src/core/pipeline/nodes/keypoints/subpixel.js ***!
  5632. \*******************************************************/
  5633. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_276177__) => {
  5634. "use strict";
  5635. __nested_webpack_require_276177__.r(__webpack_exports__);
  5636. /* harmony export */ __nested_webpack_require_276177__.d(__webpack_exports__, {
  5637. /* harmony export */ "SpeedyPipelineNodeKeypointSubpixelRefiner": () => (/* binding */ SpeedyPipelineNodeKeypointSubpixelRefiner)
  5638. /* harmony export */ });
  5639. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_276177__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  5640. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_276177__(/*! ./detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  5641. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_276177__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  5642. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_276177__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  5643. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_276177__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  5644. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_276177__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  5645. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_276177__(/*! ../../../../utils/types */ "./src/utils/types.js");
  5646. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_276177__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  5647. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_276177__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  5648. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_276177__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  5649. /*
  5650. * speedy-vision.js
  5651. * GPU-accelerated Computer Vision for JavaScript
  5652. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  5653. *
  5654. * Licensed under the Apache License, Version 2.0 (the "License");
  5655. * you may not use this file except in compliance with the License.
  5656. * You may obtain a copy of the License at
  5657. *
  5658. * http://www.apache.org/licenses/LICENSE-2.0
  5659. *
  5660. * Unless required by applicable law or agreed to in writing, software
  5661. * distributed under the License is distributed on an "AS IS" BASIS,
  5662. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5663. * See the License for the specific language governing permissions and
  5664. * limitations under the License.
  5665. *
  5666. * subpixel.js
  5667. * Subpixel refinement of keypoint location
  5668. */
  5669. /** @typedef {"quadratic1d"|"taylor2d"|"bicubic-upsample"|"bilinear-upsample"} SubpixelRefinementMethod */
  5670. /** @const {Object<SubpixelRefinementMethod,string>} method name to program name */
  5671. const METHOD2PROGRAM = Object.freeze({
  5672. 'quadratic1d': 'subpixelQuadratic1d',
  5673. 'taylor2d': 'subpixelTaylor2d',
  5674. 'bicubic-upsample': 'subpixelBicubic',
  5675. 'bilinear-upsample': 'subpixelBilinear',
  5676. });
  5677. /**
  5678. * Subpixel refinement of keypoint location
  5679. */
  5680. class SpeedyPipelineNodeKeypointSubpixelRefiner extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  5681. {
  5682. /**
  5683. * Constructor
  5684. * @param {string} [name] name of the node
  5685. */
  5686. constructor(name = undefined)
  5687. {
  5688. super(name, 2, [
  5689. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('image').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Image).satisfying(
  5690. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  5691. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_6__.ImageFormat.GREY
  5692. ),
  5693. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('keypoints').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  5694. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  5695. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)('displacements').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Vector2),
  5696. ]);
  5697. /** @type {SubpixelRefinementMethod} subpixel refinement method */
  5698. this._method = 'quadratic1d';
  5699. /** @type {number} max iterations for the upsampling methods */
  5700. this._maxIterations = 6;
  5701. /** @type {number} convergence threshold for the upsampling methods */
  5702. this._epsilon = 0.1;
  5703. }
  5704. /**
  5705. * Subpixel refinement method
  5706. * @returns {SubpixelRefinementMethod}
  5707. */
  5708. get method()
  5709. {
  5710. return this._method;
  5711. }
  5712. /**
  5713. * Subpixel refinement method
  5714. * @param {SubpixelRefinementMethod} name
  5715. */
  5716. set method(name)
  5717. {
  5718. if(!Object.prototype.hasOwnProperty.call(METHOD2PROGRAM, name))
  5719. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Invalid method: "${name}"`);
  5720. this._method = name;
  5721. }
  5722. /**
  5723. * Max. iterations for the upsampling methods
  5724. * @returns {number}
  5725. */
  5726. get maxIterations()
  5727. {
  5728. return this._maxIterations;
  5729. }
  5730. /**
  5731. * Max. iterations for the upsampling methods
  5732. * @param {number} value
  5733. */
  5734. set maxIterations(value)
  5735. {
  5736. this._maxIterations = Math.max(0, +value);
  5737. }
  5738. /**
  5739. * Convergence threshold for the upsampling methods
  5740. * @returns {number}
  5741. */
  5742. get epsilon()
  5743. {
  5744. return this._epsilon;
  5745. }
  5746. /**
  5747. * Convergence threshold for the upsampling methods
  5748. * @param {number} value
  5749. */
  5750. set epsilon(value)
  5751. {
  5752. this._epsilon = Math.max(0, +value);
  5753. }
  5754. /**
  5755. * Run the specific task of this node
  5756. * @param {SpeedyGPU} gpu
  5757. * @returns {void|SpeedyPromise<void>}
  5758. */
  5759. _run(gpu)
  5760. {
  5761. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('keypoints').read() );
  5762. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('image').read() );
  5763. const tex = this._tex;
  5764. const program = METHOD2PROGRAM[this._method];
  5765. const maxIterations = this._maxIterations;
  5766. const epsilon = this._epsilon;
  5767. // note: if you detected the keypoints using a pyramid,
  5768. // you need to pass that pyramid as input!
  5769. // we'll compute the offsets for each keypoint
  5770. const capacity = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  5771. const offsetEncoderLength = Math.max(1, Math.ceil(Math.sqrt(capacity))); // 1 pixel per refinement offset
  5772. const offsets = (gpu.programs.keypoints[program]
  5773. .outputs(offsetEncoderLength, offsetEncoderLength, tex[0])
  5774. )(image, encodedKeypoints, descriptorSize, extraSize, encoderLength, maxIterations, epsilon);
  5775. // apply the offsets to the keypoints
  5776. const refinedKeypoints = (gpu.programs.keypoints.transferFlow
  5777. .outputs(encoderLength, encoderLength, tex[1])
  5778. )(offsets, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  5779. // done!
  5780. this.output().swrite(refinedKeypoints, descriptorSize, extraSize, encoderLength);
  5781. this.output('displacements').swrite(offsets);
  5782. }
  5783. }
  5784. /***/ }),
  5785. /***/ "./src/core/pipeline/nodes/keypoints/trackers/lk.js":
  5786. /*!**********************************************************!*\
  5787. !*** ./src/core/pipeline/nodes/keypoints/trackers/lk.js ***!
  5788. \**********************************************************/
  5789. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_284074__) => {
  5790. "use strict";
  5791. __nested_webpack_require_284074__.r(__webpack_exports__);
  5792. /* harmony export */ __nested_webpack_require_284074__.d(__webpack_exports__, {
  5793. /* harmony export */ "SpeedyPipelineNodeLKKeypointTracker": () => (/* binding */ SpeedyPipelineNodeLKKeypointTracker)
  5794. /* harmony export */ });
  5795. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_284074__(/*! ../../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  5796. /* harmony import */ var _detectors_detector__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_284074__(/*! ../detectors/detector */ "./src/core/pipeline/nodes/keypoints/detectors/detector.js");
  5797. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_284074__(/*! ../../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  5798. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_284074__(/*! ../../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  5799. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_284074__(/*! ../../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  5800. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_284074__(/*! ../../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  5801. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_284074__(/*! ../../../../../utils/types */ "./src/utils/types.js");
  5802. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_284074__(/*! ../../../../speedy-size */ "./src/core/speedy-size.js");
  5803. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_284074__(/*! ../../../../../utils/utils */ "./src/utils/utils.js");
  5804. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_284074__(/*! ../../../../../utils/errors */ "./src/utils/errors.js");
  5805. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_284074__(/*! ../../../../speedy-promise */ "./src/core/speedy-promise.js");
  5806. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_11__ = __nested_webpack_require_284074__(/*! ../../../../../utils/globals */ "./src/utils/globals.js");
  5807. /*
  5808. * speedy-vision.js
  5809. * GPU-accelerated Computer Vision for JavaScript
  5810. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  5811. *
  5812. * Licensed under the Apache License, Version 2.0 (the "License");
  5813. * you may not use this file except in compliance with the License.
  5814. * You may obtain a copy of the License at
  5815. *
  5816. * http://www.apache.org/licenses/LICENSE-2.0
  5817. *
  5818. * Unless required by applicable law or agreed to in writing, software
  5819. * distributed under the License is distributed on an "AS IS" BASIS,
  5820. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  5821. * See the License for the specific language governing permissions and
  5822. * limitations under the License.
  5823. *
  5824. * lk.js
  5825. * LK optical-flow
  5826. */
  5827. // Constants
  5828. const DEFAULT_WINDOW_SIZE = new _speedy_size__WEBPACK_IMPORTED_MODULE_7__.SpeedySize(11, 11); // nice on mobile?
  5829. const DEFAULT_DEPTH = Math.min(3, _utils_globals__WEBPACK_IMPORTED_MODULE_11__.PYRAMID_MAX_LEVELS);
  5830. const DEFAULT_NUMBER_OF_ITERATIONS = 30;
  5831. const DEFAULT_DISCARD_THRESHOLD = 0.0001;
  5832. const DEFAULT_EPSILON = 0.01;
  5833. const LK_PROGRAM = {
  5834. 3: 'lk3',
  5835. 5: 'lk5',
  5836. 7: 'lk7',
  5837. 9: 'lk9',
  5838. 11: 'lk11',
  5839. 13: 'lk13',
  5840. 15: 'lk15',
  5841. 17: 'lk17',
  5842. 19: 'lk19',
  5843. 21: 'lk21',
  5844. };
  5845. /**
  5846. * LK optical-flow
  5847. */
  5848. class SpeedyPipelineNodeLKKeypointTracker extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  5849. {
  5850. /**
  5851. * Constructor
  5852. * @param {string} [name] name of the node
  5853. */
  5854. constructor(name = undefined)
  5855. {
  5856. super(name, 3, [
  5857. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('previousImage').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Image).satisfying(
  5858. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  5859. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_6__.ImageFormat.GREY
  5860. ),
  5861. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('nextImage').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Image).satisfying(
  5862. ( /** @type {SpeedyPipelineMessageWithImage} */ msg ) =>
  5863. msg.format === _utils_types__WEBPACK_IMPORTED_MODULE_6__.ImageFormat.GREY
  5864. ),
  5865. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.InputPort)('previousKeypoints').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  5866. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Keypoints),
  5867. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_3__.OutputPort)('flow').expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelineMessageType.Vector2),
  5868. ]);
  5869. /** @type {SpeedySize} window size */
  5870. this._windowSize = DEFAULT_WINDOW_SIZE;
  5871. /** @type {number} number of pyramid levels to use */
  5872. this._levels = DEFAULT_DEPTH;
  5873. /** @type {number} minimum acceptable corner response */
  5874. this._discardThreshold = DEFAULT_DISCARD_THRESHOLD;
  5875. /** @type {number} number of iterations per pyramid level (termination criteria) */
  5876. this._numberOfIterations = DEFAULT_NUMBER_OF_ITERATIONS;
  5877. /** @type {number} minimum increment per iteration (termination criteria) */
  5878. this._epsilon = DEFAULT_EPSILON;
  5879. }
  5880. /**
  5881. * Window size (use odd numbers)
  5882. * @returns {SpeedySize}
  5883. */
  5884. get windowSize()
  5885. {
  5886. return this._windowSize;
  5887. }
  5888. /**
  5889. * Window size (use odd numbers)
  5890. * @param {SpeedySize} windowSize must be a square window
  5891. */
  5892. set windowSize(windowSize)
  5893. {
  5894. if(windowSize.width != windowSize.height) {
  5895. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_9__.NotSupportedError(`LK: window ${this._windowSize.toString()} is not square!`);
  5896. }
  5897. else if(!Object.prototype.hasOwnProperty.call(LK_PROGRAM, windowSize.width)) {
  5898. const SUPPORTED_WINDOWS = Object.keys(LK_PROGRAM).sort((a,b) => a-b).map(k => k+'x'+k).join(', ');
  5899. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_9__.NotSupportedError(`LK: window of size ${this._windowSize.toString()} is not supported! Supported sizes: ${SUPPORTED_WINDOWS}`);
  5900. }
  5901. this._windowSize = windowSize;
  5902. }
  5903. /**
  5904. * Number of pyramid levels to use
  5905. * @returns {number}
  5906. */
  5907. get levels()
  5908. {
  5909. return this._levels;
  5910. }
  5911. /**
  5912. * Number of pyramid levels to use
  5913. * @param {number} levels
  5914. */
  5915. set levels(levels)
  5916. {
  5917. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(levels >= 1 && levels <= _utils_globals__WEBPACK_IMPORTED_MODULE_11__.PYRAMID_MAX_LEVELS);
  5918. this._levels = levels | 0;
  5919. }
  5920. /**
  5921. * Get the discard threshold, used to discard "bad" keypoints
  5922. * @returns {number}
  5923. */
  5924. get discardThreshold()
  5925. {
  5926. return this._discardThreshold;
  5927. }
  5928. /**
  5929. * Set the discard threshold, used to discard "bad" keypoints
  5930. * @param {number} value typically 10^(-4) - increase to discard more
  5931. */
  5932. set discardThreshold(value)
  5933. {
  5934. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(value >= 0);
  5935. this._discardThreshold = +value;
  5936. }
  5937. /**
  5938. * Get the maximum number of iterations of the pyramidal LK algorithm
  5939. * @returns {number}
  5940. */
  5941. get numberOfIterations()
  5942. {
  5943. return this._numberOfIterations;
  5944. }
  5945. /**
  5946. * Set the maximum number of iterations of the pyramidal LK algorithm
  5947. * @param {number} value
  5948. */
  5949. set numberOfIterations(value)
  5950. {
  5951. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(value >= 1);
  5952. this._numberOfIterations = value | 0;
  5953. }
  5954. /**
  5955. * Get the accuracy threshold, used to stop LK iterations
  5956. * @returns {number}
  5957. */
  5958. get epsilon()
  5959. {
  5960. return this._epsilon;
  5961. }
  5962. /**
  5963. * Get the accuracy threshold, used to stop LK iterations
  5964. * @param {number} value typically 0.01
  5965. */
  5966. set epsilon(value)
  5967. {
  5968. _utils_utils__WEBPACK_IMPORTED_MODULE_8__.Utils.assert(value >= 0);
  5969. this._epsilon = +value;
  5970. }
  5971. /**
  5972. * Run the specific task of this node
  5973. * @param {SpeedyGPU} gpu
  5974. * @returns {void|SpeedyPromise<void>}
  5975. */
  5976. _run(gpu)
  5977. {
  5978. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input('previousKeypoints').read() );
  5979. const previousImage = ( /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('previousImage').read() )).image;
  5980. const nextImage = ( /** @type {SpeedyPipelineMessageWithImage} */ ( this.input('nextImage').read() )).image;
  5981. const previousKeypoints = encodedKeypoints;
  5982. const levels = this._levels;
  5983. const windowSize = this._windowSize;
  5984. const wsize = windowSize.width; // square window
  5985. const numberOfIterations = this._numberOfIterations;
  5986. const discardThreshold = this._discardThreshold;
  5987. const epsilon = this._epsilon;
  5988. const keypoints = gpu.programs.keypoints;
  5989. const tex = this._tex;
  5990. // do we need a pyramid?
  5991. if(!(levels == 1 || (previousImage.hasMipmaps() && nextImage.hasMipmaps())))
  5992. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_9__.IllegalOperationError(`LK: a pyramid is required if levels > 1`);
  5993. else if(previousImage.width !== nextImage.width || previousImage.height !== nextImage.height)
  5994. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_9__.IllegalOperationError(`LK: can't use input images of different size`);
  5995. // select the appropriate program
  5996. const lk = keypoints[LK_PROGRAM[wsize]];
  5997. // find the dimensions of the flow texture (1 pixel per flow vector)
  5998. const numKeypoints = _detectors_detector__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineNodeKeypointDetector.encoderCapacity(descriptorSize, extraSize, encoderLength);
  5999. const lkEncoderLength = Math.max(1, Math.ceil(Math.sqrt(numKeypoints)));
  6000. lk.outputs(lkEncoderLength, lkEncoderLength, tex[0], tex[1]);
  6001. // compute optical-flow
  6002. let flow = lk.clear();
  6003. for(let lod = levels - 1; lod >= 0; lod--)
  6004. flow = lk(flow, previousKeypoints, nextImage, previousImage, lod, levels, numberOfIterations, discardThreshold, epsilon, descriptorSize, extraSize, encoderLength);
  6005. // transfer optical-flow to nextKeypoints
  6006. keypoints.transferFlow.outputs(encoderLength, encoderLength, tex[2]);
  6007. const nextKeypoints = keypoints.transferFlow(flow, previousKeypoints, descriptorSize, extraSize, encoderLength);
  6008. // done!
  6009. this.output().swrite(nextKeypoints, descriptorSize, extraSize, encoderLength);
  6010. this.output('flow').swrite(flow);
  6011. }
  6012. }
  6013. /***/ }),
  6014. /***/ "./src/core/pipeline/nodes/keypoints/transformer.js":
  6015. /*!**********************************************************!*\
  6016. !*** ./src/core/pipeline/nodes/keypoints/transformer.js ***!
  6017. \**********************************************************/
  6018. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_295590__) => {
  6019. "use strict";
  6020. __nested_webpack_require_295590__.r(__webpack_exports__);
  6021. /* harmony export */ __nested_webpack_require_295590__.d(__webpack_exports__, {
  6022. /* harmony export */ "SpeedyPipelineNodeKeypointTransformer": () => (/* binding */ SpeedyPipelineNodeKeypointTransformer)
  6023. /* harmony export */ });
  6024. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_295590__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  6025. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_295590__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  6026. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_295590__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  6027. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_295590__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  6028. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_295590__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6029. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_295590__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  6030. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_295590__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  6031. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_295590__(/*! ../../../speedy-matrix */ "./src/core/speedy-matrix.js");
  6032. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_295590__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  6033. /*
  6034. * speedy-vision.js
  6035. * GPU-accelerated Computer Vision for JavaScript
  6036. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  6037. *
  6038. * Licensed under the Apache License, Version 2.0 (the "License");
  6039. * you may not use this file except in compliance with the License.
  6040. * You may obtain a copy of the License at
  6041. *
  6042. * http://www.apache.org/licenses/LICENSE-2.0
  6043. *
  6044. * Unless required by applicable law or agreed to in writing, software
  6045. * distributed under the License is distributed on an "AS IS" BASIS,
  6046. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6047. * See the License for the specific language governing permissions and
  6048. * limitations under the License.
  6049. *
  6050. * transformer.js
  6051. * Apply a transformation matrix to a set of keypoints
  6052. */
  6053. /**
  6054. * Apply a transformation matrix to a set of keypoints
  6055. */
  6056. class SpeedyPipelineNodeKeypointTransformer extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  6057. {
  6058. /**
  6059. * Constructor
  6060. * @param {string} [name] name of the node
  6061. */
  6062. constructor(name = undefined)
  6063. {
  6064. super(name, 1, [
  6065. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints),
  6066. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Keypoints)
  6067. ]);
  6068. /** @type {SpeedyMatrix} transformation matrix */
  6069. this._transform = _speedy_matrix__WEBPACK_IMPORTED_MODULE_7__.SpeedyMatrix.Create(3, 3, [1, 0, 0, 0, 1, 0, 0, 0, 1]); // identity matrix
  6070. }
  6071. /**
  6072. * Transformation matrix
  6073. * @returns {SpeedyMatrix}
  6074. */
  6075. get transform()
  6076. {
  6077. return this._transform;
  6078. }
  6079. /**
  6080. * Transformation matrix. Must be 3x3
  6081. * @param {SpeedyMatrix} transform
  6082. */
  6083. set transform(transform)
  6084. {
  6085. if(!(transform.rows == 3 && transform.columns == 3))
  6086. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Not a 3x3 transformation matrix: ${transform}`);
  6087. this._transform = transform;
  6088. }
  6089. /**
  6090. * Run the specific task of this node
  6091. * @param {SpeedyGPU} gpu
  6092. * @returns {void|SpeedyPromise<void>}
  6093. */
  6094. _run(gpu)
  6095. {
  6096. const { encodedKeypoints, descriptorSize, extraSize, encoderLength } = /** @type {SpeedyPipelineMessageWithKeypoints} */ ( this.input().read() );
  6097. const outputTexture = this._tex[0];
  6098. const homography = this._transform.read();
  6099. // apply homography
  6100. (gpu.programs.keypoints.applyHomography
  6101. .outputs(encodedKeypoints.width, encodedKeypoints.height, outputTexture)
  6102. )(homography, encodedKeypoints, descriptorSize, extraSize, encoderLength);
  6103. // done!
  6104. this.output().swrite(outputTexture, descriptorSize, extraSize, encoderLength);
  6105. }
  6106. }
  6107. /***/ }),
  6108. /***/ "./src/core/pipeline/nodes/transforms/perspective-warp.js":
  6109. /*!****************************************************************!*\
  6110. !*** ./src/core/pipeline/nodes/transforms/perspective-warp.js ***!
  6111. \****************************************************************/
  6112. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_300615__) => {
  6113. "use strict";
  6114. __nested_webpack_require_300615__.r(__webpack_exports__);
  6115. /* harmony export */ __nested_webpack_require_300615__.d(__webpack_exports__, {
  6116. /* harmony export */ "SpeedyPipelineNodePerspectiveWarp": () => (/* binding */ SpeedyPipelineNodePerspectiveWarp)
  6117. /* harmony export */ });
  6118. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_300615__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  6119. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_300615__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  6120. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_300615__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  6121. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_300615__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  6122. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_300615__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6123. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_300615__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  6124. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_300615__(/*! ../../../../utils/types */ "./src/utils/types.js");
  6125. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_300615__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  6126. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_300615__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  6127. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_300615__(/*! ../../../speedy-matrix */ "./src/core/speedy-matrix.js");
  6128. /*
  6129. * speedy-vision.js
  6130. * GPU-accelerated Computer Vision for JavaScript
  6131. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  6132. *
  6133. * Licensed under the Apache License, Version 2.0 (the "License");
  6134. * you may not use this file except in compliance with the License.
  6135. * You may obtain a copy of the License at
  6136. *
  6137. * http://www.apache.org/licenses/LICENSE-2.0
  6138. *
  6139. * Unless required by applicable law or agreed to in writing, software
  6140. * distributed under the License is distributed on an "AS IS" BASIS,
  6141. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6142. * See the License for the specific language governing permissions and
  6143. * limitations under the License.
  6144. *
  6145. * perspective-warp.js
  6146. * Warp an image using a perspective transformation
  6147. */
  6148. // Used when an invalid matrix is provided
  6149. const SINGULAR_MATRIX = [0,0,0,0,0,0,0,0,1];
  6150. /**
  6151. * Warp an image using a perspective transformation
  6152. */
  6153. class SpeedyPipelineNodePerspectiveWarp extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  6154. {
  6155. /**
  6156. * Constructor
  6157. * @param {string} [name] name of the node
  6158. */
  6159. constructor(name = undefined)
  6160. {
  6161. super(name, 1, [
  6162. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  6163. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  6164. ]);
  6165. /** @type {SpeedyMatrix} perspective transformation */
  6166. this._transform = _speedy_matrix__WEBPACK_IMPORTED_MODULE_9__.SpeedyMatrix.Create(3, 3, [1, 0, 0, 0, 1, 0, 0, 0, 1]); // identity matrix
  6167. }
  6168. /**
  6169. * Perspective transform, a 3x3 homography matrix
  6170. * @returns {SpeedyMatrix}
  6171. */
  6172. get transform()
  6173. {
  6174. return this._transform;
  6175. }
  6176. /**
  6177. * Perspective transform, a 3x3 homography matrix
  6178. * @param {SpeedyMatrix} transform
  6179. */
  6180. set transform(transform)
  6181. {
  6182. if(!(transform.rows == 3 && transform.columns == 3))
  6183. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_8__.IllegalArgumentError(`Not a 3x3 transformation matrix: ${transform}`);
  6184. this._transform = transform;
  6185. }
  6186. /**
  6187. * Run the specific task of this node
  6188. * @param {SpeedyGPU} gpu
  6189. * @returns {void|SpeedyPromise<void>}
  6190. */
  6191. _run(gpu)
  6192. {
  6193. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  6194. const width = image.width, height = image.height;
  6195. const outputTexture = this._tex[0];
  6196. const homography = this._transform.read();
  6197. const inverseHomography = this._inverse3(homography);
  6198. const isValidHomography = !Number.isNaN(inverseHomography[0]);
  6199. gpu.programs.transforms.warpPerspective.outputs(width, height, outputTexture);
  6200. gpu.programs.transforms.warpPerspective(image, isValidHomography ? inverseHomography : SINGULAR_MATRIX);
  6201. this.output().swrite(outputTexture, format);
  6202. }
  6203. /**
  6204. * Compute the inverse of a 3x3 matrix IN-PLACE (do it fast!)
  6205. * @param {number[]} mat 3x3 matrix in column-major format
  6206. * @param {number} [eps] epsilon
  6207. * @returns {number[]} 3x3 inverse matrix in column-major format
  6208. */
  6209. _inverse3(mat, eps = 1e-6)
  6210. {
  6211. // read the entries of the matrix
  6212. const a11 = mat[0];
  6213. const a21 = mat[1];
  6214. const a31 = mat[2];
  6215. const a12 = mat[3];
  6216. const a22 = mat[4];
  6217. const a32 = mat[5];
  6218. const a13 = mat[6];
  6219. const a23 = mat[7];
  6220. const a33 = mat[8];
  6221. // compute cofactors
  6222. const b1 = a33 * a22 - a32 * a23; // b11
  6223. const b2 = a33 * a12 - a32 * a13; // b21
  6224. const b3 = a23 * a12 - a22 * a13; // b31
  6225. // compute the determinant
  6226. const det = a11 * b1 - a21 * b2 + a31 * b3;
  6227. // set up the inverse
  6228. if(!(Math.abs(det) < eps)) {
  6229. const d = 1.0 / det;
  6230. mat[0] = b1 * d;
  6231. mat[1] = -(a33 * a21 - a31 * a23) * d;
  6232. mat[2] = (a32 * a21 - a31 * a22) * d;
  6233. mat[3] = -b2 * d;
  6234. mat[4] = (a33 * a11 - a31 * a13) * d;
  6235. mat[5] = -(a32 * a11 - a31 * a12) * d;
  6236. mat[6] = b3 * d;
  6237. mat[7] = -(a23 * a11 - a21 * a13) * d;
  6238. mat[8] = (a22 * a11 - a21 * a12) * d;
  6239. }
  6240. else
  6241. mat.fill(Number.NaN, 0, 9);
  6242. // done!
  6243. return mat;
  6244. }
  6245. }
  6246. /***/ }),
  6247. /***/ "./src/core/pipeline/nodes/transforms/resize.js":
  6248. /*!******************************************************!*\
  6249. !*** ./src/core/pipeline/nodes/transforms/resize.js ***!
  6250. \******************************************************/
  6251. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_307350__) => {
  6252. "use strict";
  6253. __nested_webpack_require_307350__.r(__webpack_exports__);
  6254. /* harmony export */ __nested_webpack_require_307350__.d(__webpack_exports__, {
  6255. /* harmony export */ "SpeedyPipelineNodeResize": () => (/* binding */ SpeedyPipelineNodeResize)
  6256. /* harmony export */ });
  6257. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_307350__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  6258. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_307350__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  6259. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_307350__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  6260. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_307350__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  6261. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_307350__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6262. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_307350__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  6263. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_307350__(/*! ../../../../utils/errors */ "./src/utils/errors.js");
  6264. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_307350__(/*! ../../../../utils/types */ "./src/utils/types.js");
  6265. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_307350__(/*! ../../../speedy-size */ "./src/core/speedy-size.js");
  6266. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_307350__(/*! ../../../speedy-vector */ "./src/core/speedy-vector.js");
  6267. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_307350__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  6268. /*
  6269. * speedy-vision.js
  6270. * GPU-accelerated Computer Vision for JavaScript
  6271. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  6272. *
  6273. * Licensed under the Apache License, Version 2.0 (the "License");
  6274. * you may not use this file except in compliance with the License.
  6275. * You may obtain a copy of the License at
  6276. *
  6277. * http://www.apache.org/licenses/LICENSE-2.0
  6278. *
  6279. * Unless required by applicable law or agreed to in writing, software
  6280. * distributed under the License is distributed on an "AS IS" BASIS,
  6281. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6282. * See the License for the specific language governing permissions and
  6283. * limitations under the License.
  6284. *
  6285. * resize.js
  6286. * Resize image
  6287. */
  6288. /** @typedef {"bilinear"|"nearest"} SpeedyPipelineNodeResizeMethod */
  6289. /**
  6290. * Resize image
  6291. */
  6292. class SpeedyPipelineNodeResize extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineNode
  6293. {
  6294. /**
  6295. * Constructor
  6296. * @param {string} [name] name of the node
  6297. */
  6298. constructor(name = undefined)
  6299. {
  6300. super(name, 1, [
  6301. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  6302. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.OutputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Image),
  6303. ]);
  6304. /** @type {SpeedySize} size of the output image, in pixels */
  6305. this._size = new _speedy_size__WEBPACK_IMPORTED_MODULE_8__.SpeedySize(0, 0);
  6306. /** @type {SpeedyVector2} size of the output relative to the size of the input */
  6307. this._scale = new _speedy_vector__WEBPACK_IMPORTED_MODULE_9__.SpeedyVector2(1, 1);
  6308. /** @type {SpeedyPipelineNodeResizeMethod} interpolation method */
  6309. this._method = 'bilinear';
  6310. }
  6311. /**
  6312. * Size of the output image, in pixels (use 0 to use scale)
  6313. * @returns {SpeedySize}
  6314. */
  6315. get size()
  6316. {
  6317. return this._size;
  6318. }
  6319. /**
  6320. * Size of the output image, in pixels (use 0 to use scale)
  6321. * @param {SpeedySize} size
  6322. */
  6323. set size(size)
  6324. {
  6325. this._size = size;
  6326. }
  6327. /**
  6328. * Size of the output image relative to the size of the input image
  6329. * @returns {SpeedyVector2}
  6330. */
  6331. get scale()
  6332. {
  6333. return this._scale;
  6334. }
  6335. /**
  6336. * Size of the output image relative to the size of the input image
  6337. * @param {SpeedyVector2} scale
  6338. */
  6339. set scale(scale)
  6340. {
  6341. this._scale = scale;
  6342. }
  6343. /**
  6344. * Interpolation method
  6345. * @returns {SpeedyPipelineNodeResizeMethod}
  6346. */
  6347. get method()
  6348. {
  6349. return this._method;
  6350. }
  6351. /**
  6352. * Interpolation method
  6353. * @param {SpeedyPipelineNodeResizeMethod} method
  6354. */
  6355. set method(method)
  6356. {
  6357. if(method !== 'nearest' && method !== 'bilinear')
  6358. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_6__.IllegalArgumentError(`Invalid method method: "${method}"`);
  6359. this._method = method;
  6360. }
  6361. /**
  6362. * Run the specific task of this node
  6363. * @param {SpeedyGPU} gpu
  6364. * @returns {void|SpeedyPromise<void>}
  6365. */
  6366. _run(gpu)
  6367. {
  6368. const { image, format } = /** @type {SpeedyPipelineMessageWithImage} */ ( this.input().read() );
  6369. const width = image.width, height = image.height;
  6370. const outputTexture = this._tex[0];
  6371. const method = this._method;
  6372. const newWidth = this._size.width || Math.max(1, this._scale.x * width);
  6373. const newHeight = this._size.height || Math.max(1, this._scale.y * height);
  6374. if(method == 'bilinear') {
  6375. (gpu.programs.transforms.resizeBilinear
  6376. .outputs(newWidth, newHeight, outputTexture)
  6377. )(image);
  6378. }
  6379. else if(method == 'nearest') {
  6380. (gpu.programs.transforms.resizeNearest
  6381. .outputs(newWidth, newHeight, outputTexture)
  6382. )(image);
  6383. }
  6384. this.output().swrite(outputTexture, format);
  6385. }
  6386. }
  6387. /***/ }),
  6388. /***/ "./src/core/pipeline/nodes/vector2/sink.js":
  6389. /*!*************************************************!*\
  6390. !*** ./src/core/pipeline/nodes/vector2/sink.js ***!
  6391. \*************************************************/
  6392. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_313709__) => {
  6393. "use strict";
  6394. __nested_webpack_require_313709__.r(__webpack_exports__);
  6395. /* harmony export */ __nested_webpack_require_313709__.d(__webpack_exports__, {
  6396. /* harmony export */ "SpeedyPipelineNodeVector2Sink": () => (/* binding */ SpeedyPipelineNodeVector2Sink)
  6397. /* harmony export */ });
  6398. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_313709__(/*! ../../pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  6399. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_313709__(/*! ../../pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  6400. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_313709__(/*! ../../pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  6401. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_313709__(/*! ../../../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  6402. /* harmony import */ var _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_313709__(/*! ../../../../gpu/speedy-texture-reader */ "./src/gpu/speedy-texture-reader.js");
  6403. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_313709__(/*! ../../../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6404. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_313709__(/*! ../../../../utils/utils */ "./src/utils/utils.js");
  6405. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_313709__(/*! ../../../speedy-promise */ "./src/core/speedy-promise.js");
  6406. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_313709__(/*! ../../../speedy-vector */ "./src/core/speedy-vector.js");
  6407. /*
  6408. * speedy-vision.js
  6409. * GPU-accelerated Computer Vision for JavaScript
  6410. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  6411. *
  6412. * Licensed under the Apache License, Version 2.0 (the "License");
  6413. * you may not use this file except in compliance with the License.
  6414. * You may obtain a copy of the License at
  6415. *
  6416. * http://www.apache.org/licenses/LICENSE-2.0
  6417. *
  6418. * Unless required by applicable law or agreed to in writing, software
  6419. * distributed under the License is distributed on an "AS IS" BASIS,
  6420. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6421. * See the License for the specific language governing permissions and
  6422. * limitations under the License.
  6423. *
  6424. * sink.js
  6425. * Gets keypoints out of the pipeline
  6426. */
  6427. // next power of 2
  6428. const nextPot = x => x > 1 ? 1 << Math.ceil(Math.log2(x)) : 1;
  6429. /**
  6430. * Gets 2D vectors out of the pipeline
  6431. */
  6432. class SpeedyPipelineNodeVector2Sink extends _pipeline_node__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineSinkNode
  6433. {
  6434. /**
  6435. * Constructor
  6436. * @param {string} [name] name of the node
  6437. */
  6438. constructor(name = 'vec2')
  6439. {
  6440. super(name, 2, [
  6441. (0,_pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_2__.InputPort)().expects(_pipeline_message__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineMessageType.Vector2)
  6442. ]);
  6443. /** @type {SpeedyVector2[]} 2D vectors (output) */
  6444. this._vectors = [];
  6445. /** @type {SpeedyTextureReader} texture reader */
  6446. this._textureReader = new _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_4__.SpeedyTextureReader();
  6447. /** @type {number} page flipping index */
  6448. this._page = 0;
  6449. /** @type {boolean} accelerate GPU-CPU transfers */
  6450. this._turbo = false;
  6451. }
  6452. /**
  6453. * Accelerate GPU-CPU transfers
  6454. * @returns {boolean}
  6455. */
  6456. get turbo()
  6457. {
  6458. return this._turbo;
  6459. }
  6460. /**
  6461. * Accelerate GPU-CPU transfers
  6462. * @param {boolean} value
  6463. */
  6464. set turbo(value)
  6465. {
  6466. this._turbo = Boolean(value);
  6467. }
  6468. /**
  6469. * Initializes this node
  6470. * @param {SpeedyGPU} gpu
  6471. */
  6472. init(gpu)
  6473. {
  6474. super.init(gpu);
  6475. this._textureReader.init(gpu);
  6476. }
  6477. /**
  6478. * Releases this node
  6479. * @param {SpeedyGPU} gpu
  6480. */
  6481. release(gpu)
  6482. {
  6483. this._textureReader.release(gpu);
  6484. super.release(gpu);
  6485. }
  6486. /**
  6487. * Export data from this node to the user
  6488. * @returns {SpeedyPromise<SpeedyVector2[]>}
  6489. */
  6490. export()
  6491. {
  6492. return _speedy_promise__WEBPACK_IMPORTED_MODULE_7__.SpeedyPromise.resolve(this._vectors);
  6493. }
  6494. /**
  6495. * Run the specific task of this node
  6496. * @param {SpeedyGPU} gpu
  6497. * @returns {void|SpeedyPromise<void>}
  6498. */
  6499. _run(gpu)
  6500. {
  6501. const { vectors } = /** @type {SpeedyPipelineMessageWith2DVectors} */ ( this.input().read() );
  6502. const useBufferedDownloads = this._turbo;
  6503. const encoderLength = vectors.width;
  6504. /*
  6505. I have found experimentally that, in Firefox, readPixelsAsync()
  6506. performs MUCH better if the width of the target texture is a power
  6507. of two. I have no idea why this is the case, nor if it's related to
  6508. some interaction with the GL drivers, somehow. This seems to make no
  6509. difference on Chrome, however. In any case, let's convert the input
  6510. texture to POT.
  6511. */
  6512. const encoderWidth = nextPot(encoderLength);
  6513. const encoderHeight = nextPot(Math.ceil(encoderLength * encoderLength / encoderWidth));
  6514. //const encoderHeight = (Math.ceil(encoderLength * encoderLength / encoderWidth));
  6515. // copy the set of vectors to an internal texture
  6516. const copiedTexture = this._tex[this._page];
  6517. (gpu.programs.utils.copy2DVectors
  6518. .outputs(encoderWidth, encoderHeight, copiedTexture)
  6519. )(vectors);
  6520. // flip page
  6521. this._page = 1 - this._page;
  6522. // download the internal texture
  6523. return this._textureReader.readPixelsAsync(copiedTexture, 0, 0, copiedTexture.width, copiedTexture.height, useBufferedDownloads).then(pixels => {
  6524. this._vectors = SpeedyPipelineNodeVector2Sink._decode(pixels, encoderWidth, encoderHeight);
  6525. });
  6526. }
  6527. /**
  6528. * Decode a sequence of vectors, given a flattened image of encoded pixels
  6529. * @param {Uint8Array} pixels pixels in the [r,g,b,a,...] format
  6530. * @param {number} encoderWidth
  6531. * @param {number} encoderHeight
  6532. * @returns {SpeedyVector2[]} vectors
  6533. */
  6534. static _decode(pixels, encoderWidth, encoderHeight)
  6535. {
  6536. const bytesPerVector = 4; // 1 pixel per vector
  6537. const vectors = [];
  6538. let hi = 0, lo = 0;
  6539. let x = 0, y = 0;
  6540. // how many bytes should we read?
  6541. const e2 = encoderWidth * encoderHeight * bytesPerVector;
  6542. const size = Math.min(pixels.length, e2);
  6543. // for each encoded vector
  6544. for(let i = 0; i < size; i += bytesPerVector) {
  6545. // extract 16-bit words
  6546. lo = (pixels[i+1] << 8) | pixels[i];
  6547. hi = (pixels[i+3] << 8) | pixels[i+2];
  6548. // the vector is "null": we have reached the end of the list
  6549. if(lo == 0xFFFF && hi == 0xFFFF)
  6550. break;
  6551. // the vector must be discarded
  6552. if(lo == 0xFF00 && hi == 0xFF00)
  6553. continue;
  6554. // decode floats
  6555. x = _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.decodeFloat16(lo);
  6556. y = _utils_utils__WEBPACK_IMPORTED_MODULE_6__.Utils.decodeFloat16(hi);
  6557. // register vector
  6558. vectors.push(new _speedy_vector__WEBPACK_IMPORTED_MODULE_8__.SpeedyVector2(x, y));
  6559. }
  6560. // done!
  6561. return vectors;
  6562. }
  6563. }
  6564. /***/ }),
  6565. /***/ "./src/core/pipeline/pipeline-message.js":
  6566. /*!***********************************************!*\
  6567. !*** ./src/core/pipeline/pipeline-message.js ***!
  6568. \***********************************************/
  6569. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_321498__) => {
  6570. "use strict";
  6571. __nested_webpack_require_321498__.r(__webpack_exports__);
  6572. /* harmony export */ __nested_webpack_require_321498__.d(__webpack_exports__, {
  6573. /* harmony export */ "SpeedyPipelineMessageType": () => (/* binding */ SpeedyPipelineMessageType),
  6574. /* harmony export */ "SpeedyPipelineMessage": () => (/* binding */ SpeedyPipelineMessage),
  6575. /* harmony export */ "SpeedyPipelineMessageWithNothing": () => (/* binding */ SpeedyPipelineMessageWithNothing),
  6576. /* harmony export */ "SpeedyPipelineMessageWithImage": () => (/* binding */ SpeedyPipelineMessageWithImage),
  6577. /* harmony export */ "SpeedyPipelineMessageWithKeypoints": () => (/* binding */ SpeedyPipelineMessageWithKeypoints),
  6578. /* harmony export */ "SpeedyPipelineMessageWith2DVectors": () => (/* binding */ SpeedyPipelineMessageWith2DVectors),
  6579. /* harmony export */ "SpeedyPipelineMessageWithLSHTables": () => (/* binding */ SpeedyPipelineMessageWithLSHTables),
  6580. /* harmony export */ "SpeedyPipelineMessageWithKeypointMatches": () => (/* binding */ SpeedyPipelineMessageWithKeypointMatches)
  6581. /* harmony export */ });
  6582. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_321498__(/*! ../../utils/utils */ "./src/utils/utils.js");
  6583. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_321498__(/*! ../../utils/types */ "./src/utils/types.js");
  6584. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_321498__(/*! ../../utils/errors */ "./src/utils/errors.js");
  6585. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_321498__(/*! ../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6586. /* harmony import */ var _gpu_speedy_lsh__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_321498__(/*! ../../gpu/speedy-lsh */ "./src/gpu/speedy-lsh.js");
  6587. /*
  6588. * speedy-vision.js
  6589. * GPU-accelerated Computer Vision for JavaScript
  6590. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  6591. *
  6592. * Licensed under the Apache License, Version 2.0 (the "License");
  6593. * you may not use this file except in compliance with the License.
  6594. * You may obtain a copy of the License at
  6595. *
  6596. * http://www.apache.org/licenses/LICENSE-2.0
  6597. *
  6598. * Unless required by applicable law or agreed to in writing, software
  6599. * distributed under the License is distributed on an "AS IS" BASIS,
  6600. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  6601. * See the License for the specific language governing permissions and
  6602. * limitations under the License.
  6603. *
  6604. * pipeline-message.js
  6605. * A message that is shared between nodes of a pipeline
  6606. */
  6607. /**
  6608. * Types of messages
  6609. * @enum {Symbol}
  6610. */
  6611. const SpeedyPipelineMessageType = Object.freeze({
  6612. Nothing: Symbol('Nothing'),
  6613. Image: Symbol('Image'),
  6614. Keypoints: Symbol('Keypoints'),
  6615. Vector2: Symbol('Vector2'),
  6616. LSHTables: Symbol('LSHTables'),
  6617. KeypointMatches: Symbol('KeypointMatches'),
  6618. });
  6619. /**
  6620. * A message that is shared between nodes of a pipeline
  6621. * @abstract
  6622. */
  6623. class SpeedyPipelineMessage
  6624. {
  6625. /**
  6626. * Constructor
  6627. * @param {SpeedyPipelineMessageType} type message type
  6628. */
  6629. constructor(type)
  6630. {
  6631. /** @type {SpeedyPipelineMessageType} message type */
  6632. this._type = type;
  6633. }
  6634. /**
  6635. * Message type
  6636. * @returns {SpeedyPipelineMessageType}
  6637. */
  6638. get type()
  6639. {
  6640. return this._type;
  6641. }
  6642. /**
  6643. * Checks if the type of this message is equal to parameter type
  6644. * @param {SpeedyPipelineMessageType} type
  6645. * @returns {boolean}
  6646. */
  6647. hasType(type)
  6648. {
  6649. return this._type === type;
  6650. }
  6651. /**
  6652. * Is this an empty message?
  6653. * @returns {boolean}
  6654. */
  6655. isEmpty()
  6656. {
  6657. return this.hasType(SpeedyPipelineMessageType.Nothing);
  6658. }
  6659. /**
  6660. * Convert to string
  6661. * @returns {string}
  6662. */
  6663. toString()
  6664. {
  6665. const type = Object.keys(SpeedyPipelineMessageType).find(
  6666. type => SpeedyPipelineMessageType[type] === this.type
  6667. );
  6668. return `message of type ${type}`;
  6669. }
  6670. /**
  6671. * Set parameters
  6672. * @abstract
  6673. * @param {...any} args
  6674. * @returns {SpeedyPipelineMessage} this message
  6675. */
  6676. set(...args)
  6677. {
  6678. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  6679. }
  6680. /**
  6681. * Create a message of the specified type
  6682. * @param {SpeedyPipelineMessageType} type
  6683. * @returns {SpeedyPipelineMessage}
  6684. */
  6685. static create(type)
  6686. {
  6687. return createMessage(type);
  6688. }
  6689. }
  6690. /**
  6691. * An empty message carrying nothing
  6692. */
  6693. class SpeedyPipelineMessageWithNothing extends SpeedyPipelineMessage
  6694. {
  6695. /**
  6696. * Constructor
  6697. */
  6698. constructor()
  6699. {
  6700. super(SpeedyPipelineMessageType.Nothing);
  6701. }
  6702. /**
  6703. * Set parameters
  6704. * @returns {SpeedyPipelineMessage} this message
  6705. */
  6706. set()
  6707. {
  6708. return this;
  6709. }
  6710. }
  6711. /**
  6712. * A message transporting an image
  6713. */
  6714. class SpeedyPipelineMessageWithImage extends SpeedyPipelineMessage
  6715. {
  6716. /**
  6717. * Constructor
  6718. */
  6719. constructor()
  6720. {
  6721. super(SpeedyPipelineMessageType.Image);
  6722. /** @type {SpeedyDrawableTexture} the image we carry */
  6723. this._image = null;
  6724. /** @type {ImageFormat} image format */
  6725. this._format = _utils_types__WEBPACK_IMPORTED_MODULE_1__.ImageFormat.RGBA;
  6726. }
  6727. /**
  6728. * Set parameters
  6729. * @param {SpeedyDrawableTexture} image the image we carry
  6730. * @param {ImageFormat} [format] image format
  6731. * @returns {SpeedyPipelineMessage} this message
  6732. */
  6733. set(image, format = _utils_types__WEBPACK_IMPORTED_MODULE_1__.ImageFormat.RGBA)
  6734. {
  6735. // set parameters
  6736. this._image = image;
  6737. this._format = format;
  6738. // done!
  6739. return this;
  6740. }
  6741. /**
  6742. * The image we carry
  6743. * @returns {SpeedyDrawableTexture}
  6744. */
  6745. get image()
  6746. {
  6747. return this._image;
  6748. }
  6749. /**
  6750. * Image format
  6751. * @returns {ImageFormat}
  6752. */
  6753. get format()
  6754. {
  6755. return this._format;
  6756. }
  6757. }
  6758. /**
  6759. * A message transporting keypoints
  6760. */
  6761. class SpeedyPipelineMessageWithKeypoints extends SpeedyPipelineMessage
  6762. {
  6763. /**
  6764. * Constructor
  6765. */
  6766. constructor()
  6767. {
  6768. super(SpeedyPipelineMessageType.Keypoints);
  6769. /** @type {SpeedyDrawableTexture} encoded keypoints */
  6770. this._encodedKeypoints = null;
  6771. /** @type {number} descriptor size in bytes */
  6772. this._descriptorSize = 0;
  6773. /** @type {number} extra size in bytes */
  6774. this._extraSize = 0;
  6775. /** @type {number} encoder length */
  6776. this._encoderLength = 1;
  6777. }
  6778. /**
  6779. * Set parameters
  6780. * @param {SpeedyDrawableTexture} encodedKeypoints encoded keypoints
  6781. * @param {number} descriptorSize in bytes
  6782. * @param {number} extraSize in bytes
  6783. * @param {number} encoderLength positive integer
  6784. * @returns {SpeedyPipelineMessage} this message
  6785. */
  6786. set(encodedKeypoints, descriptorSize, extraSize, encoderLength)
  6787. {
  6788. // set parameters
  6789. this._encodedKeypoints = encodedKeypoints;
  6790. this._descriptorSize = descriptorSize | 0;
  6791. this._extraSize = extraSize | 0;
  6792. this._encoderLength = encoderLength | 0;
  6793. // validate
  6794. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._descriptorSize >= 0 && this._extraSize >= 0);
  6795. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._encoderLength === this._encodedKeypoints.width, 'Invalid encoderLength');
  6796. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._encodedKeypoints.width === this._encodedKeypoints.height, 'Invalid encodedKeypoints texture');
  6797. // done!
  6798. return this;
  6799. }
  6800. /**
  6801. * Encoded keypoints
  6802. * @returns {SpeedyDrawableTexture}
  6803. */
  6804. get encodedKeypoints()
  6805. {
  6806. return this._encodedKeypoints;
  6807. }
  6808. /**
  6809. * Descriptor size, in bytes
  6810. * @returns {number}
  6811. */
  6812. get descriptorSize()
  6813. {
  6814. return this._descriptorSize;
  6815. }
  6816. /**
  6817. * Extra size, in bytes
  6818. * @returns {number}
  6819. */
  6820. get extraSize()
  6821. {
  6822. return this._extraSize;
  6823. }
  6824. /**
  6825. * Encoder length
  6826. * @returns {number}
  6827. */
  6828. get encoderLength()
  6829. {
  6830. return this._encoderLength;
  6831. }
  6832. }
  6833. /*
  6834. * A message transporting a set of 2D vectors
  6835. */
  6836. class SpeedyPipelineMessageWith2DVectors extends SpeedyPipelineMessage
  6837. {
  6838. /**
  6839. * Constructor
  6840. */
  6841. constructor()
  6842. {
  6843. super(SpeedyPipelineMessageType.Vector2);
  6844. /** @type {SpeedyDrawableTexture} the set of vectors */
  6845. this._vectors = null;
  6846. }
  6847. /**
  6848. * Set parameters
  6849. * @param {SpeedyDrawableTexture} vectors the set of vectors
  6850. * @returns {SpeedyPipelineMessage} this message
  6851. */
  6852. set(vectors)
  6853. {
  6854. // set parameters
  6855. this._vectors = vectors;
  6856. // done!
  6857. return this;
  6858. }
  6859. /**
  6860. * The set of vectors
  6861. * @returns {SpeedyDrawableTexture}
  6862. */
  6863. get vectors()
  6864. {
  6865. return this._vectors;
  6866. }
  6867. }
  6868. /**
  6869. * A message transporting LSH tables
  6870. */
  6871. class SpeedyPipelineMessageWithLSHTables extends SpeedyPipelineMessage
  6872. {
  6873. /**
  6874. * Constructor
  6875. */
  6876. constructor()
  6877. {
  6878. super(SpeedyPipelineMessageType.LSHTables);
  6879. /** @type {SpeedyLSH} LSH data structure */
  6880. this._lsh = null;
  6881. }
  6882. /**
  6883. * Set parameters
  6884. * @param {SpeedyLSH} lsh
  6885. * @returns {SpeedyPipelineMessage} this message
  6886. */
  6887. set(lsh)
  6888. {
  6889. // set parameters
  6890. this._lsh = lsh;
  6891. // done!
  6892. return this;
  6893. }
  6894. /**
  6895. * LSH data structure
  6896. * @returns {SpeedyLSH}
  6897. */
  6898. get lsh()
  6899. {
  6900. return this._lsh;
  6901. }
  6902. }
  6903. /*
  6904. * A message transporting a set of keypoint matches
  6905. */
  6906. class SpeedyPipelineMessageWithKeypointMatches extends SpeedyPipelineMessage
  6907. {
  6908. /**
  6909. * Constructor
  6910. */
  6911. constructor()
  6912. {
  6913. super(SpeedyPipelineMessageType.KeypointMatches);
  6914. /** @type {SpeedyDrawableTexture} keypoint matches (note: 1 pixel encodes 1 match) */
  6915. this._encodedMatches = null;
  6916. /** @type {number} number of matches per keypoint */
  6917. this._matchesPerKeypoint = 1;
  6918. }
  6919. /**
  6920. * Set parameters
  6921. * @param {SpeedyDrawableTexture} encodedMatches
  6922. * @param {number} matchesPerKeypoint
  6923. * @returns {SpeedyPipelineMessage} this message
  6924. */
  6925. set(encodedMatches, matchesPerKeypoint)
  6926. {
  6927. // set parameters
  6928. this._encodedMatches = encodedMatches;
  6929. this._matchesPerKeypoint = matchesPerKeypoint | 0;
  6930. // validate
  6931. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._matchesPerKeypoint > 0);
  6932. // done!
  6933. return this;
  6934. }
  6935. /**
  6936. * The matches
  6937. * @returns {SpeedyDrawableTexture}
  6938. */
  6939. get encodedMatches()
  6940. {
  6941. return this._encodedMatches;
  6942. }
  6943. /**
  6944. * Number of matches per keypoint
  6945. * @returns {number}
  6946. */
  6947. get matchesPerKeypoint()
  6948. {
  6949. return this._matchesPerKeypoint;
  6950. }
  6951. }
  6952. //
  6953. // Utilities
  6954. //
  6955. /** Map message type to message class */
  6956. const MESSAGE_CLASS = Object.freeze({
  6957. [SpeedyPipelineMessageType.Nothing]: SpeedyPipelineMessageWithNothing,
  6958. [SpeedyPipelineMessageType.Image]: SpeedyPipelineMessageWithImage,
  6959. [SpeedyPipelineMessageType.Keypoints]: SpeedyPipelineMessageWithKeypoints,
  6960. [SpeedyPipelineMessageType.Vector2]: SpeedyPipelineMessageWith2DVectors,
  6961. [SpeedyPipelineMessageType.LSHTables]: SpeedyPipelineMessageWithLSHTables,
  6962. [SpeedyPipelineMessageType.KeypointMatches]: SpeedyPipelineMessageWithKeypointMatches,
  6963. });
  6964. /**
  6965. * Create a message of the specified type
  6966. * @param {SpeedyPipelineMessageType} type
  6967. * @returns {SpeedyPipelineMessage}
  6968. */
  6969. function createMessage(type)
  6970. {
  6971. //return Reflect.construct(MESSAGE_CLASS[type], []);
  6972. return new MESSAGE_CLASS[
  6973. // error TS2538: Type 'Symbol' cannot be used as an index type.
  6974. // heck, what the hack...
  6975. /** @type {any} */ ( type )
  6976. ];
  6977. }
  6978. /***/ }),
  6979. /***/ "./src/core/pipeline/pipeline-node.js":
  6980. /*!********************************************!*\
  6981. !*** ./src/core/pipeline/pipeline-node.js ***!
  6982. \********************************************/
  6983. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_333809__) => {
  6984. "use strict";
  6985. __nested_webpack_require_333809__.r(__webpack_exports__);
  6986. /* harmony export */ __nested_webpack_require_333809__.d(__webpack_exports__, {
  6987. /* harmony export */ "SpeedyPipelineNode": () => (/* binding */ SpeedyPipelineNode),
  6988. /* harmony export */ "SpeedyPipelineSourceNode": () => (/* binding */ SpeedyPipelineSourceNode),
  6989. /* harmony export */ "SpeedyPipelineSinkNode": () => (/* binding */ SpeedyPipelineSinkNode)
  6990. /* harmony export */ });
  6991. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_333809__(/*! ../../utils/utils */ "./src/utils/utils.js");
  6992. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_333809__(/*! ../../utils/globals */ "./src/utils/globals.js");
  6993. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_333809__(/*! ../speedy-promise */ "./src/core/speedy-promise.js");
  6994. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_333809__(/*! ../../utils/errors */ "./src/utils/errors.js");
  6995. /* harmony import */ var _pipeline_port__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_333809__(/*! ./pipeline-port */ "./src/core/pipeline/pipeline-port.js");
  6996. /* harmony import */ var _pipeline_portbuilder__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_333809__(/*! ./pipeline-portbuilder */ "./src/core/pipeline/pipeline-portbuilder.js");
  6997. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_333809__(/*! ../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  6998. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_333809__(/*! ../../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  6999. /* harmony import */ var _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_333809__(/*! ../../gpu/speedy-texture-reader */ "./src/gpu/speedy-texture-reader.js");
  7000. /*
  7001. * speedy-vision.js
  7002. * GPU-accelerated Computer Vision for JavaScript
  7003. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  7004. *
  7005. * Licensed under the Apache License, Version 2.0 (the "License");
  7006. * you may not use this file except in compliance with the License.
  7007. * You may obtain a copy of the License at
  7008. *
  7009. * http://www.apache.org/licenses/LICENSE-2.0
  7010. *
  7011. * Unless required by applicable law or agreed to in writing, software
  7012. * distributed under the License is distributed on an "AS IS" BASIS,
  7013. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  7014. * See the License for the specific language governing permissions and
  7015. * limitations under the License.
  7016. *
  7017. * pipeline-node.js
  7018. * Node of a pipeline
  7019. */
  7020. /** @typedef {Object<string,SpeedyPipelineInputPort>} InputPortDictionary */
  7021. /** @typedef {Object<string,SpeedyPipelineOutputPort>} OutputPortDictionary */
  7022. /** Generate a random name for a node */
  7023. const generateRandomName = () => Math.random().toString(16).substr(2);
  7024. /** Create an empty input port dictionary */
  7025. const createInputPortDictionary = () => /** @type {InputPortDictionary} */ ( Object.create(null) );
  7026. /** Create an empty output port dictionary */
  7027. const createOutputPortDictionary = () => /** @type {OutputPortDictionary} */ ( Object.create(null) );
  7028. /**
  7029. * Map an array of input ports to an InputPortDictionary whose keys are their names
  7030. * @param {SpeedyPipelineInputPort[]} ports
  7031. * @returns {InputPortDictionary}
  7032. */
  7033. function InputPortDictionary(ports)
  7034. {
  7035. return ports.reduce((dict, port) => ((dict[port.name] = port), dict), createInputPortDictionary());
  7036. }
  7037. /**
  7038. * Map an array of output ports to an OutputPortDictionary whose keys are their names
  7039. * @param {SpeedyPipelineOutputPort[]} ports
  7040. * @returns {OutputPortDictionary}
  7041. */
  7042. function OutputPortDictionary(ports)
  7043. {
  7044. return ports.reduce((dict, port) => ((dict[port.name] = port), dict), createOutputPortDictionary());
  7045. }
  7046. /** A flag used for debugging purposes */
  7047. let _texView = false;
  7048. /**
  7049. * Node of a pipeline
  7050. * @abstract
  7051. */
  7052. class SpeedyPipelineNode
  7053. {
  7054. /**
  7055. * Constructor
  7056. * @param {string} [name] the name of this node
  7057. * @param {number} [texCount] number of work textures
  7058. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  7059. */
  7060. constructor(name = generateRandomName(), texCount = 0, portBuilders = [])
  7061. {
  7062. /** @type {string} the name of this node */
  7063. this._name = String(name);
  7064. /** @type {SpeedyDrawableTexture[]} work texture(s) */
  7065. this._tex = (new Array(texCount)).fill(null);
  7066. // build the ports
  7067. const ports = portBuilders.map(builder => builder.build(this));
  7068. const inputPorts = /** @type {SpeedyPipelineInputPort[]} */ ( ports.filter(port => port.isInputPort()) );
  7069. const outputPorts = /** @type {SpeedyPipelineOutputPort[]} */ ( ports.filter(port => port.isOutputPort()) );
  7070. /** @type {InputPortDictionary} input ports */
  7071. this._inputPorts = InputPortDictionary(inputPorts);
  7072. /** @type {OutputPortDictionary} output ports */
  7073. this._outputPorts = OutputPortDictionary(outputPorts);
  7074. // validate
  7075. if(this._name.length == 0)
  7076. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`Invalid name "${this._name}" for node ${this.fullName}`);
  7077. else if(portBuilders.length == 0)
  7078. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`No ports have been found in node ${this.fullName}`);
  7079. }
  7080. /**
  7081. * The name of this node
  7082. * @returns {string}
  7083. */
  7084. get name()
  7085. {
  7086. return this._name;
  7087. }
  7088. /**
  7089. * Name and type of this node
  7090. * @returns {string}
  7091. */
  7092. get fullName()
  7093. {
  7094. return `${this.constructor.name}[${this.name}]`;
  7095. }
  7096. /**
  7097. * Find input port by name
  7098. * @param {string} [portName]
  7099. * @returns {SpeedyPipelineInputPort}
  7100. */
  7101. input(portName = _pipeline_port__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineInputPort.DEFAULT_NAME)
  7102. {
  7103. if(portName in this._inputPorts)
  7104. return this._inputPorts[portName];
  7105. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`Can't find input port ${portName} in node ${this.fullName}`);
  7106. }
  7107. /**
  7108. * Find output port by name
  7109. * @param {string} [portName]
  7110. * @returns {SpeedyPipelineOutputPort}
  7111. */
  7112. output(portName = _pipeline_port__WEBPACK_IMPORTED_MODULE_4__.SpeedyPipelineOutputPort.DEFAULT_NAME)
  7113. {
  7114. if(portName in this._outputPorts)
  7115. return this._outputPorts[portName];
  7116. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`Can't find output port ${portName} in node ${this.fullName}`);
  7117. }
  7118. /**
  7119. * Get data from the input ports and execute
  7120. * the task that this node is supposed to!
  7121. * @param {SpeedyGPU} gpu
  7122. * @returns {void|SpeedyPromise<void>}
  7123. */
  7124. execute(gpu)
  7125. {
  7126. let portName;
  7127. // clear output ports
  7128. for(portName in this._outputPorts)
  7129. this._outputPorts[portName].clearMessage();
  7130. // let the input ports receive what is due
  7131. for(portName in this._inputPorts)
  7132. this._inputPorts[portName].pullMessage(this.fullName);
  7133. // run the task
  7134. const runTask = this._run(gpu);
  7135. if(typeof runTask === 'undefined') {
  7136. for(portName in this._outputPorts) // ensure that no output ports are empty
  7137. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._outputPorts[portName].hasMessage(), `Did you forget to write data to the output port ${portName} of ${this.fullName}?`);
  7138. return undefined;
  7139. }
  7140. else return runTask.then(() => {
  7141. for(portName in this._outputPorts) // ensure that no output ports are empty
  7142. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._outputPorts[portName].hasMessage(), `Did you forget to write data to the output port ${portName} of ${this.fullName}?`);
  7143. });
  7144. }
  7145. /**
  7146. * Run the specific task of this node
  7147. * @abstract
  7148. * @param {SpeedyGPU} gpu
  7149. * @returns {void|SpeedyPromise<void>}
  7150. */
  7151. _run(gpu)
  7152. {
  7153. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.AbstractMethodError();
  7154. }
  7155. /**
  7156. * Initializes this node
  7157. * @param {SpeedyGPU} gpu
  7158. */
  7159. init(gpu)
  7160. {
  7161. gpu.subscribe(this._allocateWorkTextures, this, gpu);
  7162. this._allocateWorkTextures(gpu);
  7163. }
  7164. /**
  7165. * Releases this node
  7166. * @param {SpeedyGPU} gpu
  7167. */
  7168. release(gpu)
  7169. {
  7170. this._deallocateWorkTextures(gpu);
  7171. gpu.unsubscribe(this._allocateWorkTextures, this);
  7172. }
  7173. /**
  7174. * Clear all ports
  7175. */
  7176. clearPorts()
  7177. {
  7178. let portName;
  7179. for(portName in this._inputPorts)
  7180. this._inputPorts[portName].clearMessage();
  7181. for(portName in this._outputPorts)
  7182. this._outputPorts[portName].clearMessage();
  7183. }
  7184. /**
  7185. * Find all nodes that feed input to this node
  7186. * @returns {SpeedyPipelineNode[]}
  7187. */
  7188. inputNodes()
  7189. {
  7190. const nodes = [];
  7191. for(const portName in this._inputPorts) {
  7192. const port = this._inputPorts[portName];
  7193. if(port.incomingLink != null)
  7194. nodes.push(port.incomingLink.node);
  7195. }
  7196. return nodes;
  7197. }
  7198. /**
  7199. * Is this a source of the pipeline?
  7200. * @returns {boolean}
  7201. */
  7202. isSource()
  7203. {
  7204. return false;
  7205. }
  7206. /**
  7207. * Is this a sink of the pipeline?
  7208. * @returns {boolean}
  7209. */
  7210. isSink()
  7211. {
  7212. return false;
  7213. // note: a portal sink has no output ports, but it isn't a sink of the pipeline!
  7214. //return Object.keys(this._outputPorts).length == 0;
  7215. }
  7216. /**
  7217. * Allocate work texture(s)
  7218. * @param {SpeedyGPU} gpu
  7219. */
  7220. _allocateWorkTextures(gpu)
  7221. {
  7222. for(let j = 0; j < this._tex.length; j++)
  7223. this._tex[j] = gpu.texturePool.allocate();
  7224. }
  7225. /**
  7226. * Deallocate work texture(s)
  7227. * @param {SpeedyGPU} gpu
  7228. */
  7229. _deallocateWorkTextures(gpu)
  7230. {
  7231. for(let j = this._tex.length - 1; j >= 0; j--)
  7232. this._tex[j] = gpu.texturePool.free(this._tex[j]);
  7233. }
  7234. /**
  7235. * Inspect the pixels of a texture for debugging purposes
  7236. * @param {SpeedyGPU} gpu
  7237. * @param {SpeedyDrawableTexture} texture
  7238. * @returns {Uint8Array}
  7239. */
  7240. _inspect(gpu, texture)
  7241. {
  7242. const textureReader = new _gpu_speedy_texture_reader__WEBPACK_IMPORTED_MODULE_8__.SpeedyTextureReader();
  7243. textureReader.init(gpu);
  7244. const pixels = textureReader.readPixelsSync(texture);
  7245. textureReader.release(gpu);
  7246. return new Uint8Array(pixels); // copy the array
  7247. }
  7248. /**
  7249. * Inspect the pixels of a texture as unsigned 32-bit integers
  7250. * @param {SpeedyGPU} gpu
  7251. * @param {SpeedyDrawableTexture} texture
  7252. * @returns {Uint32Array}
  7253. */
  7254. _inspect32(gpu, texture)
  7255. {
  7256. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(_utils_globals__WEBPACK_IMPORTED_MODULE_1__.LITTLE_ENDIAN); // make sure we use little-endian
  7257. return new Uint32Array(this._inspect(gpu, texture).buffer);
  7258. }
  7259. /**
  7260. * Visually inspect a texture for debugging purposes
  7261. * @param {SpeedyGPU} gpu
  7262. * @param {SpeedyDrawableTexture} texture
  7263. */
  7264. _visualize(gpu, texture)
  7265. {
  7266. const canvas = gpu.renderToCanvas(texture);
  7267. if(!_texView) {
  7268. document.body.appendChild(canvas);
  7269. _texView = true;
  7270. }
  7271. }
  7272. }
  7273. /**
  7274. * Source node (a node with no input ports)
  7275. * @abstract
  7276. */
  7277. class SpeedyPipelineSourceNode extends SpeedyPipelineNode
  7278. {
  7279. /**
  7280. * Constructor
  7281. * @param {string} [name] the name of this node
  7282. * @param {number} [texCount] number of work textures
  7283. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  7284. */
  7285. constructor(name = undefined, texCount = undefined, portBuilders = undefined)
  7286. {
  7287. super(name, texCount, portBuilders);
  7288. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(Object.keys(this._inputPorts).length == 0);
  7289. }
  7290. /**
  7291. * Is this a source of the pipeline?
  7292. * @returns {boolean}
  7293. */
  7294. isSource()
  7295. {
  7296. return true;
  7297. }
  7298. }
  7299. /**
  7300. * Sink node (a node with no output ports)
  7301. * @abstract
  7302. */
  7303. class SpeedyPipelineSinkNode extends SpeedyPipelineNode
  7304. {
  7305. /**
  7306. * Constructor
  7307. * @param {string} [name] the name of this node
  7308. * @param {number} [texCount] number of work textures
  7309. * @param {SpeedyPipelinePortBuilder[]} [portBuilders] port builders
  7310. */
  7311. constructor(name = undefined, texCount = undefined, portBuilders = undefined)
  7312. {
  7313. super(name, texCount, portBuilders);
  7314. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(Object.keys(this._outputPorts).length == 0);
  7315. }
  7316. /**
  7317. * Export data from this node to the user
  7318. * @abstract
  7319. * @returns {SpeedyPromise<any>}
  7320. */
  7321. export()
  7322. {
  7323. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.AbstractMethodError();
  7324. }
  7325. /**
  7326. * Is this a sink of the pipeline?
  7327. * @returns {boolean}
  7328. */
  7329. isSink()
  7330. {
  7331. return true;
  7332. }
  7333. }
  7334. /***/ }),
  7335. /***/ "./src/core/pipeline/pipeline-port.js":
  7336. /*!********************************************!*\
  7337. !*** ./src/core/pipeline/pipeline-port.js ***!
  7338. \********************************************/
  7339. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_347268__) => {
  7340. "use strict";
  7341. __nested_webpack_require_347268__.r(__webpack_exports__);
  7342. /* harmony export */ __nested_webpack_require_347268__.d(__webpack_exports__, {
  7343. /* harmony export */ "SpeedyPipelinePort": () => (/* binding */ SpeedyPipelinePort),
  7344. /* harmony export */ "SpeedyPipelineOutputPort": () => (/* binding */ SpeedyPipelineOutputPort),
  7345. /* harmony export */ "SpeedyPipelineInputPort": () => (/* binding */ SpeedyPipelineInputPort)
  7346. /* harmony export */ });
  7347. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_347268__(/*! ../../utils/utils */ "./src/utils/utils.js");
  7348. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_347268__(/*! ../../utils/errors */ "./src/utils/errors.js");
  7349. /* harmony import */ var _pipeline_portspec__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_347268__(/*! ./pipeline-portspec */ "./src/core/pipeline/pipeline-portspec.js");
  7350. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_347268__(/*! ./pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  7351. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_347268__(/*! ./pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  7352. /*
  7353. * speedy-vision.js
  7354. * GPU-accelerated Computer Vision for JavaScript
  7355. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  7356. *
  7357. * Licensed under the Apache License, Version 2.0 (the "License");
  7358. * you may not use this file except in compliance with the License.
  7359. * You may obtain a copy of the License at
  7360. *
  7361. * http://www.apache.org/licenses/LICENSE-2.0
  7362. *
  7363. * Unless required by applicable law or agreed to in writing, software
  7364. * distributed under the License is distributed on an "AS IS" BASIS,
  7365. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  7366. * See the License for the specific language governing permissions and
  7367. * limitations under the License.
  7368. *
  7369. * pipeline-port.js
  7370. * Port of a node of a pipeline
  7371. */
  7372. // Constants
  7373. const DEFAULT_INPUT_PORT_NAME = 'in';
  7374. const DEFAULT_OUTPUT_PORT_NAME = 'out';
  7375. const ACCEPTABLE_PORT_NAME = /^[a-z][a-zA-Z0-9]*$/;
  7376. const EMPTY_MESSAGE = new _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessageWithNothing();
  7377. /**
  7378. * Port of a node of a pipeline
  7379. * @abstract
  7380. */
  7381. class SpeedyPipelinePort
  7382. {
  7383. /**
  7384. * Constructor
  7385. * @param {string} name the name of this port
  7386. * @param {SpeedyPipelinePortSpec} spec port specification
  7387. * @param {SpeedyPipelineNode} node the node to which this port belongs
  7388. */
  7389. constructor(name, spec, node)
  7390. {
  7391. /** @type {string} the name of this port */
  7392. this._name = String(name);
  7393. /** @type {SpeedyPipelinePortSpec} the specification of this port */
  7394. this._spec = spec;
  7395. /** @type {SpeedyPipelineNode} the node to which this port belongs */
  7396. this._node = node;
  7397. /** @type {SpeedyPipelineMessage} the message located in this port */
  7398. this._message = EMPTY_MESSAGE;
  7399. // check if we've got an acceptable port name
  7400. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(ACCEPTABLE_PORT_NAME.test(this._name), `Port name "${this._name}" is not acceptable`);
  7401. }
  7402. /**
  7403. * The name of this port
  7404. * @returns {string}
  7405. */
  7406. get name()
  7407. {
  7408. return this._name;
  7409. }
  7410. /**
  7411. * The node to which this port belongs
  7412. * @returns {SpeedyPipelineNode}
  7413. */
  7414. get node()
  7415. {
  7416. return this._node;
  7417. }
  7418. /**
  7419. * Connect this port to another
  7420. * @abstract
  7421. * @param {SpeedyPipelinePort} port
  7422. */
  7423. connectTo(port)
  7424. {
  7425. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.AbstractMethodError();
  7426. }
  7427. /**
  7428. * Is this an input port?
  7429. * @abstract
  7430. * @returns {boolean}
  7431. */
  7432. isInputPort()
  7433. {
  7434. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.AbstractMethodError();
  7435. }
  7436. /**
  7437. * Is this an output port?
  7438. * @returns {boolean}
  7439. */
  7440. isOutputPort()
  7441. {
  7442. return !this.isInputPort();
  7443. }
  7444. /**
  7445. * Clear the message stored in this port
  7446. */
  7447. clearMessage()
  7448. {
  7449. this._message = EMPTY_MESSAGE;
  7450. }
  7451. /**
  7452. * Is there a valid message located in this port?
  7453. * @returns {boolean}
  7454. */
  7455. hasMessage()
  7456. {
  7457. return !this._message.isEmpty();
  7458. }
  7459. /**
  7460. * Read the message that is in this port
  7461. * @returns {SpeedyPipelineMessage}
  7462. */
  7463. read()
  7464. {
  7465. if(this._message.isEmpty())
  7466. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(`Can't read from port ${this.name}: nothing to read`);
  7467. return this._message;
  7468. }
  7469. /**
  7470. * Write a message to this port
  7471. * @param {SpeedyPipelineMessage} message
  7472. */
  7473. write(message)
  7474. {
  7475. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.NotSupportedError(`Can't write ${message} to port ${this.name}: unsupported operation`);
  7476. }
  7477. /**
  7478. * Default port name
  7479. * @abstract
  7480. * @returns {string}
  7481. */
  7482. static get DEFAULT_NAME()
  7483. {
  7484. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.AbstractMethodError();
  7485. }
  7486. }
  7487. /**
  7488. * Output port
  7489. */
  7490. class SpeedyPipelineOutputPort extends SpeedyPipelinePort
  7491. {
  7492. /**
  7493. * Constructor
  7494. * @param {string} name the name of this port
  7495. * @param {SpeedyPipelinePortSpec} spec port specification
  7496. * @param {SpeedyPipelineNode} node the node to which this port belongs
  7497. */
  7498. constructor(name, spec, node)
  7499. {
  7500. super(name, spec, node);
  7501. /** @type {SpeedyPipelineMessage} cached message */
  7502. this._cachedMessage = null;
  7503. }
  7504. /**
  7505. * Connect this port to another
  7506. * @param {SpeedyPipelineInputPort} port
  7507. */
  7508. connectTo(port)
  7509. {
  7510. if(!port.isInputPort())
  7511. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Can't connect output port ${this.name} to port ${port.name}: expected an input port`);
  7512. port.connectTo(this);
  7513. }
  7514. /**
  7515. * Is this an input port?
  7516. * @returns {boolean}
  7517. */
  7518. isInputPort()
  7519. {
  7520. return false;
  7521. }
  7522. /**
  7523. * Write a message to this port
  7524. * @param {SpeedyPipelineMessage} message
  7525. */
  7526. write(message)
  7527. {
  7528. if(!this._spec.accepts(message))
  7529. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Can't write ${message} to port ${this.name}. ${this._spec}`);
  7530. this._message = message;
  7531. }
  7532. /**
  7533. * Write a message to this port using a cached message object
  7534. * @param {...any} args to be passed to SpeedyPipelineMessage.set()
  7535. */
  7536. swrite(...args)
  7537. {
  7538. if(this._cachedMessage == null)
  7539. this._cachedMessage = _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessage.create(this._spec.expectedMessageType);
  7540. this.write(this._cachedMessage.set(...args));
  7541. }
  7542. /**
  7543. * Default port name
  7544. * @returns {string}
  7545. */
  7546. static get DEFAULT_NAME()
  7547. {
  7548. return DEFAULT_OUTPUT_PORT_NAME;
  7549. }
  7550. }
  7551. /**
  7552. * Input port
  7553. */
  7554. class SpeedyPipelineInputPort extends SpeedyPipelinePort
  7555. {
  7556. /**
  7557. * Constructor
  7558. * @param {string} name the name of this port
  7559. * @param {SpeedyPipelinePortSpec} spec port specification
  7560. * @param {SpeedyPipelineNode} node the node to which this port belongs
  7561. */
  7562. constructor(name, spec, node)
  7563. {
  7564. super(name, spec, node);
  7565. /** @type {SpeedyPipelineOutputPort|null} incoming link */
  7566. this._incomingLink = null;
  7567. }
  7568. /**
  7569. * Incoming link
  7570. * @returns {SpeedyPipelineOutputPort|null}
  7571. */
  7572. get incomingLink()
  7573. {
  7574. return this._incomingLink;
  7575. }
  7576. /**
  7577. * Connect this port to another
  7578. * @param {SpeedyPipelineOutputPort} port
  7579. */
  7580. connectTo(port)
  7581. {
  7582. if(!port.isOutputPort())
  7583. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Can't connect input port ${this.name} of "${this.node.fullName}" to input port ${port.name} of "${port.node.fullName}": expected an output port`);
  7584. else if(!this._spec.isCompatibleWith(port._spec))
  7585. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Can't connect port ${this.name} of "${this.node.fullName}" to port ${port.name} of "${port.node.fullName}": incompatible types`);
  7586. this._incomingLink = port;
  7587. }
  7588. /**
  7589. * Unlink this port
  7590. */
  7591. disconnect()
  7592. {
  7593. this._incomingLink = null;
  7594. }
  7595. /**
  7596. * Is this an input port?
  7597. * @returns {boolean}
  7598. */
  7599. isInputPort()
  7600. {
  7601. return true;
  7602. }
  7603. /**
  7604. * Receive a message using the incoming link
  7605. * @param {string} [nodeName]
  7606. * @returns {SpeedyPipelineMessage}
  7607. */
  7608. pullMessage(nodeName = '')
  7609. {
  7610. const name = nodeName.length > 0 ? `${this.name} of ${nodeName}` : this.name;
  7611. if(this._incomingLink == null)
  7612. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(`No incoming link for input port ${name}`);
  7613. const message = this._incomingLink.read();
  7614. if(!this._spec.accepts(message))
  7615. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Can't receive ${message} at port ${name}: ${this._spec}`);
  7616. return (this._message = message);
  7617. }
  7618. /**
  7619. * Default port name
  7620. * @returns {string}
  7621. */
  7622. static get DEFAULT_NAME()
  7623. {
  7624. return DEFAULT_INPUT_PORT_NAME;
  7625. }
  7626. }
  7627. /***/ }),
  7628. /***/ "./src/core/pipeline/pipeline-portbuilder.js":
  7629. /*!***************************************************!*\
  7630. !*** ./src/core/pipeline/pipeline-portbuilder.js ***!
  7631. \***************************************************/
  7632. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_357107__) => {
  7633. "use strict";
  7634. __nested_webpack_require_357107__.r(__webpack_exports__);
  7635. /* harmony export */ __nested_webpack_require_357107__.d(__webpack_exports__, {
  7636. /* harmony export */ "SpeedyPipelinePortBuilder": () => (/* binding */ SpeedyPipelinePortBuilder),
  7637. /* harmony export */ "InputPort": () => (/* binding */ InputPort),
  7638. /* harmony export */ "OutputPort": () => (/* binding */ OutputPort)
  7639. /* harmony export */ });
  7640. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_357107__(/*! ../../utils/utils */ "./src/utils/utils.js");
  7641. /* harmony import */ var _pipeline_port__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_357107__(/*! ./pipeline-port */ "./src/core/pipeline/pipeline-port.js");
  7642. /* harmony import */ var _pipeline_portspec__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_357107__(/*! ./pipeline-portspec */ "./src/core/pipeline/pipeline-portspec.js");
  7643. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_357107__(/*! ./pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  7644. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_357107__(/*! ./pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  7645. /*
  7646. * speedy-vision.js
  7647. * GPU-accelerated Computer Vision for JavaScript
  7648. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  7649. *
  7650. * Licensed under the Apache License, Version 2.0 (the "License");
  7651. * you may not use this file except in compliance with the License.
  7652. * You may obtain a copy of the License at
  7653. *
  7654. * http://www.apache.org/licenses/LICENSE-2.0
  7655. *
  7656. * Unless required by applicable law or agreed to in writing, software
  7657. * distributed under the License is distributed on an "AS IS" BASIS,
  7658. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  7659. * See the License for the specific language governing permissions and
  7660. * limitations under the License.
  7661. *
  7662. * pipeline-portbuilder.js
  7663. * Builder of a port of a node of a pipeline
  7664. */
  7665. /**
  7666. * @typedef {import('./pipeline-portspec').SpeedyPipelineMessageConstraint} SpeedyPipelineMessageConstraint
  7667. */
  7668. /**
  7669. * Builder of a port of a node of a pipeline
  7670. */
  7671. class SpeedyPipelinePortBuilder
  7672. {
  7673. /**
  7674. * Constructor
  7675. * @param {typeof SpeedyPipelinePort} portClass input or output?
  7676. * @param {string} portName
  7677. */
  7678. constructor(portClass, portName)
  7679. {
  7680. /** @type {typeof SpeedyPipelinePort} input or output? */
  7681. this._class = portClass;
  7682. /** @type {string} port name */
  7683. this._name = String(portName);
  7684. /** @type {SpeedyPipelineMessageType} accepted message type */
  7685. this._type = _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessageType.Nothing;
  7686. /** @type {SpeedyPipelineMessageConstraint} message validation function */
  7687. this._messageConstraint = undefined;
  7688. }
  7689. /**
  7690. * Declare that the new port expects a certain type of message
  7691. * @param {SpeedyPipelineMessageType} type expected type
  7692. * @returns {SpeedyPipelinePortBuilder} this builder
  7693. */
  7694. expects(type)
  7695. {
  7696. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._type == _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessageType.Nothing);
  7697. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(type != _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessageType.Nothing);
  7698. this._type = type;
  7699. return this;
  7700. }
  7701. /**
  7702. * Declare that the new port expects messages satisfying a constraint
  7703. * @param {SpeedyPipelineMessageConstraint} constraint
  7704. * @returns {SpeedyPipelinePortBuilder} this builder
  7705. */
  7706. satisfying(constraint)
  7707. {
  7708. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._type != _pipeline_message__WEBPACK_IMPORTED_MODULE_3__.SpeedyPipelineMessageType.Nothing, 'You must first declare what type of message this port expects');
  7709. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._messageConstraint === undefined);
  7710. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(typeof constraint === 'function');
  7711. this._messageConstraint = constraint;
  7712. return this;
  7713. }
  7714. /**
  7715. * Build a port
  7716. * @param {SpeedyPipelineNode} node the node to which the new port will belong
  7717. * @returns {SpeedyPipelinePort}
  7718. */
  7719. build(node)
  7720. {
  7721. const spec = new _pipeline_portspec__WEBPACK_IMPORTED_MODULE_2__.SpeedyPipelinePortSpec(this._type, this._messageConstraint);
  7722. return Reflect.construct(this._class, [this._name, spec, node]);
  7723. }
  7724. }
  7725. /**
  7726. * Creates a builder for an input port
  7727. * @param {string} [portName]
  7728. * @returns {SpeedyPipelinePortBuilder}
  7729. */
  7730. function InputPort(portName = _pipeline_port__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineInputPort.DEFAULT_NAME)
  7731. {
  7732. return new SpeedyPipelinePortBuilder(_pipeline_port__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineInputPort, portName);
  7733. }
  7734. /**
  7735. * Creates a builder for an output port
  7736. * @param {string} [portName]
  7737. * @returns {SpeedyPipelinePortBuilder}
  7738. */
  7739. function OutputPort(portName = _pipeline_port__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineOutputPort.DEFAULT_NAME)
  7740. {
  7741. return new SpeedyPipelinePortBuilder(_pipeline_port__WEBPACK_IMPORTED_MODULE_1__.SpeedyPipelineOutputPort, portName);
  7742. }
  7743. /***/ }),
  7744. /***/ "./src/core/pipeline/pipeline-portspec.js":
  7745. /*!************************************************!*\
  7746. !*** ./src/core/pipeline/pipeline-portspec.js ***!
  7747. \************************************************/
  7748. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_362679__) => {
  7749. "use strict";
  7750. __nested_webpack_require_362679__.r(__webpack_exports__);
  7751. /* harmony export */ __nested_webpack_require_362679__.d(__webpack_exports__, {
  7752. /* harmony export */ "SpeedyPipelinePortSpec": () => (/* binding */ SpeedyPipelinePortSpec)
  7753. /* harmony export */ });
  7754. /* harmony import */ var _pipeline_message__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_362679__(/*! ./pipeline-message */ "./src/core/pipeline/pipeline-message.js");
  7755. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_362679__(/*! ../../utils/utils */ "./src/utils/utils.js");
  7756. /*
  7757. * speedy-vision.js
  7758. * GPU-accelerated Computer Vision for JavaScript
  7759. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  7760. *
  7761. * Licensed under the Apache License, Version 2.0 (the "License");
  7762. * you may not use this file except in compliance with the License.
  7763. * You may obtain a copy of the License at
  7764. *
  7765. * http://www.apache.org/licenses/LICENSE-2.0
  7766. *
  7767. * Unless required by applicable law or agreed to in writing, software
  7768. * distributed under the License is distributed on an "AS IS" BASIS,
  7769. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  7770. * See the License for the specific language governing permissions and
  7771. * limitations under the License.
  7772. *
  7773. * pipeline-portspec.js
  7774. * Specification (requirements) of a port of a node of a pipeline
  7775. */
  7776. /**
  7777. * A message constraint is a message validation predicate
  7778. * @typedef {function(SpeedyPipelineMessage): boolean} SpeedyPipelineMessageConstraint
  7779. */
  7780. /**
  7781. * A validation predicate that validates all messages
  7782. * @type {SpeedyPipelineMessageConstraint}
  7783. */
  7784. const none = message => true;
  7785. /**
  7786. * Specification (requirements) of a port of a node of a pipeline
  7787. */
  7788. class SpeedyPipelinePortSpec
  7789. {
  7790. /**
  7791. * Constructor
  7792. * @param {SpeedyPipelineMessageType} expectedMessageType expected message type
  7793. * @param {SpeedyPipelineMessageConstraint} [messageConstraint] message validation function
  7794. */
  7795. constructor(expectedMessageType, messageConstraint = none)
  7796. {
  7797. /** @type {SpeedyPipelineMessageType} expected message type */
  7798. this._expectedMessageType = expectedMessageType;
  7799. /** @type {SpeedyPipelineMessageConstraint} message validation function */
  7800. this._isValidMessage = (typeof messageConstraint === 'function') ? messageConstraint : none;
  7801. // expect a valid type
  7802. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(this._expectedMessageType != _pipeline_message__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineMessageType.Nothing);
  7803. }
  7804. /**
  7805. * Checks if two specs have the same expected type
  7806. * @param {SpeedyPipelinePortSpec} spec
  7807. * @returns {boolean}
  7808. */
  7809. isCompatibleWith(spec)
  7810. {
  7811. return this._expectedMessageType == spec._expectedMessageType;
  7812. }
  7813. /**
  7814. * Is the given message accepted by a port that abides by this specification?
  7815. * @param {SpeedyPipelineMessage} message
  7816. * @returns {boolean}
  7817. */
  7818. accepts(message)
  7819. {
  7820. return message.hasType(this._expectedMessageType) && this._isValidMessage(message);
  7821. }
  7822. /**
  7823. * Convert to string
  7824. * @returns {string}
  7825. */
  7826. toString()
  7827. {
  7828. const type = Object.keys(_pipeline_message__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineMessageType).find(
  7829. type => _pipeline_message__WEBPACK_IMPORTED_MODULE_0__.SpeedyPipelineMessageType[type] === this._expectedMessageType
  7830. );
  7831. return `Port expects ${type} satisfying ${this._isValidMessage}`;
  7832. }
  7833. /**
  7834. * Expected message type
  7835. * @returns {SpeedyPipelineMessageType}
  7836. */
  7837. get expectedMessageType()
  7838. {
  7839. return this._expectedMessageType;
  7840. }
  7841. }
  7842. /***/ }),
  7843. /***/ "./src/core/pipeline/pipeline.js":
  7844. /*!***************************************!*\
  7845. !*** ./src/core/pipeline/pipeline.js ***!
  7846. \***************************************/
  7847. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_366642__) => {
  7848. "use strict";
  7849. __nested_webpack_require_366642__.r(__webpack_exports__);
  7850. /* harmony export */ __nested_webpack_require_366642__.d(__webpack_exports__, {
  7851. /* harmony export */ "SpeedyPipeline": () => (/* binding */ SpeedyPipeline)
  7852. /* harmony export */ });
  7853. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_366642__(/*! ../../utils/utils */ "./src/utils/utils.js");
  7854. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_366642__(/*! ../speedy-promise */ "./src/core/speedy-promise.js");
  7855. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_366642__(/*! ../../utils/errors */ "./src/utils/errors.js");
  7856. /* harmony import */ var _pipeline_node__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_366642__(/*! ./pipeline-node */ "./src/core/pipeline/pipeline-node.js");
  7857. /* harmony import */ var _pipeline_port__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_366642__(/*! ./pipeline-port */ "./src/core/pipeline/pipeline-port.js");
  7858. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_366642__(/*! ../../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  7859. /* harmony import */ var _speedy_media__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_366642__(/*! ../speedy-media */ "./src/core/speedy-media.js");
  7860. /* harmony import */ var _speedy_keypoint__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_366642__(/*! ../speedy-keypoint */ "./src/core/speedy-keypoint.js");
  7861. /*
  7862. * speedy-vision.js
  7863. * GPU-accelerated Computer Vision for JavaScript
  7864. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  7865. *
  7866. * Licensed under the Apache License, Version 2.0 (the "License");
  7867. * you may not use this file except in compliance with the License.
  7868. * You may obtain a copy of the License at
  7869. *
  7870. * http://www.apache.org/licenses/LICENSE-2.0
  7871. *
  7872. * Unless required by applicable law or agreed to in writing, software
  7873. * distributed under the License is distributed on an "AS IS" BASIS,
  7874. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  7875. * See the License for the specific language governing permissions and
  7876. * limitations under the License.
  7877. *
  7878. * pipeline.js
  7879. * A pipeline is a network of nodes in which data flows to a sink
  7880. */
  7881. /**
  7882. * A dictionary indexed by the names of the sink nodes
  7883. * @typedef {Object<string,any>} SpeedyPipelineOutput
  7884. */
  7885. /** @type {SpeedyGPU} shared GPU programs & textures */
  7886. let gpu = null;
  7887. /** @type {number} gpu reference count */
  7888. let referenceCount = 0;
  7889. /**
  7890. * A pipeline is a network of nodes in which data flows to a sink
  7891. */
  7892. class SpeedyPipeline
  7893. {
  7894. /**
  7895. * Constructor
  7896. */
  7897. constructor()
  7898. {
  7899. /** @type {SpeedyPipelineNode[]} the collection of all nodes that belong to this pipeline */
  7900. this._nodes = [];
  7901. /** @type {SpeedyPipelineNode[]} a sequence of nodes: from the source(s) to the sink */
  7902. this._sequence = [];
  7903. /** @type {boolean} are we running the pipeline at this moment? */
  7904. this._busy = false;
  7905. }
  7906. /**
  7907. * Find a node by its name
  7908. * @template T extends SpeedyPipelineNode
  7909. * @param {string} name
  7910. * @returns {T|null}
  7911. */
  7912. node(name)
  7913. {
  7914. for(let i = 0, n = this._nodes.length; i < n; i++) {
  7915. if(this._nodes[i].name === name)
  7916. return this._nodes[i];
  7917. }
  7918. return null;
  7919. }
  7920. /**
  7921. * Initialize the pipeline
  7922. * @param {...SpeedyPipelineNode} nodes
  7923. * @returns {SpeedyPipeline} this pipeline
  7924. */
  7925. init(...nodes)
  7926. {
  7927. // validate
  7928. if(this._nodes.length > 0)
  7929. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`The pipeline has already been initialized`);
  7930. else if(nodes.length == 0)
  7931. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Can't initialize the pipeline. Please specify its nodes`);
  7932. // create a GPU instance and increase the reference count
  7933. if(0 == referenceCount++) {
  7934. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(!gpu, 'Duplicate SpeedyGPU instance');
  7935. gpu = new _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_5__.SpeedyGPU();
  7936. }
  7937. // add nodes to the network
  7938. for(let i = 0; i < nodes.length; i++) {
  7939. const node = nodes[i];
  7940. if(!this._nodes.includes(node))
  7941. this._nodes.push(node);
  7942. }
  7943. // generate the sequence of nodes
  7944. this._sequence = SpeedyPipeline._tsort(this._nodes);
  7945. SpeedyPipeline._validateSequence(this._sequence);
  7946. // initialize nodes
  7947. for(let i = 0; i < this._sequence.length; i++)
  7948. this._sequence[i].init(gpu);
  7949. // done!
  7950. return this;
  7951. }
  7952. /**
  7953. * Release the resources associated with this pipeline
  7954. * @returns {null}
  7955. */
  7956. release()
  7957. {
  7958. if(this._nodes.length == 0)
  7959. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`The pipeline has already been released or has never been initialized`);
  7960. // release nodes
  7961. for(let i = this._sequence.length - 1; i >= 0; i--)
  7962. this._sequence[i].release(gpu);
  7963. this._sequence.length = 0;
  7964. this._nodes.length = 0;
  7965. // decrease reference count and release GPU if necessary
  7966. if(0 == --referenceCount)
  7967. gpu = gpu.release();
  7968. // done!
  7969. return null;
  7970. }
  7971. /**
  7972. * Run the pipeline
  7973. * @returns {SpeedyPromise<SpeedyPipelineOutput>} results are indexed by the names of the sink nodes
  7974. */
  7975. run()
  7976. {
  7977. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._sequence.length > 0, `The pipeline has not been initialized or has been released`);
  7978. // is the pipeline busy?
  7979. if(this._busy) {
  7980. // if so, we need to wait 'til it finishes
  7981. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise((resolve, reject) => {
  7982. setTimeout(() => this.run().then(resolve, reject), 0);
  7983. });
  7984. }
  7985. else {
  7986. // the pipeline is now busy and won't accept concurrent tasks
  7987. // (we allocate textures using a single pool)
  7988. this._busy = true;
  7989. }
  7990. // find the sinks
  7991. const sinks = /** @type {SpeedyPipelineSinkNode[]} */ ( this._sequence.filter(node => node.isSink()) );
  7992. // create output template
  7993. const template = SpeedyPipeline._createOutputTemplate(sinks);
  7994. // run the pipeline
  7995. return SpeedyPipeline._runSequence(this._sequence).then(() =>
  7996. // export results
  7997. _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise.all(sinks.map(sink => sink.export().turbocharge())).then(results =>
  7998. // aggregate results by the names of the sinks
  7999. results.reduce((obj, val, idx) => ((obj[sinks[idx].name] = val), obj), template)
  8000. )
  8001. ).finally(() => {
  8002. // clear all ports
  8003. for(let i = this._sequence.length - 1; i >= 0; i--)
  8004. this._sequence[i].clearPorts();
  8005. // the pipeline is no longer busy
  8006. this._busy = false;
  8007. }).turbocharge();
  8008. }
  8009. /**
  8010. * @internal
  8011. *
  8012. * GPU instance
  8013. * @returns {SpeedyGPU}
  8014. */
  8015. get _gpu()
  8016. {
  8017. return gpu;
  8018. }
  8019. /**
  8020. * Execute the tasks of a sequence of nodes
  8021. * @param {SpeedyPipelineNode[]} sequence sequence of nodes
  8022. * @param {number} [i] in [0,n)
  8023. * @param {number} [n] number of nodes
  8024. * @returns {SpeedyPromise<void>}
  8025. */
  8026. static _runSequence(sequence, i = 0, n = sequence.length)
  8027. {
  8028. for(; i < n; i++) {
  8029. const runTask = sequence[i].execute(gpu);
  8030. // this call greatly improves performance when downloading pixel data using PBOs
  8031. gpu.gl.flush();
  8032. if(typeof runTask !== 'undefined')
  8033. return runTask.then(() => SpeedyPipeline._runSequence(sequence, i+1, n));
  8034. }
  8035. return _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise.resolve();
  8036. }
  8037. /**
  8038. * Topological sorting
  8039. * @param {SpeedyPipelineNode[]} nodes
  8040. * @returns {SpeedyPipelineNode[]}
  8041. */
  8042. static _tsort(nodes)
  8043. {
  8044. /** @typedef {[SpeedyPipelineNode, boolean]} StackNode */
  8045. const outlinks = SpeedyPipeline._outlinks(nodes);
  8046. const stack = nodes.map(node => /** @type {StackNode} */ ([ node, false ]) );
  8047. const trash = new Set();
  8048. const sorted = new Array(nodes.length);
  8049. let j = sorted.length;
  8050. while(stack.length > 0) {
  8051. const [ node, done ] = stack.pop();
  8052. if(!done) {
  8053. if(!trash.has(node)) {
  8054. const outnodes = outlinks.get(node);
  8055. trash.add(node);
  8056. stack.push([ node, true ]);
  8057. stack.push(...(outnodes.map(node => /** @type {StackNode} */ ([ node, false ]) )));
  8058. if(outnodes.some(node => trash.has(node) && !sorted.includes(node)))
  8059. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Pipeline networks cannot have cycles!`);
  8060. }
  8061. }
  8062. else
  8063. sorted[--j] = node;
  8064. }
  8065. return sorted;
  8066. }
  8067. /**
  8068. * Figure out the outgoing links of all nodes
  8069. * @param {SpeedyPipelineNode[]} nodes
  8070. * @returns {Map<SpeedyPipelineNode,SpeedyPipelineNode[]>}
  8071. */
  8072. static _outlinks(nodes)
  8073. {
  8074. const outlinks = new Map();
  8075. for(let k = 0; k < nodes.length; k++)
  8076. outlinks.set(nodes[k], []);
  8077. for(let i = 0; i < nodes.length; i++) {
  8078. const to = nodes[i];
  8079. const inputs = to.inputNodes();
  8080. for(let j = 0; j < inputs.length; j++) {
  8081. const from = inputs[j];
  8082. const links = outlinks.get(from);
  8083. if(!links)
  8084. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Can't initialize the pipeline. Missing node: ${from.fullName}. Did you forget to add it to the initialization list?`);
  8085. if(!links.includes(to))
  8086. links.push(to);
  8087. }
  8088. }
  8089. return outlinks;
  8090. }
  8091. /**
  8092. * Generate the output template by aggregating the names of the sinks
  8093. * @param {SpeedyPipelineNode[]} [sinks]
  8094. * @returns {SpeedyPipelineOutput}
  8095. */
  8096. static _createOutputTemplate(sinks = [])
  8097. {
  8098. const template = Object.create(null);
  8099. for(let i = sinks.length - 1; i >= 0; i--)
  8100. template[sinks[i].name] = null;
  8101. return template;
  8102. }
  8103. /**
  8104. * Validate a sequence of nodes
  8105. * @param {SpeedyPipelineNode[]} sequence
  8106. */
  8107. static _validateSequence(sequence)
  8108. {
  8109. if(sequence.length == 0)
  8110. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Pipeline doesn't have nodes`);
  8111. else if(!sequence[0].isSource())
  8112. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Pipeline doesn't have a source`);
  8113. else if(!sequence.find(node => node.isSink()))
  8114. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Pipeline doesn't have a sink`);
  8115. }
  8116. }
  8117. /***/ }),
  8118. /***/ "./src/core/settings.js":
  8119. /*!******************************!*\
  8120. !*** ./src/core/settings.js ***!
  8121. \******************************/
  8122. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_378214__) => {
  8123. "use strict";
  8124. __nested_webpack_require_378214__.r(__webpack_exports__);
  8125. /* harmony export */ __nested_webpack_require_378214__.d(__webpack_exports__, {
  8126. /* harmony export */ "Settings": () => (/* binding */ Settings)
  8127. /* harmony export */ });
  8128. /* harmony import */ var _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_378214__(/*! ./speedy-namespace */ "./src/core/speedy-namespace.js");
  8129. /* harmony import */ var _gpu_speedy_gl__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_378214__(/*! ../gpu/speedy-gl */ "./src/gpu/speedy-gl.js");
  8130. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_378214__(/*! ../utils/errors */ "./src/utils/errors.js");
  8131. /*
  8132. * speedy-vision.js
  8133. * GPU-accelerated Computer Vision for JavaScript
  8134. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  8135. *
  8136. * Licensed under the Apache License, Version 2.0 (the "License");
  8137. * you may not use this file except in compliance with the License.
  8138. * You may obtain a copy of the License at
  8139. *
  8140. * http://www.apache.org/licenses/LICENSE-2.0
  8141. *
  8142. * Unless required by applicable law or agreed to in writing, software
  8143. * distributed under the License is distributed on an "AS IS" BASIS,
  8144. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  8145. * See the License for the specific language governing permissions and
  8146. * limitations under the License.
  8147. *
  8148. * settings.js
  8149. * Global settings
  8150. */
  8151. /** @typedef {import('../gpu/speedy-gl').PowerPreference} PowerPreference */
  8152. /** @typedef {"raf" | "asap"} GPUPollingMode */
  8153. /** @type {GPUPollingMode} Default GPU polling mode */
  8154. const DEFAULT_GPU_POLLING_MODE = 'raf';
  8155. /** @type {GPUPollingMode} GPU polling mode */
  8156. let gpuPollingMode = DEFAULT_GPU_POLLING_MODE;
  8157. /**
  8158. * Global settings
  8159. */
  8160. class Settings extends _speedy_namespace__WEBPACK_IMPORTED_MODULE_0__.SpeedyNamespace
  8161. {
  8162. /**
  8163. * Power preference of the WebGL context
  8164. * @returns {PowerPreference}
  8165. */
  8166. static get powerPreference()
  8167. {
  8168. return _gpu_speedy_gl__WEBPACK_IMPORTED_MODULE_1__.SpeedyGL.powerPreference;
  8169. }
  8170. /**
  8171. * Power preference of the WebGL context
  8172. * @param {PowerPreference} value
  8173. */
  8174. static set powerPreference(value)
  8175. {
  8176. _gpu_speedy_gl__WEBPACK_IMPORTED_MODULE_1__.SpeedyGL.powerPreference = value;
  8177. }
  8178. /**
  8179. * GPU polling mode
  8180. * @returns {GPUPollingMode}
  8181. */
  8182. static get gpuPollingMode()
  8183. {
  8184. return gpuPollingMode;
  8185. }
  8186. /**
  8187. * GPU polling mode
  8188. * @param {GPUPollingMode} value
  8189. */
  8190. static set gpuPollingMode(value)
  8191. {
  8192. if(value !== 'raf' && value !== 'asap')
  8193. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Invalid GPU polling mode: "${value}"`);
  8194. gpuPollingMode = value;
  8195. }
  8196. }
  8197. /***/ }),
  8198. /***/ "./src/core/speedy-keypoint-descriptor.js":
  8199. /*!************************************************!*\
  8200. !*** ./src/core/speedy-keypoint-descriptor.js ***!
  8201. \************************************************/
  8202. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_381293__) => {
  8203. "use strict";
  8204. __nested_webpack_require_381293__.r(__webpack_exports__);
  8205. /* harmony export */ __nested_webpack_require_381293__.d(__webpack_exports__, {
  8206. /* harmony export */ "SpeedyKeypointDescriptor": () => (/* binding */ SpeedyKeypointDescriptor)
  8207. /* harmony export */ });
  8208. /*
  8209. * speedy-vision.js
  8210. * GPU-accelerated Computer Vision for JavaScript
  8211. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  8212. *
  8213. * Licensed under the Apache License, Version 2.0 (the "License");
  8214. * you may not use this file except in compliance with the License.
  8215. * You may obtain a copy of the License at
  8216. *
  8217. * http://www.apache.org/licenses/LICENSE-2.0
  8218. *
  8219. * Unless required by applicable law or agreed to in writing, software
  8220. * distributed under the License is distributed on an "AS IS" BASIS,
  8221. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  8222. * See the License for the specific language governing permissions and
  8223. * limitations under the License.
  8224. *
  8225. * speedy-keypoint-descriptor.js
  8226. * Keypoint descriptor
  8227. */
  8228. /**
  8229. * Represents a keypoint descriptor
  8230. */
  8231. class SpeedyKeypointDescriptor
  8232. {
  8233. /**
  8234. * Constructor
  8235. * @param {Uint8Array} data descriptor bytes
  8236. */
  8237. constructor(data)
  8238. {
  8239. this._data = data;
  8240. return Object.freeze(this);
  8241. }
  8242. /**
  8243. * Descriptor data
  8244. * @returns {Uint8Array}
  8245. */
  8246. get data()
  8247. {
  8248. return this._data;
  8249. }
  8250. /**
  8251. * The size of the descriptor, in bytes
  8252. * @returns {number}
  8253. */
  8254. get size()
  8255. {
  8256. return this._data.byteLength;
  8257. }
  8258. /**
  8259. * A string representation of the keypoint descriptor
  8260. * @returns {string}
  8261. */
  8262. toString()
  8263. {
  8264. return `SpeedyKeypointDescriptor(${this._data.join(',')})`;
  8265. }
  8266. }
  8267. /***/ }),
  8268. /***/ "./src/core/speedy-keypoint-match.js":
  8269. /*!*******************************************!*\
  8270. !*** ./src/core/speedy-keypoint-match.js ***!
  8271. \*******************************************/
  8272. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_383313__) => {
  8273. "use strict";
  8274. __nested_webpack_require_383313__.r(__webpack_exports__);
  8275. /* harmony export */ __nested_webpack_require_383313__.d(__webpack_exports__, {
  8276. /* harmony export */ "SpeedyKeypointMatch": () => (/* binding */ SpeedyKeypointMatch)
  8277. /* harmony export */ });
  8278. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_383313__(/*! ../utils/globals */ "./src/utils/globals.js");
  8279. /*
  8280. * speedy-vision.js
  8281. * GPU-accelerated Computer Vision for JavaScript
  8282. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  8283. *
  8284. * Licensed under the Apache License, Version 2.0 (the "License");
  8285. * you may not use this file except in compliance with the License.
  8286. * You may obtain a copy of the License at
  8287. *
  8288. * http://www.apache.org/licenses/LICENSE-2.0
  8289. *
  8290. * Unless required by applicable law or agreed to in writing, software
  8291. * distributed under the License is distributed on an "AS IS" BASIS,
  8292. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  8293. * See the License for the specific language governing permissions and
  8294. * limitations under the License.
  8295. *
  8296. * speedy-match.js
  8297. * A match between two keypoint descriptors
  8298. */
  8299. // Constants
  8300. const MATCH_NOT_FOUND = -1;
  8301. /**
  8302. * A match between two keypoint descriptors
  8303. */
  8304. class SpeedyKeypointMatch
  8305. {
  8306. /**
  8307. * Constructor
  8308. * @param {number} index index of the stored keypoint, a non-negative integer
  8309. * @param {number} distance a measure of the quality of the match, a non-negative number
  8310. */
  8311. constructor(index, distance)
  8312. {
  8313. const isValid = distance < _utils_globals__WEBPACK_IMPORTED_MODULE_0__.MATCH_MAX_DISTANCE;
  8314. /** @type {number} index of the stored keypoint */
  8315. this._index = isValid ? (index | 0) : MATCH_NOT_FOUND;
  8316. /** @type {number} a measure of the quality of the match */
  8317. this._distance = isValid ? +distance : Number.POSITIVE_INFINITY;
  8318. // done!
  8319. return Object.freeze(this);
  8320. }
  8321. /**
  8322. * The index of the stored keypoint
  8323. * @returns {number}
  8324. */
  8325. get index()
  8326. {
  8327. return this._index;
  8328. }
  8329. /**
  8330. * A measure of the quality of the match (lower values indicate better matches)
  8331. * @returns {number}
  8332. */
  8333. get distance()
  8334. {
  8335. return this._distance;
  8336. }
  8337. /**
  8338. * A string representation of the keypoint match
  8339. * @returns {string}
  8340. */
  8341. toString()
  8342. {
  8343. return `SpeedyKeypointMatch(${this.index},${this.distance})`;
  8344. }
  8345. }
  8346. /***/ }),
  8347. /***/ "./src/core/speedy-keypoint.js":
  8348. /*!*************************************!*\
  8349. !*** ./src/core/speedy-keypoint.js ***!
  8350. \*************************************/
  8351. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_386036__) => {
  8352. "use strict";
  8353. __nested_webpack_require_386036__.r(__webpack_exports__);
  8354. /* harmony export */ __nested_webpack_require_386036__.d(__webpack_exports__, {
  8355. /* harmony export */ "SpeedyKeypoint": () => (/* binding */ SpeedyKeypoint),
  8356. /* harmony export */ "SpeedyTrackedKeypoint": () => (/* binding */ SpeedyTrackedKeypoint),
  8357. /* harmony export */ "SpeedyMatchedKeypoint": () => (/* binding */ SpeedyMatchedKeypoint)
  8358. /* harmony export */ });
  8359. /* harmony import */ var _speedy_keypoint_descriptor__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_386036__(/*! ./speedy-keypoint-descriptor */ "./src/core/speedy-keypoint-descriptor.js");
  8360. /* harmony import */ var _speedy_keypoint_match__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_386036__(/*! ./speedy-keypoint-match */ "./src/core/speedy-keypoint-match.js");
  8361. /* harmony import */ var _speedy_point__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_386036__(/*! ./speedy-point */ "./src/core/speedy-point.js");
  8362. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_386036__(/*! ./speedy-vector */ "./src/core/speedy-vector.js");
  8363. /*
  8364. * speedy-vision.js
  8365. * GPU-accelerated Computer Vision for JavaScript
  8366. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  8367. *
  8368. * Licensed under the Apache License, Version 2.0 (the "License");
  8369. * you may not use this file except in compliance with the License.
  8370. * You may obtain a copy of the License at
  8371. *
  8372. * http://www.apache.org/licenses/LICENSE-2.0
  8373. *
  8374. * Unless required by applicable law or agreed to in writing, software
  8375. * distributed under the License is distributed on an "AS IS" BASIS,
  8376. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  8377. * See the License for the specific language governing permissions and
  8378. * limitations under the License.
  8379. *
  8380. * speedy-keypoint.js
  8381. * Keypoint class
  8382. */
  8383. /**
  8384. * Represents a keypoint
  8385. */
  8386. class SpeedyKeypoint
  8387. {
  8388. /**
  8389. * Constructor
  8390. * @param {number} x X position
  8391. * @param {number} y Y position
  8392. * @param {number} [lod] Level-of-detail
  8393. * @param {number} [rotation] Rotation in radians
  8394. * @param {number} [score] Cornerness measure
  8395. * @param {SpeedyKeypointDescriptor|null} [descriptor] Keypoint descriptor, if any
  8396. */
  8397. constructor(x, y, lod = 0.0, rotation = 0.0, score = 0.0, descriptor = null)
  8398. {
  8399. /** @type {SpeedyPoint2} keypoint position */
  8400. this._position = new _speedy_point__WEBPACK_IMPORTED_MODULE_2__.SpeedyPoint2(+x, +y);
  8401. /** @type {number} level of detail */
  8402. this._lod = +lod;
  8403. /** @type {number} rotation in radians */
  8404. this._rotation = +rotation;
  8405. /** @type {number} a cornerness measure */
  8406. this._score = +score;
  8407. /** @type {SpeedyKeypointDescriptor|null} keypoint descriptor, if any */
  8408. this._descriptor = descriptor;
  8409. }
  8410. /**
  8411. * Converts this keypoint to a descriptive string
  8412. * @returns {string}
  8413. */
  8414. toString()
  8415. {
  8416. return `SpeedyKeypoint(${this.x},${this.y})`;
  8417. }
  8418. /**
  8419. * The position of this keypoint
  8420. * @returns {SpeedyPoint2}
  8421. */
  8422. get position()
  8423. {
  8424. return this._position;
  8425. }
  8426. /**
  8427. * The x-position of this keypoint
  8428. * @returns {number}
  8429. */
  8430. get x()
  8431. {
  8432. return this._position.x;
  8433. }
  8434. /**
  8435. * The x-position of this keypoint
  8436. * @param {number} value
  8437. */
  8438. set x(value)
  8439. {
  8440. this._position.x = +value;
  8441. }
  8442. /**
  8443. * The y-position of this keypoint
  8444. * @returns {number}
  8445. */
  8446. get y()
  8447. {
  8448. return this._position.y;
  8449. }
  8450. /**
  8451. * The y-position of this keypoint
  8452. * @param {number} value
  8453. */
  8454. set y(value)
  8455. {
  8456. this._position.y = +value;
  8457. }
  8458. /**
  8459. * The pyramid level-of-detail from which this keypoint was extracted
  8460. * @returns {number}
  8461. */
  8462. get lod()
  8463. {
  8464. return this._lod;
  8465. }
  8466. /**
  8467. * Scale: 2^lod
  8468. * @returns {number}
  8469. */
  8470. get scale()
  8471. {
  8472. return Math.pow(2, this._lod);
  8473. }
  8474. /**
  8475. * The orientation of the keypoint, in radians
  8476. * @returns {number} Angle in radians
  8477. */
  8478. get rotation()
  8479. {
  8480. return this._rotation;
  8481. }
  8482. /**
  8483. * Score: a cornerness measure
  8484. * @returns {number} Score
  8485. */
  8486. get score()
  8487. {
  8488. return this._score;
  8489. }
  8490. /**
  8491. * Keypoint descriptor
  8492. * @return {SpeedyKeypointDescriptor|null}
  8493. */
  8494. get descriptor()
  8495. {
  8496. return this._descriptor;
  8497. }
  8498. }
  8499. /**
  8500. * Represents a tracked keypoint
  8501. */
  8502. class SpeedyTrackedKeypoint extends SpeedyKeypoint
  8503. {
  8504. /**
  8505. * Constructor
  8506. * @param {number} x X position
  8507. * @param {number} y Y position
  8508. * @param {number} [lod] Level-of-detail
  8509. * @param {number} [rotation] Rotation in radians
  8510. * @param {number} [score] Cornerness measure
  8511. * @param {SpeedyKeypointDescriptor|null} [descriptor] Keypoint descriptor, if any
  8512. * @param {SpeedyVector2} [flow] flow vector
  8513. */
  8514. constructor(x, y, lod = 0.0, rotation = 0.0, score = 0.0, descriptor = null, flow = new _speedy_vector__WEBPACK_IMPORTED_MODULE_3__.SpeedyVector2(0,0))
  8515. {
  8516. super(x, y, lod, rotation, score, descriptor);
  8517. /** @type {SpeedyVector2} flow vector */
  8518. this._flow = flow;
  8519. }
  8520. /**
  8521. * Flow vector
  8522. * @returns {SpeedyVector2}
  8523. */
  8524. get flow()
  8525. {
  8526. return this._flow;
  8527. }
  8528. }
  8529. /**
  8530. * Represents a matched keypoint
  8531. */
  8532. class SpeedyMatchedKeypoint extends SpeedyKeypoint
  8533. {
  8534. /**
  8535. * Constructor
  8536. * @param {number} x X position
  8537. * @param {number} y Y position
  8538. * @param {number} [lod] Level-of-detail
  8539. * @param {number} [rotation] Rotation in radians
  8540. * @param {number} [score] Cornerness measure
  8541. * @param {SpeedyKeypointDescriptor|null} [descriptor] Keypoint descriptor, if any
  8542. * @param {SpeedyKeypointMatch[]} [matches] Keypoint matches, if any
  8543. */
  8544. constructor(x, y, lod = 0.0, rotation = 0.0, score = 0.0, descriptor = null, matches = [])
  8545. {
  8546. super(x, y, lod, rotation, score, descriptor);
  8547. /** @type {SpeedyKeypointMatch[]} keypoint matches */
  8548. this._matches = matches;
  8549. }
  8550. /**
  8551. * Keypoint matches
  8552. * @returns {SpeedyKeypointMatch[]}
  8553. */
  8554. get matches()
  8555. {
  8556. return this._matches;
  8557. }
  8558. }
  8559. /***/ }),
  8560. /***/ "./src/core/speedy-matrix-expr.js":
  8561. /*!****************************************!*\
  8562. !*** ./src/core/speedy-matrix-expr.js ***!
  8563. \****************************************/
  8564. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_392606__) => {
  8565. "use strict";
  8566. __nested_webpack_require_392606__.r(__webpack_exports__);
  8567. /* harmony export */ __nested_webpack_require_392606__.d(__webpack_exports__, {
  8568. /* harmony export */ "SpeedyMatrixExpr": () => (/* binding */ SpeedyMatrixExpr)
  8569. /* harmony export */ });
  8570. /* harmony import */ var _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_392606__(/*! ./speedy-matrix-wasm */ "./src/core/speedy-matrix-wasm.js");
  8571. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_392606__(/*! ../utils/utils */ "./src/utils/utils.js");
  8572. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_392606__(/*! ../utils/errors */ "./src/utils/errors.js");
  8573. /*
  8574. * speedy-vision.js
  8575. * GPU-accelerated Computer Vision for JavaScript
  8576. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  8577. *
  8578. * Licensed under the Apache License, Version 2.0 (the "License");
  8579. * you may not use this file except in compliance with the License.
  8580. * You may obtain a copy of the License at
  8581. *
  8582. * http://www.apache.org/licenses/LICENSE-2.0
  8583. *
  8584. * Unless required by applicable law or agreed to in writing, software
  8585. * distributed under the License is distributed on an "AS IS" BASIS,
  8586. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  8587. * See the License for the specific language governing permissions and
  8588. * limitations under the License.
  8589. *
  8590. * speedy-matrix-expr.js
  8591. * Symbolic matrix expressions
  8592. */
  8593. /** @typedef {import('./speedy-matrix').SpeedyMatrixDtype} SpeedyMatrixDtype */
  8594. /** @typedef {import('./speedy-matrix').SpeedyMatrixBufferType} SpeedyMatrixBufferType */
  8595. /** @typedef {import('./speedy-matrix').SpeedyMatrixBufferTypeConstructor} SpeedyMatrixBufferTypeConstructor */
  8596. /** @typedef {import('./speedy-matrix-wasm').SpeedyMatrixWASMMemory} SpeedyMatrixWASMMemory */
  8597. /** @typedef {Object<SpeedyMatrixDtype,SpeedyMatrixBufferTypeConstructor>} Dtype2BufferType */
  8598. /** @const {Dtype2BufferType} */
  8599. const DTYPE_TO_BUFFER_TYPE = Object.freeze({
  8600. 'float32': Float32Array
  8601. });
  8602. /**
  8603. * @abstract Matrix expression
  8604. * It's an opaque object representing an algebraic
  8605. * expression. It has no data attached to it.
  8606. */
  8607. class SpeedyMatrixExpr
  8608. {
  8609. /**
  8610. * Constructor
  8611. * @param {number} rows
  8612. * @param {number} columns
  8613. * @param {SpeedyMatrixDtype} dtype
  8614. */
  8615. constructor(rows, columns, dtype)
  8616. {
  8617. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(rows > 0 && columns > 0);
  8618. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(dtype === SpeedyMatrixExpr.DEFAULT_DTYPE); // we only support float32 for now
  8619. /** @type {number} number of rows */
  8620. this._rows = rows | 0;
  8621. /** @type {number} number of columns */
  8622. this._columns = columns | 0;
  8623. /** @type {SpeedyMatrixDtype} data type */
  8624. this._dtype = dtype;
  8625. }
  8626. /**
  8627. * Number of rows
  8628. * @returns {number}
  8629. */
  8630. get rows()
  8631. {
  8632. return this._rows;
  8633. }
  8634. /**
  8635. * Number of columns
  8636. * @returns {number}
  8637. */
  8638. get columns()
  8639. {
  8640. return this._columns;
  8641. }
  8642. /**
  8643. * Data type
  8644. * @returns {SpeedyMatrixDtype}
  8645. */
  8646. get dtype()
  8647. {
  8648. return this._dtype;
  8649. }
  8650. /**
  8651. * Default data type
  8652. * @returns {SpeedyMatrixDtype}
  8653. */
  8654. static get DEFAULT_DTYPE()
  8655. {
  8656. return 'float32';
  8657. }
  8658. /**
  8659. * Buffer types
  8660. * @returns {Dtype2BufferType}
  8661. */
  8662. static get BUFFER_TYPE()
  8663. {
  8664. return DTYPE_TO_BUFFER_TYPE;
  8665. }
  8666. /**
  8667. * Matrix addition
  8668. * @param {SpeedyMatrixExpr} expr
  8669. * @returns {SpeedyMatrixExpr}
  8670. */
  8671. plus(expr)
  8672. {
  8673. return new SpeedyMatrixAddExpr(this, expr);
  8674. }
  8675. /**
  8676. * Matrix subtraction
  8677. * @param {SpeedyMatrixExpr} expr
  8678. * @returns {SpeedyMatrixExpr}
  8679. */
  8680. minus(expr)
  8681. {
  8682. return new SpeedyMatrixSubtractExpr(this, expr);
  8683. }
  8684. /**
  8685. * Matrix multiplication
  8686. * @param {SpeedyMatrixExpr|number} expr
  8687. * @returns {SpeedyMatrixExpr}
  8688. */
  8689. times(expr)
  8690. {
  8691. if(typeof expr === 'number')
  8692. return new SpeedyMatrixScaleExpr(this, expr);
  8693. else
  8694. return new SpeedyMatrixMultiplyExpr(this, expr);
  8695. }
  8696. /**
  8697. * Matrix transposition
  8698. * @returns {SpeedyMatrixExpr}
  8699. */
  8700. transpose()
  8701. {
  8702. return new SpeedyMatrixTransposeExpr(this);
  8703. }
  8704. /**
  8705. * Matrix inversion
  8706. * @returns {SpeedyMatrixExpr}
  8707. */
  8708. inverse()
  8709. {
  8710. return new SpeedyMatrixInvertExpr(this);
  8711. }
  8712. /**
  8713. * Component-wise multiplication
  8714. * @param {SpeedyMatrixExpr} expr
  8715. * @returns {SpeedyMatrixExpr}
  8716. */
  8717. compMult(expr)
  8718. {
  8719. return new SpeedyMatrixCompMultExpr(this, expr);
  8720. }
  8721. /**
  8722. * Left division: A \ b, which is equivalent to (pseudo-)inverse(A) * b
  8723. * @param {SpeedyMatrixExpr} expr
  8724. * @returns {SpeedyMatrixExpr}
  8725. */
  8726. ldiv(expr)
  8727. {
  8728. return new SpeedyMatrixLdivExpr(this, expr);
  8729. }
  8730. /**
  8731. * Returns a human-readable string representation of the matrix expression
  8732. * @returns {string}
  8733. */
  8734. toString()
  8735. {
  8736. return `SpeedyMatrixExpr(rows=${this.rows}, columns=${this.columns})`;
  8737. }
  8738. /**
  8739. * Evaluate this expression
  8740. * @abstract
  8741. * @param {WebAssembly.Instance} wasm
  8742. * @param {SpeedyMatrixWASMMemory} memory
  8743. * @returns {SpeedyMatrix}
  8744. */
  8745. _evaluate(wasm, memory)
  8746. {
  8747. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  8748. }
  8749. }
  8750. const { SpeedyMatrix } = __nested_webpack_require_392606__(/*! ./speedy-matrix */ "./src/core/speedy-matrix.js");
  8751. /**
  8752. * @abstract operation storing a temporary matrix
  8753. */
  8754. class SpeedyMatrixTempExpr extends SpeedyMatrixExpr
  8755. {
  8756. /**
  8757. * Constructor
  8758. * @param {number} rows
  8759. * @param {number} columns
  8760. * @param {SpeedyMatrixDtype} dtype
  8761. */
  8762. constructor(rows, columns, dtype)
  8763. {
  8764. super(rows, columns, dtype);
  8765. /** @type {SpeedyMatrix} holds the results of a computation */
  8766. this._tempMatrix = SpeedyMatrix.Zeros(this.rows, this.columns, this.dtype);
  8767. }
  8768. }
  8769. /**
  8770. * @abstract unary operation
  8771. */
  8772. class SpeedyMatrixUnaryOperationExpr extends SpeedyMatrixTempExpr
  8773. {
  8774. /**
  8775. * Constructor
  8776. * @param {number} rows rows of the output matrix
  8777. * @param {number} columns columns of the output matrix
  8778. * @param {SpeedyMatrixExpr} operand
  8779. */
  8780. constructor(rows, columns, operand)
  8781. {
  8782. super(rows, columns, operand.dtype);
  8783. /** @type {SpeedyMatrixExpr} operand */
  8784. this._operand = operand;
  8785. }
  8786. /**
  8787. * Evaluate this expression
  8788. * @param {WebAssembly.Instance} wasm
  8789. * @param {SpeedyMatrixWASMMemory} memory
  8790. * @returns {SpeedyMatrix}
  8791. */
  8792. _evaluate(wasm, memory)
  8793. {
  8794. const operand = this._operand._evaluate(wasm, memory);
  8795. const result = this._tempMatrix;
  8796. // allocate matrices
  8797. const resultptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.allocateMat32(wasm, memory, result);
  8798. const operandptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.allocateMat32(wasm, memory, operand);
  8799. // copy operand to WASM memory
  8800. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.copyToMat32(wasm, memory, operandptr, operand);
  8801. // run the WASM routine
  8802. this._compute(wasm, memory, resultptr, operandptr);
  8803. // copy result from WASM memory
  8804. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, resultptr, result);
  8805. // deallocate matrices
  8806. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, operandptr);
  8807. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, resultptr);
  8808. // done!
  8809. return result;
  8810. }
  8811. /**
  8812. * Compute the result of this operation
  8813. * @abstract
  8814. * @param {WebAssembly.Instance} wasm
  8815. * @param {SpeedyMatrixWASMMemory} memory
  8816. * @param {number} resultptr pointer to Mat32
  8817. * @param {number} operandptr pointer to Mat32
  8818. */
  8819. _compute(wasm, memory, resultptr, operandptr)
  8820. {
  8821. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  8822. }
  8823. }
  8824. /**
  8825. * @abstract binary operation
  8826. */
  8827. class SpeedyMatrixBinaryOperationExpr extends SpeedyMatrixTempExpr
  8828. {
  8829. /**
  8830. * Constructor
  8831. * @param {number} rows rows of the output matrix
  8832. * @param {number} columns columns of the output matrix
  8833. * @param {SpeedyMatrixExpr} left left operand
  8834. * @param {SpeedyMatrixExpr} right right operand
  8835. */
  8836. constructor(rows, columns, left, right)
  8837. {
  8838. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(left.dtype === right.dtype);
  8839. super(rows, columns, left.dtype);
  8840. /** @type {SpeedyMatrixExpr} left operand */
  8841. this._left = left;
  8842. /** @type {SpeedyMatrixExpr} right operand */
  8843. this._right = right;
  8844. }
  8845. /**
  8846. * Evaluate this expression
  8847. * @param {WebAssembly.Instance} wasm
  8848. * @param {SpeedyMatrixWASMMemory} memory
  8849. * @returns {SpeedyMatrix}
  8850. */
  8851. _evaluate(wasm, memory)
  8852. {
  8853. const left = this._left._evaluate(wasm, memory);
  8854. const right = this._right._evaluate(wasm, memory);
  8855. const result = this._tempMatrix;
  8856. // allocate matrices
  8857. const resultptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.allocateMat32(wasm, memory, result);
  8858. const leftptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.allocateMat32(wasm, memory, left);
  8859. const rightptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.allocateMat32(wasm, memory, right);
  8860. // copy input matrices to WASM memory
  8861. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.copyToMat32(wasm, memory, leftptr, left);
  8862. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.copyToMat32(wasm, memory, rightptr, right);
  8863. // run the WASM routine
  8864. this._compute(wasm, memory, resultptr, leftptr, rightptr);
  8865. // copy output matrix from WASM memory
  8866. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, resultptr, result);
  8867. // deallocate matrices
  8868. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, rightptr);
  8869. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, leftptr);
  8870. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, resultptr);
  8871. // done!
  8872. return result;
  8873. }
  8874. /**
  8875. * Compute the result of this operation
  8876. * @abstract
  8877. * @param {WebAssembly.Instance} wasm
  8878. * @param {SpeedyMatrixWASMMemory} memory
  8879. * @param {number} resultptr pointer to Mat32
  8880. * @param {number} leftptr pointer to Mat32
  8881. * @param {number} rightptr pointer to Mat32
  8882. */
  8883. _compute(wasm, memory, resultptr, leftptr, rightptr)
  8884. {
  8885. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  8886. }
  8887. }
  8888. /**
  8889. * Transpose matrix
  8890. */
  8891. class SpeedyMatrixTransposeExpr extends SpeedyMatrixUnaryOperationExpr
  8892. {
  8893. /**
  8894. * Constructor
  8895. * @param {SpeedyMatrixExpr} operand
  8896. */
  8897. constructor(operand)
  8898. {
  8899. super(operand.columns, operand.rows, operand);
  8900. }
  8901. /**
  8902. * Compute result = operand^T
  8903. * @param {WebAssembly.Instance} wasm
  8904. * @param {SpeedyMatrixWASMMemory} memory
  8905. * @param {number} resultptr pointer to Mat32
  8906. * @param {number} operandptr pointer to Mat32
  8907. */
  8908. _compute(wasm, memory, resultptr, operandptr)
  8909. {
  8910. wasm.exports.Mat32_transpose(resultptr, operandptr);
  8911. }
  8912. }
  8913. /**
  8914. * Invert square matrix
  8915. */
  8916. class SpeedyMatrixInvertExpr extends SpeedyMatrixUnaryOperationExpr
  8917. {
  8918. /**
  8919. * Constructor
  8920. * @param {SpeedyMatrixExpr} operand
  8921. */
  8922. constructor(operand)
  8923. {
  8924. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(operand.rows === operand.columns);
  8925. super(operand.rows, operand.columns, operand);
  8926. /** @type {number} size of the matrix */
  8927. this._size = operand.rows;
  8928. }
  8929. /**
  8930. * Compute result = operand ^ (-1)
  8931. * @param {WebAssembly.Instance} wasm
  8932. * @param {SpeedyMatrixWASMMemory} memory
  8933. * @param {number} resultptr pointer to Mat32
  8934. * @param {number} operandptr pointer to Mat32
  8935. */
  8936. _compute(wasm, memory, resultptr, operandptr)
  8937. {
  8938. switch(this._size) {
  8939. case 0: break;
  8940. case 1:
  8941. wasm.exports.Mat32_inverse1(resultptr, operandptr);
  8942. break;
  8943. case 2:
  8944. wasm.exports.Mat32_inverse2(resultptr, operandptr);
  8945. break;
  8946. case 3:
  8947. wasm.exports.Mat32_inverse3(resultptr, operandptr);
  8948. break;
  8949. default:
  8950. wasm.exports.Mat32_qr_inverse(resultptr, operandptr);
  8951. break;
  8952. }
  8953. }
  8954. }
  8955. /**
  8956. * Multiply matrix by a scalar value
  8957. */
  8958. class SpeedyMatrixScaleExpr extends SpeedyMatrixUnaryOperationExpr
  8959. {
  8960. /**
  8961. * Constructor
  8962. * @param {SpeedyMatrixExpr} operand
  8963. * @param {number} scalar
  8964. */
  8965. constructor(operand, scalar)
  8966. {
  8967. super(operand.rows, operand.columns, operand);
  8968. /** @type {number} scalar value */
  8969. this._scalar = +scalar;
  8970. }
  8971. /**
  8972. * Compute result = scalar * operand
  8973. * @param {WebAssembly.Instance} wasm
  8974. * @param {SpeedyMatrixWASMMemory} memory
  8975. * @param {number} resultptr pointer to Mat32
  8976. * @param {number} operandptr pointer to Mat32
  8977. */
  8978. _compute(wasm, memory, resultptr, operandptr)
  8979. {
  8980. wasm.exports.Mat32_scale(resultptr, operandptr, this._scalar);
  8981. }
  8982. }
  8983. /**
  8984. * Matrix addition
  8985. */
  8986. class SpeedyMatrixAddExpr extends SpeedyMatrixBinaryOperationExpr
  8987. {
  8988. /**
  8989. * Constructor
  8990. * @param {SpeedyMatrixExpr} left left operand
  8991. * @param {SpeedyMatrixExpr} right right operand
  8992. */
  8993. constructor(left, right)
  8994. {
  8995. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(left.rows === right.rows && left.columns === right.columns);
  8996. super(left.rows, left.columns, left, right);
  8997. }
  8998. /**
  8999. * Compute result = left + right
  9000. * @param {WebAssembly.Instance} wasm
  9001. * @param {SpeedyMatrixWASMMemory} memory
  9002. * @param {number} resultptr pointer to Mat32
  9003. * @param {number} leftptr pointer to Mat32
  9004. * @param {number} rightptr pointer to Mat32
  9005. */
  9006. _compute(wasm, memory, resultptr, leftptr, rightptr)
  9007. {
  9008. wasm.exports.Mat32_add(resultptr, leftptr, rightptr);
  9009. }
  9010. }
  9011. /**
  9012. * Matrix subtraction
  9013. */
  9014. class SpeedyMatrixSubtractExpr extends SpeedyMatrixBinaryOperationExpr
  9015. {
  9016. /**
  9017. * Constructor
  9018. * @param {SpeedyMatrixExpr} left left operand
  9019. * @param {SpeedyMatrixExpr} right right operand
  9020. */
  9021. constructor(left, right)
  9022. {
  9023. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(left.rows === right.rows && left.columns === right.columns);
  9024. super(left.rows, left.columns, left, right);
  9025. }
  9026. /**
  9027. * Compute result = left - right
  9028. * @param {WebAssembly.Instance} wasm
  9029. * @param {SpeedyMatrixWASMMemory} memory
  9030. * @param {number} resultptr pointer to Mat32
  9031. * @param {number} leftptr pointer to Mat32
  9032. * @param {number} rightptr pointer to Mat32
  9033. */
  9034. _compute(wasm, memory, resultptr, leftptr, rightptr)
  9035. {
  9036. wasm.exports.Mat32_subtract(resultptr, leftptr, rightptr);
  9037. }
  9038. }
  9039. /**
  9040. * Matrix multiplication
  9041. */
  9042. class SpeedyMatrixMultiplyExpr extends SpeedyMatrixBinaryOperationExpr
  9043. {
  9044. /**
  9045. * Constructor
  9046. * @param {SpeedyMatrixExpr} left left operand
  9047. * @param {SpeedyMatrixExpr} right right operand
  9048. */
  9049. constructor(left, right)
  9050. {
  9051. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(left.columns === right.rows);
  9052. super(left.rows, right.columns, left, right);
  9053. }
  9054. /**
  9055. * Compute result = left * right
  9056. * @param {WebAssembly.Instance} wasm
  9057. * @param {SpeedyMatrixWASMMemory} memory
  9058. * @param {number} resultptr pointer to Mat32
  9059. * @param {number} leftptr pointer to Mat32
  9060. * @param {number} rightptr pointer to Mat32
  9061. */
  9062. _compute(wasm, memory, resultptr, leftptr, rightptr)
  9063. {
  9064. wasm.exports.Mat32_multiply(resultptr, leftptr, rightptr);
  9065. }
  9066. }
  9067. /**
  9068. * Component-wise multiplication
  9069. */
  9070. class SpeedyMatrixCompMultExpr extends SpeedyMatrixBinaryOperationExpr
  9071. {
  9072. /**
  9073. * Constructor
  9074. * @param {SpeedyMatrixExpr} left left operand
  9075. * @param {SpeedyMatrixExpr} right right operand
  9076. */
  9077. constructor(left, right)
  9078. {
  9079. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(left.rows === right.rows && left.columns === right.columns);
  9080. super(right.rows, right.columns, left, right);
  9081. }
  9082. /**
  9083. * Compute result = left <compMult> right
  9084. * @param {WebAssembly.Instance} wasm
  9085. * @param {SpeedyMatrixWASMMemory} memory
  9086. * @param {number} resultptr pointer to Mat32
  9087. * @param {number} leftptr pointer to Mat32
  9088. * @param {number} rightptr pointer to Mat32
  9089. */
  9090. _compute(wasm, memory, resultptr, leftptr, rightptr)
  9091. {
  9092. wasm.exports.Mat32_compmult(resultptr, leftptr, rightptr);
  9093. }
  9094. }
  9095. /**
  9096. * Left-division. A \ b is equivalent to (pseudo-)inverse(A) * b
  9097. */
  9098. class SpeedyMatrixLdivExpr extends SpeedyMatrixBinaryOperationExpr
  9099. {
  9100. /**
  9101. * Constructor
  9102. * @param {SpeedyMatrixExpr} left left operand
  9103. * @param {SpeedyMatrixExpr} right right operand
  9104. */
  9105. constructor(left, right)
  9106. {
  9107. const m = left.rows, n = left.columns;
  9108. // TODO right doesn't need to be a column vector
  9109. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(m >= n && right.rows === m && right.columns === 1);
  9110. super(n, 1, left, right);
  9111. }
  9112. /**
  9113. * Compute result = left \ right
  9114. * @param {WebAssembly.Instance} wasm
  9115. * @param {SpeedyMatrixWASMMemory} memory
  9116. * @param {number} resultptr pointer to Mat32
  9117. * @param {number} leftptr pointer to Mat32
  9118. * @param {number} rightptr pointer to Mat32
  9119. */
  9120. _compute(wasm, memory, resultptr, leftptr, rightptr)
  9121. {
  9122. wasm.exports.Mat32_qr_ols(resultptr, leftptr, rightptr, 2);
  9123. }
  9124. }
  9125. /***/ }),
  9126. /***/ "./src/core/speedy-matrix-factory.js":
  9127. /*!*******************************************!*\
  9128. !*** ./src/core/speedy-matrix-factory.js ***!
  9129. \*******************************************/
  9130. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_411390__) => {
  9131. "use strict";
  9132. __nested_webpack_require_411390__.r(__webpack_exports__);
  9133. /* harmony export */ __nested_webpack_require_411390__.d(__webpack_exports__, {
  9134. /* harmony export */ "SpeedyMatrixFactory": () => (/* binding */ SpeedyMatrixFactory)
  9135. /* harmony export */ });
  9136. /* harmony import */ var _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_411390__(/*! ./speedy-matrix-expr */ "./src/core/speedy-matrix-expr.js");
  9137. /* harmony import */ var _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_411390__(/*! ./speedy-matrix-wasm */ "./src/core/speedy-matrix-wasm.js");
  9138. /* harmony import */ var _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_411390__(/*! ./speedy-matrix */ "./src/core/speedy-matrix.js");
  9139. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_411390__(/*! ./speedy-promise */ "./src/core/speedy-promise.js");
  9140. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_411390__(/*! ../utils/utils */ "./src/utils/utils.js");
  9141. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_411390__(/*! ../utils/errors */ "./src/utils/errors.js");
  9142. /*
  9143. * speedy-vision.js
  9144. * GPU-accelerated Computer Vision for JavaScript
  9145. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  9146. *
  9147. * Licensed under the Apache License, Version 2.0 (the "License");
  9148. * you may not use this file except in compliance with the License.
  9149. * You may obtain a copy of the License at
  9150. *
  9151. * http://www.apache.org/licenses/LICENSE-2.0
  9152. *
  9153. * Unless required by applicable law or agreed to in writing, software
  9154. * distributed under the License is distributed on an "AS IS" BASIS,
  9155. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9156. * See the License for the specific language governing permissions and
  9157. * limitations under the License.
  9158. *
  9159. * speedy-matrix-factory.js
  9160. * A factory of matrices
  9161. */
  9162. /**
  9163. * Matrix routines
  9164. */
  9165. class SpeedyMatrixFactory extends Function
  9166. {
  9167. /**
  9168. * Constructor
  9169. */
  9170. constructor()
  9171. {
  9172. // This factory can be invoked as a function
  9173. super('...args', 'return args.length > 1 ? this._create(...args) : this._from(args[0])');
  9174. return this.bind(this);
  9175. }
  9176. /**
  9177. * @private
  9178. *
  9179. * Create a new matrix filled with the specified size and entries
  9180. * @param {number} rows
  9181. * @param {number} [columns]
  9182. * @param {number[]} [entries] in column-major format
  9183. * @returns {SpeedyMatrix}
  9184. */
  9185. _create(rows, columns = rows, entries = [])
  9186. {
  9187. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.Create(rows, columns, entries);
  9188. }
  9189. /**
  9190. * @private
  9191. *
  9192. * Evaluate an expression synchronously and store the result in a new matrix
  9193. * @param {SpeedyMatrixExpr} expr matrix expression
  9194. * @returns {SpeedyMatrix}
  9195. */
  9196. _from(expr)
  9197. {
  9198. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.From(expr);
  9199. }
  9200. /**
  9201. * Create a new matrix filled with zeros with the specified size
  9202. * @param {number} rows
  9203. * @param {number} [columns]
  9204. * @returns {SpeedyMatrix}
  9205. */
  9206. Zeros(rows, columns = rows)
  9207. {
  9208. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.Zeros(rows, columns);
  9209. }
  9210. /**
  9211. * Create a new matrix filled with ones with the specified size
  9212. * @param {number} rows
  9213. * @param {number} [columns]
  9214. * @returns {SpeedyMatrix}
  9215. */
  9216. Ones(rows, columns = rows)
  9217. {
  9218. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.Ones(rows, columns);
  9219. }
  9220. /**
  9221. * Create an identity matrix with the specified size
  9222. * @param {number} rows
  9223. * @param {number} [columns]
  9224. * @returns {SpeedyMatrix}
  9225. */
  9226. Eye(rows, columns = rows)
  9227. {
  9228. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.Eye(rows, columns);
  9229. }
  9230. /**
  9231. * Returns a promise that resolves immediately if the WebAssembly routines
  9232. * are ready to be used, or as soon as they do become ready
  9233. * @returns {SpeedyPromise<void>}
  9234. */
  9235. ready()
  9236. {
  9237. return _speedy_matrix__WEBPACK_IMPORTED_MODULE_2__.SpeedyMatrix.ready();
  9238. }
  9239. /**
  9240. * QR decomposition
  9241. * @param {SpeedyMatrix} Q is m x n (reduced) or m x m (full), output
  9242. * @param {SpeedyMatrix} R is n x n (reduced) or m x n (full), output
  9243. * @param {SpeedyMatrix} mat is m x n, input
  9244. * @param {object} [options]
  9245. * @param {'reduced'|'full'} [options.mode]
  9246. * @returns {SpeedyPromise<[SpeedyMatrix,SpeedyMatrix]>} resolves to [Q,R]
  9247. */
  9248. qr(Q, R, mat, { mode = 'reduced' } = {})
  9249. {
  9250. const A = mat, m = mat.rows, n = mat.columns;
  9251. // validate shapes & mode
  9252. if(mode == 'reduced') {
  9253. if(Q.rows != m || Q.columns != n || R.rows != n || R.columns != n)
  9254. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shape for reduced QR`);
  9255. }
  9256. else if(mode == 'full') {
  9257. if(Q.rows != m || Q.columns != m || R.rows != m || R.columns != n)
  9258. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shape for full QR`);
  9259. }
  9260. else
  9261. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid mode for QR: "${mode}"`);
  9262. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9263. // allocate matrices
  9264. const Qptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, Q);
  9265. const Rptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, R);
  9266. const Aptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, A);
  9267. // copy input matrices to WASM memory
  9268. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, Aptr, A);
  9269. // run the WASM routine
  9270. if(mode == 'reduced')
  9271. wasm.exports.Mat32_qr_reduced(Qptr, Rptr, Aptr);
  9272. else
  9273. wasm.exports.Mat32_qr_full(Qptr, Rptr, Aptr);
  9274. // copy output matrices from WASM memory
  9275. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, Qptr, Q);
  9276. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, Rptr, R);
  9277. // deallocate matrices
  9278. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, Aptr);
  9279. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, Rptr);
  9280. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, Qptr);
  9281. // done!
  9282. return [Q, R];
  9283. });
  9284. }
  9285. /**
  9286. * Solve a possibly overdetermined system of linear
  9287. * equations Ax = b for x using ordinary least squares
  9288. * @param {SpeedyMatrix} solution n x 1, output
  9289. * @param {SpeedyMatrix} A m x n, m >= n, input
  9290. * @param {SpeedyMatrix} b m x 1, output
  9291. * @param {object} [options]
  9292. * @param {'qr'} [options.method] method of resolution
  9293. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to solution
  9294. */
  9295. ols(solution, A, b, { method = 'qr' } = {})
  9296. {
  9297. const m = A.rows, n = A.columns;
  9298. const x = solution;
  9299. // validate shapes
  9300. if(m < n || n == 0)
  9301. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Can't solve an underdetermined system of equations`);
  9302. else if(b.rows != m || b.columns != 1 || x.rows != n || x.columns != 1)
  9303. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shapes`);
  9304. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9305. // allocate matrices
  9306. const Aptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, A);
  9307. const bptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, b);
  9308. const xptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, x);
  9309. // copy input matrices to WASM memory
  9310. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, Aptr, A);
  9311. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, bptr, b);
  9312. // run the WASM routine
  9313. switch(method) {
  9314. case 'qr':
  9315. wasm.exports.Mat32_qr_ols(xptr, Aptr, bptr, 2);
  9316. break;
  9317. default:
  9318. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid method: "${method}"`);
  9319. }
  9320. // copy output matrix from WASM memory
  9321. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, xptr, x);
  9322. // deallocate matrices
  9323. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, xptr);
  9324. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, bptr);
  9325. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, Aptr);
  9326. // done!
  9327. return solution;
  9328. });
  9329. }
  9330. /**
  9331. * Solve a system of linear equations Ax = b for x
  9332. * @param {SpeedyMatrix} solution m x 1, output
  9333. * @param {SpeedyMatrix} A m x m, input
  9334. * @param {SpeedyMatrix} b m x 1, output
  9335. * @param {object} [options]
  9336. * @param {'qr'} [options.method] method of resolution
  9337. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to solution
  9338. */
  9339. solve(solution, A, b, { method = 'qr' } = {})
  9340. {
  9341. const m = A.rows, n = A.columns;
  9342. const x = solution;
  9343. // validate shapes
  9344. if(m != n)
  9345. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Can't solve an over or underdetermined system of equations`);
  9346. else if(b.rows != m || b.columns != 1 || x.rows != m || x.columns != 1)
  9347. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shapes`);
  9348. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9349. // select method
  9350. switch(method) {
  9351. case 'qr':
  9352. return this.ols(x, A, b, { method });
  9353. /*case 'lu':
  9354. break;*/
  9355. default:
  9356. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid method: "${method}"`);
  9357. }
  9358. });
  9359. }
  9360. /**
  9361. * Compute a perspective transformation using 4 correspondences of points
  9362. * @param {SpeedyMatrix} homography 3x3 output - homography matrix
  9363. * @param {SpeedyMatrix} src 2x4 input points - source coordinates
  9364. * @param {SpeedyMatrix} dest 2x4 input points - destination coordinates
  9365. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to homography
  9366. */
  9367. perspective(homography, src, dest)
  9368. {
  9369. // validate shapes
  9370. if(src.rows != 2 || src.columns != 4 || dest.rows != 2 || dest.columns != 4)
  9371. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`You need two 2x4 input matrices to compute a perspective transformation`);
  9372. else if(homography.rows != 3 || homography.columns != 3)
  9373. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The output of perspective() is a 3x3 homography`);
  9374. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9375. // allocate matrices
  9376. const homptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, homography);
  9377. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9378. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9379. // copy input matrices to WASM memory
  9380. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9381. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, destptr, dest);
  9382. // run the WASM routine
  9383. wasm.exports.Mat32_homography_ndlt4(homptr, srcptr, destptr);
  9384. // copy output matrix from WASM memory
  9385. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, homptr, homography);
  9386. // deallocate matrices
  9387. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9388. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9389. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, homptr);
  9390. // done!
  9391. return homography;
  9392. });
  9393. }
  9394. /**
  9395. * Compute a perspective transformation using n >= 4 correspondences of points
  9396. * @param {SpeedyMatrix} homography 3x3 output - homography matrix
  9397. * @param {SpeedyMatrix} src 2 x n input points - source coordinates
  9398. * @param {SpeedyMatrix} dest 2 x n input points - destination coordinates
  9399. * @param {object} [options]
  9400. * @param {'default'|'pransac'} [options.method] method of computation
  9401. * @param {SpeedyMatrix|null} [options.mask] (pransac) 1 x n output: i-th entry will be 1 if the i-th input point is an inlier, or 0 otherwise
  9402. * @param {number} [options.reprojectionError] (pransac) given in pixels, used to separate inliers from outliers of a particular model (e.g., 1 pixel)
  9403. * @param {number} [options.numberOfHypotheses] (pransac) number of hypotheses to be generated up-front (e.g., 512)
  9404. * @param {number} [options.bundleSize] (pransac) how many points should we check before reducing the number of viable hypotheses (e.g., 128)
  9405. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to homography
  9406. */
  9407. findHomography(homography, src, dest, {
  9408. method = 'default',
  9409. mask = null,
  9410. reprojectionError = 3,
  9411. numberOfHypotheses = 512,
  9412. bundleSize = 128,
  9413. } = {})
  9414. {
  9415. // validate shapes
  9416. if(src.rows != 2 || src.columns < 4 || dest.rows != 2 || dest.columns != src.columns)
  9417. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`You need two 2 x n (n >= 4) input matrices to compute a homography`);
  9418. else if(homography.rows != 3 || homography.columns != 3)
  9419. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The output of findHomography() is a 3x3 homography`);
  9420. else if(mask != null && (mask.rows != 1 || mask.columns != src.columns))
  9421. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shape of the inliers mask`);
  9422. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9423. // allocate matrices
  9424. const homptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, homography);
  9425. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9426. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9427. const maskptr = mask != null ? _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, mask) : 0;
  9428. // copy input matrices to WASM memory
  9429. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9430. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, destptr, dest);
  9431. // run the WASM routine
  9432. switch(method) {
  9433. case 'pransac':
  9434. _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.assert(reprojectionError >= 0 && numberOfHypotheses > 0 && bundleSize > 0);
  9435. wasm.exports.Mat32_pransac_homography(homptr, maskptr, srcptr, destptr, numberOfHypotheses, bundleSize, reprojectionError);
  9436. break;
  9437. case 'default':
  9438. case 'dlt': // obsolete
  9439. wasm.exports.Mat32_homography_ndlt(homptr, srcptr, destptr);
  9440. break;
  9441. default:
  9442. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Illegal method for findHomography(): "${method}"`);
  9443. }
  9444. // copy output matrices from WASM memory
  9445. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, homptr, homography);
  9446. if(mask != null)
  9447. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, maskptr, mask);
  9448. // deallocate matrices
  9449. if(mask != null)
  9450. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, maskptr);
  9451. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9452. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9453. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, homptr);
  9454. // done!
  9455. return homography;
  9456. });
  9457. }
  9458. /**
  9459. * Apply a perspective transformation to a set of 2D points
  9460. * @param {SpeedyMatrix} dest 2 x n output matrix
  9461. * @param {SpeedyMatrix} src 2 x n input matrix (a set of points)
  9462. * @param {SpeedyMatrix} transform 3x3 homography matrix
  9463. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to dest
  9464. */
  9465. applyPerspectiveTransform(dest, src, transform)
  9466. {
  9467. // validate shapes
  9468. if(src.rows != 2 || dest.rows != 2 || src.columns != dest.columns)
  9469. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shapes`);
  9470. else if(transform.rows != 3 || transform.columns != 3)
  9471. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The perspective transformation must be a 3x3 matrix`);
  9472. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9473. // allocate matrices
  9474. const matptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, transform);
  9475. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9476. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9477. // copy input matrices to WASM memory
  9478. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9479. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, matptr, transform);
  9480. // run the WASM routine
  9481. wasm.exports.Mat32_transform_perspective(destptr, srcptr, matptr);
  9482. // copy output matrix from WASM memory
  9483. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, destptr, dest);
  9484. // deallocate matrices
  9485. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9486. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9487. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, matptr);
  9488. // done!
  9489. return dest;
  9490. });
  9491. }
  9492. /**
  9493. * Compute an affine transform using 3 correspondences of points
  9494. * @param {SpeedyMatrix} transform 2x3 output - affine transform
  9495. * @param {SpeedyMatrix} src 2x3 input points - source coordinates
  9496. * @param {SpeedyMatrix} dest 2x3 input points - destination coordinates
  9497. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to homography
  9498. */
  9499. affine(transform, src, dest)
  9500. {
  9501. // validate shapes
  9502. if(src.rows != 2 || src.columns != 3 || dest.rows != 2 || dest.columns != 3)
  9503. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`You need two 2x3 input matrices to compute an affine transform`);
  9504. else if(transform.rows != 2 || transform.columns != 3)
  9505. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The output of affine() is a 2x3 matrix`);
  9506. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9507. // allocate matrices
  9508. const matptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, transform);
  9509. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9510. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9511. // copy input matrices to WASM memory
  9512. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9513. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, destptr, dest);
  9514. // run the WASM routine
  9515. wasm.exports.Mat32_affine_direct3(matptr, srcptr, destptr);
  9516. // copy output matrix from WASM memory
  9517. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, matptr, transform);
  9518. // deallocate matrices
  9519. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9520. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9521. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, matptr);
  9522. // done!
  9523. return transform;
  9524. });
  9525. }
  9526. /**
  9527. * Compute an affine transformation using n >= 3 correspondences of points
  9528. * @param {SpeedyMatrix} transform 2x3 output - affine transform
  9529. * @param {SpeedyMatrix} src 2 x n input points - source coordinates
  9530. * @param {SpeedyMatrix} dest 2 x n input points - destination coordinates
  9531. * @param {object} [options]
  9532. * @param {'default'|'pransac'} [options.method] method of computation
  9533. * @param {SpeedyMatrix|null} [options.mask] (pransac) 1 x n output: i-th entry will be 1 if the i-th input point is an inlier, or 0 otherwise
  9534. * @param {number} [options.reprojectionError] (pransac) given in pixels, used to separate inliers from outliers of a particular model (e.g., 1 pixel)
  9535. * @param {number} [options.numberOfHypotheses] (pransac) number of hypotheses to be generated up-front (e.g., 512)
  9536. * @param {number} [options.bundleSize] (pransac) how many points should we check before reducing the number of viable hypotheses (e.g., 128)
  9537. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to an affine transform
  9538. */
  9539. findAffineTransform(transform, src, dest, {
  9540. method = 'default',
  9541. mask = null,
  9542. reprojectionError = 3,
  9543. numberOfHypotheses = 512,
  9544. bundleSize = 128,
  9545. } = {})
  9546. {
  9547. // validate shapes
  9548. if(src.rows != 2 || src.columns < 3 || dest.rows != 2 || dest.columns != src.columns)
  9549. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`You need two 2 x n (n >= 3) input matrices to compute an affine transform`);
  9550. else if(transform.rows != 2 || transform.columns != 3)
  9551. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The output of findAffineTransform() is a 2x3 matrix`);
  9552. else if(mask != null && (mask.rows != 1 || mask.columns != src.columns))
  9553. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shape of the inliers mask`);
  9554. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9555. // allocate matrices
  9556. const matptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, transform);
  9557. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9558. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9559. const maskptr = mask != null ? _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, mask) : 0;
  9560. // copy input matrices to WASM memory
  9561. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9562. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, destptr, dest);
  9563. // run the WASM routine
  9564. switch(method) {
  9565. case 'pransac':
  9566. _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.assert(reprojectionError >= 0 && numberOfHypotheses > 0 && bundleSize > 0);
  9567. wasm.exports.Mat32_pransac_affine(matptr, maskptr, srcptr, destptr, numberOfHypotheses, bundleSize, reprojectionError);
  9568. break;
  9569. case 'default':
  9570. wasm.exports.Mat32_affine_direct(matptr, srcptr, destptr);
  9571. break;
  9572. default:
  9573. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Illegal method for findAffineTransform(): "${method}"`);
  9574. }
  9575. // copy output matrices from WASM memory
  9576. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, matptr, transform);
  9577. if(mask != null)
  9578. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, maskptr, mask);
  9579. // deallocate matrices
  9580. if(mask != null)
  9581. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, maskptr);
  9582. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9583. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9584. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, matptr);
  9585. // done!
  9586. return transform;
  9587. });
  9588. }
  9589. /**
  9590. * Apply an affine transformation to a set of 2D points
  9591. * @param {SpeedyMatrix} dest 2 x n output matrix
  9592. * @param {SpeedyMatrix} src 2 x n input matrix (a set of points)
  9593. * @param {SpeedyMatrix} transform 2x3 affine transform
  9594. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to dest
  9595. */
  9596. applyAffineTransform(dest, src, transform)
  9597. {
  9598. // validate shapes
  9599. if(src.rows != 2 || dest.rows != 2 || src.columns != dest.columns)
  9600. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`Invalid shapes`);
  9601. else if(transform.rows != 2 || transform.columns != 3)
  9602. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_5__.IllegalArgumentError(`The affine transformation must be a 2x3 matrix`);
  9603. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(({wasm, memory}) => {
  9604. // allocate matrices
  9605. const matptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, transform);
  9606. const srcptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, src);
  9607. const destptr = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.allocateMat32(wasm, memory, dest);
  9608. // copy input matrices to WASM memory
  9609. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, srcptr, src);
  9610. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyToMat32(wasm, memory, matptr, transform);
  9611. // run the WASM routine
  9612. wasm.exports.Mat32_transform_affine(destptr, srcptr, matptr);
  9613. // copy output matrix from WASM memory
  9614. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.copyFromMat32(wasm, memory, destptr, dest);
  9615. // deallocate matrices
  9616. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, destptr);
  9617. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, srcptr);
  9618. _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.deallocateMat32(wasm, memory, matptr);
  9619. // done!
  9620. return dest;
  9621. });
  9622. }
  9623. }
  9624. /***/ }),
  9625. /***/ "./src/core/speedy-matrix-wasm.js":
  9626. /*!****************************************!*\
  9627. !*** ./src/core/speedy-matrix-wasm.js ***!
  9628. \****************************************/
  9629. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_441690__) => {
  9630. "use strict";
  9631. __nested_webpack_require_441690__.r(__webpack_exports__);
  9632. /* harmony export */ __nested_webpack_require_441690__.d(__webpack_exports__, {
  9633. /* harmony export */ "SpeedyMatrixWASM": () => (/* binding */ SpeedyMatrixWASM)
  9634. /* harmony export */ });
  9635. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_441690__(/*! ./speedy-promise */ "./src/core/speedy-promise.js");
  9636. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_441690__(/*! ../utils/errors */ "./src/utils/errors.js");
  9637. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_441690__(/*! ../utils/utils */ "./src/utils/utils.js");
  9638. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_441690__(/*! ../utils/globals */ "./src/utils/globals.js");
  9639. /*
  9640. * speedy-vision.js
  9641. * GPU-accelerated Computer Vision for JavaScript
  9642. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  9643. *
  9644. * Licensed under the Apache License, Version 2.0 (the "License");
  9645. * you may not use this file except in compliance with the License.
  9646. * You may obtain a copy of the License at
  9647. *
  9648. * http://www.apache.org/licenses/LICENSE-2.0
  9649. *
  9650. * Unless required by applicable law or agreed to in writing, software
  9651. * distributed under the License is distributed on an "AS IS" BASIS,
  9652. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9653. * See the License for the specific language governing permissions and
  9654. * limitations under the License.
  9655. *
  9656. * speedy-matrix-wasm.js
  9657. * WebAssembly bridge
  9658. */
  9659. /** @typedef {import('./speedy-matrix').SpeedyMatrix} SpeedyMatrix */
  9660. /**
  9661. * @typedef {object} SpeedyMatrixWASMMemory a union-like helper for accessing a WebAssembly.Memory object
  9662. * @property {object} as
  9663. * @property {WebAssembly.Memory} as.object
  9664. * @property {Uint8Array} as.uint8
  9665. * @property {Int32Array} as.int32
  9666. * @property {Uint32Array} as.uint32
  9667. * @property {Float32Array} as.float32
  9668. * @property {Float64Array} as.float64
  9669. */
  9670. /**
  9671. * @typedef {object} SpeedyMatrixWASMHandle
  9672. * @property {WebAssembly.Instance} wasm
  9673. * @property {SpeedyMatrixWASMMemory} memory
  9674. * @property {WebAssembly.Module} module
  9675. */
  9676. /** @type {Uint8Array} WebAssembly binary */
  9677. const WASM_BINARY = __nested_webpack_require_441690__(/*! ./wasm/speedy-matrix.wasm.txt */ "./src/core/wasm/speedy-matrix.wasm.txt");
  9678. /** @type {WebAssembly.Instance|null} WebAssembly Instance, to be loaded asynchronously */
  9679. let _instance = null;
  9680. /** @type {WebAssembly.Module|null} WebAssembly Module, to be loaded asynchronously */
  9681. let _module = null;
  9682. /** @type {SpeedyMatrixWASMMemory} Augmented WebAssembly Memory object */
  9683. const _memory = (mem => ({
  9684. as: {
  9685. object: mem,
  9686. uint8: new Uint8Array(mem.buffer),
  9687. int32: new Int32Array(mem.buffer),
  9688. uint32: new Uint32Array(mem.buffer),
  9689. float32: new Float32Array(mem.buffer),
  9690. float64: new Float64Array(mem.buffer),
  9691. },
  9692. }))(new WebAssembly.Memory({
  9693. initial: 16, // 1 MB
  9694. maximum: 256
  9695. }));
  9696. /**
  9697. * WebAssembly utilities
  9698. */
  9699. class SpeedyMatrixWASM
  9700. {
  9701. /**
  9702. * Gets you the WASM instance, augmented memory & module
  9703. * @returns {SpeedyPromise<SpeedyMatrixWASMHandle>}
  9704. */
  9705. static ready()
  9706. {
  9707. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_0__.SpeedyPromise((resolve, reject) => {
  9708. SpeedyMatrixWASM._ready(resolve, reject);
  9709. });
  9710. }
  9711. /**
  9712. * Synchronously gets you the WASM instance, augmented memory & module
  9713. * @returns {SpeedyMatrixWASMHandle}
  9714. */
  9715. static get handle()
  9716. {
  9717. if(!_instance || !_module)
  9718. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.WebAssemblyError(`Can't get WASM handle: routines not yet loaded`);
  9719. return {
  9720. wasm: _instance,
  9721. memory: _memory,
  9722. module: _module,
  9723. };
  9724. }
  9725. /**
  9726. * Gets you the WASM imports bound to a memory object
  9727. * @param {SpeedyMatrixWASMMemory} memory
  9728. * @returns {Object<string,Function>}
  9729. */
  9730. static imports(memory)
  9731. {
  9732. const obj = new SpeedyMatrixWASMImports(memory);
  9733. return Object.getOwnPropertyNames(SpeedyMatrixWASMImports.prototype)
  9734. .filter(property => typeof obj[property] === 'function' && property !== 'constructor')
  9735. .reduce(
  9736. (imports, methodName) => ((imports[methodName] = obj[methodName]), imports),
  9737. Object.create(null)
  9738. );
  9739. }
  9740. /**
  9741. * Allocate a Mat32 in WebAssembly memory without copying any data
  9742. * @param {WebAssembly.Instance} wasm
  9743. * @param {SpeedyMatrixWASMMemory} memory
  9744. * @param {SpeedyMatrix} matrix
  9745. * @returns {number} pointer to the new Mat32
  9746. */
  9747. static allocateMat32(wasm, memory, matrix)
  9748. {
  9749. const dataptr = wasm.exports.malloc(matrix.data.byteLength);
  9750. const matptr = wasm.exports.Mat32_create(matrix.rows, matrix.columns, matrix.step0, matrix.step1, matrix._data.length, dataptr);
  9751. return matptr;
  9752. }
  9753. /**
  9754. * Deallocate a Mat32 in WebAssembly
  9755. * @param {WebAssembly.Instance} wasm
  9756. * @param {SpeedyMatrixWASMMemory} memory
  9757. * @param {number} matptr pointer to the allocated Mat32
  9758. * @returns {number} NULL
  9759. */
  9760. static deallocateMat32(wasm, memory, matptr)
  9761. {
  9762. const dataptr = wasm.exports.Mat32_data(matptr);
  9763. wasm.exports.free(matptr);
  9764. wasm.exports.free(dataptr);
  9765. return 0;
  9766. }
  9767. /**
  9768. * Copy the data of a matrix to a WebAssembly Mat32
  9769. * @param {WebAssembly.Instance} wasm
  9770. * @param {SpeedyMatrixWASMMemory} memory
  9771. * @param {number} matptr pointer to a Mat32
  9772. * @param {SpeedyMatrix} matrix
  9773. * @returns {number} matptr
  9774. */
  9775. static copyToMat32(wasm, memory, matptr, matrix)
  9776. {
  9777. // We assume the following:
  9778. // 1. the host uses little-endian byte ordering (just like WebAssembly)
  9779. // 2. the allocated pointers are 4-byte aligned (the bump allocator guarantees this)
  9780. // 3. the data type is float32
  9781. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(
  9782. //matrix.dtype === 'float32' &&
  9783. matrix.data.byteLength === wasm.exports.Mat32_dataSize(matptr)
  9784. );
  9785. const dataptr = wasm.exports.Mat32_data(matptr);
  9786. memory.as.float32.set(matrix.data, dataptr / Float32Array.BYTES_PER_ELEMENT);
  9787. return matptr;
  9788. }
  9789. /**
  9790. * Copy the data of a WebAssembly Mat32 to a matrix
  9791. * @param {WebAssembly.Instance} wasm
  9792. * @param {SpeedyMatrixWASMMemory} memory
  9793. * @param {number} matptr pointer to a Mat32
  9794. * @param {SpeedyMatrix} matrix
  9795. * @returns {number} matptr
  9796. */
  9797. static copyFromMat32(wasm, memory, matptr, matrix)
  9798. {
  9799. // We assume the following:
  9800. // 1. the host uses little-endian byte ordering (just like WebAssembly)
  9801. // 2. the allocated pointers are 4-byte aligned (the bump allocator guarantees this)
  9802. // 3. the data type is float32
  9803. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(
  9804. //matrix.dtype === 'float32' &&
  9805. matrix.data.byteLength === wasm.exports.Mat32_dataSize(matptr)
  9806. );
  9807. const base = wasm.exports.Mat32_data(matptr) / Float32Array.BYTES_PER_ELEMENT;
  9808. for(let offset = matrix.data.length - 1; offset >= 0; offset--)
  9809. matrix.data[offset] = memory.as.float32[base + offset];
  9810. return matptr;
  9811. }
  9812. /**
  9813. * Polls the WebAssembly instance until it's ready
  9814. * @param {function(SpeedyMatrixWASMHandle): void} resolve
  9815. * @param {function(Error): void} reject
  9816. * @param {number} [counter]
  9817. */
  9818. static _ready(resolve, reject, counter = 1000)
  9819. {
  9820. if(_instance !== null && _module !== null)
  9821. resolve({ wasm: _instance, memory: _memory, module: _module });
  9822. else if(counter <= 0)
  9823. reject(new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.TimeoutError(`Can't load WASM routines`));
  9824. else
  9825. setTimeout(SpeedyMatrixWASM._ready, 0, resolve, reject, counter - 1);
  9826. }
  9827. }
  9828. /**
  9829. * Methods called from WASM
  9830. */
  9831. class SpeedyMatrixWASMImports
  9832. {
  9833. /**
  9834. * Constructor
  9835. * @param {SpeedyMatrixWASMMemory} memory will be bound to this object
  9836. */
  9837. constructor(memory)
  9838. {
  9839. // find all methods of this object
  9840. const methodNames = Object.getOwnPropertyNames(this.constructor.prototype)
  9841. .filter(property => typeof this[property] === 'function')
  9842. .filter(property => property !== 'constructor');
  9843. // bind all methods to this object
  9844. methodNames.forEach(methodName => {
  9845. this[methodName] = this[methodName].bind(this);
  9846. });
  9847. /** @type {SpeedyMatrixWASMMemory} WASM memory */
  9848. this.memory = memory;
  9849. /** @type {CStringUtils} utilities related to C strings */
  9850. this.cstring = new CStringUtils(memory);
  9851. // done!
  9852. return Object.freeze(this);
  9853. }
  9854. /**
  9855. * Prints a message
  9856. * @param {number} ptr pointer to char
  9857. */
  9858. print(ptr)
  9859. {
  9860. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.log(this.cstring.get(ptr));
  9861. }
  9862. /**
  9863. * Throws an error
  9864. * @param {number} ptr pointer to char
  9865. */
  9866. fatal(ptr)
  9867. {
  9868. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.WebAssemblyError(this.cstring.get(ptr));
  9869. }
  9870. /**
  9871. * Fills a memory segment with a byte
  9872. * @param {number} value byte
  9873. * @param {number} start memory address, inclusive
  9874. * @param {number} end memory address greater than start, exclusive
  9875. */
  9876. bytefill(value, start, end)
  9877. {
  9878. this.memory.as.uint8.fill(value, start, end);
  9879. }
  9880. /**
  9881. * Copy a memory segment to another segment
  9882. * @param {number} target memory address, where we'll start writing
  9883. * @param {number} start memory address, where we'll start copying (inclusive)
  9884. * @param {number} end memory address, where we'll end the copy (exclusive)
  9885. */
  9886. copyWithin(target, start, end)
  9887. {
  9888. this.memory.as.uint8.copyWithin(target, start, end);
  9889. }
  9890. }
  9891. /**
  9892. * Utilities related to C strings
  9893. */
  9894. class CStringUtils
  9895. {
  9896. /**
  9897. * Constructor
  9898. * @param {SpeedyMatrixWASMMemory} memory
  9899. */
  9900. constructor(memory)
  9901. {
  9902. /** @type {TextDecoder} */
  9903. this._decoder = new TextDecoder('utf-8');
  9904. /** @type {SpeedyMatrixWASMMemory} */
  9905. this._memory = memory;
  9906. }
  9907. /**
  9908. * Convert a C string to a JavaScript string
  9909. * @param {number} ptr pointer to char
  9910. * @returns {string}
  9911. */
  9912. get(ptr)
  9913. {
  9914. const byte = this._memory.as.uint8;
  9915. const size = this._memory.as.uint8.byteLength;
  9916. let p = ptr;
  9917. while(p < size && 0 !== byte[p])
  9918. ++p;
  9919. return this._decoder.decode(byte.subarray(ptr, p));
  9920. }
  9921. }
  9922. /**
  9923. * WebAssembly loader
  9924. * @param {SpeedyMatrixWASMMemory} memory
  9925. */
  9926. (function loadWASM(memory) {
  9927. const base64decode = data => Uint8Array.from(atob(data), v => v.charCodeAt(0));
  9928. // Endianness check
  9929. if(!_utils_globals__WEBPACK_IMPORTED_MODULE_3__.LITTLE_ENDIAN)
  9930. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.NotSupportedError(`Can't run WebAssembly code: not in a little-endian machine!`);
  9931. // Load the WASM binary
  9932. _speedy_promise__WEBPACK_IMPORTED_MODULE_0__.SpeedyPromise.resolve(WASM_BINARY)
  9933. .then(data => base64decode(data))
  9934. .then(bytes => WebAssembly.instantiate(bytes, {
  9935. env: {
  9936. memory: memory.as.object,
  9937. ...SpeedyMatrixWASM.imports(memory),
  9938. }
  9939. }))
  9940. .then(wasm => {
  9941. _instance = wasm.instance;
  9942. _module = wasm.module;
  9943. wasm.instance.exports.srand((Date.now() * 0.001) & 0xffffffff); // srand(time(NULL))
  9944. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.log(`The WebAssembly routines have been loaded!`);
  9945. })
  9946. .catch(err => {
  9947. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.WebAssemblyError(`Can't load the WebAssembly routines: ${err}`, err);
  9948. });
  9949. })(_memory);
  9950. /***/ }),
  9951. /***/ "./src/core/speedy-matrix.js":
  9952. /*!***********************************!*\
  9953. !*** ./src/core/speedy-matrix.js ***!
  9954. \***********************************/
  9955. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_454013__) => {
  9956. "use strict";
  9957. __nested_webpack_require_454013__.r(__webpack_exports__);
  9958. /* harmony export */ __nested_webpack_require_454013__.d(__webpack_exports__, {
  9959. /* harmony export */ "SpeedyMatrix": () => (/* binding */ SpeedyMatrix)
  9960. /* harmony export */ });
  9961. /* harmony import */ var _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_454013__(/*! ./speedy-matrix-expr */ "./src/core/speedy-matrix-expr.js");
  9962. /* harmony import */ var _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_454013__(/*! ./speedy-matrix-wasm */ "./src/core/speedy-matrix-wasm.js");
  9963. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_454013__(/*! ./speedy-promise */ "./src/core/speedy-promise.js");
  9964. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_454013__(/*! ../utils/utils */ "./src/utils/utils.js");
  9965. /*
  9966. * speedy-vision.js
  9967. * GPU-accelerated Computer Vision for JavaScript
  9968. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  9969. *
  9970. * Licensed under the Apache License, Version 2.0 (the "License");
  9971. * you may not use this file except in compliance with the License.
  9972. * You may obtain a copy of the License at
  9973. *
  9974. * http://www.apache.org/licenses/LICENSE-2.0
  9975. *
  9976. * Unless required by applicable law or agreed to in writing, software
  9977. * distributed under the License is distributed on an "AS IS" BASIS,
  9978. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9979. * See the License for the specific language governing permissions and
  9980. * limitations under the License.
  9981. *
  9982. * speedy-matrix.js
  9983. * Matrix class
  9984. */
  9985. /** @typedef {"float32"} SpeedyMatrixDtype Matrix data type */
  9986. /** @typedef {Float32Array} SpeedyMatrixBufferType Buffer type */
  9987. /** @typedef {Float32ArrayConstructor} SpeedyMatrixBufferTypeConstructor Buffer class */
  9988. /** @typedef {import('./speedy-matrix-wasm').SpeedyMatrixWASMMemory} SpeedyMatrixWASMMemory */
  9989. /** @typedef {import('./speedy-matrix-wasm').SpeedyMatrixWASMHandle} SpeedyMatrixWASMHandle */
  9990. /**
  9991. * Matrix class
  9992. */
  9993. class SpeedyMatrix extends _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr
  9994. {
  9995. /**
  9996. * @private
  9997. *
  9998. * Low-level constructor
  9999. * @param {number} rows number of rows
  10000. * @param {number} columns number of columns
  10001. * @param {number} step0 step size between two consecutive elements (e.g., 1)
  10002. * @param {number} step1 step size between two consecutive columns (e.g., rows)
  10003. * @param {SpeedyMatrixBufferType} data entries in column-major format
  10004. */
  10005. constructor(rows, columns, step0, step1, data)
  10006. {
  10007. super(rows, columns, _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.DEFAULT_DTYPE);
  10008. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(data.constructor === _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE[this.dtype]);
  10009. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(step0 > 0 && step1 >= step0);
  10010. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(
  10011. data.length + rows * columns === 0 || // empty matrix and empty buffer, or
  10012. data.length === 1 + step0 * (rows - 1) + step1 * (columns - 1) // correctly sized buffer
  10013. );
  10014. /** @type {number} step size between two consecutive elements */
  10015. this._step0 = step0 | 0;
  10016. /** @type {number} step size between two consecutive columns */
  10017. this._step1 = step1 | 0;
  10018. /** @type {SpeedyMatrixBufferType} buffer containing the entries of the matrix in column-major order */
  10019. this._data = data;
  10020. }
  10021. /**
  10022. * Create a new matrix with the specified size and entries
  10023. * @param {number} rows number of rows
  10024. * @param {number} columns number of columns
  10025. * @param {number[]} entries in column-major format
  10026. * @param {SpeedyMatrixDtype} [dtype] data type
  10027. * @returns {SpeedyMatrix}
  10028. */
  10029. static Create(rows, columns, entries, dtype = _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.DEFAULT_DTYPE)
  10030. {
  10031. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(rows * columns > 0, `Can't create a matrix without a shape`);
  10032. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(rows * columns === entries.length, `Can't create matrix: expected ${rows * columns} entries, but found ${entries.length}`);
  10033. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(Object.prototype.hasOwnProperty.call(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE, dtype), `Invalid dtype: "${dtype}"`);
  10034. return new SpeedyMatrix(rows, columns, 1, rows, Reflect.construct(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE[dtype], [entries]));
  10035. }
  10036. /**
  10037. * Create a new matrix filled with zeros with the specified size
  10038. * @param {number} rows number of rows
  10039. * @param {number} [columns] number of columns
  10040. * @param {SpeedyMatrixDtype} [dtype] data type
  10041. * @returns {SpeedyMatrix}
  10042. */
  10043. static Zeros(rows, columns = rows, dtype = _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.DEFAULT_DTYPE)
  10044. {
  10045. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(rows * columns > 0, `Can't create a matrix without a shape`);
  10046. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(Object.prototype.hasOwnProperty.call(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE, dtype), `Invalid dtype: "${dtype}"`);
  10047. return new SpeedyMatrix(rows, columns, 1, rows, Reflect.construct(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE[dtype], [rows * columns]));
  10048. }
  10049. /**
  10050. * Create a new matrix filled with ones with the specified size
  10051. * @param {number} rows number of rows
  10052. * @param {number} [columns] number of columns
  10053. * @param {SpeedyMatrixDtype} [dtype] data type
  10054. * @returns {SpeedyMatrix}
  10055. */
  10056. static Ones(rows, columns = rows, dtype = _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.DEFAULT_DTYPE)
  10057. {
  10058. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(rows * columns > 0, `Can't create a matrix without a shape`);
  10059. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(Object.prototype.hasOwnProperty.call(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE, dtype), `Invalid dtype: "${dtype}"`);
  10060. return new SpeedyMatrix(rows, columns, 1, rows, Reflect.construct(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE[dtype], [rows * columns]).fill(1));
  10061. }
  10062. /**
  10063. * Create a new identity matrix with the specified size
  10064. * @param {number} rows number of rows
  10065. * @param {number} [columns] number of columns
  10066. * @param {SpeedyMatrixDtype} [dtype] data type
  10067. * @returns {SpeedyMatrix}
  10068. */
  10069. static Eye(rows, columns = rows, dtype = _speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.DEFAULT_DTYPE)
  10070. {
  10071. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(rows * columns > 0, `Can't create a matrix without a shape`);
  10072. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(Object.prototype.hasOwnProperty.call(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE, dtype), `Invalid dtype: "${dtype}"`);
  10073. const data = Reflect.construct(_speedy_matrix_expr__WEBPACK_IMPORTED_MODULE_0__.SpeedyMatrixExpr.BUFFER_TYPE[dtype], [rows * columns]);
  10074. for(let j = Math.min(rows, columns) - 1; j >= 0; j--)
  10075. data[j * rows + j] = 1;
  10076. return new SpeedyMatrix(rows, columns, 1, rows, data);
  10077. }
  10078. /**
  10079. * Evaluate an expression synchronously and store the result in a new matrix
  10080. * @param {SpeedyMatrixExpr} expr matrix expression
  10081. * @returns {SpeedyMatrix}
  10082. */
  10083. static From(expr)
  10084. {
  10085. return SpeedyMatrix.Zeros(expr.rows, expr.columns, expr.dtype).setToSync(expr);
  10086. }
  10087. /**
  10088. * Returns a promise that resolves immediately if the WebAssembly routines
  10089. * are ready to be used, or as soon as they do become ready
  10090. * @returns {SpeedyPromise<void>}
  10091. */
  10092. static ready()
  10093. {
  10094. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(_ => void(0));
  10095. }
  10096. /**
  10097. * Get the underlying buffer
  10098. * @returns {SpeedyMatrixBufferType}
  10099. */
  10100. get data()
  10101. {
  10102. return this._data;
  10103. }
  10104. /**
  10105. * Row-step
  10106. * @returns {number} defaults to 1
  10107. */
  10108. get step0()
  10109. {
  10110. return this._step0;
  10111. }
  10112. /**
  10113. * Column-step
  10114. * @returns {number} defaults to this.rows
  10115. */
  10116. get step1()
  10117. {
  10118. return this._step1;
  10119. }
  10120. /**
  10121. * Extract a block from this matrix. Use a shared underlying buffer
  10122. * @param {number} firstRow
  10123. * @param {number} lastRow
  10124. * @param {number} firstColumn
  10125. * @param {number} lastColumn
  10126. * @returns {SpeedyMatrix}
  10127. */
  10128. block(firstRow, lastRow, firstColumn, lastColumn)
  10129. {
  10130. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(
  10131. firstRow <= lastRow && firstColumn <= lastColumn,
  10132. `Invalid indices: [${firstRow}:${lastRow},${firstColumn}:${lastColumn}]`
  10133. );
  10134. // ensure that the indices are within bounds
  10135. firstRow = Math.max(firstRow, 0);
  10136. lastRow = Math.min(lastRow, this._rows - 1);
  10137. firstColumn = Math.max(firstColumn, 0);
  10138. lastColumn = Math.min(lastColumn, this._columns - 1);
  10139. // compute the dimensions of the new submatrix
  10140. const rows = lastRow - firstRow + 1;
  10141. const columns = lastColumn - firstColumn + 1;
  10142. // obtain the relevant portion of the data
  10143. const step0 = this._step0, step1 = this._step1;
  10144. const begin = firstRow * step0 + firstColumn * step1; // inclusive
  10145. const end = 1 + lastRow * step0 + lastColumn * step1; // exclusive
  10146. // create new matrix
  10147. return new SpeedyMatrix(rows, columns, step0, step1, this._data.subarray(begin, end));
  10148. }
  10149. /**
  10150. * Extract a row from this matrix
  10151. * @param {number} index 0-based
  10152. * @returns {SpeedyMatrix}
  10153. */
  10154. row(index)
  10155. {
  10156. return this.block(index, index, 0, this._columns - 1);
  10157. }
  10158. /**
  10159. * Extract a column from this matrix
  10160. * @param {number} index 0-based
  10161. * @returns {SpeedyMatrix}
  10162. */
  10163. column(index)
  10164. {
  10165. return this.block(0, this._rows - 1, index, index);
  10166. }
  10167. /**
  10168. * Extract the main diagonal from this matrix
  10169. * @returns {SpeedyMatrix} as a column-vector
  10170. */
  10171. diagonal()
  10172. {
  10173. const diagsize = Math.min(this._rows, this._columns);
  10174. // compute the dimensions of the new submatrix
  10175. const rows = diagsize; // make it a column vector
  10176. const columns = 1;
  10177. // obtain the relevant portion of the data
  10178. const diagstep = this._step0 + this._step1; // jump a row and a column
  10179. const begin = 0; // inclusive
  10180. const end = 1 + (diagsize - 1) * diagstep; // exclusive
  10181. // create new matrix
  10182. return new SpeedyMatrix(rows, columns, diagstep, diagstep, this._data.subarray(begin, end));
  10183. }
  10184. /**
  10185. * Read a single entry of this matrix
  10186. * @param {number} row 0-based index
  10187. * @param {number} column 0-based index
  10188. * @returns {number}
  10189. */
  10190. at(row, column)
  10191. {
  10192. if(row >= 0 && row < this._rows && column >= 0 && column < this._columns)
  10193. return this._data[this._step0 * row + this._step1 * column];
  10194. else
  10195. return Number.NaN;
  10196. }
  10197. /**
  10198. * Read the entries of the matrix in column-major format
  10199. * @returns {number[]}
  10200. */
  10201. read()
  10202. {
  10203. const entries = new Array(this._rows * this._columns);
  10204. const step0 = this._step0, step1 = this._step1;
  10205. let i = 0;
  10206. for(let column = 0; column < this._columns; column++) {
  10207. for(let row = 0; row < this._rows; row++)
  10208. entries[i++] = this._data[row * step0 + column * step1];
  10209. }
  10210. return entries;
  10211. }
  10212. /**
  10213. * Returns a human-readable string representation of the matrix
  10214. * @returns {string}
  10215. */
  10216. toString()
  10217. {
  10218. const DECIMALS = 5;
  10219. const rows = this.rows, columns = this.columns;
  10220. const entries = this.read();
  10221. const mat = /** @type {number[][]} */ ( new Array(rows) );
  10222. for(let i = 0; i < rows; i++) {
  10223. mat[i] = new Array(columns);
  10224. for(let j = 0; j < columns; j++)
  10225. mat[i][j] = entries[j * rows + i];
  10226. }
  10227. const fix = x => x.toFixed(DECIMALS);
  10228. const fmt = mat.map(row => ' ' + row.map(fix).join(', ')).join(',\n');
  10229. const str = `SpeedyMatrix(rows=${rows}, columns=${columns}, data=[\n${fmt}\n])`;
  10230. return str;
  10231. }
  10232. /**
  10233. * Set the contents of this matrix to the result of an expression
  10234. * @param {SpeedyMatrixExpr} expr matrix expression
  10235. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to this
  10236. */
  10237. setTo(expr)
  10238. {
  10239. return _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.ready().then(_ => {
  10240. // TODO: add support for WebWorkers
  10241. return this.setToSync(expr);
  10242. });
  10243. }
  10244. /**
  10245. * Synchronously set the contents of this matrix to the result of an expression
  10246. * @param {SpeedyMatrixExpr} expr matrix expression
  10247. * @returns {SpeedyMatrix} this
  10248. */
  10249. setToSync(expr)
  10250. {
  10251. const { wasm, memory } = _speedy_matrix_wasm__WEBPACK_IMPORTED_MODULE_1__.SpeedyMatrixWASM.handle;
  10252. // evaluate the expression
  10253. const result = expr._evaluate(wasm, memory);
  10254. /*
  10255. // shallow copy the results to this matrix
  10256. // limitation: can't handle blocks properly
  10257. // (a tree-like structure could be useful)
  10258. this._rows = result.rows;
  10259. this._columns = result.columns;
  10260. //this._dtype = result.dtype;
  10261. this._data = result.data;
  10262. this._step0 = result.step0;
  10263. this._step1 = result.step1;
  10264. */
  10265. // validate shape
  10266. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(
  10267. this._rows === result._rows && this._columns === result._columns && this.dtype === result.dtype,
  10268. `Can't set the values of a ${this.rows} x ${this.columns} ${this.dtype} matrix to those of a ${result.rows} x ${result.columns} ${result.dtype} matrix`
  10269. );
  10270. // deep copy
  10271. const step0 = this._step0, step1 = this._step1, rstep0 = result._step0, rstep1 = result._step1;
  10272. if(step0 === rstep0 && step1 === rstep1 && this._data.length === result._data.length) {
  10273. // fast copy
  10274. this._data.set(result._data);
  10275. }
  10276. else {
  10277. // copy each element
  10278. for(let column = this._columns - 1; column >= 0; column--) {
  10279. for(let row = this._rows - 1; row >= 0; row--)
  10280. this._data[row * step0 + column * step1] = result._data[row * rstep0 + column * rstep1];
  10281. }
  10282. }
  10283. // done!
  10284. return this;
  10285. }
  10286. /**
  10287. * Fill this matrix with a scalar value
  10288. * @param {number} value
  10289. * @returns {SpeedyPromise<SpeedyMatrix>} resolves to this
  10290. */
  10291. fill(value)
  10292. {
  10293. this.fillSync(value);
  10294. return _speedy_promise__WEBPACK_IMPORTED_MODULE_2__.SpeedyPromise.resolve(this);
  10295. }
  10296. /**
  10297. * Synchronously fill this matrix with a scalar value
  10298. * @param {number} value
  10299. * @returns {SpeedyMatrix} this
  10300. */
  10301. fillSync(value)
  10302. {
  10303. value = +value;
  10304. if(this._rows * this._columns === this._data.length) {
  10305. this._data.fill(value);
  10306. return this;
  10307. }
  10308. for(let column = 0; column < this._columns; column++) {
  10309. for(let row = 0; row < this._rows; row++) {
  10310. this._data[row * this._step0 + column * this._step1] = value;
  10311. }
  10312. }
  10313. return this;
  10314. }
  10315. /**
  10316. * Evaluate this expression
  10317. * @param {WebAssembly.Instance} wasm
  10318. * @param {SpeedyMatrixWASMMemory} memory
  10319. * @returns {SpeedyMatrix}
  10320. */
  10321. _evaluate(wasm, memory)
  10322. {
  10323. return this;
  10324. }
  10325. }
  10326. /***/ }),
  10327. /***/ "./src/core/speedy-media-source.js":
  10328. /*!*****************************************!*\
  10329. !*** ./src/core/speedy-media-source.js ***!
  10330. \*****************************************/
  10331. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_470481__) => {
  10332. "use strict";
  10333. __nested_webpack_require_470481__.r(__webpack_exports__);
  10334. /* harmony export */ __nested_webpack_require_470481__.d(__webpack_exports__, {
  10335. /* harmony export */ "SpeedyMediaSource": () => (/* binding */ SpeedyMediaSource)
  10336. /* harmony export */ });
  10337. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_470481__(/*! ../utils/utils */ "./src/utils/utils.js");
  10338. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_470481__(/*! ./speedy-promise */ "./src/core/speedy-promise.js");
  10339. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_470481__(/*! ../utils/errors */ "./src/utils/errors.js");
  10340. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_470481__(/*! ../utils/types */ "./src/utils/types.js");
  10341. /*
  10342. * speedy-vision.js
  10343. * GPU-accelerated Computer Vision for JavaScript
  10344. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  10345. *
  10346. * Licensed under the Apache License, Version 2.0 (the "License");
  10347. * you may not use this file except in compliance with the License.
  10348. * You may obtain a copy of the License at
  10349. *
  10350. * http://www.apache.org/licenses/LICENSE-2.0
  10351. *
  10352. * Unless required by applicable law or agreed to in writing, software
  10353. * distributed under the License is distributed on an "AS IS" BASIS,
  10354. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10355. * See the License for the specific language governing permissions and
  10356. * limitations under the License.
  10357. *
  10358. * speedy-media-source.js
  10359. * Wrappers around <img>, <video>, <canvas>, etc.
  10360. */
  10361. /** @typedef {HTMLImageElement|HTMLVideoElement|HTMLCanvasElement|ImageBitmap} SpeedyMediaSourceNativeElement */
  10362. /** Internal token for protected constructors */
  10363. const PRIVATE_TOKEN = Symbol();
  10364. /**
  10365. * An abstract media source: a wrapper around native
  10366. * elements such as: HTMLImageElement, HTMLVideoElement,
  10367. * and so on
  10368. * @abstract
  10369. */
  10370. class SpeedyMediaSource
  10371. {
  10372. /**
  10373. * @protected Constructor
  10374. * @param {symbol} token
  10375. */
  10376. constructor(token)
  10377. {
  10378. // the constructor is not public
  10379. if(token !== PRIVATE_TOKEN)
  10380. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError();
  10381. /** @type {SpeedyMediaSourceNativeElement} underlying media object */
  10382. this._data = null;
  10383. }
  10384. /**
  10385. * Load a media source
  10386. * @param {SpeedyMediaSourceNativeElement} wrappedObject
  10387. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10388. */
  10389. static load(wrappedObject)
  10390. {
  10391. if(wrappedObject instanceof HTMLImageElement)
  10392. return SpeedyImageMediaSource.load(wrappedObject);
  10393. else if(wrappedObject instanceof HTMLVideoElement)
  10394. return SpeedyVideoMediaSource.load(wrappedObject);
  10395. else if(wrappedObject instanceof HTMLCanvasElement)
  10396. return SpeedyCanvasMediaSource.load(wrappedObject);
  10397. else if(wrappedObject instanceof ImageBitmap)
  10398. return SpeedyBitmapMediaSource.load(wrappedObject);
  10399. else
  10400. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Unsupported media type: ${wrappedObject}`);
  10401. }
  10402. /**
  10403. * The underlying wrapped object
  10404. * @returns {SpeedyMediaSourceNativeElement}
  10405. */
  10406. get data()
  10407. {
  10408. return this._data;
  10409. }
  10410. /**
  10411. * Is the underlying media loaded?
  10412. * @returns {boolean}
  10413. */
  10414. isLoaded()
  10415. {
  10416. return this._data !== null;
  10417. }
  10418. /**
  10419. * The type of the underlying media source
  10420. * @abstract
  10421. * @returns {MediaType}
  10422. */
  10423. get type()
  10424. {
  10425. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  10426. }
  10427. /**
  10428. * Media width, in pixels
  10429. * @abstract
  10430. * @returns {number}
  10431. */
  10432. get width()
  10433. {
  10434. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  10435. }
  10436. /**
  10437. * Media height, in pixels
  10438. * @abstract
  10439. * @returns {number}
  10440. */
  10441. get height()
  10442. {
  10443. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  10444. }
  10445. /**
  10446. * Clone this media source
  10447. * @abstract
  10448. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10449. */
  10450. clone()
  10451. {
  10452. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  10453. }
  10454. /**
  10455. * Release resources associated with this object
  10456. * @returns {null}
  10457. */
  10458. release()
  10459. {
  10460. return (this._data = null);
  10461. }
  10462. /**
  10463. * Load the underlying media
  10464. * @abstract
  10465. * @param {SpeedyMediaSourceNativeElement} element
  10466. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10467. */
  10468. _load(element)
  10469. {
  10470. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.AbstractMethodError();
  10471. }
  10472. /**
  10473. * Wait for an event to be triggered in an element
  10474. * @param {Element} element
  10475. * @param {string} eventName
  10476. * @param {number} [timeout] in ms
  10477. * @returns {SpeedyPromise<Element>}
  10478. */
  10479. static _waitUntil(element, eventName, timeout = 30000)
  10480. {
  10481. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise((resolve, reject) => {
  10482. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.log(`Waiting for ${eventName} to be triggered in ${element}...`);
  10483. const timer = setTimeout(() => {
  10484. reject(new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.TimeoutError(`${eventName} has not been triggered in ${element}: timeout (${timeout}ms)`));
  10485. }, timeout);
  10486. element.addEventListener(eventName, () => {
  10487. clearTimeout(timer);
  10488. resolve(element);
  10489. }, false);
  10490. });
  10491. }
  10492. }
  10493. /**
  10494. * Image media source:
  10495. * a wrapper around HTMLImageElement
  10496. */
  10497. class SpeedyImageMediaSource extends SpeedyMediaSource
  10498. {
  10499. /**
  10500. * @private Constructor
  10501. * @param {symbol} token
  10502. */
  10503. constructor(token)
  10504. {
  10505. super(token);
  10506. /** @type {HTMLImageElement} image element */
  10507. this._data = null;
  10508. }
  10509. /**
  10510. * The underlying wrapped object
  10511. * @returns {HTMLImageElement}
  10512. */
  10513. get data()
  10514. {
  10515. return this._data;
  10516. }
  10517. /**
  10518. * The type of the underlying media source
  10519. * @returns {MediaType}
  10520. */
  10521. get type()
  10522. {
  10523. return _utils_types__WEBPACK_IMPORTED_MODULE_3__.MediaType.Image;
  10524. }
  10525. /**
  10526. * Media width, in pixels
  10527. * @returns {number}
  10528. */
  10529. get width()
  10530. {
  10531. return this._data ? this._data.naturalWidth : 0;
  10532. }
  10533. /**
  10534. * Media height, in pixels
  10535. * @returns {number}
  10536. */
  10537. get height()
  10538. {
  10539. return this._data ? this._data.naturalHeight : 0;
  10540. }
  10541. /**
  10542. * Clone this media source
  10543. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10544. */
  10545. clone()
  10546. {
  10547. if(this._data == null)
  10548. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Media not loaded`);
  10549. const newNode = /** @type {HTMLImageElement} */ ( this._data.cloneNode(true) );
  10550. return SpeedyImageMediaSource.load(newNode);
  10551. }
  10552. /**
  10553. * Load the underlying media
  10554. * @param {HTMLImageElement} image
  10555. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10556. */
  10557. _load(image)
  10558. {
  10559. if(this.isLoaded())
  10560. this.release();
  10561. if(image.complete && image.naturalWidth !== 0) { // already loaded?
  10562. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise(resolve => {
  10563. this._data = image;
  10564. resolve(this);
  10565. });
  10566. }
  10567. else {
  10568. return SpeedyMediaSource._waitUntil(image, 'load').then(() => {
  10569. this._data = image;
  10570. return this;
  10571. });
  10572. }
  10573. }
  10574. /**
  10575. * Load the underlying media
  10576. * @param {HTMLImageElement} image
  10577. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10578. */
  10579. static load(image)
  10580. {
  10581. return new SpeedyImageMediaSource(PRIVATE_TOKEN)._load(image);
  10582. }
  10583. }
  10584. /**
  10585. * Video media source:
  10586. * a wrapper around HTMLVideoElement
  10587. */
  10588. class SpeedyVideoMediaSource extends SpeedyMediaSource
  10589. {
  10590. /**
  10591. * @private Constructor
  10592. * @param {symbol} token
  10593. */
  10594. constructor(token)
  10595. {
  10596. super(token);
  10597. /** @type {HTMLVideoElement} video element */
  10598. this._data = null;
  10599. }
  10600. /**
  10601. * The underlying wrapped object
  10602. * @returns {HTMLVideoElement}
  10603. */
  10604. get data()
  10605. {
  10606. return this._data;
  10607. }
  10608. /**
  10609. * The type of the underlying media source
  10610. * @returns {MediaType}
  10611. */
  10612. get type()
  10613. {
  10614. return _utils_types__WEBPACK_IMPORTED_MODULE_3__.MediaType.Video;
  10615. }
  10616. /**
  10617. * Media width, in pixels
  10618. * @returns {number}
  10619. */
  10620. get width()
  10621. {
  10622. // Warning: videoWidth & videoHeight may change at any time !!!
  10623. // so you can't cache these dimensions
  10624. return this._data ? this._data.videoWidth : 0;
  10625. }
  10626. /**
  10627. * Media height, in pixels
  10628. * @returns {number}
  10629. */
  10630. get height()
  10631. {
  10632. return this._data ? this._data.videoHeight : 0;
  10633. }
  10634. /**
  10635. * Clone this media source
  10636. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10637. */
  10638. clone()
  10639. {
  10640. if(this._data == null)
  10641. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Media not loaded`);
  10642. const newNode = /** @type {HTMLVideoElement} */ ( this._data.cloneNode(true) );
  10643. return SpeedyVideoMediaSource.load(newNode);
  10644. }
  10645. /**
  10646. * Load the underlying media
  10647. * @param {HTMLVideoElement} video
  10648. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10649. */
  10650. _load(video)
  10651. {
  10652. if(this.isLoaded())
  10653. this.release();
  10654. if(video.readyState >= 4) { // already loaded?
  10655. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise(resolve => {
  10656. this._data = video;
  10657. resolve(this);
  10658. });
  10659. }
  10660. else {
  10661. // waitUntil('canplay'); // use readyState >= 3
  10662. return SpeedyMediaSource._waitUntil(video, 'canplaythrough').then(() => {
  10663. this._data = video;
  10664. return this;
  10665. })
  10666. }
  10667. }
  10668. /**
  10669. * Load the underlying media
  10670. * @param {HTMLVideoElement} video
  10671. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10672. */
  10673. static load(video)
  10674. {
  10675. return new SpeedyVideoMediaSource(PRIVATE_TOKEN)._load(video);
  10676. }
  10677. }
  10678. /**
  10679. * Canvas media source:
  10680. * a wrapper around HTMLCanvasElement
  10681. */
  10682. class SpeedyCanvasMediaSource extends SpeedyMediaSource
  10683. {
  10684. /**
  10685. * @private Constructor
  10686. * @param {symbol} token
  10687. */
  10688. constructor(token)
  10689. {
  10690. super(token);
  10691. /** @type {HTMLCanvasElement} canvas element */
  10692. this._data = null;
  10693. }
  10694. /**
  10695. * The underlying wrapped object
  10696. * @returns {HTMLCanvasElement}
  10697. */
  10698. get data()
  10699. {
  10700. return this._data;
  10701. }
  10702. /**
  10703. * The type of the underlying media source
  10704. * @returns {MediaType}
  10705. */
  10706. get type()
  10707. {
  10708. return _utils_types__WEBPACK_IMPORTED_MODULE_3__.MediaType.Canvas;
  10709. }
  10710. /**
  10711. * Media width, in pixels
  10712. * @returns {number}
  10713. */
  10714. get width()
  10715. {
  10716. return this._data ? this._data.width : 0;
  10717. }
  10718. /**
  10719. * Media height, in pixels
  10720. * @returns {number}
  10721. */
  10722. get height()
  10723. {
  10724. return this._data ? this._data.height : 0;
  10725. }
  10726. /**
  10727. * Clone this media source
  10728. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10729. */
  10730. clone()
  10731. {
  10732. if(this._data == null)
  10733. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Media not loaded`);
  10734. const newCanvas = _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.createCanvas(this.width, this.height);
  10735. const newContext = newCanvas.getContext('2d');
  10736. newContext.drawImage(this._data, 0, 0);
  10737. return SpeedyCanvasMediaSource.load(newCanvas);
  10738. }
  10739. /**
  10740. * Load the underlying media
  10741. * @param {HTMLCanvasElement} canvas
  10742. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10743. */
  10744. _load(canvas)
  10745. {
  10746. if(this.isLoaded())
  10747. this.release();
  10748. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise(resolve => {
  10749. this._data = canvas;
  10750. resolve(this);
  10751. });
  10752. }
  10753. /**
  10754. * Load the underlying media
  10755. * @param {HTMLCanvasElement} canvas
  10756. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10757. */
  10758. static load(canvas)
  10759. {
  10760. return new SpeedyCanvasMediaSource(PRIVATE_TOKEN)._load(canvas);
  10761. }
  10762. }
  10763. /**
  10764. * Bitmap media source:
  10765. * a wrapper around ImageBitmap
  10766. */
  10767. class SpeedyBitmapMediaSource extends SpeedyMediaSource
  10768. {
  10769. /**
  10770. * @private Constructor
  10771. * @param {symbol} token
  10772. */
  10773. constructor(token)
  10774. {
  10775. super(token);
  10776. /** @type {ImageBitmap} image bitmap */
  10777. this._data = null;
  10778. }
  10779. /**
  10780. * The underlying wrapped object
  10781. * @returns {ImageBitmap}
  10782. */
  10783. get data()
  10784. {
  10785. return this._data;
  10786. }
  10787. /**
  10788. * The type of the underlying media source
  10789. * @returns {MediaType}
  10790. */
  10791. get type()
  10792. {
  10793. return _utils_types__WEBPACK_IMPORTED_MODULE_3__.MediaType.Bitmap;
  10794. }
  10795. /**
  10796. * Media width, in pixels
  10797. * @returns {number}
  10798. */
  10799. get width()
  10800. {
  10801. return this._data ? this._data.width : 0;
  10802. }
  10803. /**
  10804. * Media height, in pixels
  10805. * @returns {number}
  10806. */
  10807. get height()
  10808. {
  10809. return this._data ? this._data.height : 0;
  10810. }
  10811. /**
  10812. * Clone this media source
  10813. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10814. */
  10815. clone()
  10816. {
  10817. if(this._data == null)
  10818. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`Media not loaded`);
  10819. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise((resolve, reject) => {
  10820. createImageBitmap(this._data).then(
  10821. newBitmap => {
  10822. const newSource = new SpeedyBitmapMediaSource(PRIVATE_TOKEN);
  10823. newSource._load(newBitmap).then(resolve, reject);
  10824. },
  10825. reject
  10826. );
  10827. });
  10828. }
  10829. /**
  10830. * Release resources associated with this object
  10831. * @returns {null}
  10832. */
  10833. release()
  10834. {
  10835. if(this._data != null)
  10836. this._data.close();
  10837. return super.release();
  10838. }
  10839. /**
  10840. * Load the underlying media
  10841. * @param {ImageBitmap} bitmap
  10842. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10843. */
  10844. _load(bitmap)
  10845. {
  10846. if(this.isLoaded())
  10847. this.release();
  10848. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise(resolve => {
  10849. this._data = bitmap;
  10850. resolve(this);
  10851. });
  10852. }
  10853. /**
  10854. * Load the underlying media
  10855. * @param {ImageBitmap} bitmap
  10856. * @returns {SpeedyPromise<SpeedyMediaSource>}
  10857. */
  10858. static load(bitmap)
  10859. {
  10860. return new SpeedyBitmapMediaSource(PRIVATE_TOKEN)._load(bitmap);
  10861. }
  10862. }
  10863. /***/ }),
  10864. /***/ "./src/core/speedy-media.js":
  10865. /*!**********************************!*\
  10866. !*** ./src/core/speedy-media.js ***!
  10867. \**********************************/
  10868. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_485820__) => {
  10869. "use strict";
  10870. __nested_webpack_require_485820__.r(__webpack_exports__);
  10871. /* harmony export */ __nested_webpack_require_485820__.d(__webpack_exports__, {
  10872. /* harmony export */ "SpeedyMedia": () => (/* binding */ SpeedyMedia)
  10873. /* harmony export */ });
  10874. /* harmony import */ var _gpu_speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_485820__(/*! ../gpu/speedy-gpu */ "./src/gpu/speedy-gpu.js");
  10875. /* harmony import */ var _gpu_speedy_texture__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_485820__(/*! ../gpu/speedy-texture */ "./src/gpu/speedy-texture.js");
  10876. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_485820__(/*! ../utils/types */ "./src/utils/types.js");
  10877. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_485820__(/*! ../utils/errors */ "./src/utils/errors.js");
  10878. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_485820__(/*! ../utils/utils */ "./src/utils/utils.js");
  10879. /* harmony import */ var _speedy_media_source__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_485820__(/*! ./speedy-media-source */ "./src/core/speedy-media-source.js");
  10880. /* harmony import */ var _speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_485820__(/*! ./speedy-promise */ "./src/core/speedy-promise.js");
  10881. /* harmony import */ var _speedy_size__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_485820__(/*! ./speedy-size */ "./src/core/speedy-size.js");
  10882. /*
  10883. * speedy-vision.js
  10884. * GPU-accelerated Computer Vision for JavaScript
  10885. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  10886. *
  10887. * Licensed under the Apache License, Version 2.0 (the "License");
  10888. * you may not use this file except in compliance with the License.
  10889. * You may obtain a copy of the License at
  10890. *
  10891. * http://www.apache.org/licenses/LICENSE-2.0
  10892. *
  10893. * Unless required by applicable law or agreed to in writing, software
  10894. * distributed under the License is distributed on an "AS IS" BASIS,
  10895. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10896. * See the License for the specific language governing permissions and
  10897. * limitations under the License.
  10898. *
  10899. * speedy-media.js
  10900. * SpeedyMedia implementation
  10901. */
  10902. /** @typedef {import('./speedy-media-source').SpeedyMediaSourceNativeElement} SpeedyMediaSourceNativeElement */
  10903. /**
  10904. * @typedef {object} SpeedyMediaOptions
  10905. * @property {ImageFormat} [format] default is RGBA
  10906. */
  10907. /** A helper used to keep the constructor of SpeedyMedia private */
  10908. const PRIVATE_TOKEN = Symbol();
  10909. /**
  10910. * SpeedyMedia encapsulates a media element
  10911. * (e.g., image, video, canvas)
  10912. */
  10913. class SpeedyMedia
  10914. {
  10915. /**
  10916. * @private Constructor. It receives a VALID media source that is ALREADY LOADED.
  10917. * @param {symbol} token
  10918. * @param {SpeedyMediaSource} source
  10919. * @param {SpeedyMediaOptions} [options] options object
  10920. */
  10921. constructor(token, source, options = {})
  10922. {
  10923. // private constructor
  10924. if(token !== PRIVATE_TOKEN)
  10925. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalOperationError();
  10926. /** @type {SpeedyMediaSource} media source */
  10927. this._source = source;
  10928. /** @type {ImageFormat} format */
  10929. this._format = options.format !== undefined ? options.format : _utils_types__WEBPACK_IMPORTED_MODULE_2__.ImageFormat.RGBA;
  10930. /** @type {SpeedyMediaOptions} options */
  10931. this._options = Object.freeze({ ...options, format: this._format });
  10932. // validate
  10933. if(!source.isLoaded())
  10934. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalOperationError(`Source not loaded: ${source}`);
  10935. else if(this._format !== _utils_types__WEBPACK_IMPORTED_MODULE_2__.ImageFormat.RGBA && this._format !== _utils_types__WEBPACK_IMPORTED_MODULE_2__.ImageFormat.GREY)
  10936. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`Invalid format: ${this._format}`);
  10937. }
  10938. /**
  10939. * Load a media source
  10940. * Will wait until the HTML media source is loaded
  10941. * @param {SpeedyMediaSourceNativeElement} mediaSource An image, video or canvas
  10942. * @param {SpeedyMediaOptions} [options] options object
  10943. * @param {boolean} [log] show log message?
  10944. * @returns {SpeedyPromise<SpeedyMedia>}
  10945. */
  10946. static load(mediaSource, options = {}, log = true)
  10947. {
  10948. return _speedy_media_source__WEBPACK_IMPORTED_MODULE_5__.SpeedyMediaSource.load(mediaSource).then(source => {
  10949. _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.assert(source.width !== 0 && source.height !== 0);
  10950. // FIXME user could pass an invalid format in options if ImageFormat is made public
  10951. const media = new SpeedyMedia(PRIVATE_TOKEN, source, options);
  10952. // show log message
  10953. if(log)
  10954. _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.log(`Loaded SpeedyMedia with a ${mediaSource}.`);
  10955. // done!
  10956. return media;
  10957. });
  10958. }
  10959. /**
  10960. * The media element (image, video, canvas) encapsulated by this SpeedyMedia object
  10961. * @returns {SpeedyMediaSourceNativeElement} the media element
  10962. */
  10963. get source()
  10964. {
  10965. return this._source ? this._source.data : null;
  10966. }
  10967. /**
  10968. * The type of the media attached to this SpeedyMedia object
  10969. * @returns {"image" | "video" | "canvas" | "bitmap" | "unknown"}
  10970. */
  10971. get type()
  10972. {
  10973. if(this.isReleased())
  10974. return 'unknown';
  10975. switch(this._source.type) {
  10976. case _utils_types__WEBPACK_IMPORTED_MODULE_2__.MediaType.Image:
  10977. return 'image';
  10978. case _utils_types__WEBPACK_IMPORTED_MODULE_2__.MediaType.Video:
  10979. return 'video';
  10980. case _utils_types__WEBPACK_IMPORTED_MODULE_2__.MediaType.Canvas:
  10981. return 'canvas';
  10982. case _utils_types__WEBPACK_IMPORTED_MODULE_2__.MediaType.Bitmap:
  10983. return 'bitmap';
  10984. default: // this shouldn't happen
  10985. return 'unknown';
  10986. }
  10987. }
  10988. /**
  10989. * Gets the width of the media
  10990. * @returns {number} media width
  10991. */
  10992. get width()
  10993. {
  10994. return this._source ? this._source.width : 0;
  10995. }
  10996. /**
  10997. * Gets the height of the media
  10998. * @returns {number} media height
  10999. */
  11000. get height()
  11001. {
  11002. return this._source ? this._source.height : 0;
  11003. }
  11004. /**
  11005. * The size of this media, in pixels
  11006. * @returns {SpeedySize}
  11007. */
  11008. get size()
  11009. {
  11010. return this._source ? new _speedy_size__WEBPACK_IMPORTED_MODULE_7__.SpeedySize(this._source.width, this._source.height) : new _speedy_size__WEBPACK_IMPORTED_MODULE_7__.SpeedySize(0, 0);
  11011. }
  11012. /**
  11013. * Returns a read-only object featuring advanced options
  11014. * related to this SpeedyMedia object
  11015. * @returns {SpeedyMediaOptions}
  11016. */
  11017. get options()
  11018. {
  11019. return this._options;
  11020. }
  11021. /**
  11022. * Releases resources associated with this media
  11023. * @returns {null}
  11024. */
  11025. release()
  11026. {
  11027. if(!this.isReleased()) {
  11028. _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.log('Releasing SpeedyMedia object...');
  11029. this._source = this._source.release();
  11030. }
  11031. return null;
  11032. }
  11033. /**
  11034. * Has this media been released?
  11035. * @returns {boolean}
  11036. */
  11037. isReleased()
  11038. {
  11039. return this._source == null;
  11040. }
  11041. /**
  11042. * Clones the SpeedyMedia object
  11043. * @returns {SpeedyPromise<SpeedyMedia>} a clone object
  11044. */
  11045. clone()
  11046. {
  11047. // has the media been released?
  11048. if(this.isReleased())
  11049. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalOperationError(`Can't clone a SpeedyMedia that has been released`);
  11050. // clone the object
  11051. const clone = new SpeedyMedia(PRIVATE_TOKEN, this._source, this._options);
  11052. // done!
  11053. return _speedy_promise__WEBPACK_IMPORTED_MODULE_6__.SpeedyPromise.resolve(clone);
  11054. }
  11055. /**
  11056. * Converts the media to an ImageBitmap
  11057. * @returns {SpeedyPromise<ImageBitmap>}
  11058. */
  11059. toBitmap()
  11060. {
  11061. if(this.isReleased())
  11062. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalOperationError('Can\'t convert SpeedyMedia to ImageBitmap: the media has been released');
  11063. else if(!this._source.isLoaded())
  11064. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalOperationError('Can\'t convert SpeedyMedia to bitmap: the media hasn\'t been loaded');
  11065. else if(this._source.type == _utils_types__WEBPACK_IMPORTED_MODULE_2__.MediaType.Bitmap)
  11066. return _speedy_promise__WEBPACK_IMPORTED_MODULE_6__.SpeedyPromise.resolve(this._source.data);
  11067. else
  11068. return new _speedy_promise__WEBPACK_IMPORTED_MODULE_6__.SpeedyPromise((resolve, reject) => createImageBitmap(this._source.data).then(resolve, reject));
  11069. }
  11070. }
  11071. /***/ }),
  11072. /***/ "./src/core/speedy-namespace.js":
  11073. /*!**************************************!*\
  11074. !*** ./src/core/speedy-namespace.js ***!
  11075. \**************************************/
  11076. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_494880__) => {
  11077. "use strict";
  11078. __nested_webpack_require_494880__.r(__webpack_exports__);
  11079. /* harmony export */ __nested_webpack_require_494880__.d(__webpack_exports__, {
  11080. /* harmony export */ "SpeedyNamespace": () => (/* binding */ SpeedyNamespace)
  11081. /* harmony export */ });
  11082. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_494880__(/*! ../utils/errors */ "./src/utils/errors.js");
  11083. /*
  11084. * speedy-vision.js
  11085. * GPU-accelerated Computer Vision for JavaScript
  11086. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11087. *
  11088. * Licensed under the Apache License, Version 2.0 (the "License");
  11089. * you may not use this file except in compliance with the License.
  11090. * You may obtain a copy of the License at
  11091. *
  11092. * http://www.apache.org/licenses/LICENSE-2.0
  11093. *
  11094. * Unless required by applicable law or agreed to in writing, software
  11095. * distributed under the License is distributed on an "AS IS" BASIS,
  11096. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11097. * See the License for the specific language governing permissions and
  11098. * limitations under the License.
  11099. *
  11100. * speedy-namespace.js
  11101. * Symbolizes a namespace
  11102. */
  11103. /**
  11104. * An abstract namespace
  11105. * @abstract
  11106. */
  11107. class SpeedyNamespace
  11108. {
  11109. /**
  11110. * Namespaces can't be instantiated.
  11111. * Only static methods are allowed.
  11112. * @abstract
  11113. * @throws SpeedyError
  11114. */
  11115. constructor()
  11116. {
  11117. // only static methods are allowed
  11118. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_0__.AbstractMethodError(`Namespaces can't be instantiated`);
  11119. }
  11120. }
  11121. /***/ }),
  11122. /***/ "./src/core/speedy-point.js":
  11123. /*!**********************************!*\
  11124. !*** ./src/core/speedy-point.js ***!
  11125. \**********************************/
  11126. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_496655__) => {
  11127. "use strict";
  11128. __nested_webpack_require_496655__.r(__webpack_exports__);
  11129. /* harmony export */ __nested_webpack_require_496655__.d(__webpack_exports__, {
  11130. /* harmony export */ "SpeedyPoint2": () => (/* binding */ SpeedyPoint2)
  11131. /* harmony export */ });
  11132. /* harmony import */ var _speedy_vector__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_496655__(/*! ./speedy-vector */ "./src/core/speedy-vector.js");
  11133. /*
  11134. * speedy-vision.js
  11135. * GPU-accelerated Computer Vision for JavaScript
  11136. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11137. *
  11138. * Licensed under the Apache License, Version 2.0 (the "License");
  11139. * you may not use this file except in compliance with the License.
  11140. * You may obtain a copy of the License at
  11141. *
  11142. * http://www.apache.org/licenses/LICENSE-2.0
  11143. *
  11144. * Unless required by applicable law or agreed to in writing, software
  11145. * distributed under the License is distributed on an "AS IS" BASIS,
  11146. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11147. * See the License for the specific language governing permissions and
  11148. * limitations under the License.
  11149. *
  11150. * speedy-point.js
  11151. * Points in space
  11152. */
  11153. /**
  11154. * 2D point
  11155. */
  11156. class SpeedyPoint2
  11157. {
  11158. /**
  11159. * Create a 2D point
  11160. * @param {number} x
  11161. * @param {number} y
  11162. */
  11163. constructor(x, y)
  11164. {
  11165. /** @type {number} x coordinate */
  11166. this._x = +x;
  11167. /** @type {number} y coordinate */
  11168. this._y = +y;
  11169. }
  11170. //
  11171. // ===== METHODS =====
  11172. //
  11173. /**
  11174. * x-coordinate
  11175. * @returns {number}
  11176. */
  11177. get x()
  11178. {
  11179. return this._x;
  11180. }
  11181. /**
  11182. * x-coordinate
  11183. * @param {number} value
  11184. */
  11185. set x(value)
  11186. {
  11187. this._x = +value;
  11188. }
  11189. /**
  11190. * y-coordinate
  11191. * @returns {number}
  11192. */
  11193. get y()
  11194. {
  11195. return this._y;
  11196. }
  11197. /**
  11198. * y-coordinate
  11199. * @param {number} value
  11200. */
  11201. set y(value)
  11202. {
  11203. this._y = +value;
  11204. }
  11205. /**
  11206. * Convert to string
  11207. * @returns {string}
  11208. */
  11209. toString()
  11210. {
  11211. return `SpeedyPoint2(${this.x.toFixed(5)}, ${this.y.toFixed(5)})`;
  11212. }
  11213. /**
  11214. * Add a vector to this point
  11215. * @param {SpeedyVector2} v
  11216. * @returns {SpeedyPoint2}
  11217. */
  11218. plus(v)
  11219. {
  11220. return new SpeedyPoint2(this.x + v.x, this.y + v.y);
  11221. }
  11222. /**
  11223. * Subtracts a point p from this point
  11224. * @param {SpeedyPoint2} p
  11225. * @returns {SpeedyVector2}
  11226. */
  11227. minus(p)
  11228. {
  11229. return new _speedy_vector__WEBPACK_IMPORTED_MODULE_0__.SpeedyVector2(this.x - p.x, this.y - p.y);
  11230. }
  11231. /**
  11232. * Is this point equal to p?
  11233. * @param {SpeedyPoint2} p
  11234. * @returns {boolean}
  11235. */
  11236. equals(p)
  11237. {
  11238. return this.x === p.x && this.y === p.y;
  11239. }
  11240. }
  11241. /***/ }),
  11242. /***/ "./src/core/speedy-promise.js":
  11243. /*!************************************!*\
  11244. !*** ./src/core/speedy-promise.js ***!
  11245. \************************************/
  11246. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_499635__) => {
  11247. "use strict";
  11248. __nested_webpack_require_499635__.r(__webpack_exports__);
  11249. /* harmony export */ __nested_webpack_require_499635__.d(__webpack_exports__, {
  11250. /* harmony export */ "SpeedyPromise": () => (/* binding */ SpeedyPromise)
  11251. /* harmony export */ });
  11252. /*
  11253. * speedy-vision.js
  11254. * GPU-accelerated Computer Vision for JavaScript
  11255. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11256. *
  11257. * Licensed under the Apache License, Version 2.0 (the "License");
  11258. * you may not use this file except in compliance with the License.
  11259. * You may obtain a copy of the License at
  11260. *
  11261. * http://www.apache.org/licenses/LICENSE-2.0
  11262. *
  11263. * Unless required by applicable law or agreed to in writing, software
  11264. * distributed under the License is distributed on an "AS IS" BASIS,
  11265. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11266. * See the License for the specific language governing permissions and
  11267. * limitations under the License.
  11268. *
  11269. * speedy-promise.js
  11270. * Speedy Promises: a fast implementation of Promises
  11271. */
  11272. const PENDING = 0;
  11273. const FULFILLED = 1;
  11274. const REJECTED = 2;
  11275. const SUSPEND_ASYNC = 1;
  11276. const asap = (typeof queueMicrotask !== 'undefined' && queueMicrotask) || // browsers
  11277. (typeof process !== 'undefined' && process.nextTick) || // node.js
  11278. (f => Promise.resolve().then(() => f())); // most compatible
  11279. /**
  11280. * SpeedyPromise: Super Fast Promises. SpeedyPromises can
  11281. * interoperate with ES6 Promises. This implementation is
  11282. * based on the Promises/A+ specification.
  11283. * @template T
  11284. */
  11285. class SpeedyPromise
  11286. {
  11287. /**
  11288. * Constructor
  11289. * @param {function(function(T=): void, function(Error): void): void} callback
  11290. */
  11291. constructor(callback)
  11292. {
  11293. this._state = PENDING;
  11294. this._value = undefined;
  11295. this._onFulfillment = null;
  11296. this._onRejection = null;
  11297. this._children = 0;
  11298. this[0] = this;
  11299. this._parent = undefined;
  11300. this._flags = 0;
  11301. this._fulfill = this._fulfill.bind(this);
  11302. this._reject = this._reject.bind(this);
  11303. this._resolve = this._resolve.bind(this);
  11304. this._broadcastIfAsync = this._broadcastIfAsync.bind(this);
  11305. callback(this._fulfill, this._reject);
  11306. }
  11307. /**
  11308. * Setup handlers
  11309. * @template U, V=never
  11310. * @param {null|undefined|(function(T): U|PromiseLike<U>|SpeedyPromise<U>)} onFulfillment called when the SpeedyPromise is fulfilled
  11311. * @param {null|undefined|(function(Error): V|PromiseLike<V>|SpeedyPromise<V>)} [onRejection] called when the SpeedyPromise is rejected
  11312. * @returns {SpeedyPromise<U>}
  11313. */
  11314. then(onFulfillment, onRejection = null)
  11315. {
  11316. const child = new SpeedyPromise(this._nop);
  11317. child._onFulfillment = typeof onFulfillment === 'function' && onFulfillment;
  11318. child._onRejection = typeof onRejection === 'function' && onRejection;
  11319. child._parent = this;
  11320. this[this._children++] = child; // attach child
  11321. this._flags &= ~SUSPEND_ASYNC; // restore the async behavior
  11322. this._notify();
  11323. return child;
  11324. }
  11325. /**
  11326. * Setup rejection handler
  11327. * @template U, V=never
  11328. * @param {null|undefined|(function(Error): V|PromiseLike<V>|SpeedyPromise<V>)} [onRejection] called when the SpeedyPromise is rejected
  11329. * @returns {SpeedyPromise<V>}
  11330. */
  11331. catch(onRejection)
  11332. {
  11333. return this.then(null, onRejection);
  11334. }
  11335. /**
  11336. * Execute a callback when the promise is settled
  11337. * (i.e., fulfilled or rejected)
  11338. * @param {function(): void} onFinally
  11339. * @returns {SpeedyPromise<T>}
  11340. */
  11341. finally(onFinally)
  11342. {
  11343. const fn = val => { onFinally(); return val; };
  11344. return this.then(fn, fn);
  11345. }
  11346. /**
  11347. * Start the computation immediately, synchronously.
  11348. * Can't afford to spend any time at all waiting for micro-tasks, etc.
  11349. * @returns {SpeedyPromise<T>} this
  11350. */
  11351. turbocharge()
  11352. {
  11353. let my = this;
  11354. // suspend the async behavior
  11355. this._flags |= SUSPEND_ASYNC;
  11356. while(my._parent !== undefined) {
  11357. my = my._parent;
  11358. my._flags |= SUSPEND_ASYNC;
  11359. }
  11360. // notify the children of the root
  11361. my._notify(); // will be synchronous
  11362. // return this SpeedyPromise
  11363. return this;
  11364. }
  11365. /**
  11366. * Convert to string
  11367. * @returns {string}
  11368. */
  11369. toString()
  11370. {
  11371. switch(this._state) {
  11372. case PENDING:
  11373. return `SpeedyPromise { <pending> }`;
  11374. case FULFILLED:
  11375. return `SpeedyPromise { <fulfilled> ${this._value} }`;
  11376. case REJECTED:
  11377. return `SpeedyPromise { <rejected> ${this._value} }`;
  11378. default:
  11379. return '';
  11380. }
  11381. }
  11382. /**
  11383. * Symbol.toStringTag
  11384. * @returns {string}
  11385. */
  11386. get [Symbol.toStringTag]()
  11387. {
  11388. return 'SpeedyPromise';
  11389. }
  11390. /**
  11391. * Creates a resolved SpeedyPromise
  11392. * @template U
  11393. * @param {U} [value]
  11394. * @returns {SpeedyPromise<U>}
  11395. */
  11396. static resolve(value)
  11397. {
  11398. const promise = new SpeedyPromise(this._snop);
  11399. if((typeof value === 'object' && value !== null && 'then' in value) || (typeof value === 'function' && 'then' in value)) {
  11400. // resolve asynchronously
  11401. promise._resolve(value);
  11402. }
  11403. else {
  11404. // fulfill synchronously
  11405. promise._value = value;
  11406. promise._state = FULFILLED;
  11407. }
  11408. return promise;
  11409. }
  11410. /**
  11411. * Creates a rejected SpeedyPromise
  11412. * @template U
  11413. * @param {Error} reason
  11414. * @returns {SpeedyPromise<U>}
  11415. */
  11416. static reject(reason)
  11417. {
  11418. const promise = new SpeedyPromise(this._snop);
  11419. promise._value = reason;
  11420. promise._state = REJECTED;
  11421. return promise;
  11422. }
  11423. /**
  11424. * Returns a SpeedyPromise that resolves to an array
  11425. * containing the results of the input promises/values,
  11426. * in their given order. The returned SpeedyPromise will
  11427. * resolve if all input promises resolve, or reject if
  11428. * any input promise rejects.
  11429. * @template U
  11430. * @param {Iterable<U>|Iterable<SpeedyPromise<U>>|Iterable<Promise<U>>} iterable e.g., a SpeedyPromise[], a thenable[]
  11431. * @returns {SpeedyPromise<U[]>}
  11432. *
  11433. * FIXME iterables need not be all <U>
  11434. */
  11435. static all(iterable)
  11436. {
  11437. return new SpeedyPromise((resolve, reject) => {
  11438. const input = [];
  11439. // get elements
  11440. for(const element of iterable)
  11441. input.push(element);
  11442. // resolve synchronously if there are no elements
  11443. const length = input.length;
  11444. if(length == 0) {
  11445. resolve([]);
  11446. return;
  11447. }
  11448. // resolve asynchronously
  11449. let counter = length;
  11450. const output = new Array(length);
  11451. const partialResolve = i => (val => { output[i] = val; if(0 == --counter) resolve(output); });
  11452. for(let i = 0; i < length; i++) {
  11453. const element = input[i];
  11454. if(element.__proto__ === SpeedyPromise.prototype || element.__proto__ === Promise.prototype)
  11455. element.then(partialResolve(i), reject);
  11456. else
  11457. SpeedyPromise.resolve(element).then(partialResolve(i), reject);
  11458. }
  11459. });
  11460. }
  11461. /**
  11462. * Returns a promise that gets fulfilled or rejected as soon
  11463. * as the first promise in the iterable gets fulfilled or
  11464. * rejected (with its value/reason).
  11465. * @template U
  11466. * @param {Iterable<U>|Iterable<SpeedyPromise<U>>|Iterable<Promise<U>>} iterable e.g., a SpeedyPromise[], a thenable[]
  11467. * @returns {SpeedyPromise<U>}
  11468. */
  11469. static race(iterable)
  11470. {
  11471. return new SpeedyPromise((resolve, reject) => {
  11472. const input = [];
  11473. // get elements
  11474. for(const element of iterable)
  11475. input.push(element);
  11476. // if the iterable is empty, the promise
  11477. // will be pending forever...
  11478. // resolve asynchronously
  11479. const length = input.length;
  11480. for(let i = 0; i < length; i++) {
  11481. const element = input[i];
  11482. if(element.__proto__ === SpeedyPromise.prototype || element.__proto__ === Promise.prototype)
  11483. element.then(resolve, reject);
  11484. else
  11485. SpeedyPromise.resolve(element).then(resolve, reject);
  11486. }
  11487. });
  11488. }
  11489. /**
  11490. * Fulfill this promise with a value
  11491. * @param {T} value
  11492. */
  11493. _fulfill(value)
  11494. {
  11495. this._setState(FULFILLED, value);
  11496. }
  11497. /**
  11498. * Reject this promise with a reason
  11499. * @param {Error} reason
  11500. */
  11501. _reject(reason)
  11502. {
  11503. this._setState(REJECTED, reason);
  11504. }
  11505. /**
  11506. * Set the state and the value of this promise
  11507. * @param {number} state
  11508. * @param {T|Error} value
  11509. */
  11510. _setState(state, value)
  11511. {
  11512. // the promise is already fulfilled or rejected
  11513. if(this._state != PENDING)
  11514. return;
  11515. // set the new state
  11516. this._state = state;
  11517. this._value = value;
  11518. this._notify();
  11519. }
  11520. /**
  11521. * Notify my children that this promise is no
  11522. * longer pending. This is an async operation:
  11523. * my childen will be notified "as soon
  11524. * as possible" (it will be scheduled).
  11525. * We may force this to be synchronous, though
  11526. */
  11527. _notify()
  11528. {
  11529. // nothing to do
  11530. if(this._state == PENDING)
  11531. return;
  11532. // have we turbocharged this promise?
  11533. if(this._flags & SUSPEND_ASYNC) {
  11534. this._broadcast(); // execute synchronously
  11535. return;
  11536. }
  11537. // install a timer (default behavior)
  11538. asap(this._broadcastIfAsync);
  11539. }
  11540. /**
  11541. * Helper method
  11542. */
  11543. _broadcastIfAsync()
  11544. {
  11545. // we may have installed a timer at some
  11546. // point, but turbocharged the promise later
  11547. if(!(this._flags & SUSPEND_ASYNC))
  11548. this._broadcast();
  11549. }
  11550. /**
  11551. * Tell my children that this promise
  11552. * is either fulfilled or rejected.
  11553. * This is a synchronous operation
  11554. */
  11555. _broadcast()
  11556. {
  11557. const children = this._children;
  11558. const state = this._state;
  11559. if(state === FULFILLED) {
  11560. for(let i = 0; i < children; i++) {
  11561. const child = this[i];
  11562. const callback = child._onFulfillment;
  11563. try {
  11564. if(callback) {
  11565. if(callback !== child._nop) {
  11566. child._resolve(callback(this._value)); // promise resolution procedure
  11567. child._onFulfillment = child._nop; // will not be called again
  11568. }
  11569. }
  11570. else
  11571. child._fulfill(this._value);
  11572. }
  11573. catch(e) {
  11574. child._reject(e);
  11575. }
  11576. }
  11577. }
  11578. else if(state === REJECTED) {
  11579. for(let i = 0; i < children; i++) {
  11580. const child = this[i];
  11581. const callback = child._onRejection;
  11582. try {
  11583. if(callback) {
  11584. if(callback !== child._nop) {
  11585. child._resolve(callback(this._value)); // promise resolution procedure
  11586. child._onRejection = child._nop; // will not be called again
  11587. }
  11588. }
  11589. else
  11590. child._reject(this._value);
  11591. }
  11592. catch(e) {
  11593. child._reject(e);
  11594. }
  11595. }
  11596. }
  11597. }
  11598. /**
  11599. * Promise Resolution Procedure
  11600. * based on the Promises/A+ spec
  11601. * @param {T} x
  11602. */
  11603. _resolve(x)
  11604. {
  11605. if((typeof x !== 'object' && typeof x !== 'function') || (x === null)) { // if(x !== Object(x))
  11606. this._fulfill(x);
  11607. return;
  11608. }
  11609. if(x === this)
  11610. throw new TypeError(); // Circular reference
  11611. if(x.__proto__ === SpeedyPromise.prototype || x.__proto__ === Promise.prototype) {
  11612. x.then(this._resolve, this._reject);
  11613. return;
  11614. }
  11615. try {
  11616. const then = x.then;
  11617. if(typeof then === 'function') {
  11618. let resolve = this._resolve, reject = this._reject;
  11619. try {
  11620. then.call(x,
  11621. y => { resolve(y); resolve = reject = this._nop; },
  11622. r => { reject(r); resolve = reject = this._nop; }
  11623. );
  11624. }
  11625. catch(e) {
  11626. if(resolve !== this._nop && reject !== this._nop)
  11627. this._reject(e);
  11628. }
  11629. }
  11630. else {
  11631. this._fulfill(x);
  11632. }
  11633. }
  11634. catch(e) {
  11635. this._reject(e);
  11636. }
  11637. }
  11638. /**
  11639. * No-operation
  11640. */
  11641. _nop()
  11642. {
  11643. }
  11644. /**
  11645. * Static no-operation
  11646. */
  11647. static _snop()
  11648. {
  11649. }
  11650. }
  11651. //module.exports = { SpeedyPromise };
  11652. /*
  11653. // Uncomment to test performance with regular Promises
  11654. module.exports = { SpeedyPromise: Promise };
  11655. Promise.prototype.turbocharge = function() { return this };
  11656. */
  11657. /***/ }),
  11658. /***/ "./src/core/speedy-size.js":
  11659. /*!*********************************!*\
  11660. !*** ./src/core/speedy-size.js ***!
  11661. \*********************************/
  11662. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_513297__) => {
  11663. "use strict";
  11664. __nested_webpack_require_513297__.r(__webpack_exports__);
  11665. /* harmony export */ __nested_webpack_require_513297__.d(__webpack_exports__, {
  11666. /* harmony export */ "SpeedySize": () => (/* binding */ SpeedySize)
  11667. /* harmony export */ });
  11668. /*
  11669. * speedy-vision.js
  11670. * GPU-accelerated Computer Vision for JavaScript
  11671. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11672. *
  11673. * Licensed under the Apache License, Version 2.0 (the "License");
  11674. * you may not use this file except in compliance with the License.
  11675. * You may obtain a copy of the License at
  11676. *
  11677. * http://www.apache.org/licenses/LICENSE-2.0
  11678. *
  11679. * Unless required by applicable law or agreed to in writing, software
  11680. * distributed under the License is distributed on an "AS IS" BASIS,
  11681. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11682. * See the License for the specific language governing permissions and
  11683. * limitations under the License.
  11684. *
  11685. * speedy-size.js
  11686. * Size of a rectangle
  11687. */
  11688. /**
  11689. * Size of a rectangle
  11690. */
  11691. class SpeedySize
  11692. {
  11693. /**
  11694. * Constructor
  11695. * @param {number} width non-negative number
  11696. * @param {number} height non-negative number
  11697. */
  11698. constructor(width, height)
  11699. {
  11700. /** @type {number} width */
  11701. this._width = Math.max(0, +width);
  11702. /** @type {number} height */
  11703. this._height = Math.max(0, +height);
  11704. }
  11705. //
  11706. // ===== METHODS =====
  11707. //
  11708. /**
  11709. * Width
  11710. * @returns {number}
  11711. */
  11712. get width()
  11713. {
  11714. return this._width;
  11715. }
  11716. /**
  11717. * Width
  11718. * @param {number} value
  11719. */
  11720. set width(value)
  11721. {
  11722. this._width = Math.max(0, +value);
  11723. }
  11724. /**
  11725. * Height
  11726. * @returns {number}
  11727. */
  11728. get height()
  11729. {
  11730. return this._height;
  11731. }
  11732. /**
  11733. * Height
  11734. * @param {number} value
  11735. */
  11736. set height(value)
  11737. {
  11738. this._height = Math.max(0, +value);
  11739. }
  11740. /**
  11741. * Convert to string
  11742. * @returns {string}
  11743. */
  11744. toString()
  11745. {
  11746. return `SpeedySize(${this.width}, ${this.height})`;
  11747. }
  11748. /**
  11749. * Is this size equal to anotherSize?
  11750. * @param {SpeedySize} anotherSize
  11751. * @returns {boolean}
  11752. */
  11753. equals(anotherSize)
  11754. {
  11755. return this.width === anotherSize.width && this.height === anotherSize.height;
  11756. }
  11757. /**
  11758. * The area of the rectangle
  11759. * @returns {number}
  11760. */
  11761. area()
  11762. {
  11763. return this.width * this.height;
  11764. }
  11765. }
  11766. /***/ }),
  11767. /***/ "./src/core/speedy-vector.js":
  11768. /*!***********************************!*\
  11769. !*** ./src/core/speedy-vector.js ***!
  11770. \***********************************/
  11771. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_515986__) => {
  11772. "use strict";
  11773. __nested_webpack_require_515986__.r(__webpack_exports__);
  11774. /* harmony export */ __nested_webpack_require_515986__.d(__webpack_exports__, {
  11775. /* harmony export */ "SpeedyVector2": () => (/* binding */ SpeedyVector2)
  11776. /* harmony export */ });
  11777. /*
  11778. * speedy-vision.js
  11779. * GPU-accelerated Computer Vision for JavaScript
  11780. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11781. *
  11782. * Licensed under the Apache License, Version 2.0 (the "License");
  11783. * you may not use this file except in compliance with the License.
  11784. * You may obtain a copy of the License at
  11785. *
  11786. * http://www.apache.org/licenses/LICENSE-2.0
  11787. *
  11788. * Unless required by applicable law or agreed to in writing, software
  11789. * distributed under the License is distributed on an "AS IS" BASIS,
  11790. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11791. * See the License for the specific language governing permissions and
  11792. * limitations under the License.
  11793. *
  11794. * speedy-vector.js
  11795. * Vectors
  11796. */
  11797. /**
  11798. * 2D vector of floating-point numbers
  11799. */
  11800. class SpeedyVector2
  11801. {
  11802. /**
  11803. * Create a 2D vector
  11804. * @param {number} x
  11805. * @param {number} y
  11806. */
  11807. constructor(x, y)
  11808. {
  11809. /** @type {number} x coordinate */
  11810. this._x = +x;
  11811. /** @type {number} y coordinate */
  11812. this._y = +y;
  11813. }
  11814. //
  11815. // ===== METHODS =====
  11816. //
  11817. /**
  11818. * x-coordinate
  11819. * @returns {number}
  11820. */
  11821. get x()
  11822. {
  11823. return this._x;
  11824. }
  11825. /**
  11826. * x-coordinate
  11827. * @param {number} value
  11828. */
  11829. set x(value)
  11830. {
  11831. this._x = +value;
  11832. }
  11833. /**
  11834. * y-coordinate
  11835. * @returns {number}
  11836. */
  11837. get y()
  11838. {
  11839. return this._y;
  11840. }
  11841. /**
  11842. * y-coordinate
  11843. * @param {number} value
  11844. */
  11845. set y(value)
  11846. {
  11847. this._y = +value;
  11848. }
  11849. /**
  11850. * Convert to string
  11851. * @returns {string}
  11852. */
  11853. toString()
  11854. {
  11855. return `SpeedyVector2(${this.x.toFixed(5)}, ${this.y.toFixed(5)})`;
  11856. }
  11857. /**
  11858. * Is this vector equal to v?
  11859. * @param {SpeedyVector2} v
  11860. * @returns {boolean}
  11861. */
  11862. equals(v)
  11863. {
  11864. return this.x === v.x && this.y === v.y;
  11865. }
  11866. /**
  11867. * Dot product between this vector and another vector
  11868. * @param {SpeedyVector2} v another vector
  11869. * @returns {number}
  11870. */
  11871. dot(v)
  11872. {
  11873. return this.x * v.x + this.y * v.y;
  11874. }
  11875. /**
  11876. * The distance between this vector and another vector
  11877. * @param {SpeedyVector2} v another vector
  11878. * @returns {number}
  11879. */
  11880. distanceTo(v)
  11881. {
  11882. const dx = this.x - v.x;
  11883. const dy = this.y - v.y;
  11884. return Math.sqrt(dx * dx + dy * dy);
  11885. }
  11886. /**
  11887. * Euclidean norm
  11888. * @returns {number}
  11889. */
  11890. length()
  11891. {
  11892. return Math.sqrt(this.x * this.x + this.y * this.y);
  11893. }
  11894. /**
  11895. * Returns a normalized version of this vector
  11896. * @returns {SpeedyVector2}
  11897. */
  11898. normalized()
  11899. {
  11900. const len = this.length();
  11901. if(len > 0.0)
  11902. return new SpeedyVector2(this.x / len, this.y / len);
  11903. else
  11904. return new SpeedyVector2(0.0, 0.0);
  11905. }
  11906. /**
  11907. * Returns a copy of this vector translated by offset
  11908. * @param {SpeedyVector2} offset
  11909. * @returns {SpeedyVector2}
  11910. */
  11911. plus(offset)
  11912. {
  11913. return new SpeedyVector2(this.x + offset.x, this.y + offset.y);
  11914. }
  11915. /**
  11916. * Returns a copy of this vector translated by -offset
  11917. * @param {SpeedyVector2} offset
  11918. * @returns {SpeedyVector2}
  11919. */
  11920. minus(offset)
  11921. {
  11922. return new SpeedyVector2(this.x - offset.x, this.y - offset.y);
  11923. }
  11924. /**
  11925. * Returns a copy of this vector scaled by a scalar
  11926. * @param {number} scalar
  11927. * @returns {SpeedyVector2}
  11928. */
  11929. times(scalar)
  11930. {
  11931. return new SpeedyVector2(this.x * scalar, this.y * scalar);
  11932. }
  11933. }
  11934. /***/ }),
  11935. /***/ "./src/gpu/programs/filters.js":
  11936. /*!*************************************!*\
  11937. !*** ./src/gpu/programs/filters.js ***!
  11938. \*************************************/
  11939. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_520087__) => {
  11940. "use strict";
  11941. __nested_webpack_require_520087__.r(__webpack_exports__);
  11942. /* harmony export */ __nested_webpack_require_520087__.d(__webpack_exports__, {
  11943. /* harmony export */ "SpeedyProgramGroupFilters": () => (/* binding */ SpeedyProgramGroupFilters)
  11944. /* harmony export */ });
  11945. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_520087__(/*! ../speedy-gpu */ "./src/gpu/speedy-gpu.js");
  11946. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_520087__(/*! ../speedy-program-group */ "./src/gpu/speedy-program-group.js");
  11947. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_520087__(/*! ../shader-declaration */ "./src/gpu/shader-declaration.js");
  11948. /* harmony import */ var _shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_520087__(/*! ../shaders/filters/convolution */ "./src/gpu/shaders/filters/convolution.js");
  11949. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_520087__(/*! ../../utils/utils */ "./src/utils/utils.js");
  11950. /*
  11951. * speedy-vision.js
  11952. * GPU-accelerated Computer Vision for JavaScript
  11953. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  11954. *
  11955. * Licensed under the Apache License, Version 2.0 (the "License");
  11956. * you may not use this file except in compliance with the License.
  11957. * You may obtain a copy of the License at
  11958. *
  11959. * http://www.apache.org/licenses/LICENSE-2.0
  11960. *
  11961. * Unless required by applicable law or agreed to in writing, software
  11962. * distributed under the License is distributed on an "AS IS" BASIS,
  11963. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11964. * See the License for the specific language governing permissions and
  11965. * limitations under the License.
  11966. *
  11967. * filters.js
  11968. * Image filtering on the GPU
  11969. */
  11970. //
  11971. // Shaders
  11972. //
  11973. // Convert to greyscale
  11974. const rgb2grey = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/rgb2grey.glsl')
  11975. .withArguments('image');
  11976. // Convolution
  11977. const convolution = [3, 5, 7].reduce((obj, ksize) => ((obj[ksize] =
  11978. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/convolution2d.glsl')
  11979. .withDefines({ 'KERNEL_SIZE_SQUARED': ksize * ksize })
  11980. .withArguments('image', 'kernel')
  11981. ), obj), {});
  11982. // Separable convolution
  11983. const convolutionX = [3, 5, 7, 9, 11, 13, 15].reduce((obj, ksize) => ((obj[ksize] =
  11984. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/convolution1d.glsl')
  11985. .withDefines({ 'KERNEL_SIZE': ksize, 'AXIS': 0 })
  11986. .withArguments('image', 'kernel')
  11987. ), obj), {});
  11988. const convolutionY = [3, 5, 7, 9, 11, 13, 15].reduce((obj, ksize) => ((obj[ksize] =
  11989. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/convolution1d.glsl')
  11990. .withDefines({ 'KERNEL_SIZE': ksize, 'AXIS': 1 })
  11991. .withArguments('image', 'kernel')
  11992. ), obj), {});
  11993. // Median filter
  11994. const median = [3, 5, 7].reduce((obj, ksize) => ((obj[ksize] =
  11995. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/fast-median.glsl')
  11996. .withDefines({ 'KERNEL_SIZE': ksize })
  11997. .withArguments('image')
  11998. ), obj), {});
  11999. // Normalize image
  12000. const normalizeGreyscale = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/normalize-image.glsl')
  12001. .withDefines({ 'GREYSCALE': 1 })
  12002. .withArguments('minmax2d', 'minValue', 'maxValue');
  12003. const normalizeColored = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/normalize-image.glsl')
  12004. .withDefines({ 'GREYSCALE': 0 })
  12005. .withArguments('minmax2dRGB', 'minValue', 'maxValue');
  12006. // Nightvision
  12007. const nightvision = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/nightvision.glsl')
  12008. .withDefines({ 'GREYSCALE': 0 })
  12009. .withArguments('image', 'illuminationMap', 'gain', 'offset', 'decay');
  12010. const nightvisionGreyscale = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('filters/nightvision.glsl')
  12011. .withDefines({ 'GREYSCALE': 1 })
  12012. .withArguments('image', 'illuminationMap', 'gain', 'offset', 'decay');
  12013. //
  12014. // Utilities
  12015. //
  12016. // Handy conversion for Gaussian filters
  12017. // (symmetric kernel, approx. zero after 3*sigma)
  12018. const ksize2sigma = ksize => Math.max(1.0, ksize / 6.0);
  12019. // Generate a 1D Gaussian kernel
  12020. const gaussian = ksize => _utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(ksize2sigma(ksize), ksize);
  12021. // Generate a 1D Box filter
  12022. const box = ksize => (new Array(ksize)).fill(1.0 / ksize);
  12023. /**
  12024. * SpeedyProgramGroupFilters
  12025. * Image filtering
  12026. */
  12027. class SpeedyProgramGroupFilters extends _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroup
  12028. {
  12029. /**
  12030. * Class constructor
  12031. * @param {SpeedyGPU} gpu
  12032. */
  12033. constructor(gpu)
  12034. {
  12035. super(gpu);
  12036. this
  12037. // convert to greyscale
  12038. .declare('rgb2grey', rgb2grey)
  12039. // median filters
  12040. .declare('median3', median[3]) // 3x3 window
  12041. .declare('median5', median[5]) // 5x5 window
  12042. .declare('median7', median[7]) // 7x7 window
  12043. // 2D convolution
  12044. .declare('convolution3', convolution[3]) // 3x3 kernel
  12045. .declare('convolution5', convolution[5]) // 5x5 kernel
  12046. .declare('convolution7', convolution[7]) // 7x7 kernel
  12047. // 1D separable convolution
  12048. .declare('convolution3x', convolutionX[3]) // 1x3 kernel
  12049. .declare('convolution3y', convolutionY[3]) // 3x1 kernel
  12050. .declare('convolution5x', convolutionX[5]) // 1x5 kernel
  12051. .declare('convolution5y', convolutionY[5]) // 5x1 kernel
  12052. .declare('convolution7x', convolutionX[7])
  12053. .declare('convolution7y', convolutionY[7])
  12054. .declare('convolution9x', convolutionX[9])
  12055. .declare('convolution9y', convolutionY[9])
  12056. .declare('convolution11x', convolutionX[11])
  12057. .declare('convolution11y', convolutionY[11])
  12058. .declare('convolution13x', convolutionX[13])
  12059. .declare('convolution13y', convolutionY[13])
  12060. .declare('convolution15x', convolutionX[15])
  12061. .declare('convolution15y', convolutionY[15])
  12062. // normalize image
  12063. .declare('normalizeGreyscale', normalizeGreyscale)
  12064. .declare('normalizeColored', normalizeColored)
  12065. // nightvision
  12066. .declare('nightvision', nightvision)
  12067. .declare('nightvisionGreyscale', nightvisionGreyscale)
  12068. .declare('illuminationMapLoX', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 31)))
  12069. .declare('illuminationMapLoY', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 31)))
  12070. .declare('illuminationMapX', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 63)))
  12071. .declare('illuminationMapY', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 63)))
  12072. .declare('illuminationMapHiX', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 255)))
  12073. .declare('illuminationMapHiY', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(_utils_utils__WEBPACK_IMPORTED_MODULE_4__.Utils.gaussianKernel(80, 255)))
  12074. // gaussian: separable kernels
  12075. // see also: http://dev.theomader.com/gaussian-kernel-calculator/
  12076. .declare('gaussian3x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)([ 0.25, 0.5, 0.25 ])) // sigma ~ 1.0
  12077. .declare('gaussian3y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)([ 0.25, 0.5, 0.25 ]))
  12078. .declare('gaussian5x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)([ 0.05, 0.25, 0.4, 0.25, 0.05 ])) // sigma ~ 1.0
  12079. .declare('gaussian5y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)([ 0.05, 0.25, 0.4, 0.25, 0.05 ]))
  12080. .declare('gaussian7x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(gaussian(7)))
  12081. .declare('gaussian7y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(gaussian(7)))
  12082. .declare('gaussian9x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(gaussian(9)))
  12083. .declare('gaussian9y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(gaussian(9)))
  12084. .declare('gaussian11x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(gaussian(11)))
  12085. .declare('gaussian11y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(gaussian(11)))
  12086. // box filter: separable kernels
  12087. .declare('box3x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(box(3)))
  12088. .declare('box3y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(box(3)))
  12089. .declare('box5x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(box(5)))
  12090. .declare('box5y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(box(5)))
  12091. .declare('box7x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(box(7)))
  12092. .declare('box7y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(box(7)))
  12093. .declare('box9x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(box(9)))
  12094. .declare('box9y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(box(9)))
  12095. .declare('box11x', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convX)(box(11)))
  12096. .declare('box11y', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_3__.convY)(box(11)))
  12097. ;
  12098. }
  12099. }
  12100. /***/ }),
  12101. /***/ "./src/gpu/programs/keypoints.js":
  12102. /*!***************************************!*\
  12103. !*** ./src/gpu/programs/keypoints.js ***!
  12104. \***************************************/
  12105. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_530931__) => {
  12106. "use strict";
  12107. __nested_webpack_require_530931__.r(__webpack_exports__);
  12108. /* harmony export */ __nested_webpack_require_530931__.d(__webpack_exports__, {
  12109. /* harmony export */ "SpeedyProgramGroupKeypoints": () => (/* binding */ SpeedyProgramGroupKeypoints)
  12110. /* harmony export */ });
  12111. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_530931__(/*! ../speedy-gpu */ "./src/gpu/speedy-gpu.js");
  12112. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_530931__(/*! ../speedy-program-group */ "./src/gpu/speedy-program-group.js");
  12113. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_530931__(/*! ../speedy-texture */ "./src/gpu/speedy-texture.js");
  12114. /* harmony import */ var _speedy_lsh__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_530931__(/*! ../speedy-lsh */ "./src/gpu/speedy-lsh.js");
  12115. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_530931__(/*! ../shader-declaration */ "./src/gpu/shader-declaration.js");
  12116. /*
  12117. * speedy-vision.js
  12118. * GPU-accelerated Computer Vision for JavaScript
  12119. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  12120. *
  12121. * Licensed under the Apache License, Version 2.0 (the "License");
  12122. * you may not use this file except in compliance with the License.
  12123. * You may obtain a copy of the License at
  12124. *
  12125. * http://www.apache.org/licenses/LICENSE-2.0
  12126. *
  12127. * Unless required by applicable law or agreed to in writing, software
  12128. * distributed under the License is distributed on an "AS IS" BASIS,
  12129. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12130. * See the License for the specific language governing permissions and
  12131. * limitations under the License.
  12132. *
  12133. * keypoints.js
  12134. * Facade for various keypoint detection algorithms
  12135. */
  12136. // FAST corner detector
  12137. const fast9_16 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/fast.glsl', 'keypoints/fast.vs.glsl')
  12138. .withDefines({ 'FAST_TYPE': 916 })
  12139. .withArguments('corners', 'pyramid', 'lod', 'threshold');
  12140. // Harris corner detector
  12141. const harris = [1, 3, 5, 7].reduce((obj, win) => ((obj[win] =
  12142. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/harris.glsl')
  12143. .withDefines({ 'WINDOW_SIZE': win })
  12144. .withArguments('corners', 'pyramid', 'derivatives', 'lod', 'lodStep', 'gaussian')
  12145. ), obj), {});
  12146. const harrisScoreFindMax = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/score-findmax.glsl')
  12147. .withArguments('corners', 'iterationNumber');
  12148. const harrisScoreCutoff = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/harris-cutoff.glsl')
  12149. .withArguments('corners', 'maxScore', 'quality');
  12150. // Subpixel refinement
  12151. const subpixelQuadratic1d = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/subpixel-refinement.glsl')
  12152. .withDefines({ 'METHOD': 0 })
  12153. .withArguments('pyramid', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxIterations', 'epsilon');
  12154. const subpixelTaylor2d = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/subpixel-refinement.glsl')
  12155. .withDefines({ 'METHOD': 1 })
  12156. .withArguments('pyramid', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxIterations', 'epsilon');
  12157. const subpixelBilinear = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/subpixel-refinement.glsl')
  12158. .withDefines({ 'METHOD': 2 })
  12159. .withArguments('pyramid', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxIterations', 'epsilon');
  12160. const subpixelBicubic = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/subpixel-refinement.glsl')
  12161. .withDefines({ 'METHOD': 3 })
  12162. .withArguments('pyramid', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxIterations', 'epsilon');
  12163. // Scale refinement
  12164. const refineScaleLoG = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/refine-scale.glsl')
  12165. .withDefines({ 'METHOD': 0 })
  12166. .withArguments('pyramid', 'lodStep', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12167. const refineScaleFAST916 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/refine-scale.glsl')
  12168. .withDefines({ 'METHOD': 1 })
  12169. .withArguments('pyramid', 'lodStep', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'threshold');
  12170. // Pixel allocation
  12171. const allocateDescriptors = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/allocate-descriptors.glsl')
  12172. .withArguments('inputEncodedKeypoints', 'inputDescriptorSize', 'inputExtraSize', 'inputEncoderLength', 'outputDescriptorSize', 'outputExtraSize', 'outputEncoderLength');
  12173. const allocateExtra = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/allocate-extra.glsl')
  12174. .withArguments('inputEncodedKeypoints', 'inputDescriptorSize', 'inputExtraSize', 'inputEncoderLength', 'outputDescriptorSize', 'outputExtraSize', 'outputEncoderLength');
  12175. const transferToExtra = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/transfer-to-extra.glsl')
  12176. .withArguments('encodedData', 'strideOfEncodedData', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12177. // ORB descriptors
  12178. const orbDescriptor = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/orb-descriptor.glsl')
  12179. .withArguments('image', 'encodedCorners', 'extraSize', 'encoderLength');
  12180. const orbOrientation = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/orb-orientation.glsl')
  12181. .withArguments('image', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12182. // Non-maximum suppression
  12183. const nonMaxSuppression = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/nonmax-suppression.glsl')
  12184. .withDefines({ 'MULTISCALE': 0 })
  12185. .withArguments('image', 'lodStep');
  12186. const multiscaleNonMaxSuppression = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/nonmax-suppression.glsl')
  12187. .withDefines({ 'MULTISCALE': 1 })
  12188. .withArguments('image', 'lodStep');
  12189. const nonmaxSpace = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/nonmax-space.glsl')
  12190. .withArguments('corners');
  12191. const nonmaxScale = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/nonmax-scale.glsl')
  12192. .withDefines({ 'USE_LAPLACIAN': 1 })
  12193. .withArguments('corners', 'pyramid', 'pyrLaplacian', 'lodStep');
  12194. const nonmaxScaleSimple = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/nonmax-scale.glsl')
  12195. .withDefines({ 'USE_LAPLACIAN': 0 })
  12196. .withArguments('corners', 'pyramid', 'lodStep');
  12197. const laplacian = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/laplacian.glsl')
  12198. .withArguments('corners', 'pyramid', 'lodStep', 'lodOffset');
  12199. // Keypoint tracking & optical-flow
  12200. const lk = [3, 5, 7, 9, 11, 13, 15, 17, 19, 21].reduce((obj, win) => ((obj[win] =
  12201. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/lk.glsl')
  12202. .withDefines({ 'WINDOW_SIZE': win })
  12203. .withArguments('encodedFlow', 'prevKeypoints', 'nextPyramid', 'prevPyramid', 'level', 'depth', 'numberOfIterations', 'discardThreshold', 'epsilon', 'descriptorSize', 'extraSize', 'encoderLength')
  12204. ), obj), {});
  12205. const transferFlow = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/transfer-flow.glsl')
  12206. .withArguments('encodedFlow', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12207. // Brute-force matching
  12208. const bfMatcherInitCandidates = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-init.glsl')
  12209. .withDefines({ 'ENCODE_FILTERS': 0 });
  12210. const bfMatcherInitFilters = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-init.glsl')
  12211. .withDefines({ 'ENCODE_FILTERS': 1 });
  12212. const bfMatcherTransfer = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-transfer.glsl')
  12213. .withArguments('encodedMatches', 'encodedKthMatches', 'numberOfMatchesPerKeypoint', 'kthMatch');
  12214. const bfMatcher32 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/bf-knn.glsl')
  12215. .withDefines({
  12216. 'DESCRIPTOR_SIZE': 32,
  12217. 'NUMBER_OF_KEYPOINTS_PER_PASS': 16,
  12218. })
  12219. .withArguments('encodedMatches', 'encodedFilters', 'matcherLength', 'dbEncodedKeypoints', 'dbDescriptorSize', 'dbExtraSize', 'dbEncoderLength', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'passId');
  12220. const bfMatcher64 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/bf-knn.glsl')
  12221. .withDefines({
  12222. 'DESCRIPTOR_SIZE': 64,
  12223. 'NUMBER_OF_KEYPOINTS_PER_PASS': 8,
  12224. })
  12225. .withArguments('encodedMatches', 'encodedFilters', 'matcherLength', 'dbEncodedKeypoints', 'dbDescriptorSize', 'dbExtraSize', 'dbEncoderLength', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'passId');
  12226. // LSH-based KNN matching
  12227. const lshKnnInitCandidates = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-init.glsl')
  12228. .withDefines({ 'ENCODE_FILTERS': 0 });
  12229. const lshKnnInitFilters = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-init.glsl')
  12230. .withDefines({ 'ENCODE_FILTERS': 1 });
  12231. const lshKnn = _speedy_lsh__WEBPACK_IMPORTED_MODULE_3__.LSH_ACCEPTABLE_DESCRIPTOR_SIZES.reduce((obj, descriptorSize) => ((obj[descriptorSize] = _speedy_lsh__WEBPACK_IMPORTED_MODULE_3__.LSH_ACCEPTABLE_HASH_SIZES.reduce((obj, hashSize) => ((obj[hashSize] = [0, 1, 2].reduce((obj, level) => ((obj[level] =
  12232. (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/lsh-knn.glsl')
  12233. .withDefines({
  12234. 'DESCRIPTOR_SIZE': descriptorSize,
  12235. 'HASH_SIZE': hashSize,
  12236. 'LEVEL': level,
  12237. 'SEQUENCE_MAXLEN': _speedy_lsh__WEBPACK_IMPORTED_MODULE_3__.LSH_SEQUENCE_MAXLEN,
  12238. 'SEQUENCE_COUNT': _speedy_lsh__WEBPACK_IMPORTED_MODULE_3__.LSH_SEQUENCE_COUNT,
  12239. })
  12240. .withArguments('candidates', 'filters', 'matcherLength', 'tables', 'descriptorDB', 'tableIndex', 'bucketCapacity', 'bucketsPerTable', 'tablesStride', 'descriptorDBStride', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength')
  12241. ), obj), {})), obj), {})), obj), {});
  12242. const lshKnnTransfer = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/knn-transfer.glsl')
  12243. .withArguments('encodedMatches', 'encodedKthMatches', 'numberOfMatchesPerKeypoint', 'kthMatch');
  12244. // Keypoint sorting
  12245. const sortCreatePermutation = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/sort-keypoints.glsl')
  12246. .withDefines({ 'STAGE': 1 })
  12247. .withArguments('encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12248. const sortMergePermutation = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/sort-keypoints.glsl')
  12249. .withDefines({ 'STAGE': 2 })
  12250. .withArguments('permutation', 'blockSize', 'dblLog2BlockSize');
  12251. const sortApplyPermutation = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/sort-keypoints.glsl')
  12252. .withDefines({ 'STAGE': 3 })
  12253. .withArguments('permutation', 'maxKeypoints', 'encodedKeypoints', 'descriptorSize', 'extraSize');
  12254. // Keypoint mixing
  12255. const mixKeypointsPreInit = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/mix-keypoints.glsl')
  12256. .withDefines({ 'STAGE': 1 })
  12257. .withArguments('encodedKeypointsA', 'encodedKeypointsB', 'encoderLengthA', 'encoderLengthB', 'encoderCapacityA', 'encoderCapacityB', 'descriptorSize', 'extraSize', 'encoderLength');
  12258. const mixKeypointsInit = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/mix-keypoints.glsl')
  12259. .withDefines({ 'STAGE': 2 })
  12260. .withArguments('encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxKeypoints');
  12261. const mixKeypointsSort = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/mix-keypoints.glsl')
  12262. .withDefines({ 'STAGE': 3 })
  12263. .withArguments('array', 'blockSize');
  12264. const mixKeypointsView = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/mix-keypoints.glsl')
  12265. .withDefines({ 'STAGE': 5 })
  12266. .withArguments('array');
  12267. const mixKeypointsApply = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/mix-keypoints.glsl')
  12268. .withDefines({ 'STAGE': 4 })
  12269. .withArguments('array', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12270. // Keypoint encoding
  12271. const initLookupTable = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/lookup-of-locations.glsl')
  12272. .withDefines({ 'FS_OUTPUT_TYPE': 2, 'STAGE': 1 })
  12273. .withArguments('corners');
  12274. const sortLookupTable = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/lookup-of-locations.glsl', 'keypoints/lookup-of-locations.vs.glsl')
  12275. .withDefines({ 'FS_OUTPUT_TYPE': 2, 'FS_USE_CUSTOM_PRECISION': 1, 'STAGE': 2 })
  12276. .withArguments('lookupTable', 'blockSize', 'width', 'height');
  12277. const viewLookupTable = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/lookup-of-locations.glsl')
  12278. .withDefines({ 'STAGE': -1 })
  12279. .withArguments('lookupTable');
  12280. const encodeKeypoints = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-keypoints.glsl')
  12281. .withArguments('corners', 'lookupTable', 'stride', 'descriptorSize', 'extraSize', 'encoderLength', 'encoderCapacity');
  12282. const encodeKeypointSkipOffsets = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-keypoint-offsets.glsl')
  12283. .withArguments('corners', 'imageSize');
  12284. const encodeKeypointLongSkipOffsets = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-keypoint-long-offsets.glsl')
  12285. .withDefines({ 'MAX_ITERATIONS': 6 }) // dependent texture reads :(
  12286. .withArguments('offsetsImage', 'imageSize');
  12287. const encodeKeypointPositions = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-keypoint-positions.glsl')
  12288. .withArguments('offsetsImage', 'imageSize', 'passId', 'numPasses', 'keypointLimit', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12289. const encodeKeypointProperties = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-keypoint-properties.glsl')
  12290. .withArguments('corners', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12291. const encodeNullKeypoints = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/encode-null-keypoints.glsl')
  12292. .withArguments();
  12293. const transferOrientation = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/transfer-orientation.glsl')
  12294. .withArguments('encodedOrientations', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12295. const uploadKeypoints = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/upload-keypoints.glsl')
  12296. .withDefines({
  12297. // UBOs can hold at least 16KB of data;
  12298. // gl.MAX_UNIFORM_BLOCK_SIZE >= 16384
  12299. // according to the GL ES 3 reference.
  12300. // Each keypoint uses 16 bytes (vec4)
  12301. 'BUFFER_SIZE': 1024 //16384 / 16
  12302. })
  12303. .withArguments('encodedKeypoints', 'startIndex', 'endIndex', 'descriptorSize', 'extraSize', 'encoderLength');
  12304. // Geometric transformations
  12305. const applyHomography = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/apply-homography.glsl')
  12306. .withArguments('homography', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12307. // Keypoint filters
  12308. const clipBorder = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/clip-border.glsl')
  12309. .withArguments('imageWidth', 'imageHeight', 'borderTop', 'borderRight', 'borderBottom', 'borderLeft', 'encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12310. const distanceFilter = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/distance-filter.glsl')
  12311. .withArguments('encodedKeypointsA', 'encoderLengthA', 'encodedKeypointsB', 'encoderLengthB', 'descriptorSize', 'extraSize', 'encoderLength', 'threshold');
  12312. const hammingDistanceFilter32 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/hamming-distance-filter.glsl')
  12313. .withDefines({ 'DESCRIPTOR_SIZE': 32 })
  12314. .withArguments('encodedKeypointsA', 'encoderLengthA', 'encodedKeypointsB', 'encoderLengthB', 'descriptorSize', 'extraSize', 'encoderLength', 'threshold');
  12315. const hammingDistanceFilter64 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/hamming-distance-filter.glsl')
  12316. .withDefines({ 'DESCRIPTOR_SIZE': 64 })
  12317. .withArguments('encodedKeypointsA', 'encoderLengthA', 'encodedKeypointsB', 'encoderLengthB', 'descriptorSize', 'extraSize', 'encoderLength', 'threshold');
  12318. // Other utilities
  12319. const shuffle = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/shuffle.glsl')
  12320. .withDefines({ 'PERMUTATION_MAXLEN': 2048 })
  12321. .withArguments('encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength');
  12322. const clip = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_4__.importShader)('keypoints/clip.glsl')
  12323. .withArguments('encodedKeypoints', 'descriptorSize', 'extraSize', 'encoderLength', 'maxKeypoints');
  12324. /**
  12325. * SpeedyProgramGroupKeypoints
  12326. * Keypoint detection
  12327. */
  12328. class SpeedyProgramGroupKeypoints extends _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroup
  12329. {
  12330. /**
  12331. * Class constructor
  12332. * @param {SpeedyGPU} gpu
  12333. */
  12334. constructor(gpu)
  12335. {
  12336. super(gpu);
  12337. this
  12338. //
  12339. // FAST corner detector
  12340. //
  12341. .declare('fast9_16', fast9_16, {
  12342. ...this.program.usesPingpongRendering()
  12343. })
  12344. //
  12345. // Harris corner detector
  12346. //
  12347. .declare('harris1', harris[1], {
  12348. ...this.program.usesPingpongRendering()
  12349. })
  12350. .declare('harris3', harris[3], {
  12351. ...this.program.usesPingpongRendering()
  12352. })
  12353. .declare('harris5', harris[5], {
  12354. ...this.program.usesPingpongRendering()
  12355. })
  12356. .declare('harris7', harris[7], {
  12357. ...this.program.usesPingpongRendering()
  12358. })
  12359. .declare('harrisScoreFindMax', harrisScoreFindMax, {
  12360. ...this.program.usesPingpongRendering()
  12361. })
  12362. .declare('harrisScoreCutoff', harrisScoreCutoff)
  12363. //
  12364. // Subpixel refinement
  12365. //
  12366. .declare('subpixelQuadratic1d', subpixelQuadratic1d)
  12367. .declare('subpixelTaylor2d', subpixelTaylor2d)
  12368. .declare('subpixelBicubic', subpixelBicubic)
  12369. .declare('subpixelBilinear', subpixelBilinear)
  12370. //
  12371. // Scale refinement
  12372. //
  12373. .declare('refineScaleLoG', refineScaleLoG)
  12374. .declare('refineScaleFAST916', refineScaleFAST916)
  12375. //
  12376. // Pixel allocation
  12377. //
  12378. .declare('allocateDescriptors', allocateDescriptors)
  12379. .declare('allocateExtra', allocateExtra)
  12380. .declare('transferToExtra', transferToExtra)
  12381. //
  12382. // ORB descriptors
  12383. //
  12384. .declare('orbDescriptor', orbDescriptor)
  12385. .declare('orbOrientation', orbOrientation)
  12386. //
  12387. // Non-maximum suppression
  12388. //
  12389. .declare('nonmax', nonMaxSuppression)
  12390. .declare('pyrnonmax', multiscaleNonMaxSuppression)
  12391. .declare('nonmaxSpace', nonmaxSpace)
  12392. .declare('nonmaxScale', nonmaxScale)
  12393. .declare('nonmaxScaleSimple', nonmaxScaleSimple)
  12394. .declare('laplacian', laplacian)
  12395. //
  12396. // LK optical-flow
  12397. //
  12398. .declare('lk21', lk[21], {
  12399. ...this.program.usesPingpongRendering()
  12400. })
  12401. .declare('lk19', lk[19], {
  12402. ...this.program.usesPingpongRendering()
  12403. })
  12404. .declare('lk17', lk[17], {
  12405. ...this.program.usesPingpongRendering()
  12406. })
  12407. .declare('lk15', lk[15], {
  12408. ...this.program.usesPingpongRendering()
  12409. })
  12410. .declare('lk13', lk[13], {
  12411. ...this.program.usesPingpongRendering()
  12412. })
  12413. .declare('lk11', lk[11], {
  12414. ...this.program.usesPingpongRendering()
  12415. })
  12416. .declare('lk9', lk[9], {
  12417. ...this.program.usesPingpongRendering()
  12418. })
  12419. .declare('lk7', lk[7], {
  12420. ...this.program.usesPingpongRendering()
  12421. })
  12422. .declare('lk5', lk[5], {
  12423. ...this.program.usesPingpongRendering()
  12424. })
  12425. .declare('lk3', lk[3], {
  12426. ...this.program.usesPingpongRendering()
  12427. })
  12428. .declare('transferFlow', transferFlow)
  12429. //
  12430. // Brute-force KNN matching
  12431. //
  12432. .declare('bfMatcherInitCandidates', bfMatcherInitCandidates)
  12433. .declare('bfMatcherInitFilters', bfMatcherInitFilters)
  12434. .declare('bfMatcherTransfer', bfMatcherTransfer, {
  12435. ...this.program.usesPingpongRendering()
  12436. })
  12437. .declare('bfMatcher32', bfMatcher32, {
  12438. ...this.program.usesPingpongRendering()
  12439. })
  12440. .declare('bfMatcher64', bfMatcher64, {
  12441. ...this.program.usesPingpongRendering()
  12442. })
  12443. //
  12444. // LSH-based KNN matching
  12445. //
  12446. .declare('lshKnnInitCandidates', lshKnnInitCandidates)
  12447. .declare('lshKnnInitFilters', lshKnnInitFilters)
  12448. .declare('lshKnnTransfer', lshKnnTransfer, {
  12449. ...this.program.usesPingpongRendering()
  12450. })
  12451. //
  12452. // Keypoint sorting
  12453. //
  12454. .declare('sortCreatePermutation', sortCreatePermutation)
  12455. .declare('sortMergePermutation', sortMergePermutation, {
  12456. ...this.program.usesPingpongRendering()
  12457. })
  12458. .declare('sortApplyPermutation', sortApplyPermutation)
  12459. //
  12460. // Keypoint mixing
  12461. //
  12462. .declare('mixKeypointsPreInit', mixKeypointsPreInit)
  12463. .declare('mixKeypointsInit', mixKeypointsInit)
  12464. .declare('mixKeypointsSort', mixKeypointsSort, {
  12465. ...this.program.usesPingpongRendering()
  12466. })
  12467. .declare('mixKeypointsView', mixKeypointsView)
  12468. .declare('mixKeypointsApply', mixKeypointsApply)
  12469. //
  12470. // Keypoint encoders
  12471. //
  12472. .declare('encodeNullKeypoints', encodeNullKeypoints)
  12473. .declare('encodeKeypoints', encodeKeypoints)
  12474. .declare('initLookupTable', initLookupTable)
  12475. .declare('sortLookupTable', sortLookupTable, {
  12476. ...this.program.usesPingpongRendering()
  12477. })
  12478. .declare('viewLookupTable', viewLookupTable)
  12479. .declare('encodeKeypointSkipOffsets', encodeKeypointSkipOffsets)
  12480. .declare('encodeKeypointLongSkipOffsets', encodeKeypointLongSkipOffsets, {
  12481. ...this.program.usesPingpongRendering()
  12482. })
  12483. .declare('encodeKeypointPositions', encodeKeypointPositions, {
  12484. ...this.program.usesPingpongRendering()
  12485. })
  12486. .declare('encodeKeypointProperties', encodeKeypointProperties)
  12487. .declare('transferOrientation', transferOrientation)
  12488. .declare('uploadKeypoints', uploadKeypoints, {
  12489. ...this.program.usesPingpongRendering()
  12490. })
  12491. //
  12492. // Geometric transformations
  12493. //
  12494. .declare('applyHomography', applyHomography)
  12495. //
  12496. // Keypoint filters
  12497. //
  12498. .declare('clipBorder', clipBorder)
  12499. .declare('distanceFilter', distanceFilter)
  12500. .declare('hammingDistanceFilter32', hammingDistanceFilter32)
  12501. .declare('hammingDistanceFilter64', hammingDistanceFilter64)
  12502. //
  12503. // Other utilities
  12504. //
  12505. .declare('shuffle', shuffle)
  12506. .declare('clip', clip)
  12507. ;
  12508. //
  12509. // LSH-based KNN matching
  12510. //
  12511. for(const descriptorSize of Object.keys(lshKnn)) {
  12512. for(const hashSize of Object.keys(lshKnn[descriptorSize])) {
  12513. for(const level of Object.keys(lshKnn[descriptorSize][hashSize])) {
  12514. const name = `lshKnn${descriptorSize}h${hashSize}lv${level}`;
  12515. this.declare(name, lshKnn[descriptorSize][hashSize][level], {
  12516. ...this.program.usesPingpongRendering()
  12517. });
  12518. }
  12519. }
  12520. }
  12521. }
  12522. }
  12523. /***/ }),
  12524. /***/ "./src/gpu/programs/pyramids.js":
  12525. /*!**************************************!*\
  12526. !*** ./src/gpu/programs/pyramids.js ***!
  12527. \**************************************/
  12528. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_558714__) => {
  12529. "use strict";
  12530. __nested_webpack_require_558714__.r(__webpack_exports__);
  12531. /* harmony export */ __nested_webpack_require_558714__.d(__webpack_exports__, {
  12532. /* harmony export */ "SpeedyProgramGroupPyramids": () => (/* binding */ SpeedyProgramGroupPyramids)
  12533. /* harmony export */ });
  12534. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_558714__(/*! ../speedy-gpu */ "./src/gpu/speedy-gpu.js");
  12535. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_558714__(/*! ../speedy-program-group */ "./src/gpu/speedy-program-group.js");
  12536. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_558714__(/*! ../speedy-texture */ "./src/gpu/speedy-texture.js");
  12537. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_558714__(/*! ../shader-declaration */ "./src/gpu/shader-declaration.js");
  12538. /* harmony import */ var _shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_558714__(/*! ../shaders/filters/convolution */ "./src/gpu/shaders/filters/convolution.js");
  12539. /*
  12540. * speedy-vision.js
  12541. * GPU-accelerated Computer Vision for JavaScript
  12542. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  12543. *
  12544. * Licensed under the Apache License, Version 2.0 (the "License");
  12545. * you may not use this file except in compliance with the License.
  12546. * You may obtain a copy of the License at
  12547. *
  12548. * http://www.apache.org/licenses/LICENSE-2.0
  12549. *
  12550. * Unless required by applicable law or agreed to in writing, software
  12551. * distributed under the License is distributed on an "AS IS" BASIS,
  12552. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12553. * See the License for the specific language governing permissions and
  12554. * limitations under the License.
  12555. *
  12556. * pyramids.js
  12557. * Image pyramids
  12558. */
  12559. //
  12560. // Shaders
  12561. //
  12562. const upsample2 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('pyramids/upsample2.glsl').withArguments('image');
  12563. const downsample2 = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('pyramids/downsample2.glsl').withArguments('image');
  12564. /**
  12565. * SpeedyProgramGroupPyramids
  12566. * Image pyramids
  12567. */
  12568. class SpeedyProgramGroupPyramids extends _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroup
  12569. {
  12570. /**
  12571. * Class constructor
  12572. * @param {SpeedyGPU} gpu
  12573. */
  12574. constructor(gpu)
  12575. {
  12576. super(gpu);
  12577. this
  12578. // upsampling & downsampling
  12579. .declare('upsample2', upsample2)
  12580. .declare('downsample2', downsample2)
  12581. // separable kernels for gaussian smoothing
  12582. // use [c, b, a, b, c] where a+2c = 2b and a+2b+2c = 1
  12583. // pick a = 0.4 for gaussian approximation (sigma = 1)
  12584. .declare('smoothX', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_4__.convX)([
  12585. 0.05, 0.25, 0.4, 0.25, 0.05
  12586. ]))
  12587. .declare('smoothY', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_4__.convY)([
  12588. 0.05, 0.25, 0.4, 0.25, 0.05
  12589. ]))
  12590. /*
  12591. .declare('reduce', conv2D([
  12592. 0.00250, 0.01250, 0.02000, 0.01250, 0.00250,
  12593. 0.01250, 0.06250, 0.10000, 0.06250, 0.01250,
  12594. 0.02000, 0.10000, 0.16000, 0.10000, 0.02000,
  12595. 0.01250, 0.06250, 0.10000, 0.06250, 0.01250,
  12596. 0.00250, 0.01250, 0.02000, 0.01250, 0.00250
  12597. ]))
  12598. */
  12599. // smoothing for 2x image
  12600. // same rules as above with sum(k) = 2
  12601. .declare('smoothX2', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_4__.convX)([
  12602. 0.1, 0.5, 0.8, 0.5, 0.1
  12603. // NOTE: this would saturate the image, but we apply it
  12604. // on a 2x upsampled version with lots of zero pixels
  12605. ]))
  12606. .declare('smoothY2', (0,_shaders_filters_convolution__WEBPACK_IMPORTED_MODULE_4__.convY)([
  12607. 0.1, 0.5, 0.8, 0.5, 0.1
  12608. ], 1.0 / 2.0))
  12609. ;
  12610. }
  12611. }
  12612. /***/ }),
  12613. /***/ "./src/gpu/programs/transforms.js":
  12614. /*!****************************************!*\
  12615. !*** ./src/gpu/programs/transforms.js ***!
  12616. \****************************************/
  12617. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_562997__) => {
  12618. "use strict";
  12619. __nested_webpack_require_562997__.r(__webpack_exports__);
  12620. /* harmony export */ __nested_webpack_require_562997__.d(__webpack_exports__, {
  12621. /* harmony export */ "SpeedyProgramGroupTransforms": () => (/* binding */ SpeedyProgramGroupTransforms)
  12622. /* harmony export */ });
  12623. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_562997__(/*! ../speedy-gpu */ "./src/gpu/speedy-gpu.js");
  12624. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_562997__(/*! ../speedy-program-group */ "./src/gpu/speedy-program-group.js");
  12625. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_562997__(/*! ../shader-declaration */ "./src/gpu/shader-declaration.js");
  12626. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_562997__(/*! ../../utils/errors */ "./src/utils/errors.js");
  12627. /*
  12628. * speedy-vision.js
  12629. * GPU-accelerated Computer Vision for JavaScript
  12630. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  12631. *
  12632. * Licensed under the Apache License, Version 2.0 (the "License");
  12633. * you may not use this file except in compliance with the License.
  12634. * You may obtain a copy of the License at
  12635. *
  12636. * http://www.apache.org/licenses/LICENSE-2.0
  12637. *
  12638. * Unless required by applicable law or agreed to in writing, software
  12639. * distributed under the License is distributed on an "AS IS" BASIS,
  12640. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12641. * See the License for the specific language governing permissions and
  12642. * limitations under the License.
  12643. *
  12644. * transforms.js
  12645. * Geometric transformations
  12646. */
  12647. //
  12648. // Shaders
  12649. //
  12650. // Perspective warp
  12651. const warpPerspective = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('transforms/warp-perspective.glsl')
  12652. .withArguments('image', 'inverseHomography');
  12653. // Resize image
  12654. const resizeNearest = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('transforms/resize.glsl')
  12655. .withDefines({
  12656. 'INTERPOLATION_METHOD': 0 // Nearest neighbors
  12657. })
  12658. .withArguments('image');
  12659. const resizeBilinear = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('transforms/resize.glsl')
  12660. .withDefines({
  12661. 'INTERPOLATION_METHOD': 1 // Bilinear interpolation
  12662. })
  12663. .withArguments('image');
  12664. // Additive mix (TODO create a new program group?)
  12665. const additiveMix = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_2__.importShader)('transforms/additive-mix.glsl')
  12666. .withArguments('image0', 'image1', 'alpha', 'beta', 'gamma');
  12667. /**
  12668. * SpeedyProgramGroupTransforms
  12669. * Geometric transformations
  12670. */
  12671. class SpeedyProgramGroupTransforms extends _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroup
  12672. {
  12673. /**
  12674. * Class constructor
  12675. * @param {SpeedyGPU} gpu
  12676. */
  12677. constructor(gpu)
  12678. {
  12679. super(gpu);
  12680. this
  12681. .declare('warpPerspective', warpPerspective)
  12682. .declare('resizeNearest', resizeNearest)
  12683. .declare('resizeBilinear', resizeBilinear)
  12684. .declare('additiveMix', additiveMix)
  12685. ;
  12686. }
  12687. }
  12688. /***/ }),
  12689. /***/ "./src/gpu/programs/utils.js":
  12690. /*!***********************************!*\
  12691. !*** ./src/gpu/programs/utils.js ***!
  12692. \***********************************/
  12693. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_566514__) => {
  12694. "use strict";
  12695. __nested_webpack_require_566514__.r(__webpack_exports__);
  12696. /* harmony export */ __nested_webpack_require_566514__.d(__webpack_exports__, {
  12697. /* harmony export */ "SpeedyProgramGroupUtils": () => (/* binding */ SpeedyProgramGroupUtils)
  12698. /* harmony export */ });
  12699. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_566514__(/*! ../speedy-gpu */ "./src/gpu/speedy-gpu.js");
  12700. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_566514__(/*! ../speedy-program-group */ "./src/gpu/speedy-program-group.js");
  12701. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_566514__(/*! ../speedy-texture */ "./src/gpu/speedy-texture.js");
  12702. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_566514__(/*! ../shader-declaration */ "./src/gpu/shader-declaration.js");
  12703. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_566514__(/*! ../../utils/utils */ "./src/utils/utils.js");
  12704. /*
  12705. * speedy-vision.js
  12706. * GPU-accelerated Computer Vision for JavaScript
  12707. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  12708. *
  12709. * Licensed under the Apache License, Version 2.0 (the "License");
  12710. * you may not use this file except in compliance with the License.
  12711. * You may obtain a copy of the License at
  12712. *
  12713. * http://www.apache.org/licenses/LICENSE-2.0
  12714. *
  12715. * Unless required by applicable law or agreed to in writing, software
  12716. * distributed under the License is distributed on an "AS IS" BASIS,
  12717. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12718. * See the License for the specific language governing permissions and
  12719. * limitations under the License.
  12720. *
  12721. * utils.js
  12722. * GPU utilities
  12723. */
  12724. //
  12725. // Shaders
  12726. //
  12727. // Copy image
  12728. const copy = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/copy.glsl').withArguments('image');
  12729. // Copy keypoints
  12730. const copyKeypoints = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/copy-raster.glsl').withDefines({ 'TYPE': 1 }).withArguments('image');
  12731. // Copy 2D vectors
  12732. const copy2DVectors = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/copy-raster.glsl').withDefines({ 'TYPE': 2 }).withArguments('image');
  12733. // Flip y-axis for output
  12734. const flipY = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/copy.glsl', 'utils/flip-y.vs.glsl').withArguments('image');
  12735. // Fill image with a constant
  12736. const fill = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/fill.glsl').withArguments('value');
  12737. // Fill zero or more color components of the input image with a constant value
  12738. const fillComponents = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/fill-components.glsl').withArguments('image', 'pixelComponents', 'value');
  12739. // Copy the src component of src to zero or more color components of a copy of dest
  12740. const copyComponents = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/copy-components.glsl').withArguments('dest', 'src', 'destComponents', 'srcComponentId');
  12741. // Scan the entire image and find the minimum & maximum pixel intensity
  12742. const scanMinMax2D = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/scan-minmax2d.glsl').withArguments('image', 'iterationNumber');
  12743. // Compute the partial derivatives of an image
  12744. const sobelDerivatives = (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_3__.importShader)('utils/sobel-derivatives.glsl', 'utils/sobel-derivatives.vs.glsl').withArguments('pyramid', 'lod');
  12745. /**
  12746. * SpeedyProgramGroupUtils
  12747. * Utility operations
  12748. */
  12749. class SpeedyProgramGroupUtils extends _speedy_program_group__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroup
  12750. {
  12751. /**
  12752. * Class constructor
  12753. * @param {SpeedyGPU} gpu
  12754. */
  12755. constructor(gpu)
  12756. {
  12757. super(gpu);
  12758. this
  12759. // render to the canvas
  12760. .declare('renderToCanvas', flipY, {
  12761. ...this.program.rendersToCanvas()
  12762. })
  12763. // copy image
  12764. .declare('copy', copy)
  12765. // copy keypoints
  12766. .declare('copyKeypoints', copyKeypoints)
  12767. // copy 2D vectors
  12768. .declare('copy2DVectors', copy2DVectors)
  12769. // Fill image with a constant
  12770. .declare('fill', fill)
  12771. // Fill zero or more color components of the input image with a constant value
  12772. .declare('fillComponents', fillComponents)
  12773. // Copy the src component of src to zero or more color components of a copy of dest
  12774. .declare('copyComponents', copyComponents)
  12775. // find minimum & maximum pixel intensity
  12776. .declare('scanMinMax2D', scanMinMax2D, {
  12777. ...this.program.usesPingpongRendering()
  12778. })
  12779. // Compute the partial derivatives of an image
  12780. .declare('sobelDerivatives', sobelDerivatives)
  12781. ;
  12782. }
  12783. }
  12784. /***/ }),
  12785. /***/ "./src/gpu/shader-declaration.js":
  12786. /*!***************************************!*\
  12787. !*** ./src/gpu/shader-declaration.js ***!
  12788. \***************************************/
  12789. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_571737__) => {
  12790. "use strict";
  12791. __nested_webpack_require_571737__.r(__webpack_exports__);
  12792. /* harmony export */ __nested_webpack_require_571737__.d(__webpack_exports__, {
  12793. /* harmony export */ "ShaderDeclaration": () => (/* binding */ ShaderDeclaration),
  12794. /* harmony export */ "importShader": () => (/* binding */ importShader),
  12795. /* harmony export */ "createShader": () => (/* binding */ createShader)
  12796. /* harmony export */ });
  12797. /* harmony import */ var _shader_preprocessor__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_571737__(/*! ./shader-preprocessor */ "./src/gpu/shader-preprocessor.js");
  12798. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_571737__(/*! ../utils/errors */ "./src/utils/errors.js");
  12799. /*
  12800. * speedy-vision.js
  12801. * GPU-accelerated Computer Vision for JavaScript
  12802. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  12803. *
  12804. * Licensed under the Apache License, Version 2.0 (the "License");
  12805. * you may not use this file except in compliance with the License.
  12806. * You may obtain a copy of the License at
  12807. *
  12808. * http://www.apache.org/licenses/LICENSE-2.0
  12809. *
  12810. * Unless required by applicable law or agreed to in writing, software
  12811. * distributed under the License is distributed on an "AS IS" BASIS,
  12812. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12813. * See the License for the specific language governing permissions and
  12814. * limitations under the License.
  12815. *
  12816. * shader-declaration.js
  12817. * Encapsulates a shader declaration
  12818. */
  12819. const DEFAULT_ATTRIBUTES = Object.freeze({
  12820. position: 'a_position',
  12821. texCoord: 'a_texCoord'
  12822. });
  12823. const DEFAULT_ATTRIBUTES_LOCATION = Object.freeze({
  12824. position: 0, // use location 0; see https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices
  12825. texCoord: 1,
  12826. });
  12827. const DEFAULT_VERTEX_SHADER_PREFIX = `#version 300 es
  12828. precision highp float;
  12829. precision highp int;
  12830. layout (location=${DEFAULT_ATTRIBUTES_LOCATION.position}) in vec2 ${DEFAULT_ATTRIBUTES.position};
  12831. layout (location=${DEFAULT_ATTRIBUTES_LOCATION.texCoord}) in vec2 ${DEFAULT_ATTRIBUTES.texCoord};
  12832. out highp vec2 texCoord;
  12833. uniform highp vec2 texSize;
  12834. #define vsinit() \
  12835. gl_Position = vec4(${DEFAULT_ATTRIBUTES.position}, 0.0f, 1.0f); \
  12836. texCoord = ${DEFAULT_ATTRIBUTES.texCoord};
  12837. \n\n`;
  12838. const DEFAULT_VERTEX_SHADER = `#define vsmain() ;`;
  12839. const DEFAULT_VERTEX_SHADER_SUFFIX = `\n\nvoid main() { vsinit(); vsmain(); }\n`;
  12840. const DEFAULT_FRAGMENT_SHADER_PREFIX = `#version 300 es
  12841. #if @FS_USE_CUSTOM_PRECISION@ == 0
  12842. precision mediump float; // ~float16
  12843. precision mediump sampler2D;
  12844. precision highp int; // int32
  12845. #endif
  12846. #if @FS_OUTPUT_TYPE@ == 0
  12847. #define OUT_TYPE mediump vec4
  12848. #elif @FS_OUTPUT_TYPE@ == 1
  12849. #define OUT_TYPE mediump ivec4
  12850. #elif @FS_OUTPUT_TYPE@ == 2
  12851. #define OUT_TYPE mediump uvec4
  12852. #else
  12853. #error Unknown FS_OUTPUT_TYPE
  12854. #endif
  12855. out OUT_TYPE color;
  12856. in highp vec2 texCoord;
  12857. uniform highp vec2 texSize;
  12858. @include "global.glsl"\n\n`;
  12859. const PRIVATE_TOKEN = Symbol();
  12860. /**
  12861. * @typedef {object} ShaderDeclarationFilepathOptions
  12862. * @property {"filepath"} type
  12863. * @property {string} filepath
  12864. * @property {string} [vsfilepath]
  12865. *
  12866. * @typedef {object} ShaderDeclarationSourceOptions
  12867. * @property {"source"} type
  12868. * @property {string} source
  12869. * @property {string} [vssource]
  12870. *
  12871. * @typedef {ShaderDeclarationFilepathOptions | ShaderDeclarationSourceOptions} ShaderDeclarationOptions
  12872. */
  12873. /** @typedef {import('./shader-preprocessor').ShaderDefines} ShaderDefines */
  12874. /**
  12875. * Shader Declaration
  12876. */
  12877. class ShaderDeclaration
  12878. {
  12879. /**
  12880. * @private Constructor
  12881. * @param {ShaderDeclarationOptions} options
  12882. * @param {Symbol} privateToken
  12883. */
  12884. constructor(options, privateToken)
  12885. {
  12886. if(privateToken !== PRIVATE_TOKEN)
  12887. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(); // private constructor!
  12888. /** @type {string} original source code provided by the user (fragment shader) */
  12889. this._source = (() => {
  12890. switch(options.type) {
  12891. case 'filepath': return __nested_webpack_require_571737__("./src/gpu/shaders sync recursive ^\\.\\/.*$")("./" + options.filepath);
  12892. case 'source': return options.source;
  12893. default: return /** @type {never} */ ( '' );
  12894. }
  12895. })();
  12896. /** @type {string} vertex shader source code (without preprocessing) */
  12897. this._vssource = (() => {
  12898. switch(options.type) {
  12899. case 'filepath': return options.vsfilepath ? __nested_webpack_require_571737__("./src/gpu/shaders sync recursive ^\\.\\/.*$")("./" + options.vsfilepath) : DEFAULT_VERTEX_SHADER;
  12900. case 'source': return options.vssource ? options.vssource : DEFAULT_VERTEX_SHADER;
  12901. default: return /** @type {never} */ ( '' );
  12902. }
  12903. })();
  12904. /** @type {string} preprocessed source code of the fragment shader */
  12905. this._fragmentSource = _shader_preprocessor__WEBPACK_IMPORTED_MODULE_0__.ShaderPreprocessor.run(DEFAULT_FRAGMENT_SHADER_PREFIX + this._source);
  12906. /** @type {string} preprocessed source code of the vertex shader */
  12907. this._vertexSource = _shader_preprocessor__WEBPACK_IMPORTED_MODULE_0__.ShaderPreprocessor.run(DEFAULT_VERTEX_SHADER_PREFIX + this._vssource + DEFAULT_VERTEX_SHADER_SUFFIX);
  12908. /** @type {string} filepath of the fragment shader */
  12909. this._filepath = options.type === 'filepath' ? options.filepath : '<in-memory>';
  12910. /** @type {string} filepath of the vertex shader */
  12911. this._vsfilepath = options.type === 'filepath' && options.vsfilepath ? options.vsfilepath : '<in-memory>';
  12912. /** @type {string[]} an ordered list of uniform names */
  12913. this._arguments = [];
  12914. /** @type {Map<string,string>} it maps uniform names to their types */
  12915. this._uniforms = this._autodetectUniforms(this._fragmentSource + '\n' + this._vertexSource);
  12916. /** @type {ShaderDefines} it maps externally #defined constants to their values */
  12917. this._defines = new Map();
  12918. }
  12919. /**
  12920. * Creates a new Shader directly from a GLSL source
  12921. * @param {string} source fragment shader
  12922. * @param {string|null} [vssource] vertex shader
  12923. * @returns {ShaderDeclaration}
  12924. */
  12925. static create(source, vssource = null)
  12926. {
  12927. return new ShaderDeclaration({ type: 'source', source, vssource }, PRIVATE_TOKEN);
  12928. }
  12929. /**
  12930. * Import a Shader from a file containing a GLSL source
  12931. * @param {string} filepath path to .glsl file relative to the shaders/ folder
  12932. * @param {string} [vsfilepath] path to a .vs.glsl file relative to the shaders/ folder
  12933. * @returns {ShaderDeclaration}
  12934. */
  12935. static import(filepath, vsfilepath = null)
  12936. {
  12937. if(!String(filepath).match(/^[a-zA-Z0-9_\-/]+\.glsl$/))
  12938. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.FileNotFoundError(`Can't import fragment shader at "${filepath}"`);
  12939. else if(vsfilepath != null && !String(vsfilepath).match(/^[a-zA-Z0-9_\-/]+\.vs\.glsl$/))
  12940. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.FileNotFoundError(`Can't import vertex shader at "${vsfilepath}"`);
  12941. return new ShaderDeclaration({ type: 'filepath', filepath, vsfilepath }, PRIVATE_TOKEN);
  12942. }
  12943. /**
  12944. * Specify the list & order of arguments to be
  12945. * passed to the shader
  12946. * @param {...string} args argument names
  12947. * @returns {this}
  12948. */
  12949. withArguments(...args)
  12950. {
  12951. // the list of arguments may be declared only once
  12952. if(this._arguments.length > 0)
  12953. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(`Redefinition of shader arguments`);
  12954. // get arguments
  12955. this._arguments = args.map(arg => String(arg));
  12956. // validate
  12957. for(const argname of this._arguments) {
  12958. if(!this._uniforms.has(argname)) {
  12959. if(!this._uniforms.has(argname + '[0]'))
  12960. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Argument "${argname}" has not been declared in the shader`);
  12961. }
  12962. }
  12963. // done!
  12964. return this;
  12965. }
  12966. /**
  12967. * Specify a set of #defines to be prepended to the fragment shader
  12968. * @param {Object<string,number>} defines key-value pairs (define-name: define-value)
  12969. * @returns {this}
  12970. */
  12971. withDefines(defines)
  12972. {
  12973. // the list of #defines may be defined only once
  12974. if(this._defines.size > 0)
  12975. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(`Redefinition of externally defined constants of a shader`);
  12976. // store and write the #defines
  12977. const defs = [], keys = Object.keys(defines);
  12978. for(const key of keys) {
  12979. const value = Number(defines[key]); // force numeric values (just in case)
  12980. this._defines.set(key, value);
  12981. defs.push(`#define ${key} ${value}\n`);
  12982. }
  12983. // update the shaders & the uniforms
  12984. const source = DEFAULT_FRAGMENT_SHADER_PREFIX + defs.join('') + this._source;
  12985. const vssource = DEFAULT_VERTEX_SHADER_PREFIX + defs.join('') + this._vssource + DEFAULT_VERTEX_SHADER_SUFFIX;
  12986. this._fragmentSource = _shader_preprocessor__WEBPACK_IMPORTED_MODULE_0__.ShaderPreprocessor.run(source, this._defines);
  12987. this._vertexSource = _shader_preprocessor__WEBPACK_IMPORTED_MODULE_0__.ShaderPreprocessor.run(vssource, this._defines);
  12988. this._uniforms = this._autodetectUniforms(this._fragmentSource + '\n' + this._vertexSource);
  12989. // done!
  12990. return this;
  12991. }
  12992. /**
  12993. * Return the GLSL source of the fragment shader
  12994. * @returns {string}
  12995. */
  12996. get fragmentSource()
  12997. {
  12998. return this._fragmentSource;
  12999. }
  13000. /**
  13001. * Return the GLSL source of the vertex shader
  13002. * @returns {string}
  13003. */
  13004. get vertexSource()
  13005. {
  13006. return this._vertexSource;
  13007. }
  13008. /**
  13009. * Get the names of the vertex shader attributes
  13010. * @returns {typeof DEFAULT_ATTRIBUTES}
  13011. */
  13012. get attributes()
  13013. {
  13014. return DEFAULT_ATTRIBUTES;
  13015. }
  13016. /**
  13017. * Get the pre-defined locations of the vertex shader attributes
  13018. * @returns {typeof DEFAULT_ATTRIBUTES_LOCATION}
  13019. */
  13020. get locationOfAttributes()
  13021. {
  13022. return DEFAULT_ATTRIBUTES_LOCATION;
  13023. }
  13024. /**
  13025. * Names of the arguments that will be passed to the Shader,
  13026. * corresponding to GLSL uniforms, in the order they will be passed
  13027. * @returns {string[]}
  13028. */
  13029. get arguments()
  13030. {
  13031. return this._arguments;
  13032. }
  13033. /**
  13034. * Names of the uniforms declared in the shader
  13035. * @returns {string[]}
  13036. */
  13037. get uniforms()
  13038. {
  13039. return Array.from(this._uniforms.keys());
  13040. }
  13041. /**
  13042. * The GLSL type of a uniform variable declared in the shader
  13043. * @param {string} name
  13044. * @returns {string}
  13045. */
  13046. uniformType(name)
  13047. {
  13048. if(!this._uniforms.has(name))
  13049. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Unrecognized uniform variable: "${name}"`);
  13050. return this._uniforms.get(name);
  13051. }
  13052. /**
  13053. * The value of an externally defined constant, i.e., via withDefines()
  13054. * @param {string} name
  13055. * @returns {number}
  13056. */
  13057. definedConstant(name)
  13058. {
  13059. if(!this._defines.has(name))
  13060. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalArgumentError(`Unrecognized externally defined constant: "${name}"`);
  13061. return this._defines.get(name);
  13062. }
  13063. /**
  13064. * Parses a GLSL source and detects the uniform variables,
  13065. * as well as their types
  13066. * @param {string} preprocessedSource
  13067. * @returns {Map<string,string>} specifies the types of all uniforms
  13068. */
  13069. _autodetectUniforms(preprocessedSource)
  13070. {
  13071. const sourceWithoutComments = preprocessedSource; // assume we've preprocessed the source already
  13072. const regex = /^\s*uniform\s+(highp\s+|mediump\s+|lowp\s+)?(\w+)\s+([^;]+)/gm;
  13073. const uniforms = new Map();
  13074. let match;
  13075. while((match = regex.exec(sourceWithoutComments)) !== null) {
  13076. const type = match[2];
  13077. const names = match[3].split(',').map(name => name.trim()).filter(name => name); // trim & remove empty names
  13078. for(const name of names) {
  13079. if(name.endsWith(']')) {
  13080. // is it an array?
  13081. if(!(match = name.match(/(\w+)\s*\[\s*(\d+)\s*\]$/)))
  13082. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.ParseError(`Unspecified array length for uniform "${name}" in the shader`);
  13083. // read array name & size
  13084. const [ array, size ] = [ match[1], Number(match[2]) ];
  13085. // register uniforms
  13086. for(let i = 0; i < size; i++)
  13087. uniforms.set(`${array}[${i}]`, type);
  13088. }
  13089. else {
  13090. // register a regular uniform
  13091. if(!uniforms.has(name) || uniforms.get(name) === type)
  13092. uniforms.set(name, type);
  13093. else
  13094. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_1__.IllegalOperationError(`Redefinition of uniform "${name}" in the shader`);
  13095. }
  13096. }
  13097. }
  13098. return uniforms;
  13099. }
  13100. }
  13101. /**
  13102. * Import a ShaderDeclaration from a GLSL file
  13103. * @param {string} filepath relative to the shaders/ folder (a .glsl file)
  13104. * @param {string|null} [vsfilepath] optional vertex shader (a .vs.glsl file)
  13105. * @returns {ShaderDeclaration}
  13106. */
  13107. function importShader(filepath, vsfilepath = null)
  13108. {
  13109. return ShaderDeclaration.import(filepath, vsfilepath);
  13110. }
  13111. /**
  13112. * Create a ShaderDeclaration from a GLSL source code
  13113. * @param {string} source fragment shader
  13114. * @param {string|null} [vssource] optional vertex shader
  13115. * @returns {ShaderDeclaration}
  13116. */
  13117. function createShader(source, vssource = null)
  13118. {
  13119. return ShaderDeclaration.create(source, vssource);
  13120. }
  13121. /***/ }),
  13122. /***/ "./src/gpu/shader-preprocessor.js":
  13123. /*!****************************************!*\
  13124. !*** ./src/gpu/shader-preprocessor.js ***!
  13125. \****************************************/
  13126. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_586033__) => {
  13127. "use strict";
  13128. __nested_webpack_require_586033__.r(__webpack_exports__);
  13129. /* harmony export */ __nested_webpack_require_586033__.d(__webpack_exports__, {
  13130. /* harmony export */ "ShaderPreprocessor": () => (/* binding */ ShaderPreprocessor)
  13131. /* harmony export */ });
  13132. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_586033__(/*! ../utils/utils */ "./src/utils/utils.js");
  13133. /* harmony import */ var _utils_types__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_586033__(/*! ../utils/types */ "./src/utils/types.js");
  13134. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_586033__(/*! ../utils/errors */ "./src/utils/errors.js");
  13135. /*
  13136. * speedy-vision.js
  13137. * GPU-accelerated Computer Vision for JavaScript
  13138. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  13139. *
  13140. * Licensed under the Apache License, Version 2.0 (the "License");
  13141. * you may not use this file except in compliance with the License.
  13142. * You may obtain a copy of the License at
  13143. *
  13144. * http://www.apache.org/licenses/LICENSE-2.0
  13145. *
  13146. * Unless required by applicable law or agreed to in writing, software
  13147. * distributed under the License is distributed on an "AS IS" BASIS,
  13148. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13149. * See the License for the specific language governing permissions and
  13150. * limitations under the License.
  13151. *
  13152. * shader-preprocessor.js
  13153. * Custom preprocessor for shaders
  13154. */
  13155. // Import numeric globals
  13156. const globals = __nested_webpack_require_586033__(/*! ../utils/globals */ "./src/utils/globals.js");
  13157. const numericGlobals = Object.keys(globals).filter(key => typeof globals[key] == 'number').reduce(
  13158. (obj, key) => ((obj[key] = globals[key]), obj), {}
  13159. );
  13160. // Constants accessible by all shaders
  13161. const constants = Object.freeze({
  13162. // numeric globals
  13163. ...numericGlobals,
  13164. // fragment shader
  13165. 'FS_USE_CUSTOM_PRECISION': 0, // use default precision settings
  13166. 'FS_OUTPUT_TYPE': 0, // normalized RGBA
  13167. // colors
  13168. 'PIXELCOMPONENT_RED': _utils_types__WEBPACK_IMPORTED_MODULE_1__.PixelComponent.RED,
  13169. 'PIXELCOMPONENT_GREEN': _utils_types__WEBPACK_IMPORTED_MODULE_1__.PixelComponent.GREEN,
  13170. 'PIXELCOMPONENT_BLUE': _utils_types__WEBPACK_IMPORTED_MODULE_1__.PixelComponent.BLUE,
  13171. 'PIXELCOMPONENT_ALPHA': _utils_types__WEBPACK_IMPORTED_MODULE_1__.PixelComponent.ALPHA,
  13172. });
  13173. // Regular Expressions
  13174. const commentsRegex = [ /\/\*(.|\s)*?\*\//g , /\/\/.*$/gm ];
  13175. const includeRegex = /^\s*@\s*include\s+"(.*?)"/gm;
  13176. const constantRegex = /@(\w+)@/g;
  13177. const unrollRegex = [
  13178. /@\s*unroll\s+?for\s*\(\s*(int|)\s*(?<counter>\w+)\s*=\s*(-?\d+|\w+)\s*;\s*\k<counter>\s*(<=?)\s*(-?\d+|\w+)\s*;\s*\k<counter>\s*\+\+()\s*\)\s*\{\s*([\s\S]+?)\s*\}/g,
  13179. /@\s*unroll\s+?for\s*\(\s*(int|)\s*(?<counter>\w+)\s*=\s*(-?\d+|\w+)\s*;\s*\k<counter>\s*(<=?)\s*(-?\d+|\w+)\s*;\s*\k<counter>\s*\+=\s*(-?\d+)\s*\)\s*\{\s*([\s\S]+?)\s*\}/g,
  13180. ];
  13181. /** @typedef {Map<string,number>} ShaderDefines */
  13182. /**
  13183. * Custom preprocessor for the shaders
  13184. */
  13185. class ShaderPreprocessor
  13186. {
  13187. /**
  13188. * Runs the preprocessor
  13189. * @param {string} code
  13190. * @param {ShaderDefines} [defines]
  13191. * @returns {string} preprocessed code
  13192. */
  13193. static run(code, defines = new Map())
  13194. {
  13195. const errors = []; // compile-time errors
  13196. //
  13197. // The preprocessor will remove comments from GLSL code,
  13198. // include requested GLSL files and import global constants
  13199. // defined for all shaders (see above)
  13200. //
  13201. return unrollLoops(
  13202. String(code)
  13203. .replace(commentsRegex[0], '')
  13204. .replace(commentsRegex[1], '')
  13205. .replace(includeRegex, (_, filename) =>
  13206. // FIXME: no cycle detection for @include
  13207. ShaderPreprocessor.run(readfileSync(filename), defines)
  13208. )
  13209. .replace(constantRegex, (_, name) => String(
  13210. // Find a defined constant. If not possible, find a global constant
  13211. defines.has(name) ? Number(defines.get(name)) : (
  13212. constants[name] !== undefined ? Number(constants[name]) : (
  13213. errors.push(`Undefined constant: ${name}`), 0
  13214. )
  13215. )
  13216. )),
  13217. defines
  13218. ) + (errors.length > 0 ? errors.map(msg => `\n#error ${msg}\n`).join('') : '');
  13219. }
  13220. }
  13221. /**
  13222. * Reads a shader from the shaders/include/ folder
  13223. * @param {string} filename
  13224. * @returns {string}
  13225. */
  13226. function readfileSync(filename)
  13227. {
  13228. if(String(filename).match(/^[a-zA-Z0-9_-]+\.glsl$/))
  13229. return __nested_webpack_require_586033__("./src/gpu/shaders/include sync recursive ^\\.\\/.*$")("./" + filename);
  13230. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.FileNotFoundError(`Shader preprocessor: can't read file "${filename}"`);
  13231. }
  13232. /**
  13233. * Unroll for loops in our own preprocessor
  13234. * @param {string} code
  13235. * @param {ShaderDefines} defines
  13236. * @returns {string}
  13237. */
  13238. function unrollLoops(code, defines)
  13239. {
  13240. //
  13241. // Currently, only integer for loops with positive step values
  13242. // can be unrolled. (TODO: negative step values?)
  13243. //
  13244. // The current implementation does not support curly braces
  13245. // inside unrolled loops. You may define macros to get around
  13246. // this, but do you actually need to unroll such loops?
  13247. //
  13248. // Loops that don't fit the supported pattern will crash
  13249. // the preprocessor if you try to unroll them.
  13250. //
  13251. const fn = unroll.bind(defines); // CRAZY!
  13252. const n = unrollRegex.length;
  13253. for(let i = 0; i < n; i++)
  13254. code = code.replace(unrollRegex[i], fn);
  13255. return code;
  13256. }
  13257. /**
  13258. * Unroll a loop pattern (regexp)
  13259. * @param {string} match the matched for loop
  13260. * @param {string} type
  13261. * @param {string} counter
  13262. * @param {string} start
  13263. * @param {string} cmp
  13264. * @param {string} end
  13265. * @param {string} step
  13266. * @param {string} loopcode
  13267. * @returns {string} unrolled loop
  13268. */
  13269. function unroll(match, type, counter, start, cmp, end, step, loopcode)
  13270. {
  13271. const defines = /** @type {ShaderDefines} */ ( this );
  13272. // check if the loop limits are numeric constants or #defined numbers from the outside
  13273. const hasStart = Number.isFinite(+start) || defines.has(start);
  13274. const hasEnd = Number.isFinite(+end) || defines.has(end);
  13275. if(!hasStart || !hasEnd) {
  13276. if(defines.size > 0)
  13277. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.ParseError(`Can't unroll loop: unknown limits (start=${start}, end=${end}). Code:\n\n${match}`);
  13278. else
  13279. return match; // don't unroll now, because defines is empty - maybe we'll succeed in the next pass
  13280. }
  13281. // parse and validate limits & step
  13282. let istart = defines.has(start) ? defines.get(start) : parseInt(start);
  13283. let iend = defines.has(end) ? defines.get(end) : parseInt(end);
  13284. let istep = (step.length == 0) ? 1 : parseInt(step);
  13285. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(istart <= iend && istep > 0);
  13286. /*
  13287. // debug
  13288. console.log(`Encontrei "${match}"`);
  13289. console.log(`type="${type}"`);
  13290. console.log(`counter="${counter}"`);
  13291. console.log(`start="${start}"`);
  13292. console.log(`cmp="${cmp}"`);
  13293. console.log(`end="${end}"`);
  13294. console.log(`step="${step}"`);
  13295. console.log(`loopcode="${loopcode}"`)
  13296. console.log('Defines:', defines);
  13297. */
  13298. // continue statements are not supported inside unrolled loops
  13299. // and will generate a compiler error. Using break is ok.
  13300. const hasBreak = (loopcode.match(/\bbreak\s*;/) !== null);
  13301. // create a new scope
  13302. let unrolledCode = hasBreak ? 'switch(1) { default:\n' : '{\n';
  13303. // declare counter
  13304. unrolledCode += `${type} ${counter};\n`;
  13305. // unroll loop
  13306. iend += (cmp == '<=') ? 1 : 0;
  13307. for(let i = istart; i < iend; i += istep)
  13308. unrolledCode += `{\n${counter} = ${i};\n${loopcode}\n}\n`;
  13309. // close scope
  13310. unrolledCode += '}\n';
  13311. //console.log('Unrolled code:\n\n' + unrolledCode);
  13312. // done!
  13313. return unrolledCode;
  13314. }
  13315. /***/ }),
  13316. /***/ "./src/gpu/shaders/filters/convolution.js":
  13317. /*!************************************************!*\
  13318. !*** ./src/gpu/shaders/filters/convolution.js ***!
  13319. \************************************************/
  13320. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_594321__) => {
  13321. "use strict";
  13322. __nested_webpack_require_594321__.r(__webpack_exports__);
  13323. /* harmony export */ __nested_webpack_require_594321__.d(__webpack_exports__, {
  13324. /* harmony export */ "conv2D": () => (/* binding */ conv2D),
  13325. /* harmony export */ "convX": () => (/* binding */ convX),
  13326. /* harmony export */ "convY": () => (/* binding */ convY)
  13327. /* harmony export */ });
  13328. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_594321__(/*! ../../shader-declaration */ "./src/gpu/shader-declaration.js");
  13329. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_594321__(/*! ../../../utils/utils */ "./src/utils/utils.js");
  13330. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_594321__(/*! ../../../utils/errors */ "./src/utils/errors.js");
  13331. /*
  13332. * speedy-vision.js
  13333. * GPU-accelerated Computer Vision for JavaScript
  13334. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  13335. *
  13336. * Licensed under the Apache License, Version 2.0 (the "License");
  13337. * you may not use this file except in compliance with the License.
  13338. * You may obtain a copy of the License at
  13339. *
  13340. * http://www.apache.org/licenses/LICENSE-2.0
  13341. *
  13342. * Unless required by applicable law or agreed to in writing, software
  13343. * distributed under the License is distributed on an "AS IS" BASIS,
  13344. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13345. * See the License for the specific language governing permissions and
  13346. * limitations under the License.
  13347. *
  13348. * convolution.js
  13349. * Convolution shader generators
  13350. */
  13351. /**
  13352. * Generate a 2D convolution with a square kernel
  13353. * @param {number[]} kernel convolution kernel
  13354. * @param {number} [normalizationConstant] will be multiplied by all kernel entries
  13355. */
  13356. function conv2D(kernel, normalizationConstant = 1.0)
  13357. {
  13358. const kernel32 = new Float32Array(kernel.map(x => (+x) * (+normalizationConstant)));
  13359. const kSize = Math.sqrt(kernel32.length) | 0;
  13360. const N = kSize >> 1; // idiv 2
  13361. // validate input
  13362. if(kSize < 1 || kSize % 2 == 0)
  13363. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Can't perform a 2D convolution with an invalid kSize of ${kSize}`);
  13364. else if(kSize * kSize != kernel32.length)
  13365. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Invalid 2D convolution kernel of ${kernel32.length} elements (expected: square)`);
  13366. // select the appropriate pixel function
  13367. const pixelAtOffset = (N <= 7) ? 'pixelAtShortOffset' : 'pixelAtLongOffset';
  13368. // code generator
  13369. const foreachKernelElement = fn => _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.cartesian(_utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.symmetricRange(N), _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.symmetricRange(N)).map(
  13370. cur => fn(
  13371. kernel32[(cur[0] + N) * kSize + (cur[1] + N)],
  13372. cur[0], cur[1]
  13373. )
  13374. ).join('\n');
  13375. const generateCode = (k, dy, dx) => `
  13376. result += ${pixelAtOffset}(image, ivec2(${(-dx) | 0}, ${(-dy) | 0})) * float(${+k});
  13377. `;
  13378. // shader
  13379. const source = `
  13380. uniform sampler2D image;
  13381. void main()
  13382. {
  13383. float alpha = threadPixel(image).a;
  13384. vec4 result = vec4(0.0f);
  13385. ${foreachKernelElement(generateCode)}
  13386. color = vec4(result.rgb, alpha);
  13387. }
  13388. `;
  13389. // done!
  13390. return (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_0__.createShader)(source).withArguments('image');
  13391. }
  13392. /**
  13393. * Generate a 1D convolution function on the x-axis
  13394. * @param {number[]} kernel convolution kernel
  13395. * @param {number} [normalizationConstant] will be multiplied by all kernel entries
  13396. */
  13397. function convX(kernel, normalizationConstant = 1.0)
  13398. {
  13399. return conv1D('x', kernel, normalizationConstant);
  13400. }
  13401. /**
  13402. * Generate a 1D convolution function on the y-axis
  13403. * @param {number[]} kernel convolution kernel
  13404. * @param {number} [normalizationConstant] will be multiplied by all kernel entries
  13405. */
  13406. function convY(kernel, normalizationConstant = 1.0)
  13407. {
  13408. return conv1D('y', kernel, normalizationConstant);
  13409. }
  13410. /**
  13411. * 1D convolution function generator
  13412. * @param {string} axis either "x" or "y"
  13413. * @param {number[]} kernel convolution kernel
  13414. * @param {number} [normalizationConstant] will be multiplied by all kernel entries
  13415. */
  13416. function conv1D(axis, kernel, normalizationConstant = 1.0)
  13417. {
  13418. const kernel32 = new Float32Array(kernel.map(x => (+x) * (+normalizationConstant)));
  13419. const kSize = kernel32.length;
  13420. const N = kSize >> 1; // idiv 2
  13421. // validate input
  13422. if(kSize < 1 || kSize % 2 == 0)
  13423. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Can't perform a 1D convolution with an invalid kSize of ${kSize}`);
  13424. else if(axis != 'x' && axis != 'y')
  13425. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Can't perform 1D convolution: invalid axis "${axis}"`); // this should never happen
  13426. // select the appropriate pixel function
  13427. const pixelAtOffset = (N <= 7) ? 'pixelAtShortOffset' : 'pixelAtLongOffset';
  13428. // code generator
  13429. const foreachKernelElement = fn => _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.symmetricRange(N).reduce(
  13430. (acc, cur) => acc + fn(kernel32[cur + N], cur),
  13431. '');
  13432. const generateCode = (k, i) => ((axis == 'x') ? `
  13433. pixel += ${pixelAtOffset}(image, ivec2(${(-i) | 0}, 0)) * float(${+k});
  13434. ` : `
  13435. pixel += ${pixelAtOffset}(image, ivec2(0, ${(-i) | 0})) * float(${+k});
  13436. `);
  13437. // shader
  13438. const source = `
  13439. uniform sampler2D image;
  13440. void main()
  13441. {
  13442. float alpha = threadPixel(image).a;
  13443. vec4 pixel = vec4(0.0f);
  13444. ${foreachKernelElement(generateCode)}
  13445. color = vec4(pixel.rgb, alpha);
  13446. }
  13447. `;
  13448. // done!
  13449. return (0,_shader_declaration__WEBPACK_IMPORTED_MODULE_0__.createShader)(source).withArguments('image');
  13450. }
  13451. /***/ }),
  13452. /***/ "./src/gpu/shaders/include sync recursive ^\\.\\/.*$":
  13453. /*!************************************************!*\
  13454. !*** ./src/gpu/shaders/include/ sync ^\.\/.*$ ***!
  13455. \************************************************/
  13456. /***/ ((module, __unused_webpack_exports, __nested_webpack_require_600488__) => {
  13457. var map = {
  13458. "./colors.glsl": "./src/gpu/shaders/include/colors.glsl",
  13459. "./filters.glsl": "./src/gpu/shaders/include/filters.glsl",
  13460. "./fixed-point.glsl": "./src/gpu/shaders/include/fixed-point.glsl",
  13461. "./float16.glsl": "./src/gpu/shaders/include/float16.glsl",
  13462. "./global.glsl": "./src/gpu/shaders/include/global.glsl",
  13463. "./int32.glsl": "./src/gpu/shaders/include/int32.glsl",
  13464. "./keypoint-descriptors.glsl": "./src/gpu/shaders/include/keypoint-descriptors.glsl",
  13465. "./keypoint-matches.glsl": "./src/gpu/shaders/include/keypoint-matches.glsl",
  13466. "./keypoints.glsl": "./src/gpu/shaders/include/keypoints.glsl",
  13467. "./math.glsl": "./src/gpu/shaders/include/math.glsl",
  13468. "./pyramids.glsl": "./src/gpu/shaders/include/pyramids.glsl",
  13469. "./subpixel.glsl": "./src/gpu/shaders/include/subpixel.glsl"
  13470. };
  13471. function webpackContext(req) {
  13472. var id = webpackContextResolve(req);
  13473. return __nested_webpack_require_600488__(id);
  13474. }
  13475. function webpackContextResolve(req) {
  13476. if(!__nested_webpack_require_600488__.o(map, req)) {
  13477. var e = new Error("Cannot find module '" + req + "'");
  13478. e.code = 'MODULE_NOT_FOUND';
  13479. throw e;
  13480. }
  13481. return map[req];
  13482. }
  13483. webpackContext.keys = function webpackContextKeys() {
  13484. return Object.keys(map);
  13485. };
  13486. webpackContext.resolve = webpackContextResolve;
  13487. module.exports = webpackContext;
  13488. webpackContext.id = "./src/gpu/shaders/include sync recursive ^\\.\\/.*$";
  13489. /***/ }),
  13490. /***/ "./src/gpu/shaders sync recursive ^\\.\\/.*$":
  13491. /*!****************************************!*\
  13492. !*** ./src/gpu/shaders/ sync ^\.\/.*$ ***!
  13493. \****************************************/
  13494. /***/ ((module, __unused_webpack_exports, __nested_webpack_require_602096__) => {
  13495. var map = {
  13496. "./filters/convolution": "./src/gpu/shaders/filters/convolution.js",
  13497. "./filters/convolution.js": "./src/gpu/shaders/filters/convolution.js",
  13498. "./filters/convolution1d.glsl": "./src/gpu/shaders/filters/convolution1d.glsl",
  13499. "./filters/convolution2d.glsl": "./src/gpu/shaders/filters/convolution2d.glsl",
  13500. "./filters/fast-median.glsl": "./src/gpu/shaders/filters/fast-median.glsl",
  13501. "./filters/nightvision.glsl": "./src/gpu/shaders/filters/nightvision.glsl",
  13502. "./filters/normalize-image.glsl": "./src/gpu/shaders/filters/normalize-image.glsl",
  13503. "./filters/rgb2grey.glsl": "./src/gpu/shaders/filters/rgb2grey.glsl",
  13504. "./include/colors.glsl": "./src/gpu/shaders/include/colors.glsl",
  13505. "./include/filters.glsl": "./src/gpu/shaders/include/filters.glsl",
  13506. "./include/fixed-point.glsl": "./src/gpu/shaders/include/fixed-point.glsl",
  13507. "./include/float16.glsl": "./src/gpu/shaders/include/float16.glsl",
  13508. "./include/global.glsl": "./src/gpu/shaders/include/global.glsl",
  13509. "./include/int32.glsl": "./src/gpu/shaders/include/int32.glsl",
  13510. "./include/keypoint-descriptors.glsl": "./src/gpu/shaders/include/keypoint-descriptors.glsl",
  13511. "./include/keypoint-matches.glsl": "./src/gpu/shaders/include/keypoint-matches.glsl",
  13512. "./include/keypoints.glsl": "./src/gpu/shaders/include/keypoints.glsl",
  13513. "./include/math.glsl": "./src/gpu/shaders/include/math.glsl",
  13514. "./include/pyramids.glsl": "./src/gpu/shaders/include/pyramids.glsl",
  13515. "./include/subpixel.glsl": "./src/gpu/shaders/include/subpixel.glsl",
  13516. "./keypoints/allocate-descriptors.glsl": "./src/gpu/shaders/keypoints/allocate-descriptors.glsl",
  13517. "./keypoints/allocate-extra.glsl": "./src/gpu/shaders/keypoints/allocate-extra.glsl",
  13518. "./keypoints/apply-homography.glsl": "./src/gpu/shaders/keypoints/apply-homography.glsl",
  13519. "./keypoints/bf-knn.glsl": "./src/gpu/shaders/keypoints/bf-knn.glsl",
  13520. "./keypoints/clip-border.glsl": "./src/gpu/shaders/keypoints/clip-border.glsl",
  13521. "./keypoints/clip.glsl": "./src/gpu/shaders/keypoints/clip.glsl",
  13522. "./keypoints/distance-filter.glsl": "./src/gpu/shaders/keypoints/distance-filter.glsl",
  13523. "./keypoints/encode-keypoint-long-offsets.glsl": "./src/gpu/shaders/keypoints/encode-keypoint-long-offsets.glsl",
  13524. "./keypoints/encode-keypoint-offsets.glsl": "./src/gpu/shaders/keypoints/encode-keypoint-offsets.glsl",
  13525. "./keypoints/encode-keypoint-positions.glsl": "./src/gpu/shaders/keypoints/encode-keypoint-positions.glsl",
  13526. "./keypoints/encode-keypoint-properties.glsl": "./src/gpu/shaders/keypoints/encode-keypoint-properties.glsl",
  13527. "./keypoints/encode-keypoints.glsl": "./src/gpu/shaders/keypoints/encode-keypoints.glsl",
  13528. "./keypoints/encode-null-keypoints.glsl": "./src/gpu/shaders/keypoints/encode-null-keypoints.glsl",
  13529. "./keypoints/fast.glsl": "./src/gpu/shaders/keypoints/fast.glsl",
  13530. "./keypoints/fast.vs.glsl": "./src/gpu/shaders/keypoints/fast.vs.glsl",
  13531. "./keypoints/hamming-distance-filter.glsl": "./src/gpu/shaders/keypoints/hamming-distance-filter.glsl",
  13532. "./keypoints/harris-cutoff.glsl": "./src/gpu/shaders/keypoints/harris-cutoff.glsl",
  13533. "./keypoints/harris.glsl": "./src/gpu/shaders/keypoints/harris.glsl",
  13534. "./keypoints/knn-init.glsl": "./src/gpu/shaders/keypoints/knn-init.glsl",
  13535. "./keypoints/knn-transfer.glsl": "./src/gpu/shaders/keypoints/knn-transfer.glsl",
  13536. "./keypoints/laplacian.glsl": "./src/gpu/shaders/keypoints/laplacian.glsl",
  13537. "./keypoints/lk.glsl": "./src/gpu/shaders/keypoints/lk.glsl",
  13538. "./keypoints/lookup-of-locations.glsl": "./src/gpu/shaders/keypoints/lookup-of-locations.glsl",
  13539. "./keypoints/lookup-of-locations.vs.glsl": "./src/gpu/shaders/keypoints/lookup-of-locations.vs.glsl",
  13540. "./keypoints/lsh-knn.glsl": "./src/gpu/shaders/keypoints/lsh-knn.glsl",
  13541. "./keypoints/mix-keypoints.glsl": "./src/gpu/shaders/keypoints/mix-keypoints.glsl",
  13542. "./keypoints/nonmax-scale.glsl": "./src/gpu/shaders/keypoints/nonmax-scale.glsl",
  13543. "./keypoints/nonmax-space.glsl": "./src/gpu/shaders/keypoints/nonmax-space.glsl",
  13544. "./keypoints/nonmax-suppression.glsl": "./src/gpu/shaders/keypoints/nonmax-suppression.glsl",
  13545. "./keypoints/orb-descriptor.glsl": "./src/gpu/shaders/keypoints/orb-descriptor.glsl",
  13546. "./keypoints/orb-orientation.glsl": "./src/gpu/shaders/keypoints/orb-orientation.glsl",
  13547. "./keypoints/refine-scale.glsl": "./src/gpu/shaders/keypoints/refine-scale.glsl",
  13548. "./keypoints/score-findmax.glsl": "./src/gpu/shaders/keypoints/score-findmax.glsl",
  13549. "./keypoints/shuffle.glsl": "./src/gpu/shaders/keypoints/shuffle.glsl",
  13550. "./keypoints/sort-keypoints.glsl": "./src/gpu/shaders/keypoints/sort-keypoints.glsl",
  13551. "./keypoints/subpixel-refinement.glsl": "./src/gpu/shaders/keypoints/subpixel-refinement.glsl",
  13552. "./keypoints/transfer-flow.glsl": "./src/gpu/shaders/keypoints/transfer-flow.glsl",
  13553. "./keypoints/transfer-orientation.glsl": "./src/gpu/shaders/keypoints/transfer-orientation.glsl",
  13554. "./keypoints/transfer-to-extra.glsl": "./src/gpu/shaders/keypoints/transfer-to-extra.glsl",
  13555. "./keypoints/upload-keypoints.glsl": "./src/gpu/shaders/keypoints/upload-keypoints.glsl",
  13556. "./pyramids/downsample2.glsl": "./src/gpu/shaders/pyramids/downsample2.glsl",
  13557. "./pyramids/upsample2.glsl": "./src/gpu/shaders/pyramids/upsample2.glsl",
  13558. "./transforms/additive-mix.glsl": "./src/gpu/shaders/transforms/additive-mix.glsl",
  13559. "./transforms/resize.glsl": "./src/gpu/shaders/transforms/resize.glsl",
  13560. "./transforms/warp-perspective.glsl": "./src/gpu/shaders/transforms/warp-perspective.glsl",
  13561. "./utils/copy-components.glsl": "./src/gpu/shaders/utils/copy-components.glsl",
  13562. "./utils/copy-raster.glsl": "./src/gpu/shaders/utils/copy-raster.glsl",
  13563. "./utils/copy.glsl": "./src/gpu/shaders/utils/copy.glsl",
  13564. "./utils/fill-components.glsl": "./src/gpu/shaders/utils/fill-components.glsl",
  13565. "./utils/fill.glsl": "./src/gpu/shaders/utils/fill.glsl",
  13566. "./utils/flip-y.vs.glsl": "./src/gpu/shaders/utils/flip-y.vs.glsl",
  13567. "./utils/scan-minmax2d.glsl": "./src/gpu/shaders/utils/scan-minmax2d.glsl",
  13568. "./utils/sobel-derivatives.glsl": "./src/gpu/shaders/utils/sobel-derivatives.glsl",
  13569. "./utils/sobel-derivatives.vs.glsl": "./src/gpu/shaders/utils/sobel-derivatives.vs.glsl"
  13570. };
  13571. function webpackContext(req) {
  13572. var id = webpackContextResolve(req);
  13573. return __nested_webpack_require_602096__(id);
  13574. }
  13575. function webpackContextResolve(req) {
  13576. if(!__nested_webpack_require_602096__.o(map, req)) {
  13577. var e = new Error("Cannot find module '" + req + "'");
  13578. e.code = 'MODULE_NOT_FOUND';
  13579. throw e;
  13580. }
  13581. return map[req];
  13582. }
  13583. webpackContext.keys = function webpackContextKeys() {
  13584. return Object.keys(map);
  13585. };
  13586. webpackContext.resolve = webpackContextResolve;
  13587. module.exports = webpackContext;
  13588. webpackContext.id = "./src/gpu/shaders sync recursive ^\\.\\/.*$";
  13589. /***/ }),
  13590. /***/ "./src/gpu/speedy-descriptordb.js":
  13591. /*!****************************************!*\
  13592. !*** ./src/gpu/speedy-descriptordb.js ***!
  13593. \****************************************/
  13594. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_608992__) => {
  13595. "use strict";
  13596. __nested_webpack_require_608992__.r(__webpack_exports__);
  13597. /* harmony export */ __nested_webpack_require_608992__.d(__webpack_exports__, {
  13598. /* harmony export */ "SpeedyDescriptorDB": () => (/* binding */ SpeedyDescriptorDB)
  13599. /* harmony export */ });
  13600. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_608992__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  13601. /* harmony import */ var _core_speedy_namespace__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_608992__(/*! ../core/speedy-namespace */ "./src/core/speedy-namespace.js");
  13602. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_608992__(/*! ../utils/utils */ "./src/utils/utils.js");
  13603. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_608992__(/*! ../utils/errors */ "./src/utils/errors.js");
  13604. /*
  13605. * speedy-vision.js
  13606. * GPU-accelerated Computer Vision for JavaScript
  13607. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  13608. *
  13609. * Licensed under the Apache License, Version 2.0 (the "License");
  13610. * you may not use this file except in compliance with the License.
  13611. * You may obtain a copy of the License at
  13612. *
  13613. * http://www.apache.org/licenses/LICENSE-2.0
  13614. *
  13615. * Unless required by applicable law or agreed to in writing, software
  13616. * distributed under the License is distributed on an "AS IS" BASIS,
  13617. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13618. * See the License for the specific language governing permissions and
  13619. * limitations under the License.
  13620. *
  13621. * speedy-descriptordb.js
  13622. * A database of binary descriptors in video memory
  13623. */
  13624. //
  13625. // A database of binary descriptors is a texture that stores
  13626. // a set of (descriptor: uint8_t[]) entries.
  13627. //
  13628. /** @type {number} we use RGBA8 textures to store the descriptors */
  13629. const DESCRIPTORDB_BYTESPERPIXEL = 4;
  13630. /** @type {number} texture size goes up to 16 MB */
  13631. const DESCRIPTORDB_MAXLOG2STRIDE = 11; // 2048x2048 RGBA8 textures are guaranteed to be available in WebGL2 (where is the source of this?)
  13632. /**
  13633. * Utility for generating a database of binary descriptors in video memory
  13634. */
  13635. class SpeedyDescriptorDB extends _core_speedy_namespace__WEBPACK_IMPORTED_MODULE_1__.SpeedyNamespace
  13636. {
  13637. /**
  13638. * Create a database of binary descriptors
  13639. * @param {SpeedyTexture} texture output texture
  13640. * @param {Uint8Array[]} descriptors binary descriptors
  13641. * @param {number} descriptorSize in bytes, a multiple of 4
  13642. * @returns {SpeedyTexture} texture
  13643. */
  13644. static create(texture, descriptors, descriptorSize)
  13645. {
  13646. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(descriptorSize % DESCRIPTORDB_BYTESPERPIXEL == 0, `Invalid descriptorSize: ${descriptorSize}`);
  13647. const numberOfDescriptors = descriptors.length;
  13648. const pixelsPerDescriptor = descriptorSize / DESCRIPTORDB_BYTESPERPIXEL;
  13649. // find an appropriate texture size
  13650. const n = Math.log2(pixelsPerDescriptor * Math.max(numberOfDescriptors, 1)) / 2;
  13651. const log2stride = Math.min(DESCRIPTORDB_MAXLOG2STRIDE, Math.ceil(n));
  13652. // setup texture parameters
  13653. const stride = 1 << log2stride;
  13654. const width = stride, height = stride; // we use powers-of-two
  13655. // are we within storage capacity?
  13656. const capacity = (width * height) / pixelsPerDescriptor;
  13657. if(numberOfDescriptors > capacity)
  13658. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.NotSupportedError(`The capacity of the descriptorDB (${capacity} for ${descriptorSize * 8}-bit descriptors) has been exceeded`);
  13659. // create texture data
  13660. const data = new Uint8Array(width * height * DESCRIPTORDB_BYTESPERPIXEL);
  13661. for(let i = 0; i < numberOfDescriptors; i++) {
  13662. const byteOffset = i * descriptorSize;
  13663. const descriptor = descriptors[i];
  13664. // validate input
  13665. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(descriptor.byteLength === descriptorSize);
  13666. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(byteOffset + descriptorSize <= data.byteLength);
  13667. // write data
  13668. data.set(descriptor, byteOffset);
  13669. }
  13670. // log data for further study
  13671. const MEGABYTE = 1048576;
  13672. const totalSize = numberOfDescriptors * descriptorSize;
  13673. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.log(
  13674. `Creating a ${width}x${height} database of ${numberOfDescriptors} ` +
  13675. `${descriptorSize * 8}-bit descriptors ` +
  13676. `(total size: ${(totalSize / MEGABYTE).toFixed(2)} MB)`
  13677. );
  13678. // upload to the texture
  13679. texture.resize(width, height);
  13680. texture.upload(data);
  13681. return texture;
  13682. }
  13683. }
  13684. /***/ }),
  13685. /***/ "./src/gpu/speedy-gl.js":
  13686. /*!******************************!*\
  13687. !*** ./src/gpu/speedy-gl.js ***!
  13688. \******************************/
  13689. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_613936__) => {
  13690. "use strict";
  13691. __nested_webpack_require_613936__.r(__webpack_exports__);
  13692. /* harmony export */ __nested_webpack_require_613936__.d(__webpack_exports__, {
  13693. /* harmony export */ "SpeedyGL": () => (/* binding */ SpeedyGL)
  13694. /* harmony export */ });
  13695. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_613936__(/*! ../utils/utils */ "./src/utils/utils.js");
  13696. /* harmony import */ var _utils_observable__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_613936__(/*! ../utils/observable */ "./src/utils/observable.js");
  13697. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_613936__(/*! ../core/speedy-promise */ "./src/core/speedy-promise.js");
  13698. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_613936__(/*! ../utils/errors */ "./src/utils/errors.js");
  13699. /*
  13700. * speedy-vision.js
  13701. * GPU-accelerated Computer Vision for JavaScript
  13702. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  13703. *
  13704. * Licensed under the Apache License, Version 2.0 (the "License");
  13705. * you may not use this file except in compliance with the License.
  13706. * You may obtain a copy of the License at
  13707. *
  13708. * http://www.apache.org/licenses/LICENSE-2.0
  13709. *
  13710. * Unless required by applicable law or agreed to in writing, software
  13711. * distributed under the License is distributed on an "AS IS" BASIS,
  13712. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13713. * See the License for the specific language governing permissions and
  13714. * limitations under the License.
  13715. *
  13716. * speedy-gl.js
  13717. * A wrapper around the WebGL Rendering Context
  13718. */
  13719. /** @typedef {'default' | 'low-power' | 'high-performance'} PowerPreference */
  13720. // Constants
  13721. const SINGLETON_KEY = Symbol();
  13722. const DEFAULT_POWER_PREFERENCE = 'default';
  13723. //
  13724. // We use a small canvas to improve the performance
  13725. // of createImageBitmap() on Firefox.
  13726. //
  13727. // A large canvas (2048x2048) causes a FPS drop, even
  13728. // if we only extract a small region of it (this is
  13729. // unlike Chrome, which is fast).
  13730. //
  13731. // Note: we automatically increase the size of the
  13732. // canvas (as needed) when rendering to it.
  13733. //
  13734. const CANVAS_WIDTH = 16, CANVAS_HEIGHT = 16;
  13735. /** @type {SpeedyGL} Singleton */
  13736. let instance = null;
  13737. /** @type {PowerPreference} power preference */
  13738. let powerPreference = DEFAULT_POWER_PREFERENCE;
  13739. /**
  13740. * A wrapper around the WebGL Rendering Context
  13741. */
  13742. class SpeedyGL extends _utils_observable__WEBPACK_IMPORTED_MODULE_1__.Observable
  13743. {
  13744. /**
  13745. * Constructor
  13746. * @param {Symbol} key
  13747. * @private
  13748. */
  13749. constructor(key)
  13750. {
  13751. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(key === SINGLETON_KEY);
  13752. super();
  13753. /** @type {boolean} internal flag */
  13754. this._reinitializeOnContextLoss = true;
  13755. /** @type {HTMLCanvasElement} canvas */
  13756. this._canvas = this._createCanvas(this._reinitialize.bind(this));
  13757. /** @type {WebGL2RenderingContext} WebGL rendering context */
  13758. this._gl = null;
  13759. // create WebGL2 rendering context
  13760. this._gl = this._createContext(this._canvas);
  13761. }
  13762. /**
  13763. * Get Singleton
  13764. * @returns {SpeedyGL}
  13765. */
  13766. static get instance()
  13767. {
  13768. return instance || (instance = new SpeedyGL(SINGLETON_KEY));
  13769. }
  13770. /**
  13771. * The WebGL Rendering Context
  13772. * Be careful not to cache this, as the WebGL Rendering Context may be lost!
  13773. * @returns {WebGL2RenderingContext}
  13774. */
  13775. get gl()
  13776. {
  13777. return this._gl;
  13778. }
  13779. /**
  13780. * The canvas
  13781. * @returns {HTMLCanvasElement}
  13782. */
  13783. get canvas()
  13784. {
  13785. return this._canvas;
  13786. }
  13787. /**
  13788. * Create a WebGL-capable canvas
  13789. * @param {Function} reinitialize to be called if we get a WebGL context loss event
  13790. * @returns {HTMLCanvasElement}
  13791. */
  13792. _createCanvas(reinitialize)
  13793. {
  13794. const canvas = _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.createCanvas(CANVAS_WIDTH, CANVAS_HEIGHT);
  13795. canvas.addEventListener('webglcontextlost', ev => {
  13796. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.warning(`Lost WebGL2 context`);
  13797. setTimeout(reinitialize, 0);
  13798. ev.preventDefault();
  13799. }, false);
  13800. /*canvas.addEventListener('webglcontextrestored', ev => {
  13801. Utils.warning(`Restored WebGL2 context`);
  13802. ev.preventDefault();
  13803. }, false);*/
  13804. return canvas;
  13805. }
  13806. /**
  13807. * Create a WebGL2 Rendering Context
  13808. * @param {HTMLCanvasElement} canvas
  13809. * @returns {WebGL2RenderingContext}
  13810. */
  13811. _createContext(canvas)
  13812. {
  13813. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.log(`Creating a ${powerPreference} WebGL2 rendering context...`);
  13814. // does the browser support WebGL2?
  13815. if(typeof WebGL2RenderingContext === 'undefined')
  13816. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.NotSupportedError(`This application requires WebGL2. Please use a different browser.`);
  13817. const gl = canvas.getContext('webgl2', {
  13818. premultipliedAlpha: false,
  13819. preserveDrawingBuffer: false,
  13820. powerPreference: powerPreference,
  13821. alpha: true, // see https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#avoid_alphafalse_which_can_be_expensive
  13822. antialias: false,
  13823. depth: false,
  13824. stencil: false,
  13825. desynchronized: true,
  13826. });
  13827. if(!gl)
  13828. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.NotSupportedError(`Can't create a WebGL2 Rendering Context. Try a different browser!`);
  13829. return gl;
  13830. }
  13831. /**
  13832. * Reinitialize WebGL
  13833. */
  13834. _reinitialize()
  13835. {
  13836. // disable reinitialization?
  13837. if(!this._reinitializeOnContextLoss)
  13838. return;
  13839. // warning
  13840. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.warning(`Reinitializing WebGL2...`);
  13841. // create new canvas
  13842. this._canvas.remove();
  13843. this._canvas = this._createCanvas(this._reinitialize.bind(this));
  13844. // create new context
  13845. this._gl = this._createContext(this._canvas);
  13846. // notify observers: we have a new context!
  13847. // we need to recreate all textures...
  13848. this._notify();
  13849. }
  13850. /**
  13851. * Lose the WebGL context. This is used to manually
  13852. * free resources, and also for purposes of testing
  13853. * @returns {WEBGL_lose_context}
  13854. */
  13855. loseContext()
  13856. {
  13857. const gl = this._gl;
  13858. // nothing to do?
  13859. if(gl.isContextLost())
  13860. return;
  13861. // find the appropriate extension
  13862. const ext = gl.getExtension('WEBGL_lose_context');
  13863. if(!ext)
  13864. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.NotSupportedError('WEBGL_lose_context extension is unavailable');
  13865. // disable reinitialization
  13866. this._reinitializeOnContextLoss = false;
  13867. // lose context
  13868. ext.loseContext();
  13869. // done!
  13870. return ext;
  13871. }
  13872. /**
  13873. * Lose & restore the WebGL context
  13874. * @param {number} [secondsToRestore]
  13875. * @return {SpeedyPromise<WEBGL_lose_context>} resolves as soon as the context is restored
  13876. */
  13877. loseAndRestoreContext(secondsToRestore = 1)
  13878. {
  13879. const ms = Math.max(secondsToRestore, 0) * 1000;
  13880. const ext = this.loseContext();
  13881. return new _core_speedy_promise__WEBPACK_IMPORTED_MODULE_2__.SpeedyPromise(resolve => {
  13882. setTimeout(() => {
  13883. //ext.restoreContext();
  13884. this._reinitializeOnContextLoss = true;
  13885. this._reinitialize();
  13886. setTimeout(() => resolve(ext), 0); // next frame
  13887. }, ms);
  13888. });
  13889. }
  13890. /**
  13891. * Power preference for the WebGL context
  13892. * @returns {PowerPreference}
  13893. */
  13894. static get powerPreference()
  13895. {
  13896. return powerPreference;
  13897. }
  13898. /**
  13899. * Power preference for the WebGL context
  13900. * @param {PowerPreference} value
  13901. */
  13902. static set powerPreference(value)
  13903. {
  13904. // validate
  13905. if(!(value === 'default' || value === 'low-power' || value === 'high-performance'))
  13906. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.IllegalArgumentError(`Invalid powerPreference: "${value}"`);
  13907. // the power preference should be set before we create the WebGL context
  13908. if(instance == null || powerPreference !== value) {
  13909. powerPreference = value;
  13910. // recreate the context if it already exists. Experimental.
  13911. if(instance != null)
  13912. instance.loseAndRestoreContext();
  13913. }
  13914. }
  13915. }
  13916. /***/ }),
  13917. /***/ "./src/gpu/speedy-gpu.js":
  13918. /*!*******************************!*\
  13919. !*** ./src/gpu/speedy-gpu.js ***!
  13920. \*******************************/
  13921. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_622719__) => {
  13922. "use strict";
  13923. __nested_webpack_require_622719__.r(__webpack_exports__);
  13924. /* harmony export */ __nested_webpack_require_622719__.d(__webpack_exports__, {
  13925. /* harmony export */ "SpeedyGPU": () => (/* binding */ SpeedyGPU)
  13926. /* harmony export */ });
  13927. /* harmony import */ var _speedy_gl__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_622719__(/*! ./speedy-gl */ "./src/gpu/speedy-gl.js");
  13928. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_622719__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  13929. /* harmony import */ var _speedy_program_center__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_622719__(/*! ./speedy-program-center */ "./src/gpu/speedy-program-center.js");
  13930. /* harmony import */ var _speedy_texture_pool__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_622719__(/*! ./speedy-texture-pool */ "./src/gpu/speedy-texture-pool.js");
  13931. /* harmony import */ var _speedy_texture_uploader__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_622719__(/*! ./speedy-texture-uploader */ "./src/gpu/speedy-texture-uploader.js");
  13932. /* harmony import */ var _core_speedy_media_source__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_622719__(/*! ../core/speedy-media-source */ "./src/core/speedy-media-source.js");
  13933. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_622719__(/*! ../core/speedy-promise */ "./src/core/speedy-promise.js");
  13934. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_622719__(/*! ../utils/utils */ "./src/utils/utils.js");
  13935. /* harmony import */ var _utils_observable__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_622719__(/*! ../utils/observable */ "./src/utils/observable.js");
  13936. /*
  13937. * speedy-vision.js
  13938. * GPU-accelerated Computer Vision for JavaScript
  13939. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  13940. *
  13941. * Licensed under the Apache License, Version 2.0 (the "License");
  13942. * you may not use this file except in compliance with the License.
  13943. * You may obtain a copy of the License at
  13944. *
  13945. * http://www.apache.org/licenses/LICENSE-2.0
  13946. *
  13947. * Unless required by applicable law or agreed to in writing, software
  13948. * distributed under the License is distributed on an "AS IS" BASIS,
  13949. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13950. * See the License for the specific language governing permissions and
  13951. * limitations under the License.
  13952. *
  13953. * speedy-gpu.js
  13954. * GPU-accelerated routines for Computer Vision
  13955. */
  13956. /**
  13957. * GPU-accelerated routines for Computer Vision
  13958. */
  13959. class SpeedyGPU extends _utils_observable__WEBPACK_IMPORTED_MODULE_8__.Observable
  13960. {
  13961. /**
  13962. * Constructor
  13963. */
  13964. constructor()
  13965. {
  13966. super();
  13967. /** @type {SpeedyGL} cached reference */
  13968. this._speedyGL = _speedy_gl__WEBPACK_IMPORTED_MODULE_0__.SpeedyGL.instance;
  13969. /** @type {SpeedyProgramCenter} GPU-based programs */
  13970. this._programs = new _speedy_program_center__WEBPACK_IMPORTED_MODULE_2__.SpeedyProgramCenter(this);
  13971. /** @type {SpeedyTexturePool} texture pool */
  13972. this._texturePool = new _speedy_texture_pool__WEBPACK_IMPORTED_MODULE_3__.SpeedyTexturePool(this);
  13973. /** @type {SpeedyTextureUploader} texture uploader */
  13974. this._textureUploader = new _speedy_texture_uploader__WEBPACK_IMPORTED_MODULE_4__.SpeedyTextureUploader(this);
  13975. // recreate the state if necessary
  13976. this._speedyGL.subscribe(this._reset, this);
  13977. }
  13978. /**
  13979. * Access point to all GPU programs
  13980. * @returns {SpeedyProgramCenter}
  13981. */
  13982. get programs()
  13983. {
  13984. return this._programs;
  13985. }
  13986. /**
  13987. * The WebGL Rendering Context
  13988. * Be careful not to cache this, as the WebGL Rendering Context may be lost!
  13989. * @returns {WebGL2RenderingContext}
  13990. */
  13991. get gl()
  13992. {
  13993. return this._speedyGL.gl;
  13994. }
  13995. /**
  13996. * Internal canvas
  13997. * @returns {HTMLCanvasElement}
  13998. */
  13999. get canvas()
  14000. {
  14001. return this._speedyGL.canvas;
  14002. }
  14003. /**
  14004. * Texture pool
  14005. * @returns {SpeedyTexturePool}
  14006. */
  14007. get texturePool()
  14008. {
  14009. return this._texturePool;
  14010. }
  14011. /**
  14012. * Renders a texture to the canvas
  14013. * @param {SpeedyTexture} texture
  14014. * @returns {HTMLCanvasElement} returned for convenience
  14015. */
  14016. renderToCanvas(texture)
  14017. {
  14018. const width = texture.width;
  14019. const height = texture.height;
  14020. const canvas = this.canvas;
  14021. // do we need to resize the canvas?
  14022. if(width > canvas.width || height > canvas.height) {
  14023. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.warning(`Resizing the canvas to ${width} x ${height}`);
  14024. canvas.width = width;
  14025. canvas.height = height;
  14026. }
  14027. // render
  14028. this.programs.utils.renderToCanvas.outputs(width, height, null);
  14029. this.programs.utils.renderToCanvas(texture);
  14030. // done!
  14031. return canvas;
  14032. }
  14033. /**
  14034. * Upload an image to the GPU
  14035. * @param {SpeedyMediaSource} source
  14036. * @param {SpeedyTexture} outputTexture
  14037. * @returns {SpeedyTexture} outputTexture
  14038. */
  14039. upload(source, outputTexture)
  14040. {
  14041. return this._textureUploader.upload(source, outputTexture);
  14042. }
  14043. /**
  14044. * Releases resources
  14045. * @returns {null}
  14046. */
  14047. release()
  14048. {
  14049. _utils_utils__WEBPACK_IMPORTED_MODULE_7__.Utils.assert(!this.isReleased());
  14050. // release internal components
  14051. this._programs = this._programs.release();
  14052. this._texturePool = this._texturePool.release();
  14053. this._textureUploader = this._textureUploader.release();
  14054. // unsubscribe
  14055. this._speedyGL.unsubscribe(this._reset);
  14056. return null;
  14057. }
  14058. /**
  14059. * Has this SpeedyGPU been released?
  14060. * @returns {boolean}
  14061. */
  14062. isReleased()
  14063. {
  14064. return this._programs == null;
  14065. }
  14066. /**
  14067. * Lose & restore the WebGL context (useful for testing purposes)
  14068. * @return {SpeedyPromise<void>} resolves as soon as the context is restored
  14069. */
  14070. loseAndRestoreWebGLContext()
  14071. {
  14072. return this._speedyGL.loseAndRestoreContext().then(() => void(0));
  14073. }
  14074. /**
  14075. * Reset the internal state
  14076. * (called on context reset)
  14077. */
  14078. _reset()
  14079. {
  14080. if(this.isReleased())
  14081. return;
  14082. this._programs = new _speedy_program_center__WEBPACK_IMPORTED_MODULE_2__.SpeedyProgramCenter(this);
  14083. this._texturePool = new _speedy_texture_pool__WEBPACK_IMPORTED_MODULE_3__.SpeedyTexturePool(this);
  14084. this._textureUploader = new _speedy_texture_uploader__WEBPACK_IMPORTED_MODULE_4__.SpeedyTextureUploader(this);
  14085. this._notify();
  14086. }
  14087. }
  14088. /***/ }),
  14089. /***/ "./src/gpu/speedy-lsh.js":
  14090. /*!*******************************!*\
  14091. !*** ./src/gpu/speedy-lsh.js ***!
  14092. \*******************************/
  14093. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_629539__) => {
  14094. "use strict";
  14095. __nested_webpack_require_629539__.r(__webpack_exports__);
  14096. /* harmony export */ __nested_webpack_require_629539__.d(__webpack_exports__, {
  14097. /* harmony export */ "LSH_DEFAULT_NUMBER_OF_TABLES": () => (/* binding */ LSH_DEFAULT_NUMBER_OF_TABLES),
  14098. /* harmony export */ "LSH_DEFAULT_HASH_SIZE": () => (/* binding */ LSH_DEFAULT_HASH_SIZE),
  14099. /* harmony export */ "LSH_ACCEPTABLE_NUMBER_OF_TABLES": () => (/* binding */ LSH_ACCEPTABLE_NUMBER_OF_TABLES),
  14100. /* harmony export */ "LSH_ACCEPTABLE_HASH_SIZES": () => (/* binding */ LSH_ACCEPTABLE_HASH_SIZES),
  14101. /* harmony export */ "LSH_ACCEPTABLE_DESCRIPTOR_SIZES": () => (/* binding */ LSH_ACCEPTABLE_DESCRIPTOR_SIZES),
  14102. /* harmony export */ "LSH_SEQUENCE_MAXLEN": () => (/* binding */ LSH_SEQUENCE_MAXLEN),
  14103. /* harmony export */ "LSH_SEQUENCE_COUNT": () => (/* binding */ LSH_SEQUENCE_COUNT),
  14104. /* harmony export */ "SpeedyLSH": () => (/* binding */ SpeedyLSH)
  14105. /* harmony export */ });
  14106. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_629539__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  14107. /* harmony import */ var _speedy_descriptordb__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_629539__(/*! ./speedy-descriptordb */ "./src/gpu/speedy-descriptordb.js");
  14108. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_629539__(/*! ../utils/utils */ "./src/utils/utils.js");
  14109. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_629539__(/*! ../utils/globals */ "./src/utils/globals.js");
  14110. /*
  14111. * speedy-vision.js
  14112. * GPU-accelerated Computer Vision for JavaScript
  14113. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  14114. *
  14115. * Licensed under the Apache License, Version 2.0 (the "License");
  14116. * you may not use this file except in compliance with the License.
  14117. * You may obtain a copy of the License at
  14118. *
  14119. * http://www.apache.org/licenses/LICENSE-2.0
  14120. *
  14121. * Unless required by applicable law or agreed to in writing, software
  14122. * distributed under the License is distributed on an "AS IS" BASIS,
  14123. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14124. * See the License for the specific language governing permissions and
  14125. * limitations under the License.
  14126. *
  14127. * speedy-lsh.js
  14128. * GPU-based LSH tables for fast matching of binary descriptors
  14129. */
  14130. /*
  14131. * ALE'S GPU-BASED LSH FOR APPROXIMATE KNN MATCHING
  14132. * ------------------------------------------------
  14133. *
  14134. * Here is my variant of Locality Sensitive Hashing for GPU-based KNN matching!
  14135. * Indices of keypoint descriptors are stored in several tables, each with many
  14136. * buckets of fixed capacity. In a nutshell, I create a data structure of fixed
  14137. * size to match the keypoints.
  14138. *
  14139. * Buckets in video memory may get full. Wouldn't it be cool if we could use a
  14140. * probabilistic approach to let us work within their storage capacity?
  14141. *
  14142. * Let there be n buckets in a table, each with storage capacity c (holding
  14143. * up to c elements). Buckets are numbered from 0 to n-1.
  14144. *
  14145. * We pick uniformly a random bucket to store a new element in the table. Let
  14146. * X be the chosen bucket. The probability that we'll store the new element in
  14147. * any particular bucket k is:
  14148. *
  14149. * P(X = k) = 1/n (k = 0, 1, 2, ... n-1)
  14150. *
  14151. * On average, each new element stored in the table inserts 1/n of an element
  14152. * in each bucket. If we add m new elements to the table, each bucket receives
  14153. * m/n elements, on average(*).
  14154. *
  14155. * (*) for all k, define the Ik random variable as 1 if X = k and 0 otherwise.
  14156. * It follows that the expected value of Ik, E(Ik), is 1/n for all k. In
  14157. * addition, the expected value of (m Ik) is m * E(ik) = m/n.
  14158. *
  14159. * Now let Yi be the number of elements inserted in bucket i in m additions to
  14160. * the table. We model Yi as Poisson(m/n), since on average, m additions to
  14161. * the table result in m/n new elements being inserted in bucket i. Buckets
  14162. * are picked independently. Hence, for all i, the probability that we insert
  14163. * q elements in bucket i in m additions to the table is:
  14164. *
  14165. * P(Yi = q) = (m/n)^q * exp(-m/n) / q! (q = 0, 1, 2...)
  14166. *
  14167. * Given that each bucket has storage capacity c, we require Yi <= c with a
  14168. * high probability p (say, p = 0.99). This means that, in m additions, we
  14169. * don't want to exceed the capacity c with high probability. So, let us find
  14170. * a (large) value of m such that:
  14171. *
  14172. * P(Yi <= c) >= p
  14173. *
  14174. * Sounds good! We can find the largest matching m using binary search.
  14175. *
  14176. * I don't think we need to enforce a high probability that ALL buckets stay
  14177. * within their capacity - n is large, we need to use the available space, and
  14178. * we have multiple tables anyway.
  14179. *
  14180. * In practice, the assumption that buckets are picked uniformly doesn't hold:
  14181. * keypoints that are nearby tend to have similar descriptors and buckets are
  14182. * picked according to those descriptors. Still, this model works well enough
  14183. * in practice and it is simple! That's what I like about it!
  14184. *
  14185. * ... now, how I actually do the matching is the theme of the next episode!
  14186. */
  14187. /** @type {number} Default number of tables in a LSH data structure */
  14188. const LSH_DEFAULT_NUMBER_OF_TABLES = 8;
  14189. /** @type {number} Default number of bits of a hash */
  14190. const LSH_DEFAULT_HASH_SIZE = 15;
  14191. /** @type {number[]} Acceptable number of tables for a LSH data structure */
  14192. const LSH_ACCEPTABLE_NUMBER_OF_TABLES = [4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32];
  14193. /** @type {number[]} Acceptable values for hashSize, in bits */
  14194. const LSH_ACCEPTABLE_HASH_SIZES = [10,11,12,13,14,15,16,17,18,19,20];
  14195. /** @type {number[]} Acceptable sizes for keypoint descriptors, in bytes */
  14196. const LSH_ACCEPTABLE_DESCRIPTOR_SIZES = [32,64];
  14197. /**
  14198. * @typedef {Object} LSHProfile LSH profile
  14199. * @property {string} name name of the profile
  14200. * @property {number} capacity maximum number of keypoints that can be stored in such a table
  14201. * @property {number} hashSize number of bits in a keypoint descriptor hash (at most 16)
  14202. * @property {number} tableCount number of tables, preferably a power of 2 (at most 16)
  14203. * @property {number} bucketCapacity maximum number of entries of a bucket of a table
  14204. */
  14205. /** @type {function(number,number,number):LSHProfile[]|null} generate LSH profiles sorted by increasing capacity */
  14206. const generateLSHProfiles = (t,h,p) => !LSH_ACCEPTABLE_HASH_SIZES.includes(h) || !LSH_ACCEPTABLE_NUMBER_OF_TABLES.includes(t) ? null : [
  14207. {
  14208. name: 'x-small',
  14209. bucketCapacity: 1,
  14210. tableCount: t,
  14211. hashSize: h,
  14212. capacity: findTableCapacity(h, 1, p),
  14213. },
  14214. {
  14215. name: 'small',
  14216. bucketCapacity: 2,
  14217. tableCount: t,
  14218. hashSize: h,
  14219. capacity: findTableCapacity(h, 2, p),
  14220. },
  14221. {
  14222. name: 'small-plus',
  14223. bucketCapacity: 3,
  14224. tableCount: t,
  14225. hashSize: h,
  14226. capacity: findTableCapacity(h, 3, p),
  14227. },
  14228. {
  14229. name: 'medium',
  14230. bucketCapacity: 4,
  14231. tableCount: t,
  14232. hashSize: h,
  14233. capacity: findTableCapacity(h, 4, p),
  14234. },
  14235. {
  14236. name: 'medium-plus',
  14237. bucketCapacity: 5,
  14238. tableCount: t,
  14239. hashSize: h,
  14240. capacity: findTableCapacity(h, 5, p),
  14241. },
  14242. {
  14243. name: 'large',
  14244. bucketCapacity: 6,
  14245. tableCount: t,
  14246. hashSize: h,
  14247. capacity: findTableCapacity(h, 6, p),
  14248. },
  14249. {
  14250. name: 'x-large',
  14251. bucketCapacity: 8,
  14252. tableCount: t,
  14253. hashSize: h,
  14254. capacity: findTableCapacity(h, 8, p),
  14255. },
  14256. ];
  14257. //
  14258. // LSH hash sequences: random bits in increasing order
  14259. // We generate a few sequences (one for each table) supporting up to 16 hash bits
  14260. // We pad each sequence with invalid values at the end - we want to pick any bit with equal probability
  14261. //
  14262. /** @typedef {Uint32Array} BitSequences flattened array of LSH_SEQUENCE_COUNT sequences of LSH_SEQUENCE_MAXLEN elements each - each entry represents a bit index */
  14263. /** @typedef {Object<number,BitSequences>} BitSequencesIndexedByDescriptorSize */
  14264. /** @typedef {Object<number,BitSequencesIndexedByDescriptorSize>} LSHSequences */
  14265. /** @type {number} maximum number of elements of a sequence */
  14266. const LSH_SEQUENCE_MAXLEN = Math.max(...LSH_ACCEPTABLE_HASH_SIZES);
  14267. /** @type {number} number of sequences in a BitSequences object */
  14268. const LSH_SEQUENCE_COUNT = Math.max(...LSH_ACCEPTABLE_NUMBER_OF_TABLES);
  14269. /** @type {function(BitSequences): BitSequences} Sort subsequences of random bits in ascending order */
  14270. const partitionedSort = seq => (_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(LSH_SEQUENCE_COUNT)
  14271. .forEach(i => seq.subarray(i * LSH_SEQUENCE_MAXLEN, (i+1) * LSH_SEQUENCE_MAXLEN).sort()),
  14272. seq);
  14273. /** @type {function(number, BitSequences): BitSequences} Set the last p entries of the input subsequences to an invalid value */
  14274. const padSequences = (p, seq) => (_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(LSH_SEQUENCE_COUNT)
  14275. .forEach(i => seq.subarray((i+1) * LSH_SEQUENCE_MAXLEN - p, (i+1) * LSH_SEQUENCE_MAXLEN).fill(0xBADCAFE)),
  14276. seq);
  14277. /** @type {LSHSequences} the bits we pick to form the hashes, laid out in ascending order and indexed by descriptorSize and hashSize */
  14278. const LSH_SEQUENCES = (f => LSH_ACCEPTABLE_HASH_SIZES.reduce((p,o) => ((p[o]=f(o)), p), {}))(h => ({
  14279. // for 256-bit descriptors
  14280. 32: partitionedSort(padSequences(LSH_SEQUENCE_MAXLEN - h, new Uint32Array([
  14281. ...(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(256))),
  14282. ...(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(256))),
  14283. ...(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(256))),
  14284. ].slice(0, LSH_SEQUENCE_COUNT * LSH_SEQUENCE_MAXLEN)))),
  14285. // for 512-bit descriptors
  14286. 64: partitionedSort(padSequences(LSH_SEQUENCE_MAXLEN - h, new Uint32Array([
  14287. ...(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(512))),
  14288. ...(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(512))),
  14289. ].slice(0, LSH_SEQUENCE_COUNT * LSH_SEQUENCE_MAXLEN)))),
  14290. }));
  14291. //
  14292. // Misc
  14293. //
  14294. /** @type {number} we use RGBA8 textures (32 bits per pixel) as storage */
  14295. const LSH_BYTESPERPIXEL = 4;
  14296. /** @type {function(number): number} next power of 2 */
  14297. const nextPot = x => x > 1 ? 1 << Math.ceil(Math.log2(x)) : 1;
  14298. /**
  14299. * GPU-based LSH tables for fast matching of binary descriptors
  14300. */
  14301. class SpeedyLSH
  14302. {
  14303. /**
  14304. * Constructor
  14305. * @param {SpeedyTexture} lshTables texture to be used as the set of LSH tables
  14306. * @param {SpeedyTexture} descriptorDB texture to be used as the descriptor database
  14307. * @param {Uint8Array[]} descriptors the binary descriptors you'll store (make sure you don't repeat them, otherwise they will just waste space)
  14308. * @param {number} [tableCount] number of LSH tables, preferably a power of two
  14309. * @param {number} [hashSize] number of bits of a hash of a descriptor
  14310. * @param {number} [probability] probability of no discard events happening in the theoretical model
  14311. */
  14312. constructor(lshTables, descriptorDB, descriptors, tableCount = LSH_DEFAULT_NUMBER_OF_TABLES, hashSize = LSH_DEFAULT_HASH_SIZE, probability = 0.95)
  14313. {
  14314. const descriptorCount = descriptors.length;
  14315. const descriptorSize = descriptorCount > 0 ? descriptors[0].byteLength : 0;
  14316. const lshProfiles = generateLSHProfiles(tableCount, hashSize, probability);
  14317. // validate input
  14318. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(descriptorCount > 0, `Can't build LSH tables without descriptors!`);
  14319. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(LSH_ACCEPTABLE_DESCRIPTOR_SIZES.includes(descriptorSize), `Can't build LSH tables: unacceptable descriptor size of ${descriptorSize} bytes`);
  14320. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(descriptors.findIndex(d => d.byteLength !== descriptorSize) < 0, `Can't build LSH tables: incorrectly sized descriptors. Expected ${descriptorSize} bytes for each`);
  14321. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(descriptorCount < _utils_globals__WEBPACK_IMPORTED_MODULE_3__.MATCH_MAX_INDEX, `Can't build LSH tables: too many descriptors (${descriptors.length})`);
  14322. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(lshProfiles != null, `Can't build LSH tables: unacceptable number of tables (${tableCount}) x hash size (${hashSize})`);
  14323. /** @type {LSHProfile} LSH profile */
  14324. this._profile = lshProfiles.find(profile => descriptorCount <= profile.capacity) || lshProfiles[lshProfiles.length - 1];
  14325. /** @type {number} descriptor size, in bytes */
  14326. this._descriptorSize = descriptorSize;
  14327. /** @type {number} number of descriptors */
  14328. this._descriptorCount = descriptorCount;
  14329. /** @type {BitSequences} bit sequences */
  14330. this._sequences = this._pickSequences(this._descriptorSize);
  14331. /** @type {SpeedyTexture} LSH tables storing indices of descriptors */
  14332. this._tables = this._createStaticTables(lshTables, this._sequences, descriptors, descriptorSize);
  14333. /** @type {SpeedyTexture} a storage of descriptors */
  14334. this._descriptorDB = _speedy_descriptordb__WEBPACK_IMPORTED_MODULE_1__.SpeedyDescriptorDB.create(descriptorDB, descriptors, descriptorSize);
  14335. }
  14336. /**
  14337. * Descriptor size, in bytes
  14338. * @returns {number}
  14339. */
  14340. get descriptorSize()
  14341. {
  14342. return this._descriptorSize;
  14343. }
  14344. /**
  14345. * Number of descriptors stored in this LSH data structure
  14346. * @returns {number}
  14347. */
  14348. get descriptorCount()
  14349. {
  14350. return this._descriptorCount;
  14351. }
  14352. /**
  14353. * LSH bit sequences
  14354. * @returns {BitSequences}
  14355. */
  14356. get sequences()
  14357. {
  14358. return this._sequences;
  14359. }
  14360. /**
  14361. * Number of bits that make a hash
  14362. * @returns {number}
  14363. */
  14364. get hashSize()
  14365. {
  14366. return this._profile.hashSize;
  14367. }
  14368. /**
  14369. * Maximum number of descriptors that can be stored in a bucket of a table
  14370. * @returns {number}
  14371. */
  14372. get bucketCapacity()
  14373. {
  14374. return this._profile.bucketCapacity;
  14375. }
  14376. /**
  14377. * How many buckets per table do we have?
  14378. * @returns {number}
  14379. */
  14380. get bucketsPerTable()
  14381. {
  14382. return 1 << this._profile.hashSize;
  14383. }
  14384. /**
  14385. * Number of LSH tables
  14386. * @returns {number}
  14387. */
  14388. get tableCount()
  14389. {
  14390. return this._profile.tableCount;
  14391. }
  14392. /**
  14393. * Size of one LSH table, in bytes
  14394. * @returns {number}
  14395. */
  14396. get tableSize()
  14397. {
  14398. return this.bucketsPerTable * this.bucketCapacity * LSH_BYTESPERPIXEL;
  14399. }
  14400. /**
  14401. * Size of all LSH tables combined, in bytes
  14402. * @returns {number}
  14403. */
  14404. get totalSize()
  14405. {
  14406. // actually, the total memory in VRAM may be a bit larger than
  14407. // this value, depending on the actual size of the texture
  14408. return this.tableCount * this.tableSize;
  14409. }
  14410. /**
  14411. * LSH tables texture
  14412. * @returns {SpeedyDrawableTexture}
  14413. */
  14414. get tables()
  14415. {
  14416. return this._tables;
  14417. }
  14418. /**
  14419. * A collection of descriptors
  14420. * @returns {SpeedyDrawableTexture}
  14421. */
  14422. get descriptorDB()
  14423. {
  14424. return this._descriptorDB;
  14425. }
  14426. /**
  14427. * Pick the appropriate LSH sequences for a particular descriptor size
  14428. * @param {number} descriptorSize in bytes
  14429. * @returns {BitSequences}
  14430. */
  14431. _pickSequences(descriptorSize)
  14432. {
  14433. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(Object.prototype.hasOwnProperty.call(LSH_SEQUENCES, this.hashSize));
  14434. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(Object.prototype.hasOwnProperty.call(LSH_SEQUENCES[this.hashSize], descriptorSize));
  14435. return LSH_SEQUENCES[this.hashSize][descriptorSize];
  14436. }
  14437. /**
  14438. * Create LSH tables
  14439. * @param {SpeedyTexture} texture output texture
  14440. * @param {BitSequences} sequences bit sequences
  14441. * @param {Uint8Array[]} descriptors non-empty array of binary descriptors, ALL HAVING THE SAME SIZE
  14442. * @param {number} descriptorSize in bytes
  14443. * @returns {SpeedyTexture} texture
  14444. */
  14445. _createStaticTables(texture, sequences, descriptors, descriptorSize)
  14446. {
  14447. const END_OF_LIST = 0xFFFFFFFF;
  14448. const profileName = this._profile.name;
  14449. const tableCapacity = this._profile.capacity;
  14450. const tableCount = this.tableCount;
  14451. const bucketsPerTable = this.bucketsPerTable;
  14452. const bucketSize = this.bucketCapacity * LSH_BYTESPERPIXEL;
  14453. const hashSize = this.hashSize;
  14454. const numberOfPixels = this.tableCount * this.bucketsPerTable * this.bucketCapacity; // watch for overflow?
  14455. const textureWidth = Math.min(nextPot(Math.sqrt(numberOfPixels)), 4096); // 4096 is compatible with most devices according to MDN
  14456. const textureHeight = Math.ceil(numberOfPixels / textureWidth);
  14457. const numberOfDescriptors = descriptors.length;
  14458. // validate input
  14459. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(hashSize <= LSH_SEQUENCE_MAXLEN);
  14460. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(tableCount <= LSH_SEQUENCE_COUNT);
  14461. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(numberOfPixels <= textureWidth * textureHeight);
  14462. // log
  14463. const MEGABYTE = 1048576;
  14464. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.log(
  14465. `Building ${tableCount} ${profileName} LSH tables with ${numberOfDescriptors} ` +
  14466. `${descriptorSize * 8}-bit descriptors each and hashSize = ${hashSize} bits ` +
  14467. `(${textureWidth}x${textureHeight}, with ${(this.tableSize / MEGABYTE).toFixed(2)} ` +
  14468. `MB per table and total size = ${(this.totalSize / MEGABYTE).toFixed(2)} MB), `
  14469. );
  14470. // warn the user if there are too many descriptors
  14471. if(numberOfDescriptors > tableCapacity) {
  14472. const exceedingPercentage = 100 * numberOfDescriptors / tableCapacity;
  14473. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.warning(`There are too many descriptors (${numberOfDescriptors}) for a ${profileName} LSH table. That's ${exceedingPercentage.toFixed(2)}% of its theoretical capacity. Consider increasing the hashSize (currently set to ${hashSize}) or reducing the number of descriptors to avoid degradation.`);
  14474. }
  14475. // create empty LSH tables
  14476. const buffer = new ArrayBuffer(textureWidth * textureHeight * LSH_BYTESPERPIXEL);
  14477. const bytes = (new Uint8Array(buffer)).fill(0xFF);
  14478. const data = new DataView(buffer);
  14479. // shuffle the descriptors...
  14480. // it seems like a good idea to handle collisions of similar descriptors,
  14481. // which may be located next to each other in the array
  14482. const permutation = _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.shuffle(_utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.range(numberOfDescriptors));
  14483. // for each descriptor
  14484. // do everything in little-endian format!
  14485. const numberOfDiscardedDescriptorsPerTable = (new Array(tableCount)).fill(0);
  14486. for(let i = 0; i < numberOfDescriptors; i++) {
  14487. const descriptorIndex = permutation[i]; //i;
  14488. const hashes = this._hashCodes(descriptors[descriptorIndex], sequences);
  14489. // for each table
  14490. for(let table = 0; table < tableCount; table++) {
  14491. // compute hash & memory addresses
  14492. const hash = hashes[table];
  14493. const tableByteOffset = table * bucketsPerTable * bucketSize;
  14494. const bucketByteOffset = tableByteOffset + hash * bucketSize;
  14495. // find the end of the list
  14496. let index = END_OF_LIST;
  14497. for(let entryByteOffset = 0; entryByteOffset < bucketSize; entryByteOffset += LSH_BYTESPERPIXEL) {
  14498. const byteOffset = bucketByteOffset + entryByteOffset;
  14499. index = data.getUint32(byteOffset, true);
  14500. // add the keypoint
  14501. if(index == END_OF_LIST) {
  14502. data.setUint32(byteOffset, descriptorIndex, true);
  14503. break;
  14504. }
  14505. }
  14506. // note: if the bucket is full, we just discard the entry :\
  14507. // we give this event a probabilistic treatment (see above),
  14508. // so it happens with low probability
  14509. if(index != END_OF_LIST)
  14510. numberOfDiscardedDescriptorsPerTable[table]++;
  14511. }
  14512. }
  14513. // log data for further study
  14514. const numberOfDiscardedDescriptors = numberOfDiscardedDescriptorsPerTable.reduce((sum, val) => sum + val, 0);
  14515. const profile = numberOfDiscardedDescriptorsPerTable.map(d => 100 * d / numberOfDescriptors);
  14516. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.log(
  14517. `When building ${tableCount} ${profileName} LSH tables with ${numberOfDescriptors} ` +
  14518. `${descriptorSize * 8}-bit descriptors each and hashSize = ${hashSize} bits, ` +
  14519. `I got the following discard profile: ` + profile.map(x => x.toFixed(2) + '%').join(', ') + `. ` +
  14520. `Average: ${(100 * numberOfDiscardedDescriptors / (tableCount * numberOfDescriptors)).toFixed(2)}%. ` +
  14521. `Minimum: ${Math.min(...profile).toFixed(2)}%. ` +
  14522. `Table capacity: ${tableCapacity}.`
  14523. );
  14524. // upload the LSH tables to the GPU
  14525. texture.resize(textureWidth, textureHeight);
  14526. texture.upload(bytes);
  14527. return texture;
  14528. }
  14529. /**
  14530. * Pick bits from a binary descriptor
  14531. * @param {Uint8Array} descriptor a single descriptor
  14532. * @param {BitSequences} sequences flattened array of tableCount sequences of LSH_SEQUENCE_MAXLEN elements each
  14533. * @returns {number[]} hash code for each table
  14534. */
  14535. _hashCodes(descriptor, sequences)
  14536. {
  14537. const tableCount = this.tableCount;
  14538. const hashSize = this.hashSize;
  14539. const bucketsPerTable = this.bucketsPerTable;
  14540. const hashes = new Array(tableCount);
  14541. //const descriptorSize = descriptor.length;
  14542. // just to be sure...
  14543. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(
  14544. hashSize <= LSH_SEQUENCE_MAXLEN &&
  14545. sequences.length >= LSH_SEQUENCE_MAXLEN * tableCount
  14546. );
  14547. // for each table
  14548. for(let table = 0; table < tableCount; table++) {
  14549. const offset = LSH_SEQUENCE_MAXLEN * table;
  14550. // pick bits [ sequences[offset] .. sequences[offset + hashSize-1] ]
  14551. let hash = 0;
  14552. for(let i = 0; i < hashSize; i++) {
  14553. let bit = sequences[offset + i];
  14554. let b = bit >>> 3;
  14555. let m = 1 << (bit & 7);
  14556. //Utils.assert(b < descriptorSize);
  14557. hash = (hash << 1) | ((descriptor[b] & m) != 0);
  14558. }
  14559. // validate & store
  14560. _utils_utils__WEBPACK_IMPORTED_MODULE_2__.Utils.assert(hash >= 0 && hash < bucketsPerTable);
  14561. hashes[table] = hash;
  14562. }
  14563. // done!
  14564. return hashes;
  14565. }
  14566. }
  14567. /**
  14568. * Compute P(X <= k), where X ~ Poisson(lambda)
  14569. * @param {number} lambda positive number
  14570. * @param {number} k non-negative integer
  14571. * @returns {number}
  14572. */
  14573. function cumulativePoisson(lambda, k)
  14574. {
  14575. const exp = Math.exp(-lambda);
  14576. let sum = 1, fat = 1, pow = 1;
  14577. // k should be small!!!
  14578. for(let i = 1; i <= k; i++)
  14579. sum += (pow *= lambda) / (fat *= i);
  14580. return sum * exp;
  14581. }
  14582. /**
  14583. * Find the maximum number of keypoint descriptors that a table can hold
  14584. * @param {number} hashSize positive integer
  14585. * @param {number} bucketCapacity positive integer
  14586. * @param {number} [probability] probability of no discard events happening in the theoretical model
  14587. * @return {number} optimal table capacity
  14588. */
  14589. function findTableCapacity(hashSize, bucketCapacity, probability = 0.99)
  14590. {
  14591. const n = 1 << hashSize // number of buckets
  14592. const c = bucketCapacity;
  14593. const p = probability;
  14594. let l = 1, r = n * c; // watch for overflow!
  14595. let m = 0, pm = 0;
  14596. // binary search
  14597. while(l < r) {
  14598. m = Math.floor((l + r) / 2);
  14599. pm = cumulativePoisson(m / n, c);
  14600. if(pm > p) //if(1-pm < 1-p)
  14601. l = m + 1;
  14602. else
  14603. r = m;
  14604. }
  14605. return m;
  14606. }
  14607. /***/ }),
  14608. /***/ "./src/gpu/speedy-program-center.js":
  14609. /*!******************************************!*\
  14610. !*** ./src/gpu/speedy-program-center.js ***!
  14611. \******************************************/
  14612. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_654331__) => {
  14613. "use strict";
  14614. __nested_webpack_require_654331__.r(__webpack_exports__);
  14615. /* harmony export */ __nested_webpack_require_654331__.d(__webpack_exports__, {
  14616. /* harmony export */ "SpeedyProgramCenter": () => (/* binding */ SpeedyProgramCenter)
  14617. /* harmony export */ });
  14618. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_654331__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  14619. /* harmony import */ var _programs_utils__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_654331__(/*! ./programs/utils */ "./src/gpu/programs/utils.js");
  14620. /* harmony import */ var _programs_filters__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_654331__(/*! ./programs/filters */ "./src/gpu/programs/filters.js");
  14621. /* harmony import */ var _programs_keypoints__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_654331__(/*! ./programs/keypoints */ "./src/gpu/programs/keypoints.js");
  14622. /* harmony import */ var _programs_pyramids__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_654331__(/*! ./programs/pyramids */ "./src/gpu/programs/pyramids.js");
  14623. /* harmony import */ var _programs_transforms__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_654331__(/*! ./programs/transforms */ "./src/gpu/programs/transforms.js");
  14624. /* harmony import */ var _speedy_program_group__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_654331__(/*! ./speedy-program-group */ "./src/gpu/speedy-program-group.js");
  14625. /*
  14626. * speedy-vision.js
  14627. * GPU-accelerated Computer Vision for JavaScript
  14628. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  14629. *
  14630. * Licensed under the Apache License, Version 2.0 (the "License");
  14631. * you may not use this file except in compliance with the License.
  14632. * You may obtain a copy of the License at
  14633. *
  14634. * http://www.apache.org/licenses/LICENSE-2.0
  14635. *
  14636. * Unless required by applicable law or agreed to in writing, software
  14637. * distributed under the License is distributed on an "AS IS" BASIS,
  14638. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14639. * See the License for the specific language governing permissions and
  14640. * limitations under the License.
  14641. *
  14642. * speedy-program-center.js
  14643. * An access point to all programs that run on the GPU
  14644. */
  14645. /**
  14646. * An access point to all programs that run on the CPU
  14647. * All program groups can be accessed via this class
  14648. */
  14649. class SpeedyProgramCenter
  14650. {
  14651. /**
  14652. * Class constructor
  14653. * @param {SpeedyGPU} gpu reference to SpeedyGPU
  14654. */
  14655. constructor(gpu)
  14656. {
  14657. // Note: we instantiate the program groups lazily
  14658. /** @type {SpeedyGPU} reference to SpeedyGPU */
  14659. this._gpu = gpu;
  14660. /** @type {SpeedyProgramGroupFilters} image filters */
  14661. this._filters = null;
  14662. /** @type {SpeedyProgramGroupTransforms} geometric transformations */
  14663. this._transforms = null;
  14664. /** @type {SpeedyProgramGroupPyramids} pyramids & scale-space */
  14665. this._pyramids = null;
  14666. /** @type {SpeedyProgramGroupKeypoints} keypoint routines */
  14667. this._keypoints = null;
  14668. /** @type {SpeedyProgramGroupUtils} utility programs */
  14669. this._utils = null;
  14670. }
  14671. /**
  14672. * Image filters & convolutions
  14673. * @returns {SpeedyProgramGroupFilters}
  14674. */
  14675. get filters()
  14676. {
  14677. return this._filters || (this._filters = new _programs_filters__WEBPACK_IMPORTED_MODULE_2__.SpeedyProgramGroupFilters(this._gpu));
  14678. }
  14679. /**
  14680. * Geometric transformations
  14681. * @returns {SpeedyProgramGroupTransforms}
  14682. */
  14683. get transforms()
  14684. {
  14685. return this._transforms || (this._transforms = new _programs_transforms__WEBPACK_IMPORTED_MODULE_5__.SpeedyProgramGroupTransforms(this._gpu));
  14686. }
  14687. /**
  14688. * Image pyramids & scale-space
  14689. * @returns {SpeedyProgramGroupPyramids}
  14690. */
  14691. get pyramids()
  14692. {
  14693. return this._pyramids || (this._pyramids = new _programs_pyramids__WEBPACK_IMPORTED_MODULE_4__.SpeedyProgramGroupPyramids(this._gpu));
  14694. }
  14695. /**
  14696. * Keypoint detection & description
  14697. * @returns {SpeedyProgramGroupKeypoints}
  14698. */
  14699. get keypoints()
  14700. {
  14701. return this._keypoints || (this._keypoints = new _programs_keypoints__WEBPACK_IMPORTED_MODULE_3__.SpeedyProgramGroupKeypoints(this._gpu));
  14702. }
  14703. /**
  14704. * Utility programs
  14705. * @returns {SpeedyProgramGroupUtils}
  14706. */
  14707. get utils()
  14708. {
  14709. return this._utils || (this._utils = new _programs_utils__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgramGroupUtils(this._gpu));
  14710. }
  14711. /**
  14712. * Release all programs from all groups. You'll
  14713. * no longer be able to use any of them.
  14714. * @returns {null}
  14715. */
  14716. release()
  14717. {
  14718. for(const key in this) {
  14719. if(Object.prototype.hasOwnProperty.call(this, key) && this[key] != null) {
  14720. const group = this[key];
  14721. if(group instanceof _speedy_program_group__WEBPACK_IMPORTED_MODULE_6__.SpeedyProgramGroup)
  14722. group.release();
  14723. }
  14724. }
  14725. return null;
  14726. }
  14727. }
  14728. /***/ }),
  14729. /***/ "./src/gpu/speedy-program-group.js":
  14730. /*!*****************************************!*\
  14731. !*** ./src/gpu/speedy-program-group.js ***!
  14732. \*****************************************/
  14733. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_659499__) => {
  14734. "use strict";
  14735. __nested_webpack_require_659499__.r(__webpack_exports__);
  14736. /* harmony export */ __nested_webpack_require_659499__.d(__webpack_exports__, {
  14737. /* harmony export */ "SpeedyProgramGroup": () => (/* binding */ SpeedyProgramGroup)
  14738. /* harmony export */ });
  14739. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_659499__(/*! ./shader-declaration */ "./src/gpu/shader-declaration.js");
  14740. /* harmony import */ var _speedy_program__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_659499__(/*! ./speedy-program */ "./src/gpu/speedy-program.js");
  14741. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_659499__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  14742. /*
  14743. * speedy-vision.js
  14744. * GPU-accelerated Computer Vision for JavaScript
  14745. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  14746. *
  14747. * Licensed under the Apache License, Version 2.0 (the "License");
  14748. * you may not use this file except in compliance with the License.
  14749. * You may obtain a copy of the License at
  14750. *
  14751. * http://www.apache.org/licenses/LICENSE-2.0
  14752. *
  14753. * Unless required by applicable law or agreed to in writing, software
  14754. * distributed under the License is distributed on an "AS IS" BASIS,
  14755. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14756. * See the License for the specific language governing permissions and
  14757. * limitations under the License.
  14758. *
  14759. * speedy-program-group.js
  14760. * An abstract group of programs that run on the GPU
  14761. */
  14762. /** @typedef {import('./speedy-program').SpeedyProgramOptions} SpeedyProgramOptions */
  14763. /**
  14764. * @typedef {object} SpeedyProgramHelpers
  14765. * @property {function(): SpeedyProgramOptions} usesPingpongRendering
  14766. * @property {function(): SpeedyProgramOptions} rendersToCanvas
  14767. */
  14768. /** @const {SpeedyProgramHelpers} Program settings generator */
  14769. const PROGRAM_HELPERS = Object.freeze({
  14770. /**
  14771. * Pingpong Rendering: the output texture of a
  14772. * program cannot be used as an input to itself.
  14773. * This is a convenient helper in these situations
  14774. * @returns {SpeedyProgramOptions}
  14775. */
  14776. usesPingpongRendering() {
  14777. return {
  14778. pingpong: true
  14779. };
  14780. },
  14781. /**
  14782. * Render to canvas
  14783. * Use it when we're supposed to see the texture
  14784. * @returns {SpeedyProgramOptions}
  14785. */
  14786. rendersToCanvas() {
  14787. return {
  14788. renderToTexture: false
  14789. };
  14790. },
  14791. });
  14792. /**
  14793. * SpeedyProgramGroup
  14794. * A semantically correlated group
  14795. * of programs that run on the GPU
  14796. * @abstract
  14797. */
  14798. class SpeedyProgramGroup
  14799. {
  14800. /**
  14801. * Class constructor
  14802. * @protected
  14803. * @param {SpeedyGPU} gpu
  14804. */
  14805. constructor(gpu)
  14806. {
  14807. /** @type {SpeedyGPU} GPU-accelerated routines */
  14808. this._gpu = gpu;
  14809. /** @type {SpeedyProgram[]} the list of all programs that belong to this group */
  14810. this._programs = [];
  14811. }
  14812. /**
  14813. * Declare a program
  14814. * @protected
  14815. * @param {string} name Program name
  14816. * @param {ShaderDeclaration} shaderdecl Shader declaration
  14817. * @param {SpeedyProgramOptions} [options] Program settings
  14818. * @returns {this}
  14819. */
  14820. declare(name, shaderdecl, options = {})
  14821. {
  14822. // lazy instantiation of kernels
  14823. Object.defineProperty(this, name, {
  14824. get: (() => {
  14825. // Why cast a symbol to symbol?
  14826. // Suppress error TS9005: Declaration emit for this file requires using private name 'key'.
  14827. const key = /** @type {symbol} */ ( Symbol(name) );
  14828. return () => this[key] || (this[key] = this._createProgram(shaderdecl, options));
  14829. })()
  14830. });
  14831. return this;
  14832. }
  14833. /**
  14834. * Neat helpers to be used when declaring programs
  14835. * @returns {SpeedyProgramHelpers}
  14836. */
  14837. get program()
  14838. {
  14839. return PROGRAM_HELPERS;
  14840. }
  14841. /**
  14842. * Releases all programs from this group
  14843. * @returns {null}
  14844. */
  14845. release()
  14846. {
  14847. for(let i = 0; i < this._programs.length; i++)
  14848. this._programs[i].release();
  14849. return null;
  14850. }
  14851. /**
  14852. * Spawn a SpeedyProgram
  14853. * @param {ShaderDeclaration} shaderdecl Shader declaration
  14854. * @param {SpeedyProgramOptions} [options] Program settings
  14855. * @returns {SpeedyProgram}
  14856. */
  14857. _createProgram(shaderdecl, options = {})
  14858. {
  14859. const program = new _speedy_program__WEBPACK_IMPORTED_MODULE_1__.SpeedyProgram(this._gpu.gl, shaderdecl, options);
  14860. this._programs.push(program);
  14861. return program;
  14862. }
  14863. }
  14864. /***/ }),
  14865. /***/ "./src/gpu/speedy-program.js":
  14866. /*!***********************************!*\
  14867. !*** ./src/gpu/speedy-program.js ***!
  14868. \***********************************/
  14869. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_664244__) => {
  14870. "use strict";
  14871. __nested_webpack_require_664244__.r(__webpack_exports__);
  14872. /* harmony export */ __nested_webpack_require_664244__.d(__webpack_exports__, {
  14873. /* harmony export */ "SpeedyProgram": () => (/* binding */ SpeedyProgram)
  14874. /* harmony export */ });
  14875. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_664244__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  14876. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_664244__(/*! ../core/speedy-promise */ "./src/core/speedy-promise.js");
  14877. /* harmony import */ var _shader_declaration__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_664244__(/*! ./shader-declaration */ "./src/gpu/shader-declaration.js");
  14878. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_664244__(/*! ../utils/utils */ "./src/utils/utils.js");
  14879. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_664244__(/*! ../utils/errors */ "./src/utils/errors.js");
  14880. /*
  14881. * speedy-vision.js
  14882. * GPU-accelerated Computer Vision for JavaScript
  14883. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  14884. *
  14885. * Licensed under the Apache License, Version 2.0 (the "License");
  14886. * you may not use this file except in compliance with the License.
  14887. * You may obtain a copy of the License at
  14888. *
  14889. * http://www.apache.org/licenses/LICENSE-2.0
  14890. *
  14891. * Unless required by applicable law or agreed to in writing, software
  14892. * distributed under the License is distributed on an "AS IS" BASIS,
  14893. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14894. * See the License for the specific language governing permissions and
  14895. * limitations under the License.
  14896. *
  14897. * speedy-program.js
  14898. * SpeedyProgram class
  14899. */
  14900. /** @const {Object<string,string>} Map uniform type to a gl function */
  14901. const UNIFORM_SETTERS = Object.freeze({
  14902. 'sampler2D': 'uniform1i',
  14903. 'isampler2D':'uniform1i',
  14904. 'usampler2D':'uniform1i',
  14905. 'float': 'uniform1f',
  14906. 'int': 'uniform1i',
  14907. 'uint': 'uniform1ui',
  14908. 'bool': 'uniform1i',
  14909. 'vec2': 'uniform2f',
  14910. 'vec3': 'uniform3f',
  14911. 'vec4': 'uniform4f',
  14912. 'ivec2': 'uniform2i',
  14913. 'ivec3': 'uniform3i',
  14914. 'ivec4': 'uniform4i',
  14915. 'uvec2': 'uniform2ui',
  14916. 'uvec3': 'uniform3ui',
  14917. 'uvec4': 'uniform4ui',
  14918. 'bvec2': 'uniform2i',
  14919. 'bvec3': 'uniform3i',
  14920. 'bvec4': 'uniform4i',
  14921. 'mat2': 'uniformMatrix2fv',
  14922. 'mat3': 'uniformMatrix3fv',
  14923. 'mat4': 'uniformMatrix4fv',
  14924. });
  14925. /**
  14926. * @typedef {object} SpeedyProgramOptions
  14927. * @property {boolean} [renderToTexture] render results to a texture?
  14928. * @property {boolean} [pingpong] alternate output texture between calls
  14929. */
  14930. /** @typedef {number|number[]|boolean|boolean[]|SpeedyTexture} SpeedyProgramUniformValue */
  14931. /**
  14932. * A SpeedyProgram is a Function that
  14933. * runs GPU-accelerated GLSL code
  14934. */
  14935. class SpeedyProgram extends Function
  14936. {
  14937. /**
  14938. * Creates a new SpeedyProgram
  14939. * @param {WebGL2RenderingContext} gl WebGL context
  14940. * @param {ShaderDeclaration} shaderdecl Shader declaration
  14941. * @param {SpeedyProgramOptions} [options] user options
  14942. */
  14943. constructor(gl, shaderdecl, options = { })
  14944. {
  14945. super('...args', 'return this._self._call(...args)');
  14946. /** @type {SpeedyProgram} this function bound to this function! */
  14947. this._self = this.bind(this);
  14948. this._self._init(gl, shaderdecl, options);
  14949. return this._self;
  14950. }
  14951. /**
  14952. * Initialize the SpeedyProgram
  14953. * @param {WebGL2RenderingContext} gl WebGL context
  14954. * @param {ShaderDeclaration} shaderdecl Shader declaration
  14955. * @param {SpeedyProgramOptions} options user options
  14956. */
  14957. _init(gl, shaderdecl, options)
  14958. {
  14959. // not a valid context?
  14960. if(gl.isContextLost())
  14961. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalOperationError(`Can't initialize SpeedyProgram: lost context`);
  14962. // options object
  14963. options = Object.assign({
  14964. // default options
  14965. renderToTexture: true,
  14966. pingpong: false,
  14967. }, options);
  14968. /** @type {WebGL2RenderingContext} */
  14969. this._gl = gl;
  14970. /** @type {WebGLProgram} vertex shader + fragment shader */
  14971. this._program = SpeedyProgram._compile(gl, shaderdecl.vertexSource, shaderdecl.fragmentSource);
  14972. /** @type {ProgramGeometry} this is a quad */
  14973. this._geometry = new ProgramGeometry(gl, {
  14974. position: shaderdecl.locationOfAttributes.position,
  14975. texCoord: shaderdecl.locationOfAttributes.texCoord
  14976. });
  14977. /** @type {string[]} names of the arguments of the SpeedyProgram */
  14978. this._argnames = shaderdecl.arguments;
  14979. /** @type {boolean[]} tells whether the i-th argument of the SpeedyProgram is an array or not */
  14980. this._argIsArray = (new Array(this._argnames.length)).fill(false);
  14981. /** @type {UBOHelper} UBO helper (lazy instantiation) */
  14982. this._ubo = null;
  14983. /** @type {boolean} should we render to a texture? If false, we render to the canvas */
  14984. this._renderToTexture = Boolean(options.renderToTexture);
  14985. /** @type {number} width of the output */
  14986. this._width = 1;
  14987. /** @type {number} height of the output */
  14988. this._height = 1;
  14989. /** @type {SpeedyDrawableTexture[]} output texture(s) */
  14990. this._texture = (new Array(options.pingpong ? 2 : 1)).fill(null);
  14991. /** @type {number} used for pingpong rendering */
  14992. this._textureIndex = 0;
  14993. /** @type {Map<string,UniformVariable>} uniform variables */
  14994. this._uniform = new Map();
  14995. /** @type {ShaderDeclaration} shader declaration */
  14996. this._shaderdecl = shaderdecl;
  14997. // autodetect uniforms
  14998. gl.useProgram(this._program);
  14999. for(const name of shaderdecl.uniforms) {
  15000. const type = shaderdecl.uniformType(name);
  15001. const location = gl.getUniformLocation(this._program, name);
  15002. this._uniform.set(name, new UniformVariable(type, location));
  15003. }
  15004. // match arguments & uniforms
  15005. for(let j = 0; j < this._argnames.length; j++) {
  15006. const argname = this._argnames[j];
  15007. if(!this._uniform.has(argname)) {
  15008. this._argIsArray[j] = this._uniform.has(argname + '[0]');
  15009. if(!this._argIsArray[j])
  15010. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalOperationError(`Expected uniform "${argname}", as declared in the argument list`);
  15011. }
  15012. }
  15013. }
  15014. /**
  15015. * Run the SpeedyProgram
  15016. * @param {...SpeedyProgramUniformValue} args
  15017. * @returns {SpeedyDrawableTexture}
  15018. */
  15019. _call(...args)
  15020. {
  15021. const gl = this._gl;
  15022. const argnames = this._argnames;
  15023. // matching arguments?
  15024. if(args.length != argnames.length)
  15025. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: incorrect number of arguments (expected ${argnames.length}, got ${args.length})`);
  15026. // can't use the output texture as an input
  15027. const flatArgs = _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.flatten(args);
  15028. for(let j = flatArgs.length - 1; j >= 0; j--) {
  15029. if(flatArgs[j] === this._texture[this._textureIndex])
  15030. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.NotSupportedError(`Can't run shader: don't use its output texture as an input to itself. Consider using pingpong rendering!`);
  15031. }
  15032. // context loss?
  15033. if(gl.isContextLost())
  15034. return this._texture[this._textureIndex];
  15035. // use program
  15036. gl.useProgram(this._program);
  15037. // bind the VAO
  15038. gl.bindVertexArray(this._geometry.vao);
  15039. // select the render target
  15040. const texture = this._texture[this._textureIndex];
  15041. const fbo = this._renderToTexture ? texture.glFbo : null;
  15042. // update texSize uniform (available in all fragment shaders)
  15043. const width = this._width, height = this._height;
  15044. const texSize = this._uniform.get('texSize');
  15045. texSize.setValue(gl, [ width, height ]);
  15046. //gl.uniform2f(texSize.location, width, height);
  15047. // set uniforms[i] to args[i]
  15048. for(let i = 0, texNo = 0; i < args.length; i++) {
  15049. const argname = argnames[i];
  15050. if(!this._argIsArray[i]) {
  15051. // uniform variable matches argument name
  15052. const uniform = this._uniform.get(argname);
  15053. texNo = uniform.setValue(gl, args[i], texNo);
  15054. }
  15055. else {
  15056. // uniform array matches argument name
  15057. const array = args[i];
  15058. if(Array.isArray(array)) {
  15059. if(this._uniform.has(`${argname}[${array.length}]`))
  15060. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: too few elements in the "${argname}" array`);
  15061. for(let j = 0, uniform = undefined; (uniform = this._uniform.get(`${argname}[${j}]`)) !== undefined; j++)
  15062. texNo = uniform.setValue(gl, array[j], texNo);
  15063. }
  15064. else
  15065. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: expected an array for "${argname}"`);
  15066. }
  15067. }
  15068. // set Uniform Buffer Objects (if any)
  15069. if(this._ubo !== null)
  15070. this._ubo.update();
  15071. // bind the FBO
  15072. gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  15073. // draw call
  15074. gl.viewport(0, 0, width, height);
  15075. gl.drawArrays(gl.TRIANGLES, 0, 6); // mode, offset, count
  15076. // unbind the FBO
  15077. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  15078. // unbind the VAO
  15079. gl.bindVertexArray(null);
  15080. // we've just changed the texture! discard the pyramid, if any
  15081. if(texture != null)
  15082. texture.discardMipmaps();
  15083. // ping-pong rendering
  15084. this._pingpong();
  15085. // done!
  15086. return texture;
  15087. }
  15088. /**
  15089. * Set the output texture(s) and its (their) shape(s)
  15090. * @param {number} width new width, in pixels
  15091. * @param {number} height new height, in pixels
  15092. * @param {...SpeedyDrawableTexture|null} texture output texture(s)
  15093. * @returns {SpeedyProgram} this
  15094. */
  15095. outputs(width, height, ...texture)
  15096. {
  15097. this._setOutputTexture(...texture);
  15098. this._setOutputSize(width, height);
  15099. return this;
  15100. }
  15101. /**
  15102. * Set the size of the output
  15103. * @param {number} width new width, in pixels
  15104. * @param {number} height new height, in pixels
  15105. * @returns {SpeedyProgram} this
  15106. */
  15107. _setOutputSize(width, height)
  15108. {
  15109. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(width > 0 && height > 0);
  15110. // update output size
  15111. this._width = width | 0;
  15112. this._height = height | 0;
  15113. // resize the output texture(s)
  15114. for(let i = 0; i < this._texture.length; i++) {
  15115. if(this._texture[i] != null)
  15116. this._texture[i].resize(this._width, this._height);
  15117. }
  15118. // done!
  15119. return this;
  15120. }
  15121. /**
  15122. * Use the provided texture(s) as output
  15123. * @param {...SpeedyDrawableTexture} texture set to null to use the internal texture(s)
  15124. * @returns {SpeedyProgram} this
  15125. */
  15126. _setOutputTexture(...texture)
  15127. {
  15128. _utils_utils__WEBPACK_IMPORTED_MODULE_3__.Utils.assert(texture.length === this._texture.length, `Incorrect number of textures (expected ${this._texture.length})`);
  15129. // update output texture(s)
  15130. for(let i = 0; i < this._texture.length; i++)
  15131. this._texture[i] = texture[i];
  15132. this._textureIndex = 0;
  15133. // done!
  15134. return this;
  15135. }
  15136. /**
  15137. * Clear the internal textures
  15138. * @returns {SpeedyDrawableTexture}
  15139. */
  15140. clear()
  15141. {
  15142. const texture = this._texture[this._textureIndex];
  15143. // clear internal textures
  15144. for(let i = 0; i < this._texture.length; i++)
  15145. this._texture[i].clear();
  15146. // ping-pong rendering
  15147. this._pingpong();
  15148. // done!
  15149. return texture;
  15150. }
  15151. /**
  15152. * Set data using a Uniform Buffer Object
  15153. * @param {string} blockName uniform block name
  15154. * @param {ArrayBufferView} data
  15155. * @returns {SpeedyProgram} this
  15156. */
  15157. setUBO(blockName, data)
  15158. {
  15159. if(this._ubo === null)
  15160. this._ubo = new UBOHelper(this._gl, this._program);
  15161. this._ubo.set(blockName, data);
  15162. return this;
  15163. }
  15164. /**
  15165. * Release the resources associated with this SpeedyProgram
  15166. * @returns {null}
  15167. */
  15168. release()
  15169. {
  15170. const gl = this._gl;
  15171. // Release UBOs (if any)
  15172. if(this._ubo != null)
  15173. this._ubo = this._ubo.release();
  15174. // Unlink textures
  15175. this._texture.fill(null);
  15176. // Release geometry
  15177. this._geometry = this._geometry.release();
  15178. // Release program
  15179. gl.deleteProgram(this._program);
  15180. this._program = null;
  15181. // Need to delete the shaders as well? In sec 5.14.9 Programs and shaders
  15182. // of the WebGL 1.0 spec, it is mentioned that the underlying GL object
  15183. // will automatically be marked for deletion when the JS object is
  15184. // destroyed (i.e., garbage collected)
  15185. // done!
  15186. return null;
  15187. }
  15188. /**
  15189. * A constant #defined in the shader declaration
  15190. * @param {string} name
  15191. * @returns {number}
  15192. */
  15193. definedConstant(name)
  15194. {
  15195. return this._shaderdecl.definedConstant(name);
  15196. }
  15197. /**
  15198. * Helper method for pingpong rendering: alternates
  15199. * the texture index from 0 to 1 and vice-versa
  15200. */
  15201. _pingpong()
  15202. {
  15203. if(this._texture.length > 1)
  15204. this._textureIndex = 1 - this._textureIndex;
  15205. }
  15206. /**
  15207. * Compile and link GLSL shaders
  15208. * @param {WebGL2RenderingContext} gl
  15209. * @param {string} vertexShaderSource GLSL code of the vertex shader
  15210. * @param {string} fragmentShaderSource GLSL code of the fragment shader
  15211. * @returns {WebGLProgram}
  15212. */
  15213. static _compile(gl, vertexShaderSource, fragmentShaderSource)
  15214. {
  15215. const program = gl.createProgram();
  15216. const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  15217. const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  15218. // compile vertex shader
  15219. gl.shaderSource(vertexShader, vertexShaderSource);
  15220. gl.compileShader(vertexShader);
  15221. gl.attachShader(program, vertexShader);
  15222. // compile fragment shader
  15223. gl.shaderSource(fragmentShader, fragmentShaderSource);
  15224. gl.compileShader(fragmentShader);
  15225. gl.attachShader(program, fragmentShader);
  15226. // link program
  15227. gl.linkProgram(program);
  15228. gl.validateProgram(program);
  15229. // return on success
  15230. if(gl.getProgramParameter(program, gl.LINK_STATUS))
  15231. return program;
  15232. // display an error
  15233. const errors = [
  15234. gl.getShaderInfoLog(fragmentShader),
  15235. gl.getShaderInfoLog(vertexShader),
  15236. gl.getProgramInfoLog(program),
  15237. ];
  15238. gl.deleteProgram(program);
  15239. gl.deleteShader(fragmentShader);
  15240. gl.deleteShader(vertexShader);
  15241. // display error
  15242. const spaces = i => Math.max(0, 2 - Math.floor(Math.log10(i)));
  15243. const col = k => new Array(spaces(k)).fill(' ').join('') + k + '. ';
  15244. const source = errors[0] ? fragmentShaderSource : vertexShaderSource;
  15245. const formattedSource = source.split('\n')
  15246. .map((line, no) => col(1+no) + line)
  15247. .join('\n');
  15248. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.GLError(
  15249. `\n\n---------- ERROR ----------\n\n` +
  15250. errors.filter(err => err).join('\n') +
  15251. `\n\n---------- SOURCE CODE ----------\n\n` +
  15252. formattedSource + '\n'
  15253. );
  15254. }
  15255. }
  15256. // ============================================================================
  15257. // HELPERS
  15258. // ============================================================================
  15259. /**
  15260. * Configure and store the VAO and the VBOs
  15261. * @param {WebGL2RenderingContext} gl
  15262. * @param {LocationOfAttributes} location
  15263. * @returns {ProgramGeometry}
  15264. *
  15265. * @typedef {Object} LocationOfAttributes
  15266. * @property {number} position
  15267. * @property {number} texCoord
  15268. *
  15269. * @typedef {Object} BufferOfAttributes
  15270. * @property {WebGLBuffer} position
  15271. * @property {WebGLBuffer} texCoord
  15272. */
  15273. function ProgramGeometry(gl, location)
  15274. {
  15275. /** @type {WebGLVertexArrayObject} Vertex Array Object */
  15276. this.vao = gl.createVertexArray();
  15277. /** @type {BufferOfAttributes} Vertex Buffer Objects */
  15278. this.vbo = Object.freeze({
  15279. position: gl.createBuffer(),
  15280. texCoord: gl.createBuffer()
  15281. });
  15282. /** @type {WebGL2RenderingContext} */
  15283. this._gl = gl;
  15284. // bind the VAO
  15285. gl.bindVertexArray(this.vao);
  15286. // set the position attribute
  15287. gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo.position);
  15288. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  15289. // clip coordinates (CCW)
  15290. -1, -1,
  15291. 1, -1,
  15292. -1, 1,
  15293. -1, 1,
  15294. 1, -1,
  15295. 1, 1,
  15296. ]), gl.STATIC_DRAW);
  15297. gl.enableVertexAttribArray(location.position);
  15298. gl.vertexAttribPointer(location.position, // attribute location
  15299. 2, // 2 components per vertex (x,y)
  15300. gl.FLOAT, // type
  15301. false, // don't normalize
  15302. 0, // default stride (tightly packed)
  15303. 0); // offset
  15304. // set the texCoord attribute
  15305. gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo.texCoord);
  15306. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  15307. // texture coordinates (CCW)
  15308. 0, 0,
  15309. 1, 0,
  15310. 0, 1,
  15311. 0, 1,
  15312. 1, 0,
  15313. 1, 1,
  15314. ]), gl.STATIC_DRAW);
  15315. gl.enableVertexAttribArray(location.texCoord);
  15316. gl.vertexAttribPointer(location.texCoord, // attribute location
  15317. 2, // 2 components per vertex (x,y)
  15318. gl.FLOAT, // type
  15319. false, // don't normalize
  15320. 0, // default stride (tightly packed)
  15321. 0); // offset
  15322. // unbind
  15323. gl.bindBuffer(gl.ARRAY_BUFFER, null);
  15324. gl.bindVertexArray(null);
  15325. // done!
  15326. return Object.freeze(this);
  15327. }
  15328. /**
  15329. * Releases the internal resources
  15330. * @returns {null}
  15331. */
  15332. ProgramGeometry.prototype.release = function()
  15333. {
  15334. const gl = this._gl;
  15335. gl.deleteVertexArray(this.vao);
  15336. gl.deleteBuffer(this.vbo.position);
  15337. gl.deleteBuffer(this.vbo.texCoord);
  15338. return null;
  15339. }
  15340. /**
  15341. * Helper class for storing data in GLSL uniform variables
  15342. * @param {string} type
  15343. * @param {WebGLUniformLocation} location
  15344. */
  15345. function UniformVariable(type, location)
  15346. {
  15347. /** @type {string} GLSL data type */
  15348. this.type = String(type);
  15349. if(!Object.prototype.hasOwnProperty.call(UNIFORM_SETTERS, this.type))
  15350. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.NotSupportedError(`Unsupported uniform type: ${this.type}`);
  15351. /** @type {WebGLUniformLocation} uniform location in a WebGL program */
  15352. this.location = location;
  15353. /** @type {string} setter function */
  15354. this.setter = UNIFORM_SETTERS[this.type];
  15355. const n = Number((this.setter.match(/^uniform(Matrix)?(\d)/))[2]) | 0;
  15356. /** @type {number} is the uniform a scalar (0), a vector (1) or a matrix (2)? */
  15357. this.dim = this.type.startsWith('mat') ? 2 : ((this.type.indexOf('vec') >= 0) ? 1 : 0);
  15358. /** @type {number} required number of scalars */
  15359. this.length = (this.dim == 2) ? n * n : n;
  15360. /** @type {SpeedyProgramUniformValue|null} cached value */
  15361. this._value = null;
  15362. }
  15363. /**
  15364. * Set the value of a uniform variable
  15365. * @param {WebGL2RenderingContext} gl
  15366. * @param {SpeedyProgramUniformValue} value use column-major format for matrices
  15367. * @param {number} [texNo] current texture index
  15368. * @returns {number} new texture index
  15369. */
  15370. UniformVariable.prototype.setValue = function(gl, value, texNo = -1)
  15371. {
  15372. const setValue = /** @type {Function} */ ( gl[this.setter] );
  15373. // check uniform type
  15374. if(typeof value === 'object' && this.type.endsWith('sampler2D')) {
  15375. // set texture
  15376. if(texNo >= gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)
  15377. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.NotSupportedError(`Can't activate texture unit ${texNo}: max is ${gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS}`);
  15378. else if(Array.isArray(value))
  15379. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.NotSupportedError(`Can't pass arrays of textures to shaders`);
  15380. else if(value == null)
  15381. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: cannot use ${value} as an input texture`);
  15382. else if(texNo < 0)
  15383. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Missing texNo`);
  15384. const tex = value;
  15385. gl.activeTexture(gl.TEXTURE0 + texNo);
  15386. gl.bindTexture(gl.TEXTURE_2D, tex.glTexture);
  15387. gl.uniform1i(this.location, texNo);
  15388. texNo++;
  15389. }
  15390. else if(value === this._value) {
  15391. // do not update the uniform if it hasn't changed
  15392. void(0);
  15393. }
  15394. else if(typeof value === 'number' || typeof value === 'boolean') {
  15395. // set scalar value
  15396. setValue.call(gl, this.location, value);
  15397. }
  15398. else if(Array.isArray(value)) {
  15399. // set vector or matrix
  15400. if(value.length === this.length) {
  15401. if(this.dim == 2)
  15402. setValue.call(gl, this.location, false, value); // matrix
  15403. else
  15404. setValue.call(gl, this.location, ...value); // vector
  15405. }
  15406. else
  15407. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: incorrect number of values for ${this.type}: "${value}"`);
  15408. }
  15409. else
  15410. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_4__.IllegalArgumentError(`Can't run shader: unrecognized argument "${value}"`);
  15411. // cache the value
  15412. this._value = value;
  15413. // done
  15414. return texNo;
  15415. }
  15416. /**
  15417. * @typedef {object} UBOStuff
  15418. * @property {WebGLBuffer} buffer
  15419. * @property {number} blockBindingIndex "global" binding index
  15420. * @property {number} blockIndex UBO "location" in the program
  15421. * @property {ArrayBufferView|null} data user-data
  15422. */
  15423. /**
  15424. * A helper class for handling Uniform Buffer Objects (UBOs)
  15425. * @param {WebGL2RenderingContext} gl
  15426. * @param {WebGLProgram} program
  15427. */
  15428. function UBOHelper(gl, program)
  15429. {
  15430. /** @type {WebGL2RenderingContext} */
  15431. this._gl = gl;
  15432. /** @type {WebGLProgram} */
  15433. this._program = program;
  15434. /** @type {number} auto-increment counter */
  15435. this._nextIndex = 0;
  15436. /** @type {Object<string,UBOStuff>} UBO dictionary indexed by uniform block names */
  15437. this._ubo = Object.create(null);
  15438. }
  15439. /**
  15440. * Set Uniform Buffer Object data
  15441. * (the buffer will be uploaded when the program is executed)
  15442. * @param {string} name uniform block name
  15443. * @param {ArrayBufferView} data
  15444. */
  15445. UBOHelper.prototype.set = function(name, data)
  15446. {
  15447. const gl = this._gl;
  15448. // create UBO entry
  15449. if(this._ubo[name] === undefined) {
  15450. this._ubo[name] = {
  15451. buffer: gl.createBuffer(),
  15452. blockBindingIndex: this._nextIndex++,
  15453. blockIndex: -1,
  15454. data: null
  15455. };
  15456. }
  15457. // get UBO entry for the given block name
  15458. const ubo = this._ubo[name];
  15459. // read block index & assign binding point
  15460. if(ubo.blockIndex < 0) {
  15461. const blockIndex = gl.getUniformBlockIndex(this._program, name); // GLuint
  15462. gl.uniformBlockBinding(this._program, blockIndex, ubo.blockBindingIndex);
  15463. ubo.blockIndex = blockIndex;
  15464. }
  15465. // store the data - we'll upload it later
  15466. ubo.data = data;
  15467. }
  15468. /**
  15469. * Update UBO data
  15470. * Called when we're using the appropriate WebGLProgram
  15471. */
  15472. UBOHelper.prototype.update = function()
  15473. {
  15474. const gl = this._gl;
  15475. for(const name in this._ubo) {
  15476. const ubo = this._ubo[name];
  15477. gl.bindBuffer(gl.UNIFORM_BUFFER, ubo.buffer);
  15478. gl.bufferData(gl.UNIFORM_BUFFER, ubo.data, gl.DYNAMIC_DRAW);
  15479. gl.bindBufferBase(gl.UNIFORM_BUFFER, ubo.blockBindingIndex, ubo.buffer);
  15480. gl.bindBuffer(gl.UNIFORM_BUFFER, null);
  15481. }
  15482. }
  15483. /**
  15484. * Release allocated buffers
  15485. * @returns {null}
  15486. */
  15487. UBOHelper.prototype.release = function()
  15488. {
  15489. const gl = this._gl;
  15490. for(const name in this._ubo) {
  15491. const ubo = this._ubo[name];
  15492. gl.deleteBuffer(ubo.buffer);
  15493. ubo.data = null;
  15494. }
  15495. return null;
  15496. }
  15497. /***/ }),
  15498. /***/ "./src/gpu/speedy-texture-pool.js":
  15499. /*!****************************************!*\
  15500. !*** ./src/gpu/speedy-texture-pool.js ***!
  15501. \****************************************/
  15502. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_689460__) => {
  15503. "use strict";
  15504. __nested_webpack_require_689460__.r(__webpack_exports__);
  15505. /* harmony export */ __nested_webpack_require_689460__.d(__webpack_exports__, {
  15506. /* harmony export */ "SpeedyTexturePool": () => (/* binding */ SpeedyTexturePool)
  15507. /* harmony export */ });
  15508. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_689460__(/*! ../utils/utils */ "./src/utils/utils.js");
  15509. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_689460__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  15510. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_689460__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  15511. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_689460__(/*! ../utils/errors */ "./src/utils/errors.js");
  15512. /*
  15513. * speedy-vision.js
  15514. * GPU-accelerated Computer Vision for JavaScript
  15515. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  15516. *
  15517. * Licensed under the Apache License, Version 2.0 (the "License");
  15518. * you may not use this file except in compliance with the License.
  15519. * You may obtain a copy of the License at
  15520. *
  15521. * http://www.apache.org/licenses/LICENSE-2.0
  15522. *
  15523. * Unless required by applicable law or agreed to in writing, software
  15524. * distributed under the License is distributed on an "AS IS" BASIS,
  15525. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15526. * See the License for the specific language governing permissions and
  15527. * limitations under the License.
  15528. *
  15529. * speedy-texture-pool.js
  15530. * Texture pool
  15531. */
  15532. // Constants
  15533. const DEFAULT_CAPACITY = 1024;
  15534. const BUCKET = Symbol('Bucket');
  15535. /*
  15536. === Heuristics to figure out the capacity of a texture pool ===
  15537. 1. Decide the maximum amount of VRAM you'd like to use in a pool (say, 64 MB).
  15538. 2. Figure out the average texture size in your application (say, 640x360 pixels).
  15539. 3. Figure out the average texture size in bytes (say, 921600 bytes). Each pixel
  15540. uses 4 bytes (RGBA format).
  15541. 4. Divide the maximum amount of VRAM by the average texture size in bytes
  15542. (say, 72). That's the capacity of the pool.
  15543. Note that textures are allocated lazily, so VRAM usage is kept to a minimum.
  15544. Adapted from: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices
  15545. */
  15546. /**
  15547. * @typedef {number} TextureBucketIndex index of a bucket in a pool
  15548. */
  15549. /**
  15550. * A bucket
  15551. */
  15552. class TextureBucket
  15553. {
  15554. /**
  15555. * Constructor
  15556. * @param {SpeedyDrawableTexture} texture managed texture
  15557. * @param {TextureBucketIndex} index index of this bucket
  15558. * @param {TextureBucketIndex} next index of the next bucket
  15559. */
  15560. constructor(texture, index, next)
  15561. {
  15562. /** @type {SpeedyDrawableTexture} managed texture */
  15563. this.texture = texture;
  15564. /** @type {TextureBucketIndex} index of this bucket */
  15565. this.index = index;
  15566. /** @type {TextureBucketIndex} index of the next bucket */
  15567. this.next = next;
  15568. /** @type {boolean} whether the texture is available or not */
  15569. this.free = true;
  15570. }
  15571. }
  15572. /**
  15573. * Texture pool
  15574. */
  15575. class SpeedyTexturePool
  15576. {
  15577. /**
  15578. * Constructor
  15579. * @param {SpeedyGPU} gpu
  15580. * @param {number} [capacity] number of textures in the pool
  15581. */
  15582. constructor(gpu, capacity = DEFAULT_CAPACITY)
  15583. {
  15584. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(capacity > 0);
  15585. /** @type {TextureBucket[]} buckets */
  15586. this._bucket = Array.from({ length: capacity }, (_, i) => new TextureBucket(null, i, i - 1));
  15587. /** @type {TextureBucketIndex} index of an available bucket */
  15588. this._head = capacity - 1;
  15589. /** @type {SpeedyGPU} GPU instance */
  15590. this._gpu = gpu;
  15591. }
  15592. /**
  15593. * Get a texture from the pool
  15594. * @returns {SpeedyDrawableTexture}
  15595. */
  15596. allocate()
  15597. {
  15598. if(this._head < 0)
  15599. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_3__.OutOfMemoryError(`Exhausted pool (capacity: ${this._bucket.length})`);
  15600. const bucket = this._bucket[this._head];
  15601. bucket.free = false;
  15602. this._head = bucket.next;
  15603. if(bucket.texture == null) // lazy instantiation
  15604. bucket.texture = SpeedyTexturePool._createManagedTexture(this._gpu.gl, bucket);
  15605. return bucket.texture;
  15606. }
  15607. /**
  15608. * Put a texture back in the pool
  15609. * @param {SpeedyDrawableTexture} texture
  15610. * @returns {null}
  15611. */
  15612. free(texture)
  15613. {
  15614. const bucket = texture[BUCKET];
  15615. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(bucket !== undefined && !bucket.free, `Unmanaged texture or double free`);
  15616. bucket.next = this._head;
  15617. bucket.free = true;
  15618. this._head = bucket.index;
  15619. return null;
  15620. }
  15621. /**
  15622. * Release the texture pool
  15623. * @returns {null}
  15624. */
  15625. release()
  15626. {
  15627. for(let i = 0; i < this._bucket.length; i++) {
  15628. if(this._bucket[i].texture != null)
  15629. this._bucket[i].texture = this._bucket[i].texture.release();
  15630. }
  15631. return null;
  15632. }
  15633. /**
  15634. * Create a texture with a reference to a bucket
  15635. * @param {WebGL2RenderingContext} gl
  15636. * @param {TextureBucket} bucket
  15637. * @returns {SpeedyDrawableTexture}
  15638. */
  15639. static _createManagedTexture(gl, bucket)
  15640. {
  15641. const texture = new _speedy_texture__WEBPACK_IMPORTED_MODULE_2__.SpeedyDrawableTexture(gl, 1, 1);
  15642. return Object.defineProperty(texture, BUCKET, {
  15643. configurable: false,
  15644. enumerable: false,
  15645. writable: false,
  15646. value: bucket
  15647. });
  15648. }
  15649. }
  15650. /***/ }),
  15651. /***/ "./src/gpu/speedy-texture-reader.js":
  15652. /*!******************************************!*\
  15653. !*** ./src/gpu/speedy-texture-reader.js ***!
  15654. \******************************************/
  15655. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_695313__) => {
  15656. "use strict";
  15657. __nested_webpack_require_695313__.r(__webpack_exports__);
  15658. /* harmony export */ __nested_webpack_require_695313__.d(__webpack_exports__, {
  15659. /* harmony export */ "SpeedyTextureReader": () => (/* binding */ SpeedyTextureReader)
  15660. /* harmony export */ });
  15661. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_695313__(/*! ../utils/utils */ "./src/utils/utils.js");
  15662. /* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_695313__(/*! ../core/settings */ "./src/core/settings.js");
  15663. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_695313__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  15664. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_695313__(/*! ../core/speedy-promise */ "./src/core/speedy-promise.js");
  15665. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_695313__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  15666. /* harmony import */ var _utils_asap__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_695313__(/*! ../utils/asap */ "./src/utils/asap.js");
  15667. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_695313__(/*! ../utils/errors */ "./src/utils/errors.js");
  15668. /*
  15669. * speedy-vision.js
  15670. * GPU-accelerated Computer Vision for JavaScript
  15671. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  15672. *
  15673. * Licensed under the Apache License, Version 2.0 (the "License");
  15674. * you may not use this file except in compliance with the License.
  15675. * You may obtain a copy of the License at
  15676. *
  15677. * http://www.apache.org/licenses/LICENSE-2.0
  15678. *
  15679. * Unless required by applicable law or agreed to in writing, software
  15680. * distributed under the License is distributed on an "AS IS" BASIS,
  15681. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15682. * See the License for the specific language governing permissions and
  15683. * limitations under the License.
  15684. *
  15685. * speedy-texture-reader.js
  15686. * Reads data from textures
  15687. */
  15688. /** @type {number} number of PBOs; used to get a performance boost in gl.readPixels() */
  15689. const DEFAULT_NUMBER_OF_BUFFERS = 2;
  15690. /** @type {(fn: Function, ...args: any[]) => number} Run function fn on the "next frame" */
  15691. const runOnNextFrame = navigator.userAgent.includes('Firefox') ?
  15692. ((fn, ...args) => setTimeout(fn, 10, ...args)) : // RAF produces a warning on Firefox
  15693. ((fn, ...args) => requestAnimationFrame(() => fn.apply(undefined, args))); // reduce battery usage
  15694. /**
  15695. * Reads data from textures
  15696. */
  15697. class SpeedyTextureReader
  15698. {
  15699. /**
  15700. * Constructor
  15701. * @param {number} [numberOfBuffers]
  15702. */
  15703. constructor(numberOfBuffers = DEFAULT_NUMBER_OF_BUFFERS)
  15704. {
  15705. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(numberOfBuffers > 0);
  15706. /** @type {boolean} is this object initialized? */
  15707. this._initialized = false;
  15708. /** @type {Uint8Array[]} pixel buffers for data transfers (each stores RGBA data) */
  15709. this._pixelBuffer = (new Array(numberOfBuffers)).fill(null).map(() => new Uint8Array(0));
  15710. /** @type {WebGLBuffer[]} Pixel Buffer Objects (PBOs) */
  15711. this._pbo = (new Array(numberOfBuffers)).fill(null);
  15712. /** @type {number} the index of the buffer that will be consumed in this frame */
  15713. this._consumerIndex = 0;
  15714. /** @type {number} the index of the buffer that will be produced next */
  15715. this._producerIndex = numberOfBuffers - 1;
  15716. /** @type {SpeedyPromise<void>[]} producer-consumer promises */
  15717. this._promise = Array.from({ length: numberOfBuffers }, () => _core_speedy_promise__WEBPACK_IMPORTED_MODULE_3__.SpeedyPromise.resolve());
  15718. /** @type {boolean[]} are the contents of the ith buffer being produced? */
  15719. this._busy = (new Array(numberOfBuffers)).fill(false);
  15720. /** @type {boolean[]} can the ith buffer be consumed? */
  15721. this._ready = (new Array(numberOfBuffers)).fill(true);
  15722. }
  15723. /**
  15724. * Initialize this object
  15725. * @param {SpeedyGPU} gpu
  15726. */
  15727. init(gpu)
  15728. {
  15729. this._allocatePBOs(gpu);
  15730. gpu.subscribe(this._allocatePBOs, this, gpu);
  15731. this._initialized = true;
  15732. }
  15733. /**
  15734. * Release resources
  15735. * @param {SpeedyGPU} gpu
  15736. * @returns {null}
  15737. */
  15738. release(gpu)
  15739. {
  15740. gpu.unsubscribe(this._allocatePBOs, this);
  15741. this._deallocatePBOs(gpu);
  15742. this._initialized = false;
  15743. return null;
  15744. }
  15745. /**
  15746. * Read pixels from a texture, synchronously.
  15747. * You may optionally specify a (x,y,width,height) sub-rectangle.
  15748. * @param {SpeedyDrawableTexture} texture a texture with a FBO
  15749. * @param {number} [x]
  15750. * @param {number} [y]
  15751. * @param {number} [width]
  15752. * @param {number} [height]
  15753. * @returns {Uint8Array} pixels in the RGBA format
  15754. */
  15755. readPixelsSync(texture, x = 0, y = 0, width = texture.width, height = texture.height)
  15756. {
  15757. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._initialized);
  15758. const gl = texture.gl;
  15759. const fbo = texture.glFbo;
  15760. // clamp values
  15761. width = Math.max(0, Math.min(width, texture.width));
  15762. height = Math.max(0, Math.min(height, texture.height));
  15763. x = Math.max(0, Math.min(x, texture.width - width));
  15764. y = Math.max(0, Math.min(y, texture.height - height));
  15765. // buffer allocation
  15766. const sizeofBuffer = width * height * 4; // 4 bytes per pixel (RGBA)
  15767. this._reallocate(sizeofBuffer);
  15768. // lost context?
  15769. if(gl.isContextLost())
  15770. return this._pixelBuffer[0].subarray(0, sizeofBuffer);
  15771. // read pixels
  15772. gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  15773. gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this._pixelBuffer[0]);
  15774. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  15775. // done!
  15776. return this._pixelBuffer[0].subarray(0, sizeofBuffer);
  15777. }
  15778. /**
  15779. * Read pixels from a texture, asynchronously, with PBOs.
  15780. * You may optionally specify a (x,y,width,height) sub-rectangle.
  15781. * @param {SpeedyDrawableTexture} texture a texture with a FBO
  15782. * @param {number} [x]
  15783. * @param {number} [y]
  15784. * @param {number} [width]
  15785. * @param {number} [height]
  15786. * @param {boolean} [useBufferedDownloads] accelerate downloads by returning pixels from the texture of the previous call (useful for streaming)
  15787. * @returns {SpeedyPromise<Uint8Array>} resolves to an array of pixels in the RGBA format
  15788. */
  15789. readPixelsAsync(texture, x = 0, y = 0, width = texture.width, height = texture.height, useBufferedDownloads = false)
  15790. {
  15791. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(this._initialized);
  15792. const gl = texture.gl;
  15793. const fbo = texture.glFbo;
  15794. // clamp values
  15795. width = Math.max(0, Math.min(width, texture.width));
  15796. height = Math.max(0, Math.min(height, texture.height));
  15797. x = Math.max(0, Math.min(x, texture.width - width));
  15798. y = Math.max(0, Math.min(y, texture.height - height));
  15799. // buffer allocation
  15800. const sizeofBuffer = width * height * 4; // 4 bytes per pixel (RGBA)
  15801. this._reallocate(sizeofBuffer);
  15802. // lost context?
  15803. if(gl.isContextLost())
  15804. return _core_speedy_promise__WEBPACK_IMPORTED_MODULE_3__.SpeedyPromise.resolve(this._pixelBuffer[0].subarray(0, sizeofBuffer));
  15805. // do not optimize?
  15806. if(!useBufferedDownloads) {
  15807. const pixelBuffer = this._pixelBuffer[0].subarray(0, sizeofBuffer);
  15808. return SpeedyTextureReader._readPixelsViaPBO(gl, this._pbo[0], pixelBuffer, fbo, x, y, width, height).then(() =>
  15809. pixelBuffer
  15810. );
  15811. }
  15812. // Hide latency with a Producer-Consumer mechanism
  15813. const numberOfBuffers = this._pixelBuffer.length;
  15814. // GPU needs to produce data
  15815. const producerIndex = this._producerIndex;
  15816. if(!this._busy[producerIndex]) {
  15817. const pbo = this._pbo[producerIndex];
  15818. const pixelBuffer = this._pixelBuffer[producerIndex].subarray(0, sizeofBuffer);
  15819. this._producerIndex = (producerIndex + 1) % numberOfBuffers;
  15820. this._ready[producerIndex] = false;
  15821. this._busy[producerIndex] = true;
  15822. //console.time("produce "+producerIndex);
  15823. this._promise[producerIndex] = SpeedyTextureReader._readPixelsViaPBO(gl, pbo, pixelBuffer, fbo, x, y, width, height).then(() => {
  15824. //console.timeEnd("produce "+producerIndex);
  15825. this._busy[producerIndex] = false;
  15826. this._ready[producerIndex] = true;
  15827. });
  15828. }
  15829. //else console.log("skip",producerIndex);
  15830. else /* skip frame */ ;
  15831. // CPU needs to consume data
  15832. const consumerIndex = this._consumerIndex;
  15833. this._consumerIndex = (consumerIndex + 1) % numberOfBuffers;
  15834. if(!this._ready[consumerIndex]) {
  15835. //console.time("consume "+consumerIndex);
  15836. return this._promise[consumerIndex].then(() => {
  15837. //console.timeEnd("consume "+consumerIndex);
  15838. this._ready[consumerIndex] = false;
  15839. return this._pixelBuffer[consumerIndex];
  15840. });
  15841. }
  15842. //console.log("NO WAIT "+consumerIndex);
  15843. this._ready[consumerIndex] = false;
  15844. return _core_speedy_promise__WEBPACK_IMPORTED_MODULE_3__.SpeedyPromise.resolve(this._pixelBuffer[consumerIndex]);
  15845. }
  15846. /**
  15847. * Reallocate the pixel buffers, so that they can hold the required number of bytes
  15848. * If the pixel buffers already have the required capacity, then nothing is done
  15849. * @param {number} size in bytes
  15850. */
  15851. _reallocate(size)
  15852. {
  15853. // no need to reallocate
  15854. if(size <= this._pixelBuffer[0].byteLength)
  15855. return;
  15856. // reallocate
  15857. for(let i = 0; i < this._pixelBuffer.length; i++) {
  15858. const newBuffer = new Uint8Array(size);
  15859. //newBuffer.set(this._pixelBuffer[i]); // make this optional?
  15860. this._pixelBuffer[i] = newBuffer;
  15861. }
  15862. }
  15863. /**
  15864. * Allocate PBOs
  15865. * @param {SpeedyGPU} gpu
  15866. */
  15867. _allocatePBOs(gpu)
  15868. {
  15869. const gl = gpu.gl;
  15870. for(let i = 0; i < this._pbo.length; i++)
  15871. this._pbo[i] = gl.createBuffer();
  15872. }
  15873. /**
  15874. * Deallocate PBOs
  15875. * @param {SpeedyGPU} gpu
  15876. */
  15877. _deallocatePBOs(gpu)
  15878. {
  15879. const gl = gpu.gl;
  15880. for(let i = this._pbo.length - 1; i >= 0; i--) {
  15881. gl.deleteBuffer(this._pbo[i]);
  15882. this._pbo[i] = null;
  15883. }
  15884. }
  15885. /**
  15886. * Read pixels to a Uint8Array, asynchronously, using a Pixel Buffer Object (PBO)
  15887. * It's assumed that the target texture is in the RGBA8 format
  15888. * @param {WebGL2RenderingContext} gl
  15889. * @param {WebGLBuffer} pbo
  15890. * @param {Uint8Array} outputBuffer with size >= width * height * 4
  15891. * @param {WebGLFramebuffer} fbo
  15892. * @param {GLint} x
  15893. * @param {GLint} y
  15894. * @param {GLsizei} width
  15895. * @param {GLsizei} height
  15896. * @returns {SpeedyPromise<void>}
  15897. */
  15898. static _readPixelsViaPBO(gl, pbo, outputBuffer, fbo, x, y, width, height)
  15899. {
  15900. /*
  15901. When testing Speedy on Chrome (mobile) using about:tracing with the
  15902. --enable-gpu-service-tracing flag, I found that A LOT of time is spent
  15903. in TraceGLAPI::glMapBufferRange, which takes place just after
  15904. GLES2DecoderImpl::HandleReadPixels and GLES2DecoderImpl::glReadPixels.
  15905. Using multiple PBOs doesn't seem to impact Chrome too much. Performance
  15906. is much better on Firefox. This suggests there is room for improvement.
  15907. I do not yet understand clearly the cause for this lag on Chrome. It
  15908. may be a CPU-GPU synchronization issue.
  15909. EDIT: I have found that using gl.flush() aggressively greatly improves
  15910. things. WebGL commands will be pushed frequently!
  15911. See also:
  15912. https://www.khronos.org/registry/webgl/specs/latest/2.0/#3.7.3 (Buffer objects)
  15913. https://github.com/chromium/chromium/blob/master/docs/gpu/debugging_gpu_related_code.md
  15914. */
  15915. const size = width * height * 4;
  15916. // validate outputBuffer
  15917. _utils_utils__WEBPACK_IMPORTED_MODULE_0__.Utils.assert(outputBuffer.byteLength >= size, `Invalid buffer size`);
  15918. // read pixels into the PBO
  15919. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo);
  15920. gl.bufferData(gl.PIXEL_PACK_BUFFER, size, gl.DYNAMIC_READ);
  15921. gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  15922. gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, 0);
  15923. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  15924. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  15925. // create a fence
  15926. const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
  15927. gl.flush(); // make sure the sync command is read
  15928. // wait for the commands to be processed by the GPU
  15929. return new _core_speedy_promise__WEBPACK_IMPORTED_MODULE_3__.SpeedyPromise((resolve, reject) => {
  15930. // according to the WebGL2 spec sec 3.7.14 Sync objects,
  15931. // "sync objects may only transition to the signaled state
  15932. // when the user agent's event loop is not executing a task"
  15933. // in other words, it won't be signaled in the same frame
  15934. if(_core_settings__WEBPACK_IMPORTED_MODULE_1__.Settings.gpuPollingMode != 'asap')
  15935. runOnNextFrame(SpeedyTextureReader._clientWaitAsync, gl, sync, 0, resolve, reject);
  15936. else
  15937. (0,_utils_asap__WEBPACK_IMPORTED_MODULE_5__.asap)(SpeedyTextureReader._clientWaitAsync, gl, sync, 0, resolve, reject);
  15938. }).then(() => {
  15939. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, pbo);
  15940. gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, outputBuffer);
  15941. gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
  15942. }).catch(err => {
  15943. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_6__.IllegalOperationError(`Can't getBufferSubDataAsync(): error in clientWaitAsync()`, err);
  15944. }).finally(() => {
  15945. gl.deleteSync(sync);
  15946. });
  15947. }
  15948. /**
  15949. * Waits for a sync object to become signaled
  15950. * @param {WebGL2RenderingContext} gl
  15951. * @param {WebGLSync} sync
  15952. * @param {GLbitfield} flags may be gl.SYNC_FLUSH_COMMANDS_BIT or 0
  15953. * @param {Function} resolve
  15954. * @param {Function} reject
  15955. * @param {number} [pollInterval] in milliseconds
  15956. * @param {number} [remainingAttempts] for timeout
  15957. */
  15958. static _clientWaitAsync(gl, sync, flags, resolve, reject, pollInterval = 10, remainingAttempts = 1000)
  15959. {
  15960. (function poll() {
  15961. const status = gl.clientWaitSync(sync, flags, 0);
  15962. if(remainingAttempts-- <= 0) {
  15963. reject(new _utils_errors__WEBPACK_IMPORTED_MODULE_6__.TimeoutError(`GPU polling timeout`, _utils_errors__WEBPACK_IMPORTED_MODULE_6__.GLError.from(gl)));
  15964. }
  15965. else if(status === gl.CONDITION_SATISFIED || status === gl.ALREADY_SIGNALED) {
  15966. resolve();
  15967. }
  15968. else {
  15969. //setTimeout(poll, pollInterval);
  15970. if(_core_settings__WEBPACK_IMPORTED_MODULE_1__.Settings.gpuPollingMode != 'asap')
  15971. requestAnimationFrame(poll); // RAF is a rather unusual way to do polling at ~60 fps. Does it reduce CPU usage?
  15972. else
  15973. (0,_utils_asap__WEBPACK_IMPORTED_MODULE_5__.asap)(poll);
  15974. }
  15975. })();
  15976. }
  15977. }
  15978. /***/ }),
  15979. /***/ "./src/gpu/speedy-texture-uploader.js":
  15980. /*!********************************************!*\
  15981. !*** ./src/gpu/speedy-texture-uploader.js ***!
  15982. \********************************************/
  15983. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_711112__) => {
  15984. "use strict";
  15985. __nested_webpack_require_711112__.r(__webpack_exports__);
  15986. /* harmony export */ __nested_webpack_require_711112__.d(__webpack_exports__, {
  15987. /* harmony export */ "SpeedyTextureUploader": () => (/* binding */ SpeedyTextureUploader)
  15988. /* harmony export */ });
  15989. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_711112__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  15990. /* harmony import */ var _speedy_texture__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_711112__(/*! ./speedy-texture */ "./src/gpu/speedy-texture.js");
  15991. /* harmony import */ var _core_speedy_media_source__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_711112__(/*! ../core/speedy-media-source */ "./src/core/speedy-media-source.js");
  15992. /*
  15993. * speedy-vision.js
  15994. * GPU-accelerated Computer Vision for JavaScript
  15995. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  15996. *
  15997. * Licensed under the Apache License, Version 2.0 (the "License");
  15998. * you may not use this file except in compliance with the License.
  15999. * You may obtain a copy of the License at
  16000. *
  16001. * http://www.apache.org/licenses/LICENSE-2.0
  16002. *
  16003. * Unless required by applicable law or agreed to in writing, software
  16004. * distributed under the License is distributed on an "AS IS" BASIS,
  16005. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16006. * See the License for the specific language governing permissions and
  16007. * limitations under the License.
  16008. *
  16009. * speedy-texture-uploader.js
  16010. * A utility that helps uploading data to textures
  16011. */
  16012. /**
  16013. * A utility that helps uploading data to textures
  16014. */
  16015. class SpeedyTextureUploader
  16016. {
  16017. /**
  16018. * Constructor
  16019. * @param {SpeedyGPU} gpu
  16020. */
  16021. constructor(gpu)
  16022. {
  16023. /** @type {SpeedyGPU} GPU instance */
  16024. this._gpu = gpu;
  16025. }
  16026. /**
  16027. * Upload an image to the GPU
  16028. * @param {SpeedyMediaSource} source
  16029. * @param {SpeedyTexture} outputTexture
  16030. * @returns {SpeedyTexture} output texture
  16031. */
  16032. upload(source, outputTexture)
  16033. {
  16034. const data = source.data;
  16035. // bugfix: if the media is a video, we can't really
  16036. // upload it to the GPU unless it's ready
  16037. //if(data.constructor.name == 'HTMLVideoElement') {
  16038. if(data instanceof HTMLVideoElement) {
  16039. if(data.readyState < 2) {
  16040. // this may happen when the video loops (Firefox)
  16041. // return the previously uploaded texture
  16042. //Utils.warning(`Trying to process a video that isn't ready yet`);
  16043. return outputTexture;
  16044. }
  16045. }
  16046. // upload to the output texture
  16047. return outputTexture.upload(data, source.width, source.height);
  16048. }
  16049. /**
  16050. * Release the texture uploader
  16051. * @returns {null}
  16052. */
  16053. release()
  16054. {
  16055. return null;
  16056. }
  16057. }
  16058. /***/ }),
  16059. /***/ "./src/gpu/speedy-texture.js":
  16060. /*!***********************************!*\
  16061. !*** ./src/gpu/speedy-texture.js ***!
  16062. \***********************************/
  16063. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_714137__) => {
  16064. "use strict";
  16065. __nested_webpack_require_714137__.r(__webpack_exports__);
  16066. /* harmony export */ __nested_webpack_require_714137__.d(__webpack_exports__, {
  16067. /* harmony export */ "SpeedyTexture": () => (/* binding */ SpeedyTexture),
  16068. /* harmony export */ "SpeedyDrawableTexture": () => (/* binding */ SpeedyDrawableTexture)
  16069. /* harmony export */ });
  16070. /* harmony import */ var _speedy_gpu__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_714137__(/*! ./speedy-gpu */ "./src/gpu/speedy-gpu.js");
  16071. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_714137__(/*! ../utils/utils */ "./src/utils/utils.js");
  16072. /* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_714137__(/*! ../utils/errors */ "./src/utils/errors.js");
  16073. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_714137__(/*! ../utils/globals */ "./src/utils/globals.js");
  16074. /*
  16075. * speedy-vision.js
  16076. * GPU-accelerated Computer Vision for JavaScript
  16077. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  16078. *
  16079. * Licensed under the Apache License, Version 2.0 (the "License");
  16080. * you may not use this file except in compliance with the License.
  16081. * You may obtain a copy of the License at
  16082. *
  16083. * http://www.apache.org/licenses/LICENSE-2.0
  16084. *
  16085. * Unless required by applicable law or agreed to in writing, software
  16086. * distributed under the License is distributed on an "AS IS" BASIS,
  16087. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16088. * See the License for the specific language governing permissions and
  16089. * limitations under the License.
  16090. *
  16091. * speedy-texture.js
  16092. * A wrapper around WebGLTexture
  16093. */
  16094. /**
  16095. * Get a buffer filled with zeros
  16096. * @param {number} size number of bytes
  16097. * @returns {Uint8Array}
  16098. */
  16099. /*
  16100. const zeros = (function() {
  16101. let buffer = new Uint8Array(4);
  16102. return function(size) {
  16103. if(size > buffer.length)
  16104. buffer = new Uint8Array(size);
  16105. return buffer.subarray(0, size);
  16106. }
  16107. })();
  16108. */
  16109. /**
  16110. * A wrapper around WebGLTexture
  16111. */
  16112. class SpeedyTexture
  16113. {
  16114. /**
  16115. * Constructor
  16116. * @param {WebGL2RenderingContext} gl
  16117. * @param {number} width texture width in pixels
  16118. * @param {number} height texture height in pixels
  16119. * @param {number} [format]
  16120. * @param {number} [internalFormat]
  16121. * @param {number} [dataType]
  16122. * @param {number} [filter]
  16123. * @param {number} [wrap]
  16124. */
  16125. constructor(gl, width, height, format = gl.RGBA, internalFormat = gl.RGBA8, dataType = gl.UNSIGNED_BYTE, filter = gl.NEAREST, wrap = gl.MIRRORED_REPEAT)
  16126. {
  16127. /** @type {WebGL2RenderingContext} rendering context */
  16128. this._gl = gl;
  16129. /** @type {number} width of the texture */
  16130. this._width = Math.max(1, width | 0);
  16131. /** @type {number} height of the texture */
  16132. this._height = Math.max(1, height | 0);
  16133. /** @type {boolean} have we generated mipmaps for this texture? */
  16134. this._hasMipmaps = false;
  16135. /** @type {number} texture format */
  16136. this._format = format;
  16137. /** @type {number} internal format (usually a sized format) */
  16138. this._internalFormat = internalFormat;
  16139. /** @type {number} data type */
  16140. this._dataType = dataType;
  16141. /** @type {number} texture filtering (min & mag) */
  16142. this._filter = filter;
  16143. /** @type {number} texture wrapping */
  16144. this._wrap = wrap;
  16145. /** @type {WebGLTexture} internal texture object */
  16146. this._glTexture = SpeedyTexture._createTexture(this._gl, this._width, this._height, this._format, this._internalFormat, this._dataType, this._filter, this._wrap);
  16147. }
  16148. /**
  16149. * Releases the texture
  16150. * @returns {null}
  16151. */
  16152. release()
  16153. {
  16154. const gl = this._gl;
  16155. // already released?
  16156. if(this._glTexture == null)
  16157. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`The SpeedyTexture has already been released`);
  16158. // release resources
  16159. this.discardMipmaps();
  16160. gl.deleteTexture(this._glTexture);
  16161. this._glTexture = null;
  16162. this._width = this._height = 0;
  16163. // done!
  16164. return null;
  16165. }
  16166. /**
  16167. * Upload pixel data to the texture. The texture will be resized if needed.
  16168. * @param {TexImageSource} pixels
  16169. * @param {number} [width] in pixels
  16170. * @param {number} [height] in pixels
  16171. * @return {SpeedyTexture} this
  16172. */
  16173. upload(pixels, width = this._width, height = this._height)
  16174. {
  16175. const gl = this._gl;
  16176. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(width > 0 && height > 0);
  16177. this.discardMipmaps();
  16178. this._width = width;
  16179. this._height = height;
  16180. this._internalFormat = gl.RGBA8;
  16181. this._format = gl.RGBA;
  16182. this._dataType = gl.UNSIGNED_BYTE;
  16183. SpeedyTexture._upload(gl, this._glTexture, this._width, this._height, pixels, 0, this._format, this._internalFormat, this._dataType);
  16184. return this;
  16185. }
  16186. /**
  16187. * Clear the texture
  16188. * @returns {this}
  16189. */
  16190. clear()
  16191. {
  16192. const gl = this._gl;
  16193. // context loss?
  16194. if(gl.isContextLost())
  16195. return this;
  16196. // clear texture data
  16197. gl.bindTexture(gl.TEXTURE_2D, this._glTexture);
  16198. gl.texImage2D(gl.TEXTURE_2D, 0, this._internalFormat, this._width, this._height, 0, this._format, this._dataType, null);
  16199. gl.bindTexture(gl.TEXTURE_2D, null);
  16200. // no mipmaps
  16201. this.discardMipmaps();
  16202. // done!
  16203. return this;
  16204. }
  16205. /**
  16206. * Resize this texture. Its content will be lost!
  16207. * @param {number} width new width, in pixels
  16208. * @param {number} height new height, in pixels
  16209. * @returns {this}
  16210. */
  16211. resize(width, height)
  16212. {
  16213. const gl = this._gl;
  16214. // no need to resize?
  16215. if(this._width === width && this._height === height)
  16216. return this;
  16217. // validate size
  16218. width |= 0; height |= 0;
  16219. if(width > _utils_globals__WEBPACK_IMPORTED_MODULE_3__.MAX_TEXTURE_LENGTH || height > _utils_globals__WEBPACK_IMPORTED_MODULE_3__.MAX_TEXTURE_LENGTH)
  16220. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.NotSupportedError(`Maximum texture size exceeded. Using ${width} x ${height}, expected up to ${_utils_globals__WEBPACK_IMPORTED_MODULE_3__.MAX_TEXTURE_LENGTH} x ${_utils_globals__WEBPACK_IMPORTED_MODULE_3__.MAX_TEXTURE_LENGTH}.`);
  16221. else if(width < 1 || height < 1)
  16222. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalArgumentError(`Invalid texture size: ${width} x ${height}`);
  16223. // context loss?
  16224. if(gl.isContextLost())
  16225. return this;
  16226. // update dimensions
  16227. this._width = width;
  16228. this._height = height;
  16229. // resize
  16230. // Note: this is fast on Chrome, but seems slow on Firefox
  16231. gl.bindTexture(gl.TEXTURE_2D, this._glTexture);
  16232. gl.texImage2D(gl.TEXTURE_2D, 0, this._internalFormat, this._width, this._height, 0, this._format, this._dataType, null);
  16233. gl.bindTexture(gl.TEXTURE_2D, null);
  16234. // no mipmaps
  16235. this.discardMipmaps();
  16236. // done!
  16237. return this;
  16238. }
  16239. /**
  16240. * Generate mipmap
  16241. * @param {SpeedyDrawableTexture[]} [mipmap] custom texture for each mip level
  16242. * @returns {SpeedyTexture} this
  16243. */
  16244. generateMipmaps(mipmap = [])
  16245. {
  16246. const gl = this._gl;
  16247. // nothing to do
  16248. if(this._hasMipmaps)
  16249. return this;
  16250. // let the hardware compute the all levels of the pyramid, up to 1x1
  16251. // we also specify the TEXTURE_MIN_FILTER to be used from now on
  16252. gl.bindTexture(gl.TEXTURE_2D, this._glTexture);
  16253. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
  16254. gl.generateMipmap(gl.TEXTURE_2D);
  16255. gl.bindTexture(gl.TEXTURE_2D, null);
  16256. // accept custom textures
  16257. if(mipmap.length > 0) {
  16258. // expected number of mipmap levels according to the OpenGL ES 3.0 spec (sec 3.8.10.4)
  16259. const width = this.width, height = this.height;
  16260. const numMipmaps = 1 + Math.floor(Math.log2(Math.max(width, height)));
  16261. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(mipmap.length <= numMipmaps);
  16262. // verify the dimensions of each level
  16263. for(let level = 1; level < mipmap.length; level++) {
  16264. // use max(1, floor(size / 2^lod)), in accordance to
  16265. // the OpenGL ES 3.0 spec sec 3.8.10.4 (Mipmapping)
  16266. const w = Math.max(1, width >>> level);
  16267. const h = Math.max(1, height >>> level);
  16268. // verify the dimensions of this level
  16269. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(mipmap[level].width === w && mipmap[level].height === h);
  16270. // copy to mipmap
  16271. mipmap[level].copyTo(this, level);
  16272. }
  16273. }
  16274. // done!
  16275. this._hasMipmaps = true;
  16276. return this;
  16277. }
  16278. /**
  16279. * Invalidates previously generated mipmap, if any
  16280. */
  16281. discardMipmaps()
  16282. {
  16283. const gl = this._gl;
  16284. // nothing to do
  16285. if(!this._hasMipmaps)
  16286. return;
  16287. // reset the min filter
  16288. gl.bindTexture(gl.TEXTURE_2D, this._glTexture);
  16289. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this._filter);
  16290. gl.bindTexture(gl.TEXTURE_2D, null);
  16291. // done!
  16292. this._hasMipmaps = false;
  16293. }
  16294. /**
  16295. * Does this texture have a mipmap?
  16296. * @returns {boolean}
  16297. */
  16298. hasMipmaps()
  16299. {
  16300. return this._hasMipmaps;
  16301. }
  16302. /**
  16303. * Has this texture been released?
  16304. * @returns {boolean}
  16305. */
  16306. isReleased()
  16307. {
  16308. return this._glTexture == null;
  16309. }
  16310. /**
  16311. * The internal WebGLTexture
  16312. * @returns {WebGLTexture}
  16313. */
  16314. get glTexture()
  16315. {
  16316. return this._glTexture;
  16317. }
  16318. /**
  16319. * The width of the texture, in pixels
  16320. * @returns {number}
  16321. */
  16322. get width()
  16323. {
  16324. return this._width;
  16325. }
  16326. /**
  16327. * The height of the texture, in pixels
  16328. * @returns {number}
  16329. */
  16330. get height()
  16331. {
  16332. return this._height;
  16333. }
  16334. /**
  16335. * The WebGL Context
  16336. * @returns {WebGL2RenderingContext}
  16337. */
  16338. get gl()
  16339. {
  16340. return this._gl;
  16341. }
  16342. /**
  16343. * Create a WebGL texture
  16344. * @param {WebGL2RenderingContext} gl
  16345. * @param {number} width in pixels
  16346. * @param {number} height in pixels
  16347. * @param {number} format usually gl.RGBA
  16348. * @param {number} internalFormat usually gl.RGBA8
  16349. * @param {number} dataType usually gl.UNSIGNED_BYTE
  16350. * @param {number} filter usually gl.NEAREST or gl.LINEAR
  16351. * @param {number} wrap gl.REPEAT, gl.MIRRORED_REPEAT or gl.CLAMP_TO_EDGE
  16352. * @returns {WebGLTexture}
  16353. */
  16354. static _createTexture(gl, width, height, format, internalFormat, dataType, filter, wrap)
  16355. {
  16356. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(width > 0 && height > 0);
  16357. // create & bind texture
  16358. const texture = gl.createTexture();
  16359. gl.bindTexture(gl.TEXTURE_2D, texture);
  16360. // setup
  16361. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
  16362. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
  16363. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
  16364. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
  16365. //gl.texStorage2D(gl.TEXTURE_2D, 1, internalFormat, width, height);
  16366. gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, dataType, null);
  16367. // unbind & return
  16368. gl.bindTexture(gl.TEXTURE_2D, null);
  16369. return texture;
  16370. }
  16371. /**
  16372. * Upload pixel data to a WebGL texture
  16373. * @param {WebGL2RenderingContext} gl
  16374. * @param {WebGLTexture} texture
  16375. * @param {GLsizei} width texture width
  16376. * @param {GLsizei} height texture height
  16377. * @param {TexImageSource} pixels
  16378. * @param {GLint} lod mipmap level-of-detail
  16379. * @param {number} format
  16380. * @param {number} internalFormat
  16381. * @param {number} dataType
  16382. * @returns {WebGLTexture} texture
  16383. */
  16384. static _upload(gl, texture, width, height, pixels, lod, format, internalFormat, dataType)
  16385. {
  16386. // Prefer calling _upload() before gl.useProgram() to avoid the
  16387. // needless switching of GL programs internally. See also:
  16388. // https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices
  16389. gl.bindTexture(gl.TEXTURE_2D, texture);
  16390. /*
  16391. // slower than texImage2D, unlike the spec?
  16392. gl.texSubImage2D(gl.TEXTURE_2D, // target
  16393. lod, // mip level
  16394. 0, // x-offset
  16395. 0, // y-offset
  16396. width, // texture width
  16397. height, // texture height
  16398. gl.RGBA, // source format
  16399. gl.UNSIGNED_BYTE, // source type
  16400. pixels); // source data
  16401. */
  16402. gl.texImage2D(gl.TEXTURE_2D, // target
  16403. lod, // mip level
  16404. internalFormat, // internal format
  16405. width, // texture width
  16406. height, // texture height
  16407. 0, // border
  16408. format, // source format
  16409. dataType, // source type
  16410. pixels); // source data
  16411. gl.bindTexture(gl.TEXTURE_2D, null);
  16412. return texture;
  16413. }
  16414. }
  16415. /**
  16416. * A SpeedyTexture with a framebuffer
  16417. */
  16418. class SpeedyDrawableTexture extends SpeedyTexture
  16419. {
  16420. /**
  16421. * Constructor
  16422. * @param {WebGL2RenderingContext} gl
  16423. * @param {number} width texture width in pixels
  16424. * @param {number} height texture height in pixels
  16425. * @param {number} [format]
  16426. * @param {number} [internalFormat]
  16427. * @param {number} [dataType]
  16428. * @param {number} [filter]
  16429. * @param {number} [wrap]
  16430. */
  16431. constructor(gl, width, height, format = undefined, internalFormat = undefined, dataType = undefined, filter = undefined, wrap = undefined)
  16432. {
  16433. super(gl, width, height, format, internalFormat, dataType, filter, wrap);
  16434. /** @type {WebGLFramebuffer} framebuffer */
  16435. this._glFbo = SpeedyDrawableTexture._createFramebuffer(gl, this._glTexture);
  16436. }
  16437. /**
  16438. * Releases the texture
  16439. * @returns {null}
  16440. */
  16441. release()
  16442. {
  16443. const gl = this._gl;
  16444. // already released?
  16445. if(this._glFbo == null)
  16446. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.IllegalOperationError(`The SpeedyDrawableTexture has already been released`);
  16447. // release the framebuffer
  16448. gl.deleteFramebuffer(this._glFbo);
  16449. this._glFbo = null;
  16450. // release the SpeedyTexture
  16451. return super.release();
  16452. }
  16453. /**
  16454. * The internal WebGLFramebuffer
  16455. * @returns {WebGLFramebuffer}
  16456. */
  16457. get glFbo()
  16458. {
  16459. return this._glFbo;
  16460. }
  16461. /**
  16462. * Copy this texture into another
  16463. * (you may have to discard the mipmaps after calling this function)
  16464. * @param {SpeedyTexture} texture target texture
  16465. * @param {number} [lod] level-of-detail of the target texture
  16466. */
  16467. copyTo(texture, lod = 0)
  16468. {
  16469. const gl = this._gl;
  16470. // context loss?
  16471. if(gl.isContextLost())
  16472. return;
  16473. // compute texture size as max(1, floor(size / 2^lod)),
  16474. // in accordance to the OpenGL ES 3.0 spec sec 3.8.10.4
  16475. // (Mipmapping)
  16476. const pot = 1 << (lod |= 0);
  16477. const expectedWidth = Math.max(1, Math.floor(texture.width / pot));
  16478. const expectedHeight = Math.max(1, Math.floor(texture.height / pot));
  16479. // validate
  16480. _utils_utils__WEBPACK_IMPORTED_MODULE_1__.Utils.assert(this._width === expectedWidth && this._height === expectedHeight);
  16481. // copy to texture
  16482. SpeedyDrawableTexture._copyToTexture(gl, this._glFbo, texture.glTexture, 0, 0, this._width, this._height, lod);
  16483. }
  16484. /*
  16485. * Resize this texture
  16486. * @param {number} width new width, in pixels
  16487. * @param {number} height new height, in pixels
  16488. * @param {boolean} [preserveContent] should we preserve the content of the texture? EXPENSIVE!
  16489. * @returns {this}
  16490. */
  16491. /*resize(width, height, preserveContent = false)
  16492. {
  16493. const gl = this._gl;
  16494. // no need to preserve the content?
  16495. if(!preserveContent)
  16496. return super.resize(width, height);
  16497. // no need to resize?
  16498. if(this._width === width && this._height === height)
  16499. return this;
  16500. // validate size
  16501. width |= 0; height |= 0;
  16502. Utils.assert(width > 0 && height > 0);
  16503. // context loss?
  16504. if(gl.isContextLost())
  16505. return this;
  16506. // allocate new texture
  16507. const newTexture = SpeedyTexture._createTexture(gl, width, height);
  16508. // initialize the new texture with zeros to avoid a
  16509. // warning when calling copyTexSubImage2D() on Firefox
  16510. // this may not be very efficient?
  16511. SpeedyTexture._upload(gl, newTexture, width, height, zeros(width * height * 4)); // RGBA: 4 bytes per pixel
  16512. // copy the old texture to the new one
  16513. const oldWidth = this._width, oldHeight = this._height;
  16514. SpeedyDrawableTexture._copyToTexture(gl, this._glFbo, newTexture, 0, 0, Math.min(width, oldWidth), Math.min(height, oldHeight), 0);
  16515. // bind FBO
  16516. gl.bindFramebuffer(gl.FRAMEBUFFER, this._glFbo);
  16517. // invalidate old data (is this needed?)
  16518. gl.invalidateFramebuffer(gl.FRAMEBUFFER, [gl.COLOR_ATTACHMENT0]);
  16519. // attach the new texture to the existing framebuffer
  16520. gl.framebufferTexture2D(gl.FRAMEBUFFER, // target
  16521. gl.COLOR_ATTACHMENT0, // color buffer
  16522. gl.TEXTURE_2D, // tex target
  16523. newTexture, // texture
  16524. 0); // mipmap level
  16525. // unbind FBO
  16526. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  16527. // release the old texture and replace it
  16528. gl.deleteTexture(this._glTexture);
  16529. this._glTexture = newTexture;
  16530. // update dimensions & discard mipmaps
  16531. this.discardMipmaps();
  16532. this._width = width;
  16533. this._height = height;
  16534. // done!
  16535. return this;
  16536. }
  16537. */
  16538. /**
  16539. * Clear the texture
  16540. * @returns {this}
  16541. */
  16542. clear()
  16543. {
  16544. //
  16545. // When we pass null to texImage2D(), it seems that Firefox
  16546. // doesn't clear the texture. Instead, it displays this warning:
  16547. //
  16548. // "WebGL warning: drawArraysInstanced:
  16549. // Tex image TEXTURE_2D level 0 is incurring lazy initialization."
  16550. //
  16551. // Here is a workaround:
  16552. //
  16553. return this.clearToColor(0, 0, 0, 0);
  16554. }
  16555. /**
  16556. * Clear the texture to a color
  16557. * @param {number} r red component, a value in [0,1]
  16558. * @param {number} g green component, a value in [0,1]
  16559. * @param {number} b blue component, a value in [0,1]
  16560. * @param {number} a alpha component, a value in [0,1]
  16561. * @returns {this}
  16562. */
  16563. clearToColor(r, g, b, a)
  16564. {
  16565. const gl = this._gl;
  16566. // context loss?
  16567. if(gl.isContextLost())
  16568. return this;
  16569. // clamp parameters
  16570. r = Math.max(0.0, Math.min(+r, 1.0));
  16571. g = Math.max(0.0, Math.min(+g, 1.0));
  16572. b = Math.max(0.0, Math.min(+b, 1.0));
  16573. a = Math.max(0.0, Math.min(+a, 1.0));
  16574. // discard mipmaps, if any
  16575. this.discardMipmaps();
  16576. // clear the texture
  16577. gl.bindFramebuffer(gl.FRAMEBUFFER, this._glFbo);
  16578. gl.viewport(0, 0, this._width, this._height);
  16579. gl.clearColor(r, g, b, a);
  16580. gl.clear(gl.COLOR_BUFFER_BIT);
  16581. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  16582. // done!
  16583. return this;
  16584. }
  16585. /**
  16586. * Create a FBO associated with an existing texture
  16587. * @param {WebGL2RenderingContext} gl
  16588. * @param {WebGLTexture} texture
  16589. * @returns {WebGLFramebuffer}
  16590. */
  16591. static _createFramebuffer(gl, texture)
  16592. {
  16593. const fbo = gl.createFramebuffer();
  16594. // setup framebuffer
  16595. gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  16596. gl.framebufferTexture2D(gl.FRAMEBUFFER, // target
  16597. gl.COLOR_ATTACHMENT0, // color buffer
  16598. gl.TEXTURE_2D, // tex target
  16599. texture, // texture
  16600. 0); // mipmap level
  16601. // check for errors
  16602. const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
  16603. if(status != gl.FRAMEBUFFER_COMPLETE) {
  16604. const error = (() => (([
  16605. 'FRAMEBUFFER_UNSUPPORTED',
  16606. 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT',
  16607. 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS',
  16608. 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT',
  16609. 'FRAMEBUFFER_INCOMPLETE_MULTISAMPLE'
  16610. ].filter(err => gl[err] === status))[0] || 'unknown error'))();
  16611. throw new _utils_errors__WEBPACK_IMPORTED_MODULE_2__.GLError(`Can't create framebuffer: ${error} (${status})`);
  16612. }
  16613. // unbind & return
  16614. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  16615. return fbo;
  16616. }
  16617. /**
  16618. * Copy data from a framebuffer to a texture
  16619. * @param {WebGL2RenderingContext} gl
  16620. * @param {WebGLFramebuffer} fbo we'll read the data from this
  16621. * @param {WebGLTexture} texture destination texture
  16622. * @param {GLint} x xpos (where to start copying)
  16623. * @param {GLint} y ypos (where to start copying)
  16624. * @param {GLsizei} width width of the texture
  16625. * @param {GLsizei} height height of the texture
  16626. * @param {GLint} [lod] mipmap level-of-detail
  16627. * @returns {WebGLTexture} texture
  16628. */
  16629. static _copyToTexture(gl, fbo, texture, x, y, width, height, lod = 0)
  16630. {
  16631. //gl.activeTexture(gl.TEXTURE0);
  16632. gl.bindTexture(gl.TEXTURE_2D, texture);
  16633. gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  16634. gl.copyTexSubImage2D(
  16635. gl.TEXTURE_2D, // target
  16636. lod, // mipmap level
  16637. 0, // xoffset
  16638. 0, // yoffset
  16639. x, // xpos (where to start copying)
  16640. y, // ypos (where to start copying)
  16641. width, // width of the texture
  16642. height // height of the texture
  16643. );
  16644. /*
  16645. gl.copyTexImage2D(
  16646. gl.TEXTURE_2D, // target
  16647. lod, // mipmap level
  16648. gl.RGBA, // internal format
  16649. x, // xpos (where to start copying)
  16650. y, // ypos (where to start copying)
  16651. width, // width of the texture
  16652. height, // height of the texture
  16653. 0 // border
  16654. );
  16655. */
  16656. gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  16657. gl.bindTexture(gl.TEXTURE_2D, null);
  16658. return texture;
  16659. }
  16660. }
  16661. /***/ }),
  16662. /***/ "./src/utils/asap.js":
  16663. /*!***************************!*\
  16664. !*** ./src/utils/asap.js ***!
  16665. \***************************/
  16666. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_737678__) => {
  16667. "use strict";
  16668. __nested_webpack_require_737678__.r(__webpack_exports__);
  16669. /* harmony export */ __nested_webpack_require_737678__.d(__webpack_exports__, {
  16670. /* harmony export */ "asap": () => (/* binding */ asap)
  16671. /* harmony export */ });
  16672. /*
  16673. * speedy-vision.js
  16674. * GPU-accelerated Computer Vision for JavaScript
  16675. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  16676. *
  16677. * Licensed under the Apache License, Version 2.0 (the "License");
  16678. * you may not use this file except in compliance with the License.
  16679. * You may obtain a copy of the License at
  16680. *
  16681. * http://www.apache.org/licenses/LICENSE-2.0
  16682. *
  16683. * Unless required by applicable law or agreed to in writing, software
  16684. * distributed under the License is distributed on an "AS IS" BASIS,
  16685. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16686. * See the License for the specific language governing permissions and
  16687. * limitations under the License.
  16688. *
  16689. * asap.js
  16690. * Schedule a function to run "as soon as possible"
  16691. */
  16692. /** callbacks */
  16693. const callbacks = /** @type {Function[]} */ ( [] );
  16694. /** arguments to be passed to the callbacks */
  16695. const args = /** @type {any[][]} */ ( [] );
  16696. /** asap key */
  16697. const ASAP_KEY = 'asap' + Math.random().toString(36).substr(1);
  16698. // Register an event listener
  16699. window.addEventListener('message', event => {
  16700. if(event.source !== window || event.data !== ASAP_KEY)
  16701. return;
  16702. event.stopPropagation();
  16703. if(callbacks.length == 0)
  16704. return;
  16705. const fn = callbacks.pop();
  16706. const argArray = args.pop();
  16707. fn.apply(undefined, argArray);
  16708. }, true);
  16709. /**
  16710. * Schedule a function to run "as soon as possible"
  16711. * @param {Function} fn callback
  16712. * @param {any[]} params optional parameters
  16713. */
  16714. function asap(fn, ...params)
  16715. {
  16716. callbacks.unshift(fn);
  16717. args.unshift(params);
  16718. window.postMessage(ASAP_KEY, '*');
  16719. }
  16720. /***/ }),
  16721. /***/ "./src/utils/errors.js":
  16722. /*!*****************************!*\
  16723. !*** ./src/utils/errors.js ***!
  16724. \*****************************/
  16725. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_739725__) => {
  16726. "use strict";
  16727. __nested_webpack_require_739725__.r(__webpack_exports__);
  16728. /* harmony export */ __nested_webpack_require_739725__.d(__webpack_exports__, {
  16729. /* harmony export */ "SpeedyError": () => (/* binding */ SpeedyError),
  16730. /* harmony export */ "NotSupportedError": () => (/* binding */ NotSupportedError),
  16731. /* harmony export */ "NotImplementedError": () => (/* binding */ NotImplementedError),
  16732. /* harmony export */ "GLError": () => (/* binding */ GLError),
  16733. /* harmony export */ "AbstractMethodError": () => (/* binding */ AbstractMethodError),
  16734. /* harmony export */ "IllegalArgumentError": () => (/* binding */ IllegalArgumentError),
  16735. /* harmony export */ "IllegalOperationError": () => (/* binding */ IllegalOperationError),
  16736. /* harmony export */ "OutOfMemoryError": () => (/* binding */ OutOfMemoryError),
  16737. /* harmony export */ "FileNotFoundError": () => (/* binding */ FileNotFoundError),
  16738. /* harmony export */ "TimeoutError": () => (/* binding */ TimeoutError),
  16739. /* harmony export */ "ParseError": () => (/* binding */ ParseError),
  16740. /* harmony export */ "AssertionError": () => (/* binding */ AssertionError),
  16741. /* harmony export */ "AccessDeniedError": () => (/* binding */ AccessDeniedError),
  16742. /* harmony export */ "WebAssemblyError": () => (/* binding */ WebAssemblyError)
  16743. /* harmony export */ });
  16744. /*
  16745. * speedy-vision.js
  16746. * GPU-accelerated Computer Vision for JavaScript
  16747. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  16748. *
  16749. * Licensed under the Apache License, Version 2.0 (the "License");
  16750. * you may not use this file except in compliance with the License.
  16751. * You may obtain a copy of the License at
  16752. *
  16753. * http://www.apache.org/licenses/LICENSE-2.0
  16754. *
  16755. * Unless required by applicable law or agreed to in writing, software
  16756. * distributed under the License is distributed on an "AS IS" BASIS,
  16757. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16758. * See the License for the specific language governing permissions and
  16759. * limitations under the License.
  16760. *
  16761. * errors.js
  16762. * Error classes
  16763. */
  16764. /** @typedef {SpeedyError|Error|null} SpeedyErrorCause */
  16765. /**
  16766. * Generic error class for Speedy
  16767. */
  16768. class SpeedyError extends Error
  16769. {
  16770. /**
  16771. * Class constructor
  16772. * @param {string} message message text
  16773. * @param {SpeedyErrorCause} [cause] cause of the error
  16774. */
  16775. constructor(message, cause = null)
  16776. {
  16777. super([
  16778. message,
  16779. cause ? cause.toString() : '[speedy-vision.js]'
  16780. ].join('\n-> '));
  16781. /** @type {SpeedyErrorCause} cause of the error */
  16782. this._cause = cause;
  16783. }
  16784. /**
  16785. * Error name
  16786. * @returns {string}
  16787. */
  16788. get name()
  16789. {
  16790. return this.constructor.name;
  16791. }
  16792. /**
  16793. * Set error name (ignored)
  16794. * @param {string} _ ignored
  16795. */
  16796. set name(_)
  16797. {
  16798. void(0);
  16799. }
  16800. /**
  16801. * Get the cause of the error. Available if
  16802. * it has been specified in the constructor
  16803. * @returns {SpeedyErrorCause}
  16804. */
  16805. get cause()
  16806. {
  16807. return this._cause;
  16808. }
  16809. }
  16810. /**
  16811. * Unsupported operation error
  16812. * The requested operation is not supported
  16813. */
  16814. class NotSupportedError extends SpeedyError
  16815. {
  16816. /**
  16817. * Class constructor
  16818. * @param {string} [message] additional text
  16819. * @param {SpeedyErrorCause} [cause] cause of the error
  16820. */
  16821. constructor(message = '', cause = null)
  16822. {
  16823. super(`Unsupported operation. ${message}`, cause);
  16824. }
  16825. }
  16826. /**
  16827. * Not implemented error
  16828. * The called method is not implemented
  16829. */
  16830. class NotImplementedError extends SpeedyError
  16831. {
  16832. /**
  16833. * Class constructor
  16834. * @param {string} [message] additional text
  16835. * @param {SpeedyErrorCause} [cause] cause of the error
  16836. */
  16837. constructor(message = '', cause = null)
  16838. {
  16839. super(`Method not implemented. ${message}`, cause);
  16840. }
  16841. }
  16842. /**
  16843. * WebGL error
  16844. */
  16845. class GLError extends SpeedyError
  16846. {
  16847. /**
  16848. * Class constructor
  16849. * @param {string} [message] additional text
  16850. * @param {SpeedyErrorCause} [cause] cause of the error
  16851. */
  16852. constructor(message = '', cause = null)
  16853. {
  16854. super(`WebGL error. ${message}`, cause);
  16855. }
  16856. /**
  16857. * Get an error object describing the latest WebGL error
  16858. * @param {WebGL2RenderingContext} gl
  16859. * @returns {GLError}
  16860. */
  16861. static from(gl)
  16862. {
  16863. const recognizedErrors = [
  16864. 'NO_ERROR',
  16865. 'INVALID_ENUM',
  16866. 'INVALID_VALUE',
  16867. 'INVALID_OPERATION',
  16868. 'INVALID_FRAMEBUFFER_OPERATION',
  16869. 'OUT_OF_MEMORY',
  16870. 'CONTEXT_LOST_WEBGL',
  16871. ];
  16872. const glError = gl.getError();
  16873. const message = recognizedErrors.find(error => gl[error] == glError) || 'Unknown';
  16874. return new GLError(message);
  16875. }
  16876. }
  16877. /**
  16878. * AbstractMethodError
  16879. * Thrown when one tries to call an abstract method
  16880. */
  16881. class AbstractMethodError extends SpeedyError
  16882. {
  16883. /**
  16884. * Class constructor
  16885. * @param {string} [message] additional text
  16886. * @param {SpeedyErrorCause} [cause] cause of the error
  16887. */
  16888. constructor(message = '', cause = null)
  16889. {
  16890. super(`Can't call abstract method. ${message}`, cause);
  16891. }
  16892. }
  16893. /**
  16894. * Illegal argument error
  16895. * A method has received one or more illegal arguments
  16896. */
  16897. class IllegalArgumentError extends SpeedyError
  16898. {
  16899. /**
  16900. * Class constructor
  16901. * @param {string} [message] additional text
  16902. * @param {SpeedyErrorCause} [cause] cause of the error
  16903. */
  16904. constructor(message = '', cause = null)
  16905. {
  16906. super(`Illegal argument. ${message}`, cause);
  16907. }
  16908. }
  16909. /**
  16910. * Illegal operation error
  16911. * The method arguments are valid, but the method can't
  16912. * be called due to the current the state of the object
  16913. */
  16914. class IllegalOperationError extends SpeedyError
  16915. {
  16916. /**
  16917. * Class constructor
  16918. * @param {string} [message] additional text
  16919. * @param {SpeedyErrorCause} [cause] cause of the error
  16920. */
  16921. constructor(message = '', cause = null)
  16922. {
  16923. super(`Illegal operation. ${message}`, cause);
  16924. }
  16925. }
  16926. /**
  16927. * Out of memory
  16928. */
  16929. class OutOfMemoryError extends SpeedyError
  16930. {
  16931. /**
  16932. * Class constructor
  16933. * @param {string} [message] additional text
  16934. * @param {SpeedyErrorCause} [cause] cause of the error
  16935. */
  16936. constructor(message = '', cause = null)
  16937. {
  16938. super(`Out of memory. ${message}`, cause);
  16939. }
  16940. }
  16941. /**
  16942. * File not found error
  16943. */
  16944. class FileNotFoundError extends SpeedyError
  16945. {
  16946. /**
  16947. * Class constructor
  16948. * @param {string} [message] additional text
  16949. * @param {SpeedyErrorCause} [cause] cause of the error
  16950. */
  16951. constructor(message = '', cause = null)
  16952. {
  16953. super(`File not found. ${message}`, cause);
  16954. }
  16955. }
  16956. /**
  16957. * Timeout error
  16958. */
  16959. class TimeoutError extends SpeedyError
  16960. {
  16961. /**
  16962. * Class constructor
  16963. * @param {string} [message] additional text
  16964. * @param {SpeedyErrorCause} [cause] cause of the error
  16965. */
  16966. constructor(message = '', cause = null)
  16967. {
  16968. super(`Timeout error. ${message}`, cause);
  16969. }
  16970. }
  16971. /**
  16972. * Parse error
  16973. */
  16974. class ParseError extends SpeedyError
  16975. {
  16976. /**
  16977. * Class constructor
  16978. * @param {string} [message] additional text
  16979. * @param {SpeedyErrorCause} [cause] cause of the error
  16980. */
  16981. constructor(message = '', cause = null)
  16982. {
  16983. super(`Parse error. ${message}`, cause);
  16984. }
  16985. }
  16986. /**
  16987. * Assertion error
  16988. */
  16989. class AssertionError extends SpeedyError
  16990. {
  16991. /**
  16992. * Class constructor
  16993. * @param {string} [message] additional text
  16994. * @param {SpeedyErrorCause} [cause] cause of the error
  16995. */
  16996. constructor(message = '', cause = null)
  16997. {
  16998. super(`Assertion failed. ${message}`, cause);
  16999. }
  17000. }
  17001. /**
  17002. * Access denied
  17003. */
  17004. class AccessDeniedError extends SpeedyError
  17005. {
  17006. /**
  17007. * Class constructor
  17008. * @param {string} [message] additional text
  17009. * @param {SpeedyErrorCause} [cause] cause of the error
  17010. */
  17011. constructor(message = '', cause = null)
  17012. {
  17013. super(`Access denied. ${message}`, cause);
  17014. }
  17015. }
  17016. /**
  17017. * WebAssembly error
  17018. */
  17019. class WebAssemblyError extends SpeedyError
  17020. {
  17021. /**
  17022. * Class constructor
  17023. * @param {string} [message] additional text
  17024. * @param {SpeedyErrorCause} [cause] cause of the error
  17025. */
  17026. constructor(message = '', cause = null)
  17027. {
  17028. super(`WebAssembly error. ${message}`, cause);
  17029. }
  17030. }
  17031. /***/ }),
  17032. /***/ "./src/utils/fps-counter.js":
  17033. /*!**********************************!*\
  17034. !*** ./src/utils/fps-counter.js ***!
  17035. \**********************************/
  17036. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_748303__) => {
  17037. "use strict";
  17038. __nested_webpack_require_748303__.r(__webpack_exports__);
  17039. /* harmony export */ __nested_webpack_require_748303__.d(__webpack_exports__, {
  17040. /* harmony export */ "FPSCounter": () => (/* binding */ FPSCounter)
  17041. /* harmony export */ });
  17042. /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_748303__(/*! ./errors */ "./src/utils/errors.js");
  17043. /*
  17044. * speedy-vision.js
  17045. * GPU-accelerated Computer Vision for JavaScript
  17046. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  17047. *
  17048. * Licensed under the Apache License, Version 2.0 (the "License");
  17049. * you may not use this file except in compliance with the License.
  17050. * You may obtain a copy of the License at
  17051. *
  17052. * http://www.apache.org/licenses/LICENSE-2.0
  17053. *
  17054. * Unless required by applicable law or agreed to in writing, software
  17055. * distributed under the License is distributed on an "AS IS" BASIS,
  17056. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17057. * See the License for the specific language governing permissions and
  17058. * limitations under the License.
  17059. *
  17060. * fps-counter.js
  17061. * A FPS counter
  17062. */
  17063. /** @const {number} update interval in milliseconds */
  17064. const UPDATE_INTERVAL = 500;
  17065. /** @type {FPSCounter|null} Singleton */
  17066. let instance = null;
  17067. /**
  17068. * FPS counter
  17069. */
  17070. class FPSCounter
  17071. {
  17072. /**
  17073. * Creates a new FPSCounter
  17074. * @private
  17075. */
  17076. constructor()
  17077. {
  17078. /** @type {number} current FPS rate */
  17079. this._fps = 60;
  17080. /** @type {number} frame counter */
  17081. this._frames = 0;
  17082. /** @type {number} update interval in milliseconds */
  17083. this._updateInterval = UPDATE_INTERVAL;
  17084. /** @type {number} time of the last update */
  17085. this._lastUpdate = performance.now();
  17086. /** @type {function(): void} bound update function */
  17087. this._boundUpdate = this._update.bind(this);
  17088. // this should never happen...
  17089. if(instance !== null)
  17090. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.IllegalOperationError(`Can't have multiple instances of FPSCounter`);
  17091. // start FPS counter
  17092. this._boundUpdate();
  17093. }
  17094. /**
  17095. * Gets an instance of the FPS counter.
  17096. * We use lazy loading, i.e., we will not
  17097. * create a FPS counter unless we need to!
  17098. * @returns {FPSCounter}
  17099. */
  17100. static get instance()
  17101. {
  17102. if(instance === null)
  17103. instance = new FPSCounter();
  17104. return instance;
  17105. }
  17106. /**
  17107. * Get the FPS rate
  17108. * @returns {number} frames per second
  17109. */
  17110. get fps()
  17111. {
  17112. return this._fps;
  17113. }
  17114. /**
  17115. * Updates the FPS counter
  17116. */
  17117. _update()
  17118. {
  17119. const now = performance.now();
  17120. const deltaTime = now - this._lastUpdate;
  17121. if(deltaTime >= this._updateInterval) {
  17122. this._fps = Math.round(this._frames / (deltaTime * 0.001));
  17123. this._frames = 0;
  17124. this._lastUpdate = now;
  17125. }
  17126. this._frames++;
  17127. requestAnimationFrame(this._boundUpdate);
  17128. }
  17129. }
  17130. /***/ }),
  17131. /***/ "./src/utils/globals.js":
  17132. /*!******************************!*\
  17133. !*** ./src/utils/globals.js ***!
  17134. \******************************/
  17135. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_751526__) => {
  17136. "use strict";
  17137. __nested_webpack_require_751526__.r(__webpack_exports__);
  17138. /* harmony export */ __nested_webpack_require_751526__.d(__webpack_exports__, {
  17139. /* harmony export */ "PYRAMID_MAX_LEVELS": () => (/* binding */ PYRAMID_MAX_LEVELS),
  17140. /* harmony export */ "LOG2_PYRAMID_MAX_SCALE": () => (/* binding */ LOG2_PYRAMID_MAX_SCALE),
  17141. /* harmony export */ "PYRAMID_MAX_SCALE": () => (/* binding */ PYRAMID_MAX_SCALE),
  17142. /* harmony export */ "FIX_BITS": () => (/* binding */ FIX_BITS),
  17143. /* harmony export */ "FIX_RESOLUTION": () => (/* binding */ FIX_RESOLUTION),
  17144. /* harmony export */ "MAX_TEXTURE_LENGTH": () => (/* binding */ MAX_TEXTURE_LENGTH),
  17145. /* harmony export */ "MIN_KEYPOINT_SIZE": () => (/* binding */ MIN_KEYPOINT_SIZE),
  17146. /* harmony export */ "MIN_ENCODER_LENGTH": () => (/* binding */ MIN_ENCODER_LENGTH),
  17147. /* harmony export */ "MAX_ENCODER_CAPACITY": () => (/* binding */ MAX_ENCODER_CAPACITY),
  17148. /* harmony export */ "DEFAULT_ENCODER_CAPACITY": () => (/* binding */ DEFAULT_ENCODER_CAPACITY),
  17149. /* harmony export */ "LOG2_MAX_DESCRIPTOR_SIZE": () => (/* binding */ LOG2_MAX_DESCRIPTOR_SIZE),
  17150. /* harmony export */ "MAX_DESCRIPTOR_SIZE": () => (/* binding */ MAX_DESCRIPTOR_SIZE),
  17151. /* harmony export */ "MATCH_INDEX_BITS": () => (/* binding */ MATCH_INDEX_BITS),
  17152. /* harmony export */ "MATCH_INDEX_MASK": () => (/* binding */ MATCH_INDEX_MASK),
  17153. /* harmony export */ "MATCH_MAX_INDEX": () => (/* binding */ MATCH_MAX_INDEX),
  17154. /* harmony export */ "MATCH_MAX_DISTANCE": () => (/* binding */ MATCH_MAX_DISTANCE),
  17155. /* harmony export */ "LITTLE_ENDIAN": () => (/* binding */ LITTLE_ENDIAN)
  17156. /* harmony export */ });
  17157. /*
  17158. * speedy-vision.js
  17159. * GPU-accelerated Computer Vision for JavaScript
  17160. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  17161. *
  17162. * Licensed under the Apache License, Version 2.0 (the "License");
  17163. * you may not use this file except in compliance with the License.
  17164. * You may obtain a copy of the License at
  17165. *
  17166. * http://www.apache.org/licenses/LICENSE-2.0
  17167. *
  17168. * Unless required by applicable law or agreed to in writing, software
  17169. * distributed under the License is distributed on an "AS IS" BASIS,
  17170. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17171. * See the License for the specific language governing permissions and
  17172. * limitations under the License.
  17173. *
  17174. * globals.js
  17175. * Global constants
  17176. */
  17177. // -----------------------------------------------------------------
  17178. // IMAGE PYRAMIDS & SCALE-SPACE
  17179. // -----------------------------------------------------------------
  17180. /** @type {number} The maximum number of levels in a pyramid, considering a scale factor of 2x between levels */
  17181. const PYRAMID_MAX_LEVELS = 8;
  17182. /** @type {number} The base-2 logarithm of PYRAMID_MAX_SCALE */
  17183. const LOG2_PYRAMID_MAX_SCALE = 0;
  17184. /** @type {number} The maximum supported scale for a pyramid level */
  17185. const PYRAMID_MAX_SCALE = 1 << LOG2_PYRAMID_MAX_SCALE;
  17186. // -----------------------------------------------------------------
  17187. // FIXED-POINT MATH
  17188. // -----------------------------------------------------------------
  17189. /** @type {number} How many bits do we use to store fractional data? */
  17190. const FIX_BITS = 3; // step size: 0.125 = 1/2^FIX_BITS
  17191. /** @type {number} Fixed-point resolution */
  17192. const FIX_RESOLUTION = 1 << FIX_BITS; // float(2^(FIX_BITS))
  17193. // -----------------------------------------------------------------
  17194. // TEXTURE LIMITS
  17195. // -----------------------------------------------------------------
  17196. /** @type {number} Maximum texture length (width, height) */
  17197. const MAX_TEXTURE_LENGTH = (1 << (16 - FIX_BITS)) - 1; // must be 2^n - 1 due to keypoint encoding
  17198. // -----------------------------------------------------------------
  17199. // KEYPOINTS
  17200. // -----------------------------------------------------------------
  17201. /** @type {number} Size of a keypoint header, in bytes (must be divisible by 4) */
  17202. const MIN_KEYPOINT_SIZE = 8;
  17203. /** @type {number} Minimum length of a keypoint encoder, in pixels (encodes at least 1 keypoint) */
  17204. const MIN_ENCODER_LENGTH = 2; // capacity computations are based on this // Math.ceil(Math.sqrt(MIN_KEYPOINT_SIZE / 4));
  17205. /** @type {number} Maximum number of keypoints we can encode (the actual length of the encoder may vary) */
  17206. const MAX_ENCODER_CAPACITY = 8192;
  17207. /** @type {number} Default capacity of a keypoint encoder (64x64 texture with 2 pixels per keypoint) */
  17208. const DEFAULT_ENCODER_CAPACITY = 2048;
  17209. /** @type {number} log2 of MAX_DESCRIPTOR_SIZE */
  17210. const LOG2_MAX_DESCRIPTOR_SIZE = 6;
  17211. /** @type {number} maximum size of a keypoint descriptor, in bytes */
  17212. const MAX_DESCRIPTOR_SIZE = 1 << LOG2_MAX_DESCRIPTOR_SIZE;
  17213. /** @type {number} How many bits will we use when encoding the index of a keypoint match? */
  17214. const MATCH_INDEX_BITS = 32 - (LOG2_MAX_DESCRIPTOR_SIZE + 3); // 32 - log2(MAX_DESCRIPTOR_SIZE * 8)
  17215. /** @type {number} Bitwise mask to extract a keypoint index from an encoded match */
  17216. const MATCH_INDEX_MASK = (1 << MATCH_INDEX_BITS) - 1;
  17217. /** @type {number} Maximum size of the database of keypoints for matching */
  17218. const MATCH_MAX_INDEX = (1 << MATCH_INDEX_BITS) - 1;
  17219. /** @type {number} The maximum distance that can be stored in a match */
  17220. const MATCH_MAX_DISTANCE = (1 << (32 - MATCH_INDEX_BITS)) - 1;
  17221. // -----------------------------------------------------------------
  17222. // MISC
  17223. // -----------------------------------------------------------------
  17224. /** @type {boolean} Are we in a little-endian machine? */
  17225. const LITTLE_ENDIAN = (function() {
  17226. return 0xCAFE === (new Uint16Array(new Uint8Array([0xFE, 0xCA]).buffer))[0];
  17227. })();
  17228. /***/ }),
  17229. /***/ "./src/utils/observable.js":
  17230. /*!*********************************!*\
  17231. !*** ./src/utils/observable.js ***!
  17232. \*********************************/
  17233. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_757299__) => {
  17234. "use strict";
  17235. __nested_webpack_require_757299__.r(__webpack_exports__);
  17236. /* harmony export */ __nested_webpack_require_757299__.d(__webpack_exports__, {
  17237. /* harmony export */ "Observable": () => (/* binding */ Observable)
  17238. /* harmony export */ });
  17239. /*
  17240. * speedy-vision.js
  17241. * GPU-accelerated Computer Vision for JavaScript
  17242. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  17243. *
  17244. * Licensed under the Apache License, Version 2.0 (the "License");
  17245. * you may not use this file except in compliance with the License.
  17246. * You may obtain a copy of the License at
  17247. *
  17248. * http://www.apache.org/licenses/LICENSE-2.0
  17249. *
  17250. * Unless required by applicable law or agreed to in writing, software
  17251. * distributed under the License is distributed on an "AS IS" BASIS,
  17252. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17253. * See the License for the specific language governing permissions and
  17254. * limitations under the License.
  17255. *
  17256. * observable.js
  17257. * Observer design pattern
  17258. */
  17259. /**
  17260. * Implementation of the Observer design pattern
  17261. * @abstract
  17262. */
  17263. class Observable
  17264. {
  17265. /**
  17266. * Constructor
  17267. */
  17268. constructor()
  17269. {
  17270. /** @type {Function[]} subscribers / callbacks */
  17271. this._subscribers = [];
  17272. /** @type {object[]} "this" pointers */
  17273. this._thisptr = [];
  17274. /** @type {Array<any[]>} function arguments */
  17275. this._args = [];
  17276. }
  17277. /**
  17278. * Add subscriber
  17279. * @param {Function} fn callback
  17280. * @param {object} [thisptr] "this" pointer to be used when invoking the callback
  17281. * @param {...any} args arguments to be passed to the callback
  17282. */
  17283. subscribe(fn, thisptr, ...args)
  17284. {
  17285. this._subscribers.push(fn);
  17286. this._thisptr.push(thisptr);
  17287. this._args.push(args);
  17288. }
  17289. /**
  17290. * Remove subscriber
  17291. * @param {Function} fn previously added callback
  17292. * @param {object} [thisptr] "this" pointer
  17293. */
  17294. unsubscribe(fn, thisptr)
  17295. {
  17296. for(let j = this._subscribers.length - 1; j >= 0; j--) {
  17297. if(this._subscribers[j] === fn && this._thisptr[j] === thisptr) {
  17298. this._subscribers.splice(j, 1);
  17299. this._thisptr.splice(j, 1);
  17300. this._args.splice(j, 1);
  17301. break;
  17302. }
  17303. }
  17304. }
  17305. /**
  17306. * Notify all subscribers about a state change
  17307. * @protected
  17308. */
  17309. _notify()
  17310. {
  17311. for(let i = 0; i < this._subscribers.length; i++)
  17312. this._subscribers[i].call(this._thisptr[i], ...(this._args[i]));
  17313. }
  17314. }
  17315. /***/ }),
  17316. /***/ "./src/utils/types.js":
  17317. /*!****************************!*\
  17318. !*** ./src/utils/types.js ***!
  17319. \****************************/
  17320. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_760030__) => {
  17321. "use strict";
  17322. __nested_webpack_require_760030__.r(__webpack_exports__);
  17323. /* harmony export */ __nested_webpack_require_760030__.d(__webpack_exports__, {
  17324. /* harmony export */ "MediaType": () => (/* binding */ MediaType),
  17325. /* harmony export */ "ImageFormat": () => (/* binding */ ImageFormat),
  17326. /* harmony export */ "PixelComponent": () => (/* binding */ PixelComponent),
  17327. /* harmony export */ "ColorComponentId": () => (/* binding */ ColorComponentId)
  17328. /* harmony export */ });
  17329. /*
  17330. * speedy-vision.js
  17331. * GPU-accelerated Computer Vision for JavaScript
  17332. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  17333. *
  17334. * Licensed under the Apache License, Version 2.0 (the "License");
  17335. * you may not use this file except in compliance with the License.
  17336. * You may obtain a copy of the License at
  17337. *
  17338. * http://www.apache.org/licenses/LICENSE-2.0
  17339. *
  17340. * Unless required by applicable law or agreed to in writing, software
  17341. * distributed under the License is distributed on an "AS IS" BASIS,
  17342. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17343. * See the License for the specific language governing permissions and
  17344. * limitations under the License.
  17345. *
  17346. * types.js
  17347. * Types & formats
  17348. */
  17349. /**
  17350. * Media types
  17351. * @enum {Symbol}
  17352. */
  17353. const MediaType = Object.freeze({
  17354. Image: Symbol('Image'),
  17355. Video: Symbol('Video'),
  17356. Canvas: Symbol('Canvas'),
  17357. Bitmap: Symbol('Bitmap'),
  17358. });
  17359. /**
  17360. * Image formats
  17361. * @enum {Symbol}
  17362. */
  17363. const ImageFormat = Object.freeze({
  17364. RGBA: Symbol('RGBA'),
  17365. GREY: Symbol('GREY'),
  17366. });
  17367. /**
  17368. * Pixel component (bitwise flags)
  17369. * @typedef {number} PixelComponent
  17370. */
  17371. const PixelComponent = Object.freeze({
  17372. RED: 1,
  17373. GREEN: 2,
  17374. BLUE: 4,
  17375. ALPHA: 8,
  17376. ALL: 15 // = RED | GREEN | BLUE | ALPHA
  17377. });
  17378. /**
  17379. * Component ID utility
  17380. */
  17381. const ColorComponentId = Object.freeze({
  17382. [PixelComponent.RED]: 0,
  17383. [PixelComponent.GREEN]: 1,
  17384. [PixelComponent.BLUE]: 2,
  17385. [PixelComponent.ALPHA]: 3
  17386. });
  17387. /***/ }),
  17388. /***/ "./src/utils/utils.js":
  17389. /*!****************************!*\
  17390. !*** ./src/utils/utils.js ***!
  17391. \****************************/
  17392. /***/ ((__unused_webpack_module, __webpack_exports__, __nested_webpack_require_762198__) => {
  17393. "use strict";
  17394. __nested_webpack_require_762198__.r(__webpack_exports__);
  17395. /* harmony export */ __nested_webpack_require_762198__.d(__webpack_exports__, {
  17396. /* harmony export */ "Utils": () => (/* binding */ Utils)
  17397. /* harmony export */ });
  17398. /* harmony import */ var _errors__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_762198__(/*! ./errors */ "./src/utils/errors.js");
  17399. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_762198__(/*! ../core/speedy-promise */ "./src/core/speedy-promise.js");
  17400. /*
  17401. * speedy-vision.js
  17402. * GPU-accelerated Computer Vision for JavaScript
  17403. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  17404. *
  17405. * Licensed under the Apache License, Version 2.0 (the "License");
  17406. * you may not use this file except in compliance with the License.
  17407. * You may obtain a copy of the License at
  17408. *
  17409. * http://www.apache.org/licenses/LICENSE-2.0
  17410. *
  17411. * Unless required by applicable law or agreed to in writing, software
  17412. * distributed under the License is distributed on an "AS IS" BASIS,
  17413. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17414. * See the License for the specific language governing permissions and
  17415. * limitations under the License.
  17416. *
  17417. * utils.js
  17418. * Generic utilities
  17419. */
  17420. /**
  17421. * Generic utilities
  17422. */
  17423. class Utils
  17424. {
  17425. /**
  17426. * Generates a warning
  17427. * @param {string} text message text
  17428. * @param {...string} args optional text
  17429. */
  17430. static warning(text, ...args)
  17431. {
  17432. console.warn('[speedy-vision]', text, ...args);
  17433. }
  17434. /**
  17435. * Logs a message
  17436. * @param {string} text message text
  17437. * @param {...string} args optional text
  17438. */
  17439. static log(text, ...args)
  17440. {
  17441. console.log('[speedy-vision]', text, ...args);
  17442. }
  17443. /**
  17444. * Assertion
  17445. * @param {boolean} expr expression
  17446. * @param {string} [text] error message
  17447. * @throws {AssertionError}
  17448. */
  17449. static assert(expr, text = '')
  17450. {
  17451. if(!expr)
  17452. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.AssertionError(text);
  17453. }
  17454. /**
  17455. * Gets the names of the arguments of the specified function
  17456. * @param {Function} fun
  17457. * @returns {string[]}
  17458. */
  17459. static functionArguments(fun)
  17460. {
  17461. const code = fun.toString();
  17462. const regex = code.startsWith('function') ? 'function\\s.*\\(([^)]*)\\)' :
  17463. (code.startsWith('(') ? '\\(([^)]*)\\).*=>' : '([^=]+).*=>');
  17464. const match = new RegExp(regex).exec(code);
  17465. if(match !== null) {
  17466. const args = match[1].replace(/\/\*.*?\*\//g, ''); // remove comments
  17467. return args.split(',').map(argname =>
  17468. argname.replace(/=.*$/, '').trim() // remove default params & trim
  17469. ).filter(argname =>
  17470. argname // handle trailing commas
  17471. );
  17472. }
  17473. else
  17474. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.ParseError(`Can't detect function arguments of ${code}`);
  17475. }
  17476. /**
  17477. * Get all property descriptors from an object,
  17478. * traversing its entire prototype chain
  17479. * @param {object} obj
  17480. * @returns {object}
  17481. */
  17482. static getAllPropertyDescriptors(obj)
  17483. {
  17484. if(obj) {
  17485. const proto = Object.getPrototypeOf(obj);
  17486. return {
  17487. ...(Utils.getAllPropertyDescriptors(proto)),
  17488. ...Object.getOwnPropertyDescriptors(obj)
  17489. };
  17490. }
  17491. else
  17492. return Object.create(null);
  17493. }
  17494. /**
  17495. * Creates a HTMLCanvasElement with the given dimensions
  17496. * @param {number} width in pixels
  17497. * @param {number} height in pixels
  17498. * @returns {HTMLCanvasElement}
  17499. */
  17500. static createCanvas(width, height)
  17501. {
  17502. const canvas = document.createElement('canvas');
  17503. canvas.width = width;
  17504. canvas.height = height;
  17505. return canvas;
  17506. }
  17507. /**
  17508. * Generates a random number with
  17509. * Gaussian distribution (mu, sigma)
  17510. * @param {number} mu mean
  17511. * @param {number} sigma standard deviation
  17512. * @returns {number} random number
  17513. */
  17514. static gaussianNoise(mu = 0, sigma = 1)
  17515. {
  17516. // Box-Muller transformation
  17517. const TWO_PI = 2.0 * Math.PI;
  17518. let a, b = Math.random();
  17519. do { a = Math.random(); } while(a <= Number.EPSILON);
  17520. let z = Math.sqrt(-2 * Math.log(a)) * Math.sin(TWO_PI * b);
  17521. return z * sigma + mu;
  17522. }
  17523. /**
  17524. * Generate a 1D gaussian kernel with custom sigma
  17525. * Tip: use kernelSize >= (5 * sigma), kernelSize odd
  17526. * @param {number} sigma gaussian sigma
  17527. * @param {number} [kernelSize] kernel size, odd number
  17528. * @param {boolean} [normalized] normalize entries so that their sum is 1
  17529. * @returns {number[]}
  17530. */
  17531. static gaussianKernel(sigma, kernelSize = 0, normalized = true)
  17532. {
  17533. /*
  17534. * Let G(x) be a Gaussian function centered at 0 with fixed sigma:
  17535. *
  17536. * G(x) = (1 / (sigma * sqrt(2 * pi))) * exp(-(x / (sqrt(2) * sigma))^2)
  17537. *
  17538. * In addition, let f(p) be a kernel value at pixel p, -k/2 <= p <= k/2:
  17539. *
  17540. * f(p) = \int_{p - 0.5}^{p + 0.5} G(x) dx (integrate around p)
  17541. * = \int_{0}^{p + 0.5} G(x) dx - \int_{0}^{p - 0.5} G(x) dx
  17542. *
  17543. * Setting a constant c := sqrt(2) * sigma, it follows that:
  17544. *
  17545. * f(p) = (1 / 2c) * (erf((p + 0.5) / c) - erf((p - 0.5) / c))
  17546. */
  17547. // default kernel size
  17548. if(kernelSize == 0) {
  17549. kernelSize = Math.ceil(5.0 * sigma) | 0;
  17550. kernelSize += 1 - (kernelSize % 2);
  17551. }
  17552. // validate input
  17553. kernelSize |= 0;
  17554. if(kernelSize < 1 || kernelSize % 2 == 0)
  17555. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.IllegalArgumentError(`Invalid kernel size given to gaussianKernel: ${kernelSize} x 1`);
  17556. else if(sigma <= 0.0)
  17557. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.IllegalArgumentError(`Invalid sigma given to gaussianKernel: ${sigma}`);
  17558. // function erf(x) = -erf(-x) can be approximated numerically. See:
  17559. // https://en.wikipedia.org/wiki/Error_function#Numerical_approximations
  17560. const kernel = new Array(kernelSize);
  17561. // set constants
  17562. const N = kernelSize >> 1; // integer (floor, div 2)
  17563. const c = (+sigma) * 1.4142135623730951; // sigma * sqrt(2)
  17564. const m = 0.3275911;
  17565. const a1 = 0.254829592;
  17566. const a2 = -0.284496736;
  17567. const a3 = 1.421413741;
  17568. const a4 = -1.453152027;
  17569. const a5 = 1.061405429;
  17570. // compute the kernel
  17571. let sum = 0.0;
  17572. for(let j = 0; j < kernelSize; j++) {
  17573. let xa = (j - N + 0.5) / c;
  17574. let xb = (j - N - 0.5) / c;
  17575. let sa = 1.0, sb = 1.0;
  17576. if(xa < 0.0) { sa = -1.0; xa = -xa; }
  17577. if(xb < 0.0) { sb = -1.0; xb = -xb; }
  17578. const ta = 1.0 / (1.0 + m * xa);
  17579. const tb = 1.0 / (1.0 + m * xb);
  17580. const pa = ((((a5 * ta + a4) * ta + a3) * ta + a2) * ta + a1) * ta;
  17581. const pb = ((((a5 * tb + a4) * tb + a3) * tb + a2) * tb + a1) * tb;
  17582. const ya = 1.0 - pa * Math.exp(-xa * xa);
  17583. const yb = 1.0 - pb * Math.exp(-xb * xb);
  17584. const erfa = sa * ya;
  17585. const erfb = sb * yb;
  17586. const fp = (erfa - erfb) / (2.0 * c);
  17587. kernel[j] = fp;
  17588. sum += fp;
  17589. }
  17590. // normalize the kernel
  17591. if(normalized) {
  17592. for(let j = 0; j < kernelSize; j++)
  17593. kernel[j] /= sum;
  17594. }
  17595. // done!
  17596. return kernel;
  17597. }
  17598. /**
  17599. * Generate a 2D kernel in column-major format using two separable 1D kernels
  17600. * @param {number[]} ka 1D kernel
  17601. * @param {number[]} [kb]
  17602. * @returns {number[]}
  17603. */
  17604. static kernel2d(ka, kb = ka)
  17605. {
  17606. const ksize = ka.length;
  17607. Utils.assert(ka.length == ka.length);
  17608. Utils.assert(ksize >= 1 && ksize % 2 == 1);
  17609. // compute the outer product ka x kb
  17610. let kernel2d = new Array(ksize * ksize), k = 0;
  17611. for(let col = 0; col < ksize; col++) {
  17612. for(let row = 0; row < ksize; row++)
  17613. kernel2d[k++] = ka[row] * kb[col];
  17614. }
  17615. return kernel2d;
  17616. }
  17617. /**
  17618. * Cartesian product a x b: [ [ai, bj] for all i, j ]
  17619. * @param {number[]} a
  17620. * @param {number[]} b
  17621. * @returns {Array<[number,number]>}
  17622. */
  17623. static cartesian(a, b)
  17624. {
  17625. return [].concat(...a.map(a => b.map(b => [a, b])));
  17626. }
  17627. /**
  17628. * Symmetric range
  17629. * @param {number} n non-negative integer
  17630. * @returns {number[]} [ -n, ..., n ]
  17631. */
  17632. static symmetricRange(n)
  17633. {
  17634. if((n |= 0) < 0)
  17635. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.IllegalArgumentError(`Expected a non-negative integer as input`);
  17636. return [...(Array(2*n + 1).keys())].map(x => x - n);
  17637. }
  17638. /**
  17639. * Compute the [0, n) range of integers
  17640. * @param {number} n positive integer
  17641. * @returns {number[]} [ 0, 1, ..., n-1 ]
  17642. */
  17643. static range(n)
  17644. {
  17645. if((n |= 0) <= 0)
  17646. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.IllegalArgumentError(`Expected a positive integer as input`);
  17647. return [...(Array(n).keys())];
  17648. }
  17649. /**
  17650. * Shuffle in-place
  17651. * @template T
  17652. * @param {T[]} arr
  17653. * @returns {T[]} arr
  17654. */
  17655. static shuffle(arr)
  17656. {
  17657. const len = arr.length;
  17658. const m = len - 1;
  17659. // Fisher-Yattes
  17660. for(let i = 0; i < m; i++) {
  17661. const j = i + ((Math.random() * (len - i)) | 0); // i <= j < arr.length
  17662. if(i !== j) {
  17663. const t = arr[i];
  17664. arr[i] = arr[j];
  17665. arr[j] = t;
  17666. }
  17667. }
  17668. return arr;
  17669. }
  17670. /**
  17671. * Flatten an array (1 level only)
  17672. * @template U
  17673. * @param {U[]} array
  17674. * @returns {U[]}
  17675. */
  17676. static flatten(array)
  17677. {
  17678. //return array.flat();
  17679. //return array.reduce((arr, val) => arr.concat(val), []);
  17680. const flat = [];
  17681. for(let i = 0, n = array.length; i < n; i++) {
  17682. const entry = array[i];
  17683. if(Array.isArray(entry)) {
  17684. for(let j = 0, m = entry.length; j < m; j++)
  17685. flat.push(entry[j]);
  17686. }
  17687. else
  17688. flat.push(entry);
  17689. }
  17690. return flat;
  17691. }
  17692. /**
  17693. * Decode a 16-bit float from a
  17694. * unsigned 16-bit integer
  17695. * @param {number} uint16
  17696. * @returns {number}
  17697. */
  17698. static decodeFloat16(uint16)
  17699. {
  17700. // decode according to sec 2.1.2
  17701. // 16-Bit Floating Point Numbers
  17702. // of the OpenGL ES 3 spec
  17703. const s = (uint16 & 0xFFFF) >> 15; // sign bit
  17704. const e = (uint16 & 0x7FFF) >> 10; // exponent
  17705. const m = (uint16 & 0x3FF); // mantissa
  17706. const sign = 1 - 2 * s; // (-1)^s
  17707. if(e == 0)
  17708. return m == 0 ? sign * 0.0 : sign * m * 5.960464477539063e-8; // zero / subnormal
  17709. else if(e == 31)
  17710. return m == 0 ? sign * Number.POSITIVE_INFINITY : Number.NaN;
  17711. const f = e >= 15 ? (1 << (e-15)) : 1.0 / (1 << (15-e)); // 2^(e-15)
  17712. return sign * f * (1.0 + m * 0.0009765625); // normal
  17713. }
  17714. /**
  17715. * Wrapper around getUserMedia()
  17716. * @param {MediaStreamConstraints} [constraints] will be passed to getUserMedia()
  17717. * @returns {SpeedyPromise<HTMLVideoElement>}
  17718. */
  17719. static requestCameraStream(constraints = { audio: false, video: true })
  17720. {
  17721. Utils.log('Accessing the webcam...');
  17722. if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)
  17723. throw new _errors__WEBPACK_IMPORTED_MODULE_0__.NotSupportedError('Unsupported browser: no mediaDevices.getUserMedia()');
  17724. return new _core_speedy_promise__WEBPACK_IMPORTED_MODULE_1__.SpeedyPromise((resolve, reject) => {
  17725. navigator.mediaDevices.getUserMedia(constraints).then(stream => {
  17726. const video = document.createElement('video');
  17727. video.onloadedmetadata = () => {
  17728. video.play();
  17729. Utils.log(`The camera is on! Resolution: ${video.videoWidth} x ${video.videoHeight}`);
  17730. resolve(video);
  17731. };
  17732. video.srcObject = stream;
  17733. })
  17734. .catch(err => {
  17735. reject(new _errors__WEBPACK_IMPORTED_MODULE_0__.AccessDeniedError(
  17736. `Please give access to the camera and reload the page`,
  17737. err
  17738. ));
  17739. });
  17740. });
  17741. }
  17742. }
  17743. /***/ }),
  17744. /***/ "./src/gpu/shaders/filters/convolution1d.glsl":
  17745. /*!****************************************************!*\
  17746. !*** ./src/gpu/shaders/filters/convolution1d.glsl ***!
  17747. \****************************************************/
  17748. /***/ ((module) => {
  17749. module.exports = "#if !defined(KERNEL_SIZE) || !defined(AXIS) || (AXIS != 0 && AXIS != 1)\n#error Undefined KERNEL_SIZE / AXIS\n#endif\nuniform sampler2D image;\nuniform float kernel[@KERNEL_SIZE@];\nconst ivec2 axis = ivec2(1-AXIS, AXIS);\n#define S(x,k) result += pixelAtShortOffset(image, ivec2((x),(x)) * axis) * kernel[k]\nvoid main()\n{\nvec4 result = vec4(0.0f);\n#if KERNEL_SIZE == 3\nS(-1, 2);\nS( 0, 1);\nS( 1, 0);\n#elif KERNEL_SIZE == 5\nS(-2, 4);\nS(-1, 3);\nS( 0, 2);\nS( 1, 1);\nS( 2, 0);\n#elif KERNEL_SIZE == 7\nS(-3, 6);\nS(-2, 5);\nS(-1, 4);\nS( 0, 3);\nS( 1, 2);\nS( 2, 1);\nS( 3, 0);\n#elif KERNEL_SIZE == 9\nS(-4, 8);\nS(-3, 7);\nS(-2, 6);\nS(-1, 5);\nS( 0, 4);\nS( 1, 3);\nS( 2, 2);\nS( 3, 1);\nS( 4, 0);\n#elif KERNEL_SIZE == 11\nS(-5, 10);\nS(-4, 9);\nS(-3, 8);\nS(-2, 7);\nS(-1, 6);\nS( 0, 5);\nS( 1, 4);\nS( 2, 3);\nS( 3, 2);\nS( 4, 1);\nS( 5, 0);\n#elif KERNEL_SIZE == 13\nS(-6, 12);\nS(-5, 11);\nS(-4, 10);\nS(-3, 9);\nS(-2, 8);\nS(-1, 7);\nS( 0, 6);\nS( 1, 5);\nS( 2, 4);\nS( 3, 3);\nS( 4, 2);\nS( 5, 1);\nS( 6, 0);\n#elif KERNEL_SIZE == 15\nS(-7, 14);\nS(-6, 13);\nS(-5, 12);\nS(-4, 11);\nS(-3, 10);\nS(-2, 9);\nS(-1, 8);\nS( 0, 7);\nS( 1, 6);\nS( 2, 5);\nS( 3, 4);\nS( 4, 3);\nS( 5, 2);\nS( 6, 1);\nS( 7, 0);\n#else\n#error Invalid parameters\n#endif\ncolor = vec4(result.rgb, 1.0f);\n}"
  17750. /***/ }),
  17751. /***/ "./src/gpu/shaders/filters/convolution2d.glsl":
  17752. /*!****************************************************!*\
  17753. !*** ./src/gpu/shaders/filters/convolution2d.glsl ***!
  17754. \****************************************************/
  17755. /***/ ((module) => {
  17756. module.exports = "#ifndef KERNEL_SIZE_SQUARED\n#define Must define KERNEL_SIZE_SQUARED\n#endif\nuniform sampler2D image;\nuniform float kernel[@KERNEL_SIZE_SQUARED@];\n#define S(x,y,k) result += pixelAtShortOffset(image, ivec2((x),(y))) * kernel[k]\nvoid main()\n{\nvec4 result = vec4(0.0f);\n#if KERNEL_SIZE_SQUARED == 9\nS(-1,-1, 8);\nS(-1, 0, 7);\nS(-1, 1, 6);\nS( 0,-1, 5);\nS( 0, 0, 4);\nS( 0, 1, 3);\nS( 1,-1, 2);\nS( 1, 0, 1);\nS( 1, 1, 0);\n#elif KERNEL_SIZE_SQUARED == 25\nS(-2,-2, 24);\nS(-2,-1, 23);\nS(-2, 0, 22);\nS(-2, 1, 21);\nS(-2, 2, 20);\nS(-1,-2, 19);\nS(-1,-1, 18);\nS(-1, 0, 17);\nS(-1, 1, 16);\nS(-1, 2, 15);\nS( 0,-2, 14);\nS( 0,-1, 13);\nS( 0, 0, 12);\nS( 0, 1, 11);\nS( 0, 2, 10);\nS( 1,-2, 9);\nS( 1,-1, 8);\nS( 1, 0, 7);\nS( 1, 1, 6);\nS( 1, 2, 5);\nS( 2,-2, 4);\nS( 2,-1, 3);\nS( 2, 0, 2);\nS( 2, 1, 1);\nS( 2, 2, 0);\n#elif KERNEL_SIZE_SQUARED == 49\nS(-3,-3, 48);\nS(-3,-2, 47);\nS(-3,-1, 46);\nS(-3, 0, 45);\nS(-3, 1, 44);\nS(-3, 2, 43);\nS(-3, 3, 42);\nS(-2,-3, 41);\nS(-2,-2, 40);\nS(-2,-1, 39);\nS(-2, 0, 38);\nS(-2, 1, 37);\nS(-2, 2, 36);\nS(-2, 3, 35);\nS(-1,-3, 34);\nS(-1,-2, 33);\nS(-1,-1, 32);\nS(-1, 0, 31);\nS(-1, 1, 30);\nS(-1, 2, 29);\nS(-1, 3, 28);\nS( 0,-3, 27);\nS( 0,-2, 26);\nS( 0,-1, 25);\nS( 0, 0, 24);\nS( 0, 1, 23);\nS( 0, 2, 22);\nS( 0, 3, 21);\nS( 1,-3, 20);\nS( 1,-2, 19);\nS( 1,-1, 18);\nS( 1, 0, 17);\nS( 1, 1, 16);\nS( 1, 2, 15);\nS( 1, 3, 14);\nS( 2,-3, 13);\nS( 2,-2, 12);\nS( 2,-1, 11);\nS( 2, 0, 10);\nS( 2, 1, 9);\nS( 2, 2, 8);\nS( 2, 3, 7);\nS( 3,-3, 6);\nS( 3,-2, 5);\nS( 3,-1, 4);\nS( 3, 0, 3);\nS( 3, 1, 2);\nS( 3, 2, 1);\nS( 3, 3, 0);\n#else\n#error Invalid KERNEL_SIZE_SQUARED\n#endif\ncolor = vec4(result.rgb, 1.0f);\n}"
  17757. /***/ }),
  17758. /***/ "./src/gpu/shaders/filters/fast-median.glsl":
  17759. /*!**************************************************!*\
  17760. !*** ./src/gpu/shaders/filters/fast-median.glsl ***!
  17761. \**************************************************/
  17762. /***/ ((module) => {
  17763. module.exports = "uniform sampler2D image;\n#define X(i,j) t = vec2(min(p[i], p[j]), max(p[i], p[j])); p[i] = t.x; p[j] = t.y;\n#define S(i,x,y) p[i] = pixelAtShortOffset(image, ivec2((x),(y))).g\nvoid main()\n{\nfloat median;\nvec2 t;\n#if !defined(KERNEL_SIZE)\n#error Must define KERNEL_SIZE\n#elif KERNEL_SIZE == 3\nfloat p[9];\nS(0,-1,-1);\nS(1, 0,-1);\nS(2, 1,-1);\nS(3,-1, 0);\nS(4, 0, 0);\nS(5, 1, 0);\nS(6,-1, 1);\nS(7, 0, 1);\nS(8, 1, 1);\nX(1,2);X(4,5);X(7,8);X(0,1);X(3,4);X(6,7);X(1,2);X(4,5);X(7,8);X(0,3);X(5,8);X(4,7);X(3,6);X(1,4);X(2,5);X(4,7);X(4,2);X(6,4);X(4,2);\nmedian = p[4];\n#elif KERNEL_SIZE == 5\nfloat p[25];\nS( 0,-2,-2);\nS( 1,-1,-2);\nS( 2, 0,-2);\nS( 3, 1,-2);\nS( 4, 2,-2);\nS( 5,-2,-1);\nS( 6,-1,-1);\nS( 7, 0,-1);\nS( 8, 1,-1);\nS( 9, 2,-1);\nS(10,-2, 0);\nS(11,-1, 0);\nS(12, 0, 0);\nS(13, 1, 0);\nS(14, 2, 0);\nS(15,-2, 1);\nS(16,-1, 1);\nS(17, 0, 1);\nS(18, 1, 1);\nS(19, 2, 1);\nS(20,-2, 2);\nS(21,-1, 2);\nS(22, 0, 2);\nS(23, 1, 2);\nS(24, 2, 2);\nX(0,1);X(3,4);X(2,4);X(2,3);X(6,7);X(5,7);X(5,6);X(9,10);X(8,10);X(8,9);X(12,13);X(11,13);X(11,12);X(15,16);X(14,16);X(14,15);X(18,19);X(17,19);X(17,18);X(21,22);X(20,22);X(20,21);X(23,24);X(2,5);X(3,6);X(0,6);X(0,3);X(4,7);X(1,7);X(1,4);X(11,14);X(8,14);X(8,11);X(12,15);X(9,15);X(9,12);X(13,16);X(10,16);X(10,13);X(20,23);X(17,23);X(17,20);X(21,24);X(18,24);X(18,21);X(19,22);X(8,17);X(9,18);X(0,18);X(0,9);X(10,19);X(1,19);X(1,10);X(11,20);X(2,20);X(2,11);X(12,21);X(3,21);X(3,12);X(13,22);X(4,22);X(4,13);X(14,23);X(5,23);X(5,14);X(15,24);X(6,24);X(6,15);X(7,16);X(7,19);X(13,21);X(15,23);X(7,13);X(7,15);X(1,9);X(3,11);X(5,17);X(11,17);X(9,17);X(4,10);X(6,12);X(7,14);X(4,6);X(4,7);X(12,14);X(10,14);X(6,7);X(10,12);X(6,10);X(6,17);X(12,17);X(7,17);X(7,10);X(12,18);X(7,12);X(10,18);X(12,20);X(10,20);X(10,12);\nmedian = p[12];\n#elif KERNEL_SIZE == 7\nfloat p[49];\nS( 0,-3,-3);\nS( 1,-2,-3);\nS( 2,-1,-3);\nS( 3, 0,-3);\nS( 4, 1,-3);\nS( 5, 2,-3);\nS( 6, 3,-3);\nS( 7,-3,-2);\nS( 8,-2,-2);\nS( 9,-1,-2);\nS(10, 0,-2);\nS(11, 1,-2);\nS(12, 2,-2);\nS(13, 3,-2);\nS(14,-3,-1);\nS(15,-2,-1);\nS(16,-1,-1);\nS(17, 0,-1);\nS(18, 1,-1);\nS(19, 2,-1);\nS(20, 3,-1);\nS(21,-3, 0);\nS(22,-2, 0);\nS(23,-1, 0);\nS(24, 0, 0);\nS(25, 1, 0);\nS(26, 2, 0);\nS(27, 3, 0);\nS(28,-3, 1);\nS(29,-2, 1);\nS(30,-1, 1);\nS(31, 0, 1);\nS(32, 1, 1);\nS(33, 2, 1);\nS(34, 3, 1);\nS(35,-3, 2);\nS(36,-2, 2);\nS(37,-1, 2);\nS(38, 0, 2);\nS(39, 1, 2);\nS(40, 2, 2);\nS(41, 3, 2);\nS(42,-3, 3);\nS(43,-2, 3);\nS(44,-1, 3);\nS(45, 0, 3);\nS(46, 1, 3);\nS(47, 2, 3);\nS(48, 3, 3);\nX(0,1);X(2,3);X(0,2);X(1,3);X(1,2);X(4,5);X(6,7);X(4,6);X(5,7);X(5,6);X(0,4);X(2,6);X(2,4);X(1,5);X(3,7);X(3,5);X(1,2);X(3,4);X(5,6);X(8,9);X(10,11);X(8,10);X(9,11);X(9,10);X(12,13);X(14,15);X(12,14);X(13,15);X(13,14);X(8,12);X(10,14);X(10,12);X(9,13);X(11,15);X(11,13);X(9,10);X(11,12);X(13,14);X(0,8);X(4,12);X(4,8);X(2,10);X(6,14);X(6,10);X(2,4);X(6,8);X(10,12);X(1,9);X(5,13);X(5,9);X(3,11);X(7,15);X(7,11);X(3,5);X(7,9);X(11,13);X(1,2);X(3,4);X(5,6);X(7,8);X(9,10);X(11,12);X(13,14);X(16,17);X(18,19);X(16,18);X(17,19);X(17,18);X(20,21);X(22,23);X(20,22);X(21,23);X(21,22);X(16,20);X(18,22);X(18,20);X(17,21);X(19,23);X(19,21);X(17,18);X(19,20);X(21,22);X(24,25);X(26,27);X(24,26);X(25,27);X(25,26);X(28,29);X(30,31);X(28,30);X(29,31);X(29,30);X(24,28);X(26,30);X(26,28);X(25,29);X(27,31);X(27,29);X(25,26);X(27,28);X(29,30);X(16,24);X(20,28);X(20,24);X(18,26);X(22,30);X(22,26);X(18,20);X(22,24);X(26,28);X(17,25);X(21,29);X(21,25);X(19,27);X(23,31);X(23,27);X(19,21);X(23,25);X(27,29);X(17,18);X(19,20);X(21,22);X(23,24);X(25,26);X(27,28);X(29,30);X(0,16);X(8,24);X(8,16);X(4,20);X(12,28);X(12,20);X(4,8);X(12,16);X(20,24);X(2,18);X(10,26);X(10,18);X(6,22);X(14,30);X(14,22);X(6,10);X(14,18);X(22,26);X(2,4);X(6,8);X(10,12);X(14,16);X(18,20);X(22,24);X(26,28);X(1,17);X(9,25);X(9,17);X(5,21);X(13,29);X(13,21);X(5,9);X(13,17);X(21,25);X(3,19);X(11,27);X(11,19);X(7,23);X(15,31);X(15,23);X(7,11);X(15,19);X(23,27);X(3,5);X(7,9);X(11,13);X(15,17);X(19,21);X(23,25);X(27,29);X(1,2);X(3,4);X(5,6);X(7,8);X(9,10);X(11,12);X(13,14);X(15,16);X(17,18);X(19,20);X(21,22);X(23,24);X(25,26);X(27,28);X(29,30);X(32,33);X(34,35);X(32,34);X(33,35);X(33,34);X(36,37);X(38,39);X(36,38);X(37,39);X(37,38);X(32,36);X(34,38);X(34,36);X(33,37);X(35,39);X(35,37);X(33,34);X(35,36);X(37,38);X(40,41);X(42,43);X(40,42);X(41,43);X(41,42);X(44,45);X(46,47);X(44,46);X(45,47);X(45,46);X(40,44);X(42,46);X(42,44);X(41,45);X(43,47);X(43,45);X(41,42);X(43,44);X(45,46);X(32,40);X(36,44);X(36,40);X(34,42);X(38,46);X(38,42);X(34,36);X(38,40);X(42,44);X(33,41);X(37,45);X(37,41);X(35,43);X(39,47);X(39,43);X(35,37);X(39,41);X(43,45);X(33,34);X(35,36);X(37,38);X(39,40);X(41,42);X(43,44);X(45,46);X(32,48);X(40,48);X(36,40);X(44,48);X(38,42);X(34,36);X(38,40);X(42,44);X(46,48);X(37,41);X(39,43);X(35,37);X(39,41);X(43,45);X(33,34);X(35,36);X(37,38);X(39,40);X(41,42);X(43,44);X(45,46);X(47,48);X(0,32);X(16,48);X(16,32);X(8,40);X(24,40);X(8,16);X(24,32);X(40,48);X(4,36);X(20,36);X(12,44);X(28,44);X(12,20);X(28,36);X(4,8);X(12,16);X(20,24);X(28,32);X(36,40);X(44,48);X(2,34);X(18,34);X(10,42);X(26,42);X(10,18);X(26,34);X(6,38);X(22,38);X(14,46);X(30,46);X(14,22);X(30,38);X(6,10);X(14,18);X(22,26);X(30,34);X(38,42);X(2,4);X(6,8);X(10,12);X(14,16);X(18,20);X(22,24);X(26,28);X(30,32);X(34,36);X(38,40);X(42,44);X(46,48);X(1,33);X(17,33);X(9,41);X(25,41);X(9,17);X(25,33);X(5,37);X(21,37);X(13,45);X(29,45);X(13,21);X(29,37);X(5,9);X(13,17);X(21,25);X(29,33);X(37,41);X(3,35);X(19,35);X(11,43);X(27,43);X(11,19);X(27,35);X(7,39);X(23,39);X(15,47);X(31,47);X(15,23);X(31,39);X(7,11);X(15,19);X(23,27);X(31,35);X(39,43);X(3,5);X(7,9);X(11,13);X(15,17);X(19,21);X(23,25);X(27,29);X(31,33);X(35,37);X(39,41);X(43,45);X(1,2);X(3,4);X(5,6);X(7,8);X(9,10);X(11,12);X(13,14);X(15,16);X(17,18);X(19,20);X(21,22);X(23,24);\nmedian = p[24];\n#else\n#error Unsupported kernel size\n#endif\ncolor = vec4(median, median, median, 1.0f);\n}"
  17764. /***/ }),
  17765. /***/ "./src/gpu/shaders/filters/nightvision.glsl":
  17766. /*!**************************************************!*\
  17767. !*** ./src/gpu/shaders/filters/nightvision.glsl ***!
  17768. \**************************************************/
  17769. /***/ ((module) => {
  17770. module.exports = "uniform sampler2D image;\nuniform sampler2D illuminationMap;\nuniform float gain;\nuniform float offset;\nuniform float decay;\n#ifndef GREYSCALE\n#error Must define GREYSCALE\n#endif\n#if GREYSCALE == 0\nconst mat3 rgb2yuv = mat3(\n0.299f, -0.14713f, 0.615f,\n0.587f, -0.28886f, -0.51499f,\n0.114f, 0.436f, -0.10001f\n);\nconst mat3 yuv2rgb = mat3(\n1.0f, 1.0f, 1.0f,\n0.0f, -0.39465f, 2.03211f,\n1.13983f, -0.58060f, 0.0f\n);\n#endif\nconst float eps = 0.0001f;\nconst float sqrt2 = 1.4142135623730951f;\nconst float magic = 20.0f;\nconst vec2 center = vec2(0.5f);\nvoid main()\n{\nvec4 pixel = threadPixel(image);\nvec4 imapPixel = threadPixel(illuminationMap);\nfloat lambda = -sqrt2 * log(max(1.0f - decay, eps));\nfloat dist = length(texCoord - center);\nfloat vgain = gain * exp(-lambda * dist);\nfloat normalizedGain = 2.0f * vgain;\nfloat normalizedOffset = 2.0f * offset - 1.0f;\n#if GREYSCALE != 0\nfloat luma = 1.0 / (1.0 + exp(-normalizedGain * magic * (pixel.g - imapPixel.g)));\nluma = clamp(luma + normalizedOffset, 0.0f, 1.0f);\ncolor = vec4(luma, luma, luma, 1.0f);\n#else\nvec3 yuvPixel = rgb2yuv * pixel.rgb;\nvec3 yuvImapPixel = rgb2yuv * imapPixel.rgb;\nfloat luma = 1.0 / (1.0 + exp(-normalizedGain * magic * (yuvPixel.r - yuvImapPixel.r)));\nluma += normalizedOffset;\nvec3 rgbCorrectedPixel = yuv2rgb * vec3(luma, yuvPixel.gb);\nrgbCorrectedPixel = clamp(rgbCorrectedPixel, 0.0f, 1.0f);\ncolor = vec4(rgbCorrectedPixel, 1.0f);\n#endif\n}"
  17771. /***/ }),
  17772. /***/ "./src/gpu/shaders/filters/normalize-image.glsl":
  17773. /*!******************************************************!*\
  17774. !*** ./src/gpu/shaders/filters/normalize-image.glsl ***!
  17775. \******************************************************/
  17776. /***/ ((module) => {
  17777. module.exports = "#ifndef GREYSCALE\n#error Must define GREYSCALE\n#endif\n#if GREYSCALE != 0\nuniform sampler2D minmax2d;\n#else\nuniform sampler2D minmax2dRGB[3];\n#endif\nuniform float minValue;\nuniform float maxValue;\nconst float eps = 1.0f / 255.0f;\nvoid main()\n{\nvec2 minmax = clamp(vec2(minValue, maxValue), 0.0f, 255.0f) / 255.0f;\nvec4 newMin = vec4(minmax.x);\nvec4 newRange = vec4(minmax.y - minmax.x);\nvec4 alpha = vec4(1.0f, newMin.x, newRange.x, 1.0f);\n#if GREYSCALE != 0\nvec4 pixel = threadPixel(minmax2d);\nmat4 channel = mat4(pixel, pixel, pixel, alpha);\n#else\nmat4 channel = mat4(\nthreadPixel(minmax2dRGB[0]),\nthreadPixel(minmax2dRGB[1]),\nthreadPixel(minmax2dRGB[2]),\nalpha\n);\n#endif\nvec4 oldMin = vec4(channel[0].g, channel[1].g, channel[2].g, channel[3].g);\nvec4 oldRange = max(vec4(channel[0].b, channel[1].b, channel[2].b, channel[3].b), eps);\nvec4 oldIntensity = vec4(channel[0].a, channel[1].a, channel[2].a, channel[3].a);\nvec4 newIntensity = (oldIntensity - oldMin) * newRange / oldRange + newMin;\ncolor = newIntensity;\n}"
  17778. /***/ }),
  17779. /***/ "./src/gpu/shaders/filters/rgb2grey.glsl":
  17780. /*!***********************************************!*\
  17781. !*** ./src/gpu/shaders/filters/rgb2grey.glsl ***!
  17782. \***********************************************/
  17783. /***/ ((module) => {
  17784. module.exports = "const vec4 grey = vec4(0.299f, 0.587f, 0.114f, 0.0f);\nuniform sampler2D image;\nvoid main()\n{\nvec4 pixel = threadPixel(image);\nfloat g = dot(pixel, grey);\ncolor = vec4(g, g, g, 1.0f);\n}"
  17785. /***/ }),
  17786. /***/ "./src/gpu/shaders/include/colors.glsl":
  17787. /*!*********************************************!*\
  17788. !*** ./src/gpu/shaders/include/colors.glsl ***!
  17789. \*********************************************/
  17790. /***/ ((module) => {
  17791. module.exports = "#ifndef _COLORS_GLSL\n#define _COLORS_GLSL\n#define PIXELCOMPONENT_RED @PIXELCOMPONENT_RED@\n#define PIXELCOMPONENT_GREEN @PIXELCOMPONENT_GREEN@\n#define PIXELCOMPONENT_BLUE @PIXELCOMPONENT_BLUE@\n#define PIXELCOMPONENT_ALPHA @PIXELCOMPONENT_ALPHA@\n#endif"
  17792. /***/ }),
  17793. /***/ "./src/gpu/shaders/include/filters.glsl":
  17794. /*!**********************************************!*\
  17795. !*** ./src/gpu/shaders/include/filters.glsl ***!
  17796. \**********************************************/
  17797. /***/ ((module) => {
  17798. module.exports = "#ifndef _FILTERS_GLSL\n#define _FILTERS_GLSL\nfloat laplacian(sampler2D pyramid, vec2 position, float lod)\n{\nfloat pot = exp2(lod);\nivec2 pyrBaseSize = textureSize(pyramid, 0);\nconst vec3 ones = vec3(1.0f);\nconst mat3 kernel = mat3(\n0,-1, 0,\n-1, 4,-1,\n0,-1, 0\n);\n#define LPC(x,y) pyrSubpixelAtExOffset(pyramid, position, lod, pot, ivec2((x),(y)), pyrBaseSize).g\nmat3 neighborhood = mat3(\n0.0f, LPC(0,-1), 0.0f,\nLPC(-1,0), LPC(0,0), LPC(1,0),\n0.0f, LPC(0,1), 0.0f\n);\nmat3 m = matrixCompMult(neighborhood, kernel);\nreturn dot(ones, vec3(\ndot(m[0], ones),\ndot(m[1], ones),\ndot(m[2], ones)\n)) * (1.0f + lod);\n}\n#endif"
  17799. /***/ }),
  17800. /***/ "./src/gpu/shaders/include/fixed-point.glsl":
  17801. /*!**************************************************!*\
  17802. !*** ./src/gpu/shaders/include/fixed-point.glsl ***!
  17803. \**************************************************/
  17804. /***/ ((module) => {
  17805. module.exports = "#ifndef _FIXEDPOINT_GLSL\n#define _FIXEDPOINT_GLSL\n#define fixed_t int\n#define fixed2_t ivec2\nconst int FIX_BITS = int(@FIX_BITS@);\nconst float FIX_RESOLUTION = float(@FIX_RESOLUTION@);\n#define itofix(x) fixed_t((x) << FIX_BITS)\n#define fixtoi(f) int((x) >> FIX_BITS)\n#define ftofix(x) fixed_t((x) * FIX_RESOLUTION + 0.5f)\n#define fixtof(f) (float(f) / FIX_RESOLUTION)\n#define ivec2tofix(x) fixed2_t((x) << FIX_BITS)\n#define fixtoivec2(f) ivec2((f) >> FIX_BITS)\n#define vec2tofix(v) fixed2_t((v) * FIX_RESOLUTION + vec2(0.5f))\n#define fixtovec2(f) (vec2(f) / FIX_RESOLUTION)\n#endif"
  17806. /***/ }),
  17807. /***/ "./src/gpu/shaders/include/float16.glsl":
  17808. /*!**********************************************!*\
  17809. !*** ./src/gpu/shaders/include/float16.glsl ***!
  17810. \**********************************************/
  17811. /***/ ((module) => {
  17812. module.exports = "#ifndef _FLOAT16_GLSL\n#define _FLOAT16_GLSL\n#define encodeFloat16(f) (vec2(packf16(f)) / 255.0f)\n#define decodeFloat16(v) unpackf16(uvec2((v) * 255.0f))\n#define encodePairOfFloat16(f) vec4(encodeFloat16((f).x), encodeFloat16((f).y))\n#define decodePairOfFloat16(v) vec2(decodeFloat16((v).rg), decodeFloat16((v).ba))\n#define encodeNullPairOfFloat16() vec4(1.0f)\n#define isNullPairOfFloat16(v) all(equal((v), encodeNullPairOfFloat16()))\n#define encodeDiscardedPairOfFloat16() vec4(0.0f, 1.0f, 0.0f, 1.0f)\n#define isDiscardedPairOfFloat16(v) all(equal((v), encodeDiscardedPairOfFloat16()))\n#define encodeFloat16NaN() vec2(0.5f, 1.0f)\n#define isEncodedFloat16NaN(v) all(equal((v), encodeFloat16NaN()))\nuvec2 packf16( float f)\n{\nuint y = packHalf2x16(vec2(f, 0.0f));\nreturn uvec2(y, y >> 8u) & 0xFFu;\n}\nfloat unpackf16(uvec2 v)\n{\nv &= 0xFFu;\nreturn unpackHalf2x16(v.x | (v.y << 8u)).x;\n}\nbool isEncodedFloat16Zero(vec2 v)\n{\nuvec2 w = uvec2(v * 255.0f);\nreturn 0u == w.x + w.y * (0x80u - w.y);\n}\n#endif"
  17813. /***/ }),
  17814. /***/ "./src/gpu/shaders/include/global.glsl":
  17815. /*!*********************************************!*\
  17816. !*** ./src/gpu/shaders/include/global.glsl ***!
  17817. \*********************************************/
  17818. /***/ ((module) => {
  17819. module.exports = "#ifndef _GLOBAL_GLSL\n#define _GLOBAL_GLSL\n#define threadLocation() ivec2(texCoord * texSize)\n#define outputSize() ivec2(texSize)\n#define threadPixel(img) textureLod((img), texCoord, 0.0f)\n#define pixelAt(img, pos) texelFetch((img), (pos), 0)\n#define pixelAtShortOffset(img, offset) textureLodOffset((img), texCoord, 0.0f, (offset))\n#define pixelAtLongOffset(img, offset) textureLod((img), texCoord + vec2(offset) / texSize, 0.0f)\n#endif"
  17820. /***/ }),
  17821. /***/ "./src/gpu/shaders/include/int32.glsl":
  17822. /*!********************************************!*\
  17823. !*** ./src/gpu/shaders/include/int32.glsl ***!
  17824. \********************************************/
  17825. /***/ ((module) => {
  17826. module.exports = "#ifndef _INT32_GLSL\n#define _INT32_GLSL\nuint decodeUint32(vec4 rgba)\n{\nuvec4 v = uvec4(rgba * 255.0f) & 255u;\nreturn v.x | (v.y << 8u) | (v.z << 16u) | (v.w << 24u);\n}\nvec4 encodeUint32(uint value)\n{\nuvec4 v = uvec4(value, value >> 8u, value >> 16u, value >> 24u) & 255u;\nreturn vec4(v) / 255.0f;\n}\n#endif"
  17827. /***/ }),
  17828. /***/ "./src/gpu/shaders/include/keypoint-descriptors.glsl":
  17829. /*!***********************************************************!*\
  17830. !*** ./src/gpu/shaders/include/keypoint-descriptors.glsl ***!
  17831. \***********************************************************/
  17832. /***/ ((module) => {
  17833. module.exports = "#ifndef _KEYPOINT_DESCRIPTORS_GLSL\n#define _KEYPOINT_DESCRIPTORS_GLSL\n#if !defined(DESCRIPTOR_SIZE)\n#error Must define DESCRIPTOR_SIZE\n#elif !defined(_KEYPOINTS_GLSL)\n#error Must include keypoints.glsl\n#endif\nuint[DESCRIPTOR_SIZE] readKeypointDescriptor(sampler2D encodedKeypoints, int descriptorSize, int extraSize, int encoderLength, KeypointAddress address)\n{\nint descriptorOffset = sizeofEncodedKeypoint(0, extraSize) / 4;\nKeypointAddress descriptorAddress = KeypointAddress(address.base, descriptorOffset);\nuint[DESCRIPTOR_SIZE] descriptor;\nvec4 pixel; uvec4 bytes;\n@unroll\nfor(int i = 0; i < DESCRIPTOR_SIZE; i += 4) {\npixel = readKeypointData(encodedKeypoints, encoderLength, descriptorAddress);\nbytes = uvec4(pixel * 255.0f);\ndescriptor[i] = bytes.r;\ndescriptor[i+1] = bytes.g;\ndescriptor[i+2] = bytes.b;\ndescriptor[i+3] = bytes.a;\ndescriptorAddress.offset++;\n}\nreturn descriptor;\n}\nuint[DESCRIPTOR_SIZE] readKeypointDescriptorFromDB(sampler2D descriptorDB, int descriptorDBStride, int index)\n{\nuint[DESCRIPTOR_SIZE] descriptor;\nint rasterIndex = index * (DESCRIPTOR_SIZE / 4) * int(index >= 0);\nvec4 pixel; uvec4 bytes; ivec2 pos;\n@unroll\nfor(int i = 0; i < DESCRIPTOR_SIZE; i += 4) {\npos = ivec2(rasterIndex % descriptorDBStride, rasterIndex / descriptorDBStride);\npixel = (index >= 0) ? texelFetch(descriptorDB, pos, 0) : vec4(0.0f);\nbytes = uvec4(pixel * 255.0f);\ndescriptor[i] = bytes.r;\ndescriptor[i+1] = bytes.g;\ndescriptor[i+2] = bytes.b;\ndescriptor[i+3] = bytes.a;\nrasterIndex++;\n}\nreturn descriptor;\n}\nint distanceBetweenKeypointDescriptors(uint[DESCRIPTOR_SIZE] a, uint[DESCRIPTOR_SIZE] b)\n{\nconst int[256] POPCNT = int[256](0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8);\nuvec4 xor, u, v;\nint dist = 0;\nivec4 bits;\n@unroll\nfor(int i = 0; i < DESCRIPTOR_SIZE; i += 4) {\nu = uvec4(a[i], a[i+1], a[i+2], a[i+3]);\nv = uvec4(b[i], b[i+1], b[i+2], b[i+3]);\nxor = (u ^ v) & 255u;\nbits = ivec4(POPCNT[xor.x], POPCNT[xor.y], POPCNT[xor.z], POPCNT[xor.w]);\ndist += bits.x + bits.y + bits.z + bits.w;\n}\nreturn dist;\n}\n#endif"
  17834. /***/ }),
  17835. /***/ "./src/gpu/shaders/include/keypoint-matches.glsl":
  17836. /*!*******************************************************!*\
  17837. !*** ./src/gpu/shaders/include/keypoint-matches.glsl ***!
  17838. \*******************************************************/
  17839. /***/ ((module) => {
  17840. module.exports = "#ifndef _KEYPOINT_MATCHES_GLSL\n#define _KEYPOINT_MATCHES_GLSL\n@include \"int32.glsl\"\nconst int MATCH_INDEX_BITS = int(@MATCH_INDEX_BITS@);\nconst int MATCH_INDEX_MASK = int(@MATCH_INDEX_MASK@);\nconst int MATCH_MAX_INDEX = int(@MATCH_MAX_INDEX@);\nconst int MATCH_MAX_DISTANCE = int(@MATCH_MAX_DISTANCE@);\nstruct KeypointMatch\n{\nint index;\nint dist;\n};\nvec4 encodeKeypointMatch(KeypointMatch candidate)\n{\nuint index = uint(candidate.index & MATCH_INDEX_MASK);\nuint dist = uint(clamp(candidate.dist, 0, MATCH_MAX_DISTANCE));\nuint u32 = index | (dist << MATCH_INDEX_BITS);\nreturn encodeUint32(u32);\n}\nKeypointMatch decodeKeypointMatch(vec4 rgba)\n{\nuint u32 = decodeUint32(rgba);\nint dist = int(u32 >> MATCH_INDEX_BITS);\nint index = int(u32 & uint(MATCH_INDEX_MASK));\nreturn KeypointMatch(index, dist);\n}\nconst KeypointMatch MATCH_NOT_FOUND = KeypointMatch(MATCH_MAX_INDEX, MATCH_MAX_DISTANCE);\n#endif"
  17841. /***/ }),
  17842. /***/ "./src/gpu/shaders/include/keypoints.glsl":
  17843. /*!************************************************!*\
  17844. !*** ./src/gpu/shaders/include/keypoints.glsl ***!
  17845. \************************************************/
  17846. /***/ ((module) => {
  17847. module.exports = "#ifndef _KEYPOINTS_GLSL\n#define _KEYPOINTS_GLSL\n@include \"math.glsl\"\n@include \"fixed-point.glsl\"\n@include \"float16.glsl\"\n@include \"pyramids.glsl\"\nstruct Keypoint\n{\nvec2 position;\nfloat lod;\nfloat orientation;\nfloat score;\nuint flags;\n};\nstruct KeypointAddress\n{\nint base;\nint offset;\n};\nconst int MIN_KEYPOINT_SIZE = int(@MIN_KEYPOINT_SIZE@);\nconst int MAX_DESCRIPTOR_SIZE = int(@MAX_DESCRIPTOR_SIZE@);\nconst uint KPF_NONE = 0u;\nconst uint KPF_NULL = 1u;\nconst uint KPF_DISCARDED = 2u;\n#define encodeKeypointScore(score) encodeFloat16(score)\n#define decodeKeypointScore(encodedScore) decodeFloat16(encodedScore)\n#define encodeKeypointOrientation(angle) ((angle) * INV_PI_OVER_2 + 0.5f)\n#define decodeKeypointOrientation(value) ((value) * TWO_PI - PI)\n#define encodeNullKeypoint() (vec4(1.0f))\n#define encodeDiscardedKeypoint() (vec4(0.0f))\n#define isNullKeypoint(keypoint) ((((keypoint).flags) & KPF_NULL) != 0u)\n#define isDiscardedKeypoint(keypoint) ((((keypoint).flags) & KPF_DISCARDED) != 0u)\n#define isBadKeypoint(keypoint) ((keypoint).score < 0.0f)\n#define sizeofEncodedKeypoint(descriptorSize, extraSize) (MIN_KEYPOINT_SIZE + (descriptorSize) + (extraSize))\n#define sizeofEncodedKeypointHeader() sizeofEncodedKeypoint(0,0)\n#define findKeypointIndex(address, descriptorSize, extraSize) ((address).base / ((sizeofEncodedKeypoint((descriptorSize), (extraSize))) / 4))\nvec4 readKeypointData(sampler2D encodedKeypoints, int encoderLength, KeypointAddress address)\n{\nint rasterIndex = address.base + address.offset;\nvec4 data = pixelAt(encodedKeypoints, ivec2(rasterIndex % encoderLength, rasterIndex / encoderLength));\nreturn rasterIndex < encoderLength * encoderLength ? data : encodeNullKeypoint();\n}\nKeypointAddress findKeypointAddress(ivec2 thread, int encoderLength, int descriptorSize, int extraSize)\n{\nint threadRaster = thread.y * encoderLength + thread.x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nint keypointIndex = int(threadRaster / pixelsPerKeypoint);\nKeypointAddress address = KeypointAddress(\nkeypointIndex * pixelsPerKeypoint,\nthreadRaster % pixelsPerKeypoint\n);\nreturn address;\n}\nKeypoint decodeKeypoint(sampler2D encodedKeypoints, int encoderLength, KeypointAddress address)\n{\nKeypoint keypoint;\nKeypointAddress positionAddress = KeypointAddress(address.base, 0);\nKeypointAddress propertiesAddress = KeypointAddress(address.base, 1);\nvec4 rawEncodedPosition = readKeypointData(encodedKeypoints, encoderLength, positionAddress);\nivec4 encodedPosition = ivec4(rawEncodedPosition * 255.0f);\nkeypoint.position = fixtovec2(fixed2_t(\nencodedPosition.r | (encodedPosition.g << 8),\nencodedPosition.b | (encodedPosition.a << 8)\n));\nvec4 rawEncodedProperties = readKeypointData(encodedKeypoints, encoderLength, propertiesAddress);\nkeypoint.lod = decodeLod(rawEncodedProperties.r);\nkeypoint.orientation = decodeKeypointOrientation(rawEncodedProperties.g);\nkeypoint.score = decodeKeypointScore(rawEncodedProperties.ba);\nbool isNull = all(equal(rawEncodedPosition, vec4(1)));\nbool isDiscarded = all(equal(rawEncodedPosition + rawEncodedProperties, vec4(0)));\nkeypoint.score = (isNull || isDiscarded) ? -1.0f : keypoint.score;\nkeypoint.flags = KPF_NONE;\nkeypoint.flags |= KPF_NULL * uint(isNull);\nkeypoint.flags |= KPF_DISCARDED * uint(isDiscarded);\nreturn keypoint;\n}\nvec4 encodeKeypointPosition(vec2 position)\n{\nconst vec2 zeros = vec2(0.0f);\nfixed2_t pos = vec2tofix(max(position, zeros));\nfixed2_t lo = pos & 255;\nfixed2_t hi = (pos >> 8) & 255;\nreturn vec4(lo.x, hi.x, lo.y, hi.y) / 255.0f;\n}\n#endif"
  17848. /***/ }),
  17849. /***/ "./src/gpu/shaders/include/math.glsl":
  17850. /*!*******************************************!*\
  17851. !*** ./src/gpu/shaders/include/math.glsl ***!
  17852. \*******************************************/
  17853. /***/ ((module) => {
  17854. module.exports = "#ifndef _MATH_GLSL\n#define _MATH_GLSL\n#define TWO_PI 6.28318530718f\n#define PI 3.14159265359f\n#define PI_OVER_2 1.57079632679f\n#define PI_OVER_4 0.78539816339f\n#define INV_PI 0.3183098861837907f\n#define INV_PI_OVER_2 0.15915494309189535f\nconst highp float INFINITY = 1.0f / 0.0f;\nfloat fastAtan(float x)\n{\nfloat w = 1.0f - abs(x);\nreturn (w >= 0.0f) ? ((PI_OVER_4 + 0.273f * w) * x) :\n(sign(x) * PI_OVER_2 - (PI_OVER_4 + 0.273f * (1.0f - abs(1.0f / x))) / x);\n}\nfloat fastAtan2(float y, float x)\n{\nreturn (x == 0.0f) ? PI_OVER_2 * sign(y) : fastAtan(y / x) + float(x < 0.0f) * PI * sign(y);\n}\n#endif"
  17855. /***/ }),
  17856. /***/ "./src/gpu/shaders/include/pyramids.glsl":
  17857. /*!***********************************************!*\
  17858. !*** ./src/gpu/shaders/include/pyramids.glsl ***!
  17859. \***********************************************/
  17860. /***/ ((module) => {
  17861. module.exports = "#ifndef _PYRAMIDS_GLSL\n#define _PYRAMIDS_GLSL\n#define pyrPixel(pyr, lod) textureLod((pyr), texCoord, (lod))\n#define pyrPixelAtOffset(pyr, lod, pot, offset) textureLod((pyr), texCoord + ((pot) * vec2(offset)) / texSize, (lod))\n#define pyrPixelAt(pyr, pos, lod) textureLod((pyr), (vec2(pos) + vec2(0.5f)) / texSize, (lod))\n#define pyrPixelAtEx(pyr, pos, lod, pyrBaseSize) textureLod((pyr), (vec2(pos) + vec2(0.5f)) / vec2(pyrBaseSize), (lod))\n#define pyrSubpixelAtEx(pyr, pos, lod, pyrBaseSize) textureLod((pyr), ((pos) + vec2(0.5f)) / vec2(pyrBaseSize), (lod))\n#define pyrSubpixelAtExOffset(pyr, pos, lod, pot, offset, pyrBaseSize) textureLod((pyr), (((pos) + vec2(0.5f)) + ((pot) * vec2(offset))) / vec2(pyrBaseSize), (lod))\nconst int PYRAMID_MAX_LEVELS = int(@PYRAMID_MAX_LEVELS@);\nconst float F_PYRAMID_MAX_LEVELS = float(@PYRAMID_MAX_LEVELS@);\nconst float LOG2_PYRAMID_MAX_SCALE = float(@LOG2_PYRAMID_MAX_SCALE@);\n#define encodeLod(lod) ((LOG2_PYRAMID_MAX_SCALE + (lod)) / (LOG2_PYRAMID_MAX_SCALE + F_PYRAMID_MAX_LEVELS))\nfloat decodeLod(float encodedLod)\n{\nfloat lod = encodedLod * (LOG2_PYRAMID_MAX_SCALE + F_PYRAMID_MAX_LEVELS) - LOG2_PYRAMID_MAX_SCALE;\nreturn lod - lod * step(1.0f, encodedLod);\n}\n#define LOD_EPS 0.0625f\nconst float ENCODED_LOD_EPS = (LOD_EPS / (LOG2_PYRAMID_MAX_SCALE + F_PYRAMID_MAX_LEVELS));\n#define isSameLod(lod1, lod2) (abs((lod1) - (lod2)) < LOD_EPS)\n#define isSameEncodedLod(alpha1, alpha2) (abs((alpha1) - (alpha2)) < ENCODED_LOD_EPS)\n#endif"
  17862. /***/ }),
  17863. /***/ "./src/gpu/shaders/include/subpixel.glsl":
  17864. /*!***********************************************!*\
  17865. !*** ./src/gpu/shaders/include/subpixel.glsl ***!
  17866. \***********************************************/
  17867. /***/ ((module) => {
  17868. module.exports = "#ifndef _SUBPIXEL_GLSL\n#define _SUBPIXEL_GLSL\n#define subpixelAt(image, pos) textureLod((image), ((pos) + vec2(0.5f)) / texSize, 0.0f)\nvec4 subpixelAtBI(sampler2D image, vec2 pos)\n{\nvec2 frc = fract(pos);\nvec2 ifrc = vec2(1.0f) - frc;\nvec2 p = (floor(pos) + vec2(0.5f)) / vec2(textureSize(image, 0));\nvec4 pix00 = textureLod(image, p, 0.0f);\nvec4 pix10 = textureLodOffset(image, p, 0.0f, ivec2(1,0));\nvec4 pix01 = textureLodOffset(image, p, 0.0f, ivec2(0,1));\nvec4 pix11 = textureLodOffset(image, p, 0.0f, ivec2(1,1));\nmat4 pix = mat4(pix00, pix10, pix01, pix11);\nvec4 mul = vec4(ifrc.x * ifrc.y, frc.x * ifrc.y, ifrc.x * frc.y, frc.x * frc.y);\nreturn pix * mul;\n}\n#endif"
  17869. /***/ }),
  17870. /***/ "./src/gpu/shaders/keypoints/allocate-descriptors.glsl":
  17871. /*!*************************************************************!*\
  17872. !*** ./src/gpu/shaders/keypoints/allocate-descriptors.glsl ***!
  17873. \*************************************************************/
  17874. /***/ ((module) => {
  17875. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D inputEncodedKeypoints;\nuniform int inputDescriptorSize;\nuniform int inputExtraSize;\nuniform int inputEncoderLength;\nuniform int outputDescriptorSize;\nuniform int outputExtraSize;\nuniform int outputEncoderLength;\nconst vec4 EMPTY_DESCRIPTOR = vec4(0.0f);\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress myAddress = findKeypointAddress(thread, outputEncoderLength, outputDescriptorSize, outputExtraSize);\nint myIndex = findKeypointIndex(myAddress, outputDescriptorSize, outputExtraSize);\nint headerSize = sizeofEncodedKeypointHeader();\nbool isDescriptor = (myAddress.offset >= (headerSize + outputExtraSize) / 4);\nint addressOffset = myAddress.offset;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(inputDescriptorSize, inputExtraSize) / 4;\nKeypointAddress otherAddress = KeypointAddress(myIndex * pixelsPerKeypoint, addressOffset);\ncolor = isDescriptor ? EMPTY_DESCRIPTOR : readKeypointData(inputEncodedKeypoints, inputEncoderLength, otherAddress);\n}"
  17876. /***/ }),
  17877. /***/ "./src/gpu/shaders/keypoints/allocate-extra.glsl":
  17878. /*!*******************************************************!*\
  17879. !*** ./src/gpu/shaders/keypoints/allocate-extra.glsl ***!
  17880. \*******************************************************/
  17881. /***/ ((module) => {
  17882. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D inputEncodedKeypoints;\nuniform int inputDescriptorSize;\nuniform int inputExtraSize;\nuniform int inputEncoderLength;\nuniform int outputDescriptorSize;\nuniform int outputExtraSize;\nuniform int outputEncoderLength;\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress myAddress = findKeypointAddress(thread, outputEncoderLength, outputDescriptorSize, outputExtraSize);\nint myIndex = findKeypointIndex(myAddress, outputDescriptorSize, outputExtraSize);\nint headerSize = sizeofEncodedKeypointHeader();\nbool isHead = (myAddress.offset < headerSize / 4);\nbool isDescriptor = (myAddress.offset >= (headerSize + outputExtraSize) / 4);\nbool isExtra = (!isHead && !isDescriptor);\nint numberOfExtraPixels = outputExtraSize / 4;\nint addressOffset = myAddress.offset - int(isDescriptor) * numberOfExtraPixels;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(inputDescriptorSize, inputExtraSize) / 4;\nKeypointAddress otherAddress = KeypointAddress(myIndex * pixelsPerKeypoint, addressOffset);\ncolor = isExtra ? vec4(0.0f) : readKeypointData(inputEncodedKeypoints, inputEncoderLength, otherAddress);\n}"
  17883. /***/ }),
  17884. /***/ "./src/gpu/shaders/keypoints/apply-homography.glsl":
  17885. /*!*********************************************************!*\
  17886. !*** ./src/gpu/shaders/keypoints/apply-homography.glsl ***!
  17887. \*********************************************************/
  17888. /***/ ((module) => {
  17889. module.exports = "@include \"keypoints.glsl\"\nuniform mat3 homography;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\ncolor = pixel;\nif(address.offset != 0)\nreturn;\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\nif(isBadKeypoint(keypoint))\nreturn;\nvec3 pos3 = homography * vec3(keypoint.position, 1.0f);\ncolor = encodeKeypointPosition(pos3.xy / pos3.z);\n}"
  17890. /***/ }),
  17891. /***/ "./src/gpu/shaders/keypoints/bf-knn.glsl":
  17892. /*!***********************************************!*\
  17893. !*** ./src/gpu/shaders/keypoints/bf-knn.glsl ***!
  17894. \***********************************************/
  17895. /***/ ((module) => {
  17896. module.exports = "@include \"keypoints.glsl\"\n@include \"keypoint-descriptors.glsl\"\n@include \"keypoint-matches.glsl\"\nuniform sampler2D encodedMatches;\nuniform sampler2D encodedFilters;\nuniform int matcherLength;\nuniform sampler2D dbEncodedKeypoints;\nuniform int dbDescriptorSize;\nuniform int dbExtraSize;\nuniform int dbEncoderLength;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int passId;\n#ifndef NUMBER_OF_KEYPOINTS_PER_PASS\n#error Undefined NUMBER_OF_KEYPOINTS_PER_PASS\n#endif\nconst int INFINITE_DISTANCE = MATCH_MAX_DISTANCE + 1;\nvoid main()\n{\nivec2 thread = threadLocation();\nint keypointIndex = thread.x + thread.y * matcherLength;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\ncolor = encodeKeypointMatch(MATCH_NOT_FOUND);\nif(isBadKeypoint(keypoint))\nreturn;\nKeypointMatch bestMatch = decodeKeypointMatch(threadPixel(encodedMatches));\nKeypointMatch filterMatch = decodeKeypointMatch(threadPixel(encodedFilters));\nuint[DESCRIPTOR_SIZE] descriptor = readKeypointDescriptor(encodedKeypoints, descriptorSize, extraSize, encoderLength, address);\nuint[DESCRIPTOR_SIZE] dbDescriptor;\nint dbPixelsPerKeypoint = sizeofEncodedKeypoint(dbDescriptorSize, dbExtraSize) / 4;\nfor(int i = 0; i < NUMBER_OF_KEYPOINTS_PER_PASS; i++) {\nint dbKeypointIndex = passId * NUMBER_OF_KEYPOINTS_PER_PASS + i;\nKeypointAddress dbAddress = KeypointAddress(dbKeypointIndex * dbPixelsPerKeypoint, 0);\nKeypoint dbKeypoint = decodeKeypoint(dbEncodedKeypoints, dbEncoderLength, dbAddress);\ndbDescriptor = readKeypointDescriptor(dbEncodedKeypoints, dbDescriptorSize, dbExtraSize, dbEncoderLength, dbAddress);\nint dist = !isBadKeypoint(dbKeypoint) ? distanceBetweenKeypointDescriptors(descriptor, dbDescriptor) : INFINITE_DISTANCE;\nbestMatch.index = all(bvec2(\ndist < bestMatch.dist || (dist == bestMatch.dist && dbKeypointIndex > bestMatch.index),\ndist > filterMatch.dist || (dist == filterMatch.dist && dbKeypointIndex < filterMatch.index)\n)) ? dbKeypointIndex : bestMatch.index;\nbestMatch.dist = dbKeypointIndex == bestMatch.index ? dist : bestMatch.dist;\n}\ncolor = encodeKeypointMatch(bestMatch);\n}"
  17897. /***/ }),
  17898. /***/ "./src/gpu/shaders/keypoints/clip-border.glsl":
  17899. /*!****************************************************!*\
  17900. !*** ./src/gpu/shaders/keypoints/clip-border.glsl ***!
  17901. \****************************************************/
  17902. /***/ ((module) => {
  17903. module.exports = "@include \"keypoints.glsl\"\nuniform int imageWidth;\nuniform int imageHeight;\nuniform int borderTop;\nuniform int borderRight;\nuniform int borderBottom;\nuniform int borderLeft;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress addr = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, addr);\nvec2 p = keypoint.position;\nbool withinBorder = any(lessThan(\nvec4(p.x, p.y, -p.x, -p.y),\nvec4(borderLeft, borderTop, borderRight - (imageWidth - 1), borderBottom - (imageHeight - 1))\n));\nvec4 pixel = threadPixel(encodedKeypoints);\nvec4 nullPixel = encodeNullKeypoint();\ncolor = withinBorder ? nullPixel : pixel;\n}"
  17904. /***/ }),
  17905. /***/ "./src/gpu/shaders/keypoints/clip.glsl":
  17906. /*!*********************************************!*\
  17907. !*** ./src/gpu/shaders/keypoints/clip.glsl ***!
  17908. \*********************************************/
  17909. /***/ ((module) => {
  17910. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int maxKeypoints;\nvoid main()\n{\nivec2 thread = threadLocation();\nint newEncoderLength = outputSize().x;\nKeypointAddress address = findKeypointAddress(thread, newEncoderLength, descriptorSize, extraSize);\nint index = findKeypointIndex(address, descriptorSize, extraSize);\nvec4 pixel = readKeypointData(encodedKeypoints, encoderLength, address);\ncolor = index < maxKeypoints ? pixel : encodeNullKeypoint();\n}"
  17911. /***/ }),
  17912. /***/ "./src/gpu/shaders/keypoints/distance-filter.glsl":
  17913. /*!********************************************************!*\
  17914. !*** ./src/gpu/shaders/keypoints/distance-filter.glsl ***!
  17915. \********************************************************/
  17916. /***/ ((module) => {
  17917. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedKeypointsA;\nuniform int encoderLengthA;\nuniform sampler2D encodedKeypointsB;\nuniform int encoderLengthB;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform float threshold;\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint index = findKeypointIndex(address, descriptorSize, extraSize);\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nvec4 data = readKeypointData(encodedKeypointsA, encoderLengthA, address);\ncolor = data;\nif(address.offset >= sizeofEncodedKeypointHeader() / 4)\nreturn;\nKeypoint keypointA = decodeKeypoint(encodedKeypointsA, encoderLengthA, address);\nKeypoint keypointB = decodeKeypoint(encodedKeypointsB, encoderLengthB, address);\ncolor = encodeNullKeypoint();\nif(isNullKeypoint(keypointA) && isNullKeypoint(keypointB))\nreturn;\ncolor = encodeDiscardedKeypoint();\nif(isDiscardedKeypoint(keypointA) || isDiscardedKeypoint(keypointB))\nreturn;\ncolor = encodeDiscardedKeypoint();\nif(isNullKeypoint(keypointA) || isNullKeypoint(keypointB))\nreturn;\nvec2 delta = keypointA.position - keypointB.position;\nbool shouldKeep = (dot(delta, delta) <= threshold * threshold);\ncolor = shouldKeep ? data : encodeDiscardedKeypoint();\n}"
  17918. /***/ }),
  17919. /***/ "./src/gpu/shaders/keypoints/encode-keypoint-long-offsets.glsl":
  17920. /*!*********************************************************************!*\
  17921. !*** ./src/gpu/shaders/keypoints/encode-keypoint-long-offsets.glsl ***!
  17922. \*********************************************************************/
  17923. /***/ ((module) => {
  17924. module.exports = "@include \"float16.glsl\"\nuniform sampler2D offsetsImage;\nuniform ivec2 imageSize;\n#ifndef MAX_ITERATIONS\n#error Undefined MAX_ITERATIONS\n#endif\n#define decodeSkipOffset(pixel) (int((pixel).g * 255.0f) | (int((pixel).a * 255.0f) << 8))\n#define encodeSkipOffset(offset) (vec2((offset) & 255, (offset) >> 8) / 255.0f)\nvoid main()\n{\nvec4 pixel = threadPixel(offsetsImage);\nivec2 thread = threadLocation();\nint rasterIndex = thread.y * imageSize.x + thread.x;\nint offset = decodeSkipOffset(pixel);\nint totalOffset = offset;\nvec2 encodedScore = pixel.rb;\nivec2 pos = thread; int allow = 1;\n@unroll\nfor(int i = 0; i < MAX_ITERATIONS; i++) {\nallow *= int(pos.y < imageSize.y) * int(isEncodedFloat16Zero(pixel.rb));\nrasterIndex += allow * offset;\npos = ivec2(rasterIndex % imageSize.x, rasterIndex / imageSize.x);\npixel = pixelAt(offsetsImage, pos);\noffset = decodeSkipOffset(pixel);\ntotalOffset += allow * offset;\n}\ntotalOffset = min(totalOffset, 65535);\ncolor.rb = encodedScore;\ncolor.ga = encodeSkipOffset(totalOffset);\n}"
  17925. /***/ }),
  17926. /***/ "./src/gpu/shaders/keypoints/encode-keypoint-offsets.glsl":
  17927. /*!****************************************************************!*\
  17928. !*** ./src/gpu/shaders/keypoints/encode-keypoint-offsets.glsl ***!
  17929. \****************************************************************/
  17930. /***/ ((module) => {
  17931. module.exports = "@include \"float16.glsl\"\nuniform sampler2D corners;\nuniform ivec2 imageSize;\nvoid main()\n{\nvec4 pixel = threadPixel(corners);\nivec2 pos = threadLocation();\nvec2 encodedScore = pixel.rb;\nint offset = 0, allow = 1, jumped = 0;\n#define READ(j) ; \\\nallow *= int(pos.y < imageSize.y) * int(isEncodedFloat16Zero(pixel.rb)); \\\noffset += allow; \\\npos.x = (pos.x + 1) % imageSize.x; \\\npos.y += int(pos.x == 0); \\\npixel = (0 != (jumped |= int(pos.x == 0))) ? pixelAtShortOffset(corners, ivec2((j),1)) : pixelAtShortOffset(corners, ivec2((j),0))\nREAD(1); READ(2); READ(3); READ(4); READ(5); READ(6); READ(7);\ncolor.rb = encodedScore;\ncolor.ga = vec2(offset, 0) / 255.0f;\n}"
  17932. /***/ }),
  17933. /***/ "./src/gpu/shaders/keypoints/encode-keypoint-positions.glsl":
  17934. /*!******************************************************************!*\
  17935. !*** ./src/gpu/shaders/keypoints/encode-keypoint-positions.glsl ***!
  17936. \******************************************************************/
  17937. /***/ ((module) => {
  17938. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D offsetsImage;\nuniform ivec2 imageSize;\nuniform int passId;\nuniform int numPasses;\nuniform int keypointLimit;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#define decodeSkipOffset(pixel) (int((pixel).g * 255.0f) | (int((pixel).a * 255.0f) << 8))\nbool findQthKeypoint(int q, int p, inout ivec2 position, out vec4 pixel)\n{\nint notFirstPass = int(passId > 0);\nposition *= notFirstPass;\np |= -(1 - notFirstPass);\np -= notFirstPass;\nint rasterIndex = position.y * imageSize.x + position.x;\nwhile(position.y < imageSize.y && p != q) {\nposition = ivec2(rasterIndex % imageSize.x, rasterIndex / imageSize.x);\npixel = texelFetch(offsetsImage, position, 0);\np += int(!isEncodedFloat16Zero(pixel.rb));\nrasterIndex += max(1, decodeSkipOffset(pixel));\n}\nreturn (p == q);\n}\nvoid main()\n{\nivec2 thread = threadLocation();\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint q = findKeypointIndex(address, descriptorSize, extraSize);\ncolor = vec4(0.0f);\nif(address.offset != 0)\nreturn;\ncolor = threadPixel(encodedKeypoints);\nint numPixels = encoderLength * encoderLength;\nint maxKeypoints = numPixels / pixelsPerKeypoint;\nint maxKeypointsPerPass = maxKeypoints / numPasses + int(maxKeypoints % numPasses != 0);\nint targetPassId = q / maxKeypointsPerPass;\nif(passId != targetPassId)\nreturn;\nint lastIndexFromPrevPass = passId * maxKeypointsPerPass - 1;\nKeypointAddress lastAddressFromPrevPass = KeypointAddress(max(0, lastIndexFromPrevPass) * pixelsPerKeypoint, 0);\nKeypoint lastKeypointFromPrevPass = decodeKeypoint(encodedKeypoints, encoderLength, lastAddressFromPrevPass);\nivec2 position = passId > 0 ? ivec2(lastKeypointFromPrevPass.position) : ivec2(0);\nvec4 pixel;\ncolor = encodeNullKeypoint();\nif(q >= min(maxKeypoints, keypointLimit) || !findQthKeypoint(q, lastIndexFromPrevPass, position, pixel))\nreturn;\ncolor = encodeKeypointPosition(vec2(position));\n}"
  17939. /***/ }),
  17940. /***/ "./src/gpu/shaders/keypoints/encode-keypoint-properties.glsl":
  17941. /*!*******************************************************************!*\
  17942. !*** ./src/gpu/shaders/keypoints/encode-keypoint-properties.glsl ***!
  17943. \*******************************************************************/
  17944. /***/ ((module) => {
  17945. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D corners;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvoid main()\n{\nivec2 thread = threadLocation();\nvec4 pixel = threadPixel(encodedKeypoints);\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint q = findKeypointIndex(address, descriptorSize, extraSize);\ncolor = pixel;\nif(address.offset != 1)\nreturn;\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\nvec4 kpix = pixelAt(corners, ivec2(keypoint.position));\nkeypoint.score = decodeFloat16(kpix.rb);\ncolor.r = kpix.a;\ncolor.g = encodeKeypointOrientation(0.0f);\ncolor.ba = encodeKeypointScore(keypoint.score);\n}"
  17946. /***/ }),
  17947. /***/ "./src/gpu/shaders/keypoints/encode-keypoints.glsl":
  17948. /*!*********************************************************!*\
  17949. !*** ./src/gpu/shaders/keypoints/encode-keypoints.glsl ***!
  17950. \*********************************************************/
  17951. /***/ ((module) => {
  17952. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D corners;\nuniform mediump usampler2D lookupTable;\nuniform int stride;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int encoderCapacity;\nconst uvec2 NULL_ELEMENT = uvec2(0xFFFFu);\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint index = findKeypointIndex(address, descriptorSize, extraSize);\nivec2 pos = ivec2(index % stride, index / stride);\nuvec4 entry = texelFetch(lookupTable, pos, 0);\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nint rasterIndex = address.base + address.offset;\nint numberOfPixels = encoderLength * encoderLength;\nint numberOfValidPixels = numberOfPixels - (numberOfPixels % pixelsPerKeypoint);\nint maxEncoderCapacity = numberOfValidPixels / pixelsPerKeypoint;\ncolor = encodeNullKeypoint();\nif(all(equal(entry.xy, NULL_ELEMENT)) || index >= min(encoderCapacity, maxEncoderCapacity))\nreturn;\ncolor = encodeKeypointPosition(vec2(entry.xy));\nif(address.offset == 0)\nreturn;\ncolor = vec4(0.0f);\nif(address.offset >= sizeofEncodedKeypointHeader() / 4)\nreturn;\nvec4 pixel = texelFetch(corners, ivec2(entry.xy), 0);\nvec2 encodedScore = encodeKeypointScore(decodeFloat16(pixel.rb));\nfloat encodedOrientation = encodeKeypointOrientation(0.0f);\nfloat encodedLod = pixel.a;\ncolor = vec4(encodedLod, encodedOrientation, encodedScore);\n}"
  17953. /***/ }),
  17954. /***/ "./src/gpu/shaders/keypoints/encode-null-keypoints.glsl":
  17955. /*!**************************************************************!*\
  17956. !*** ./src/gpu/shaders/keypoints/encode-null-keypoints.glsl ***!
  17957. \**************************************************************/
  17958. /***/ ((module) => {
  17959. module.exports = "@include \"keypoints.glsl\"\nvoid main()\n{\ncolor = encodeNullKeypoint();\n}"
  17960. /***/ }),
  17961. /***/ "./src/gpu/shaders/keypoints/fast.glsl":
  17962. /*!*********************************************!*\
  17963. !*** ./src/gpu/shaders/keypoints/fast.glsl ***!
  17964. \*********************************************/
  17965. /***/ ((module) => {
  17966. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D corners;\nuniform sampler2D pyramid;\nuniform float lod;\nuniform int threshold;\n#define USE_VARYINGS 1\n#if !defined(FAST_TYPE)\n#error Undefined FAST_TYPE\n#elif FAST_TYPE == 916\nin vec2 v_pix0, v_pix1, v_pix2, v_pix3, v_pix4, v_pix5, v_pix6, v_pix7,\nv_pix8, v_pix9, v_pix10,v_pix11,v_pix12,v_pix13,v_pix14,v_pix15;\n#else\n#error Invalid FAST_TYPE\n#endif\n#define PIX(x,y) pyrPixelAtOffset(pyramid, lod, pot, ivec2((x),(y))).g\n#define XIP(v) textureLod(pyramid, (v), lod).g\nvoid main()\n{\nfloat pixel = threadPixel(pyramid).g;\nvec4 prev = threadPixel(corners);\nivec2 thread = threadLocation();\nivec2 size = outputSize();\nfloat pot = exp2(lod);\nfloat t = float(clamp(threshold, 0, 255)) / 255.0f;\nfloat ct = pixel + t, c_t = pixel - t;\ncolor = vec4(prev.r, pixel, prev.ba);\n#if FAST_TYPE == 916\nconst ivec4 margin = ivec4(3, 3, 4, 4);\nif(any(lessThan(ivec4(thread, size - thread), margin)))\nreturn;\n#if USE_VARYINGS\nfloat p0 = XIP(v_pix0), p4 = XIP(v_pix4), p8 = XIP(v_pix8), p12 = XIP(v_pix12);\n#else\nfloat p0 = PIX(0,3), p4 = PIX(3,0), p8 = PIX(0,-3), p12 = PIX(-3,0);\n#endif\nbvec4 brighter = bvec4(p0 > ct, p4 > ct, p8 > ct, p12 > ct);\nbvec4 darker = bvec4(p0 < c_t, p4 < c_t, p8 < c_t, p12 < c_t);\nbvec4 bpairs = bvec4(all(brighter.xy), all(brighter.yz), all(brighter.zw), all(brighter.wx));\nbvec4 dpairs = bvec4(all(darker.xy), all(darker.yz), all(darker.zw), all(darker.wx));\nif(!(any(bpairs) || any(dpairs)))\nreturn;\n#if USE_VARYINGS\nfloat p1 = XIP(v_pix1), p2 = XIP(v_pix2), p3 = XIP(v_pix3),\np5 = XIP(v_pix5), p6 = XIP(v_pix6), p7 = XIP(v_pix7),\np9 = XIP(v_pix9), p10 = XIP(v_pix10), p11 = XIP(v_pix11),\np13 = XIP(v_pix13), p14 = XIP(v_pix14), p15 = XIP(v_pix15);\n#else\nfloat p1 = PIX(1,3), p2 = PIX(2,2), p3 = PIX(3,1),\np5 = PIX(3,-1), p6 = PIX(2,-2), p7 = PIX(1,-3),\np9 = PIX(-1,-3), p10 = PIX(-2,-2), p11 = PIX(-3,-1),\np13 = PIX(-3,1), p14 = PIX(-2,2), p15 = PIX(-1,3);\n#endif\nbool A=(p0>ct),B=(p1>ct),C=(p2>ct),D=(p3>ct),E=(p4>ct),F=(p5>ct),G=(p6>ct),H=(p7>ct),I=(p8>ct),J=(p9>ct),K=(p10>ct),L=(p11>ct),M=(p12>ct),N=(p13>ct),O=(p14>ct),P=(p15>ct),a=(p0<c_t),b=(p1<c_t),c=(p2<c_t),d=(p3<c_t),e=(p4<c_t),f=(p5<c_t),g=(p6<c_t),h=(p7<c_t),i=(p8<c_t),j=(p9<c_t),k=(p10<c_t),l=(p11<c_t),m=(p12<c_t),n=(p13<c_t),o=(p14<c_t),p=(p15<c_t);\nbool isCorner=A&&(B&&(K&&L&&J&&(M&&N&&O&&P||G&&H&&I&&(M&&N&&O||F&&(M&&N||E&&(M||D))))||C&&(K&&L&&M&&(N&&O&&P||G&&H&&I&&J&&(N&&O||F&&(N||E)))||D&&(N&&(L&&M&&(K&&G&&H&&I&&J&&(O||F)||O&&P)||k&&l&&m&&e&&f&&g&&h&&i&&j)||E&&(O&&(M&&N&&(K&&L&&G&&H&&I&&J||P)||k&&l&&m&&n&&f&&g&&h&&i&&j)||F&&(P&&(N&&O||k&&l&&m&&n&&o&&g&&h&&i&&j)||G&&(O&&P||H&&(P||I)||k&&l&&m&&n&&o&&p&&h&&i&&j)||k&&l&&m&&n&&o&&h&&i&&j&&(p||g))||k&&l&&m&&n&&h&&i&&j&&(o&&(p||g)||f&&(o&&p||g)))||k&&l&&m&&h&&i&&j&&(n&&(o&&p||g&&(o||f))||e&&(n&&o&&p||g&&(n&&o||f))))||k&&l&&h&&i&&j&&(m&&(n&&o&&p||g&&(n&&o||f&&(n||e)))||d&&(m&&n&&o&&p||g&&(m&&n&&o||f&&(m&&n||e)))))||k&&h&&i&&j&&(l&&(m&&n&&o&&p||g&&(m&&n&&o||f&&(m&&n||e&&(m||d))))||c&&(l&&m&&n&&o&&p||g&&(l&&m&&n&&o||f&&(l&&m&&n||e&&(l&&m||d))))))||K&&I&&J&&(L&&M&&N&&O&&P||G&&H&&(L&&M&&N&&O||F&&(L&&M&&N||E&&(L&&M||D&&(L||C)))))||h&&i&&j&&(b&&(k&&l&&m&&n&&o&&p||g&&(k&&l&&m&&n&&o||f&&(k&&l&&m&&n||e&&(k&&l&&m||d&&(k&&l||c)))))||k&&(l&&m&&n&&o&&p||g&&(l&&m&&n&&o||f&&(l&&m&&n||e&&(l&&m||d&&(l||c)))))))||B&&(H&&I&&J&&(K&&L&&M&&N&&O&&P&&a||G&&(K&&L&&M&&N&&O&&a||F&&(K&&L&&M&&N&&a||E&&(K&&L&&M&&a||D&&(K&&L&&a||C)))))||a&&k&&i&&j&&(l&&m&&n&&o&&p||g&&h&&(l&&m&&n&&o||f&&(l&&m&&n||e&&(l&&m||d&&(l||c))))))||C&&(K&&H&&I&&J&&(L&&M&&N&&O&&P&&a&&b||G&&(L&&M&&N&&O&&a&&b||F&&(L&&M&&N&&a&&b||E&&(L&&M&&a&&b||D))))||a&&b&&k&&l&&j&&(m&&n&&o&&p||g&&h&&i&&(m&&n&&o||f&&(m&&n||e&&(m||d)))))||D&&(K&&L&&H&&I&&J&&(M&&N&&O&&P&&a&&b&&c||G&&(M&&N&&O&&a&&b&&c||F&&(M&&N&&a&&b&&c||E)))||a&&b&&k&&l&&m&&c&&(n&&o&&p||g&&h&&i&&j&&(n&&o||f&&(n||e))))||E&&(K&&L&&M&&H&&I&&J&&(N&&O&&P&&a&&b&&c&&d||G&&(N&&O&&a&&b&&c&&d||F))||a&&b&&l&&m&&n&&c&&d&&(k&&g&&h&&i&&j&&(o||f)||o&&p))||F&&(K&&L&&M&&N&&H&&I&&J&&(O&&P&&a&&b&&c&&d&&e||G)||a&&b&&m&&n&&o&&c&&d&&e&&(k&&l&&g&&h&&i&&j||p))||G&&(K&&L&&M&&N&&O&&H&&I&&J||a&&b&&n&&o&&p&&c&&d&&e&&f)||H&&(K&&L&&M&&N&&O&&P&&I&&J||a&&b&&o&&p&&c&&d&&e&&f&&g)||a&&(b&&(k&&l&&j&&(m&&n&&o&&p||g&&h&&i&&(m&&n&&o||f&&(m&&n||e&&(m||d))))||c&&(k&&l&&m&&(n&&o&&p||g&&h&&i&&j&&(n&&o||f&&(n||e)))||d&&(l&&m&&n&&(k&&g&&h&&i&&j&&(o||f)||o&&p)||e&&(m&&n&&o&&(k&&l&&g&&h&&i&&j||p)||f&&(n&&o&&p||g&&(o&&p||h&&(p||i)))))))||k&&i&&j&&(l&&m&&n&&o&&p||g&&h&&(l&&m&&n&&o||f&&(l&&m&&n||e&&(l&&m||d&&(l||c))))))||h&&i&&j&&(k&&l&&m&&n&&o&&p||g&&(k&&l&&m&&n&&o||f&&(k&&l&&m&&n||e&&(k&&l&&m||d&&(k&&l||c&&(b||k))))));\nif(!isCorner)\nreturn;\nmat4 mp = mat4(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15);\nmat4 mct = mp - mat4(ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct);\nmat4 mc_t = mat4(c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t) - mp;\nconst vec4 zeros = vec4(0.0f), ones = vec4(1.0f);\nvec4 bs = max(mct[0], zeros), ds = max(mc_t[0], zeros);\nbs += max(mct[1], zeros); ds += max(mc_t[1], zeros);\nbs += max(mct[2], zeros); ds += max(mc_t[2], zeros);\nbs += max(mct[3], zeros); ds += max(mc_t[3], zeros);\nfloat thisScore = max(dot(bs, ones), dot(ds, ones)) / 16.0f;\nfloat prevScore = decodeFloat16(prev.rb);\nvec3 thisResult = vec3(encodeFloat16(thisScore), encodeLod(lod));\ncolor.rba = thisScore > prevScore ? thisResult : color.rba;\n#endif\n}"
  17967. /***/ }),
  17968. /***/ "./src/gpu/shaders/keypoints/fast.vs.glsl":
  17969. /*!************************************************!*\
  17970. !*** ./src/gpu/shaders/keypoints/fast.vs.glsl ***!
  17971. \************************************************/
  17972. /***/ ((module) => {
  17973. module.exports = "uniform mediump float lod;\n#if !defined(FAST_TYPE)\n#error Undefined FAST_TYPE\n#elif FAST_TYPE == 916\nout vec2 v_pix0, v_pix1, v_pix2, v_pix3, v_pix4, v_pix5, v_pix6, v_pix7,\nv_pix8, v_pix9, v_pix10,v_pix11,v_pix12,v_pix13,v_pix14,v_pix15;\n#else\n#error Invalid FAST_TYPE\n#endif\n#define PIX(x,y) (texCoord + ((pot) * vec2((x),(y))) / texSize)\nvoid vsmain()\n{\nfloat pot = exp2(lod);\n#if FAST_TYPE == 916\nv_pix0 = PIX(0,3); v_pix1 = PIX(1,3), v_pix2 = PIX(2,2), v_pix3 = PIX(3,1);\nv_pix4 = PIX(3,0); v_pix5 = PIX(3,-1), v_pix6 = PIX(2,-2), v_pix7 = PIX(1,-3);\nv_pix8 = PIX(0,-3); v_pix9 = PIX(-1,-3), v_pix10 = PIX(-2,-2), v_pix11 = PIX(-3,-1);\nv_pix12 = PIX(-3,0); v_pix13 = PIX(-3,1), v_pix14 = PIX(-2,2), v_pix15 = PIX(-1,3);\n#endif\n}"
  17974. /***/ }),
  17975. /***/ "./src/gpu/shaders/keypoints/hamming-distance-filter.glsl":
  17976. /*!****************************************************************!*\
  17977. !*** ./src/gpu/shaders/keypoints/hamming-distance-filter.glsl ***!
  17978. \****************************************************************/
  17979. /***/ ((module) => {
  17980. module.exports = "@include \"keypoints.glsl\"\n@include \"keypoint-descriptors.glsl\"\nuniform sampler2D encodedKeypointsA;\nuniform int encoderLengthA;\nuniform sampler2D encodedKeypointsB;\nuniform int encoderLengthB;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int threshold;\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint index = findKeypointIndex(address, descriptorSize, extraSize);\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nvec4 data = readKeypointData(encodedKeypointsA, encoderLengthA, address);\ncolor = data;\nif(address.offset >= sizeofEncodedKeypointHeader() / 4)\nreturn;\nKeypoint keypointA = decodeKeypoint(encodedKeypointsA, encoderLengthA, address);\nKeypoint keypointB = decodeKeypoint(encodedKeypointsB, encoderLengthB, address);\ncolor = encodeNullKeypoint();\nif(isNullKeypoint(keypointA) && isNullKeypoint(keypointB))\nreturn;\ncolor = encodeDiscardedKeypoint();\nif(isDiscardedKeypoint(keypointA) || isDiscardedKeypoint(keypointB))\nreturn;\ncolor = encodeDiscardedKeypoint();\nif(isNullKeypoint(keypointA) || isNullKeypoint(keypointB))\nreturn;\nuint[DESCRIPTOR_SIZE] descriptorA, descriptorB;\ndescriptorA = readKeypointDescriptor(encodedKeypointsA, descriptorSize, extraSize, encoderLengthA, address);\ndescriptorB = readKeypointDescriptor(encodedKeypointsB, descriptorSize, extraSize, encoderLengthB, address);\nint dist = distanceBetweenKeypointDescriptors(descriptorA, descriptorB);\nbool shouldKeep = (dist <= threshold);\ncolor = shouldKeep ? data : encodeDiscardedKeypoint();\n}"
  17981. /***/ }),
  17982. /***/ "./src/gpu/shaders/keypoints/harris-cutoff.glsl":
  17983. /*!******************************************************!*\
  17984. !*** ./src/gpu/shaders/keypoints/harris-cutoff.glsl ***!
  17985. \******************************************************/
  17986. /***/ ((module) => {
  17987. module.exports = "@include \"float16.glsl\"\nuniform sampler2D corners;\nuniform sampler2D maxScore;\nuniform float quality;\nvoid main()\n{\nvec4 pixel = threadPixel(corners);\nfloat score = decodeFloat16(pixel.rb);\nfloat maxval = decodeFloat16(threadPixel(maxScore).rb);\nfloat threshold = maxval * clamp(quality, 0.0f, 1.0f);\ncolor = pixel;\ncolor.rb = score >= threshold ? color.rb : encodeFloat16(0.0f);\n}"
  17988. /***/ }),
  17989. /***/ "./src/gpu/shaders/keypoints/harris.glsl":
  17990. /*!***********************************************!*\
  17991. !*** ./src/gpu/shaders/keypoints/harris.glsl ***!
  17992. \***********************************************/
  17993. /***/ ((module) => {
  17994. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\n@include \"filters.glsl\"\n#if !defined(WINDOW_SIZE)\n#error Undefined WINDOW_SIZE\n#endif\n#define WINDOW_RADIUS ((WINDOW_SIZE - 1) / 2)\nuniform sampler2D corners;\nuniform sampler2D pyramid;\nuniform sampler2D derivatives;\nuniform float lod;\nuniform float lodStep;\nuniform float gaussian[@WINDOW_SIZE@];\n#define G(x) gaussian[(x) + WINDOW_RADIUS]\n#define W(x,y) (G(x) * G(y))\n#define H(ox,oy) dpix = pixelAtShortOffset(derivatives, ivec2((ox),(oy))); \\\ndf = (1.0f + lod) * decodePairOfFloat16(dpix); \\\nh += vec3(df.x * df.x, df.x * df.y, df.y * df.y) * W((ox),(oy))\nvoid main()\n{\nfloat intensity = 0.0f;\nivec2 thread = threadLocation();\nvec4 pixel = threadPixel(corners);\nvec4 dpix = vec4(0.0f);\nvec2 df = vec2(0.0f);\nvec3 h = vec3(0.0f);\ncolor = pixel;\n#if WINDOW_SIZE == 1\nH(0,0);\n#elif WINDOW_SIZE == 3\nH(-1,-1); H(0,-1); H(1,-1);\nH(-1,0); H(0,0); H(1,0);\nH(-1,1); H(0,1); H(1,1);\n#elif WINDOW_SIZE == 5\nH(-2,-2); H(-1,-2); H(0,-2); H(1,-2); H(2,-2);\nH(-2,-1); H(-1,-1); H(0,-1); H(1,-1); H(2,-1);\nH(-2,0); H(-1,0); H(0,0); H(1,0); H(2,0);\nH(-2,1); H(-1,1); H(0,1); H(1,1); H(2,1);\nH(-2,2); H(-1,2); H(0,2); H(1,2); H(2,2);\n#elif WINDOW_SIZE == 7\nH(-3,-3); H(-2,-3); H(-1,-3); H(0,-3); H(1,-3); H(2,-3); H(3,-3);\nH(-3,-2); H(-2,-2); H(-1,-2); H(0,-2); H(1,-2); H(2,-2); H(3,-2);\nH(-3,-1); H(-2,-1); H(-1,-1); H(0,-1); H(1,-1); H(2,-1); H(3,-1);\nH(-3,0); H(-2,0); H(-1,0); H(0,0); H(1,0); H(2,0); H(3,0);\nH(-3,1); H(-2,1); H(-1,1); H(0,1); H(1,1); H(2,1); H(3,1);\nH(-3,2); H(-2,2); H(-1,2); H(0,2); H(1,2); H(2,2); H(3,2);\nH(-3,3); H(-2,3); H(-1,3); H(0,3); H(1,3); H(2,3); H(3,3);\n#else\n#error Invalid WINDOW_SIZE\n#endif\nfloat response = 0.5f * (h.x + h.z - sqrt((h.x - h.z) * (h.x - h.z) + 4.0f * h.y * h.y));\nresponse /= float(WINDOW_SIZE * WINDOW_SIZE);\nfloat lodPlus = min(float(PYRAMID_MAX_LEVELS - 1), lod + lodStep);\nfloat currentScaleStrength = abs(laplacian(pyramid, vec2(thread), lod));\nfloat previousScaleStrength = abs(laplacian(pyramid, vec2(thread), lodPlus));\nfloat previousResponse = decodeFloat16(pixel.rb);\nvec4 result = vec4(encodeFloat16(response), encodeLod(lod), intensity);\ncolor.rbag = (currentScaleStrength >= previousScaleStrength || previousResponse == 0.0f) ? result : pixel.rbag;\n}"
  17995. /***/ }),
  17996. /***/ "./src/gpu/shaders/keypoints/knn-init.glsl":
  17997. /*!*************************************************!*\
  17998. !*** ./src/gpu/shaders/keypoints/knn-init.glsl ***!
  17999. \*************************************************/
  18000. /***/ ((module) => {
  18001. module.exports = "@include \"keypoint-matches.glsl\"\nvoid main()\n{\n#if ENCODE_FILTERS != 0\nKeypointMatch initial = KeypointMatch(MATCH_MAX_INDEX, 0);\n#else\nKeypointMatch initial = KeypointMatch(MATCH_MAX_INDEX, MATCH_MAX_DISTANCE);\n#endif\ncolor = encodeKeypointMatch(initial);\n}"
  18002. /***/ }),
  18003. /***/ "./src/gpu/shaders/keypoints/knn-transfer.glsl":
  18004. /*!*****************************************************!*\
  18005. !*** ./src/gpu/shaders/keypoints/knn-transfer.glsl ***!
  18006. \*****************************************************/
  18007. /***/ ((module) => {
  18008. module.exports = "@include \"keypoint-matches.glsl\"\nuniform sampler2D encodedMatches;\nuniform sampler2D encodedKthMatches;\nuniform int numberOfMatchesPerKeypoint;\nuniform int kthMatch;\nvoid main()\n{\nivec2 thread = threadLocation();\nivec2 matcherSize = textureSize(encodedMatches, 0);\nivec2 kthMatcherSize = textureSize(encodedKthMatches, 0);\nint rasterIndex = thread.y * matcherSize.x + thread.x;\nint matchIndex = rasterIndex / numberOfMatchesPerKeypoint;\nint matchCell = rasterIndex % numberOfMatchesPerKeypoint;\ncolor = threadPixel(encodedMatches);\nif(matchCell != kthMatch)\nreturn;\ncolor = encodeKeypointMatch(MATCH_NOT_FOUND);\nif(matchIndex >= kthMatcherSize.x * kthMatcherSize.y)\nreturn;\nivec2 pos = ivec2(matchIndex % kthMatcherSize.x, matchIndex / kthMatcherSize.x);\ncolor = texelFetch(encodedKthMatches, pos, 0);\n}"
  18009. /***/ }),
  18010. /***/ "./src/gpu/shaders/keypoints/laplacian.glsl":
  18011. /*!**************************************************!*\
  18012. !*** ./src/gpu/shaders/keypoints/laplacian.glsl ***!
  18013. \**************************************************/
  18014. /***/ ((module) => {
  18015. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\n@include \"filters.glsl\"\nuniform sampler2D corners;\nuniform sampler2D pyramid;\nuniform float lodStep;\nuniform float lodOffset;\nvoid main()\n{\nivec2 thread = threadLocation();\nvec4 pixel = threadPixel(corners);\nfloat lod = decodeLod(pixel.a);\nfloat lodMinus = max(0.0f, lod - lodStep + lodOffset);\nfloat lodPlus = min(float(PYRAMID_MAX_LEVELS - 1), lod + lodStep + lodOffset);\nfloat lapMinus = laplacian(pyramid, vec2(thread), lodMinus);\nfloat lapPlus = abs(lodPlus - lodMinus) < 1e-5 ? lapMinus : laplacian(pyramid, vec2(thread), lodPlus);\ncolor = encodePairOfFloat16(vec2(lapMinus, lapPlus));\n}"
  18016. /***/ }),
  18017. /***/ "./src/gpu/shaders/keypoints/lk.glsl":
  18018. /*!*******************************************!*\
  18019. !*** ./src/gpu/shaders/keypoints/lk.glsl ***!
  18020. \*******************************************/
  18021. /***/ ((module) => {
  18022. module.exports = "@include \"keypoints.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D nextPyramid;\nuniform sampler2D prevPyramid;\nuniform sampler2D encodedFlow;\nuniform sampler2D prevKeypoints;\nuniform int level;\nuniform int depth;\nuniform int numberOfIterations;\nuniform float discardThreshold;\nuniform float epsilon;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#ifndef WINDOW_SIZE\n#error Undefined WINDOW_SIZE\n#endif\n#define NEXT_IMAGE 1\n#define PREV_IMAGE 0\nconst int WINDOW_RADIUS = (WINDOW_SIZE - 1) / 2;\nconst int WINDOW_SIZE_SQUARED = (WINDOW_SIZE) * (WINDOW_SIZE);\nconst int WINDOW_SIZE_PLUS = (WINDOW_SIZE) + 2;\nconst int WINDOW_SIZE_PLUS_SQUARED = WINDOW_SIZE_PLUS * WINDOW_SIZE_PLUS;\nconst int DBL_WINDOW_SIZE_PLUS_SQUARED = 2 * WINDOW_SIZE_PLUS_SQUARED;\nconst int WINDOW_RADIUS_PLUS = (WINDOW_SIZE_PLUS - 1) / 2;\nconst highp float FLT_SCALE = 9.5367431640625e-7;\nconst highp float FLT_EPSILON = 0.00000011920929f;\nint pixelBuffer[DBL_WINDOW_SIZE_PLUS_SQUARED];\n#define prevPixel(index) pixelBuffer[(index)]\n#define nextPixel(index) pixelBuffer[WINDOW_SIZE_PLUS_SQUARED + (index)]\n#define pixelIndex(i, j) (((j) + WINDOW_RADIUS_PLUS) * WINDOW_SIZE_PLUS + ((i) + WINDOW_RADIUS_PLUS))\nivec2 derivBuffer[WINDOW_SIZE_SQUARED];\n#define derivativesAt(x, y) derivBuffer[((y) + WINDOW_RADIUS) * WINDOW_SIZE + ((x) + WINDOW_RADIUS)]\nvoid readWindow(vec2 center, float lod)\n{\nconst int r = WINDOW_RADIUS;\nivec2 pyrBaseSize = textureSize(prevPyramid, 0);\nfloat pot = exp2(lod);\nivec2 offset; int idx;\n#define readPixelsAt(ox, oy) offset = ivec2((ox), (oy)); \\\nidx = pixelIndex(offset.x, offset.y); \\\nnextPixel(idx) = int(255.0f * pyrSubpixelAtExOffset(nextPyramid, center, lod, pot, offset, pyrBaseSize).g); \\\nprevPixel(idx) = int(255.0f * pyrSubpixelAtExOffset(prevPyramid, center, lod, pot, offset, pyrBaseSize).g)\nfor(int j = 0; j < WINDOW_SIZE; j++) {\nfor(int i = 0; i < WINDOW_SIZE; i++) {\nreadPixelsAt(i-r, j-r);\n}\n}\nint r1 = r+1;\nfor(int k = 0; k < WINDOW_SIZE; k++) {\nreadPixelsAt(-r1, k-r);\nreadPixelsAt( r1, k-r);\nreadPixelsAt(k-r,-r1);\nreadPixelsAt(k-r, r1);\n}\nreadPixelsAt(-r1,-r1);\nreadPixelsAt( r1,-r1);\nreadPixelsAt(-r1, r1);\nreadPixelsAt( r1, r1);\n}\nivec2 computeDerivatives(int imageCode, ivec2 offset)\n{\nconst mat3 dx = mat3(\n3, 0, -3,\n10, 0, -10,\n3, 0, -3\n);\nconst mat3 dy = mat3(\n3, 10, 3,\n0, 0, 0,\n-3, -10, -3\n);\nint indexOffset = imageCode * WINDOW_SIZE_PLUS_SQUARED;\nmat3 window = mat3(\npixelBuffer[indexOffset + pixelIndex(offset.x-1, offset.y-1)],\npixelBuffer[indexOffset + pixelIndex(offset.x+0, offset.y-1)],\npixelBuffer[indexOffset + pixelIndex(offset.x+1, offset.y-1)],\npixelBuffer[indexOffset + pixelIndex(offset.x-1, offset.y+0)],\n0.0f,\npixelBuffer[indexOffset + pixelIndex(offset.x+1, offset.y+0)],\npixelBuffer[indexOffset + pixelIndex(offset.x-1, offset.y+1)],\npixelBuffer[indexOffset + pixelIndex(offset.x+0, offset.y+1)],\npixelBuffer[indexOffset + pixelIndex(offset.x+1, offset.y+1)]\n);\nmat3 fx = matrixCompMult(dx, window);\nmat3 fy = matrixCompMult(dy, window);\nconst vec3 ones = vec3(1.0f);\nreturn ivec2(\ndot(fx[0], ones) + dot(fx[1], ones) + dot(fx[2], ones),\ndot(fy[0], ones) + dot(fy[1], ones) + dot(fy[2], ones)\n);\n}\nint readBufferedPixel(int imageCode, ivec2 offset)\n{\nconst int r = WINDOW_RADIUS;\noffset = clamp(offset, -r, r);\nint indexOffset = imageCode * WINDOW_SIZE_PLUS_SQUARED;\nreturn pixelBuffer[indexOffset + pixelIndex(offset.x, offset.y)];\n}\nint readBufferedSubpixel(int imageCode, vec2 offset)\n{\nivec2 p = ivec2(floor(offset));\nvec2 frc = fract(offset);\nvec2 ifrc = vec2(1.0f) - frc;\nvec4 pix = vec4(\nreadBufferedPixel(imageCode, p),\nreadBufferedPixel(imageCode, p + ivec2(1,0)),\nreadBufferedPixel(imageCode, p + ivec2(0,1)),\nreadBufferedPixel(imageCode, p + ivec2(1,1))\n);\nvec4 sub = vec4(\nifrc.x * ifrc.y,\nfrc.x * ifrc.y,\nifrc.x * frc.y,\nfrc.x * frc.y\n);\nreturn int(0.5f + dot(sub*pix, vec4(1.0f)));\n}\nvec2 computeMismatch(vec2 pyrGuess, vec2 localGuess)\n{\nconst int r = WINDOW_RADIUS;\nint timeDerivative;\nivec2 mismatch = ivec2(0);\nint x, y, _x, _y;\nvec2 d = pyrGuess + localGuess;\n#define innerLoop() \\\nfor(_x = 0; _x < WINDOW_SIZE; _x++) { \\\nx = _x - r; y = _y - r; \\\ntimeDerivative = ( \\\nreadBufferedSubpixel(NEXT_IMAGE, vec2(x, y) + d) - \\\nreadBufferedPixel(PREV_IMAGE, ivec2(x, y)) \\\n); \\\nmismatch += derivativesAt(x, y) * timeDerivative; \\\n}\n@unroll\nfor(_y = 0; _y < WINDOW_SIZE; _y++) {\ninnerLoop();\n}\nreturn vec2(mismatch) * FLT_SCALE;\n}\nbool isInsideImage(vec2 position)\n{\nvec2 imageSize = vec2(textureSize(nextPyramid, 0));\nvec2 border = vec2(WINDOW_SIZE);\nreturn all(bvec4(\ngreaterThanEqual(position, border),\nlessThan(position, imageSize - border)\n));\n}\nvoid main()\n{\nvec4 pixel = threadPixel(encodedFlow);\nivec2 thread = threadLocation();\nfloat windowArea = float(WINDOW_SIZE * WINDOW_SIZE);\nconst int r = WINDOW_RADIUS;\nint keypointIndex = thread.x + thread.y * outputSize().x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(prevKeypoints, encoderLength, address);\ncolor = encodeNullPairOfFloat16();\nif(isNullKeypoint(keypoint))\nreturn;\ncolor = encodeDiscardedPairOfFloat16();\nif(isBadKeypoint(keypoint))\nreturn;\nvec2 pyrGuess = (level < depth - 1) ? decodePairOfFloat16(pixel) : vec2(0.0f);\npyrGuess *= 2.0f;\nreadWindow(keypoint.position, float(level));\nivec2 derivatives;\nivec3 harris3i = ivec3(0);\nfor(int j = 0; j < WINDOW_SIZE; j++) {\nfor(int i = 0; i < WINDOW_SIZE; i++) {\nderivatives = computeDerivatives(PREV_IMAGE, ivec2(i-r, j-r));\nharris3i += ivec3(\nderivatives.x * derivatives.x,\nderivatives.x * derivatives.y,\nderivatives.y * derivatives.y\n);\nderivativesAt(i-r, j-r) = derivatives;\n}\n}\nhighp vec3 harris = vec3(harris3i) * FLT_SCALE;\nhighp mat2 invHarris = mat2(harris.z, -harris.y, -harris.y, harris.x);\nhighp float det = harris.x * harris.z - harris.y * harris.y;\nhighp float invDet = abs(det) >= FLT_EPSILON ? 1.0f / det : 0.0f;\nhighp float minEigenvalue = 0.5f * ((harris.x + harris.z) - sqrt(\n(harris.x - harris.z) * (harris.x - harris.z) + 4.0f * (harris.y * harris.y)\n));\nint niceNumbers = int(abs(det) >= FLT_EPSILON && minEigenvalue >= discardThreshold * windowArea);\nbool goodKeypoint = (level > 0) || (niceNumbers != 0);\nhighp float eps2 = epsilon * epsilon;\nhighp vec2 mismatch, delta, localGuess = vec2(0.0f);\nfor(int k = 0; k < numberOfIterations; k++) {\nmismatch = niceNumbers != 0 ? computeMismatch(pyrGuess, localGuess) : vec2(0.0f);\ndelta = mismatch * invHarris * invDet;\nniceNumbers *= int(eps2 <= dot(delta, delta));\nlocalGuess += float(niceNumbers) * delta;\n}\nvec2 opticalFlow = pyrGuess + localGuess;\nbool mustDiscard = (level == 0) && any(bvec2(\n!goodKeypoint,\n!isInsideImage(keypoint.position + opticalFlow)\n));\ncolor = !mustDiscard ? encodePairOfFloat16(opticalFlow) : encodeDiscardedPairOfFloat16();\n}"
  18023. /***/ }),
  18024. /***/ "./src/gpu/shaders/keypoints/lookup-of-locations.glsl":
  18025. /*!************************************************************!*\
  18026. !*** ./src/gpu/shaders/keypoints/lookup-of-locations.glsl ***!
  18027. \************************************************************/
  18028. /***/ ((module) => {
  18029. module.exports = "#if @FS_USE_CUSTOM_PRECISION@\nprecision mediump int;\nprecision mediump float;\n#endif\n#if !defined(STAGE)\n#error Undefined STAGE\n#elif STAGE == 1\n@include \"float16.glsl\"\nuniform sampler2D corners;\n#elif STAGE < 1\nuniform mediump usampler2D lookupTable;\n#else\n#define SKIP_TEXTURE_READS 1\n#define DENSITY_FACTOR 0.10\nuniform mediump usampler2D lookupTable;\nuniform int blockSize;\nuniform int width;\nuniform int height;\nin vec2 v_topLeft, v_top, v_topRight,\nv_left, v_center, v_right,\nv_bottomLeft, v_bottom, v_bottomRight;\n#endif\nconst uvec2 NULL_ELEMENT = uvec2(0xFFFFu);\nvoid main()\n{\n#if STAGE == 1\nuvec2 outSize = uvec2(outputSize());\nuvec2 thread = uvec2(threadLocation());\nuvec2 size = uvec2(textureSize(corners, 0));\nuint location = thread.y * outSize.x + thread.x;\nivec2 pos = ivec2(location % size.x, location / size.x);\nvec4 pixel = location < size.x * size.y ? texelFetch(corners, pos, 0) : vec4(0.0f);\nbool isCorner = !isEncodedFloat16Zero(pixel.rb);\ncolor = isCorner ? uvec4(uvec2(pos), 1u, 0u) : uvec4(NULL_ELEMENT, 0u, 0u);\n#elif STAGE > 1\nint dblBlockSize = 2 * blockSize;\nivec2 thread = threadLocation();\nivec2 offset = thread % dblBlockSize;\nivec2 delta = thread - offset;\n#if SKIP_TEXTURE_READS\nif(blockSize >= 8) {\nuint sb = texture(lookupTable, texCoord).z;\nfloat p = max((float(sb) / float(blockSize)) / float(blockSize), DENSITY_FACTOR);\nfloat rowthr = float(dblBlockSize) * p + 3.0f * sqrt(p * (1.0f - p));\ncolor = uvec4(NULL_ELEMENT, 4u * sb, 0u);\nif(offset.y >= max(1, int(ceil(rowthr))))\nreturn;\n}\n#endif\n#define deltaCenter ivec2(0,0)\n#define deltaTop ivec2(0,-blockSize)\n#define deltaTopRight ivec2(blockSize,-blockSize)\n#define deltaRight ivec2(blockSize,0)\n#define deltaBottomRight ivec2(blockSize,blockSize)\n#define deltaBottom ivec2(0,blockSize)\n#define deltaBottomLeft ivec2(-blockSize,blockSize)\n#define deltaLeft ivec2(-blockSize,0)\n#define deltaTopLeft ivec2(-blockSize,-blockSize)\nivec2 boundary = ivec2(width - 1, height - 1) / blockSize;\nivec2 bottomRightPos = thread + deltaBottomRight;\nuvec2 valid = uvec2(\nbottomRightPos.x < width || bottomRightPos.x / blockSize == boundary.x,\nbottomRightPos.y < height || bottomRightPos.y / blockSize == boundary.y\n);\nuvec4 mask[4] = uvec4[4](\nuvec4(1u, valid.x, valid.y, valid.x * valid.y),\nuvec4(1u, 1u, valid.y, valid.y),\nuvec4(1u, valid.x, 1u, valid.x),\nuvec4(1u)\n);\n#if SKIP_TEXTURE_READS\n#define calcSb(delta) texelFetch(lookupTable, blockSize * ((thread + (delta)) / blockSize), 0).z\nuint center = calcSb(deltaCenter);\nuint top = calcSb(deltaTop);\nuint topRight = calcSb(deltaTopRight);\nuint right = calcSb(deltaRight);\nuint bottomRight = calcSb(deltaBottomRight);\nuint bottom = calcSb(deltaBottom);\nuint bottomLeft = calcSb(deltaBottomLeft);\nuint left = calcSb(deltaLeft);\nuint topLeft = calcSb(deltaTopLeft);\n#else\n#define calcSb(pos) texture(lookupTable, (pos)).z\nuint center = calcSb(v_center);\nuint top = calcSb(v_top);\nuint topRight = calcSb(v_topRight);\nuint right = calcSb(v_right);\nuint bottomRight = calcSb(v_bottomRight);\nuint bottom = calcSb(v_bottom);\nuint bottomLeft = calcSb(v_bottomLeft);\nuint left = calcSb(v_left);\nuint topLeft = calcSb(v_topLeft);\n#endif\nuvec4 sums[4] = uvec4[4](\nuvec4(center, right, bottom, bottomRight),\nuvec4(left, center, bottomLeft, bottom),\nuvec4(top, topRight, center, right),\nuvec4(topLeft, top, left, center)\n);\nivec2 cmp = ivec2(greaterThanEqual(offset, ivec2(blockSize)));\nint option = 2 * cmp.y + cmp.x;\nuvec4 cdef = sums[option] * mask[option];\nuint c2b = cdef.x, d2b = cdef.y, e2b = cdef.z, f2b = cdef.w;\nuint sb = center;\nuint s2b = c2b + d2b + e2b + f2b;\ns2b = s2b < sb ? 0xFFFFu : min(0xFFFFu, s2b);\nuint w2b = uint(min(dblBlockSize, width - delta.x));\nuvec2 uoffset = uvec2(offset);\nuint ceiling = s2b >= uoffset.x ? (s2b - uoffset.x) / w2b + uint((s2b - uoffset.x) % w2b > 0u) : 0u;\ncolor = uvec4(NULL_ELEMENT, s2b, 0u);\nif(uoffset.y >= ceiling)\nreturn;\nuint i2b = uoffset.y * w2b + uoffset.x;\nuint j2b = i2b >= c2b ? i2b - c2b : 0u;\nuint k2b = j2b >= d2b ? j2b - d2b : 0u;\nuint l2b = k2b >= e2b ? k2b - e2b : 0u;\nuint wl = uint(min(blockSize, width - delta.x));\nuint wr = uint(min(blockSize, width - delta.x - blockSize));\nivec2 magicOffset = (\n(i2b < c2b) ? ivec2(i2b % wl, i2b / wl) : (\n(j2b < d2b) ? ivec2(j2b % wr, j2b / wr) + ivec2(blockSize, 0) : (\n(k2b < e2b) ? ivec2(k2b % wl, k2b / wl) + ivec2(0, blockSize) : (\n(l2b < f2b) ? ivec2(l2b % wr, l2b / wr) + ivec2(blockSize) : ivec2(0)\n))));\nuvec2 a2b = texelFetch(lookupTable, delta + magicOffset, 0).xy;\ncolor = uvec4(a2b, s2b, 0u);\n#else\nuvec4 pix = texture(lookupTable, texCoord);\ncolor = all(equal(pix.xy, NULL_ELEMENT)) ? vec4(0,1,1,1) : vec4(1,0,0,1);\n#endif\n}"
  18030. /***/ }),
  18031. /***/ "./src/gpu/shaders/keypoints/lookup-of-locations.vs.glsl":
  18032. /*!***************************************************************!*\
  18033. !*** ./src/gpu/shaders/keypoints/lookup-of-locations.vs.glsl ***!
  18034. \***************************************************************/
  18035. /***/ ((module) => {
  18036. module.exports = "#if !defined(STAGE) || STAGE < 1\n#error Invalid STAGE\n#else\nuniform mediump int blockSize;\nout vec2 v_topLeft, v_top, v_topRight,\nv_left, v_center, v_right,\nv_bottomLeft, v_bottom, v_bottomRight;\nvoid vsmain()\n{\nfloat b = float(blockSize);\n#define V(x,y) (texCoord + (vec2((x),(y)) * b) / texSize)\nv_topLeft = V(-1,-1); v_top = V(0,-1); v_topRight = V(1,-1);\nv_left = V(-1,0); v_center = V(0,0); v_right = V(1,0);\nv_bottomLeft = V(-1,1); v_bottom = V(0,1); v_bottomRight = V(1,1);\n}\n#endif"
  18037. /***/ }),
  18038. /***/ "./src/gpu/shaders/keypoints/lsh-knn.glsl":
  18039. /*!************************************************!*\
  18040. !*** ./src/gpu/shaders/keypoints/lsh-knn.glsl ***!
  18041. \************************************************/
  18042. /***/ ((module) => {
  18043. module.exports = "@include \"keypoints.glsl\"\n@include \"keypoint-matches.glsl\"\n@include \"keypoint-descriptors.glsl\"\nuniform sampler2D candidates;\nuniform sampler2D filters;\nuniform int matcherLength;\nuniform sampler2D tables;\nuniform sampler2D descriptorDB;\nuniform int tableIndex;\nuniform int bucketCapacity;\nuniform int bucketsPerTable;\nuniform int tablesStride;\nuniform int descriptorDBStride;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#if HASH_SIZE > SEQUENCE_MAXLEN\n#error LSH: invalid HASH_SIZE\n#elif SEQUENCE_COUNT * SEQUENCE_MAXLEN * 4 > 16384\n#error LSH: sequences are too large!\n#elif (SEQUENCE_COUNT * SEQUENCE_MAXLEN) % 4 > 0\n#error LSH: sequences of invalid size!\n#endif\nlayout(std140) uniform LSHSequences\n{\nuvec4 sequences[(SEQUENCE_COUNT * SEQUENCE_MAXLEN) / 4];\n};\n#if HASH_SIZE == 10\nconst int SWAP_COUNT[3] = int[3](1, 11, 56);\nconst int[56] SWAP = int[56](0,1,2,4,8,16,32,64,128,256,512,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768);\n#elif HASH_SIZE == 11\nconst int SWAP_COUNT[3] = int[3](1, 12, 67);\nconst int[67] SWAP = int[67](0,1,2,4,8,16,32,64,128,256,512,1024,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536);\n#elif HASH_SIZE == 12\nconst int SWAP_COUNT[3] = int[3](1, 13, 79);\nconst int[79] SWAP = int[79](0,1,2,4,8,16,32,64,128,256,512,1024,2048,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072);\n#elif HASH_SIZE == 13\nconst int SWAP_COUNT[3] = int[3](1, 14, 92);\nconst int[92] SWAP = int[92](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144);\n#elif HASH_SIZE == 14\nconst int SWAP_COUNT[3] = int[3](1, 15, 106);\nconst int[106] SWAP = int[106](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288);\n#elif HASH_SIZE == 15\nconst int SWAP_COUNT[3] = int[3](1, 16, 121);\nconst int[121] SWAP = int[121](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576);\n#elif HASH_SIZE == 16\nconst int SWAP_COUNT[3] = int[3](1, 17, 137);\nconst int[137] SWAP = int[137](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576,32769,32770,32772,32776,32784,32800,32832,32896,33024,33280,33792,34816,36864,40960,49152);\n#elif HASH_SIZE == 17\nconst int SWAP_COUNT[3] = int[3](1, 18, 154);\nconst int[154] SWAP = int[154](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576,32769,32770,32772,32776,32784,32800,32832,32896,33024,33280,33792,34816,36864,40960,49152,65537,65538,65540,65544,65552,65568,65600,65664,65792,66048,66560,67584,69632,73728,81920,98304);\n#elif HASH_SIZE == 18\nconst int SWAP_COUNT[3] = int[3](1, 19, 172);\nconst int[172] SWAP = int[172](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576,32769,32770,32772,32776,32784,32800,32832,32896,33024,33280,33792,34816,36864,40960,49152,65537,65538,65540,65544,65552,65568,65600,65664,65792,66048,66560,67584,69632,73728,81920,98304,131073,131074,131076,131080,131088,131104,131136,131200,131328,131584,132096,133120,135168,139264,147456,163840,196608);\n#elif HASH_SIZE == 19\nconst int SWAP_COUNT[3] = int[3](1, 20, 191);\nconst int[191] SWAP = int[191](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576,32769,32770,32772,32776,32784,32800,32832,32896,33024,33280,33792,34816,36864,40960,49152,65537,65538,65540,65544,65552,65568,65600,65664,65792,66048,66560,67584,69632,73728,81920,98304,131073,131074,131076,131080,131088,131104,131136,131200,131328,131584,132096,133120,135168,139264,147456,163840,196608,262145,262146,262148,262152,262160,262176,262208,262272,262400,262656,263168,264192,266240,270336,278528,294912,327680,393216);\n#elif HASH_SIZE == 20\nconst int SWAP_COUNT[3] = int[3](1, 21, 211);\nconst int[211] SWAP = int[211](0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,3,5,6,9,10,12,17,18,20,24,33,34,36,40,48,65,66,68,72,80,96,129,130,132,136,144,160,192,257,258,260,264,272,288,320,384,513,514,516,520,528,544,576,640,768,1025,1026,1028,1032,1040,1056,1088,1152,1280,1536,2049,2050,2052,2056,2064,2080,2112,2176,2304,2560,3072,4097,4098,4100,4104,4112,4128,4160,4224,4352,4608,5120,6144,8193,8194,8196,8200,8208,8224,8256,8320,8448,8704,9216,10240,12288,16385,16386,16388,16392,16400,16416,16448,16512,16640,16896,17408,18432,20480,24576,32769,32770,32772,32776,32784,32800,32832,32896,33024,33280,33792,34816,36864,40960,49152,65537,65538,65540,65544,65552,65568,65600,65664,65792,66048,66560,67584,69632,73728,81920,98304,131073,131074,131076,131080,131088,131104,131136,131200,131328,131584,132096,133120,135168,139264,147456,163840,196608,262145,262146,262148,262152,262160,262176,262208,262272,262400,262656,263168,264192,266240,270336,278528,294912,327680,393216,524289,524290,524292,524296,524304,524320,524352,524416,524544,524800,525312,526336,528384,532480,540672,557056,589824,655360,786432);\n#else\n#error Invalid HASH_SIZE\n#endif\n#if LEVEL < 0 || LEVEL > 2\n#error Invalid LEVEL\n#endif\nconst uint END_OF_LIST = 0xFFFFFFFFu;\nconst int NUMBER_OF_HASHES = SWAP_COUNT[LEVEL];\nuint sequenceElement(int sequenceIndex, int elementIndex)\n{\nint offset = (SEQUENCE_MAXLEN) * sequenceIndex + elementIndex;\nuvec4 tuple = sequences[offset / 4];\nreturn tuple[offset & 3];\n}\nint descriptorHash(uint[DESCRIPTOR_SIZE] descriptor, int sequenceIndex)\n{\nuint bit, b, m;\nint hash = 0;\n@unroll\nfor(int i = 0; i < HASH_SIZE; i++) {\nbit = sequenceElement(sequenceIndex, i);\nb = bit >> 3u;\nm = 1u << (bit & 7u);\nhash = (hash << 1) | int((descriptor[b] & m) != 0u);\n}\nreturn hash;\n}\n#define readTableData(tables, tablesStride, rasterIndex) decodeUint32(texelFetch((tables), ivec2((rasterIndex) % (tablesStride), (rasterIndex) / (tablesStride)), 0))\nvoid main()\n{\nivec2 thread = threadLocation();\nint keypointIndex = thread.x + thread.y * matcherLength;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\ncolor = encodeKeypointMatch(MATCH_NOT_FOUND);\nif(isBadKeypoint(keypoint))\nreturn;\nKeypointMatch candidate = decodeKeypointMatch(threadPixel(candidates));\nKeypointMatch mfilter = decodeKeypointMatch(threadPixel(filters));\nuint[DESCRIPTOR_SIZE] candidateDescriptor;\nuint[DESCRIPTOR_SIZE] descriptor = readKeypointDescriptor(encodedKeypoints, descriptorSize, extraSize, encoderLength, address);\nint hash0 = descriptorHash(descriptor, tableIndex);\nfor(int h = 0; h < NUMBER_OF_HASHES; h++) {\nint hash = hash0 ^ SWAP[h];\nint tableAddress = tableIndex * bucketsPerTable * bucketCapacity;\nint bucketAddress = tableAddress + hash * bucketCapacity;\nbool validEntry = true;\nfor(int b = 0; b < bucketCapacity; b++) {\nint entryAddress = bucketAddress + b;\nuint entry = validEntry ? readTableData(tables, tablesStride, entryAddress) : END_OF_LIST;\nvalidEntry = (validEntry && entry != END_OF_LIST);\nint candidateIndex = int(entry);\ncandidateDescriptor = readKeypointDescriptorFromDB(descriptorDB, descriptorDBStride, validEntry ? candidateIndex : -1);\nint descriptorDistance = distanceBetweenKeypointDescriptors(descriptor, candidateDescriptor);\nKeypointMatch match = KeypointMatch(candidateIndex, descriptorDistance);\nbool betterThanCandidate = (match.dist < candidate.dist) || (match.dist == candidate.dist && match.index > candidate.index);\nbool worseThanFilter = (match.dist > mfilter.dist) || (match.dist == mfilter.dist && match.index < mfilter.index);\nbool nicerMatch = (validEntry && betterThanCandidate && worseThanFilter);\nivec2 v = nicerMatch ? ivec2(match.index, match.dist) : ivec2(candidate.index, candidate.dist);\ncandidate = KeypointMatch(v.x, v.y);\n}\n}\ncolor = encodeKeypointMatch(candidate);\n}"
  18044. /***/ }),
  18045. /***/ "./src/gpu/shaders/keypoints/mix-keypoints.glsl":
  18046. /*!******************************************************!*\
  18047. !*** ./src/gpu/shaders/keypoints/mix-keypoints.glsl ***!
  18048. \******************************************************/
  18049. /***/ ((module) => {
  18050. module.exports = "@include \"keypoints.glsl\"\n@include \"int32.glsl\"\n#if !defined(STAGE)\n#error Undefined STAGE\n#elif STAGE == 1\nuniform sampler2D encodedKeypointsA;\nuniform sampler2D encodedKeypointsB;\nuniform int encoderLengthA;\nuniform int encoderLengthB;\nuniform int encoderCapacityA;\nuniform int encoderCapacityB;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#elif STAGE == 2\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int maxKeypoints;\n#elif STAGE == 3\nuniform sampler2D array;\nuniform int blockSize;\n#elif STAGE == 4\nuniform sampler2D array;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#elif STAGE == 5\nuniform sampler2D array;\n#else\n#error Invalid STAGE\n#endif\n#define NULL_KEYPOINT_INDEX 0xFFFF\nconst highp uint UNIT = 0x10000u;\nvoid main()\n{\n#if STAGE == 1\nivec2 thread = threadLocation();\nKeypointAddress addr = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint keypointIndex = findKeypointIndex(addr, descriptorSize, extraSize);\nint newKeypointIndex = keypointIndex < encoderCapacityA ? keypointIndex : keypointIndex - encoderCapacityA;\ncolor = encodeNullKeypoint();\nif(newKeypointIndex >= max(encoderCapacityA, encoderCapacityB))\nreturn;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\naddr = KeypointAddress(newKeypointIndex * pixelsPerKeypoint, addr.offset);\nvec4 dataA = readKeypointData(encodedKeypointsA, encoderLengthA, addr);\nvec4 dataB = readKeypointData(encodedKeypointsB, encoderLengthB, addr);\ncolor = keypointIndex < encoderCapacityA ? dataA : dataB;\n#elif STAGE == 2\nivec2 thread = threadLocation();\nint keypointIndex = thread.y * outputSize().x + thread.x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress addr = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, addr);\nbool isValid = !isNullKeypoint(keypoint) && keypointIndex < maxKeypoints;\nkeypointIndex = isValid ? keypointIndex : NULL_KEYPOINT_INDEX;\ncolor = encodeUint32(uint(keypointIndex & 0xFFFF) | (isValid ? UNIT : 0u));\n#elif STAGE == 3\nivec2 thread = threadLocation();\nivec2 size = outputSize();\nint arrayLength = size.x * size.y;\nint arrayIndex = thread.y * size.x + thread.x;\nint arrayIndexLeft = arrayIndex - blockSize;\nint arrayIndexRight = arrayIndex + blockSize;\nint mask = int(arrayIndexRight < arrayLength || arrayIndexRight / blockSize == (arrayLength - 1) / blockSize);\narrayIndexLeft = max(0, arrayIndexLeft);\narrayIndexRight = min(arrayLength - 1, arrayIndexRight);\n#define raster2pos(k) ivec2((k) % size.x, (k) / size.x)\nuvec3 entries32 = uvec3(\ndecodeUint32(threadPixel(array)),\ndecodeUint32(texelFetch(array, raster2pos(arrayIndexLeft), 0)),\ndecodeUint32(texelFetch(array, raster2pos(arrayIndexRight), 0))\n);\nivec3 sb = ivec3((entries32 >> 16u) & 0xFFFFu);\nsb.z *= mask;\nint dblBlockSize = 2 * blockSize;\nint offset = arrayIndex % dblBlockSize;\nint s2b = sb.x + (offset < blockSize ? sb.z : sb.y);\nint l2b = offset < blockSize ? sb.x : sb.y;\nuint keypointIndex = entries32.x & 0xFFFFu;\nuint shiftedS2b = uint(s2b) << 16u;\ncolor = encodeUint32(uint(NULL_KEYPOINT_INDEX) | shiftedS2b);\nif(offset >= s2b)\nreturn;\ncolor = encodeUint32(keypointIndex | shiftedS2b);\nif(offset < l2b)\nreturn;\nvec4 entry = texelFetch(array, raster2pos(arrayIndex + blockSize - l2b), 0);\nkeypointIndex = decodeUint32(entry) & 0xFFFFu;\ncolor = encodeUint32(keypointIndex | shiftedS2b);\n#elif STAGE == 4\nivec2 thread = threadLocation();\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress addr = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint keypointIndex = findKeypointIndex(addr, descriptorSize, extraSize);\n#define raster2pos(k) ivec2((k) % size.x, (k) / size.x)\nivec2 size = textureSize(array, 0);\nuint sortedPair = decodeUint32(texelFetch(array, raster2pos(keypointIndex), 0));\nint newKeypointIndex = int(sortedPair & 0xFFFFu);\ncolor = encodeNullKeypoint();\nif(newKeypointIndex == NULL_KEYPOINT_INDEX || keypointIndex >= size.x * size.y)\nreturn;\nKeypointAddress newAddr = KeypointAddress(newKeypointIndex * pixelsPerKeypoint, addr.offset);\ncolor = readKeypointData(encodedKeypoints, encoderLength, newAddr);\n#elif STAGE == 5\nuint val = decodeUint32(threadPixel(array));\ncolor = (val & 0xFFFFu) == uint(NULL_KEYPOINT_INDEX) ? vec4(0,1,1,1) : vec4(1,0,0,1);\n#endif\n}"
  18051. /***/ }),
  18052. /***/ "./src/gpu/shaders/keypoints/nonmax-scale.glsl":
  18053. /*!*****************************************************!*\
  18054. !*** ./src/gpu/shaders/keypoints/nonmax-scale.glsl ***!
  18055. \*****************************************************/
  18056. /***/ ((module) => {
  18057. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\n@include \"filters.glsl\"\n#if !defined(USE_LAPLACIAN)\n#error Undefined USE_LAPLACIAN\n#endif\nuniform sampler2D corners;\nuniform sampler2D pyramid;\nuniform float lodStep;\n#if USE_LAPLACIAN\nuniform sampler2D pyrLaplacian;\n#endif\nvoid main()\n{\nivec2 thread = threadLocation();\nvec4 pixel = threadPixel(corners);\nfloat score = decodeFloat16(pixel.rb);\nfloat myEncodedLod = pixel.a;\nfloat lod = decodeLod(myEncodedLod);\nfloat lodPlus = lod + lodStep;\nfloat lodMinus = lod - lodStep;\nfloat pot = exp2(lod);\nfloat potPlus = exp2(lodPlus);\nfloat potMinus = exp2(lodMinus);\ncolor = pixel;\nif(score == 0.0f)\nreturn;\n#define P(p,u,v) textureLod(corners, texCoord + (p) * vec2((u),(v)) / texSize, 0.0f)\nvec4 pix[18] = vec4[18](\n#define D(u,v) P(potMinus,(u),(v))\nD(-1,-1), D(0,-1), D(1,-1),\nD(-1,0), D(0,0), D(1,0),\nD(-1,1), D(0,1), D(1,1)\n,\n#define U(u,v) P(potPlus,(u),(v))\nU(-1,-1), U(0,-1), U(1,-1),\nU(-1,0), U(0,0), U(1,0),\nU(-1,1), U(0,1), U(1,1)\n);\nfloat scores[18] = float[18](\n#define C(j) decodeFloat16(pix[j].rb)\nC(0), C(1), C(2),\nC(3), C(4), C(5),\nC(6), C(7), C(8)\n,\nC(9), C(10), C(11),\nC(12), C(13), C(14),\nC(15), C(16), C(17)\n);\nfloat lods[18] = float[18](\n#define E(j) decodeLod(pix[j].a)\nE(0), E(1), E(2),\nE(3), E(4), E(5),\nE(6), E(7), E(8)\n,\nE(9), E(10), E(11),\nE(12), E(13), E(14),\nE(15), E(16), E(17)\n);\n#if USE_LAPLACIAN\n#define L(p,u,v) textureLod(pyrLaplacian, texCoord + (p) * vec2((u),(v)) / texSize, 0.0f)\nmat3 strengths[2] = mat3[2](mat3(\n#define Lm(u,v) abs(decodeFloat16(L(potMinus,(u),(v)).xy))\nLm(-1,-1), Lm(0,-1), Lm(1,-1),\nLm(-1,0), Lm(0,0), Lm(1,0),\nLm(-1,1), Lm(0,1), Lm(1,1)\n), mat3(\n#define Lp(u,v) abs(decodeFloat16(L(potPlus,(u),(v)).zw))\nLp(-1,-1), Lp(0,-1), Lp(1,-1),\nLp(-1,0), Lp(0,0), Lp(1,0),\nLp(-1,1), Lp(0,1), Lp(1,1)\n));\nfloat myStrength = abs(laplacian(pyramid, vec2(thread), lod));\n#else\n#define L(u,v) (((v)+1)*3 + ((u)+1))\nmat3 strengths[2] = mat3[2](mat3(\n#define Lm(u,v) scores[L((u),(v))]\nLm(-1,-1), Lm(0,-1), Lm(1,-1),\nLm(-1,0), Lm(0,0), Lm(1,0),\nLm(-1,1), Lm(0,1), Lm(1,1)\n), mat3(\n#define Lp(u,v) scores[9 + L((u),(v))]\nLp(-1,-1), Lp(0,-1), Lp(1,-1),\nLp(-1,0), Lp(0,0), Lp(1,0),\nLp(-1,1), Lp(0,1), Lp(1,1)\n));\nfloat myStrength = score;\n#endif\n#define B(j,lod) float(isSameLod(lods[j], (lod))) * float(scores[j] > 0.0f)\nmat3 nearLod[2] = mat3[2](mat3(\n#define Bm(j) B((j), lodMinus)\nBm(0), Bm(1), Bm(2),\nBm(3), Bm(4), Bm(5),\nBm(6), Bm(7), Bm(8)\n), mat3(\n#define Bp(j) B((j), lodPlus)\nBp(9), Bp(10), Bp(11),\nBp(12), Bp(13), Bp(14),\nBp(15), Bp(16), Bp(17)\n));\nmat3 upStrengths = matrixCompMult(strengths[1], nearLod[1]);\nmat3 downStrengths = matrixCompMult(strengths[0], nearLod[0]);\nvec3 maxUpStrength3 = max(upStrengths[0], max(upStrengths[1], upStrengths[2]));\nvec3 maxDownStrength3 = max(downStrengths[0], max(downStrengths[1], downStrengths[2]));\nvec3 maxStrength3 = max(maxUpStrength3, maxDownStrength3);\nfloat maxStrength = max(maxStrength3.x, max(maxStrength3.y, maxStrength3.z));\ncolor.rb = encodeFloat16(score * step(maxStrength, myStrength));\n}"
  18058. /***/ }),
  18059. /***/ "./src/gpu/shaders/keypoints/nonmax-space.glsl":
  18060. /*!*****************************************************!*\
  18061. !*** ./src/gpu/shaders/keypoints/nonmax-space.glsl ***!
  18062. \*****************************************************/
  18063. /***/ ((module) => {
  18064. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D corners;\nvoid main()\n{\nivec2 thread = threadLocation();\nvec4 pixel = threadPixel(corners);\nfloat encodedLod = pixel.a;\nfloat score = decodeFloat16(pixel.rb);\nfloat lod = decodeLod(encodedLod);\nfloat pot = exp2(lod);\ncolor = pixel;\nif(score == 0.0f)\nreturn;\n#if 1\nvec2 gridSize = vec2(pot);\nvec2 gridLocation = floor(mod(texCoord * texSize, gridSize));\nvec2 gridDelta = gridLocation / gridSize - vec2(0.5f);\nfloat gridStep = 1.0f / pot;\nconst float adjustment = 1.25f;\ncolor.rb = encodeFloat16(0.0f);\nif(max(abs(gridDelta.x), abs(gridDelta.y)) > adjustment * gridStep)\nreturn;\n#endif\n#define P(x,y) textureLod(corners, texCoord + pot * vec2((x), (y)) / texSize, 0.0f)\nvec4 pix[9] = vec4[9](\nP(-1,-1), P(0,-1), P(1,-1),\nP(-1,0), pixel, P(1,0),\nP(-1,1), P(0,1), P(1,1)\n);\n#define S(j) decodeFloat16(pix[j].rb)\nmat3 scores = mat3(\nS(0), S(1), S(2),\nS(3), S(4), S(5),\nS(6), S(7), S(8)\n);\n#define B(j) float(isSameLod(decodeLod(pix[j].a), lod))\nmat3 sameLod = mat3(\nB(0), B(1), B(2),\nB(3), B(4), B(5),\nB(6), B(7), B(8)\n);\nmat3 sameLodScores = matrixCompMult(scores, sameLod);\nvec3 maxScore3 = max(sameLodScores[0], max(sameLodScores[1], sameLodScores[2]));\nfloat maxScore = max(maxScore3.x, max(maxScore3.y, maxScore3.z));\ncolor.rb = encodeFloat16(score * step(maxScore, score));\n}"
  18065. /***/ }),
  18066. /***/ "./src/gpu/shaders/keypoints/nonmax-suppression.glsl":
  18067. /*!***********************************************************!*\
  18068. !*** ./src/gpu/shaders/keypoints/nonmax-suppression.glsl ***!
  18069. \***********************************************************/
  18070. /***/ ((module) => {
  18071. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D image;\nuniform float lodStep;\n#if !defined(MULTISCALE)\n#error Must define MULTISCALE\n#elif MULTISCALE != 0\n#define LOD_STEP (lodStep)\n#define USE_MIDDLE_RING\n#else\n#define LOD_STEP (0.0f)\n#endif\n#define PIX(x,y) pixelAtShortOffset(image, ivec2((x),(y)))\n#define L2(v,i) bvec2(isSameEncodedLod(v[i].a, alphaMinus), isSameEncodedLod(v[i].a, alphaPlus))\n#define L3(v,i) bvec3(isSameEncodedLod(v[i].a, alpha), isSameEncodedLod(v[i].a, alphaMinus), isSameEncodedLod(v[i].a, alphaPlus))\n#define S3(v,i) decodeFloat16(v[i].rb) * float(any(L3(v,i)))\n#define S2(v,i) decodeFloat16(v[i].rb) * float(any(L2(v,i)))\n#define P(i) S3(p,i)\n#define Q(i) S2(q,i)\n#define R(i) S2(r,i)\nconst vec4 O = vec4(0.0f);\nvoid main()\n{\nvec4 pixel = threadPixel(image);\nfloat lod = decodeLod(pixel.a);\nfloat score = decodeFloat16(pixel.rb);\ncolor = pixel;\nif(score == 0.0f)\nreturn;\nvec4 p[8] = vec4[8](\nPIX(0,1), PIX(1,1), PIX(1,0), PIX(1,-1),\nPIX(0,-1), PIX(-1,-1), PIX(-1,0), PIX(-1,1)\n);\n#ifdef USE_MIDDLE_RING\nvec4 q[16] = vec4[16](\nPIX(0,2), PIX(1,2), PIX(2,2), PIX(2,1),\nPIX(2,0), PIX(2,-1), PIX(2,-2), PIX(1,-2),\nPIX(0,-2), PIX(-1,-2), PIX(-2,-2), PIX(-2,-1),\nPIX(-2,0), PIX(-2,1), PIX(-2,2), PIX(-1,2)\n);\n#else\nvec4 q[16] = vec4[16](O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O);\n#endif\n#ifdef USE_OUTER_RING\nvec4 r[16] = vec4[16](\nPIX(0,3), PIX(1,3), PIX(3,1), PIX(3,0),\nPIX(3,-1), PIX(1,-3), PIX(0,-3), PIX(-1,-3),\nPIX(-3,-1), PIX(-3,0), PIX(-3,1), PIX(-1,3),\nPIX(0,4), PIX(4,0), PIX(0,-4), PIX(-4,0)\n);\n#else\nvec4 r[16] = vec4[16](O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O);\n#endif\nfloat alphaPlus = encodeLod(lod + LOD_STEP);\nfloat alphaMinus = encodeLod(lod - LOD_STEP);\nfloat alpha = encodeLod(lod);\nmat3 innerScore = mat3(\nP(0), P(1), P(2), P(3),\nP(4), P(5), P(6), P(7),\n0.0f);\nmat4 middleScore = mat4(\nQ(0), Q(1), Q(2), Q(3),\nQ(4), Q(5), Q(6), Q(7),\nQ(8), Q(9), Q(10), Q(11),\nQ(12), Q(13), Q(14), Q(15)\n);\nmat4 outerScore = mat4(\nR(0), R(1), R(2), R(3),\nR(4), R(5), R(6), R(7),\nR(8), R(9), R(10), R(11),\nR(12), R(13), R(14), R(15)\n);\nvec3 maxInnerScore3 = max(innerScore[0], max(innerScore[1], innerScore[2]));\nvec4 maxMiddleScore4 = max(max(middleScore[0], middleScore[1]), max(middleScore[2], middleScore[3]));\nvec4 maxOuterScore4 = max(max(outerScore[0], outerScore[1]), max(outerScore[2], outerScore[3]));\nfloat maxInnerScore = max(maxInnerScore3.x, max(maxInnerScore3.y, maxInnerScore3.z));\nfloat maxMiddleScore = max(max(maxMiddleScore4.x, maxMiddleScore4.y), max(maxMiddleScore4.z, maxMiddleScore4.w));\nfloat maxOuterScore = max(max(maxOuterScore4.x, maxOuterScore4.y), max(maxOuterScore4.z, maxOuterScore4.w));\nfloat maxScore = max(maxInnerScore, max(maxMiddleScore, maxOuterScore));\nfloat finalScore = step(maxScore, score) * score;\ncolor.rb = encodeFloat16(finalScore);\n}"
  18072. /***/ }),
  18073. /***/ "./src/gpu/shaders/keypoints/orb-descriptor.glsl":
  18074. /*!*******************************************************!*\
  18075. !*** ./src/gpu/shaders/keypoints/orb-descriptor.glsl ***!
  18076. \*******************************************************/
  18077. /***/ ((module) => {
  18078. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedCorners;\nuniform int encoderLength;\nuniform sampler2D image;\nuniform int extraSize;\nconst int descriptorSize = 32;\n#define P(a,b,c,d) ivec4((a),(b),(c),(d))\nconst ivec4 pat31[256] = ivec4[256](\nP(8,-3,9,5),\nP(4,2,7,-12),\nP(-11,9,-8,2),\nP(7,-12,12,-13),\nP(2,-13,2,12),\nP(1,-7,1,6),\nP(-2,-10,-2,-4),\nP(-13,-13,-11,-8),\nP(-13,-3,-12,-9),\nP(10,4,11,9),\nP(-13,-8,-8,-9),\nP(-11,7,-9,12),\nP(7,7,12,6),\nP(-4,-5,-3,0),\nP(-13,2,-12,-3),\nP(-9,0,-7,5),\nP(12,-6,12,-1),\nP(-3,6,-2,12),\nP(-6,-13,-4,-8),\nP(11,-13,12,-8),\nP(4,7,5,1),\nP(5,-3,10,-3),\nP(3,-7,6,12),\nP(-8,-7,-6,-2),\nP(-2,11,-1,-10),\nP(-13,12,-8,10),\nP(-7,3,-5,-3),\nP(-4,2,-3,7),\nP(-10,-12,-6,11),\nP(5,-12,6,-7),\nP(5,-6,7,-1),\nP(1,0,4,-5),\nP(9,11,11,-13),\nP(4,7,4,12),\nP(2,-1,4,4),\nP(-4,-12,-2,7),\nP(-8,-5,-7,-10),\nP(4,11,9,12),\nP(0,-8,1,-13),\nP(-13,-2,-8,2),\nP(-3,-2,-2,3),\nP(-6,9,-4,-9),\nP(8,12,10,7),\nP(0,9,1,3),\nP(7,-5,11,-10),\nP(-13,-6,-11,0),\nP(10,7,12,1),\nP(-6,-3,-6,12),\nP(10,-9,12,-4),\nP(-13,8,-8,-12),\nP(-13,0,-8,-4),\nP(3,3,7,8),\nP(5,7,10,-7),\nP(-1,7,1,-12),\nP(3,-10,5,6),\nP(2,-4,3,-10),\nP(-13,0,-13,5),\nP(-13,-7,-12,12),\nP(-13,3,-11,8),\nP(-7,12,-4,7),\nP(6,-10,12,8),\nP(-9,-1,-7,-6),\nP(-2,-5,0,12),\nP(-12,5,-7,5),\nP(3,-10,8,-13),\nP(-7,-7,-4,5),\nP(-3,-2,-1,-7),\nP(2,9,5,-11),\nP(-11,-13,-5,-13),\nP(-1,6,0,-1),\nP(5,-3,5,2),\nP(-4,-13,-4,12),\nP(-9,-6,-9,6),\nP(-12,-10,-8,-4),\nP(10,2,12,-3),\nP(7,12,12,12),\nP(-7,-13,-6,5),\nP(-4,9,-3,4),\nP(7,-1,12,2),\nP(-7,6,-5,1),\nP(-13,11,-12,5),\nP(-3,7,-2,-6),\nP(7,-8,12,-7),\nP(-13,-7,-11,-12),\nP(1,-3,12,12),\nP(2,-6,3,0),\nP(-4,3,-2,-13),\nP(-1,-13,1,9),\nP(7,1,8,-6),\nP(1,-1,3,12),\nP(9,1,12,6),\nP(-1,-9,-1,3),\nP(-13,-13,-10,5),\nP(7,7,10,12),\nP(12,-5,12,9),\nP(6,3,7,11),\nP(5,-13,6,10),\nP(2,-12,2,3),\nP(3,8,4,-6),\nP(2,6,12,-13),\nP(9,-12,10,3),\nP(-8,4,-7,9),\nP(-11,12,-4,-6),\nP(1,12,2,-8),\nP(6,-9,7,-4),\nP(2,3,3,-2),\nP(6,3,11,0),\nP(3,-3,8,-8),\nP(7,8,9,3),\nP(-11,-5,-6,-4),\nP(-10,11,-5,10),\nP(-5,-8,-3,12),\nP(-10,5,-9,0),\nP(8,-1,12,-6),\nP(4,-6,6,-11),\nP(-10,12,-8,7),\nP(4,-2,6,7),\nP(-2,0,-2,12),\nP(-5,-8,-5,2),\nP(7,-6,10,12),\nP(-9,-13,-8,-8),\nP(-5,-13,-5,-2),\nP(8,-8,9,-13),\nP(-9,-11,-9,0),\nP(1,-8,1,-2),\nP(7,-4,9,1),\nP(-2,1,-1,-4),\nP(11,-6,12,-11),\nP(-12,-9,-6,4),\nP(3,7,7,12),\nP(5,5,10,8),\nP(0,-4,2,8),\nP(-9,12,-5,-13),\nP(0,7,2,12),\nP(-1,2,1,7),\nP(5,11,7,-9),\nP(3,5,6,-8),\nP(-13,-4,-8,9),\nP(-5,9,-3,-3),\nP(-4,-7,-3,-12),\nP(6,5,8,0),\nP(-7,6,-6,12),\nP(-13,6,-5,-2),\nP(1,-10,3,10),\nP(4,1,8,-4),\nP(-2,-2,2,-13),\nP(2,-12,12,12),\nP(-2,-13,0,-6),\nP(4,1,9,3),\nP(-6,-10,-3,-5),\nP(-3,-13,-1,1),\nP(7,5,12,-11),\nP(4,-2,5,-7),\nP(-13,9,-9,-5),\nP(7,1,8,6),\nP(7,-8,7,6),\nP(-7,-4,-7,1),\nP(-8,11,-7,-8),\nP(-13,6,-12,-8),\nP(2,4,3,9),\nP(10,-5,12,3),\nP(-6,-5,-6,7),\nP(8,-3,9,-8),\nP(2,-12,2,8),\nP(-11,-2,-10,3),\nP(-12,-13,-7,-9),\nP(-11,0,-10,-5),\nP(5,-3,11,8),\nP(-2,-13,-1,12),\nP(-1,-8,0,9),\nP(-13,-11,-12,-5),\nP(-10,-2,-10,11),\nP(-3,9,-2,-13),\nP(2,-3,3,2),\nP(-9,-13,-4,0),\nP(-4,6,-3,-10),\nP(-4,12,-2,-7),\nP(-6,-11,-4,9),\nP(6,-3,6,11),\nP(-13,11,-5,5),\nP(11,11,12,6),\nP(7,-5,12,-2),\nP(-1,12,0,7),\nP(-4,-8,-3,-2),\nP(-7,1,-6,7),\nP(-13,-12,-8,-13),\nP(-7,-2,-6,-8),\nP(-8,5,-6,-9),\nP(-5,-1,-4,5),\nP(-13,7,-8,10),\nP(1,5,5,-13),\nP(1,0,10,-13),\nP(9,12,10,-1),\nP(5,-8,10,-9),\nP(-1,11,1,-13),\nP(-9,-3,-6,2),\nP(-1,-10,1,12),\nP(-13,1,-8,-10),\nP(8,-11,10,-6),\nP(2,-13,3,-6),\nP(7,-13,12,-9),\nP(-10,-10,-5,-7),\nP(-10,-8,-8,-13),\nP(4,-6,8,5),\nP(3,12,8,-13),\nP(-4,2,-3,-3),\nP(5,-13,10,-12),\nP(4,-13,5,-1),\nP(-9,9,-4,3),\nP(0,3,3,-9),\nP(-12,1,-6,1),\nP(3,2,4,-8),\nP(-10,-10,-10,9),\nP(8,-13,12,12),\nP(-8,-12,-6,-5),\nP(2,2,3,7),\nP(10,6,11,-8),\nP(6,8,8,-12),\nP(-7,10,-6,5),\nP(-3,-9,-3,9),\nP(-1,-13,-1,5),\nP(-3,-7,-3,4),\nP(-8,-2,-8,3),\nP(4,2,12,12),\nP(2,-5,3,11),\nP(6,-9,11,-13),\nP(3,-1,7,12),\nP(11,-1,12,4),\nP(-3,0,-3,6),\nP(4,-11,4,12),\nP(2,-4,2,1),\nP(-10,-6,-8,1),\nP(-13,7,-11,1),\nP(-13,12,-11,-13),\nP(6,0,11,-13),\nP(0,-1,1,4),\nP(-13,3,-9,-2),\nP(-9,8,-6,-3),\nP(-13,-6,-8,-2),\nP(5,-9,8,10),\nP(2,7,3,-9),\nP(-1,-6,-1,-1),\nP(9,5,11,-2),\nP(11,-3,12,-8),\nP(3,0,3,5),\nP(-1,4,0,10),\nP(3,-6,4,5),\nP(-13,0,-10,5),\nP(5,8,12,11),\nP(8,9,9,-6),\nP(7,-4,8,-12),\nP(-10,4,-10,9),\nP(7,3,12,4),\nP(9,-7,10,-2),\nP(7,0,12,-2),\nP(-1,-6,0,-11)\n);\nvoid getPair(int index, mat2 rot, out vec2 p, out vec2 q)\n{\nivec4 data = pat31[index];\nvec2 op = vec2(data.xy);\nvec2 oq = vec2(data.zw);\np = rot * op;\nq = rot * oq;\n}\nvoid main()\n{\nvec4 pixel = threadPixel(encodedCorners);\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint descriptorCell = address.offset - sizeofEncodedKeypoint(0, extraSize) / 4;\ncolor = pixel;\nif(descriptorCell < 0)\nreturn;\nKeypoint keypoint = decodeKeypoint(encodedCorners, encoderLength, address);\nif(isBadKeypoint(keypoint))\nreturn;\nfloat degreesOrientation = round(360.0f + degrees(keypoint.orientation));\nfloat orientation = radians(degreesOrientation - mod(degreesOrientation, 12.0f));\nfloat kcos = cos(orientation);\nfloat ksin = sin(orientation);\nmat2 rot = mat2(kcos, ksin, -ksin, kcos);\nfloat pot = exp2(keypoint.lod);\nint patternStart = 32 * descriptorCell;\nuint test[4] = uint[4](0u, 0u, 0u, 0u);\nfor(int t = 0; t < 4; t++) {\nuint bits = 0u;\nvec2 p, q;\nvec4 a, b;\nint i = t * 8;\n@unroll\nfor(int j = 0; j < 8; j++) {\ngetPair(patternStart + i + j, rot, p, q);\na = texelFetch(image, ivec2(round(keypoint.position + pot * p)), 0);\nb = texelFetch(image, ivec2(round(keypoint.position + pot * q)), 0);\nbits |= uint(a.g < b.g) << j;\n}\ntest[t] = bits;\n}\ncolor = vec4(test[0], test[1], test[2], test[3]) / 255.0f;\n}"
  18079. /***/ }),
  18080. /***/ "./src/gpu/shaders/keypoints/orb-orientation.glsl":
  18081. /*!********************************************************!*\
  18082. !*** ./src/gpu/shaders/keypoints/orb-orientation.glsl ***!
  18083. \********************************************************/
  18084. /***/ ((module) => {
  18085. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D image;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#define P(x,y) ivec2((x),(y))\nconst int diskPointCount[16] = int[16](0, 4, 12, 28, 48, 80, 112, 148, 196, 252, 316, 376, 440, 528, 612, 708);\nconst ivec2 diskPoint[708] = ivec2[708](\nP(0,-1),P(-1,0),P(1,0),P(0,1),\nP(-1,-1),P(1,-1),P(-1,1),P(1,1),P(0,-2),P(-2,0),P(2,0),P(0,2),\nP(-1,-2),P(1,-2),P(-2,-1),P(2,-1),P(-2,1),P(2,1),P(-1,2),P(1,2),P(-2,-2),P(2,-2),P(-2,2),P(2,2),P(0,-3),P(-3,0),P(3,0),P(0,3),\nP(-1,-3),P(1,-3),P(-3,-1),P(3,-1),P(-3,1),P(3,1),P(-1,3),P(1,3),P(-2,-3),P(2,-3),P(-3,-2),P(3,-2),P(-3,2),P(3,2),P(-2,3),P(2,3),P(0,-4),P(-4,0),P(4,0),P(0,4),\nP(-1,-4),P(1,-4),P(-4,-1),P(4,-1),P(-4,1),P(4,1),P(-1,4),P(1,4),P(-3,-3),P(3,-3),P(-3,3),P(3,3),P(-2,-4),P(2,-4),P(-4,-2),P(4,-2),P(-4,2),P(4,2),P(-2,4),P(2,4),P(0,-5),P(-3,-4),P(3,-4),P(-4,-3),P(4,-3),P(-5,0),P(5,0),P(-4,3),P(4,3),P(-3,4),P(3,4),P(0,5),\nP(-1,-5),P(1,-5),P(-5,-1),P(5,-1),P(-5,1),P(5,1),P(-1,5),P(1,5),P(-2,-5),P(2,-5),P(-5,-2),P(5,-2),P(-5,2),P(5,2),P(-2,5),P(2,5),P(-4,-4),P(4,-4),P(-4,4),P(4,4),P(-3,-5),P(3,-5),P(-5,-3),P(5,-3),P(-5,3),P(5,3),P(-3,5),P(3,5),P(0,-6),P(-6,0),P(6,0),P(0,6),\nP(-1,-6),P(1,-6),P(-6,-1),P(6,-1),P(-6,1),P(6,1),P(-1,6),P(1,6),P(-2,-6),P(2,-6),P(-6,-2),P(6,-2),P(-6,2),P(6,2),P(-2,6),P(2,6),P(-4,-5),P(4,-5),P(-5,-4),P(5,-4),P(-5,4),P(5,4),P(-4,5),P(4,5),P(-3,-6),P(3,-6),P(-6,-3),P(6,-3),P(-6,3),P(6,3),P(-3,6),P(3,6),P(0,-7),P(-7,0),P(7,0),P(0,7),\nP(-1,-7),P(1,-7),P(-5,-5),P(5,-5),P(-7,-1),P(7,-1),P(-7,1),P(7,1),P(-5,5),P(5,5),P(-1,7),P(1,7),P(-4,-6),P(4,-6),P(-6,-4),P(6,-4),P(-6,4),P(6,4),P(-4,6),P(4,6),P(-2,-7),P(2,-7),P(-7,-2),P(7,-2),P(-7,2),P(7,2),P(-2,7),P(2,7),P(-3,-7),P(3,-7),P(-7,-3),P(7,-3),P(-7,3),P(7,3),P(-3,7),P(3,7),P(-5,-6),P(5,-6),P(-6,-5),P(6,-5),P(-6,5),P(6,5),P(-5,6),P(5,6),P(0,-8),P(-8,0),P(8,0),P(0,8),\nP(-1,-8),P(1,-8),P(-4,-7),P(4,-7),P(-7,-4),P(7,-4),P(-8,-1),P(8,-1),P(-8,1),P(8,1),P(-7,4),P(7,4),P(-4,7),P(4,7),P(-1,8),P(1,8),P(-2,-8),P(2,-8),P(-8,-2),P(8,-2),P(-8,2),P(8,2),P(-2,8),P(2,8),P(-6,-6),P(6,-6),P(-6,6),P(6,6),P(-3,-8),P(3,-8),P(-8,-3),P(8,-3),P(-8,3),P(8,3),P(-3,8),P(3,8),P(-5,-7),P(5,-7),P(-7,-5),P(7,-5),P(-7,5),P(7,5),P(-5,7),P(5,7),P(-4,-8),P(4,-8),P(-8,-4),P(8,-4),P(-8,4),P(8,4),P(-4,8),P(4,8),P(0,-9),P(-9,0),P(9,0),P(0,9),\nP(-1,-9),P(1,-9),P(-9,-1),P(9,-1),P(-9,1),P(9,1),P(-1,9),P(1,9),P(-2,-9),P(2,-9),P(-6,-7),P(6,-7),P(-7,-6),P(7,-6),P(-9,-2),P(9,-2),P(-9,2),P(9,2),P(-7,6),P(7,6),P(-6,7),P(6,7),P(-2,9),P(2,9),P(-5,-8),P(5,-8),P(-8,-5),P(8,-5),P(-8,5),P(8,5),P(-5,8),P(5,8),P(-3,-9),P(3,-9),P(-9,-3),P(9,-3),P(-9,3),P(9,3),P(-3,9),P(3,9),P(-4,-9),P(4,-9),P(-9,-4),P(9,-4),P(-9,4),P(9,4),P(-4,9),P(4,9),P(-7,-7),P(7,-7),P(-7,7),P(7,7),P(0,-10),P(-6,-8),P(6,-8),P(-8,-6),P(8,-6),P(-10,0),P(10,0),P(-8,6),P(8,6),P(-6,8),P(6,8),P(0,10),\nP(-1,-10),P(1,-10),P(-10,-1),P(10,-1),P(-10,1),P(10,1),P(-1,10),P(1,10),P(-2,-10),P(2,-10),P(-10,-2),P(10,-2),P(-10,2),P(10,2),P(-2,10),P(2,10),P(-5,-9),P(5,-9),P(-9,-5),P(9,-5),P(-9,5),P(9,5),P(-5,9),P(5,9),P(-3,-10),P(3,-10),P(-10,-3),P(10,-3),P(-10,3),P(10,3),P(-3,10),P(3,10),P(-7,-8),P(7,-8),P(-8,-7),P(8,-7),P(-8,7),P(8,7),P(-7,8),P(7,8),P(-4,-10),P(4,-10),P(-10,-4),P(10,-4),P(-10,4),P(10,4),P(-4,10),P(4,10),P(-6,-9),P(6,-9),P(-9,-6),P(9,-6),P(-9,6),P(9,6),P(-6,9),P(6,9),P(0,-11),P(-11,0),P(11,0),P(0,11),\nP(-1,-11),P(1,-11),P(-11,-1),P(11,-1),P(-11,1),P(11,1),P(-1,11),P(1,11),P(-2,-11),P(2,-11),P(-5,-10),P(5,-10),P(-10,-5),P(10,-5),P(-11,-2),P(11,-2),P(-11,2),P(11,2),P(-10,5),P(10,5),P(-5,10),P(5,10),P(-2,11),P(2,11),P(-8,-8),P(8,-8),P(-8,8),P(8,8),P(-3,-11),P(3,-11),P(-7,-9),P(7,-9),P(-9,-7),P(9,-7),P(-11,-3),P(11,-3),P(-11,3),P(11,3),P(-9,7),P(9,7),P(-7,9),P(7,9),P(-3,11),P(3,11),P(-6,-10),P(6,-10),P(-10,-6),P(10,-6),P(-10,6),P(10,6),P(-6,10),P(6,10),P(-4,-11),P(4,-11),P(-11,-4),P(11,-4),P(-11,4),P(11,4),P(-4,11),P(4,11),P(0,-12),P(-12,0),P(12,0),P(0,12),\nP(-1,-12),P(1,-12),P(-8,-9),P(8,-9),P(-9,-8),P(9,-8),P(-12,-1),P(12,-1),P(-12,1),P(12,1),P(-9,8),P(9,8),P(-8,9),P(8,9),P(-1,12),P(1,12),P(-5,-11),P(5,-11),P(-11,-5),P(11,-5),P(-11,5),P(11,5),P(-5,11),P(5,11),P(-2,-12),P(2,-12),P(-12,-2),P(12,-2),P(-12,2),P(12,2),P(-2,12),P(2,12),P(-7,-10),P(7,-10),P(-10,-7),P(10,-7),P(-10,7),P(10,7),P(-7,10),P(7,10),P(-3,-12),P(3,-12),P(-12,-3),P(12,-3),P(-12,3),P(12,3),P(-3,12),P(3,12),P(-6,-11),P(6,-11),P(-11,-6),P(11,-6),P(-11,6),P(11,6),P(-6,11),P(6,11),P(-4,-12),P(4,-12),P(-12,-4),P(12,-4),P(-12,4),P(12,4),P(-4,12),P(4,12),P(-9,-9),P(9,-9),P(-9,9),P(9,9),P(-8,-10),P(8,-10),P(-10,-8),P(10,-8),P(-10,8),P(10,8),P(-8,10),P(8,10),P(0,-13),P(-5,-12),P(5,-12),P(-12,-5),P(12,-5),P(-13,0),P(13,0),P(-12,5),P(12,5),P(-5,12),P(5,12),P(0,13),\nP(-1,-13),P(1,-13),P(-7,-11),P(7,-11),P(-11,-7),P(11,-7),P(-13,-1),P(13,-1),P(-13,1),P(13,1),P(-11,7),P(11,7),P(-7,11),P(7,11),P(-1,13),P(1,13),P(-2,-13),P(2,-13),P(-13,-2),P(13,-2),P(-13,2),P(13,2),P(-2,13),P(2,13),P(-3,-13),P(3,-13),P(-13,-3),P(13,-3),P(-13,3),P(13,3),P(-3,13),P(3,13),P(-6,-12),P(6,-12),P(-12,-6),P(12,-6),P(-12,6),P(12,6),P(-6,12),P(6,12),P(-9,-10),P(9,-10),P(-10,-9),P(10,-9),P(-10,9),P(10,9),P(-9,10),P(9,10),P(-4,-13),P(4,-13),P(-8,-11),P(8,-11),P(-11,-8),P(11,-8),P(-13,-4),P(13,-4),P(-13,4),P(13,4),P(-11,8),P(11,8),P(-8,11),P(8,11),P(-4,13),P(4,13),P(-7,-12),P(7,-12),P(-12,-7),P(12,-7),P(-12,7),P(12,7),P(-7,12),P(7,12),P(-5,-13),P(5,-13),P(-13,-5),P(13,-5),P(-13,5),P(13,5),P(-5,13),P(5,13),P(0,-14),P(-14,0),P(14,0),P(0,14),\nP(-1,-14),P(1,-14),P(-14,-1),P(14,-1),P(-14,1),P(14,1),P(-1,14),P(1,14),P(-2,-14),P(2,-14),P(-10,-10),P(10,-10),P(-14,-2),P(14,-2),P(-14,2),P(14,2),P(-10,10),P(10,10),P(-2,14),P(2,14),P(-9,-11),P(9,-11),P(-11,-9),P(11,-9),P(-11,9),P(11,9),P(-9,11),P(9,11),P(-3,-14),P(3,-14),P(-6,-13),P(6,-13),P(-13,-6),P(13,-6),P(-14,-3),P(14,-3),P(-14,3),P(14,3),P(-13,6),P(13,6),P(-6,13),P(6,13),P(-3,14),P(3,14),P(-8,-12),P(8,-12),P(-12,-8),P(12,-8),P(-12,8),P(12,8),P(-8,12),P(8,12),P(-4,-14),P(4,-14),P(-14,-4),P(14,-4),P(-14,4),P(14,4),P(-4,14),P(4,14),P(-7,-13),P(7,-13),P(-13,-7),P(13,-7),P(-13,7),P(13,7),P(-7,13),P(7,13),P(-5,-14),P(5,-14),P(-10,-11),P(10,-11),P(-11,-10),P(11,-10),P(-14,-5),P(14,-5),P(-14,5),P(14,5),P(-11,10),P(11,10),P(-10,11),P(10,11),P(-5,14),P(5,14),P(0,-15),P(-9,-12),P(9,-12),P(-12,-9),P(12,-9),P(-15,0),P(15,0),P(-12,9),P(12,9),P(-9,12),P(9,12),P(0,15)\n);\nconst int DEFAULT_PATCH_RADIUS = 15;\nconst int MIN_PATCH_RADIUS = 2;\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nint keypointIndex = thread.x + thread.y * outputSize().x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\nvec2 m = vec2(0.0f);\nfloat pot = exp2(keypoint.lod);\nvec2 imageSize = vec2(textureSize(image, 0));\nint scaledRadius = int(ceil(float(DEFAULT_PATCH_RADIUS) / pot));\nint radius = max(scaledRadius, MIN_PATCH_RADIUS);\nint count = diskPointCount[radius];\nfor(int j = 0; j < count; j++) {\nvec2 offset = vec2(diskPoint[j]);\nvec2 position = keypoint.position + round(pot * offset);\nvec4 patchPixel = texture(image, (position + vec2(0.5f)) / imageSize);\nm += offset * patchPixel.g;\n}\nfloat angle = fastAtan2(m.y, m.x);\nfloat encodedOrientation = encodeKeypointOrientation(angle);\ncolor = vec4(0.0f, encodedOrientation, 0.0f, 0.0f);\n}"
  18086. /***/ }),
  18087. /***/ "./src/gpu/shaders/keypoints/refine-scale.glsl":
  18088. /*!*****************************************************!*\
  18089. !*** ./src/gpu/shaders/keypoints/refine-scale.glsl ***!
  18090. \*****************************************************/
  18091. /***/ ((module) => {
  18092. module.exports = "@include \"keypoints.glsl\"\n@include \"filters.glsl\"\n#if !defined(METHOD)\n#error Undefined METHOD\n#endif\nuniform sampler2D pyramid;\nuniform float lodStep;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#if METHOD == 1\nuniform int threshold;\n#endif\nconst float eps = 1e-6;\nfloat cornerStrength(vec2 position, float lod)\n{\n#if METHOD == 0\nreturn laplacian(pyramid, position, lod);\n#elif METHOD == 1\nfloat pot = exp2(lod);\nfloat t = float(clamp(threshold, 0, 255)) / 255.0f;\n#define P(x,y) pyrPixelAtOffset(pyramid, lod, pot, ivec2((x),(y))).g\nmat4 mp = mat4(\nP(0,3),P(3,0),P(0,-3),P(-3,0),\nP(1,3),P(2,2),P(3,1),P(3,-1),\nP(2,-2),P(1,-3),P(-1,-3),P(-2,-2),\nP(-3,-1),P(-3,1),P(-2,2),P(-1,3)\n);\nfloat c = P(0,0);\nfloat ct = c + t, c_t = c - t;\nmat4 mct = mp - mat4(ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct,ct);\nmat4 mc_t = mat4(c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t,c_t) - mp;\nconst vec4 zeros = vec4(0.0f), ones = vec4(1.0f);\nvec4 bs = max(mct[0], zeros), ds = max(mc_t[0], zeros);\nbs += max(mct[1], zeros); ds += max(mc_t[1], zeros);\nbs += max(mct[2], zeros); ds += max(mc_t[2], zeros);\nbs += max(mct[3], zeros); ds += max(mc_t[3], zeros);\nreturn max(dot(bs, ones), dot(ds, ones)) / 16.0f;\n#else\n#error Invalid method\n#endif\n}\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\ncolor = pixel;\nif(address.offset != 1)\nreturn;\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\nif(isBadKeypoint(keypoint))\nreturn;\nvec3 strength = vec3(\ncornerStrength(keypoint.position, max(0.0f, keypoint.lod - lodStep)),\ncornerStrength(keypoint.position, keypoint.lod),\ncornerStrength(keypoint.position, keypoint.lod + lodStep)\n);\nvec3 p = mat3(\n2, -3, 1,\n-4, 4, 0,\n2, -1, 0\n) * strength;\nfloat maxStrength = max(strength.x, max(strength.y, strength.z));\nvec3 diffStrength = abs(strength - vec3(maxStrength));\nvec3 strengthIndicators = vec3(lessThan(diffStrength, vec3(eps)));\nfloat maxPoint = min(1.0f, dot(vec3(0.0f, 0.5f, 1.0f), strengthIndicators));\nbool hasMax = p.x < -eps;\nfloat pmax = hasMax ? -0.5f * p.y / p.x : maxPoint;\nfloat alpha = abs(pmax - 0.5f) <= 0.5f ? pmax : maxPoint;\nfloat lodOffset = mix(-lodStep, lodStep, alpha);\nfloat lod = keypoint.lod + lodOffset;\ncolor.r = encodeLod(lod);\n}"
  18093. /***/ }),
  18094. /***/ "./src/gpu/shaders/keypoints/score-findmax.glsl":
  18095. /*!******************************************************!*\
  18096. !*** ./src/gpu/shaders/keypoints/score-findmax.glsl ***!
  18097. \******************************************************/
  18098. /***/ ((module) => {
  18099. module.exports = "@include \"float16.glsl\"\nuniform sampler2D corners;\nuniform int iterationNumber;\nvoid main()\n{\nivec2 thread = threadLocation();\nivec2 bounds = outputSize();\nint jump = (1 << iterationNumber);\nint clusterLength = jump << 1;\nint clusterMask = clusterLength - 1;\nivec2 clusterPos = ivec2(thread >> (1 + iterationNumber)) << (1 + iterationNumber);\nivec2 next1 = clusterPos + ((thread - clusterPos + ivec2(jump, 0)) & clusterMask);\nivec2 next2 = clusterPos + ((thread - clusterPos + ivec2(0, jump)) & clusterMask);\nivec2 next3 = clusterPos + ((thread - clusterPos + ivec2(jump, jump)) & clusterMask);\nvec4 p0 = threadPixel(corners);\nvec4 p1 = texelFetch(corners, next1 % bounds, 0);\nvec4 p2 = texelFetch(corners, next2 % bounds, 0);\nvec4 p3 = texelFetch(corners, next3 % bounds, 0);\nfloat s0 = decodeFloat16(p0.rb);\nfloat s1 = decodeFloat16(p1.rb);\nfloat s2 = decodeFloat16(p2.rb);\nfloat s3 = decodeFloat16(p3.rb);\nbool b0 = s0 >= s1 && s0 >= s2 && s0 >= s3;\nbool b1 = s1 >= s0 && s1 >= s2 && s1 >= s3;\nbool b2 = s2 >= s0 && s2 >= s1 && s2 >= s3;\ncolor = vec4(0.0f);\ncolor.rb = b0 ? p0.rb : (\nb1 ? p1.rb : (\nb2 ? p2.rb : p3.rb\n)\n);\n}"
  18100. /***/ }),
  18101. /***/ "./src/gpu/shaders/keypoints/shuffle.glsl":
  18102. /*!************************************************!*\
  18103. !*** ./src/gpu/shaders/keypoints/shuffle.glsl ***!
  18104. \************************************************/
  18105. /***/ ((module) => {
  18106. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#if PERMUTATION_MAXLEN % 4 > 0 || PERMUTATION_MAXLEN * 4 > 16384\n#error Invalid PERMUTATION_MAXLEN\n#endif\nlayout(std140) uniform Permutation\n{\nivec4 permutation[PERMUTATION_MAXLEN / 4];\n};\nint permutationElement(int index)\n{\nint base = index - (index % PERMUTATION_MAXLEN);\nint offset = index - base;\nivec4 tuple = permutation[offset / 4];\nint newOffset = tuple[offset & 3];\nreturn base + newOffset;\n}\nvoid main()\n{\nivec2 thread = threadLocation();\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress myAddress = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint myIndex = findKeypointIndex(myAddress, descriptorSize, extraSize);\nint otherIndex = permutationElement(myIndex);\nKeypointAddress otherAddress = KeypointAddress(otherIndex * pixelsPerKeypoint, myAddress.offset);\nKeypoint myKeypoint = decodeKeypoint(encodedKeypoints, encoderLength, myAddress);\nKeypoint otherKeypoint = decodeKeypoint(encodedKeypoints, encoderLength, otherAddress);\ncolor = readKeypointData(encodedKeypoints, encoderLength, otherAddress);\n}"
  18107. /***/ }),
  18108. /***/ "./src/gpu/shaders/keypoints/sort-keypoints.glsl":
  18109. /*!*******************************************************!*\
  18110. !*** ./src/gpu/shaders/keypoints/sort-keypoints.glsl ***!
  18111. \*******************************************************/
  18112. /***/ ((module) => {
  18113. module.exports = "@include \"keypoints.glsl\"\n#if !defined(STAGE)\n#error Undefined STAGE\n#elif STAGE == 1\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#elif STAGE == 2\nuniform sampler2D permutation;\nuniform int blockSize;\nuniform int dblLog2BlockSize;\n#elif STAGE == 3\nuniform sampler2D permutation;\nuniform int maxKeypoints;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\n#else\n#error Invalid STAGE\n#endif\nstruct PermutationElement\n{\nint keypointIndex;\nfloat score;\nbool valid;\n};\nvec4 encodePermutationElement(PermutationElement element)\n{\nconst vec2 ONES = vec2(1.0f);\nvec2 encodedScore = element.valid ? encodeFloat16(element.score) : ONES;\nvec2 encodedIndex = vec2(element.keypointIndex & 255, (element.keypointIndex >> 8) & 255) / 255.0f;\nreturn vec4(encodedIndex, encodedScore);\n}\nPermutationElement decodePermutationElement(vec4 pixel)\n{\nconst vec2 ONES = vec2(1.0f);\nPermutationElement element;\nelement.keypointIndex = int(pixel.r * 255.0f) | (int(pixel.g * 255.0f) << 8);\nelement.valid = !all(equal(pixel.ba, ONES));\nelement.score = element.valid ? decodeFloat16(pixel.ba) : -1.0f;\nreturn element;\n}\nPermutationElement readPermutationElement(sampler2D permutation, int elementIndex, int stride, int height)\n{\nconst vec4 INVALID_PIXEL = vec4(1.0f);\nivec2 pos = ivec2(elementIndex % stride, elementIndex / stride);\nvec4 pixel = pos.y < height ? pixelAt(permutation, pos) : INVALID_PIXEL;\nreturn decodePermutationElement(pixel);\n}\n#if STAGE == 2\nPermutationElement selectKth(sampler2D permutation, int k, int la, int ra, int lb, int rb)\n{\nfloat scoreA, scoreB;\nint ha, hb, ma, mb;\nbool discard1stHalf, altb;\nbool locked = false;\nint tmp, result = 0;\nint stride = outputSize().x;\nint height = outputSize().y;\nfor(int i = 0; i < dblLog2BlockSize; i++) {\ntmp = (lb > rb && !locked) ? (la+k) : result;\nresult = (la > ra && !locked) ? (lb+k) : tmp;\nlocked = locked || (la > ra) || (lb > rb);\nha = (ra - la + 1) / 2;\nhb = (rb - lb + 1) / 2;\nma = la + ha;\nmb = lb + hb;\nscoreA = readPermutationElement(permutation, ma, stride, height).score;\nscoreB = readPermutationElement(permutation, mb, stride, height).score;\ndiscard1stHalf = (k > ha + hb);\naltb = (-scoreA < -scoreB);\nk -= int(discard1stHalf && altb) * (ha + 1);\nk -= int(discard1stHalf && !altb) * (hb + 1);\nla += int(discard1stHalf && altb) * (ma + 1 - la);\nlb += int(discard1stHalf && !altb) * (mb + 1 - lb);\nra += int(!discard1stHalf && !altb) * (ma - 1 - ra);\nrb += int(!discard1stHalf && altb) * (mb - 1 - rb);\n}\nreturn readPermutationElement(permutation, result, stride, height);\n}\n#endif\nvoid main()\n{\n#if STAGE == 1\nivec2 thread = threadLocation();\nint stride = outputSize().x;\nint keypointIndex = thread.y * stride + thread.x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\nPermutationElement element;\nelement.keypointIndex = keypointIndex;\nelement.score = keypoint.score;\nelement.valid = !isBadKeypoint(keypoint);\ncolor = encodePermutationElement(element);\n#elif STAGE == 2\nivec2 thread = threadLocation();\nint stride = outputSize().x;\nint elementIndex = thread.y * stride + thread.x;\nint blockIndex = elementIndex / blockSize;\nint blockOffset = elementIndex % blockSize;\nint la = blockIndex * blockSize;\nint lb = la + blockSize / 2;\nint ra = lb - 1;\nint rb = (blockIndex + 1) * blockSize - 1;\nint k = blockOffset;\nPermutationElement element = selectKth(permutation, k, la, ra, lb, rb);\ncolor = encodePermutationElement(element);\n#elif STAGE == 3\nivec2 thread = threadLocation();\nint newEncoderLength = outputSize().x;\nKeypointAddress myAddress = findKeypointAddress(thread, newEncoderLength, descriptorSize, extraSize);\nint myKeypointIndex = findKeypointIndex(myAddress, descriptorSize, extraSize);\nivec2 psize = textureSize(permutation, 0);\nPermutationElement element = readPermutationElement(permutation, myKeypointIndex, psize.x, psize.y);\nint oldEncoderLength = textureSize(encodedKeypoints, 0).x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(element.keypointIndex * pixelsPerKeypoint, myAddress.offset);\nvec4 keypointData = readKeypointData(encodedKeypoints, oldEncoderLength, address);\ncolor = myKeypointIndex < maxKeypoints && element.valid ? keypointData : encodeNullKeypoint();\n#endif\n}"
  18114. /***/ }),
  18115. /***/ "./src/gpu/shaders/keypoints/subpixel-refinement.glsl":
  18116. /*!************************************************************!*\
  18117. !*** ./src/gpu/shaders/keypoints/subpixel-refinement.glsl ***!
  18118. \************************************************************/
  18119. /***/ ((module) => {
  18120. module.exports = "@include \"keypoints.glsl\"\n@include \"float16.glsl\"\n#if !defined(METHOD)\n#error Must define METHOD\n#endif\nuniform sampler2D pyramid;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nuniform int maxIterations;\nuniform float epsilon;\nconst int PATCH_RADIUS = 1;\nconst int PATCH_SIZE = 2 * PATCH_RADIUS + 1;\nconst int PATCH_SIZE_SQUARED = PATCH_SIZE * PATCH_SIZE;\nconst int LARGE_PATCH_RADIUS = PATCH_RADIUS + 1;\nconst int LARGE_PATCH_SIZE = 2 * LARGE_PATCH_RADIUS + 1;\nconst int LARGE_PATCH_SIZE_SQUARED = LARGE_PATCH_SIZE * LARGE_PATCH_SIZE;\nconst int LARGER_PATCH_RADIUS = LARGE_PATCH_RADIUS + 1;\nconst int LARGER_PATCH_SIZE = 2 * LARGER_PATCH_RADIUS + 1;\nconst int LARGER_PATCH_SIZE_SQUARED = LARGER_PATCH_SIZE * LARGER_PATCH_SIZE;\nconst float EPS = 1e-5;\nfloat smoothPixelBuffer[LARGER_PATCH_SIZE_SQUARED];\nvec2 derivativesBuffer[LARGE_PATCH_SIZE_SQUARED];\nfloat responseBuffer[PATCH_SIZE_SQUARED];\n#define patchPixelAt(u,v) smoothPixelBuffer[((v) + LARGER_PATCH_RADIUS) * LARGER_PATCH_SIZE + ((u) + LARGER_PATCH_RADIUS)]\n#define derivativesAt(u,v) derivativesBuffer[((v) + LARGE_PATCH_RADIUS) * LARGE_PATCH_SIZE + ((u) + LARGE_PATCH_RADIUS)]\n#define responseAt(u,v) responseBuffer[((v) + PATCH_RADIUS) * PATCH_SIZE + ((u) + PATCH_RADIUS)]\nvoid readPixels(vec2 center, float lod)\n{\nivec2 pyrBaseSize = textureSize(pyramid, 0);\nfloat pot = exp2(lod);\nint u, v;\nfor(int j = 0; j < LARGER_PATCH_SIZE; j++) {\nfor(int i = 0; i < LARGER_PATCH_SIZE; i++) {\nu = i - LARGER_PATCH_RADIUS;\nv = j - LARGER_PATCH_RADIUS;\npatchPixelAt(u,v) = pyrSubpixelAtExOffset(pyramid, center, lod, pot, ivec2(u,v), pyrBaseSize).g;\n}\n}\n}\nvoid computeDerivatives()\n{\nconst mat3 dx = mat3(\n-1, 0, 1,\n-2, 0, 2,\n-1, 0, 1\n);\nconst mat3 dy = mat3(\n1, 2, 1,\n0, 0, 0,\n-1,-2,-1\n);\nint u, v;\nmat3 pix, convX, convY;\nconst vec3 ones = vec3(1.0f);\nfor(int j = 0; j < LARGE_PATCH_SIZE; j++) {\nfor(int i = 0; i < LARGE_PATCH_SIZE; i++) {\nu = i - LARGE_PATCH_RADIUS;\nv = j - LARGE_PATCH_RADIUS;\npix = mat3(\npatchPixelAt(u+1,v+1), patchPixelAt(u+0,v+1), patchPixelAt(u-1,v+1),\npatchPixelAt(u+1,v+0), patchPixelAt(u+0,v+0), patchPixelAt(u-1,v+0),\npatchPixelAt(u+1,v-1), patchPixelAt(u+0,v-1), patchPixelAt(u-1,v-1)\n);\nconvX = matrixCompMult(dx, pix);\nconvY = matrixCompMult(dy, pix);\nderivativesAt(u,v) = vec2(\ndot(ones, vec3(\ndot(convX[0], ones),\ndot(convX[1], ones),\ndot(convX[2], ones)\n)),\ndot(ones, vec3(\ndot(convY[0], ones),\ndot(convY[1], ones),\ndot(convY[2], ones)\n))\n);\n}\n}\n}\nvec2 computeResponseMap()\n{\nfloat patchArea = float(PATCH_SIZE * PATCH_SIZE);\nvec3 h; vec2 d, c = vec2(0.0f);\nconst vec3 ones = vec3(1.0f);\nfloat response, sum = 0.0f;\nint u, v;\n#define H(r,s) d = derivativesAt((r),(s)); h += vec3(d.x * d.x, d.x * d.y, d.y * d.y)\nfor(int j = 0; j < PATCH_SIZE; j++) {\nfor(int i = 0; i < PATCH_SIZE; i++) {\nu = i - PATCH_RADIUS;\nv = j - PATCH_RADIUS;\nh = vec3(0.0f);\nH(u-1,v-1); H(u+0,v-1); H(u+1,v-1);\nH(u-1,v+0); H(u+0,v+0); H(u+1,v+0);\nH(u-1,v+1); H(u+0,v+1); H(u+1,v+1);\nresponse = 0.5f * (h.x + h.z - sqrt((h.x - h.z) * (h.x - h.z) + 4.0f * h.y * h.y));\nresponse /= patchArea;\nresponseAt(u,v) = response;\nc += vec2(u,v) * response;\nsum += response;\n}\n}\nreturn abs(sum) > EPS ? c / sum : vec2(0.0f);\n}\n#if METHOD == 0\nvec2 quadratic1d()\n{\nfloat a = 0.5f * (responseAt(-1,0) - 2.0f * responseAt(0,0) + responseAt(1,0));\nfloat b = 0.5f * (responseAt(1,0) - responseAt(-1,0));\nfloat c = responseAt(0,0);\nfloat d = 0.5f * (responseAt(0,-1) - 2.0f * responseAt(0,0) + responseAt(0,1));\nfloat e = 0.5f * (responseAt(0,1) - responseAt(0,-1));\nfloat f = responseAt(0,0);\nbool hasMax = a < -EPS && d < -EPS;\nreturn hasMax ? -0.5f * vec2(b / a, e / d) : vec2(0.0f);\n}\n#endif\n#if METHOD == 1\nvec2 taylor2d()\n{\nfloat dx = (-responseAt(-1,0) + responseAt(1,0)) * 0.5f;\nfloat dy = (-responseAt(0,-1) + responseAt(0,1)) * 0.5f;\nfloat dxx = responseAt(-1,0) - 2.0f * responseAt(0,0) + responseAt(1,0);\nfloat dyy = responseAt(0,-1) - 2.0f * responseAt(0,0) + responseAt(0,1);\nfloat dxy = (responseAt(-1,-1) + responseAt(1,1) - responseAt(1,-1) - responseAt(-1,1)) * 0.25f;\nfloat det = dxx * dyy - dxy * dxy;\nmat2 inv = mat2(dyy, -dxy, -dxy, dxx);\nbool hasMax = det > EPS && dxx < 0.0f;\nreturn hasMax ? inv * vec2(dx, dy) / (-det) : vec2(0.0f);\n}\n#endif\n#if METHOD == 2\nvoid bilinearUpsample(ivec2 patchOffset, vec4 pixelsOfPatch)\n{\nint u, v, i, j;\nvec2 frc, ifrc; vec4 sub;\nconst vec4 ones = vec4(1.0f);\nfloat s = 1.0f / float(PATCH_SIZE - 1);\nint xoff = 2 * patchOffset.x;\nint yoff = 2 * patchOffset.y;\nfor(j = 0; j < PATCH_SIZE; j++) {\nfor(i = 0; i < PATCH_SIZE; i++) {\nu = i - PATCH_RADIUS;\nv = j - PATCH_RADIUS;\nfrc = vec2(i, j) * s;\nifrc = vec2(1.0f) - frc;\nsub = vec4(\nifrc.x * ifrc.y,\nfrc.x * ifrc.y,\nifrc.x * frc.y,\nfrc.x * frc.y\n);\npatchPixelAt(u+xoff,v+yoff) = dot(sub*pixelsOfPatch, ones);\n}\n}\n}\n#endif\n#if METHOD == 3\nvoid bicubicUpsample(ivec2 patchOffset, vec4 pixelsOfPatch, vec4 dx, vec4 dy, vec4 dxy)\n{\nfloat x, y, s = 1.0f / float(PATCH_SIZE - 1);\nint u, v, i, j;\nfloat f00 = pixelsOfPatch.x;\nfloat f10 = pixelsOfPatch.y;\nfloat f01 = pixelsOfPatch.z;\nfloat f11 = pixelsOfPatch.w;\nfloat fx00 = dx.x;\nfloat fx10 = dx.y;\nfloat fx01 = dx.z;\nfloat fx11 = dx.w;\nfloat fy00 = dy.x;\nfloat fy10 = dy.y;\nfloat fy01 = dy.z;\nfloat fy11 = dy.w;\nfloat fxy00 = dxy.x;\nfloat fxy10 = dxy.y;\nfloat fxy01 = dxy.z;\nfloat fxy11 = dxy.w;\nmat4 bicubic = mat4(\n1, 0, -3, 2,\n0, 0, 3, -2,\n0, 1, -2, 1,\n0, 0, -1, 1\n) * mat4(\nf00, f10, fx00, fx10,\nf01, f11, fx01, fx11,\nfy00, fy10, fxy00, fxy10,\nfy01, fy11, fxy01, fxy11\n) * mat4(\n1, 0, 0, 0,\n0, 0, 1, 0,\n-3, 3, -2, -1,\n2, -2, 1, 1\n);\nint xoff = 2 * patchOffset.x;\nint yoff = 2 * patchOffset.y;\nfor(j = 0; j < PATCH_SIZE; j++) {\nfor(i = 0; i < PATCH_SIZE; i++) {\nu = i - PATCH_RADIUS;\nv = j - PATCH_RADIUS;\nx = float(i) * s;\ny = float(j) * s;\npatchPixelAt(u+xoff,v+yoff) = dot(\nvec4(1, x, x*x, x*x*x),\nbicubic * vec4(1, y, y*y, y*y*y)\n);\n}\n}\n}\n#endif\n#if METHOD == 2 || METHOD == 3\nvoid upsamplePatch(int left, int top, int right, int bottom)\n{\nint x, y, k;\nvec4 ptch[9];\nvec2 d00, d10, d01, d11;\nfor(k = 0; k < 9; k++) {\nx = -1 + (k % 3);\ny = -1 + (k / 3);\nptch[k] = vec4(\npatchPixelAt(left+x, top+y),\npatchPixelAt(right+x, top+y),\npatchPixelAt(left+x, bottom+y),\npatchPixelAt(right+x, bottom+y)\n);\n}\nfor(k = 0; k < 9; k++) {\nx = -1 + (k % 3);\ny = -1 + (k / 3);\n#if METHOD == 2\nbilinearUpsample(ivec2(x, y), ptch[k]);\n#elif METHOD == 3\nd00 = derivativesAt(left+x, top+y);\nd10 = derivativesAt(right+x, top+y);\nd01 = derivativesAt(left+x, bottom+y);\nd11 = derivativesAt(right+x, bottom+y);\nbicubicUpsample(ivec2(x, y), ptch[k],\nvec4(d00.x, d10.x, d01.x, d11.x),\nvec4(d00.y, d10.y, d01.y, d11.y),\n0.25f * vec4(\n(patchPixelAt(left+x + 1,top+y + 1) + patchPixelAt(left+x - 1, top+y - 1)) - (patchPixelAt(left+x + 1, top+y - 1) + patchPixelAt(left+x - 1, top+y + 1)),\n(patchPixelAt(right+x + 1,top+y + 1) + patchPixelAt(right+x - 1, top+y - 1)) - (patchPixelAt(right+x + 1, top+y - 1) + patchPixelAt(right+x - 1, top+y + 1)),\n(patchPixelAt(left+x + 1,bottom+y + 1) + patchPixelAt(left+x - 1, bottom+y - 1)) - (patchPixelAt(left+x + 1, bottom+y - 1) + patchPixelAt(left+x - 1, bottom+y + 1)),\n(patchPixelAt(right+x + 1,bottom+y + 1) + patchPixelAt(right+x - 1, bottom+y - 1)) - (patchPixelAt(right+x + 1, bottom+y - 1) + patchPixelAt(right+x - 1, bottom+y + 1))\n)\n);\n#endif\n}\n}\nvec2 upsampleResponseMap(int left, int top, int right, int bottom)\n{\nupsamplePatch(left, top, right, bottom);\ncomputeDerivatives();\nreturn computeResponseMap();\n}\nvec2 iterativeUpsample(vec2 initialGuess)\n{\nint refine = 1;\nfloat scale = 0.5f;\nfloat eps2 = epsilon * epsilon;\nvec2 guess = initialGuess, localGuess = initialGuess;\nfor(int k = 0; k < maxIterations; k++) {\nivec4 quad = ivec4(floor(localGuess.x), floor(localGuess.y), ceil(localGuess.x), ceil(localGuess.y));\nvec2 response = (refine != 0) ? upsampleResponseMap(quad.x, quad.y, quad.z, quad.w) : vec2(0.0f);\nlocalGuess = response * scale;\nguess += localGuess;\nscale *= 0.5f;\nrefine *= int(dot(localGuess, localGuess) >= eps2);\n}\nreturn guess;\n}\n#endif\nvoid main()\n{\nivec2 thread = threadLocation();\nint keypointIndex = thread.x + thread.y * outputSize().x;\nint pixelsPerKeypoint = sizeofEncodedKeypoint(descriptorSize, extraSize) / 4;\nKeypointAddress address = KeypointAddress(keypointIndex * pixelsPerKeypoint, 0);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, address);\ncolor = encodeNullPairOfFloat16();\nif(isNullKeypoint(keypoint))\nreturn;\ncolor = encodeDiscardedPairOfFloat16();\nif(isBadKeypoint(keypoint))\nreturn;\nreadPixels(keypoint.position, keypoint.lod);\ncomputeDerivatives();\nvec2 offset = computeResponseMap();\n#if METHOD == 0\noffset = quadratic1d();\n#elif METHOD == 1\noffset = taylor2d();\n#elif METHOD == 2 || METHOD == 3\noffset = iterativeUpsample(offset);\n#else\n#error Unknown METHOD\n#endif\nfloat pot = exp2(keypoint.lod);\ncolor = encodePairOfFloat16(offset * pot);\n}"
  18121. /***/ }),
  18122. /***/ "./src/gpu/shaders/keypoints/transfer-flow.glsl":
  18123. /*!******************************************************!*\
  18124. !*** ./src/gpu/shaders/keypoints/transfer-flow.glsl ***!
  18125. \******************************************************/
  18126. /***/ ((module) => {
  18127. module.exports = "@include \"keypoints.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D encodedFlow;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nint len = textureSize(encodedFlow, 0).x;\nKeypointAddress myAddress = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, myAddress);\nint myIndex = findKeypointIndex(myAddress, descriptorSize, extraSize);\ncolor = pixel;\nif(isBadKeypoint(keypoint))\nreturn;\nivec2 location = ivec2(myIndex % len, myIndex / len);\nvec4 encodedFlow = myIndex < len * len ? pixelAt(encodedFlow, location) : encodeDiscardedKeypoint();\nbool discardFlow = isDiscardedPairOfFloat16(encodedFlow);\nvec2 flow = !discardFlow ? decodePairOfFloat16(encodedFlow) : vec2(0.0f);\nvec4 newPosition = encodeKeypointPosition(keypoint.position + flow);\nvec4 newPixel = myAddress.offset == 0 ? newPosition : pixel;\ncolor = !discardFlow ? newPixel : encodeDiscardedKeypoint();\n}"
  18128. /***/ }),
  18129. /***/ "./src/gpu/shaders/keypoints/transfer-orientation.glsl":
  18130. /*!*************************************************************!*\
  18131. !*** ./src/gpu/shaders/keypoints/transfer-orientation.glsl ***!
  18132. \*************************************************************/
  18133. /***/ ((module) => {
  18134. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedOrientations;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nKeypointAddress myAddress = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint myIndex = findKeypointIndex(myAddress, descriptorSize, extraSize);\nint orientationEncoderLength = textureSize(encodedOrientations, 0).x;\nivec2 location = ivec2(myIndex % orientationEncoderLength, myIndex / orientationEncoderLength);\nvec4 targetPixel = pixelAt(encodedOrientations, location);\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, myAddress);\nbool isValid = !isBadKeypoint(keypoint);\nfloat encodedOrientation = targetPixel.g;\ncolor = isValid && myAddress.offset == 1 ? vec4(pixel.r, encodedOrientation, pixel.ba) : pixel;\n}"
  18135. /***/ }),
  18136. /***/ "./src/gpu/shaders/keypoints/transfer-to-extra.glsl":
  18137. /*!**********************************************************!*\
  18138. !*** ./src/gpu/shaders/keypoints/transfer-to-extra.glsl ***!
  18139. \**********************************************************/
  18140. /***/ ((module) => {
  18141. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedData;\nuniform int strideOfEncodedData;\nuniform sampler2D encodedKeypoints;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\nvec4 readEncodedData(sampler2D encodedData, int strideOfEncodedData, int elementId, int pixelsPerElement, int pixelOffset)\n{\nint rasterIndex = elementId * pixelsPerElement + pixelOffset;\nivec2 pos = ivec2(rasterIndex % strideOfEncodedData, rasterIndex / strideOfEncodedData);\nreturn texelFetch(encodedData, pos, 0);\n}\nvoid main()\n{\nivec2 thread = threadLocation();\nKeypointAddress myAddress = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint myIndex = findKeypointIndex(myAddress, descriptorSize, extraSize);\nint headerSize = sizeofEncodedKeypointHeader();\nint extraCell = myAddress.offset - headerSize / 4;\nint numberOfExtraCells = extraSize / 4;\ncolor = threadPixel(encodedKeypoints);\nif(extraCell < 0 || extraCell >= numberOfExtraCells)\nreturn;\nKeypoint keypoint = decodeKeypoint(encodedKeypoints, encoderLength, myAddress);\nif(isBadKeypoint(keypoint))\nreturn;\ncolor = readEncodedData(encodedData, strideOfEncodedData, myIndex, numberOfExtraCells, extraCell);\n}"
  18142. /***/ }),
  18143. /***/ "./src/gpu/shaders/keypoints/upload-keypoints.glsl":
  18144. /*!*********************************************************!*\
  18145. !*** ./src/gpu/shaders/keypoints/upload-keypoints.glsl ***!
  18146. \*********************************************************/
  18147. /***/ ((module) => {
  18148. module.exports = "@include \"keypoints.glsl\"\nuniform sampler2D encodedKeypoints;\nuniform int startIndex;\nuniform int endIndex;\nuniform int descriptorSize;\nuniform int extraSize;\nuniform int encoderLength;\n#ifndef BUFFER_SIZE\n#error Undefined BUFFER_SIZE\n#endif\nlayout(std140) uniform KeypointBuffer\n{\nvec4 keypointBuffer[BUFFER_SIZE];\n};\nvoid main()\n{\nvec4 pixel = threadPixel(encodedKeypoints);\nivec2 thread = threadLocation();\nKeypointAddress address = findKeypointAddress(thread, encoderLength, descriptorSize, extraSize);\nint index = findKeypointIndex(address, descriptorSize, extraSize);\ncolor = pixel;\nif(index < startIndex)\nreturn;\ncolor = encodeNullKeypoint();\nif(index >= endIndex)\nreturn;\nvec4 data = keypointBuffer[index - startIndex];\nswitch(address.offset) {\ncase 0: {\ncolor = encodeKeypointPosition(data.xy);\nbreak;\n}\ncase 1: {\nvec2 score = encodeKeypointScore(max(data.w, 0.0f));\nfloat scale = encodeLod(data.z);\nfloat rotation = encodeKeypointOrientation(0.0f);\ncolor = vec4(scale, rotation, score);\nbreak;\n}\ndefault: {\ncolor = vec4(0.0f);\nbreak;\n}\n}\n}"
  18149. /***/ }),
  18150. /***/ "./src/gpu/shaders/pyramids/downsample2.glsl":
  18151. /*!***************************************************!*\
  18152. !*** ./src/gpu/shaders/pyramids/downsample2.glsl ***!
  18153. \***************************************************/
  18154. /***/ ((module) => {
  18155. module.exports = "uniform sampler2D image;\nvoid main()\n{\n#if 1\ncolor = texture(image, texCoord);\n#else\nivec2 thread = threadLocation();\nivec2 pos = min(thread * 2, textureSize(image, 0) - ivec2(1));\ncolor = pixelAt(image, pos);\n#endif\n}"
  18156. /***/ }),
  18157. /***/ "./src/gpu/shaders/pyramids/upsample2.glsl":
  18158. /*!*************************************************!*\
  18159. !*** ./src/gpu/shaders/pyramids/upsample2.glsl ***!
  18160. \*************************************************/
  18161. /***/ ((module) => {
  18162. module.exports = "uniform sampler2D image;\nvoid main()\n{\nivec2 thread = threadLocation();\nvec4 pixel = pixelAt(image, thread / 2);\ncolor = (((thread.x + thread.y) & 1) == 0) ? pixel : vec4(0.0f, 0.0f, 0.0f, pixel.a);\n}"
  18163. /***/ }),
  18164. /***/ "./src/gpu/shaders/transforms/additive-mix.glsl":
  18165. /*!******************************************************!*\
  18166. !*** ./src/gpu/shaders/transforms/additive-mix.glsl ***!
  18167. \******************************************************/
  18168. /***/ ((module) => {
  18169. module.exports = "@include \"subpixel.glsl\"\nuniform sampler2D image0;\nuniform sampler2D image1;\nuniform float alpha;\nuniform float beta;\nuniform float gamma;\nconst vec4 BACKGROUND = vec4(0.0f);\nvoid main()\n{\nivec2 location = threadLocation();\nivec2 size0 = textureSize(image0, 0);\nivec2 size1 = textureSize(image1, 0);\nvec4 pix0 = all(lessThan(location, size0)) ? pixelAt(image0, location) : BACKGROUND;\nvec4 pix1 = all(lessThan(location, size1)) ? pixelAt(image1, location) : BACKGROUND;\nvec4 pix = clamp(alpha * pix0 + beta * pix1 + vec4(gamma), 0.0f, 1.0f);\ncolor = vec4(pix.rgb, 1.0f);\n}"
  18170. /***/ }),
  18171. /***/ "./src/gpu/shaders/transforms/resize.glsl":
  18172. /*!************************************************!*\
  18173. !*** ./src/gpu/shaders/transforms/resize.glsl ***!
  18174. \************************************************/
  18175. /***/ ((module) => {
  18176. module.exports = "@include \"subpixel.glsl\"\nuniform sampler2D image;\nvoid main()\n{\nvec2 imageSize = vec2(textureSize(image, 0));\n#if !defined(INTERPOLATION_METHOD)\n#error Must define INTERPOLATION_METHOD\n#elif INTERPOLATION_METHOD == 0\nvec2 pos = texCoord * imageSize;\ncolor = textureLod(image, (round(pos) + vec2(0.5f)) / imageSize, 0.0f);\n#elif INTERPOLATION_METHOD == 1\ncolor = subpixelAtBI(image, texCoord * imageSize);\n#else\n#error Invalid INTERPOLATION_METHOD\n#endif\n}"
  18177. /***/ }),
  18178. /***/ "./src/gpu/shaders/transforms/warp-perspective.glsl":
  18179. /*!**********************************************************!*\
  18180. !*** ./src/gpu/shaders/transforms/warp-perspective.glsl ***!
  18181. \**********************************************************/
  18182. /***/ ((module) => {
  18183. module.exports = "@include \"subpixel.glsl\"\nuniform sampler2D image;\nuniform mat3 inverseHomography;\nconst vec4 emptyColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);\nvec2 perspectiveWarp(mat3 homography, vec2 p)\n{\nvec3 q = homography * vec3(p, 1.0f);\nreturn q.xy / q.z;\n}\nvoid main()\n{\nivec2 location = threadLocation();\nivec2 size = outputSize();\nconst vec2 zero = vec2(0.0f);\nvec2 target = perspectiveWarp(inverseHomography, vec2(location));\nbool withinBounds = all(bvec4(greaterThanEqual(target, zero), lessThan(target, vec2(size))));\ncolor = withinBounds ? subpixelAtBI(image, target) : emptyColor;\n}"
  18184. /***/ }),
  18185. /***/ "./src/gpu/shaders/utils/copy-components.glsl":
  18186. /*!****************************************************!*\
  18187. !*** ./src/gpu/shaders/utils/copy-components.glsl ***!
  18188. \****************************************************/
  18189. /***/ ((module) => {
  18190. module.exports = "@include \"colors.glsl\"\nuniform sampler2D dest, src;\nuniform int destComponents;\nuniform int srcComponentId;\nvoid main()\n{\nvec4 destPixel = threadPixel(dest);\nvec4 srcPixel = threadPixel(src);\nbvec4 flags = bvec4(\n(destComponents & PIXELCOMPONENT_RED) != 0,\n(destComponents & PIXELCOMPONENT_GREEN) != 0,\n(destComponents & PIXELCOMPONENT_BLUE) != 0,\n(destComponents & PIXELCOMPONENT_ALPHA) != 0\n);\ncolor = mix(destPixel, vec4(srcPixel[srcComponentId]), flags);\n}"
  18191. /***/ }),
  18192. /***/ "./src/gpu/shaders/utils/copy-raster.glsl":
  18193. /*!************************************************!*\
  18194. !*** ./src/gpu/shaders/utils/copy-raster.glsl ***!
  18195. \************************************************/
  18196. /***/ ((module) => {
  18197. module.exports = "#if !defined(TYPE)\n#error Undefined TYPE\n#elif TYPE == 1\n@include \"keypoints.glsl\"\n#define nullPixel() encodeNullKeypoint()\n#elif TYPE == 2\n@include \"float16.glsl\"\n#define nullPixel() encodeNullPairOfFloat16()\n#else\n#error Invalid TYPE\n#endif\nuniform sampler2D image;\nvoid main()\n{\nivec2 thread = threadLocation();\nivec2 imageSize = textureSize(image, 0);\nint rasterIndex = thread.y * outputSize().x + thread.x;\nbool isValidPixel = rasterIndex < imageSize.x * imageSize.y;\nivec2 pos = ivec2(rasterIndex % imageSize.x, rasterIndex / imageSize.x);\nvec4 nullpix = nullPixel();\ncolor = isValidPixel ? texelFetch(image, pos, 0) : nullpix;\n}"
  18198. /***/ }),
  18199. /***/ "./src/gpu/shaders/utils/copy.glsl":
  18200. /*!*****************************************!*\
  18201. !*** ./src/gpu/shaders/utils/copy.glsl ***!
  18202. \*****************************************/
  18203. /***/ ((module) => {
  18204. module.exports = "uniform sampler2D image;\nvoid main()\n{\ncolor = threadPixel(image);\n}"
  18205. /***/ }),
  18206. /***/ "./src/gpu/shaders/utils/fill-components.glsl":
  18207. /*!****************************************************!*\
  18208. !*** ./src/gpu/shaders/utils/fill-components.glsl ***!
  18209. \****************************************************/
  18210. /***/ ((module) => {
  18211. module.exports = "@include \"colors.glsl\"\nuniform sampler2D image;\nuniform int pixelComponents;\nuniform float value;\nvoid main()\n{\nvec4 pixel = threadPixel(image);\nbvec4 flags = bvec4(\n(pixelComponents & PIXELCOMPONENT_RED) != 0,\n(pixelComponents & PIXELCOMPONENT_GREEN) != 0,\n(pixelComponents & PIXELCOMPONENT_BLUE) != 0,\n(pixelComponents & PIXELCOMPONENT_ALPHA) != 0\n);\ncolor = mix(pixel, vec4(value), flags);\n}"
  18212. /***/ }),
  18213. /***/ "./src/gpu/shaders/utils/fill.glsl":
  18214. /*!*****************************************!*\
  18215. !*** ./src/gpu/shaders/utils/fill.glsl ***!
  18216. \*****************************************/
  18217. /***/ ((module) => {
  18218. module.exports = "uniform float value;\nvoid main()\n{\ncolor = vec4(value);\n}"
  18219. /***/ }),
  18220. /***/ "./src/gpu/shaders/utils/flip-y.vs.glsl":
  18221. /*!**********************************************!*\
  18222. !*** ./src/gpu/shaders/utils/flip-y.vs.glsl ***!
  18223. \**********************************************/
  18224. /***/ ((module) => {
  18225. module.exports = "void vsmain()\n{\ngl_Position *= vec4(1,-1,1,1);\n}"
  18226. /***/ }),
  18227. /***/ "./src/gpu/shaders/utils/scan-minmax2d.glsl":
  18228. /*!**************************************************!*\
  18229. !*** ./src/gpu/shaders/utils/scan-minmax2d.glsl ***!
  18230. \**************************************************/
  18231. /***/ ((module) => {
  18232. module.exports = "uniform sampler2D image;\nuniform int iterationNumber;\nvoid main()\n{\nivec2 thread = threadLocation();\nivec2 last = outputSize() - ivec2(1);\nint jump = (1 << iterationNumber);\nint clusterLength = jump << 1;\nint clusterMask = clusterLength - 1;\nivec2 clusterPos = ivec2(thread >> (1 + iterationNumber)) << (1 + iterationNumber);\nivec2 next1 = clusterPos + ((thread - clusterPos + ivec2(jump, 0)) & clusterMask);\nivec2 next2 = clusterPos + ((thread - clusterPos + ivec2(0, jump)) & clusterMask);\nivec2 next3 = clusterPos + ((thread - clusterPos + ivec2(jump, jump)) & clusterMask);\nvec4 p0 = texelFetch(image, thread, 0);\nvec4 p1 = texelFetch(image, min(next1, last), 0);\nvec4 p2 = texelFetch(image, min(next2, last), 0);\nvec4 p3 = texelFetch(image, min(next3, last), 0);\nvec4 pmax = max(max(p0, p1), max(p2, p3));\nvec4 pmin = min(min(p0, p1), min(p2, p3));\ncolor = vec4(pmax.r, pmin.g, pmax.r - pmin.g, p0.a);\n}"
  18233. /***/ }),
  18234. /***/ "./src/gpu/shaders/utils/sobel-derivatives.glsl":
  18235. /*!******************************************************!*\
  18236. !*** ./src/gpu/shaders/utils/sobel-derivatives.glsl ***!
  18237. \******************************************************/
  18238. /***/ ((module) => {
  18239. module.exports = "@include \"pyramids.glsl\"\n@include \"float16.glsl\"\nuniform sampler2D pyramid;\nuniform float lod;\n#define USE_VARYINGS 1\nin vec2 v_pix0, v_pix1, v_pix2,\nv_pix3, v_pix4, v_pix5,\nv_pix6, v_pix7, v_pix8;\nconst mat3 hkern = mat3(\n1.0f, 0.0f,-1.0f,\n2.0f, 0.0f,-2.0f,\n1.0f, 0.0f,-1.0f\n), vkern = mat3(\n1.0f, 2.0f, 1.0f,\n0.0f, 0.0f, 0.0f,\n-1.0f,-2.0f,-1.0f\n);\n#define PIX(x,y) pyrPixelAtOffset(pyramid, lod, pot, ivec2((x),(y))).g\n#define XIP(v) textureLod(pyramid, (v), lod).g\nvoid main()\n{\nconst vec3 ones = vec3(1.0f);\nfloat pot = exp2(lod);\nmat3 win = mat3(\n#if USE_VARYINGS\nXIP(v_pix0), XIP(v_pix1), XIP(v_pix2),\nXIP(v_pix3), XIP(v_pix4), XIP(v_pix5),\nXIP(v_pix6), XIP(v_pix7), XIP(v_pix8)\n#else\nPIX(-1,-1), PIX(0,-1), PIX(1,-1),\nPIX(-1,0), PIX(0,0), PIX(1,0),\nPIX(-1,1), PIX(0,1), PIX(1,1)\n#endif\n);\nmat3 dx = matrixCompMult(hkern, win);\nmat3 dy = matrixCompMult(vkern, win);\nvec2 df = vec2(\ndot(dx[0] + dx[1] + dx[2], ones),\ndot(dy[0] + dy[1] + dy[2], ones)\n);\ncolor = encodePairOfFloat16(df);\n}"
  18240. /***/ }),
  18241. /***/ "./src/gpu/shaders/utils/sobel-derivatives.vs.glsl":
  18242. /*!*********************************************************!*\
  18243. !*** ./src/gpu/shaders/utils/sobel-derivatives.vs.glsl ***!
  18244. \*********************************************************/
  18245. /***/ ((module) => {
  18246. module.exports = "uniform mediump float lod;\nout vec2 v_pix0, v_pix1, v_pix2,\nv_pix3, v_pix4, v_pix5,\nv_pix6, v_pix7, v_pix8;\n#define PIX(x,y) (texCoord + ((pot) * vec2((x),(y))) / texSize)\nvoid vsmain()\n{\nfloat pot = exp2(lod);\nv_pix0 = PIX(-1,-1); v_pix1 = PIX(0,-1); v_pix2 = PIX(1,-1);\nv_pix3 = PIX(-1,0); v_pix4 = PIX(0,0); v_pix5 = PIX(1,0);\nv_pix6 = PIX(-1,1); v_pix7 = PIX(0,1); v_pix8 = PIX(1,1);\n}"
  18247. /***/ }),
  18248. /***/ "./src/core/wasm/speedy-matrix.wasm.txt":
  18249. /*!**********************************************!*\
  18250. !*** ./src/core/wasm/speedy-matrix.wasm.txt ***!
  18251. \**********************************************/
  18252. /***/ ((module) => {
  18253. module.exports = `AGFzbQEAAAABiwETYAABfmADf39/AX9gAX8AYAN/f38AYAF9AX9gAX8Bf2ACf38Bf2AFf39/f38B
  18254. f2AFf39/f38AYAZ/f39/f38Bf2AAAX9gAn99AX9gA39/fQF/YAJ/fwF9YAF/AX1gBH9/f38AYAR/
  18255. f39/AX9gEX98fHx8fHx8fHx8fHx8fHx8AGAHf39/f39/fQF/AjsEA2VudgZtZW1vcnkCAAIDZW52
  18256. BWZhdGFsAAIDZW52CGJ5dGVmaWxsAAMDZW52CmNvcHlXaXRoaW4AAwNAPwQFBgIGAQECBwgGAwAJ
  18257. AgYCBgYKBQUFCQsFBgEBDAEBBgYGAQEMAQ0OAwgPAxAIAwYBEQEBAQEBARIBEgEBDwQFAXABBQUG
  18258. CAF/AUHwmgQLB/QDHAZtYWxsb2MABARmcmVlAAYFc3JhbmQACgxNYXQzMl9jcmVhdGUAEA1NYXQz
  18259. Ml9kZXN0cm95ABcKTWF0MzJfZGF0YQAYDk1hdDMyX2RhdGFTaXplABkPTWF0MzJfdHJhbnNwb3Nl
  18260. AB0JTWF0MzJfYWRkAB4OTWF0MzJfc3VidHJhY3QAHwtNYXQzMl9zY2FsZQAgDk1hdDMyX2NvbXBt
  18261. dWx0ACEOTWF0MzJfbXVsdGlwbHkAIg5NYXQzMl9pbnZlcnNlMQAjDk1hdDMyX2ludmVyc2UyACQO
  18262. TWF0MzJfaW52ZXJzZTMAJQ1NYXQzMl9xcl9mdWxsACwQTWF0MzJfcXJfcmVkdWNlZAAvDE1hdDMy
  18263. X3FyX29scwAwEE1hdDMyX3FyX2ludmVyc2UAMxZNYXQzMl9ob21vZ3JhcGh5X25kbHQ0ADcVTWF0
  18264. MzJfaG9tb2dyYXBoeV9uZGx0ADgUTWF0MzJfYWZmaW5lX2RpcmVjdDMAOhNNYXQzMl9hZmZpbmVf
  18265. ZGlyZWN0ADsYTWF0MzJfcHJhbnNhY19ob21vZ3JhcGh5ADwUTWF0MzJfcHJhbnNhY19hZmZpbmUA
  18266. PhtNYXQzMl90cmFuc2Zvcm1fcGVyc3BlY3RpdmUAPxZNYXQzMl90cmFuc2Zvcm1fYWZmaW5lAEAJ
  18267. CgEAQQELBA8REz0Kh7oBPyMBAX8gALwiAUGAgID8B3FBgICA/AdGIAFB////A3FBAEdxC2kBAX9B
  18268. AEEAKALAmoCAAEEBajYCwJqAgABBAEEAKAK0moCAACIBQQdxIAFqIgEgAGo2ArSagIAAAkBB8JqE
  18269. gABBB3EgAWpB8JqEgABqIgA/AEEQdEkNAEGEiICAABCAgICAAEEADwsgAAt1AQJ/QQAhAkEAQQAo
  18270. AsCagIAAQQFqNgLAmoCAAEEAQQAoArSagIAAIgNBB3EgA2oiAyAAajYCtJqAgAACQAJAQfCahIAA
  18271. QQdxIANqQfCahIAAaiIAPwBBEHRJDQAgAUUNASABEICAgIAAQQAPCyAAIQILIAILRgECf0EAQQAo
  18272. AsCagIAAIgFBf2oiAjYCwJqAgAACQCACDQBBAEEINgK0moCAAA8LAkAgAUEASg0AQZOIgIAAEICA
  18273. gIAACwtGAQJ/QQBBACgCwJqAgAAiAkF/aiIDNgLAmoCAAAJAIAMNAEEAQQg2ArSagIAAQQAPCwJA
  18274. IAJBAEoNACABEICAgIAAC0EACxcAIAFB/wFxIAAgACACahCBgICAACAACxMAIAAgASABIAJqEIKA
  18275. gIAAIAALoQECAX8CfkEAKAK4moCAACIBIACtQiCGIABBf3OthCICQqrw0/Sv7ry3PHwiA0IeiCAD
  18276. hUK5y5Pn0e2RrL9/fiIDQhuIIAOFQuujxJmxt5LolH9+IgNCH4ggA4U3AwggASACQpX4qfqXt96b
  18277. nn98IgJCHoggAoVCucuT59Htkay/f34iAkIbiCAChULro8SZsbeS6JR/fiICQh+IIAKFNwMAC0QB
  18278. AX9B3oG33QAhBQJAIAJFDQAgAEUNACADRQ0AQQAhBSABQQJJDQAgACAAIAFBf2ogAmxqIAIgAyAE
  18279. EIyAgIAACyAFC60GAwR/AXwFfwJAAkAgASAASw0AIAEhBSAAIQYMAQtBACACayEHIAJBBEshCANA
  18280. IAEiBSAAIgZrIAJuIgFBCEkNAQJAAkBBACgCvJqAgAARgICAgAAAQgyIQoCAgICAgID4P4S/RAAA
  18281. AAAAAPC/oCABQQFquKIiCUQAAAAAAADwQWMgCUQAAAAAAAAAAGZxRQ0AIAmrIQEMAQtBACEBCyAG
  18282. IAEgAmxqIQogBSEBIAYhCwNAAkAgCyAKIAQgAxGBgICAAABBf0oNAANAIAsgAmoiCyAKIAQgAxGB
  18283. gICAAABBAEgNAAsLAkAgASAKIAQgAxGBgICAAABBAUgNAANAIAEgB2oiASAKIAQgAxGBgICAAABB
  18284. AEoNAAsLAkAgCyABTw0AIAEhACALIQwgAiENAkACQCAIDQACQAJAIAIOBQMBAQEAAwsgCygCACEA
  18285. IAsgASgCADYCACABIAA2AgAMAgsgASEAIAshDCACIQ0LA0AgDC0AACEOIAwgAC0AADoAACAAIA46
  18286. AAAgAEEBaiEAIAxBAWohDCANQX9qIg0NAAsLIAEgCyAKIAogAUYbIAogC0YbIQogASAHaiEBIAsg
  18287. AmohCwwBCwsgCyACaiALIAsgAUYiABshDAJAAkAgASAHaiABIAAbIgEgBk0NACAMIAVPDQACQCAB
  18288. IAZrIAUgDGtNDQAgDCAFIAIgAyAEEIyAgIAAIAYhAAwCCyAGIAEgAiADIAQQjICAgAAgBSEBIAwh
  18289. AAwBCyAGIAwgASAGSyIKGyEAIAEgBSAKGyEBIAoNACAMIAVPDQILIAEhBSAAIQYgASAASw0ACwsC
  18290. QCAGIAVPDQAgAkEESyEHA0AgBiINIAJqIgYhASANIQACQCAGIAVLDQADQCABIAAgASAAIAQgAxGB
  18291. gICAAABBAEgbIQAgASACaiIBIAVNDQALIAAgDUYNAAJAIAcNAAJAIAIOBQIBAQEAAgsgACgCACEB
  18292. IAAgDSgCADYCACANIAE2AgAMAQtBACEBA0AgACABaiIMLQAAIQogDCANIAFqIgstAAA6AAAgCyAK
  18293. OgAAIAIgAUEBaiIBRw0ACwsgBiAFSQ0ACwsLNQECfwJAIAFBAUgNAEEAIQIgACEDA0AgAyACNgIA
  18294. IANBBGohAyABIAJBAWoiAkcNAAsLIAALvgIFAn8BfAF/AXwEfwJAIAFBf2oiA0UNACACQQRLIQRE
  18295. AAAAAAAAAAAhBUEAIQYDQAJAAkBBACgCvJqAgAARgICAgAAAQgyIQoCAgICAgID4P4S/RAAAAAAA
  18296. APC/oCABIAZruKIgBaAiB0QAAAAAAADwQWMgB0QAAAAAAAAAAGZxRQ0AIAerIQgMAQtBACEICwJA
  18297. IAYgCEYNAAJAIAQNAAJAIAIOBQIBAQEAAgsgACAGQQJ0aiIJKAIAIQogCSAAIAhBAnRqIggoAgA2
  18298. AgAgCCAKNgIADAELIAAgBiACbGohCSAAIAggAmxqIQggAiEKA0AgCS0AACELIAkgCC0AADoAACAI
  18299. IAs6AAAgCEEBaiEIIAlBAWohCSAKQX9qIgoNAAsLIAVEAAAAAAAA8D+gIQUgBkEBaiIGIANHDQAL
  18300. CwtFAQN+QQBBACkD2JqAgAAiAEEAKQPQmoCAACIBhSICQiWJNwPYmoCAAEEAIAFCGIkgAoUgAkIQ
  18301. hoU3A9CagIAAIAAgAXwLlAEBAX8CQAJAIAMgAkgNACAAQQFIDQAgAUEBSA0AIAJBAUgNACAAQX9q
  18302. IAJsIAFBf2ogA2xqQQFqIARHDQAgBQ0BC0GfiICAABCAgICAAAtBHEG+iICAABCFgICAACIGIAM2
  18303. AhQgBiACNgIQIAYgATYCDCAGIAA2AgggBiAENgIEIAZBgoCAgAA2AhggBiAFNgIAIAYLAgALkwEB
  18304. BH8CQAJAIABBAUgNACABQQBKDQELQdqIgIAAEICAgIAAC0EcQfmIgIAAEIWAgIAAIQIgASAAbCID
  18305. QQJ0IgRBlYmAgAAQhYCAgAAhBSACIAA2AhQgAkEBNgIQIAIgATYCDCACIAA2AgggAiADNgIEIAVB
  18306. ACAEEIiAgIAAIQAgAkGDgICAADYCGCACIAA2AgAgAgsRACAAQeeKgIAAEIeAgIAAGgv0AQEEfwJA
  18307. AkAgAEEBSA0AIAFBAEoNAQtB2oiAgAAQgICAgAALQRxB+YiAgAAQhYCAgAAhAiABIABsIgNBAnQi
  18308. BEGViYCAABCFgICAACEFIAIgADYCFCACQQE2AhAgAiABNgIMIAIgADYCCCACIAM2AgQgBUEAIAQQ
  18309. iICAgAAhAyACQYOAgIAANgIYIAIgAzYCAAJAIAAgASAAIAFIGyIBQQFIDQAgAyACKAIUIAIoAhBq
  18310. IgQgAUF/amxBAnRqIQAgAUEBaiEBQQAgBEECdGshAwNAIABBgICA/AM2AgAgACADaiEAIAFBf2oi
  18311. AUEBSg0ACwsgAguYAgEKfwJAAkAgACgCCCABKAIIRw0AIAAoAgwgASgCDEYNAQtBx4qAgAAQgICA
  18312. gAALAkACQCAAKAIEIgIgASgCBEYNACAAKAIMIgNBAUgNAUEAIQQgACgCCCIFQQFIIQZBACEHA0AC
  18313. QCAGDQAgACgCEEECdCEIIAEoAhBBAnQhCSAAKAIAIAAoAhQgBGxqIQIgASgCACABKAIUIARsaiEK
  18314. QQAhCwNAIAIgCigCADYCACACIAhqIQIgCiAJaiEKIAtBAWoiCyAFSA0ACwsgBEEEaiEEIAdBAWoi
  18315. ByADSA0ADAILCwJAIAEoAgAiCiAAKAIAIgsgAkECdCICak8NACAKIAJqIAtLDQELIAsgCiACEImA
  18316. gIAAGgsgAAtVAQF/QRxBsYmAgAAQhYCAgAAiAEEYakEAKALoiYCAADYCACAAQRBqQQApAuCJgIAA
  18317. NwIAIABBCGpBACkC2ImAgAA3AgAgAEEAKQLQiYCAADcCACAACyEAIAAoAgAgACgCGBGCgICAAAAg
  18318. AEHsiYCAABCHgICAAAsHACAAKAIACwoAIAAoAgRBAnQL0AEBAn8CQCAAKAIYQYKAgIAARg0AQYeK
  18319. gIAAEICAgIAACwJAAkAgAyACSA0AIAJBAEgNACAFIARIDQAgBEEASA0AIAEoAgggA0wNACABKAIM
  18320. IAVKDQELQaeKgIAAEICAgIAACyABKAIQIQYgAEEUaiABQRRqKAIAIgc2AgAgACAGNgIQIAAgBSAE
  18321. a0EBajYCDCAAIAMgAmtBAWo2AgggACAGIANsIAcgBWxqIAcgBGwgBiACbGoiAmtBAWo2AgQgACAB
  18322. KAIAIAJBAnRqNgIAIAALgQEBCH8CQCAAKAIMIgJBAUgNAEEAIQMgACgCCCIEQQFIIQVBACEGA0AC
  18323. QCAFDQAgACgCEEECdCEHIAAoAgAgACgCFCADbGohCEEAIQkDQCAIIAE4AgAgCCAHaiEIIAlBAWoi
  18324. CSAESA0ACwsgA0EEaiEDIAZBAWoiBiACSA0ACwsgAAumAQEIfwJAIAAoAgwiASAAKAIIIgJsIgMg
  18325. ACgCBEcNACAAKAIAQQAgA0ECdBCIgICAABogAA8LAkAgAUEBSA0AIAJBAUghBEEAIQVBACEGA0AC
  18326. QCAEDQAgACgCEEECdCEHIAAoAgAgACgCFCAFbGohAyACIQgDQCADQQA2AgAgAyAHaiEDIAhBf2oi
  18327. CA0ACwsgBUEEaiEFIAZBAWoiBiABRw0ACwsgAAvcAQEKfwJAAkAgACgCCCABKAIMRw0AIAAoAgwi
  18328. AiABKAIIRg0BC0GBi4CAABCAgICAACAAKAIMIQILAkAgAkEBSA0AIAAoAgwhA0EAIQQgACgCCCIF
  18329. QQFIIQZBACEHA0ACQCAGDQAgACgCEEECdCEIIAEoAhRBAnQhCSAAKAIAIAAoAhQgBGxqIQIgASgC
  18330. ACABKAIQIARsaiEKQQAhCwNAIAIgCigCADYCACACIAhqIQIgCiAJaiEKIAtBAWoiCyAFSA0ACwsg
  18331. BEEEaiEEIAdBAWoiByADSA0ACwsgAAuZAgEMfwJAAkAgASgCCCIDIAIoAghHDQAgASgCDCIEIAIo
  18332. AgxHDQAgACgCCCADRw0AIAAoAgwgBEYNAQtBp4uAgAAQgICAgAAgACgCDCEECwJAIARBAUgNACAA
  18333. KAIMIQVBACEGIAAoAggiB0EBSCEIQQAhCQNAAkAgCA0AIAAoAhBBAnQhCiACKAIQQQJ0IQsgASgC
  18334. EEECdCEMIAAoAgAgACgCFCAGbGohBCACKAIAIAIoAhQgBmxqIQMgASgCACABKAIUIAZsaiENQQAh
  18335. DgNAIAQgDSoCACADKgIAkjgCACAEIApqIQQgAyALaiEDIA0gDGohDSAOQQFqIg4gB0gNAAsLIAZB
  18336. BGohBiAJQQFqIgkgBUgNAAsLIAALmQIBDH8CQAJAIAEoAggiAyACKAIIRw0AIAEoAgwiBCACKAIM
  18337. Rw0AIAAoAgggA0cNACAAKAIMIARGDQELQc2LgIAAEICAgIAAIAAoAgwhBAsCQCAEQQFIDQAgACgC
  18338. DCEFQQAhBiAAKAIIIgdBAUghCEEAIQkDQAJAIAgNACAAKAIQQQJ0IQogAigCEEECdCELIAEoAhBB
  18339. AnQhDCAAKAIAIAAoAhQgBmxqIQQgAigCACACKAIUIAZsaiEDIAEoAgAgASgCFCAGbGohDUEAIQ4D
  18340. QCAEIA0qAgAgAyoCAJM4AgAgBCAKaiEEIAMgC2ohAyANIAxqIQ0gDkEBaiIOIAdIDQALCyAGQQRq
  18341. IQYgCUEBaiIJIAVIDQALCyAAC98BAQp/AkACQCAAKAIIIAEoAghHDQAgACgCDCIDIAEoAgxGDQEL
  18342. QfOLgIAAEICAgIAAIAAoAgwhAwsCQCADQQFIDQAgACgCDCEEQQAhBSAAKAIIIgZBAUghB0EAIQgD
  18343. QAJAIAcNACAAKAIQQQJ0IQkgASgCEEECdCEKIAAoAgAgACgCFCAFbGohAyABKAIAIAEoAhQgBWxq
  18344. IQtBACEMA0AgAyALKgIAIAKUOAIAIAMgCWohAyALIApqIQsgDEEBaiIMIAZIDQALCyAFQQRqIQUg
  18345. CEEBaiIIIARIDQALCyAAC5kCAQx/AkACQCABKAIIIgMgAigCCEcNACABKAIMIgQgAigCDEcNACAA
  18346. KAIIIANHDQAgACgCDCAERg0BC0GZjICAABCAgICAACAAKAIMIQQLAkAgBEEBSA0AIAAoAgwhBUEA
  18347. IQYgACgCCCIHQQFIIQhBACEJA0ACQCAIDQAgACgCEEECdCEKIAIoAhBBAnQhCyABKAIQQQJ0IQwg
  18348. ACgCACAAKAIUIAZsaiEEIAIoAgAgAigCFCAGbGohAyABKAIAIAEoAhQgBmxqIQ1BACEOA0AgBCAN
  18349. KgIAIAMqAgCUOAIAIAQgCmohBCADIAtqIQMgDSAMaiENIA5BAWoiDiAHSA0ACwsgBkEEaiEGIAlB
  18350. AWoiCSAFSA0ACwsgAAvOAgMLfwF9BX8CQAJAIAEoAgwgAigCCEcNACAAKAIIIAEoAghHDQAgACgC
  18351. DCACKAIMRg0BC0HAjICAABCAgICAAAsgABCcgICAABoCQCAAKAIMIgNBAUgNAEEAIQQgAigCCCIF
  18352. QQFIIQZBACEHA0ACQCAGDQAgAigCFCAHbCEIIAAoAgghCSACKAIQIQogAigCACELQQAhDEEAIQ0D
  18353. QAJAIAlBAUgNACALIAggCiANbGpBAnRqKgIAIQ4gACgCEEECdCEPIAEoAhBBAnQhECAAKAIAIAQg
  18354. ACgCFGxqIREgASgCACABKAIUIAxsaiESQQAhEwNAIBEgDiASKgIAlCARKgIAkjgCACARIA9qIREg
  18355. EiAQaiESIBNBAWoiEyAJSA0ACwsgDEEEaiEMIA1BAWoiDSAFSA0ACwsgBEEEaiEEIAdBAWoiByAD
  18356. SA0ACwsgAAuIAQICfwF9AkACQCAAKAIIIgIgASgCCEcNACACQQFHDQAgAiAAKAIMIgNHDQAgAyAB
  18357. KAIMRg0BC0HnjICAABCAgICAAAsCQAJAIAEoAgAqAgAiBIu7RI3ttaD3xrA+Y0EBcw0AQQAqAoCI
  18358. gIAAIQQMAQtDAACAPyAElSEECyAAKAIAIAQ4AgAgAAuNAgICfwV9AkACQCAAKAIIIgIgASgCCEcN
  18359. ACACQQJHDQAgAiAAKAIMIgNHDQAgAyABKAIMRg0BC0GOjYCAABCAgICAAAsCQAJAIAEoAgAiAioC
  18360. ACIEIAIgAUEUaigCACIDIAEoAhAiAWpBAnRqKgIAIgWUIAIgAUECdGoqAgAiBiACIANBAnRqKgIA
  18361. IgeUkyIIi7tEje21oPfGsD5jQQFzDQBBACoCgIiAgAAhCAwBC0MAAIA/IAiVIQgLIAAoAgAiASAF
  18362. IAiUOAIAIAEgACgCECICQQJ0aiAIIAaMlDgCACABIABBFGooAgAiA0ECdGogCCAHjJQ4AgAgASAD
  18363. IAJqQQJ0aiAEIAiUOAIAIAALnAQGAn8CfQF/BX0BfwZ9AkACQCAAKAIIIgIgASgCCEcNACACQQNH
  18364. DQAgAiAAKAIMIgNHDQAgAyABKAIMRg0BC0G1jYCAABCAgICAAAsCQAJAIAEoAgAiAiABKAIQIgNB
  18365. A3RqKgIAIgQgAiABQRRqKAIAIgFBAnRqKgIAIgUgAiABQQF0IgYgA2pBAnRqKgIAIgeUIAIgASAD
  18366. akECdGoqAgAiCCACIAFBA3RqKgIAIgmUkyIKlCACKgIAIgsgCCACIAYgA0EBdCIMakECdGoqAgAi
  18367. DZQgAiAMIAFqQQJ0aioCACIOIAeUkyIPlCACIANBAnRqKgIAIhAgBSANlCAOIAmUkyIRlJOSIhKL
  18368. u0SN7bWg98awPmNBAXMNAEEAKgKAiICAACESDAELQwAAgD8gEpUhEgsgACgCACICIA8gEpQ4AgAg
  18369. AiAAKAIQIgFBAnRqIBIgECANlCAEIAeUk4yUOAIAIAIgAUEDdGogECAOlCAEIAiUkyASlDgCACAC
  18370. IABBFGooAgAiA0ECdGogEiARjJQ4AgAgAiADIAFqIgZBAnRqIAsgDZQgBCAJlJMgEpQ4AgAgAiAD
  18371. IAFBAXRqQQJ0aiASIAsgDpQgBCAFlJOMlDgCACACIANBA3RqIAogEpQ4AgAgAiABIANBAXRqQQJ0
  18372. aiASIAsgB5QgECAJlJOMlDgCACACIAZBA3RqIAsgCJQgECAFlJMgEpQ4AgAgAAvZAgIRfwF9AkAC
  18373. QCABKAIIIAIoAghHDQAgACgCCCABKAIMRw0AIAAoAgwiAyACKAIMRg0BC0HcjYCAABCAgICAACAA
  18374. KAIMIQMLAkAgA0EBSA0AIAAoAgwhBCAAKAIIIgVBAUghBkEAIQdBACEIA0ACQCAGDQAgACgCFCAI
  18375. bCEJIAIoAgghCiAAKAIQIQsgACgCACEMQQAhDUEAIQ4DQCAMIAkgCyAObGpBAnRqIg9BADYCAAJA
  18376. IApBAUgNACACKAIQQQJ0IRAgASgCEEECdCERIAIoAgAgByACKAIUbGohAyABKAIAIAEoAhQgDWxq
  18377. IRJBACETQwAAAAAhFANAIA8gFCASKgIAIAMqAgCUkiIUOAIAIAMgEGohAyASIBFqIRIgE0EBaiIT
  18378. IApIDQALCyANQQRqIQ0gDkEBaiIOIAVIDQALCyAHQQRqIQcgCEEBaiIIIARIDQALCyAAC5sFBAR/
  18379. An0DfxB9AkACQCAAKAIIIgMgACgCDEcNACABKAIIIgQgASgCDEcNACACKAIIIgVBA0cNACAEQQNH
  18380. DQAgA0EDRw0AIAUgAigCDEYNAQtBg46AgAAQgICAgAALIAIoAgAiAyACQRRqKAIAIgRBAXQiBiAC
  18381. KAIQIgVBAXQiAmpBAnRqKgIAIQcgAyACIARqQQJ0aioCACEIIAEoAgAiAiABKAIQIglBAXQiCiAB
  18382. QRRqKAIAIgtqQQJ0aioCACEMIAIgC0EBdCIBIApqQQJ0aioCACENIAMgBEEDdGoqAgAhDiADIAYg
  18383. BWpBAnRqKgIAIQ8gAyAEQQJ0aioCACEQIAMgBCAFakECdGoqAgAhESACIAlBA3RqKgIAIRIgAiAJ
  18384. QQJ0aioCACETIAIgCyAJakECdGoqAgAhFCACIAEgCWpBAnRqKgIAIRUgACgCACIBIAIqAgAiFiAD
  18385. KgIAIheUIAIgC0ECdGoqAgAiGCADIAVBAnRqKgIAIhmUkiACIAtBA3RqKgIAIhogAyAFQQN0aioC
  18386. ACIblJI4AgAgASAAKAIQIgNBAnRqIBMgF5QgFCAZlJIgFSAblJI4AgAgASADQQN0aiASIBeUIAwg
  18387. GZSSIA0gG5SSOAIAIAEgAEEUaigCACICQQJ0aiAWIBCUIBggEZSSIBogCJSSOAIAIAEgAiADaiIE
  18388. QQJ0aiATIBCUIBQgEZSSIBUgCJSSOAIAIAEgAiADQQF0akECdGogEiAQlCAMIBGUkiANIAiUkjgC
  18389. ACABIAJBA3RqIBYgDpQgGCAPlJIgGiAHlJI4AgAgASADIAJBAXRqQQJ0aiATIA6UIBQgD5SSIBUg
  18390. B5SSOAIAIAEgBEEDdGogEiAOlCAMIA+UkiANIAeUkjgCACAAC+UBAQp/AkACQCAAKAIIIAEoAghH
  18391. DQAgACgCDCIDIAEoAgxGDQELQaqOgIAAEICAgIAAIAAoAgwhAwsCQCADQQFIDQAgACgCDCEEQQAh
  18392. BSAAKAIIIgZBAUghB0EAIQgDQAJAIAcNACAAKAIQQQJ0IQkgASgCEEECdCEKIAAoAgAgACgCFCAF
  18393. bGohAyABKAIAIAEoAhQgBWxqIQtBACEMA0AgAyALKgIAIAKUIAMqAgCSOAIAIAMgCWohAyALIApq
  18394. IQsgDEEBaiIMIAZIDQALCyAFQQRqIQUgCEEBaiIIIARIDQALCyAAC48CAwh/AX0DfwJAAkAgASgC
  18395. DEEBRw0AIAIoAghBAUcNACAAKAIIIAEoAghHDQAgACgCDCIDIAIoAgxGDQELQdGOgIAAEICAgIAA
  18396. IAAoAgwhAwsCQCADQQFIDQAgAkEUaigCACEEIAAoAgwhBSACKAIAIQZBACEHIAAoAggiCEEBSCEJ
  18397. QQAhCgNAAkAgCQ0AIAYgBCAKbEECdGoqAgAhCyAAKAIQQQJ0IQwgASgCEEECdCENIAAoAgAgACgC
  18398. FCAHbGohAiABKAIAIQNBACEOA0AgAiALIAMqAgCUOAIAIAIgDGohAiADIA1qIQMgDkEBaiIOIAhI
  18399. DQALCyAHQQRqIQcgCkEBaiIKIAVIDQALCyAAC70BAwF/AX0DfwJAAkAgACgCDEEBRw0AIAEoAgxB
  18400. AUcNACAAKAIIIgIgASgCCEYNAQtB+I6AgAAQgICAgAAgASgCCCECCwJAAkAgAkEBTg0AQwAAAAAh
  18401. AwwBCyABKAIQQQJ0IQQgACgCEEECdCEFIAEoAgghBiABKAIAIQEgACgCACEAQwAAAAAhA0EAIQID
  18402. QCADIAAqAgAgASoCAJSSIQMgASAEaiEBIAAgBWohACACQQFqIgIgBkgNAAsLIAMLggEEAX8BfQJ/
  18403. AX0CQCAAKAIMQQFGDQBBn4+AgAAQgICAgAALAkACQCAAKAIIIgFBAU4NAEMAAAAAIQIMAQsgACgC
  18404. EEECdCEDIAAoAgAhAEEAIQRDAAAAACECA0AgAiAAKgIAIgUgBZSSIQIgACADaiEAIARBAWoiBCAB
  18405. SA0ACwsgApELsQIBBX8CQCACKAIIIgMgAigCDCIETg0AQcaPgIAAEICAgIAACwJAAkAgACgCCCAD
  18406. Rw0AIAAoAgwgA0cNACABKAIIIANHDQAgASgCDCAERg0BC0Hlj4CAABCAgICAAAsgBEECdEGfkYCA
  18407. ABCFgICAACEFAkACQCAEQQFIDQBBACEGIAUhBwNAIAcgAyAGakEBEJKAgIAANgIAIAdBBGohByAE
  18408. IAZBf2oiBmoNAAsgAyAEIAUgASACEK2AgIAAIAMgBCAFIAAQroCAgAAgBEEBaiEHIARBAnQgBWpB
  18409. fGohBgNAIAYoAgAQl4CAgAAaIAZBfGohBiAHQX9qIgdBAUoNAAwCCwsgAyAEIAUgASACEK2AgIAA
  18410. IAMgBCAFIAAQroCAgAALIAVBlZKAgAAQh4CAgAAaC5AEAgl/An0CQCAAIAFODQBBupGAgAAQgICA
  18411. gAALAkACQCAEKAIIIABHDQAgBCgCDCABRw0AIAMoAgggAEcNACADKAIMIAFGDQELQdiRgIAAEICA
  18412. gIAACxCWgICAACEFEJaAgIAAIQYQloCAgAAhBxCWgICAACEIIABBAWoiCSABQQFqIgoQkoCAgAAh
  18413. CyAJIAoQkoCAgAAhDCADIAQQlYCAgAAaAkAgAUEBSA0AIAFBf2ohDSAAQX9qIQpBACEAA0AgBSAD
  18414. IAAgCiAAIAAQmoCAgAAiBCgCACoCACEOIAIoAgAgBBCVgICAABogBBCrgICAACEPIAIoAgAiBCgC
  18415. ACIJIA8gDkMAAAAAYCAOQwAAAABda7KUIAkqAgCSOAIAAkAgBBCrgICAACIOi7tEje21oPfGsD5j
  18416. DQAgAigCACIEIARDAACAPyAOlRCggICAABogBiADIAAgCiAAIA0QmoCAgAAhBCAHIAtBASACKAIA
  18417. KAIMQQEgBCgCDBCagICAACACKAIAIAQQpoCAgAAhCSAEIAggDEEBIAIoAgAoAghBASAEKAIMEJqA
  18418. gIAAIAIoAgAgCRCpgICAAEMAAADAEKiAgIAAGgsgAkEEaiECIAEgAEEBaiIARw0ACwsgDBCXgICA
  18419. ABogCxCXgICAABogCBCXgICAABogBxCXgICAABogBhCXgICAABogBRCXgICAABoL8gICCH8BfQJA
  18420. AkAgAygCCCAARw0AIAMoAgwiBCAARg0BIAQgAUYNAQtB9pGAgAAQgICAgAALEJaAgIAAIQUQloCA
  18421. gAAhBiADEJyAgIAAGgJAIAMoAgwiB0EBSA0AIAMoAgAgA0EUaigCACADKAIQaiIIIAdBf2psQQJ0
  18422. aiEEIAdBAWohCUEAIAhBAnRrIQgDQCAEQYCAgPwDNgIAIAQgCGohBCAJQX9qIglBAUoNAAsgB0EB
  18423. SA0AIAFBAWohCiAAQX9qIQAgAUECdCACakF8aiELQQAhAgNAIAUgA0EAIAAgAiACEJqAgIAAIQcg
  18424. CyEEIAohCQJAIAFBAUgNAANAIAYgByAJQX5qIABBAEEAEJqAgIAAIQggBCgCACAIEKqAgIAAIQwg
  18425. CCAEKAIAIAxDAAAAwJQQqICAgAAaIARBfGohBCAJQX9qIglBAUoNAAsLIAJBAWoiAiADKAIMSA0A
  18426. CwsgBhCXgICAABogBRCXgICAABoLlwMBB38CQCACKAIIIgMgAigCDCIETg0AQYSQgIAAEICAgIAA
  18427. CwJAAkAgACgCCCADRw0AIAAoAgwgBEcNACABKAIIIARHDQAgASgCDCAERg0BC0GjkICAABCAgICA
  18428. AAsQloCAgAAhBSADIAQQkoCAgAAhBiAEQQJ0QZ+RgIAAEIWAgIAAIQcCQAJAIARBAUgNAEEAIQgg
  18429. ByEJA0AgCSADIAhqQQEQkoCAgAA2AgAgCUEEaiEJIAQgCEF/aiIIag0ACyADIAQgByAGIAIQrYCA
  18430. gAAgAyAEIAcgABCugICAACABIAUgBkEAIARBf2oiCEEAIAgQmoCAgAAQlYCAgAAaIARBAWohCSAE
  18431. QQJ0IAdqQXxqIQgDQCAIKAIAEJeAgIAAGiAIQXxqIQggCUF/aiIJQQFKDQAMAgsLIAMgBCAHIAYg
  18432. AhCtgICAACADIAQgByAAEK6AgIAAIAEgBSAGQQAgBEF/aiIIQQAgCBCagICAABCVgICAABoLIAdB
  18433. lZKAgAAQh4CAgAAaIAYQl4CAgAAaIAUQl4CAgAAaC+QDAQp/AkAgASgCCCIEIAEoAgwiBU4NAEHC
  18434. kICAABCAgICAAAsCQAJAIAIoAgggBEcNACACKAIMQQFHDQAgACgCCCAFRw0AIAAoAgxBAUYNAQtB
  18435. 4ZCAgAAQgICAgAALIAQgBRCSgICAACEGIARBARCSgICAACEHIARBARCSgICAACEIIAVBARCSgICA
  18436. ACEJIAVBAnRBn5GAgAAQhYCAgAAhCgJAIAVBAUgNACAEIQsgCiEMIAUhDQNAIAwgC0EBEJKAgIAA
  18437. NgIAIAtBf2ohCyAMQQRqIQwgDUF/aiINDQALCyAEIAUgCiAGIAEQrYCAgAAgBCAFIAogByACELGA
  18438. gIAAIAAgBiAHELKAgIAAAkAgA0EBSA0AIANBAWohCwNAIAggAiAHIAEgABCigICAABCfgICAABog
  18439. BCAFIAogByAIELGAgIAAIAkgBiAHELKAgIAAIAAgCUMAAIA/EKiAgIAAGiALQX9qIgtBAUoNAAsL
  18440. AkAgBUEBSA0AIAVBAWohDCAFQQJ0IApqQXxqIQsDQCALKAIAEJeAgIAAGiALQXxqIQsgDEF/aiIM
  18441. QQFKDQALCyAKQZWSgIAAEIeAgIAAGiAJEJeAgIAAGiAIEJeAgIAAGiAHEJeAgIAAGiAGEJeAgIAA
  18442. GiAAC+MCAwh/AX0BfwJAAkAgAygCCCAARw0AIAMoAgxBAUcNACAEKAIIIABHDQAgBCgCDEEBRg0B
  18443. C0GukoCAABCAgICAAAsgAyAEEJWAgIAAGgJAIAFBAUgNAEEAIQUgACEGQQAhBwNAAkAgByAATiII
  18444. DQAgAygCECIEQQJ0IQkgAygCACAEIAVsaiEEIAIgB0ECdGoiCigCACILKAIQQQJ0IQwgCygCACEL
  18445. QwAAAAAhDSAGIQ4DQCANIAsqAgAgBCoCAJSSIQ0gBCAJaiEEIAsgDGohCyAOQX9qIg4NAAsgCA0A
  18446. IA0gDZIhDSADKAIQIgRBAnQhCSADKAIAIAQgBWxqIQQgCigCACILKAIQQQJ0IQwgCygCACELIAYh
  18447. DgNAIAQgBCoCACANIAsqAgCUkzgCACAEIAlqIQQgCyAMaiELIA5Bf2oiDg0ACwsgBUEEaiEFIAZB
  18448. f2ohBiAHQQFqIgcgAUcNAAsLC7IDAwx/An0DfwJAIAEoAggiAyABKAIMIgRODQBBzZKAgAAQgICA
  18449. gAALAkACQCAAKAIIIARHDQAgACgCDEEBRw0AIAIoAgggA0cNACACKAIMQQFGDQELQeySgIAAEICA
  18450. gIAACwJAIARBAUgNAEEAIQVBACABQRRqKAIAIgNBAnQiBiABKAIQIgdBAnRqayEIIAEoAgAiCSAD
  18451. IARsIAcgBEF/amxqQQJ0aiEKIARBAnQhCyADIAdqIQwgBCENA0ACQCAJIAwgDUF/aiIObEECdGoq
  18452. AgAiD4u7RI3ttaD3xrA+Y0EBcw0AIABBACoCgIiAgAAQm4CAgAAaDwsgAigCACACKAIQIA5sQQJ0
  18453. aioCACEQAkACQCANIARIDQAgACgCECERIAAoAgAhEgwBCyAAKAIQIhFBAnQhEyAAKAIAIhIgESAL
  18454. bGohASAKIQMgBSEHA0AgECADKgIAIAEqAgCUkyEQIAEgE2ohASADIAZqIQMgB0F/aiIHDQALCyAS
  18455. IBEgDmxBAnRqIBAgD5U4AgAgC0F8aiELIAogCGohCiAFQQFqIQUgDUEBSiEBIA4hDSABDQALCwvC
  18456. AwEKfwJAAkAgACgCCCICIAAoAgxHDQAgAiABKAIIIgNHDQAgAyABKAIMRg0BC0GAkYCAABCAgICA
  18457. ACAAKAIMIQILIAIgAhCUgICAACEEIAIgAhCSgICAACEFIAJBARCSgICAACEGEJaAgIAAIQcQloCA
  18458. gAAhCCACQQJ0QZ+RgIAAEIWAgIAAIQkCQAJAIAJBAUgNACAJIQMgAiEKA0AgAyAKQQEQkoCAgAA2
  18459. AgAgA0EEaiEDIApBf2oiCg0ACyACIAIgCSAFIAEQrYCAgAAgAkEBSA0BIAJBf2ohCkEAIQMDQCAH
  18460. IARBACAKIAMgAxCagICAACEBIAggAEEAIAogAyADEJqAgIAAIQsgAiACIAkgBiABELGAgIAAIAsg
  18461. BSAGELKAgIAAIAIgA0EBaiIDRw0ACyACQQFIDQEgAkEBaiEKIAJBAnQgCWpBfGohAwNAIAMoAgAQ
  18462. l4CAgAAaIANBfGohAyAKQX9qIgpBAUoNAAwCCwsgAiACIAkgBSABEK2AgIAACyAJQZWSgIAAEIeA
  18463. gIAAGiAIEJeAgIAAGiAHEJeAgIAAGiAGEJeAgIAAGiAFEJeAgIAAGiAEEJeAgIAAGiAAC9YCAQJ/
  18464. AkACQCAAKAIIQQNHDQAgACgCDEEDRw0AIAEoAghBAkcNACABKAIMQQRHDQAgAigCCEECRw0AIAIo
  18465. AgxBBEYNAQtBi5OAgAAQgICAgAALIAAgASgCACIDKgIAuyADIAEoAhAiBEECdGoqAgC7IAMgAUEU
  18466. aigCACIBQQJ0aioCALsgAyABIARqQQJ0aioCALsgAyABQQN0aioCALsgAyABQQF0IARqQQJ0aioC
  18467. ALsgAyABQQNsIgFBAnRqKgIAuyADIAEgBGpBAnRqKgIAuyACKAIAIgMqAgC7IAMgAigCECIEQQJ0
  18468. aioCALsgAyACQRRqKAIAIgFBAnRqKgIAuyADIAEgBGpBAnRqKgIAuyADIAFBA3RqKgIAuyADIAFB
  18469. AXQgBGpBAnRqKgIAuyADIAFBA2wiAUECdGoqAgC7IAMgASAEakECdGoqAgC7ELWAgIAAIAAL9QoC
  18470. FnwDf0EAKgKAiICAALshEQJAAkAgAiAEoSISIAWiIAQgBqEiEyABoiAGIAKhIhQgA6KgoCAKIAyh
  18471. IhUgDaIgDCAOoSIWIAmiIA4gCqEgC6KgoKJEAAAAAAAAAABjDQAgEyAHoiAGIAihIhcgA6IgCCAE
  18472. oSIYIAWioKAgFiAPoiAOIBChIhkgC6IgECAMoSANoqCgokQAAAAAAAAAAGMNACASIAeiIAQgCKEg
  18473. AaIgCCACoSITIAOioKAgFSAPoiAMIBChIAmiIBAgCqEiEiALoqCgokQAAAAAAAAAAGMNACACIAah
  18474. IAeiIBcgAaIgEyAFoqCgIAogDqEgD6IgGSAJoiASIA2ioKCiRAAAAAAAAAAAYw0AIAQgAqEiGiAH
  18475. IAGhIheiIAMgAaEiGyAToqEiHJkiHUSN7bWg98awPmMNACAUIBeiIAUgAaEiHiAToqEiH5kiIESN
  18476. 7bWg98awPmMNACAbIBSiIBogHqKhIhSZIiFEje21oPfGsD5jDQAgBiAEoSAHIAOhoiAFIAOhIBii
  18477. oZlEje21oPfGsD5jDQAgHCAFoiIYIB8gA6KhIiIgFCAIoiAcIAaiIh6gIiOiIB4gHyAEoqEiHiAU
  18478. IAeiIBigIhiioSIkmUSN7bWg98awPmMNACAcmiIlIBShIiYgIqIgHyAcoSIiIBiioUQAAAAAAADw
  18479. PyAkoyIkoiEYICIgI6IgJiAeoqEgJKIhHgJAAkAgHSAgZEEBcw0AIBMgGCAEoiAeIAOiRAAAAAAA
  18480. APA/oKAiBKIgJaMhHSAcIR8MAQsgEyAYIAaiIB4gBaJEAAAAAAAA8D+goCIEoiAfmqMhHQsgFyAE
  18481. oiAfoyETAkACQCAhICWZZEEBcw0AIBogGCAGoiAeIAWiRAAAAAAAAPA/oKAiBKIgFJqjIQcMAQsg
  18482. GiAYIAiiIB4gB6JEAAAAAAAA8D+goCIEoiAcoyEHICUhFAsgGCAdmiABoiATIAKioSIXIAeioiAd
  18483. IBsgBKIgFKMiFKIgHiATIAeaIAGiIBQgAqKhIhyioqCgIBMgB6KhIBggHSAcoqKhIB4gFyAUoqKh
  18484. mUSN7bWg98awPmMNACALIA2hIhsgECAOoSIaoiAWIA8gDaEiH6KhIiCZRI3ttaD3xrA+Yw0AIBEh
  18485. BCARIQIgESEGIBEhDiARIQEgESEDIBEhBSARIQggGyAVIBmgIhWiIBYgCSALoSANIA+hoCIZoqFE
  18486. AAAAAAAA8D8gIKMiFqIiDSAMIAqhIBogGaIgHyAVoqEgFqIiFiAMoqAiDCAJoqIgCyAJoSAWIAui
  18487. oCILIBIgDSAQoqAiEKIgFiAPIAmhIA0gD6KgIg8gCqKioKAgDyAMoqEgDSALIAqioqEgFiAQIAmi
  18488. oqGZRI3ttaD3xrA+Yw0BIBYgF6IgDSAcoqBEAAAAAAAA8D+gIQUgGCAWIBOiIA0gFKKgoCEDIB4g
  18489. FiAdoiANIAeioKAhASAMIBeiIBAgHKKgIAqgIQ4gGCAKoiAMIBOiIBAgFKKgoCEGIB4gCqIgDCAd
  18490. oiAQIAeioKAhAiALIBeiIA8gHKKgIAmgIQQgGCAJoiALIBOiIA8gFKKgoCERIB4gCaIgCyAdoiAP
  18491. IAeioKAhCAwBCyARIQQgESECIBEhBiARIQ4gESEBIBEhAyARIQUgESEICyAAKAIAIicgCLY4AgAg
  18492. JyAAQRRqKAIAIihBAnRqIBG2OAIAICcgKEEDdGogBLY4AgAgJyAAKAIQIgBBAnRqIAK2OAIAICcg
  18493. ACAoaiIpQQJ0aiAGtjgCACAnIAAgKEEBdGpBAnRqIA62OAIAICcgAEEDdGogAbY4AgAgJyAoIABB
  18494. AXRqQQJ0aiADtjgCACAnIClBA3RqIAW2OAIAC7oHAhZ/Cn0CQAJAIAAoAghBA0cNACAAKAIMQQNH
  18495. DQAgASgCCEECRw0AIAEoAgwiA0EESA0AIAIoAghBAkcNACACKAIMIANGDQELQbKTgIAAEICAgIAA
  18496. IAEoAgwhAwsgA0EBdCIEQQgQkoCAgAAhBSAEQQEQkoCAgAAhBkEIQQEQkoCAgAAhBwJAIANBAUgN
  18497. ACAFQRRqKAIAIgRBDGwgBSgCECIIQQJ0IglqIQogBEEEdCAJaiELIARBFGwgCWohDCAEQRhsIg0g
  18498. CWohDiAEQRxsIg8gCWohECACKAIQQQJ0IREgASgCEEECdCESIAhBA3QhCCAGKAIQIglBA3QhEyAJ
  18499. QQJ0IRQgAkEUaigCAEECdCEVIAFBFGooAgBBAnQhFiAEQQN0IRcgBEECdCEYIAYoAgAhCSAFKAIA
  18500. IQQgAigCACECIAEoAgAhAQNAIAIgEWoqAgAhGSABIBJqKgIAIRogAioCACEbIAQgASoCACIcOAIA
  18501. IAQgGGogGjgCACAEIBdqQYCAgPwDNgIAIAQgCmogHDgCACAEIAtqIBo4AgAgBCAMakGAgID8AzYC
  18502. ACAEIA1qIBsgHIwiHJQ4AgAgBCAOaiAZIByUOAIAIAQgD2ogGyAajCIalDgCACAEIBBqIBkgGpQ4
  18503. AgAgCSAbOAIAIAkgFGogGTgCACACIBVqIQIgASAWaiEBIAQgCGohBCAJIBNqIQkgA0F/aiIDDQAL
  18504. CyAHIAUgBkEDELCAgIAAGgJAAkAgBygCACIEKgIAIhkgBCAHKAIQIglBBHRqKgIAIhqUIAQgCUEC
  18505. dGoqAgAiGyAEIAlBFGxqKgIAIhyUIAQgCUEYbGoqAgAiHZSSIAQgCUEDdGoqAgAiHiAEIAlBDGxq
  18506. KgIAIh+UIAQgCUEcbGoqAgAiIJSSIBsgH5STIBkgHJQgIJSTIB4gGpQgHZSTIiEQg4CAgAANAEMA
  18507. AIA/ISIgIYu7RI3ttaD3xrA+Y0EBcw0BC0EAKgKAiICAACIZIRsgGSEeIBkhHyAZIRogGSEcIBkh
  18508. HSAZISAgGSEiCyAAKAIAIgQgGTgCACAEIABBFGooAgAiCUECdGogGzgCACAEIAlBA3RqIB44AgAg
  18509. BCAAKAIQIgJBAnRqIB84AgAgBCACIAlqIgFBAnRqIBo4AgAgBCACIAlBAXRqQQJ0aiAcOAIAIAQg
  18510. AkEDdGogHTgCACAEIAkgAkEBdGpBAnRqICA4AgAgBCABQQN0aiAiOAIAIAcQl4CAgAAaIAYQl4CA
  18511. gAAaIAUQl4CAgAAaIAALnwgKAX8BfQF/An0Bfwp9AX8BfQN/AX0CQAJAIAAoAghBA0cNACAAKAIM
  18512. QQNHDQAgASgCCEECRw0AIAEoAgxBBEcNACACKAIIQQJHDQAgAigCDEEERg0BC0HZk4CAABCAgICA
  18513. AAsgACABKAIAIgMqAgAiBCAEIAMgAUEUaigCACIFQQJ0aioCACIGkiADIAVBA3RqKgIAIgeSIAMg
  18514. BUEDbCIIQQJ0aioCACIJkkMAAIA+lCIKkyIEQwAAAEEgAyAIIAEoAhAiAWpBAnRqKgIAIgsgCyAD
  18515. IAFBAnRqKgIAIgwgAyAFIAFqQQJ0aioCACINkiADIAVBAXQgAWpBAnRqKgIAIg6SkkMAAIA+lCIP
  18516. kyILIAuUIAkgCpMiCSAJlCAOIA+TIg4gDpQgByAKkyIHIAeUIA0gD5MiDSANlCAGIAqTIgYgBpQg
  18517. BCAElCAMIA+TIgwgDJSSkpKSkpKSlZEiBJS7IAwgBJS7IAYgBJS7IA0gBJS7IAcgBJS7IA4gBJS7
  18518. IAkgBJS7IAsgBJS7IAIoAgAiAyoCACILIAsgAyACQRRqKAIAIgVBAnRqKgIAIhCSIAMgBUEDdGoq
  18519. AgAiDJIgAyAFQQNsIghBAnRqKgIAIg2SQwAAgD6UIgmTIgtDAAAAQSADIAggAigCECIBakECdGoq
  18520. AgAiDiAOIAMgAUECdGoqAgAiESADIAUgAWpBAnRqKgIAIhKSIAMgBUEBdCABakECdGoqAgAiBpKS
  18521. QwAAgD6UIg6TIgcgB5QgDSAJkyINIA2UIAYgDpMiBiAGlCAMIAmTIgwgDJQgEiAOkyISIBKUIBAg
  18522. CZMiECAQlCALIAuUIBEgDpMiESARlJKSkpKSkpKVkSILlLsgESALlLsgECALlLsgEiALlLsgDCAL
  18523. lLsgBiALlLsgDSALlLsgByALlLsQtYCAgAAgACgCACIDIABBFGooAgAiBUEBdCICIAAoAhAiAUEB
  18524. dCIIakECdGoqAgAhECADIAggBWpBAnRqIggqAgAhByADIAIgAWpBAnRqIgIqAgAhESADIAVBA3Rq
  18525. IhMqAgAhFCADIAUgAWoiFUECdGoiFioCACEGIAMgBUECdGoiBSoCACEMIAMgAUECdGoiFyoCACES
  18526. IAMgBCAJIAMgAUEDdGoiASoCACINlCADKgIAIhhDAACAPyALlSILlJKUOAIAIBcgBCAOIA2UIBIg
  18527. C5SSlDgCACABIAQgDZQ4AgAgBSAEIAkgB5QgDCALlJKUOAIAIBYgBCAOIAeUIAYgC5SSlDgCACAI
  18528. IAQgB5Q4AgAgEyAUIAQgCiAYlCAPIAyUkpSTIAuUIAkgECAEIAogDZQgDyAHlJKUkyIHlJI4AgAg
  18529. AiARIAQgCiASlCAPIAaUkpSTIAuUIA4gB5SSOAIAIAMgFUEDdGogBzgCACAAC5sCAQZ/AkACQCAA
  18530. KAIIQQNHDQAgACgCDEEDRw0AIAEoAghBAkcNACABKAIMIgNBBEgNACACKAIIQQJHDQAgAigCDCAD
  18531. Rg0BC0GAlICAABCAgICAACABKAIMIQMLQQIgAxCSgICAACEEQQIgAxCSgICAACEFQQNBAxCSgICA
  18532. ACEGQQNBAxCSgICAACEHQQNBAxCSgICAACEIIAQgASAGQQNBAxCSgICAACIDEMGAgIAAIAUgAiAD
  18533. IAcQwYCAgAAgAyAIIAQgBRC2gICAACIBIAYQp4CAgAAaIAAgByADEKeAgIAAGiADEJeAgIAAGiAB
  18534. EJeAgIAAGiAHEJeAgIAAGiAGEJeAgIAAGiAFEJeAgIAAGiAEEJeAgIAAGiAAC/kFAhZ/Bn0CQAJA
  18535. IAAoAghBAkcNACAAKAIMQQNHDQAgASgCCEECRw0AIAEoAgwiA0EDSA0AIAIoAghBAkcNACACKAIM
  18536. IANGDQELQaeUgIAAEICAgIAAIAEoAgwhAwsgA0EBdCIEQQYQkoCAgAAhBSAEQQEQkoCAgAAhBkEG
  18537. QQEQkoCAgAAhBwJAIANBAUgNACAFQRRqKAIAIgRBDGwgBSgCECIIQQJ0IglqIQogBEEEdCAJaiEL
  18538. IARBFGwgCWohDCACKAIQQQJ0IQ0gASgCEEECdCEOIAhBA3QhDyAGKAIQIglBA3QhECAJQQJ0IREg
  18539. AkEUaigCAEECdCESIAFBFGooAgBBAnQhEyAEQQN0IRQgBEECdCEVIAYoAgAhCSAFKAIAIQQgAigC
  18540. ACECIAEoAgAhAQNAIAIgDWooAgAhFiABIA5qKAIAIQggAigCACEXIAQgASgCACIYNgIAIAQgFWog
  18541. CDYCACAEIBRqQYCAgPwDNgIAIAQgCmogGDYCACAEIAtqIAg2AgAgBCAMakGAgID8AzYCACAJIBc2
  18542. AgAgCSARaiAWNgIAIAIgEmohAiABIBNqIQEgBCAPaiEEIAkgEGohCSADQX9qIgMNAAsLIAcgBSAG
  18543. QQMQsICAgAAaAkACQCAHKAIAIgQqAgAiGSAEIAcoAhAiCUECdGoqAgAiGpIgBCAJQQN0aioCACIb
  18544. kiAEIAlBDGxqKgIAIhySIAQgCUEEdGoqAgAiHZIgBCAJQRRsaioCACIekhCDgICAAA0AIBkgHZQg
  18545. GiAclJOLu0SN7bWg98awPmNBAXMNAQtBACoCgIiAgAAiGSEaIBkhGyAZIRwgGSEdIBkhHgsgACgC
  18546. ACIEIBk4AgAgBCAAQRRqKAIAIglBAnRqIBo4AgAgBCAJQQN0aiAbOAIAIAQgACgCECICQQJ0aiAc
  18547. OAIAIAQgAiAJakECdGogHTgCACAEIAIgCUEBdGpBAnRqIB44AgAgBxCXgICAABogBhCXgICAABog
  18548. BRCXgICAABogAAvNBQMBfAJ/FXwCQAJAIAAoAghBAkcNACAAKAIMQQNHDQAgASgCCEECRw0AIAEo
  18549. AgxBA0cNACACKAIIQQJHDQAgAigCDEEDRg0BC0HKlICAABCAgICAAAtBACoCgIiAgAC7IQMCQAJA
  18550. IAEoAgAiBCABKAIQIgVBAnRqKgIAuyIGIAQgAUEUaigCACIBIAVqQQJ0aioCALsiB6EiCCAEIAFB
  18551. A3RqKgIAuyIJoiAHIAQgAUEBdCAFakECdGoqAgC7IgqhIgsgBCoCALsiDKIgCiAGoSINIAQgAUEC
  18552. dGoqAgC7Ig6ioKAiD5lEje21oPfGsD5jDQAgAigCACIEIAIoAhAiBUECdGoqAgC7IhAgBCACQRRq
  18553. KAIAIgEgBWpBAnRqKgIAuyIRoSAEIAFBA3RqKgIAuyISoiARIAQgAUEBdCAFakECdGoqAgC7IhOh
  18554. IAQqAgC7IhSiIBMgEKEgBCABQQJ0aioCALsiFaKgoJlEje21oPfGsD5jDQBEAAAAAAAA8D8gD6Mi
  18555. FiALIBSiIA0gFaKgIAggEqKgoiIPIBYgCSAOoSIXIBCiIAwgCaEiGCARoqAgDiAMoSIZIBOioKIi
  18556. GqIgFiAXIBSiIBggFaKgIBkgEqKgoiIXIBYgCyAQoiANIBGioCAIIBOioKIiCKKhmUSN7bWg98aw
  18557. PmNBAXNFDQAgFiAOIAqiIAcgCaKhIgMgEKIgBiAJoiAMIAqioSIKIBGioCAMIAeiIAYgDqKhIgcg
  18558. E6KgoiEGIBYgAyAUoiAKIBWioCAHIBKioKIhAwwBCyADIQ8gAyEXIAMhCCADIRogAyEGCyAAKAIA
  18559. IgQgD7Y4AgAgBCAAQRRqKAIAIgFBAnRqIBe2OAIAIAQgAUEDdGogA7Y4AgAgBCAAKAIQIgVBAnRq
  18560. IAi2OAIAIAQgBSABakECdGogGrY4AgAgBCAFIAFBAXRqQQJ0aiAGtjgCACAAC4EDAQl/AkACQCAA
  18561. KAIIQQJHDQAgACgCDEEDRw0AIAEoAghBAkcNACABKAIMIgNBA0gNACACKAIIQQJHDQAgAigCDCAD
  18562. Rg0BC0HtlICAABCAgICAACABKAIMIQMLQQIgAxCSgICAACEEQQIgAxCSgICAACEFQQNBAxCSgICA
  18563. ACEGQQNBAxCSgICAACEHQQNBAxCUgICAACEIEJaAgIAAIAhBAEEBQQBBAhCagICAACEJQQNBAxCS
  18564. gICAACEDQQNBAxCSgICAACEKEJaAgIAAIApBAEEBQQBBAhCagICAACELIAQgASAGIAMQwYCAgAAg
  18565. BSACIAMgBxDBgICAACAJIAQgBRC5gICAACEBIAMgCCAGEKeAgIAAGiAKIAcgAxCngICAABogACAL
  18566. EJWAgIAAGiALEJeAgIAAGiAKEJeAgIAAGiADEJeAgIAAGiABEJeAgIAAGiAIEJeAgIAAGiAHEJeA
  18567. gIAAGiAGEJeAgIAAGiAFEJeAgIAAGiAEEJeAgIAAGiAAC5kUAhx/DX0jgICAgABBEGsiBySAgICA
  18568. AAJAAkAgACgCCEEDRw0AIAAoAgxBA0cNACACKAIIQQJHDQAgAigCDCIIQQRIDQAgAygCCEECRw0A
  18569. IAMoAgwgCEcNAAJAIAFFDQAgASgCCEEBRw0BIAEoAgwgCEcNAQsgBEEBSA0AIAVBAUgNACAGQwAA
  18570. AABgDQELQZCVgIAAEICAgIAAIAIoAgwhCAsCQCABRQ0AIAFDAAAAABCbgICAABoLIAhBAnQiCUGy
  18571. lYCAABCFgICAACEKIAlB0ZWAgAAQhYCAgAAgCBCNgICAACILIAhBBBCOgICAACAIIARBAnQiDCAI
  18572. b2sgDGoiDUECdEHwlYCAABCFgICAACEOAkAgDUEBSA0AQQAhDyAIQQFIIRAgDiERA0ACQCAQDQBB
  18573. ACEMIBEhEgNAIBIgDDYCACASQQRqIRIgCCAMQQFqIgxHDQALCyAOIA9BAnRqIAhBBBCOgICAACAR
  18574. IAlqIREgDyAIaiIPIA1IDQALC0ECQQQQkoCAgAAhE0ECQQQQkoCAgAAhFCAEQQN0QY+WgIAAEIWA
  18575. gIAAIRUgBCEWAkAgBEEBSA0AIBUhFyAOIQkgBCEYIAQhFgNAIAcgCSgCACIZNgIAIAcgCUEEaigC
  18576. ACIaNgIEIAcgCUEIaigCACIbNgIIIAcgCUEMaigCADYCDCAUKAIUIQ0gEygCFCEQIAMoAhAhHCAU
  18577. KAIQIR0gFCgCACEMIAMoAgAhEiADKAIUIR4gAigCECEfIBMoAhAhICATKAIAIg8gAigCACIRIBkg
  18578. AigCFCIhbCIiQQJ0aigCADYCACAPICBBAnRqIBEgHyAiakECdGooAgA2AgAgDCASIB4gGWwiGUEC
  18579. dGooAgA2AgAgDCAdQQJ0aiASIBwgGWpBAnRqKAIANgIAIA8gEEECdGogESAhIBpsIhlBAnRqKAIA
  18580. NgIAIA8gICAQakECdGogESAfIBlqQQJ0aigCADYCACAMIA1BAnRqIBIgHiAabCIZQQJ0aigCADYC
  18581. ACAMIB0gDWpBAnRqIBIgHCAZakECdGooAgA2AgAgDyAQQQN0aiARICEgG2wiGUECdGooAgA2AgAg
  18582. DyAgIBBBAXRqQQJ0aiARIB8gGWpBAnRqKAIANgIAIAwgDUEDdGogEiAeIBtsIhlBAnRqKAIANgIA
  18583. IAwgHSANQQF0akECdGogEiAcIBlqQQJ0aigCADYCACAPIBBBA2wiEEECdGogESAhIAcoAgwiGWwi
  18584. IUECdGooAgA2AgAgDyAgIBBqQQJ0aiARIB8gIWpBAnRqKAIANgIAIAwgDUEDbCIPQQJ0aiASIB4g
  18585. GWwiEUECdGooAgA2AgAgDCAdIA9qQQJ0aiASIBwgEWpBAnRqKAIANgIAQQNBAxCSgICAACEMIBdB
  18586. BGoiEkEANgIAIBcgDDYCACAMIBMgFBC0gICAABoCQCAXKAIAKAIAKgIAEIOAgIAARQ0AIBJBfzYC
  18587. ACAWQX9qIRYLIBdBCGohFyAJQRBqIQkgGEF/aiIYDQALCwJAAkAgFg0AIABBACoCgIiAgAAQm4CA
  18588. gAAaDAELIAYgBpQhI0EAIRcgFSAEQQhBhICAgABBABCLgICAABoCQAJAIAhBAUgNAEEAIRwDQCAc
  18589. IhJBAWoiHCAFbyEMAkAgFkECSA0AIAwNACAVIBZBCEGEgICAAEEAEIuAgIAAGiAWQQF2IRYLAkAg
  18590. FkEBRw0AQQAhFwwDCwJAIBZBAUgNACADKAIAIgwgAygCFCALIBJBAnRqKAIAIhJsIg9BAnRqKgIA
  18591. ISQgAigCACIRIAIoAhQgEmwiEkECdGoqAgAhBiAMIA8gAygCEGpBAnRqKgIAISUgESASIAIoAhBq
  18592. QQJ0aioCACEmIBUhESAWIQkDQCARQQRqIgwgDCgCACARKAIAIg8oAgAiDCAPQRRqKAIAIhJBAXQi
  18593. DSAPKAIQIg9qQQJ0aioCACAGIAwgD0ECdGoqAgCUICYgDCASIA9qQQJ0aioCAJSSkiAMIA0gD0EB
  18594. dCIQakECdGoqAgAgBiAMIA9BA3RqKgIAlCAmIAwgECASakECdGoqAgCUkpIiJ5UgJZMiKCAolCAM
  18595. IBJBA3RqKgIAIAYgDCoCAJQgJiAMIBJBAnRqKgIAlJKSICeVICSTIicgJ5SSICNfajYCACARQQhq
  18596. IREgCUF/aiIJDQALCyAcIAhHDQALCyAWQQJIDQAgFUEMaiEMQQAhF0EBIRIDQCASIBcgDCgCACAV
  18597. IBdBA3RqKAIEShshFyAMQQhqIQwgFiASQQFqIhJHDQALCwJAIAhBAUgNACAVIBdBA3RqKAIAIg8o
  18598. AgAiDCAPKAIQIhJBA3RqKgIAISQgDCASQQJ0aioCACElIAwgD0EUaigCACIPQQN0aioCACEpIAwg
  18599. D0ECdGoqAgAhKiAMIBJBAXQiESAPakECdGoqAgAhKyAMIA8gEmpBAnRqKgIAISwgDCAPQQF0Ig8g
  18600. EWpBAnRqKgIAIS0gDCAPIBJqQQJ0aioCACEuIAwqAgAhLyADKAIAIQ8gAigCACERQQAhEkEAIQwD
  18601. QAJAICkgLyARIAIoAhQgDGwiCUECdGoqAgAiBpQgKiARIAkgAigCEGpBAnRqKgIAIiaUkpIgLSAk
  18602. IAaUICsgJpSSkiInlSAPIAMoAhQgDGwiCUECdGoqAgCTIiggKJQgLiAlIAaUICwgJpSSkiAnlSAP
  18603. IAkgAygCEGpBAnRqKgIAkyIGIAaUkiAjX0EBcw0AIAogEkECdGogDDYCACASQQFqIRIgAUUNACAB
  18604. KAIAIAEoAhQgDGxBAnRqQYCAgPwDNgIACyAIIAxBAWoiDEcNAAsgEkEDTA0AQQIgEhCSgICAACEW
  18605. QQIgEhCSgICAACIZKAIQQQJ0IRcgFkEUaigCAEECdCEcIBYoAhBBAnQhHSAZQRRqKAIAQQJ0IR4g
  18606. GSgCACEMIANBFGooAgAhHyAWKAIAIQ8gAkEUaigCACEgIAMoAhAhISADKAIAIQggAigCECEDIAIo
  18607. AgAhCSAKIREDQCAPIAkgICARKAIAIg1sIhBBAnRqKAIANgIAIA8gHWogCSADIBBqQQJ0aigCADYC
  18608. ACAMIAggHyANbCINQQJ0aigCADYCACAMIBdqIAggISANakECdGooAgA2AgAgDCAeaiEMIA8gHGoh
  18609. DyARQQRqIREgEkF/aiISDQALIAAgFiAZELiAgIAAGiAZEJeAgIAAGiAWEJeAgIAAGgwBCyAAQQAq
  18610. AoCIgIAAEJuAgIAAGgsCQCAEQQFIDQAgBEEBaiESIARBA3QgFWpBeGohDANAIAwoAgAQl4CAgAAa
  18611. IAxBeGohDCASQX9qIhJBAUoNAAsLIBVBr5aAgAAQh4CAgAAaIBQQl4CAgAAaIBMQl4CAgAAaIA5B
  18612. zZaAgAAQh4CAgAAaIAtB65aAgAAQh4CAgAAaIApBiZeAgAAQh4CAgAAaIAdBEGokgICAgAAgAAsN
  18613. ACABKAIEIAAoAgRrC8gRAhh/CX0CQAJAIAAoAghBAkcNACAAKAIMQQNHDQAgAigCCEECRw0AIAIo
  18614. AgwiB0EDSA0AIAMoAghBAkcNACADKAIMIAdHDQACQCABRQ0AIAEoAghBAUcNASABKAIMIAdHDQEL
  18615. IARBAUgNACAFQQFIDQAgBkMAAAAAYA0BC0Gnl4CAABCAgICAACACKAIMIQcLAkAgAUUNACABQwAA
  18616. AAAQm4CAgAAaCyAHQQJ0IghBypeAgAAQhYCAgAAhCSAIQeqXgIAAEIWAgIAAIAcQjYCAgAAiCiAH
  18617. QQQQjoCAgAAgByAEQQNsIgsgB29rIAtqIgxBAnRBipiAgAAQhYCAgAAhDQJAIAxBAUgNAEEAIQ4g
  18618. B0EBSCEPIA0hEANAAkAgDw0AQQAhCyAQIREDQCARIAs2AgAgEUEEaiERIAcgC0EBaiILRw0ACwsg
  18619. DSAOQQJ0aiAHQQQQjoCAgAAgECAIaiEQIA4gB2oiDiAMSA0ACwtBAkEDEJKAgIAAIQ9BAkEDEJKA
  18620. gIAAIRIgBEEDdEGqmICAABCFgICAACETIAQhFAJAIARBAUgNACATIQggDSEMIAQhFSAEIRQDQCAP
  18621. KAIAIgsgAigCACIRIAIoAhQiFiAMKAIAIhdsIg5BAnRqKAIANgIAIAsgDygCECIYQQJ0aiARIAIo
  18622. AhAiGSAOakECdGooAgA2AgAgEigCACIOIAMoAgAiECAXIAMoAhQiGmwiF0ECdGooAgA2AgAgDiAS
  18623. KAIQIhtBAnRqIBAgAygCECIcIBdqQQJ0aigCADYCACALIA8oAhQiF0ECdGogESAWIAxBBGooAgAi
  18624. HWwiHkECdGooAgA2AgAgCyAYIBdqQQJ0aiARIBkgHmpBAnRqKAIANgIAIA4gEigCFCIeQQJ0aiAQ
  18625. IBogHWwiHUECdGooAgA2AgAgDiAbIB5qQQJ0aiAQIBwgHWpBAnRqKAIANgIAIAsgF0EDdGogESAW
  18626. IAxBCGooAgAiHWwiFkECdGooAgA2AgAgCyAYIBdBAXRqQQJ0aiARIBkgFmpBAnRqKAIANgIAIA4g
  18627. HkEDdGogECAaIB1sIgtBAnRqKAIANgIAIA4gGyAeQQF0akECdGogECAcIAtqQQJ0aigCADYCAEEC
  18628. QQMQkoCAgAAhCyAIQQRqIhFBADYCACAIIAs2AgAgCyAPIBIQuoCAgAAaAkAgCCgCACgCACoCABCD
  18629. gICAAEUNACARQX82AgAgFEF/aiEUCyAIQQhqIQggDEEMaiEMIBVBf2oiFQ0ACwsCQAJAIBQNACAA
  18630. QQAqAoCIgIAAEJuAgIAAGgwBCyAGIAaUIR9BACEMIBMgBEEIQYSAgIAAQQAQi4CAgAAaAkACQCAH
  18631. QQFIDQBBACEXA0AgFyIRQQFqIhcgBW8hCwJAIBRBAkgNACALDQAgEyAUQQhBhICAgABBABCLgICA
  18632. ABogFEEBdiEUCwJAIBRBAUcNAEEAIQwMAwsCQCAUQQFIDQAgAygCACILIAMoAhQgCiARQQJ0aigC
  18633. ACIRbCIOQQJ0aioCACEgIAIoAgAiECACKAIUIBFsIhFBAnRqKgIAIQYgCyAOIAMoAhBqQQJ0aioC
  18634. ACEhIBAgESACKAIQakECdGoqAgAhIiATIREgFCEIA0AgEUEEaiILIAsoAgAgESgCACIQKAIAIgsg
  18635. EEEUaigCACIOQQN0aioCACAGIAsqAgCUICIgCyAOQQJ0aioCAJSSkiAgkyIjICOUIAsgDkEBdCAQ
  18636. KAIQIhBqQQJ0aioCACAGIAsgEEECdGoqAgCUICIgCyAOIBBqQQJ0aioCAJSSkiAhkyIjICOUkiAf
  18637. X2o2AgAgEUEIaiERIAhBf2oiCA0ACwsgFyAHRw0ACwsgFEECSA0AIBNBDGohC0EAIQxBASERA0Ag
  18638. ESAMIAsoAgAgEyAMQQN0aigCBEobIQwgC0EIaiELIBQgEUEBaiIRRw0ACwsCQCAHQQFIDQAgEyAM
  18639. QQN0aigCACIRKAIAIgsgESgCECIOQQJ0aioCACEgIAsgEUEUaigCACIRQQN0aioCACEhIAsgEUEC
  18640. dGoqAgAhJCALIBEgDmpBAnRqKgIAISUgCyARQQF0IA5qQQJ0aioCACEmIAsqAgAhJyADKAIAIQ4g
  18641. AigCACEQQQAhEUEAIQsDQAJAICEgJyAQIAIoAhQgC2wiCEECdGoqAgAiBpQgJCAQIAggAigCEGpB
  18642. AnRqKgIAIiKUkpIgDiADKAIUIAtsIghBAnRqKgIAkyIjICOUICYgICAGlCAlICKUkpIgDiAIIAMo
  18643. AhBqQQJ0aioCAJMiBiAGlJIgH19BAXMNACAJIBFBAnRqIAs2AgAgEUEBaiERIAFFDQAgASgCACAB
  18644. KAIUIAtsQQJ0akGAgID8AzYCAAsgByALQQFqIgtHDQALIBFBAkwNAEECIBEQkoCAgAAhG0ECIBEQ
  18645. koCAgAAiHCgCEEECdCEXIBtBFGooAgBBAnQhHiAbKAIQQQJ0IRQgHEEUaigCAEECdCEWIBwoAgAh
  18646. CyADQRRqKAIAIRggGygCACEOIAJBFGooAgAhGSADKAIQIRogAygCACEQIAIoAhAhAyACKAIAIQgg
  18647. CSEHA0AgDiAIIBkgBygCACIMbCICQQJ0aigCADYCACAOIBRqIAggAyACakECdGooAgA2AgAgCyAQ
  18648. IBggDGwiDEECdGooAgA2AgAgCyAXaiAQIBogDGpBAnRqKAIANgIAIAsgFmohCyAOIB5qIQ4gB0EE
  18649. aiEHIBFBf2oiEQ0ACyAAIBsgHBC7gICAABogHBCXgICAABogGxCXgICAABoMAQsgAEEAKgKAiICA
  18650. ABCbgICAABoLAkAgBEEBSA0AIARBAWohESAEQQN0IBNqQXhqIQsDQCALKAIAEJeAgIAAGiALQXhq
  18651. IQsgEUF/aiIRQQFKDQALCyATQcqYgIAAEIeAgIAAGiASEJeAgIAAGiAPEJeAgIAAGiANQeiYgIAA
  18652. EIeAgIAAGiAKQYaZgIAAEIeAgIAAGiAJQaSZgIAAEIeAgIAAGiAAC+IDCAN/An0BfwN9AX8EfQF/
  18653. A30CQAJAIAAoAghBAkcNACABKAIIQQJHDQAgACgCDCIDIAEoAgxHDQAgAigCCEEDRw0AIAIoAgxB
  18654. A0YNAQtBwpmAgAAQgICAgAAgASgCDCEDCwJAIAIoAgAiBCACKAIQIgVBA3RqKgIAIgYgBCACQRRq
  18655. KAIAIgJBAnRqKgIAIgcgBCACQQF0IgggBWpBAnRqKgIAIgmUIAQgAkEDdGoqAgAiCiAEIAIgBWpB
  18656. AnRqKgIAIguUk5QgBCAFQQF0IgwgAmpBAnRqKgIAIg0gCiAEIAVBAnRqKgIAIg6UIAQqAgAiDyAJ
  18657. lJOUkiAPIAuUIAcgDpSTIAQgCCAMakECdGoqAgAiEJSSi7tEje21oPfGsD5jDQACQCADQQFIDQAg
  18658. ACgCEEECdCECIAEoAhBBAnQhCCAAQRRqKAIAQQJ0IQwgAUEUaigCAEECdCERIAAoAgAhBCABKAIA
  18659. IQUDQCAEIAogDyAFKgIAIhKUIAcgBSAIaioCACITlJKSIBAgBiASlCANIBOUkpIiFJU4AgAgBCAC
  18660. aiAJIA4gEpQgCyATlJKSIBSVOAIAIAQgDGohBCAFIBFqIQUgA0F/aiIDDQALCyAADwsgAEEAKgKA
  18661. iICAABCbgICAAAvVAgQDfwZ9An8CfQJAAkAgACgCCEECRw0AIAEoAghBAkcNACAAKAIMIgMgASgC
  18662. DEcNACACKAIIQQJHDQAgAigCDEEDRg0BC0HnmYCAABCAgICAACABKAIMIQMLAkAgA0EBSA0AIAIo
  18663. AgAiBCACKAIQIgVBAnRqKgIAIQYgBCACQRRqKAIAIgJBA3RqKgIAIQcgBCACQQJ0aioCACEIIAQg
  18664. AiAFakECdGoqAgAhCSAEIAJBAXQgBWpBAnRqKgIAIQogBCoCACELIAAoAhBBAnQhAiABKAIQQQJ0
  18665. IQUgAEEUaigCAEECdCEMIAFBFGooAgBBAnQhDSAAKAIAIQQgASgCACEBA0AgBCAHIAsgASoCACIO
  18666. lCAIIAEgBWoqAgAiD5SSkjgCACAEIAJqIAogBiAOlCAJIA+UkpI4AgAgBCAMaiEEIAEgDWohASAD
  18667. QX9qIgMNAAsLIAAL+AcHAX8BfQF/A30DfwF9An8CQAJAAkAgASgCCEECRw0AIAEoAgwiBEEBSA0A
  18668. IAAoAghBAkcNACAAKAIMIARHDQAgAigCCEEDRw0AIAIoAgxBA0cNACADKAIIQQNHDQAgAygCDEED
  18669. Rw0AIASyIQUMAQtBjJqAgAAQgICAgABBACEGIAEoAgwiBLIhBSAEQQBKDQBDAAAAACEHQwAAAAAg
  18670. BZUiCCEJDAELIAEoAhBBAnQhCiABQRRqKAIAQQJ0IQsgASgCACEGQwAAAAAhByAEIQxDAAAAACEN
  18671. A0AgByAGKgIAkiEHIA0gBiAKaioCAJIhDSAGIAtqIQYgDEF/aiIMDQALIA0gBZUhCCAHIAWVIQkg
  18672. ASgCEEECdCEKIAFBFGooAgBBAnQhCyABKAIAIQZDAAAAACEHIAQhDANAIAcgBioCACAJkyINIA2U
  18673. IAYgCmoqAgAgCJMiDSANlJKSIQcgBiALaiEGIAxBf2oiDA0AC0EBIQYLAkAgByAFlZEiB4u7RI3t
  18674. taD3xrA+Y0UNACACEJyAgIAAGiADEJyAgIAAGiADKAIAIgZBgICA/AM2AgAgAigCACIMQYCAgPwD
  18675. NgIAIAYgA0EUaigCACADKAIQaiIKQQJ0akGAgID8AzYCACAMIAJBFGooAgAgAigCEGoiC0ECdGpB
  18676. gICA/AM2AgAgBiAKQQN0akGAgID8AzYCACAMIAtBA3RqQYCAgPwDNgIAIAAgARCVgICAABoPCyAH
  18677. Q/MEtT+VIQ1D8wS1PyAHlSEHAkAgBkUNACAAKAIQQQJ0IQogASgCEEECdCELIABBFGooAgBBAnQh
  18678. DiABQRRqKAIAQQJ0IQ8gACgCACEGIAEoAgAhDANAIAYgByAMKgIAIAmTlDgCACAGIApqIAcgDCAL
  18679. aioCACAIk5Q4AgAgBiAOaiEGIAwgD2ohDCAEQX9qIgQNAAsLIAIoAgAiBiAHOAIAIAYgAkEUaigC
  18680. ACIMQQJ0akEANgIAIAYgDEEDdGogCSAHjCIFlDgCACAGIAIoAhAiCkECdGpBADYCACAGIAogDGoi
  18681. C0ECdGogBzgCACAGIAogDEEBdGpBAnRqIAggBZQ4AgAgBiAKQQN0akEANgIAIAYgDCAKQQF0akEC
  18682. dGpBADYCACAGIAtBA3RqQYCAgPwDNgIAIAMoAgAiBiANOAIAIAYgA0EUaigCACIMQQJ0akEANgIA
  18683. IAYgDEEDdGogCTgCACAGIAMoAhAiCkECdGpBADYCACAGIAogDGoiC0ECdGogDTgCACAGIAogDEEB
  18684. dGpBAnRqIAg4AgAgBiAKQQN0akEANgIAIAYgDCAKQQF0akECdGpBADYCACAGIAtBA3RqQYCAgPwD
  18685. NgIACwv2EgMAQYAIC7ISAAD4f091dCBvZiBtZW1vcnkhAERvdWJsZSBmcmVlAEFzc2VydGlvbiBm
  18686. YWlsZWQgYXQgbWF0MzIuYzo2MQBPdXQgb2YgbWVtb3J5IGF0IG1hdDMyLmM6NjMAQXNzZXJ0aW9u
  18687. IGZhaWxlZCBhdCBtYXQzMi5jOjg0AE91dCBvZiBtZW1vcnkgYXQgbWF0MzIuYzo4NgBPdXQgb2Yg
  18688. bWVtb3J5IGF0IG1hdDMyLmM6ODkAT3V0IG9mIG1lbW9yeSBhdCBtYXQzMi5jOjEzNgAAAGANAAAB
  18689. AAAAAAAAAAAAAAABAAAAAQAAAAIAAABEb3VibGUgZnJlZSBhdCBtYXQzMi5jOjE0OQBBc3NlcnRp
  18690. b24gZmFpbGVkIGF0IG1hdDMyLmM6MTg0AEFzc2VydGlvbiBmYWlsZWQgYXQgbWF0MzIuYzoxODgA
  18691. QXNzZXJ0aW9uIGZhaWxlZCBhdCBtYXQzMi5jOjI3NQBEb3VibGUgZnJlZSBhdCBtYXQzMi5jOjI5
  18692. AEFzc2VydGlvbiBmYWlsZWQgYXQgYXJpdGhtZXRpYzMyLmM6MzYAQXNzZXJ0aW9uIGZhaWxlZCBh
  18693. dCBhcml0aG1ldGljMzIuYzo1OABBc3NlcnRpb24gZmFpbGVkIGF0IGFyaXRobWV0aWMzMi5jOjgw
  18694. AEFzc2VydGlvbiBmYWlsZWQgYXQgYXJpdGhtZXRpYzMyLmM6OTkAQXNzZXJ0aW9uIGZhaWxlZCBh
  18695. dCBhcml0aG1ldGljMzIuYzoxMjEAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGljMzIuYzox
  18696. NDMAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGljMzIuYzoxNjgAQXNzZXJ0aW9uIGZhaWxl
  18697. ZCBhdCBhcml0aG1ldGljMzIuYzoxODkAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGljMzIu
  18698. YzoyMTgAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGljMzIuYzoyNzEAQXNzZXJ0aW9uIGZh
  18699. aWxlZCBhdCBhcml0aG1ldGljMzIuYzozMjIAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGlj
  18700. MzIuYzozNTYAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1ldGljMzIuYzozNzgAQXNzZXJ0aW9u
  18701. IGZhaWxlZCBhdCBhcml0aG1ldGljMzIuYzo0MjAAQXNzZXJ0aW9uIGZhaWxlZCBhdCBhcml0aG1l
  18702. dGljMzIuYzo0MzYAQXNzZXJ0aW9uIGZhaWxlZCBhdCBxcjMyLmM6MjYxAEFzc2VydGlvbiBmYWls
  18703. ZWQgYXQgcXIzMi5jOjI2NQBBc3NlcnRpb24gZmFpbGVkIGF0IHFyMzIuYzoyODYAQXNzZXJ0aW9u
  18704. IGZhaWxlZCBhdCBxcjMyLmM6MjkwAEFzc2VydGlvbiBmYWlsZWQgYXQgcXIzMi5jOjMyMQBBc3Nl
  18705. cnRpb24gZmFpbGVkIGF0IHFyMzIuYzozMjUAQXNzZXJ0aW9uIGZhaWxlZCBhdCBxcjMyLmM6Mzc5
  18706. AE91dCBvZiBtZW1vcnkgYXQgcXIzMi5jOjM2AEFzc2VydGlvbiBmYWlsZWQgYXQgcXIzMi5jOjY5
  18707. AEFzc2VydGlvbiBmYWlsZWQgYXQgcXIzMi5jOjczAEFzc2VydGlvbiBmYWlsZWQgYXQgcXIzMi5j
  18708. OjE4NABEb3VibGUgZnJlZSBhdCBxcjMyLmM6NTUAQXNzZXJ0aW9uIGZhaWxlZCBhdCBxcjMyLmM6
  18709. MTQ4AEFzc2VydGlvbiBmYWlsZWQgYXQgcXIzMi5jOjIyNABBc3NlcnRpb24gZmFpbGVkIGF0IHFy
  18710. MzIuYzoyMjgAQXNzZXJ0aW9uIGZhaWxlZCBhdCBob21vZ3JhcGh5MzIuYzoyNDQAQXNzZXJ0aW9u
  18711. IGZhaWxlZCBhdCBob21vZ3JhcGh5MzIuYzoyODAAQXNzZXJ0aW9uIGZhaWxlZCBhdCBob21vZ3Jh
  18712. cGh5MzIuYzozNTkAQXNzZXJ0aW9uIGZhaWxlZCBhdCBob21vZ3JhcGh5MzIuYzo0NDQAQXNzZXJ0
  18713. aW9uIGZhaWxlZCBhdCBhZmZpbmUzMi5jOjExOQBBc3NlcnRpb24gZmFpbGVkIGF0IGFmZmluZTMy
  18714. LmM6MTk2AEFzc2VydGlvbiBmYWlsZWQgYXQgYWZmaW5lMzIuYzoyMjkAQXNzZXJ0aW9uIGZhaWxl
  18715. ZCBhdCByYW5zYWMzMi5jOjcxAE91dCBvZiBtZW1vcnkgYXQgcmFuc2FjMzIuYzo4NABPdXQgb2Yg
  18716. bWVtb3J5IGF0IHJhbnNhYzMyLmM6ODgAT3V0IG9mIG1lbW9yeSBhdCByYW5zYWMzMi5jOjkzAE91
  18717. dCBvZiBtZW1vcnkgYXQgcmFuc2FjMzIuYzoxMDcARG91YmxlIGZyZWUgYXQgcmFuc2FjMzIuYzoy
  18718. MzYARG91YmxlIGZyZWUgYXQgcmFuc2FjMzIuYzoyNDMARG91YmxlIGZyZWUgYXQgcmFuc2FjMzIu
  18719. YzoyNDYARG91YmxlIGZyZWUgYXQgcmFuc2FjMzIuYzoyNDkAQXNzZXJ0aW9uIGZhaWxlZCBhdCBy
  18720. YW5zYWMzMi5jOjI3NQBPdXQgb2YgbWVtb3J5IGF0IHJhbnNhYzMyLmM6Mjg4AE91dCBvZiBtZW1v
  18721. cnkgYXQgcmFuc2FjMzIuYzoyOTIAT3V0IG9mIG1lbW9yeSBhdCByYW5zYWMzMi5jOjI5NwBPdXQg
  18722. b2YgbWVtb3J5IGF0IHJhbnNhYzMyLmM6MzExAERvdWJsZSBmcmVlIGF0IHJhbnNhYzMyLmM6NDM2
  18723. AERvdWJsZSBmcmVlIGF0IHJhbnNhYzMyLmM6NDQzAERvdWJsZSBmcmVlIGF0IHJhbnNhYzMyLmM6
  18724. NDQ2AERvdWJsZSBmcmVlIGF0IHJhbnNhYzMyLmM6NDQ5AEFzc2VydGlvbiBmYWlsZWQgYXQgdHJh
  18725. bnNmb3JtMzIuYzozOQBBc3NlcnRpb24gZmFpbGVkIGF0IHRyYW5zZm9ybTMyLmM6NzcAQXNzZXJ0
  18726. aW9uIGZhaWxlZCBhdCB0cmFuc2Zvcm0zMi5jOjExNAAAQbQaCwwIAAAAUA0AAAEAAAAAQcAaCyQA
  18727. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  18728. `
  18729. /***/ })
  18730. /******/ });
  18731. /************************************************************************/
  18732. /******/ // The module cache
  18733. /******/ var __webpack_module_cache__ = {};
  18734. /******/
  18735. /******/ // The require function
  18736. /******/ function __nested_webpack_require_962272__(moduleId) {
  18737. /******/ // Check if module is in cache
  18738. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  18739. /******/ if (cachedModule !== undefined) {
  18740. /******/ return cachedModule.exports;
  18741. /******/ }
  18742. /******/ // Create a new module (and put it into the cache)
  18743. /******/ var module = __webpack_module_cache__[moduleId] = {
  18744. /******/ // no module.id needed
  18745. /******/ // no module.loaded needed
  18746. /******/ exports: {}
  18747. /******/ };
  18748. /******/
  18749. /******/ // Execute the module function
  18750. /******/ __webpack_modules__[moduleId](module, module.exports, __nested_webpack_require_962272__);
  18751. /******/
  18752. /******/ // Return the exports of the module
  18753. /******/ return module.exports;
  18754. /******/ }
  18755. /******/
  18756. /************************************************************************/
  18757. /******/ /* webpack/runtime/define property getters */
  18758. /******/ (() => {
  18759. /******/ // define getter functions for harmony exports
  18760. /******/ __nested_webpack_require_962272__.d = (exports, definition) => {
  18761. /******/ for(var key in definition) {
  18762. /******/ if(__nested_webpack_require_962272__.o(definition, key) && !__nested_webpack_require_962272__.o(exports, key)) {
  18763. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  18764. /******/ }
  18765. /******/ }
  18766. /******/ };
  18767. /******/ })();
  18768. /******/
  18769. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  18770. /******/ (() => {
  18771. /******/ __nested_webpack_require_962272__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  18772. /******/ })();
  18773. /******/
  18774. /******/ /* webpack/runtime/make namespace object */
  18775. /******/ (() => {
  18776. /******/ // define __esModule on exports
  18777. /******/ __nested_webpack_require_962272__.r = (exports) => {
  18778. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  18779. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  18780. /******/ }
  18781. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  18782. /******/ };
  18783. /******/ })();
  18784. /******/
  18785. /************************************************************************/
  18786. var __webpack_exports__ = {};
  18787. // This entry need to be wrapped in an IIFE because it need to be in strict mode.
  18788. (() => {
  18789. "use strict";
  18790. /*!*********************!*\
  18791. !*** ./src/main.js ***!
  18792. \*********************/
  18793. __nested_webpack_require_962272__.r(__webpack_exports__);
  18794. /* harmony export */ __nested_webpack_require_962272__.d(__webpack_exports__, {
  18795. /* harmony export */ "default": () => (/* binding */ Speedy)
  18796. /* harmony export */ });
  18797. /* harmony import */ var _gpu_speedy_gl__WEBPACK_IMPORTED_MODULE_0__ = __nested_webpack_require_962272__(/*! ./gpu/speedy-gl */ "./src/gpu/speedy-gl.js");
  18798. /* harmony import */ var _core_speedy_media__WEBPACK_IMPORTED_MODULE_1__ = __nested_webpack_require_962272__(/*! ./core/speedy-media */ "./src/core/speedy-media.js");
  18799. /* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_2__ = __nested_webpack_require_962272__(/*! ./core/settings */ "./src/core/settings.js");
  18800. /* harmony import */ var _utils_fps_counter__WEBPACK_IMPORTED_MODULE_3__ = __nested_webpack_require_962272__(/*! ./utils/fps-counter */ "./src/utils/fps-counter.js");
  18801. /* harmony import */ var _core_speedy_vector__WEBPACK_IMPORTED_MODULE_4__ = __nested_webpack_require_962272__(/*! ./core/speedy-vector */ "./src/core/speedy-vector.js");
  18802. /* harmony import */ var _core_speedy_point__WEBPACK_IMPORTED_MODULE_5__ = __nested_webpack_require_962272__(/*! ./core/speedy-point */ "./src/core/speedy-point.js");
  18803. /* harmony import */ var _core_speedy_size__WEBPACK_IMPORTED_MODULE_6__ = __nested_webpack_require_962272__(/*! ./core/speedy-size */ "./src/core/speedy-size.js");
  18804. /* harmony import */ var _core_speedy_matrix_factory__WEBPACK_IMPORTED_MODULE_7__ = __nested_webpack_require_962272__(/*! ./core/speedy-matrix-factory */ "./src/core/speedy-matrix-factory.js");
  18805. /* harmony import */ var _core_speedy_promise__WEBPACK_IMPORTED_MODULE_8__ = __nested_webpack_require_962272__(/*! ./core/speedy-promise */ "./src/core/speedy-promise.js");
  18806. /* harmony import */ var _core_pipeline_pipeline__WEBPACK_IMPORTED_MODULE_9__ = __nested_webpack_require_962272__(/*! ./core/pipeline/pipeline */ "./src/core/pipeline/pipeline.js");
  18807. /* harmony import */ var _core_pipeline_factories_image_factory__WEBPACK_IMPORTED_MODULE_10__ = __nested_webpack_require_962272__(/*! ./core/pipeline/factories/image-factory */ "./src/core/pipeline/factories/image-factory.js");
  18808. /* harmony import */ var _core_pipeline_factories_filter_factory__WEBPACK_IMPORTED_MODULE_11__ = __nested_webpack_require_962272__(/*! ./core/pipeline/factories/filter-factory */ "./src/core/pipeline/factories/filter-factory.js");
  18809. /* harmony import */ var _core_pipeline_factories_transform_factory__WEBPACK_IMPORTED_MODULE_12__ = __nested_webpack_require_962272__(/*! ./core/pipeline/factories/transform-factory */ "./src/core/pipeline/factories/transform-factory.js");
  18810. /* harmony import */ var _core_pipeline_factories_keypoint_factory__WEBPACK_IMPORTED_MODULE_13__ = __nested_webpack_require_962272__(/*! ./core/pipeline/factories/keypoint-factory */ "./src/core/pipeline/factories/keypoint-factory.js");
  18811. /* harmony import */ var _core_pipeline_factories_vector2_factory__WEBPACK_IMPORTED_MODULE_14__ = __nested_webpack_require_962272__(/*! ./core/pipeline/factories/vector2-factory */ "./src/core/pipeline/factories/vector2-factory.js");
  18812. /* harmony import */ var _utils_utils__WEBPACK_IMPORTED_MODULE_15__ = __nested_webpack_require_962272__(/*! ./utils/utils */ "./src/utils/utils.js");
  18813. /* harmony import */ var _utils_globals__WEBPACK_IMPORTED_MODULE_16__ = __nested_webpack_require_962272__(/*! ./utils/globals */ "./src/utils/globals.js");
  18814. /*
  18815. * speedy-vision.js
  18816. * GPU-accelerated Computer Vision for JavaScript
  18817. * Copyright 2020-2022 Alexandre Martins <alemartf(at)gmail.com>
  18818. *
  18819. * Licensed under the Apache License, Version 2.0 (the "License");
  18820. * you may not use this file except in compliance with the License.
  18821. * You may obtain a copy of the License at
  18822. *
  18823. * http://www.apache.org/licenses/LICENSE-2.0
  18824. *
  18825. * Unless required by applicable law or agreed to in writing, software
  18826. * distributed under the License is distributed on an "AS IS" BASIS,
  18827. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18828. * See the License for the specific language governing permissions and
  18829. * limitations under the License.
  18830. *
  18831. * main.js
  18832. * The entry point of the library
  18833. */
  18834. /* eslint-disable no-undef */
  18835. /** @typedef {import('./core/speedy-matrix').SpeedyMatrix} SpeedyMatrix */
  18836. /** @typedef {import('./core/speedy-matrix-expr').SpeedyMatrixExpr} SpeedyMatrixExpr */
  18837. /** @typedef {import('./core/speedy-media').SpeedyMediaOptions} SpeedyMediaOptions */
  18838. /** @typedef {import('./core/speedy-media-source').SpeedyMediaSourceNativeElement} SpeedyMediaSourceNativeElement */
  18839. // Constants
  18840. /** @type {SpeedyMatrixFactory} */
  18841. const matrixFactory = new _core_speedy_matrix_factory__WEBPACK_IMPORTED_MODULE_7__.SpeedyMatrixFactory();
  18842. /** @type {SpeedyPipelineVector2Factory} */
  18843. const vector2Factory = new _core_pipeline_factories_vector2_factory__WEBPACK_IMPORTED_MODULE_14__.SpeedyPipelineVector2Factory();
  18844. /**
  18845. * GPU-accelerated Computer Vision for JavaScript
  18846. */
  18847. class Speedy
  18848. {
  18849. /**
  18850. * Loads a SpeedyMedia object based on the provided source element
  18851. * @param {SpeedyMediaSourceNativeElement} sourceElement The source media
  18852. * @param {SpeedyMediaOptions} [options] Additional options for advanced configuration
  18853. * @returns {SpeedyPromise<SpeedyMedia>}
  18854. */
  18855. static load(sourceElement, options = {})
  18856. {
  18857. return _core_speedy_media__WEBPACK_IMPORTED_MODULE_1__.SpeedyMedia.load(sourceElement, options);
  18858. }
  18859. /**
  18860. * Loads a camera stream
  18861. * @param {number | MediaStreamConstraints} [widthOrConstraints] width of the stream or contraints object
  18862. * @param {number} [height] height of the stream
  18863. * @returns {SpeedyPromise<SpeedyMedia>}
  18864. */
  18865. static camera(widthOrConstraints = 640, height = 360)
  18866. {
  18867. const constraints = (typeof(widthOrConstraints) === 'object') ? widthOrConstraints : ({
  18868. audio: false,
  18869. video: {
  18870. width: widthOrConstraints | 0,
  18871. height: height | 0,
  18872. },
  18873. });
  18874. return _utils_utils__WEBPACK_IMPORTED_MODULE_15__.Utils.requestCameraStream(constraints).then(
  18875. video => _core_speedy_media__WEBPACK_IMPORTED_MODULE_1__.SpeedyMedia.load(video)
  18876. );
  18877. }
  18878. /**
  18879. * Checks if Speedy can be executed in this machine & browser
  18880. * @returns {boolean} true if Speedy can be executed in this machine & browser
  18881. */
  18882. static isSupported()
  18883. {
  18884. return (
  18885. (typeof WebAssembly !== 'undefined') &&
  18886. (typeof WebGL2RenderingContext !== 'undefined') &&
  18887. (_gpu_speedy_gl__WEBPACK_IMPORTED_MODULE_0__.SpeedyGL.instance.gl != null)
  18888. );
  18889. }
  18890. /**
  18891. * Create a 2D vector
  18892. * @returns {SpeedyPipelineVector2Factory & ((x: number, y: number) => SpeedyVector2)}
  18893. */
  18894. static get Vector2()
  18895. {
  18896. return vector2Factory;
  18897. }
  18898. /**
  18899. * Create a 2D point
  18900. * @param {number} x
  18901. * @param {number} y
  18902. * @returns {SpeedyPoint2}
  18903. */
  18904. static Point2(x, y)
  18905. {
  18906. return new _core_speedy_point__WEBPACK_IMPORTED_MODULE_5__.SpeedyPoint2(x, y);
  18907. }
  18908. /**
  18909. * Create a new size object
  18910. * @param {number} width
  18911. * @param {number} height
  18912. * @returns {SpeedySize}
  18913. */
  18914. static Size(width, height)
  18915. {
  18916. return new _core_speedy_size__WEBPACK_IMPORTED_MODULE_6__.SpeedySize(width, height);
  18917. }
  18918. /**
  18919. * Create a Matrix (entries are given in column-major format)
  18920. * @returns {SpeedyMatrixFactory & ((rows: number, columns: number, entries: number[]) => SpeedyMatrix) & ((expr: SpeedyMatrixExpr) => SpeedyMatrix)}
  18921. */
  18922. static get Matrix()
  18923. {
  18924. return matrixFactory;
  18925. }
  18926. /**
  18927. * Speedy Promises
  18928. * @returns {typeof SpeedyPromise}
  18929. */
  18930. static get Promise()
  18931. {
  18932. return _core_speedy_promise__WEBPACK_IMPORTED_MODULE_8__.SpeedyPromise;
  18933. }
  18934. /**
  18935. * Create a new Pipeline
  18936. * @returns {SpeedyPipeline}
  18937. */
  18938. static Pipeline()
  18939. {
  18940. return new _core_pipeline_pipeline__WEBPACK_IMPORTED_MODULE_9__.SpeedyPipeline();
  18941. }
  18942. /**
  18943. * Image-related nodes
  18944. * @returns {typeof SpeedyPipelineImageFactory}
  18945. */
  18946. static get Image()
  18947. {
  18948. return _core_pipeline_factories_image_factory__WEBPACK_IMPORTED_MODULE_10__.SpeedyPipelineImageFactory;
  18949. }
  18950. /**
  18951. * Image filters
  18952. * @returns {typeof SpeedyPipelineFilterFactory}
  18953. */
  18954. static get Filter()
  18955. {
  18956. return _core_pipeline_factories_filter_factory__WEBPACK_IMPORTED_MODULE_11__.SpeedyPipelineFilterFactory;
  18957. }
  18958. /**
  18959. * Image transforms
  18960. * @returns {typeof SpeedyPipelineTransformFactory}
  18961. */
  18962. static get Transform()
  18963. {
  18964. return _core_pipeline_factories_transform_factory__WEBPACK_IMPORTED_MODULE_12__.SpeedyPipelineTransformFactory;
  18965. }
  18966. /**
  18967. * Keypoint-related nodes
  18968. * @returns {typeof SpeedyPipelineKeypointFactory}
  18969. */
  18970. static get Keypoint()
  18971. {
  18972. return _core_pipeline_factories_keypoint_factory__WEBPACK_IMPORTED_MODULE_13__.SpeedyPipelineKeypointFactory;
  18973. }
  18974. /**
  18975. * The version of the library
  18976. * @returns {string} The version of the library
  18977. */
  18978. static get version()
  18979. {
  18980. if(true)
  18981. return "0.9.0-wip" + '-dev';
  18982. else
  18983. {}
  18984. }
  18985. /**
  18986. * The FPS rate
  18987. * @returns {number} Frames per second (FPS)
  18988. */
  18989. static get fps()
  18990. {
  18991. return _utils_fps_counter__WEBPACK_IMPORTED_MODULE_3__.FPSCounter.instance.fps;
  18992. }
  18993. /**
  18994. * Global settings
  18995. * @returns {typeof Settings}
  18996. */
  18997. static get Settings()
  18998. {
  18999. return _core_settings__WEBPACK_IMPORTED_MODULE_2__.Settings;
  19000. }
  19001. }
  19002. // Freeze the namespace
  19003. Object.freeze(Speedy);
  19004. // Display a notice
  19005. _utils_utils__WEBPACK_IMPORTED_MODULE_15__.Utils.log(
  19006. `Speedy Vision version ${Speedy.version}. ` +
  19007. `GPU-accelerated Computer Vision for JavaScript by Alexandre Martins. ` +
  19008. "https://github.com/alemart/speedy-vision"
  19009. );
  19010. // Big-endian machine? Currently untested.
  19011. if(!_utils_globals__WEBPACK_IMPORTED_MODULE_16__.LITTLE_ENDIAN)
  19012. _utils_utils__WEBPACK_IMPORTED_MODULE_15__.Utils.warning('Running on a big-endian machine');
  19013. })();
  19014. __webpack_exports__ = __webpack_exports__["default"];
  19015. /******/ return __webpack_exports__;
  19016. /******/ })()
  19017. ;
  19018. });
  19019. //# sourceMappingURL=speedy-vision.js.map
  19020. /***/ })
  19021. /******/ });
  19022. /************************************************************************/
  19023. /******/ // The module cache
  19024. /******/ var __webpack_module_cache__ = {};
  19025. /******/
  19026. /******/ // The require function
  19027. /******/ function __webpack_require__(moduleId) {
  19028. /******/ // Check if module is in cache
  19029. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  19030. /******/ if (cachedModule !== undefined) {
  19031. /******/ return cachedModule.exports;
  19032. /******/ }
  19033. /******/ // Create a new module (and put it into the cache)
  19034. /******/ var module = __webpack_module_cache__[moduleId] = {
  19035. /******/ // no module.id needed
  19036. /******/ // no module.loaded needed
  19037. /******/ exports: {}
  19038. /******/ };
  19039. /******/
  19040. /******/ // Execute the module function
  19041. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  19042. /******/
  19043. /******/ // Return the exports of the module
  19044. /******/ return module.exports;
  19045. /******/ }
  19046. /******/
  19047. /************************************************************************/
  19048. /******/ /* webpack/runtime/compat get default export */
  19049. /******/ (() => {
  19050. /******/ // getDefaultExport function for compatibility with non-harmony modules
  19051. /******/ __webpack_require__.n = (module) => {
  19052. /******/ var getter = module && module.__esModule ?
  19053. /******/ () => (module['default']) :
  19054. /******/ () => (module);
  19055. /******/ __webpack_require__.d(getter, { a: getter });
  19056. /******/ return getter;
  19057. /******/ };
  19058. /******/ })();
  19059. /******/
  19060. /******/ /* webpack/runtime/define property getters */
  19061. /******/ (() => {
  19062. /******/ // define getter functions for harmony exports
  19063. /******/ __webpack_require__.d = (exports, definition) => {
  19064. /******/ for(var key in definition) {
  19065. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  19066. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  19067. /******/ }
  19068. /******/ }
  19069. /******/ };
  19070. /******/ })();
  19071. /******/
  19072. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  19073. /******/ (() => {
  19074. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  19075. /******/ })();
  19076. /******/
  19077. /************************************************************************/
  19078. var __webpack_exports__ = {};
  19079. // This entry need to be wrapped in an IIFE because it need to be in strict mode.
  19080. (() => {
  19081. "use strict";
  19082. // EXPORTS
  19083. __webpack_require__.d(__webpack_exports__, {
  19084. "default": () => (/* binding */ Martins)
  19085. });
  19086. // EXTERNAL MODULE: ./node_modules/speedy-vision/dist/speedy-vision.js
  19087. var speedy_vision = __webpack_require__(528);
  19088. var speedy_vision_default = /*#__PURE__*/__webpack_require__.n(speedy_vision);
  19089. ;// CONCATENATED MODULE: ./src/utils/errors.ts
  19090. /*
  19091. * MARTINS.js Free Edition
  19092. * GPU-accelerated Augmented Reality for the web
  19093. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19094. * https://github.com/alemart/martins-js
  19095. *
  19096. * This program is free software: you can redistribute it and/or modify
  19097. * it under the terms of the GNU Affero General Public License version 3
  19098. * as published by the Free Software Foundation.
  19099. *
  19100. * This program is distributed in the hope that it will be useful,
  19101. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19102. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19103. * GNU Affero General Public License for more details.
  19104. *
  19105. * You should have received a copy of the GNU Affero General Public License
  19106. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19107. *
  19108. * errors.ts
  19109. * Error classes
  19110. */
  19111. /**
  19112. * Generic error class
  19113. */
  19114. class MartinsError extends Error {
  19115. /**
  19116. * Constructor
  19117. * @param message error message
  19118. * @param cause optional error cause
  19119. */
  19120. constructor(message = '', cause = null) {
  19121. super(`${message}\n${cause ? cause.toString() : ''}`);
  19122. this.cause = cause;
  19123. }
  19124. /**
  19125. * Error name
  19126. */
  19127. get name() {
  19128. return this.constructor.name;
  19129. }
  19130. }
  19131. /**
  19132. * A method has received one or more illegal arguments
  19133. */
  19134. class IllegalArgumentError extends MartinsError {
  19135. }
  19136. /**
  19137. * The method arguments are valid, but the method can't be called due to the
  19138. * current state of the object
  19139. */
  19140. class IllegalOperationError extends MartinsError {
  19141. }
  19142. /**
  19143. * The requested operation is not supported
  19144. */
  19145. class NotSupportedError extends MartinsError {
  19146. }
  19147. /**
  19148. * Access denied
  19149. */
  19150. class AccessDeniedError extends MartinsError {
  19151. }
  19152. /**
  19153. * Assertion error
  19154. */
  19155. class AssertionError extends MartinsError {
  19156. }
  19157. /**
  19158. * Tracking error
  19159. */
  19160. class TrackingError extends MartinsError {
  19161. }
  19162. /**
  19163. * Detection error
  19164. */
  19165. class DetectionError extends MartinsError {
  19166. }
  19167. /**
  19168. * Training error
  19169. */
  19170. class TrainingError extends MartinsError {
  19171. }
  19172. ;// CONCATENATED MODULE: ./src/core/resolution.ts
  19173. /*
  19174. * MARTINS.js Free Edition
  19175. * GPU-accelerated Augmented Reality for the web
  19176. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19177. * https://github.com/alemart/martins-js
  19178. *
  19179. * This program is free software: you can redistribute it and/or modify
  19180. * it under the terms of the GNU Affero General Public License version 3
  19181. * as published by the Free Software Foundation.
  19182. *
  19183. * This program is distributed in the hope that it will be useful,
  19184. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19185. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19186. * GNU Affero General Public License for more details.
  19187. *
  19188. * You should have received a copy of the GNU Affero General Public License
  19189. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19190. *
  19191. * resolution.ts
  19192. * Resolution utilities
  19193. */
  19194. /** Reference heights when in landscape mode, measured in pixels */
  19195. const REFERENCE_HEIGHT = {
  19196. 'xs': 120,
  19197. 'xs+': 160,
  19198. 'sm': 200,
  19199. 'sm+': 240,
  19200. 'md': 320,
  19201. 'md+': 360,
  19202. 'lg': 480,
  19203. 'lg+': 600,
  19204. };
  19205. /**
  19206. * Convert a resolution type to a (width, height) pair
  19207. * @param resolution resolution type
  19208. * @param aspectRatio desired width / height ratio
  19209. * @returns size in pixels
  19210. */
  19211. function computeResolution(resolution, aspectRatio) {
  19212. const referenceHeight = REFERENCE_HEIGHT[resolution];
  19213. let width = 0, height = 0;
  19214. if (aspectRatio >= 1) {
  19215. // landscape
  19216. height = referenceHeight;
  19217. width = Math.round(height * aspectRatio);
  19218. width -= width % 2;
  19219. }
  19220. else {
  19221. // portrait
  19222. width = referenceHeight;
  19223. height = Math.round(width / aspectRatio);
  19224. height -= height % 2;
  19225. }
  19226. return speedy_vision_default().Size(width, height);
  19227. }
  19228. ;// CONCATENATED MODULE: ./src/utils/utils.ts
  19229. /*
  19230. * MARTINS.js Free Edition
  19231. * GPU-accelerated Augmented Reality for the web
  19232. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19233. * https://github.com/alemart/martins-js
  19234. *
  19235. * This program is free software: you can redistribute it and/or modify
  19236. * it under the terms of the GNU Affero General Public License version 3
  19237. * as published by the Free Software Foundation.
  19238. *
  19239. * This program is distributed in the hope that it will be useful,
  19240. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19241. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19242. * GNU Affero General Public License for more details.
  19243. *
  19244. * You should have received a copy of the GNU Affero General Public License
  19245. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19246. *
  19247. * utils.ts
  19248. * Generic utilities
  19249. */
  19250. /**
  19251. * Generic utilities
  19252. */
  19253. class Utils {
  19254. /**
  19255. * Log a message
  19256. * @param message
  19257. * @param args optional additional messages
  19258. */
  19259. static log(message, ...args) {
  19260. console.log('[martins-js]', message, ...args);
  19261. }
  19262. /**
  19263. * Display a warning
  19264. * @param message
  19265. * @param args optional additional messages
  19266. */
  19267. static warning(message, ...args) {
  19268. console.warn('[martins-js]', message, ...args);
  19269. }
  19270. /**
  19271. * Display an error message
  19272. * @param message
  19273. * @param args optional additional messages
  19274. */
  19275. static error(message, ...args) {
  19276. console.error('[martins-js]', message, ...args);
  19277. }
  19278. /**
  19279. * Assertion
  19280. * @param expr expression
  19281. * @param errorMessage optional error message
  19282. * @throws {AssertionError}
  19283. */
  19284. static assert(expr, errorMessage = '') {
  19285. if (!expr)
  19286. throw new AssertionError(errorMessage);
  19287. }
  19288. /**
  19289. * Returns a range [0, 1, ..., n-1]
  19290. * @param n non-negative integer
  19291. * @returns range from 0 to n-1, inclusive
  19292. */
  19293. static range(n) {
  19294. if ((n |= 0) < 0)
  19295. throw new IllegalArgumentError();
  19296. return Array.from({ length: n }, (_, i) => i);
  19297. }
  19298. /**
  19299. * Convert a resolution type to a resolution measured in pixels
  19300. * @param resolution resolution type
  19301. * @param aspectRatio width / height ratio
  19302. * @returns resolution measured in pixels
  19303. */
  19304. static resolution(resolution, aspectRatio) {
  19305. return computeResolution(resolution, aspectRatio);
  19306. }
  19307. }
  19308. ;// CONCATENATED MODULE: ./src/utils/ar-events.ts
  19309. /*
  19310. * MARTINS.js Free Edition
  19311. * GPU-accelerated Augmented Reality for the web
  19312. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19313. * https://github.com/alemart/martins-js
  19314. *
  19315. * This program is free software: you can redistribute it and/or modify
  19316. * it under the terms of the GNU Affero General Public License version 3
  19317. * as published by the Free Software Foundation.
  19318. *
  19319. * This program is distributed in the hope that it will be useful,
  19320. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19321. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19322. * GNU Affero General Public License for more details.
  19323. *
  19324. * You should have received a copy of the GNU Affero General Public License
  19325. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19326. *
  19327. * ar-events.ts
  19328. * AR-related Events
  19329. */
  19330. /**
  19331. * AR Event
  19332. */
  19333. class AREvent extends Event {
  19334. /**
  19335. * Constructor
  19336. * @param type event type
  19337. */
  19338. constructor(type) {
  19339. super(type);
  19340. }
  19341. /**
  19342. * Event type
  19343. */
  19344. get type() {
  19345. return super.type;
  19346. }
  19347. }
  19348. /**
  19349. * AR Event Target
  19350. */
  19351. class AREventTarget {
  19352. /**
  19353. * Constructor
  19354. */
  19355. constructor() {
  19356. this._delegate = new EventTarget();
  19357. }
  19358. /**
  19359. * Add event listener
  19360. * @param type event type
  19361. * @param callback
  19362. */
  19363. addEventListener(type, callback) {
  19364. this._delegate.addEventListener(type, callback);
  19365. }
  19366. /**
  19367. * Remove event listener
  19368. * @param type event type
  19369. * @param callback
  19370. */
  19371. removeEventListener(type, callback) {
  19372. this._delegate.removeEventListener(type, callback);
  19373. }
  19374. /**
  19375. * Synchronously trigger an event
  19376. * @param event
  19377. * @returns same value as a standard event target
  19378. * @internal
  19379. */
  19380. dispatchEvent(event) {
  19381. return this._delegate.dispatchEvent(event);
  19382. }
  19383. }
  19384. ;// CONCATENATED MODULE: ./src/core/hud.ts
  19385. /*
  19386. * MARTINS.js Free Edition
  19387. * GPU-accelerated Augmented Reality for the web
  19388. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19389. * https://github.com/alemart/martins-js
  19390. *
  19391. * This program is free software: you can redistribute it and/or modify
  19392. * it under the terms of the GNU Affero General Public License version 3
  19393. * as published by the Free Software Foundation.
  19394. *
  19395. * This program is distributed in the hope that it will be useful,
  19396. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19397. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19398. * GNU Affero General Public License for more details.
  19399. *
  19400. * You should have received a copy of the GNU Affero General Public License
  19401. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19402. *
  19403. * hud.ts
  19404. * Heads Up Display
  19405. */
  19406. /**
  19407. * Heads Up Display: an overlay displayed in front of the augmented scene
  19408. */
  19409. class HUD {
  19410. /**
  19411. * Constructor
  19412. * @param parent parent of the hud container
  19413. * @param hudContainer an existing hud container (optional)
  19414. */
  19415. constructor(parent, hudContainer) {
  19416. this._container = hudContainer || this._createContainer(parent);
  19417. this._ownContainer = (hudContainer == null);
  19418. // validate
  19419. if (this._container.parentElement !== parent)
  19420. throw new IllegalArgumentError('The container of the HUD must be a direct child of the container of the viewport');
  19421. // the HUD should be hidden initially
  19422. if (!this._container.hidden)
  19423. Utils.warning(`The container of the HUD should have the hidden attribute`);
  19424. }
  19425. /**
  19426. * The container of the HUD
  19427. */
  19428. get container() {
  19429. return this._container;
  19430. }
  19431. /**
  19432. * Whether or not the HUD is visible
  19433. */
  19434. get visible() {
  19435. return !this._container.hidden;
  19436. }
  19437. /**
  19438. * Whether or not the HUD is visible
  19439. */
  19440. set visible(visible) {
  19441. this._container.hidden = !visible;
  19442. }
  19443. /**
  19444. * Initialize the HUD
  19445. * @param zIndex the z-index of the container
  19446. * @internal
  19447. */
  19448. _init(zIndex) {
  19449. const container = this._container;
  19450. container.style.position = 'absolute';
  19451. container.style.left = container.style.top = '0px';
  19452. container.style.right = container.style.bottom = '0px';
  19453. container.style.padding = container.style.margin = '0px';
  19454. container.style.zIndex = String(zIndex);
  19455. container.style.userSelect = 'none';
  19456. }
  19457. /**
  19458. * Release the HUD
  19459. * @internal
  19460. */
  19461. _release() {
  19462. if (this._ownContainer) {
  19463. this._ownContainer = false;
  19464. this._container.remove();
  19465. }
  19466. }
  19467. /**
  19468. * Create a HUD container as an immediate child of the input node
  19469. * @param parent parent container
  19470. * @returns HUD container
  19471. */
  19472. _createContainer(parent) {
  19473. const node = document.createElement('div');
  19474. node.hidden = true;
  19475. parent.appendChild(node);
  19476. return node;
  19477. }
  19478. }
  19479. ;// CONCATENATED MODULE: ./src/core/viewport.ts
  19480. /*
  19481. * MARTINS.js Free Edition
  19482. * GPU-accelerated Augmented Reality for the web
  19483. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19484. * https://github.com/alemart/martins-js
  19485. *
  19486. * This program is free software: you can redistribute it and/or modify
  19487. * it under the terms of the GNU Affero General Public License version 3
  19488. * as published by the Free Software Foundation.
  19489. *
  19490. * This program is distributed in the hope that it will be useful,
  19491. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19492. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19493. * GNU Affero General Public License for more details.
  19494. *
  19495. * You should have received a copy of the GNU Affero General Public License
  19496. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19497. *
  19498. * viewport.ts
  19499. * Viewport
  19500. */
  19501. /** An event emitted by a Viewport */
  19502. class ViewportEvent extends AREvent {
  19503. }
  19504. /** Default viewport constructor settings */
  19505. const DEFAULT_VIEWPORT_SETTINGS = {
  19506. container: null,
  19507. hudContainer: null,
  19508. resolution: 'lg',
  19509. canvas: null,
  19510. };
  19511. /** Base z-index of the children of the viewport container */
  19512. const BASE_ZINDEX = 0;
  19513. /** Default viewport width, in pixels */
  19514. const DEFAULT_VIEWPORT_WIDTH = 300;
  19515. /** Default viewport height, in pixels */
  19516. const DEFAULT_VIEWPORT_HEIGHT = 150;
  19517. /**
  19518. * Viewport
  19519. */
  19520. class BaseViewport extends AREventTarget {
  19521. /**
  19522. * Constructor
  19523. * @param viewportSettings
  19524. */
  19525. constructor(viewportSettings) {
  19526. super();
  19527. // validate settings
  19528. const settings = Object.assign({}, DEFAULT_VIEWPORT_SETTINGS, viewportSettings);
  19529. if (settings.container == null)
  19530. throw new IllegalArgumentError('Unspecified viewport container');
  19531. // initialize attributes
  19532. this._resolution = settings.resolution;
  19533. this._container = settings.container;
  19534. this._hud = new HUD(settings.container, settings.hudContainer);
  19535. this._parentOfImportedForegroundCanvas = settings.canvas ? settings.canvas.parentNode : null;
  19536. // create canvas elements
  19537. const size = speedy_vision_default().Size(DEFAULT_VIEWPORT_WIDTH, DEFAULT_VIEWPORT_HEIGHT);
  19538. this._backgroundCanvas = this._createBackgroundCanvas(this._container, size);
  19539. this._foregroundCanvas = settings.canvas == null ?
  19540. this._createForegroundCanvas(this._container, size) :
  19541. this._foregroundCanvas = this._importForegroundCanvas(settings.canvas, this._container, size);
  19542. }
  19543. /**
  19544. * Viewport container
  19545. */
  19546. get container() {
  19547. return this._container;
  19548. }
  19549. /**
  19550. * HUD
  19551. */
  19552. get hud() {
  19553. return this._hud;
  19554. }
  19555. /**
  19556. * Resolution of the virtual scene
  19557. */
  19558. get resolution() {
  19559. return this._resolution;
  19560. }
  19561. /**
  19562. * Size in pixels of the drawing buffer of the canvas
  19563. * on which the virtual scene will be drawn
  19564. */
  19565. get virtualSize() {
  19566. const aspectRatio = this._backgroundCanvas.width / this._backgroundCanvas.height;
  19567. return Utils.resolution(this._resolution, aspectRatio);
  19568. }
  19569. /**
  19570. * The canvas on which the virtual scene will be drawn
  19571. */
  19572. get canvas() {
  19573. return this._foregroundCanvas;
  19574. }
  19575. /**
  19576. * Background canvas
  19577. * @internal
  19578. */
  19579. get _background() {
  19580. return this._backgroundCanvas;
  19581. }
  19582. /**
  19583. * Size of the drawing buffer of the background canvas, in pixels
  19584. * @internal
  19585. */
  19586. get _size() {
  19587. throw new IllegalOperationError();
  19588. }
  19589. /**
  19590. * Initialize the viewport (when the session starts)
  19591. * @internal
  19592. */
  19593. _init() {
  19594. this._container.style.touchAction = 'none';
  19595. this._hud._init(BASE_ZINDEX + 2);
  19596. this._hud.visible = true;
  19597. }
  19598. /**
  19599. * Release the viewport (when the session starts)
  19600. * @internal
  19601. */
  19602. _release() {
  19603. //this._hud.visible = false; // depends on the type of the viewport
  19604. this._hud._release();
  19605. this._restoreImportedForegroundCanvas();
  19606. this._container.style.touchAction = 'auto';
  19607. }
  19608. /**
  19609. * Function to be called when the viewport is resized
  19610. * @internal
  19611. */
  19612. _onResize() {
  19613. // Resize the drawing buffer of the foreground canvas, so that it
  19614. // matches the desired resolution and the aspect ratio of the
  19615. // background canvas
  19616. const virtualSize = this.virtualSize;
  19617. this._foregroundCanvas.width = virtualSize.width;
  19618. this._foregroundCanvas.height = virtualSize.height;
  19619. this._styleCanvas(this._foregroundCanvas, 'foreground');
  19620. // dispatch event
  19621. const event = new ViewportEvent('resize');
  19622. this.dispatchEvent(event);
  19623. }
  19624. /**
  19625. * Create the background canvas
  19626. * @param parent parent container
  19627. * @param size size of the drawing buffer
  19628. * @returns a new canvas as a child of parent
  19629. */
  19630. _createBackgroundCanvas(parent, size) {
  19631. const canvas = this._createCanvas(parent, size);
  19632. return this._styleCanvas(canvas, 'background');
  19633. }
  19634. /**
  19635. * Create the foreground canvas
  19636. * @param parent parent container
  19637. * @param size size of the drawing buffer
  19638. * @returns a new canvas as a child of parent
  19639. */
  19640. _createForegroundCanvas(parent, size) {
  19641. const canvas = this._createCanvas(parent, size);
  19642. return this._styleCanvas(canvas, 'foreground');
  19643. }
  19644. /**
  19645. * Create a canvas and attach it to another HTML element
  19646. * @param parent parent container
  19647. * @param size size of the drawing buffer
  19648. * @returns a new canvas as a child of parent
  19649. */
  19650. _createCanvas(parent, size) {
  19651. const canvas = document.createElement('canvas');
  19652. canvas.width = size.width;
  19653. canvas.height = size.height;
  19654. parent.appendChild(canvas);
  19655. return canvas;
  19656. }
  19657. /**
  19658. * Add suitable CSS rules to a canvas
  19659. * @param canvas
  19660. * @param canvasType
  19661. * @returns canvas
  19662. */
  19663. _styleCanvas(canvas, canvasType) {
  19664. const offset = (canvasType == 'foreground') ? 1 : 0;
  19665. const zIndex = BASE_ZINDEX + offset;
  19666. canvas.setAttribute('style', [
  19667. 'position: absolute',
  19668. 'left: 0px',
  19669. 'top: 0px',
  19670. 'z-index: ' + String(zIndex),
  19671. 'width: 100% !important',
  19672. 'height: 100% !important',
  19673. ].join('; '));
  19674. return canvas;
  19675. }
  19676. /**
  19677. * Import an existing foreground canvas to the viewport
  19678. * @param canvas existing canvas
  19679. * @param parent parent container
  19680. * @param size size of the drawing buffer
  19681. * @returns the input canvas
  19682. */
  19683. _importForegroundCanvas(canvas, parent, size) {
  19684. if (!(canvas instanceof HTMLCanvasElement))
  19685. throw new IllegalArgumentError(`Not a <canvas>: ${canvas}`);
  19686. // borrow the canvas; add it as a child of the viewport container
  19687. canvas.remove();
  19688. parent.appendChild(canvas);
  19689. canvas.width = size.width;
  19690. canvas.height = size.height;
  19691. canvas.dataset.cssText = canvas.style.cssText; // save CSS
  19692. canvas.style.cssText = ''; // clear CSS
  19693. this._styleCanvas(canvas, 'foreground');
  19694. return canvas;
  19695. }
  19696. /**
  19697. * Restore a previously imported foreground canvas to its original parent
  19698. */
  19699. _restoreImportedForegroundCanvas() {
  19700. // not an imported canvas; nothing to do
  19701. if (this._parentOfImportedForegroundCanvas == null)
  19702. return;
  19703. const canvas = this._foregroundCanvas;
  19704. canvas.style.cssText = canvas.dataset.cssText || ''; // restore CSS
  19705. canvas.remove();
  19706. this._parentOfImportedForegroundCanvas.appendChild(canvas);
  19707. }
  19708. }
  19709. /**
  19710. * Viewport decorator
  19711. */
  19712. class ViewportDecorator extends AREventTarget {
  19713. /**
  19714. * Constructor
  19715. * @param base to be decorated
  19716. * @param getSize size getter
  19717. */
  19718. constructor(base, getSize) {
  19719. super();
  19720. this._base = base;
  19721. this._getSize = getSize;
  19722. }
  19723. /**
  19724. * Viewport container
  19725. */
  19726. get container() {
  19727. return this._base.container;
  19728. }
  19729. /**
  19730. * HUD
  19731. */
  19732. get hud() {
  19733. return this._base.hud;
  19734. }
  19735. /**
  19736. * Resolution of the virtual scene
  19737. */
  19738. get resolution() {
  19739. return this._base.resolution;
  19740. }
  19741. /**
  19742. * Size in pixels of the drawing buffer of the canvas
  19743. * on which the virtual scene will be drawn
  19744. */
  19745. get virtualSize() {
  19746. return this._base.virtualSize;
  19747. }
  19748. /**
  19749. * The canvas on which the virtual scene will be drawn
  19750. */
  19751. get canvas() {
  19752. return this._base.canvas;
  19753. }
  19754. /**
  19755. * Background canvas
  19756. * @internal
  19757. */
  19758. get _background() {
  19759. return this._base._background;
  19760. }
  19761. /**
  19762. * Size of the drawing buffer of the background canvas, in pixels
  19763. * @internal
  19764. */
  19765. get _size() {
  19766. return this._getSize();
  19767. }
  19768. /**
  19769. * Initialize the viewport
  19770. * @internal
  19771. */
  19772. _init() {
  19773. this._base._init();
  19774. }
  19775. /**
  19776. * Release the viewport
  19777. * @internal
  19778. */
  19779. _release() {
  19780. this._base._release();
  19781. }
  19782. /**
  19783. * Function to be called when the viewport is resized
  19784. * @internal
  19785. */
  19786. _onResize() {
  19787. this._base._onResize();
  19788. }
  19789. /**
  19790. * Add event listener
  19791. * @param type event type
  19792. * @param callback
  19793. */
  19794. addEventListener(type, callback) {
  19795. this._base.addEventListener(type, callback);
  19796. }
  19797. /**
  19798. * Remove event listener
  19799. * @param type event type
  19800. * @param callback
  19801. */
  19802. removeEventListener(type, callback) {
  19803. this._base.removeEventListener(type, callback);
  19804. }
  19805. /**
  19806. * Synchronously trigger an event
  19807. * @param event
  19808. * @returns same value as a standard event target
  19809. * @internal
  19810. */
  19811. dispatchEvent(event) {
  19812. return this._base.dispatchEvent(event);
  19813. }
  19814. }
  19815. /**
  19816. * A viewport that watches for page resizes
  19817. */
  19818. class ResizableViewport extends ViewportDecorator {
  19819. /**
  19820. * Constructor
  19821. * @param base to be decorated
  19822. * @param getSize size getter
  19823. */
  19824. constructor(base, getSize) {
  19825. super(base, getSize);
  19826. this._active = false;
  19827. }
  19828. /**
  19829. * Initialize the viewport
  19830. * @internal
  19831. */
  19832. _init() {
  19833. super._init();
  19834. this._active = true;
  19835. // Configure the resize listener. We want the viewport
  19836. // to adjust itself if the phone/screen is resized or
  19837. // changes orientation
  19838. let timeout = null;
  19839. const onresize = () => {
  19840. if (!this._active) {
  19841. window.removeEventListener('resize', onresize);
  19842. return;
  19843. }
  19844. if (timeout !== null)
  19845. clearTimeout(timeout);
  19846. timeout = setTimeout(() => {
  19847. timeout = null;
  19848. this._resize.call(this);
  19849. this._onResize.call(this);
  19850. }, 100);
  19851. };
  19852. window.addEventListener('resize', onresize);
  19853. this._resize();
  19854. this._onResize();
  19855. }
  19856. /**
  19857. * Release the viewport
  19858. * @internal
  19859. */
  19860. _release() {
  19861. this._active = false;
  19862. super._release();
  19863. }
  19864. }
  19865. /**
  19866. * Immersive viewport: it occupies the entire page
  19867. */
  19868. class ImmersiveViewport extends ResizableViewport {
  19869. /**
  19870. * Release the viewport
  19871. * @internal
  19872. */
  19873. _release() {
  19874. this.canvas.remove();
  19875. this._background.remove();
  19876. this.hud.visible = false;
  19877. this.container.style.cssText = ''; // reset CSS
  19878. super._release();
  19879. }
  19880. /**
  19881. * Resize the immersive viewport, so that it occupies the entire page.
  19882. * We respect the aspect ratio of the source media
  19883. */
  19884. _resize() {
  19885. const { width, height } = this._size;
  19886. const viewportSize = speedy_vision_default().Size(0, 0);
  19887. const viewportAspectRatio = width / height;
  19888. const windowSize = speedy_vision_default().Size(window.innerWidth, window.innerHeight);
  19889. const windowAspectRatio = windowSize.width / windowSize.height;
  19890. // figure out the viewport size
  19891. if (viewportAspectRatio <= windowAspectRatio) {
  19892. viewportSize.height = windowSize.height;
  19893. viewportSize.width = (viewportSize.height * viewportAspectRatio) | 0;
  19894. }
  19895. else {
  19896. viewportSize.width = windowSize.width;
  19897. viewportSize.height = (viewportSize.width / viewportAspectRatio) | 0;
  19898. }
  19899. // position the viewport and set its size
  19900. const container = this.container;
  19901. container.style.position = 'fixed';
  19902. container.style.left = `calc(50% - ${viewportSize.width >>> 1}px)`;
  19903. container.style.top = `calc(50% - ${viewportSize.height >>> 1}px)`;
  19904. container.style.zIndex = '1000000000'; // 1B //String(2147483647);
  19905. container.style.width = viewportSize.width + 'px';
  19906. container.style.height = viewportSize.height + 'px';
  19907. container.style.backgroundColor = '#000';
  19908. // set the size of the drawing buffer of the background canvas
  19909. const backgroundCanvas = this._background;
  19910. const backgroundCanvasAspectRatio = viewportAspectRatio;
  19911. const referenceHeight = height;
  19912. backgroundCanvas.height = referenceHeight;
  19913. backgroundCanvas.width = (backgroundCanvas.height * backgroundCanvasAspectRatio) | 0;
  19914. }
  19915. }
  19916. /**
  19917. * Inline viewport: it follows the typical flow of a web page
  19918. */
  19919. class InlineViewport extends ResizableViewport {
  19920. /**
  19921. * Resize the inline viewport
  19922. */
  19923. _resize() {
  19924. const { width, height } = this._size;
  19925. this.container.style.position = 'relative';
  19926. this.container.style.width = width + 'px';
  19927. this.container.style.height = height + 'px';
  19928. //this.container.style.display = 'inline-block';
  19929. this._background.width = width;
  19930. this._background.height = height;
  19931. }
  19932. }
  19933. ;// CONCATENATED MODULE: ./src/core/stats.ts
  19934. /*
  19935. * MARTINS.js Free Edition
  19936. * GPU-accelerated Augmented Reality for the web
  19937. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  19938. * https://github.com/alemart/martins-js
  19939. *
  19940. * This program is free software: you can redistribute it and/or modify
  19941. * it under the terms of the GNU Affero General Public License version 3
  19942. * as published by the Free Software Foundation.
  19943. *
  19944. * This program is distributed in the hope that it will be useful,
  19945. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19946. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19947. * GNU Affero General Public License for more details.
  19948. *
  19949. * You should have received a copy of the GNU Affero General Public License
  19950. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19951. *
  19952. * stats.ts
  19953. * Stats for performance measurements
  19954. */
  19955. /** update interval, given in seconds */
  19956. const UPDATE_INTERVAL = 0.5;
  19957. /**
  19958. * Stats for performance measurements
  19959. */
  19960. class Stats {
  19961. /**
  19962. * Constructor
  19963. */
  19964. constructor() {
  19965. this._timeOfLastUpdate = this._now();
  19966. this._partialCycleCount = 0;
  19967. this._cyclesPerSecond = 0;
  19968. }
  19969. /**
  19970. * Update stats - call every frame
  19971. */
  19972. update() {
  19973. const now = this._now();
  19974. ++this._partialCycleCount;
  19975. if (now >= this._timeOfLastUpdate + 1000 * UPDATE_INTERVAL) {
  19976. this._cyclesPerSecond = this._partialCycleCount / UPDATE_INTERVAL;
  19977. this._partialCycleCount = 0;
  19978. this._timeOfLastUpdate = now;
  19979. }
  19980. }
  19981. /**
  19982. * Reset stats
  19983. */
  19984. reset() {
  19985. this._timeOfLastUpdate = this._now();
  19986. this._partialCycleCount = 0;
  19987. this._cyclesPerSecond = 0;
  19988. }
  19989. /**
  19990. * Number of cycles per second
  19991. */
  19992. get cyclesPerSecond() {
  19993. return this._cyclesPerSecond;
  19994. }
  19995. /**
  19996. * A measurement of time, in milliseconds
  19997. * @returns time in ms
  19998. */
  19999. _now() {
  20000. return performance.now();
  20001. }
  20002. }
  20003. ;// CONCATENATED MODULE: ./src/core/stats-panel.ts
  20004. /*
  20005. * MARTINS.js Free Edition
  20006. * GPU-accelerated Augmented Reality for the web
  20007. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20008. * https://github.com/alemart/martins-js
  20009. *
  20010. * This program is free software: you can redistribute it and/or modify
  20011. * it under the terms of the GNU Affero General Public License version 3
  20012. * as published by the Free Software Foundation.
  20013. *
  20014. * This program is distributed in the hope that it will be useful,
  20015. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20016. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20017. * GNU Affero General Public License for more details.
  20018. *
  20019. * You should have received a copy of the GNU Affero General Public License
  20020. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20021. *
  20022. * stats-panel.ts
  20023. * Stats panel used for development purposes
  20024. */
  20025. /** Update interval, in ms */
  20026. const stats_panel_UPDATE_INTERVAL = 500;
  20027. /** Icons for different power profiles */
  20028. const POWER_ICON = Object.freeze({
  20029. 'default': '',
  20030. 'low-power': '<span style="color:#0f0">&#x1F50B</span>',
  20031. 'high-performance': '<span style="color:#ff0">&#x26A1</span>'
  20032. });
  20033. /**
  20034. * Stats panel used for development purposes
  20035. */
  20036. class StatsPanel {
  20037. /**
  20038. * Constructor
  20039. * @param parent parent element of the panel
  20040. */
  20041. constructor(parent) {
  20042. this._container = this._createContainer(parent);
  20043. this._lastUpdate = 0;
  20044. }
  20045. /**
  20046. * Release the panel
  20047. */
  20048. release() {
  20049. this._container.remove();
  20050. }
  20051. /**
  20052. * A method to be called in the update loop
  20053. * @param time current time in ms
  20054. * @param trackers the trackers attached to the session
  20055. * @param sources the sources of media linked to the session
  20056. * @param gpu GPU cycles per second
  20057. * @param fps frames per second
  20058. */
  20059. update(time, trackers, sources, gpu, fps) {
  20060. if (time >= this._lastUpdate + stats_panel_UPDATE_INTERVAL) {
  20061. this._lastUpdate = time;
  20062. this._update(trackers, sources, fps, gpu);
  20063. }
  20064. }
  20065. /**
  20066. * Visibility of the panel
  20067. */
  20068. get visible() {
  20069. return !this._container.hidden;
  20070. }
  20071. /**
  20072. * Visibility of the panel
  20073. */
  20074. set visible(visible) {
  20075. this._container.hidden = !visible;
  20076. }
  20077. /**
  20078. * Update the contents of the panel
  20079. * @param trackers the trackers attached to the session
  20080. * @param sources the sources of media linked to the session
  20081. * @param fps frames per second
  20082. * @param gpu GPU cycles per second
  20083. */
  20084. _update(trackers, sources, fps, gpu) {
  20085. const trackerStats = trackers.map(tracker => tracker._stats).join(', ');
  20086. const sourceStats = sources.map(source => source._stats).join(', ');
  20087. const param = {
  20088. fps: this._colorize(fps),
  20089. gpu: this._colorize(gpu),
  20090. powerIcon: POWER_ICON[Settings.powerPreference]
  20091. };
  20092. this._container.textContent = (`MARTINS.js ${Martins.edition}
  20093. Version ${Martins.version}
  20094. FPS: [fps] | GPU: [gpu] [powerIcon]
  20095. IN : ${sourceStats}
  20096. OUT: ${trackerStats}`);
  20097. const fn = (_, x) => param[x];
  20098. this._container.innerHTML = this._container.innerHTML.replace(/\[(\w+)\]/g, fn);
  20099. }
  20100. /**
  20101. * Colorize a frequency number
  20102. * @param f frequency given in cycles per second
  20103. * @returns colorized number (HTML)
  20104. */
  20105. _colorize(f) {
  20106. const GREEN = '#0f0', YELLOW = '#ff0', RED = '#f33';
  20107. const color3 = f >= 50 ? GREEN : (f >= 30 ? YELLOW : RED);
  20108. const color2 = f >= 30 ? GREEN : RED;
  20109. const color = Settings.powerPreference != 'low-power' ? color3 : color2;
  20110. return `<span style="color:${color}">${Number(f)}</span>`;
  20111. }
  20112. /**
  20113. * Create the container for the panel
  20114. * @param parent parent element
  20115. * @returns a container
  20116. */
  20117. _createContainer(parent) {
  20118. const container = document.createElement('div');
  20119. container.style.position = 'absolute';
  20120. container.style.left = container.style.top = '0px';
  20121. container.style.zIndex = '1000000';
  20122. container.style.padding = '4px';
  20123. container.style.whiteSpace = 'pre-line';
  20124. container.style.backgroundColor = 'rgba(0,0,0,0.5)';
  20125. container.style.color = '#fff';
  20126. container.style.fontFamily = 'monospace';
  20127. container.style.fontSize = '14px';
  20128. parent.appendChild(container);
  20129. return container;
  20130. }
  20131. }
  20132. ;// CONCATENATED MODULE: ./src/core/frame.ts
  20133. /*
  20134. * MARTINS.js Free Edition
  20135. * GPU-accelerated Augmented Reality for the web
  20136. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20137. * https://github.com/alemart/martins-js
  20138. *
  20139. * This program is free software: you can redistribute it and/or modify
  20140. * it under the terms of the GNU Affero General Public License version 3
  20141. * as published by the Free Software Foundation.
  20142. *
  20143. * This program is distributed in the hope that it will be useful,
  20144. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20145. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20146. * GNU Affero General Public License for more details.
  20147. *
  20148. * You should have received a copy of the GNU Affero General Public License
  20149. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20150. *
  20151. * frame.ts
  20152. * A Frame holds information used to render a single animation frame of a Session
  20153. */
  20154. /**
  20155. * Iterable frame results (helper class)
  20156. */
  20157. class IterableTrackerResults {
  20158. constructor(_results) {
  20159. this._results = _results;
  20160. this._index = 0;
  20161. }
  20162. next() {
  20163. const i = this._index++;
  20164. return i < this._results.length ?
  20165. { done: false, value: this._results[i] } :
  20166. { done: true, value: undefined };
  20167. }
  20168. [Symbol.iterator]() {
  20169. return this;
  20170. }
  20171. }
  20172. /**
  20173. * A Frame holds information used to render a single animation frame of a Session
  20174. */
  20175. class Frame {
  20176. /**
  20177. * Constructor
  20178. * @param session
  20179. * @param results
  20180. */
  20181. constructor(session, results) {
  20182. this._session = session;
  20183. this._results = new IterableTrackerResults(results);
  20184. }
  20185. /**
  20186. * The session of which this frame holds data
  20187. */
  20188. get session() {
  20189. return this._session;
  20190. }
  20191. /**
  20192. * The results of all trackers in this frame
  20193. */
  20194. get results() {
  20195. return this._results;
  20196. }
  20197. }
  20198. ;// CONCATENATED MODULE: ./src/core/time.ts
  20199. /*
  20200. * MARTINS.js Free Edition
  20201. * GPU-accelerated Augmented Reality for the web
  20202. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20203. * https://github.com/alemart/martins-js
  20204. *
  20205. * This program is free software: you can redistribute it and/or modify
  20206. * it under the terms of the GNU Affero General Public License version 3
  20207. * as published by the Free Software Foundation.
  20208. *
  20209. * This program is distributed in the hope that it will be useful,
  20210. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20211. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20212. * GNU Affero General Public License for more details.
  20213. *
  20214. * You should have received a copy of the GNU Affero General Public License
  20215. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20216. *
  20217. * time.ts
  20218. * Time utilities
  20219. */
  20220. /**
  20221. * Time Manager
  20222. */
  20223. class Time {
  20224. constructor() {
  20225. /** time scale */
  20226. this._scale = 1;
  20227. /** time since the start of the session, in milliseconds */
  20228. this._time = 0;
  20229. /** unscaled time since the start of the session, in milliseconds */
  20230. this._unscaledTime = 0;
  20231. /** elapsed time between the current and the previous frame, in milliseconds */
  20232. this._delta = 0;
  20233. /** time of the first update call, in milliseconds */
  20234. this._firstUpdate = 0;
  20235. /** time of the last update call, in milliseconds */
  20236. this._lastUpdate = Number.POSITIVE_INFINITY;
  20237. }
  20238. /**
  20239. * Update the Time Manager
  20240. * @param timestamp in milliseconds
  20241. * @internal
  20242. */
  20243. _update(timestamp) {
  20244. if (timestamp < this._lastUpdate) {
  20245. this._firstUpdate = this._lastUpdate = timestamp;
  20246. return;
  20247. }
  20248. this._delta = (timestamp - this._lastUpdate) * this._scale;
  20249. this._time += this._delta;
  20250. this._unscaledTime = timestamp - this._firstUpdate;
  20251. this._lastUpdate = timestamp;
  20252. }
  20253. /**
  20254. * Elapsed time since the start of the session, measured at the
  20255. * beginning of the current animation frame and given in seconds
  20256. */
  20257. get elapsed() {
  20258. return this._time * 0.001;
  20259. }
  20260. /**
  20261. * Elapsed time between the current and the previous animation
  20262. * frame, given in seconds
  20263. */
  20264. get delta() {
  20265. return this._delta * 0.001;
  20266. }
  20267. /**
  20268. * Time scale (defaults to 1)
  20269. */
  20270. get scale() {
  20271. return this._scale;
  20272. }
  20273. /**
  20274. * Time scale (defaults to 1)
  20275. */
  20276. set scale(scale) {
  20277. this._scale = Math.max(0, +scale);
  20278. }
  20279. /**
  20280. * Time scale independent elapsed time since the start of the session,
  20281. * measured at the beginning of the current animation frame and given
  20282. * in seconds
  20283. */
  20284. get unscaled() {
  20285. return this._unscaledTime * 0.001;
  20286. }
  20287. }
  20288. ;// CONCATENATED MODULE: ./src/core/gizmos.ts
  20289. /*
  20290. * MARTINS.js Free Edition
  20291. * GPU-accelerated Augmented Reality for the web
  20292. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20293. * https://github.com/alemart/martins-js
  20294. *
  20295. * This program is free software: you can redistribute it and/or modify
  20296. * it under the terms of the GNU Affero General Public License version 3
  20297. * as published by the Free Software Foundation.
  20298. *
  20299. * This program is distributed in the hope that it will be useful,
  20300. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20301. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20302. * GNU Affero General Public License for more details.
  20303. *
  20304. * You should have received a copy of the GNU Affero General Public License
  20305. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20306. *
  20307. * gizmos.ts
  20308. * Visual cues for testing & debugging
  20309. */
  20310. /** The maximum match distance ratio we'll consider to be "good" */
  20311. const GOOD_MATCH_THRESHOLD = 0.7;
  20312. /**
  20313. * Visual cues for testing & debugging
  20314. */
  20315. class Gizmos {
  20316. /**
  20317. * Constructor
  20318. */
  20319. constructor() {
  20320. this._visible = false;
  20321. }
  20322. /**
  20323. * Whether or not the gizmos will be rendered
  20324. */
  20325. get visible() {
  20326. return this._visible;
  20327. }
  20328. /**
  20329. * Whether or not the gizmos will be rendered
  20330. */
  20331. set visible(visible) {
  20332. this._visible = visible;
  20333. }
  20334. /**
  20335. * Render gizmos
  20336. * @param viewport
  20337. * @param trackers
  20338. * @internal
  20339. */
  20340. _render(viewport, trackers) {
  20341. // no need to render?
  20342. if (!this._visible)
  20343. return;
  20344. // viewport
  20345. const viewportSize = viewport._size;
  20346. const canvas = viewport._background;
  20347. const ctx = canvas.getContext('2d', { alpha: false });
  20348. if (!ctx)
  20349. throw new IllegalOperationError();
  20350. // debug
  20351. //ctx.fillStyle = '#000';
  20352. //ctx.fillRect(0, 0, canvas.width, canvas.height);
  20353. //ctx.clearRect(0, 0, canvas.width, canvas.height);
  20354. // render keypoints
  20355. for (let i = 0; i < trackers.length; i++) {
  20356. if (trackers[i].type != 'image-tracker')
  20357. continue;
  20358. const output = trackers[i]._output;
  20359. const keypoints = output.keypoints;
  20360. const screenSize = output.screenSize;
  20361. if (keypoints !== undefined && screenSize !== undefined)
  20362. this._splitAndRenderKeypoints(ctx, keypoints, screenSize, viewportSize);
  20363. }
  20364. // render polylines
  20365. for (let i = 0; i < trackers.length; i++) {
  20366. if (trackers[i].type != 'image-tracker')
  20367. continue;
  20368. const output = trackers[i]._output;
  20369. const polyline = output.polyline;
  20370. const screenSize = output.screenSize;
  20371. if (polyline !== undefined && screenSize !== undefined)
  20372. this._renderPolyline(ctx, polyline, screenSize, viewportSize);
  20373. }
  20374. // render the axes of the 3D coordinate system
  20375. for (let i = 0; i < trackers.length; i++) {
  20376. if (trackers[i].type != 'image-tracker')
  20377. continue;
  20378. const output = trackers[i]._output;
  20379. const cameraMatrix = output.cameraMatrix;
  20380. const screenSize = output.screenSize;
  20381. if (cameraMatrix !== undefined && screenSize !== undefined)
  20382. this._renderAxes(ctx, cameraMatrix, screenSize, viewportSize);
  20383. }
  20384. }
  20385. /**
  20386. * Split keypoints in matched/unmatched categories and
  20387. * render them for testing & development purposes
  20388. * @param ctx canvas 2D context
  20389. * @param keypoints keypoints to render
  20390. * @param screenSize AR screen size
  20391. * @param viewportSize viewport size
  20392. * @param size base keypoint rendering size
  20393. */
  20394. _splitAndRenderKeypoints(ctx, keypoints, screenSize, viewportSize, size = 1) {
  20395. if (keypoints.length == 0)
  20396. return;
  20397. if (!Object.prototype.hasOwnProperty.call(keypoints[0], '_matches')) { // hack...
  20398. this._renderKeypoints(ctx, keypoints, screenSize, viewportSize, '#f00', size);
  20399. return;
  20400. }
  20401. const isGoodMatch = (keypoint) => (keypoint.matches.length == 1 && keypoint.matches[0].index >= 0) ||
  20402. (keypoint.matches.length > 1 &&
  20403. keypoint.matches[0].index >= 0 && keypoint.matches[1].index >= 0 &&
  20404. keypoint.matches[0].distance <= GOOD_MATCH_THRESHOLD * keypoint.matches[1].distance);
  20405. const matchedKeypoints = keypoints;
  20406. const goodMatches = matchedKeypoints.filter(keypoint => isGoodMatch(keypoint));
  20407. const badMatches = matchedKeypoints.filter(keypoint => !isGoodMatch(keypoint));
  20408. this._renderKeypoints(ctx, badMatches, screenSize, viewportSize, '#f00', size);
  20409. this._renderKeypoints(ctx, goodMatches, screenSize, viewportSize, '#0f0', size);
  20410. }
  20411. /**
  20412. * Render keypoints for testing & development purposes
  20413. * @param ctx canvas 2D context
  20414. * @param keypoints keypoints to render
  20415. * @param screenSize AR screen size
  20416. * @param viewportSize viewport size
  20417. * @param color color of the rendered keypoints
  20418. * @param size base keypoint rendering size
  20419. */
  20420. _renderKeypoints(ctx, keypoints, screenSize, viewportSize, color = 'red', size = 1) {
  20421. const sx = viewportSize.width / screenSize.width;
  20422. const sy = viewportSize.height / screenSize.height;
  20423. ctx.beginPath();
  20424. for (let i = keypoints.length - 1; i >= 0; i--) {
  20425. const keypoint = keypoints[i];
  20426. const x = (keypoint.x * sx + 0.5) | 0;
  20427. const y = (keypoint.y * sy + 0.5) | 0;
  20428. const r = (size * keypoint.scale + 0.5) | 0;
  20429. ctx.rect(x - r, y - r, 2 * r, 2 * r);
  20430. }
  20431. ctx.strokeStyle = color;
  20432. ctx.lineWidth = 1;
  20433. ctx.stroke();
  20434. }
  20435. /**
  20436. * Render polyline for testing & development purposes
  20437. * @param ctx canvas 2D context
  20438. * @param polyline vertices
  20439. * @param screenSize AR screen size
  20440. * @param viewportSize viewport size
  20441. * @param color color of the rendered polyline
  20442. * @param lineWidth
  20443. */
  20444. _renderPolyline(ctx, polyline, screenSize, viewportSize, color = '#0f0', lineWidth = 2) {
  20445. if (polyline.length == 0)
  20446. return;
  20447. const n = polyline.length;
  20448. const sx = viewportSize.width / screenSize.width;
  20449. const sy = viewportSize.height / screenSize.height;
  20450. // render polyline
  20451. ctx.beginPath();
  20452. ctx.moveTo(polyline[n - 1].x * sx, polyline[n - 1].y * sy);
  20453. for (let j = 0; j < n; j++)
  20454. ctx.lineTo(polyline[j].x * sx, polyline[j].y * sy);
  20455. ctx.strokeStyle = color;
  20456. ctx.lineWidth = lineWidth;
  20457. ctx.stroke();
  20458. }
  20459. /**
  20460. * Render the axes of a 3D coordinate system
  20461. * @param ctx canvas 2D context
  20462. * @param cameraMatrix 3x4 camera matrix that maps normalized coordinates [-1,1]^3 to AR screen space
  20463. * @param screenSize AR screen size
  20464. * @param viewportSize viewport size
  20465. * @param lineWidth
  20466. */
  20467. _renderAxes(ctx, cameraMatrix, screenSize, viewportSize, lineWidth = 4) {
  20468. const RED = '#f00', GREEN = '#0f0', BLUE = '#00f';
  20469. const color = [RED, GREEN, BLUE]; // color of each axis: (X,Y,Z)
  20470. const length = 1; // length of each axis-corresponding line, given in normalized space units
  20471. const sx = viewportSize.width / screenSize.width;
  20472. const sy = viewportSize.height / screenSize.height;
  20473. /*
  20474. Multiply the 3x4 camera matrix P by:
  20475. [ 0 L 0 0 ]
  20476. [ 0 0 L 0 ] , where L = length in normalized space of the lines
  20477. [ 0 0 0 L ] corresponding to the 3 axes (typically 1)
  20478. [ 1 1 1 1 ]
  20479. Each column of the resulting matrix will give us the pixel coordinates
  20480. we're looking for.
  20481. Note: we're working with homogeneous coordinates
  20482. */
  20483. const p = cameraMatrix.read();
  20484. const l = length;
  20485. const o = [p[9], p[10], p[11]]; // origin of the coordinate system
  20486. const x = [l * p[0] + p[9], l * p[1] + p[10], l * p[2] + p[11]]; // x-axis
  20487. const y = [l * p[3] + p[9], l * p[4] + p[10], l * p[5] + p[11]]; // y-axis
  20488. const z = [l * p[6] + p[9], l * p[7] + p[10], l * p[8] + p[11]]; // z-axis
  20489. const axis = [x, y, z];
  20490. // draw each axis
  20491. const ox = o[0] / o[2], oy = o[1] / o[2];
  20492. for (let i = 0; i < 3; i++) {
  20493. const q = axis[i];
  20494. const x = q[0] / q[2], y = q[1] / q[2];
  20495. ctx.beginPath();
  20496. ctx.moveTo(ox * sx, oy * sy);
  20497. ctx.lineTo(x * sx, y * sy);
  20498. ctx.strokeStyle = color[i];
  20499. ctx.lineWidth = lineWidth;
  20500. ctx.stroke();
  20501. }
  20502. //console.log("Origin",ox,oy);
  20503. }
  20504. }
  20505. ;// CONCATENATED MODULE: ./src/utils/asap.ts
  20506. /*
  20507. * MARTINS.js Free Edition
  20508. * GPU-accelerated Augmented Reality for the web
  20509. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20510. * https://github.com/alemart/martins-js
  20511. *
  20512. * This program is free software: you can redistribute it and/or modify
  20513. * it under the terms of the GNU Affero General Public License version 3
  20514. * as published by the Free Software Foundation.
  20515. *
  20516. * This program is distributed in the hope that it will be useful,
  20517. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20518. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20519. * GNU Affero General Public License for more details.
  20520. *
  20521. * You should have received a copy of the GNU Affero General Public License
  20522. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20523. *
  20524. * asap.ts
  20525. * Schedule a function to run "as soon as possible"
  20526. */
  20527. /** callbacks */
  20528. const callbacks = [];
  20529. /** arguments to be passed to the callbacks */
  20530. const args = [];
  20531. /** asap key */
  20532. const ASAP_KEY = 'asap' + Math.random().toString(36).substr(1);
  20533. // Register an event listener
  20534. window.addEventListener('message', event => {
  20535. if (event.source !== window || event.data !== ASAP_KEY)
  20536. return;
  20537. event.stopPropagation();
  20538. if (callbacks.length == 0)
  20539. return;
  20540. const fn = callbacks.pop();
  20541. const argArray = args.pop();
  20542. fn.apply(undefined, argArray);
  20543. }, true);
  20544. /**
  20545. * Schedule a function to run "as soon as possible"
  20546. * @param fn callback
  20547. * @param params optional parameters
  20548. */
  20549. function asap(fn, ...params) {
  20550. callbacks.unshift(fn);
  20551. args.unshift(params);
  20552. window.postMessage(ASAP_KEY, '*');
  20553. }
  20554. ;// CONCATENATED MODULE: ./src/core/session.ts
  20555. /*
  20556. * MARTINS.js Free Edition
  20557. * GPU-accelerated Augmented Reality for the web
  20558. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20559. * https://github.com/alemart/martins-js
  20560. *
  20561. * This program is free software: you can redistribute it and/or modify
  20562. * it under the terms of the GNU Affero General Public License version 3
  20563. * as published by the Free Software Foundation.
  20564. *
  20565. * This program is distributed in the hope that it will be useful,
  20566. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20567. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20568. * GNU Affero General Public License for more details.
  20569. *
  20570. * You should have received a copy of the GNU Affero General Public License
  20571. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20572. *
  20573. * session.ts
  20574. * WebAR Session
  20575. */
  20576. /** An event emitted by a Session */
  20577. class SessionEvent extends AREvent {
  20578. }
  20579. /** Default options when starting a session */
  20580. const DEFAULT_OPTIONS = {
  20581. mode: 'immersive',
  20582. trackers: [],
  20583. sources: [],
  20584. viewport: null,
  20585. stats: false,
  20586. gizmos: false,
  20587. };
  20588. /**
  20589. * A Session represents an intent to display AR content
  20590. * and encapsulates the main loop (update-render cycle)
  20591. */
  20592. class Session extends AREventTarget {
  20593. /**
  20594. * Constructor
  20595. * @param sources previously initialized sources of data
  20596. * @param mode session mode
  20597. * @param viewport viewport
  20598. * @param stats render stats panel?
  20599. * @param gizmos render gizmos?
  20600. */
  20601. constructor(sources, mode, viewport, stats, gizmos) {
  20602. super();
  20603. this._mode = mode;
  20604. this._trackers = [];
  20605. this._sources = sources;
  20606. this._updateStats = new Stats();
  20607. this._renderStats = new Stats();
  20608. this._active = true;
  20609. this._frameReady = true; // no trackers at the moment
  20610. this._rafQueue = [];
  20611. this._time = new Time();
  20612. this._gizmos = new Gizmos();
  20613. this._gizmos.visible = gizmos;
  20614. // get media
  20615. const media = this.media;
  20616. // setup the viewport
  20617. if (mode == 'immersive')
  20618. this._viewport = new ImmersiveViewport(viewport, () => media.size);
  20619. else if (mode == 'inline')
  20620. this._viewport = new InlineViewport(viewport, () => media.size);
  20621. else
  20622. throw new IllegalArgumentError(`Invalid session mode "${mode}"`);
  20623. this._viewport._init();
  20624. // setup the main loop
  20625. this._setupUpdateLoop();
  20626. this._setupRenderLoop();
  20627. // setup the stats panel
  20628. this._statsPanel = new StatsPanel(this._viewport.hud.container);
  20629. this._statsPanel.visible = stats;
  20630. // done!
  20631. Session._count++;
  20632. Utils.log(`The ${mode} session is now active!`);
  20633. }
  20634. /**
  20635. * Checks if the engine can be run in the browser the client is using
  20636. * @returns true if the engine is compatible with the browser
  20637. */
  20638. static isSupported() {
  20639. return speedy_vision_default().isSupported();
  20640. }
  20641. /**
  20642. * Instantiate a session
  20643. * @param options options
  20644. * @returns a promise that resolves to a new session
  20645. */
  20646. static instantiate(options = DEFAULT_OPTIONS) {
  20647. const { mode = DEFAULT_OPTIONS.mode, sources = DEFAULT_OPTIONS.sources, trackers = DEFAULT_OPTIONS.trackers, viewport = DEFAULT_OPTIONS.viewport, stats = DEFAULT_OPTIONS.stats, gizmos = DEFAULT_OPTIONS.gizmos, } = options;
  20648. Utils.log(`Starting a new ${mode} session...`);
  20649. return speedy_vision_default().Promise.resolve().then(() => {
  20650. // is the engine supported?
  20651. if (!Session.isSupported())
  20652. throw new NotSupportedError('You need a browser/device compatible with WebGL2 and WebAssembly in order to experience Augmented Reality with the MARTINS.js engine');
  20653. // block multiple immersive sessions
  20654. if (mode !== 'inline' && Session.count > 0)
  20655. throw new IllegalOperationError(`Can't start more than one immersive session`);
  20656. // initialize matrix routines
  20657. return speedy_vision_default().Matrix.ready();
  20658. }).then(() => {
  20659. // validate sources of data
  20660. const videoSources = sources.filter(source => source._type == 'video');
  20661. if (videoSources.length != 1)
  20662. throw new IllegalArgumentError(`One video source of data must be provided`);
  20663. for (let i = sources.length - 1; i >= 0; i--) {
  20664. if (sources.indexOf(sources[i]) < i)
  20665. throw new IllegalArgumentError(`Found repeated sources of data`);
  20666. }
  20667. // initialize sources of data
  20668. return speedy_vision_default().Promise.all(sources.map(source => source._init()));
  20669. }).then(() => {
  20670. // get the viewport
  20671. if (!viewport)
  20672. throw new IllegalArgumentError(`Can't create a session without a viewport`);
  20673. // instantiate session
  20674. return new Session(sources, mode, viewport, stats, gizmos);
  20675. }).then(session => {
  20676. // validate trackers
  20677. if (trackers.length == 0)
  20678. Utils.warning(`No trackers have been attached to the session!`);
  20679. for (let i = trackers.length - 1; i >= 0; i--) {
  20680. if (trackers.indexOf(trackers[i]) < i)
  20681. throw new IllegalArgumentError(`Found repeated trackers`);
  20682. }
  20683. // attach trackers and return the session
  20684. return speedy_vision_default().Promise.all(trackers.map(tracker => session._attachTracker(tracker))).then(() => session);
  20685. }).catch(err => {
  20686. // log errors, if any
  20687. Utils.error(`Can't start session: ${err.message}`);
  20688. throw err;
  20689. });
  20690. }
  20691. /**
  20692. * Number of active sessions
  20693. */
  20694. static get count() {
  20695. return this._count;
  20696. }
  20697. /**
  20698. * End the session
  20699. * @returns promise that resolves after the session is shut down
  20700. */
  20701. end() {
  20702. // is the session inactive?
  20703. if (!this._active)
  20704. return speedy_vision_default().Promise.resolve();
  20705. // deactivate the session
  20706. Utils.log('Shutting down the session...');
  20707. this._active = false; // set before wait()
  20708. // wait a few ms, so that the GPU is no longer sending any data
  20709. const wait = (ms) => new (speedy_vision_default()).Promise(resolve => {
  20710. setTimeout(resolve, ms);
  20711. });
  20712. // release resources
  20713. return wait(100).then(() => speedy_vision_default().Promise.all(
  20714. // release trackers
  20715. this._trackers.map(tracker => tracker._release()))).then(() => speedy_vision_default().Promise.all(
  20716. // release input sources
  20717. this._sources.map(source => source._release()))).then(() => {
  20718. this._sources.length = 0;
  20719. this._trackers.length = 0;
  20720. // release internal components
  20721. this._updateStats.reset();
  20722. this._renderStats.reset();
  20723. this._statsPanel.release();
  20724. this._viewport._release();
  20725. // end the session
  20726. Session._count--;
  20727. // dispatch event
  20728. const event = new SessionEvent('end');
  20729. this.dispatchEvent(event);
  20730. // done!
  20731. Utils.log('Session ended.');
  20732. });
  20733. }
  20734. /**
  20735. * Analogous to window.requestAnimationFrame()
  20736. * @param callback
  20737. * @returns a handle
  20738. */
  20739. requestAnimationFrame(callback) {
  20740. const handle = Symbol('raf-handle');
  20741. if (this._active)
  20742. this._rafQueue.push([handle, callback]);
  20743. else
  20744. throw new IllegalOperationError(`Can't requestAnimationFrame(): session ended.`);
  20745. return handle;
  20746. }
  20747. /**
  20748. * Analogous to window.cancelAnimationFrame()
  20749. * @param handle a handle returned by this.requestAnimationFrame()
  20750. */
  20751. cancelAnimationFrame(handle) {
  20752. for (let i = this._rafQueue.length - 1; i >= 0; i--) {
  20753. if (this._rafQueue[i][0] === handle) {
  20754. this._rafQueue.splice(i, 1);
  20755. break;
  20756. }
  20757. }
  20758. }
  20759. /**
  20760. * The underlying media (generally a camera stream)
  20761. * @internal
  20762. */
  20763. get media() {
  20764. for (let i = this._sources.length - 1; i >= 0; i--) {
  20765. if (this._sources[i]._type == 'video')
  20766. return this._sources[i]._data;
  20767. }
  20768. // this shouldn't happen
  20769. throw new IllegalOperationError(`Invalid input source`);
  20770. }
  20771. /**
  20772. * Session mode
  20773. */
  20774. get mode() {
  20775. return this._mode;
  20776. }
  20777. /**
  20778. * Rendering viewport
  20779. */
  20780. get viewport() {
  20781. return this._viewport;
  20782. }
  20783. /**
  20784. * Time utilities
  20785. */
  20786. get time() {
  20787. return this._time;
  20788. }
  20789. /**
  20790. * Visual cues for testing & debugging
  20791. */
  20792. get gizmos() {
  20793. return this._gizmos;
  20794. }
  20795. /**
  20796. * Attach a tracker to the session
  20797. * @param tracker
  20798. */
  20799. _attachTracker(tracker) {
  20800. if (this._trackers.indexOf(tracker) >= 0)
  20801. throw new IllegalArgumentError(`Duplicate tracker attached to the session`);
  20802. else if (!this._active)
  20803. throw new IllegalOperationError(`Inactive session`);
  20804. this._trackers.push(tracker);
  20805. return tracker._init(this);
  20806. }
  20807. /**
  20808. * Render the user media to the background canvas
  20809. */
  20810. _renderUserMedia() {
  20811. const canvas = this._viewport._background;
  20812. const ctx = canvas.getContext('2d', { alpha: false });
  20813. if (ctx) {
  20814. ctx.imageSmoothingEnabled = false;
  20815. // draw user media
  20816. const image = this.media.source;
  20817. ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
  20818. // render output image(s)
  20819. for (let i = 0; i < this._trackers.length; i++) {
  20820. const image = this._trackers[i]._output.image;
  20821. if (image !== undefined)
  20822. ctx.drawImage(image.source, 0, 0, canvas.width, canvas.height);
  20823. //ctx.drawImage(image.source, canvas.width - image.width, canvas.height - image.height, image.width, image.height);
  20824. }
  20825. // render gizmos
  20826. this._gizmos._render(this._viewport, this._trackers);
  20827. }
  20828. }
  20829. /**
  20830. * Setup the update loop
  20831. */
  20832. _setupUpdateLoop() {
  20833. const scheduleNextFrame = () => {
  20834. if (this._active) {
  20835. if (Settings.powerPreference == 'high-performance')
  20836. asap(repeat);
  20837. else
  20838. window.requestAnimationFrame(repeat);
  20839. }
  20840. };
  20841. const update = () => {
  20842. this._update().then(scheduleNextFrame).turbocharge();
  20843. };
  20844. function repeat() {
  20845. if (Settings.powerPreference == 'low-power') // 30 fps
  20846. window.requestAnimationFrame(update);
  20847. else
  20848. update();
  20849. }
  20850. window.requestAnimationFrame(update);
  20851. }
  20852. /**
  20853. * The core of the update loop
  20854. */
  20855. _update() {
  20856. // active session?
  20857. if (this._active) {
  20858. return speedy_vision_default().Promise.all(
  20859. // update trackers
  20860. this._trackers.map(tracker => tracker._update().turbocharge())).then(() => {
  20861. // update internals
  20862. this._updateStats.update();
  20863. this._frameReady = true;
  20864. }).catch(err => {
  20865. // handle error
  20866. Utils.warning('Tracking error: ' + err.toString());
  20867. });
  20868. }
  20869. else {
  20870. // inactive session
  20871. this._updateStats.reset();
  20872. return speedy_vision_default().Promise.resolve();
  20873. }
  20874. }
  20875. /**
  20876. * Setup the render loop
  20877. */
  20878. _setupRenderLoop() {
  20879. let skip = false, toggle = false;
  20880. const render = (timestamp) => {
  20881. const enableFrameSkipping = (Settings.powerPreference == 'low-power');
  20882. const highPerformance = (Settings.powerPreference == 'high-performance');
  20883. // advance time
  20884. this._time._update(timestamp);
  20885. // skip frames
  20886. if (!enableFrameSkipping || !(skip = !skip))
  20887. this._render(timestamp, false);
  20888. //this._render(timestamp, !enableFrameSkipping && !highPerformance && (toggle = !toggle));
  20889. // repeat
  20890. if (this._active)
  20891. window.requestAnimationFrame(render);
  20892. };
  20893. window.requestAnimationFrame(render);
  20894. }
  20895. /**
  20896. * Render a frame (RAF callback)
  20897. * @param time current time, in ms
  20898. * @param skipUserMedia skip copying the pixels of the user media to the background canvas in order to reduce the processing load (video stream is probably at 30fps?)
  20899. */
  20900. _render(time, skipUserMedia) {
  20901. // is the session active?
  20902. if (this._active) {
  20903. // are we ready to render a frame?
  20904. if (this._frameReady) {
  20905. // create a frame
  20906. const results = this._trackers.map(tracker => tracker._output.exports || ({
  20907. tracker: tracker,
  20908. trackables: [],
  20909. }));
  20910. const frame = new Frame(this, results);
  20911. // clone & clear the RAF queue
  20912. const rafQueue = this._rafQueue.slice(0);
  20913. this._rafQueue.length = 0;
  20914. // render user media
  20915. if (!skipUserMedia)
  20916. this._renderUserMedia();
  20917. // render frame
  20918. for (let i = 0; i < rafQueue.length; i++)
  20919. rafQueue[i][1].call(undefined, time, frame);
  20920. // update internals
  20921. this._renderStats.update();
  20922. this._statsPanel.update(time, this._trackers, this._sources, this._updateStats.cyclesPerSecond, this._renderStats.cyclesPerSecond);
  20923. this._frameReady = false;
  20924. }
  20925. else {
  20926. // skip frame
  20927. ;
  20928. // we'll update the renderStats even if we skip the frame,
  20929. // otherwise this becomes updateStats! (approximately)
  20930. // This is a window.requestAnimationFrame() call, so the
  20931. // browser is rendering content even if we're not.
  20932. this._renderStats.update();
  20933. }
  20934. }
  20935. else {
  20936. // inactive session
  20937. this._renderStats.reset();
  20938. }
  20939. }
  20940. }
  20941. /** Number of active sessions */
  20942. Session._count = 0;
  20943. ;// CONCATENATED MODULE: ./src/core/settings.ts
  20944. /*
  20945. * MARTINS.js Free Edition
  20946. * GPU-accelerated Augmented Reality for the web
  20947. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  20948. * https://github.com/alemart/martins-js
  20949. *
  20950. * This program is free software: you can redistribute it and/or modify
  20951. * it under the terms of the GNU Affero General Public License version 3
  20952. * as published by the Free Software Foundation.
  20953. *
  20954. * This program is distributed in the hope that it will be useful,
  20955. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20956. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20957. * GNU Affero General Public License for more details.
  20958. *
  20959. * You should have received a copy of the GNU Affero General Public License
  20960. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20961. *
  20962. * settings.ts
  20963. * Global Settings
  20964. */
  20965. /**
  20966. * Global Settings
  20967. */
  20968. class Settings {
  20969. /**
  20970. * Power preference (may impact performance x battery life)
  20971. */
  20972. static get powerPreference() {
  20973. return this._powerPreference;
  20974. }
  20975. /**
  20976. * Power preference (may impact performance x battery life)
  20977. * Note: this setting should be the very first thing you set
  20978. * (before the WebGL context is created by Speedy)
  20979. */
  20980. static set powerPreference(value) {
  20981. // validate
  20982. if (Session.count > 0)
  20983. throw new IllegalOperationError(`Can't change the powerPreference while there are active sessions going on`);
  20984. else if (!('low-power' == value || 'default' == value || 'high-performance' == value))
  20985. throw new IllegalArgumentError(`Invalid powerPreference: "${value}"`);
  20986. /*
  20987. // we won't use 'high-performance' for Speedy's GPU computations
  20988. // see the WebGL 1.0 spec sec 5.2.1 for battery life considerations
  20989. // also, it seems like low-power mode may break WebGL2 in some drivers?!
  20990. if(value == 'high-performance')
  20991. Speedy.Settings.powerPreference = 'default';
  20992. else
  20993. Speedy.Settings.powerPreference = value;
  20994. */
  20995. // change the GPU polling mode
  20996. if (value == 'high-performance')
  20997. (speedy_vision_default()).Settings.gpuPollingMode = 'asap';
  20998. else
  20999. (speedy_vision_default()).Settings.gpuPollingMode = 'raf';
  21000. // update the power preference
  21001. this._powerPreference = value;
  21002. // log
  21003. Utils.log(`Changed the powerPreference to "${this._powerPreference}"`);
  21004. }
  21005. }
  21006. Settings._powerPreference = 'default';
  21007. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/reference-image-database.ts
  21008. /*
  21009. * MARTINS.js Free Edition
  21010. * GPU-accelerated Augmented Reality for the web
  21011. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21012. * https://github.com/alemart/martins-js
  21013. *
  21014. * This program is free software: you can redistribute it and/or modify
  21015. * it under the terms of the GNU Affero General Public License version 3
  21016. * as published by the Free Software Foundation.
  21017. *
  21018. * This program is distributed in the hope that it will be useful,
  21019. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21020. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21021. * GNU Affero General Public License for more details.
  21022. *
  21023. * You should have received a copy of the GNU Affero General Public License
  21024. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21025. *
  21026. * reference-image-database.ts
  21027. * A collection of Reference Images
  21028. */
  21029. /** Default capacity of a Reference Image Database */
  21030. const DEFAULT_CAPACITY = 100;
  21031. /** Generate a unique name for a reference image */
  21032. const generateUniqueName = () => 'target-' + Math.random().toString(16).substr(2);
  21033. /**
  21034. * A collection of Reference Images
  21035. */
  21036. class ReferenceImageDatabase {
  21037. /**
  21038. * Constructor
  21039. */
  21040. constructor() {
  21041. this._capacity = DEFAULT_CAPACITY;
  21042. this._database = [];
  21043. this._locked = false;
  21044. }
  21045. /**
  21046. * The number of reference images stored in this database
  21047. */
  21048. get count() {
  21049. return this._database.length;
  21050. }
  21051. /**
  21052. * Maximum number of elements
  21053. */
  21054. get capacity() {
  21055. return this._capacity;
  21056. }
  21057. /**
  21058. * Maximum number of elements
  21059. */
  21060. /*
  21061. set capacity(value: number)
  21062. {
  21063. const capacity = Math.max(0, value | 0);
  21064. if(this.count > capacity)
  21065. throw new IllegalArgumentError(`Can't set the capacity of the database to ${this._capacity}: it currently stores ${this.count} entries`);
  21066. this._capacity = capacity;
  21067. }
  21068. */
  21069. /**
  21070. * Iterates over the collection
  21071. */
  21072. *[Symbol.iterator]() {
  21073. const ref = this._database.map(entry => entry.referenceImage);
  21074. yield* ref;
  21075. }
  21076. /**
  21077. * Add reference images to this database
  21078. * Add only the images you actually need to track!
  21079. * (each image take up storage space)
  21080. * @param referenceImages one or more reference images with unique names (a unique name will
  21081. * be generated automatically if you don't specify one)
  21082. * @returns a promise that resolves as soon as the images are loaded and added to this database
  21083. */
  21084. add(referenceImages) {
  21085. // handle no input
  21086. if (referenceImages.length == 0)
  21087. return speedy_vision_default().Promise.resolve();
  21088. // handle multiple images as input
  21089. if (referenceImages.length > 1) {
  21090. const promises = referenceImages.map(image => this.add([image]));
  21091. return speedy_vision_default().Promise.all(promises).then(() => void (0));
  21092. }
  21093. // handle a single image as input
  21094. const referenceImage = referenceImages[0];
  21095. // locked database?
  21096. if (this._locked)
  21097. throw new IllegalOperationError(`Can't add reference image to the database: it's locked`);
  21098. // reached full capacity?
  21099. if (this.count >= this.capacity)
  21100. throw new IllegalOperationError(`Can't add reference image to the database: the capacity of ${this.capacity} images has been exceeded.`);
  21101. // check for duplicate names
  21102. if (this._database.find(entry => entry.referenceImage.name === referenceImage.name) !== undefined)
  21103. throw new IllegalArgumentError(`Can't add reference image to the database: found duplicated name "${referenceImage.name}"`);
  21104. // load the media and add the reference image to the database
  21105. return speedy_vision_default().load(referenceImage.image).then(media => {
  21106. this._database.push({
  21107. referenceImage: Object.freeze(Object.assign(Object.assign({}, referenceImage), { name: referenceImage.name || generateUniqueName() })),
  21108. media: media
  21109. });
  21110. });
  21111. }
  21112. /**
  21113. * Lock the database, so that new reference images can no longer be added to it
  21114. * @internal
  21115. */
  21116. _lock() {
  21117. this._locked = true;
  21118. }
  21119. /**
  21120. * Get the media object associated to a reference image
  21121. * @param name reference image name
  21122. * @returns media
  21123. * @internal
  21124. */
  21125. _findMedia(name) {
  21126. for (let i = 0; i < this._database.length; i++) {
  21127. if (this._database[i].referenceImage.name === name)
  21128. return this._database[i].media;
  21129. }
  21130. throw new IllegalArgumentError(`Can't find reference image "${name}"`);
  21131. }
  21132. }
  21133. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/settings.ts
  21134. /*
  21135. * MARTINS.js Free Edition
  21136. * GPU-accelerated Augmented Reality for the web
  21137. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21138. * https://github.com/alemart/martins-js
  21139. *
  21140. * This program is free software: you can redistribute it and/or modify
  21141. * it under the terms of the GNU Affero General Public License version 3
  21142. * as published by the Free Software Foundation.
  21143. *
  21144. * This program is distributed in the hope that it will be useful,
  21145. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21146. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21147. * GNU Affero General Public License for more details.
  21148. *
  21149. * You should have received a copy of the GNU Affero General Public License
  21150. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21151. *
  21152. * settings.ts
  21153. * Settings of the Image Tracker
  21154. */
  21155. /** Default tracking resolution */
  21156. const DEFAULT_TRACKING_RESOLUTION = 'sm+';
  21157. /** Maximum number of keypoints to be stored for each reference image when in the training state */
  21158. const TRAIN_MAX_KEYPOINTS = 1024; //512;
  21159. /** Percentage relative to the screen size adjusted to the aspect ratio of the reference image */
  21160. const TRAIN_IMAGE_SCALE = 0.8; // ORB is not scale invariant
  21161. /** Normalized width & height of an image target, in pixels */
  21162. const TRAIN_TARGET_NORMALIZED_SIZE = 1024; // keypoint positions are stored as fixed point
  21163. /** Used to identify the best maches */
  21164. const SCAN_MATCH_RATIO = 0.7; // usually a value in [0.6, 0.8]
  21165. /** Maximum number of keypoints to be analyzed when in the scanning state */
  21166. const SCAN_MAX_KEYPOINTS = 512;
  21167. /** Number of pyramid levels to be scanned by the corner detector when in the scanning & training states */
  21168. const SCAN_PYRAMID_LEVELS = 4; //7;
  21169. /** Scale factor between pyramid levels to be scanned by the corner detector when in the scanning & training states */
  21170. const SCAN_PYRAMID_SCALEFACTOR = 1.19; // 2 ^ 0.25
  21171. /** Threshold of the FAST corner detector used in the scanning/training states */
  21172. const SCAN_FAST_THRESHOLD = 60;
  21173. /** Minimum number of accepted matches for us to move out from the scanning state */
  21174. const SCAN_MIN_MATCHES = 20; //30;
  21175. /** When in the scanning state, we require the image to be matched during a few consecutive frames before accepting it */
  21176. const SCAN_CONSECUTIVE_FRAMES = 30; //15;//45;
  21177. /** Reprojection error, in pixels, used when estimating a motion model (scanning state) */
  21178. const SCAN_RANSAC_REPROJECTIONERROR = 5;
  21179. /** Number of tables used in the LSH-based keypoint matching */
  21180. const SCAN_LSH_TABLES = 8; // up to 32
  21181. /** Hash size, in bits, used in the LSH-based keypoint matching */
  21182. const SCAN_LSH_HASHSIZE = 15; // up to 16
  21183. /** Use the Nightvision filter when in the scanning/training state? */
  21184. const SCAN_WITH_NIGHTVISION = true;
  21185. /** Nightvision filter: gain */
  21186. const NIGHTVISION_GAIN = 0.3; // 0.2;
  21187. /** Nightvision filter: offset */
  21188. const NIGHTVISION_OFFSET = 0.5;
  21189. /** Nightvision filter: decay */
  21190. const NIGHTVISION_DECAY = 0.0;
  21191. /** Nightvision filter: quality level */
  21192. const NIGHTVISION_QUALITY = 'low';
  21193. /** Kernel size (square) of the Gaussian filter applied before computing the ORB descriptors */
  21194. const ORB_GAUSSIAN_KSIZE = 9;
  21195. /** Sigma of the Gaussian filter applied before computing the ORB descriptors */
  21196. const ORB_GAUSSIAN_SIGMA = 2.0;
  21197. /** Kernel size (square) of the Gaussian filter applied before subpixel refinement for noise reduction */
  21198. const SUBPIXEL_GAUSSIAN_KSIZE = 5;
  21199. /** Sigma of the Gaussian filter applied before subpixel refinement for noise reduction */
  21200. const SUBPIXEL_GAUSSIAN_SIGMA = 1.0;
  21201. /** Subpixel refinement method */
  21202. const SUBPIXEL_METHOD = 'bilinear-upsample'; // 'quadratic1d';
  21203. /** Minimum acceptable number of matched keypoints when in the tracking state */
  21204. const TRACK_MIN_MATCHES = 4; //10; //20;
  21205. /** Maximum number of keypoints to be analyzed in the tracking state */
  21206. const TRACK_MAX_KEYPOINTS = 200; //400; // <-- impacts performance!
  21207. /** Capacity of the keypoint detector used in the the tracking state */
  21208. const TRACK_DETECTOR_CAPACITY = 2048; //4096;
  21209. /** Quality of the Harris/Shi-Tomasi corner detector */
  21210. const TRACK_HARRIS_QUALITY = 0.005; // get a lot of keypoints
  21211. /** Use the Nightvision filter when in the tracking state? */
  21212. const TRACK_WITH_NIGHTVISION = false; // produces shaking?
  21213. /** Relative size (%) of the (top, right, bottom, left) borders of the rectified image */
  21214. const TRACK_RECTIFIED_BORDER = 0.15; //0.20;
  21215. /** Relative size (%) used to clip keypoints from the borders of the rectified image */
  21216. const TRACK_CLIPPING_BORDER = TRACK_RECTIFIED_BORDER * 1.20; //1.25; //1.15;
  21217. /** Number of iterations used to refine the target image before tracking */
  21218. const TRACK_REFINEMENT_ITERATIONS = 3;
  21219. /** Reprojection error, in pixels, used when estimating a motion model (tracking state) */
  21220. const TRACK_RANSAC_REPROJECTIONERROR = 3; //2.5;
  21221. /** We use a N x N grid to spatially distribute the keypoints in order to compute a better homography */
  21222. const TRACK_GRID_GRANULARITY = 10; //20; // the value of N
  21223. /** Used to identify the best maches */
  21224. const TRACK_MATCH_RATIO = 0.75; // usually a value in [0.6, 0.8] - low values => strict tracking
  21225. /** Number of consecutive frames in which we tolerate a "target lost" situation */
  21226. const TRACK_LOST_TOLERANCE = 10;
  21227. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/state.ts
  21228. /*
  21229. * MARTINS.js Free Edition
  21230. * GPU-accelerated Augmented Reality for the web
  21231. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21232. * https://github.com/alemart/martins-js
  21233. *
  21234. * This program is free software: you can redistribute it and/or modify
  21235. * it under the terms of the GNU Affero General Public License version 3
  21236. * as published by the Free Software Foundation.
  21237. *
  21238. * This program is distributed in the hope that it will be useful,
  21239. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21240. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21241. * GNU Affero General Public License for more details.
  21242. *
  21243. * You should have received a copy of the GNU Affero General Public License
  21244. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21245. *
  21246. * state.ts
  21247. * Abstract state of the Image Tracker
  21248. */
  21249. /**
  21250. * Abstract state of the Image Tracker
  21251. */
  21252. class ImageTrackerState {
  21253. /**
  21254. * Constructor
  21255. * @param name
  21256. * @param imageTracker
  21257. */
  21258. constructor(name, imageTracker) {
  21259. this._name = name;
  21260. this._imageTracker = imageTracker;
  21261. this._pipeline = this._createPipeline();
  21262. }
  21263. /**
  21264. * State name
  21265. */
  21266. get name() {
  21267. return this._name;
  21268. }
  21269. /**
  21270. * AR screen size
  21271. */
  21272. get screenSize() {
  21273. const screen = this._pipeline.node('screen');
  21274. if (!screen)
  21275. throw new IllegalOperationError();
  21276. // this is available once this state has run at least once
  21277. return screen.size;
  21278. }
  21279. /**
  21280. * Initialize the state
  21281. */
  21282. init() {
  21283. }
  21284. /**
  21285. * Release resources
  21286. */
  21287. release() {
  21288. return this._pipeline.release();
  21289. }
  21290. /**
  21291. * Update the state
  21292. * @param media user media
  21293. * @param screenSize AR screen size for image processing
  21294. * @param state all states
  21295. * @returns promise
  21296. */
  21297. update(media, screenSize) {
  21298. const source = this._pipeline.node('source');
  21299. const screen = this._pipeline.node('screen');
  21300. // validate the pipeline
  21301. if (!source || !screen)
  21302. throw new IllegalOperationError();
  21303. // prepare the pipeline
  21304. source.media = media;
  21305. screen.size = screenSize;
  21306. // run the pipeline
  21307. return this._beforeUpdate().then(() => this._gpuUpdate()).then(result => this._afterUpdate(result));
  21308. }
  21309. /**
  21310. * Called as soon as this becomes the active state, just before update() runs for the first time
  21311. * @param settings
  21312. */
  21313. onEnterState(settings) {
  21314. }
  21315. /**
  21316. * Called when leaving the state, after update()
  21317. */
  21318. onLeaveState() {
  21319. }
  21320. /**
  21321. * Called just before the GPU processing
  21322. * @returns promise
  21323. */
  21324. _beforeUpdate() {
  21325. return speedy_vision_default().Promise.resolve();
  21326. }
  21327. /**
  21328. * GPU processing
  21329. * @returns promise with the pipeline results
  21330. */
  21331. _gpuUpdate() {
  21332. return this._pipeline.run();
  21333. }
  21334. //
  21335. // Some utility methods common to various states
  21336. //
  21337. /**
  21338. * Find the coordinates of a polyline surrounding the target image
  21339. * @param homography maps the target image to the AR screen
  21340. * @param targetSize size of the target space
  21341. * @returns promise that resolves to 4 points in AR screen space
  21342. */
  21343. _findPolylineCoordinates(homography, targetSize) {
  21344. const w = targetSize.width, h = targetSize.height;
  21345. const referenceImageCoordinates = speedy_vision_default().Matrix(2, 4, [
  21346. 0, 0,
  21347. w, 0,
  21348. w, h,
  21349. 0, h,
  21350. ]);
  21351. const polylineCoordinates = speedy_vision_default().Matrix.Zeros(2, 4);
  21352. return speedy_vision_default().Matrix.applyPerspectiveTransform(polylineCoordinates, referenceImageCoordinates, homography);
  21353. }
  21354. /**
  21355. * Find a polyline surrounding the target image
  21356. * @param homography maps the target image to the AR screen
  21357. * @param targetSize size of the target space
  21358. * @returns promise that resolves to 4 points in AR screen space
  21359. */
  21360. _findPolyline(homography, targetSize) {
  21361. return this._findPolylineCoordinates(homography, targetSize).then(polylineCoordinates => {
  21362. const polydata = polylineCoordinates.read();
  21363. const polyline = Array.from({ length: 4 }, (_, i) => speedy_vision_default().Point2(polydata[2 * i], polydata[2 * i + 1]));
  21364. return polyline;
  21365. });
  21366. }
  21367. /**
  21368. * Whether or not to rotate the warped image in order to best fit the AR screen
  21369. * @param media media associated with the reference image
  21370. * @param screenSize AR screen
  21371. * @returns boolean
  21372. */
  21373. _mustRotateWarpedImage(media, screenSize) {
  21374. const screenAspectRatio = screenSize.width / screenSize.height;
  21375. const mediaAspectRatio = media.width / media.height;
  21376. const eps = 0.1;
  21377. return (mediaAspectRatio >= 1 + eps && screenAspectRatio < 1 - eps) || (mediaAspectRatio < 1 - eps && screenAspectRatio >= 1 + eps);
  21378. }
  21379. /**
  21380. * Find a rectification matrix to be applied to an image fitting the entire AR screen
  21381. * @param media media associated with the reference image
  21382. * @param screenSize AR screen
  21383. * @returns promise that resolves to a rectification matrix
  21384. */
  21385. _findRectificationMatrixOfFullscreenImage(media, screenSize) {
  21386. const b = TRACK_RECTIFIED_BORDER;
  21387. const sw = screenSize.width, sh = screenSize.height;
  21388. const mediaAspectRatio = media.width / media.height;
  21389. const mustRotate = this._mustRotateWarpedImage(media, screenSize);
  21390. // compute the vertices of the target in screen space
  21391. // we suppose portrait or landscape mode for both screen & media
  21392. const c = mustRotate ? 1 / mediaAspectRatio : mediaAspectRatio;
  21393. const top = sw >= sh ? b * sh : (sh - sw * (1 - 2 * b) / c) / 2;
  21394. const left = sw >= sh ? (sw - sh * (1 - 2 * b) * c) / 2 : b * sw;
  21395. const right = sw - left;
  21396. const bottom = sh - top;
  21397. const targetVertices = speedy_vision_default().Matrix(2, 4, [
  21398. left, top,
  21399. right, top,
  21400. right, bottom,
  21401. left, bottom,
  21402. ]);
  21403. const screenVertices = speedy_vision_default().Matrix(2, 4, [
  21404. 0, 0,
  21405. sw, 0,
  21406. sw, sh,
  21407. 0, sh
  21408. ]);
  21409. const preRectificationMatrix = speedy_vision_default().Matrix.Eye(3);
  21410. const alignmentMatrix = speedy_vision_default().Matrix.Zeros(3);
  21411. const rectificationMatrix = speedy_vision_default().Matrix.Zeros(3);
  21412. return (mustRotate ? speedy_vision_default().Matrix.perspective(
  21413. // pre-rectifation: rotate by 90 degrees counterclockwise and scale to screenSize
  21414. preRectificationMatrix, screenVertices, speedy_vision_default().Matrix(2, 4, [0, sh, 0, 0, sw, 0, sw, sh])) : speedy_vision_default().Promise.resolve(preRectificationMatrix)).then(_ =>
  21415. // alignment: align the target to the center of the screen
  21416. speedy_vision_default().Matrix.perspective(alignmentMatrix, screenVertices, targetVertices)).then(_ =>
  21417. // pre-rectify and then align
  21418. rectificationMatrix.setTo(alignmentMatrix.times(preRectificationMatrix)));
  21419. }
  21420. /**
  21421. * Find a rectification matrix to be applied to the target image
  21422. * @param homography maps a reference image to the AR screen
  21423. * @param targetSize size of the target space
  21424. * @param media media associated with the reference image
  21425. * @param screenSize AR screen
  21426. * @returns promise that resolves to a rectification matrix
  21427. */
  21428. _findRectificationMatrixOfCameraImage(homography, targetSize, media, screenSize) {
  21429. const sw = screenSize.width, sh = screenSize.height;
  21430. const screen = speedy_vision_default().Matrix(2, 4, [0, 0, sw, 0, sw, sh, 0, sh]);
  21431. const rectificationMatrix = speedy_vision_default().Matrix.Zeros(3);
  21432. return this._findPolylineCoordinates(homography, targetSize).then(polyline =>
  21433. // from target space to (full)screen
  21434. speedy_vision_default().Matrix.perspective(rectificationMatrix, polyline, screen)).then(_ =>
  21435. // from (full)screen to rectified coordinates
  21436. this._findRectificationMatrixOfFullscreenImage(media, screenSize)).then(mat =>
  21437. // function composition
  21438. rectificationMatrix.setTo(mat.times(rectificationMatrix)));
  21439. }
  21440. }
  21441. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/initial.ts
  21442. /*
  21443. * MARTINS.js Free Edition
  21444. * GPU-accelerated Augmented Reality for the web
  21445. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21446. * https://github.com/alemart/martins-js
  21447. *
  21448. * This program is free software: you can redistribute it and/or modify
  21449. * it under the terms of the GNU Affero General Public License version 3
  21450. * as published by the Free Software Foundation.
  21451. *
  21452. * This program is distributed in the hope that it will be useful,
  21453. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21454. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21455. * GNU Affero General Public License for more details.
  21456. *
  21457. * You should have received a copy of the GNU Affero General Public License
  21458. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21459. *
  21460. * initial.ts
  21461. * Initial state of the Image Tracker
  21462. */
  21463. /**
  21464. * The purpose of the initial state of the Image Tracker
  21465. * is to initialize the training state using the state machine
  21466. */
  21467. class ImageTrackerInitialState extends ImageTrackerState {
  21468. /**
  21469. * Constructor
  21470. * @param imageTracker
  21471. */
  21472. constructor(imageTracker) {
  21473. super('initial', imageTracker);
  21474. }
  21475. /**
  21476. * Called just before the GPU processing
  21477. * @returns promise
  21478. */
  21479. _beforeUpdate() {
  21480. const source = this._pipeline.node('source');
  21481. const media = source.media;
  21482. const mediaSize = media.size;
  21483. if (mediaSize.area() < this.screenSize.area())
  21484. Utils.warning('The resolution of the tracker is larger than the resolution of the video. This is inefficient.');
  21485. return speedy_vision_default().Promise.resolve();
  21486. }
  21487. /**
  21488. * Post processing that takes place just after the GPU processing
  21489. * @param result pipeline results
  21490. * @returns state output
  21491. */
  21492. _afterUpdate(result) {
  21493. return speedy_vision_default().Promise.resolve({
  21494. nextState: 'training',
  21495. trackerOutput: {},
  21496. });
  21497. }
  21498. /**
  21499. * Create & setup the pipeline
  21500. * @returns pipeline
  21501. */
  21502. _createPipeline() {
  21503. // this pipeline does nothing useful,
  21504. // but it does preload some shaders...
  21505. const pipeline = speedy_vision_default().Pipeline();
  21506. const source = speedy_vision_default().Image.Source('source');
  21507. const screen = speedy_vision_default().Transform.Resize('screen');
  21508. const greyscale = speedy_vision_default().Filter.Greyscale();
  21509. const imageRectifier = speedy_vision_default().Transform.PerspectiveWarp();
  21510. const nightvision = speedy_vision_default().Filter.Nightvision();
  21511. const nightvisionMux = speedy_vision_default().Image.Multiplexer();
  21512. const detector = speedy_vision_default().Keypoint.Detector.Harris();
  21513. const descriptor = speedy_vision_default().Keypoint.Descriptor.ORB();
  21514. const blur = speedy_vision_default().Filter.GaussianBlur();
  21515. const clipper = speedy_vision_default().Keypoint.Clipper();
  21516. const borderClipper = speedy_vision_default().Keypoint.BorderClipper();
  21517. const denoiser = speedy_vision_default().Filter.GaussianBlur();
  21518. const subpixel = speedy_vision_default().Keypoint.SubpixelRefiner();
  21519. const matcher = speedy_vision_default().Keypoint.Matcher.BFKNN();
  21520. const keypointRectifier = speedy_vision_default().Keypoint.Transformer();
  21521. const keypointPortalSink = speedy_vision_default().Keypoint.Portal.Sink();
  21522. const keypointPortalSource = speedy_vision_default().Keypoint.Portal.Source();
  21523. const muxOfReferenceKeypoints = speedy_vision_default().Keypoint.Multiplexer();
  21524. const bufferOfReferenceKeypoints = speedy_vision_default().Keypoint.Buffer();
  21525. const muxOfBufferOfReferenceKeypoints = speedy_vision_default().Keypoint.Multiplexer();
  21526. const keypointSink = speedy_vision_default().Keypoint.SinkOfMatchedKeypoints();
  21527. source.media = null;
  21528. screen.size = speedy_vision_default().Size(0, 0);
  21529. imageRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  21530. nightvision.quality = NIGHTVISION_QUALITY;
  21531. subpixel.method = SUBPIXEL_METHOD;
  21532. //borderClipper.imageSize = screen.size;
  21533. borderClipper.imageSize = speedy_vision_default().Size(100, 100);
  21534. borderClipper.borderSize = speedy_vision_default().Vector2(0, 0);
  21535. matcher.k = 1; //2;
  21536. keypointRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  21537. keypointPortalSource.source = keypointPortalSink;
  21538. muxOfReferenceKeypoints.port = 0;
  21539. muxOfBufferOfReferenceKeypoints.port = 0;
  21540. bufferOfReferenceKeypoints.frozen = false;
  21541. keypointSink.turbo = false;
  21542. // prepare input
  21543. source.output().connectTo(screen.input());
  21544. screen.output().connectTo(greyscale.input());
  21545. // preprocess images
  21546. greyscale.output().connectTo(imageRectifier.input());
  21547. imageRectifier.output().connectTo(nightvisionMux.input('in0'));
  21548. imageRectifier.output().connectTo(nightvision.input());
  21549. nightvision.output().connectTo(nightvisionMux.input('in1'));
  21550. nightvisionMux.output().connectTo(blur.input());
  21551. // keypoint detection & clipping
  21552. nightvisionMux.output().connectTo(detector.input());
  21553. detector.output().connectTo(borderClipper.input());
  21554. borderClipper.output().connectTo(clipper.input());
  21555. // keypoint refinement
  21556. imageRectifier.output().connectTo(denoiser.input());
  21557. denoiser.output().connectTo(subpixel.input('image'));
  21558. clipper.output().connectTo(subpixel.input('keypoints'));
  21559. // keypoint description
  21560. blur.output().connectTo(descriptor.input('image'));
  21561. subpixel.output().connectTo(descriptor.input('keypoints'));
  21562. // keypoint matching
  21563. descriptor.output().connectTo(muxOfReferenceKeypoints.input('in0'));
  21564. muxOfBufferOfReferenceKeypoints.output().connectTo(muxOfReferenceKeypoints.input('in1'));
  21565. muxOfReferenceKeypoints.output().connectTo(matcher.input('database'));
  21566. descriptor.output().connectTo(matcher.input('keypoints'));
  21567. // store reference keypoints
  21568. keypointPortalSource.output().connectTo(muxOfBufferOfReferenceKeypoints.input('in0'));
  21569. bufferOfReferenceKeypoints.output().connectTo(muxOfBufferOfReferenceKeypoints.input('in1'));
  21570. keypointPortalSource.output().connectTo(bufferOfReferenceKeypoints.input());
  21571. // portals
  21572. descriptor.output().connectTo(keypointPortalSink.input());
  21573. // prepare output
  21574. descriptor.output().connectTo(keypointRectifier.input());
  21575. keypointRectifier.output().connectTo(keypointSink.input());
  21576. matcher.output().connectTo(keypointSink.input('matches'));
  21577. // done!
  21578. pipeline.init(source, screen, greyscale, imageRectifier, nightvision, nightvisionMux, blur, detector, subpixel, clipper, borderClipper, denoiser, descriptor, keypointPortalSource, muxOfReferenceKeypoints, matcher, bufferOfReferenceKeypoints, muxOfBufferOfReferenceKeypoints, keypointRectifier, keypointSink, keypointPortalSink);
  21579. /*
  21580. const run = pipeline.run.bind(pipeline);
  21581. pipeline.run = function() {
  21582. console.time("TIME");
  21583. return run().then(x => {
  21584. console.timeEnd("TIME");
  21585. return x;
  21586. });
  21587. };
  21588. */
  21589. return pipeline;
  21590. }
  21591. }
  21592. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/training.ts
  21593. /*
  21594. * MARTINS.js Free Edition
  21595. * GPU-accelerated Augmented Reality for the web
  21596. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21597. * https://github.com/alemart/martins-js
  21598. *
  21599. * This program is free software: you can redistribute it and/or modify
  21600. * it under the terms of the GNU Affero General Public License version 3
  21601. * as published by the Free Software Foundation.
  21602. *
  21603. * This program is distributed in the hope that it will be useful,
  21604. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21605. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21606. * GNU Affero General Public License for more details.
  21607. *
  21608. * You should have received a copy of the GNU Affero General Public License
  21609. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21610. *
  21611. * training.ts
  21612. * Training state of the Image Tracker
  21613. */
  21614. /**
  21615. * Training state of the Image Tracker
  21616. */
  21617. class ImageTrackerTrainingState extends ImageTrackerState {
  21618. /**
  21619. * Constructor
  21620. * @param imageTracker
  21621. */
  21622. constructor(imageTracker) {
  21623. super('training', imageTracker);
  21624. this._currentImageIndex = 0;
  21625. this._image = [];
  21626. // initialize the training map
  21627. this._trainingMap = {
  21628. referenceImageIndex: [],
  21629. referenceImage: [],
  21630. keypoints: []
  21631. };
  21632. }
  21633. /**
  21634. * Called as soon as this becomes the active state, just before update() runs for the first time
  21635. * @param settings
  21636. */
  21637. onEnterState(settings) {
  21638. const database = this._imageTracker.database;
  21639. // validate
  21640. if (database.count == 0)
  21641. throw new TrainingError(`Can't train the Image Tracker: the Reference Image Database is empty`);
  21642. // prepare to train...
  21643. this._currentImageIndex = 0;
  21644. this._image.length = 0;
  21645. this._trainingMap.referenceImageIndex.length = 0;
  21646. this._trainingMap.referenceImage.length = 0;
  21647. this._trainingMap.keypoints.length = 0;
  21648. // lock the database
  21649. Utils.log(`Image Tracker: training using ${database.count} reference image${database.count != 1 ? 's' : ''}`);
  21650. database._lock();
  21651. // collect all images
  21652. for (const referenceImage of database)
  21653. this._image.push(referenceImage);
  21654. }
  21655. /**
  21656. * Called just before the GPU processing
  21657. * @returns promise
  21658. */
  21659. _beforeUpdate() {
  21660. const arScreenSize = this.screenSize;
  21661. const source = this._pipeline.node('source');
  21662. const screen = this._pipeline.node('screen');
  21663. const keypointScaler = this._pipeline.node('keypointScaler');
  21664. // this shouldn't happen
  21665. if (this._currentImageIndex >= this._image.length)
  21666. return speedy_vision_default().Promise.reject(new IllegalOperationError());
  21667. // set the appropriate training media
  21668. const database = this._imageTracker.database;
  21669. const referenceImage = this._image[this._currentImageIndex];
  21670. const media = database._findMedia(referenceImage.name);
  21671. source.media = media;
  21672. // compute the appropriate size of the training image space
  21673. const resolution = this._imageTracker.resolution;
  21674. const scale = TRAIN_IMAGE_SCALE; // ORB is not scale-invariant
  21675. const aspectRatioOfTrainingImage = media.width / media.height;
  21676. /*
  21677. let sin = 0, cos = 1;
  21678. if((aspectRatioOfSourceVideo - 1) * (aspectRatioOfTrainingImage - 1) >= 0) {
  21679. // training image and source video: both in landscape mode or both in portrait mode
  21680. screen.size = Utils.resolution(resolution, aspectRatioOfTrainingImage);
  21681. screen.size.width = Math.round(screen.size.width * scale);
  21682. screen.size.height = Math.round(screen.size.height * scale);
  21683. }
  21684. else if(aspectRatioOfTrainingImage > aspectRatioOfSourceVideo) {
  21685. // training image: portrait mode; source video: landscape mode
  21686. screen.size = Utils.resolution(resolution, 1 / aspectRatioOfTrainingImage);
  21687. screen.size.width = Math.round(screen.size.width * scale);
  21688. screen.size.height = Math.round(screen.size.height * scale);
  21689. sin = 1; cos = 0; // rotate 90deg
  21690. }
  21691. else {
  21692. // training image: landscape mode; source video: portrait mode
  21693. }
  21694. */
  21695. screen.size = Utils.resolution(resolution, aspectRatioOfTrainingImage);
  21696. screen.size.width = Math.round(screen.size.width * scale);
  21697. screen.size.height = Math.round(screen.size.height * scale);
  21698. // convert keypoints from the training image space to AR screen space
  21699. // let's pretend that trained keypoints belong to the AR screen space,
  21700. // regardless of the size of the target image. This will make things
  21701. // easier when computing the homography.
  21702. /*
  21703. const sw = arScreenSize.width / screen.size.width;
  21704. const sh = arScreenSize.height / screen.size.height;
  21705. */
  21706. const sw = TRAIN_TARGET_NORMALIZED_SIZE / screen.size.width;
  21707. const sh = TRAIN_TARGET_NORMALIZED_SIZE / screen.size.height;
  21708. keypointScaler.transform = speedy_vision_default().Matrix(3, 3, [
  21709. sw, 0, 0,
  21710. 0, sh, 0,
  21711. 0, 0, 1,
  21712. ]);
  21713. // log
  21714. Utils.log(`Image Tracker: training using reference image "${referenceImage.name}" at ${screen.size.width}x${screen.size.height}...`);
  21715. // done!
  21716. return speedy_vision_default().Promise.resolve();
  21717. }
  21718. /**
  21719. * Post processing that takes place just after the GPU processing
  21720. * @param result pipeline results
  21721. * @returns state output
  21722. */
  21723. _afterUpdate(result) {
  21724. const referenceImage = this._image[this._currentImageIndex];
  21725. const keypoints = result.keypoints;
  21726. const image = result.image;
  21727. // log
  21728. Utils.log(`Image Tracker: found ${keypoints.length} keypoints in reference image "${referenceImage.name}"`);
  21729. // set the training map, so that we can map all keypoints of the current image to the current image
  21730. this._trainingMap.referenceImage.push(referenceImage);
  21731. for (let i = 0; i < keypoints.length; i++) {
  21732. this._trainingMap.keypoints.push(keypoints[i]);
  21733. this._trainingMap.referenceImageIndex.push(this._currentImageIndex);
  21734. }
  21735. // the current image has been processed!
  21736. ++this._currentImageIndex;
  21737. // set output
  21738. if (this._currentImageIndex >= this._image.length) {
  21739. // finished training!
  21740. return speedy_vision_default().Promise.resolve({
  21741. //nextState: 'training',
  21742. nextState: 'scanning',
  21743. nextStateSettings: {
  21744. keypoints: this._trainingMap.keypoints,
  21745. },
  21746. trackerOutput: {},
  21747. //trackerOutput: { image, keypoints, screenSize: this.screenSize },
  21748. });
  21749. }
  21750. else {
  21751. // we're not done yet
  21752. return speedy_vision_default().Promise.resolve({
  21753. nextState: 'training',
  21754. trackerOutput: {},
  21755. //trackerOutput: { image, keypoints, screenSize: this.screenSize },
  21756. });
  21757. }
  21758. }
  21759. /**
  21760. * Create & setup the pipeline
  21761. * @returns pipeline
  21762. */
  21763. _createPipeline() {
  21764. const pipeline = speedy_vision_default().Pipeline();
  21765. const source = speedy_vision_default().Image.Source('source');
  21766. const screen = speedy_vision_default().Transform.Resize('screen');
  21767. const greyscale = speedy_vision_default().Filter.Greyscale();
  21768. const blur = speedy_vision_default().Filter.GaussianBlur();
  21769. const nightvision = speedy_vision_default().Filter.Nightvision();
  21770. const nightvisionMux = speedy_vision_default().Image.Multiplexer('nightvisionMux');
  21771. const pyramid = speedy_vision_default().Image.Pyramid();
  21772. const detector = speedy_vision_default().Keypoint.Detector.FAST('fast');
  21773. const descriptor = speedy_vision_default().Keypoint.Descriptor.ORB();
  21774. const subpixel = speedy_vision_default().Keypoint.SubpixelRefiner();
  21775. const blurredPyramid = speedy_vision_default().Image.Pyramid();
  21776. const denoiser = speedy_vision_default().Filter.GaussianBlur();
  21777. const clipper = speedy_vision_default().Keypoint.Clipper();
  21778. const keypointScaler = speedy_vision_default().Keypoint.Transformer('keypointScaler');
  21779. const keypointSink = speedy_vision_default().Keypoint.Sink('keypoints');
  21780. const imageSink = speedy_vision_default().Image.Sink('image');
  21781. source.media = null;
  21782. screen.size = speedy_vision_default().Size(0, 0);
  21783. blur.kernelSize = speedy_vision_default().Size(ORB_GAUSSIAN_KSIZE, ORB_GAUSSIAN_KSIZE);
  21784. blur.sigma = speedy_vision_default().Vector2(ORB_GAUSSIAN_SIGMA, ORB_GAUSSIAN_SIGMA);
  21785. nightvision.gain = NIGHTVISION_GAIN;
  21786. nightvision.offset = NIGHTVISION_OFFSET;
  21787. nightvision.decay = NIGHTVISION_DECAY;
  21788. nightvision.quality = NIGHTVISION_QUALITY;
  21789. nightvisionMux.port = SCAN_WITH_NIGHTVISION ? 1 : 0; // 1 = enable nightvision
  21790. detector.levels = SCAN_PYRAMID_LEVELS;
  21791. detector.scaleFactor = SCAN_PYRAMID_SCALEFACTOR;
  21792. detector.threshold = SCAN_FAST_THRESHOLD;
  21793. detector.capacity = 8192;
  21794. subpixel.method = SUBPIXEL_METHOD;
  21795. denoiser.kernelSize = speedy_vision_default().Size(SUBPIXEL_GAUSSIAN_KSIZE, SUBPIXEL_GAUSSIAN_KSIZE);
  21796. denoiser.sigma = speedy_vision_default().Vector2(SUBPIXEL_GAUSSIAN_SIGMA, SUBPIXEL_GAUSSIAN_SIGMA);
  21797. clipper.size = TRAIN_MAX_KEYPOINTS;
  21798. keypointScaler.transform = speedy_vision_default().Matrix.Eye(3);
  21799. keypointSink.turbo = false;
  21800. // prepare input
  21801. source.output().connectTo(screen.input());
  21802. screen.output().connectTo(greyscale.input());
  21803. // preprocess image
  21804. greyscale.output().connectTo(nightvisionMux.input('in0'));
  21805. greyscale.output().connectTo(nightvision.input());
  21806. nightvision.output().connectTo(nightvisionMux.input('in1'));
  21807. nightvisionMux.output().connectTo(pyramid.input());
  21808. // keypoint detection
  21809. pyramid.output().connectTo(detector.input());
  21810. detector.output().connectTo(clipper.input());
  21811. // keypoint refinement
  21812. greyscale.output().connectTo(denoiser.input()); // reduce noise
  21813. denoiser.output().connectTo(blurredPyramid.input());
  21814. clipper.output().connectTo(subpixel.input('keypoints'));
  21815. blurredPyramid.output().connectTo(subpixel.input('image'));
  21816. // keypoint description
  21817. greyscale.output().connectTo(blur.input());
  21818. blur.output().connectTo(descriptor.input('image'));
  21819. clipper.output().connectTo(descriptor.input('keypoints'));
  21820. // prepare output
  21821. descriptor.output().connectTo(keypointScaler.input());
  21822. keypointScaler.output().connectTo(keypointSink.input());
  21823. nightvisionMux.output().connectTo(imageSink.input());
  21824. // done!
  21825. pipeline.init(source, screen, greyscale, nightvision, nightvisionMux, pyramid, detector, blur, descriptor, clipper, denoiser, blurredPyramid, subpixel, keypointScaler, keypointSink, imageSink);
  21826. return pipeline;
  21827. }
  21828. /**
  21829. * Get reference image
  21830. * @param keypointIndex -1 if not found
  21831. * @returns reference image
  21832. */
  21833. referenceImageOfKeypoint(keypointIndex) {
  21834. const imageIndex = this.referenceImageIndexOfKeypoint(keypointIndex);
  21835. if (imageIndex < 0)
  21836. return null;
  21837. return this._trainingMap.referenceImage[imageIndex];
  21838. }
  21839. /**
  21840. * Get reference image index
  21841. * @param keypointIndex -1 if not found
  21842. * @returns reference image index, or -1 if not found
  21843. */
  21844. referenceImageIndexOfKeypoint(keypointIndex) {
  21845. const n = this._trainingMap.referenceImageIndex.length;
  21846. if (keypointIndex < 0 || keypointIndex >= n)
  21847. return -1;
  21848. const imageIndex = this._trainingMap.referenceImageIndex[keypointIndex];
  21849. if (imageIndex < 0 || imageIndex >= this._trainingMap.referenceImage.length)
  21850. return -1;
  21851. return imageIndex;
  21852. }
  21853. /**
  21854. * Get keypoint of the trained set
  21855. * @param keypointIndex -1 if not found
  21856. * @returns a keypoint
  21857. */
  21858. referenceKeypoint(keypointIndex) {
  21859. if (keypointIndex < 0 || keypointIndex >= this._trainingMap.keypoints.length)
  21860. return null;
  21861. return this._trainingMap.keypoints[keypointIndex];
  21862. }
  21863. }
  21864. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/scanning.ts
  21865. /*
  21866. * MARTINS.js Free Edition
  21867. * GPU-accelerated Augmented Reality for the web
  21868. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  21869. * https://github.com/alemart/martins-js
  21870. *
  21871. * This program is free software: you can redistribute it and/or modify
  21872. * it under the terms of the GNU Affero General Public License version 3
  21873. * as published by the Free Software Foundation.
  21874. *
  21875. * This program is distributed in the hope that it will be useful,
  21876. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21877. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21878. * GNU Affero General Public License for more details.
  21879. *
  21880. * You should have received a copy of the GNU Affero General Public License
  21881. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21882. *
  21883. * scanning.ts
  21884. * Scanning state of the Image Tracker
  21885. */
  21886. /** Default target space size (used when training) */
  21887. const DEFAULT_TARGET_SPACE_SIZE = speedy_vision_default().Size(TRAIN_TARGET_NORMALIZED_SIZE, TRAIN_TARGET_NORMALIZED_SIZE);
  21888. /** Port of the portal multiplexer: get new data from the camera */
  21889. const PORT_CAMERA = 0;
  21890. /** Port of the portal multiplexer: get previously memorized data */
  21891. const PORT_MEMORY = 1;
  21892. /**
  21893. * Scanning state of the Image Tracker
  21894. */
  21895. class ImageTrackerScanningState extends ImageTrackerState {
  21896. /**
  21897. * Constructor
  21898. * @param imageTracker
  21899. */
  21900. constructor(imageTracker) {
  21901. super('scanning', imageTracker);
  21902. this._counter = 0;
  21903. this._bestScore = 0;
  21904. this._bestHomography = speedy_vision_default().Matrix.Eye(3);
  21905. }
  21906. /**
  21907. * Called as soon as this becomes the active state, just before update() runs for the first time
  21908. * @param settings
  21909. */
  21910. onEnterState(settings) {
  21911. const imagePortalMux = this._pipeline.node('imagePortalMux');
  21912. const lshTables = this._pipeline.node('lshTables');
  21913. const keypoints = settings.keypoints;
  21914. // set attributes
  21915. this._counter = 0;
  21916. this._bestScore = 0;
  21917. // reset the image memorization circuit
  21918. imagePortalMux.port = PORT_CAMERA;
  21919. // prepare the keypoint matcher
  21920. if (keypoints !== undefined)
  21921. lshTables.keypoints = keypoints;
  21922. }
  21923. /**
  21924. * Post processing that takes place just after the GPU processing
  21925. * @param result pipeline results
  21926. * @returns state output
  21927. */
  21928. _afterUpdate(result) {
  21929. const imagePortalMux = this._pipeline.node('imagePortalMux');
  21930. const keypoints = result.keypoints;
  21931. const matchedKeypoints = this._goodMatches(keypoints);
  21932. // tracker output
  21933. const trackerOutput = {
  21934. keypoints: keypoints,
  21935. screenSize: this.screenSize
  21936. };
  21937. // keep the last memorized image
  21938. imagePortalMux.port = PORT_MEMORY;
  21939. // have we found enough matches...?
  21940. if (matchedKeypoints.length >= SCAN_MIN_MATCHES) {
  21941. return this._findHomography(matchedKeypoints).then(([homography, score]) => {
  21942. // have we found the best homography so far?
  21943. if (score >= this._bestScore) {
  21944. // store it only if we'll be running the pipeline again
  21945. if (this._counter < SCAN_CONSECUTIVE_FRAMES - 1) {
  21946. this._bestScore = score;
  21947. this._bestHomography = homography;
  21948. // memorize the last image, corresponding to the best homography(*)
  21949. imagePortalMux.port = PORT_CAMERA;
  21950. /*
  21951. (*) technically speaking, this is not exactly the case. Since we're
  21952. using turbo to download the keypoints, there's a slight difference
  21953. between the data used to compute the homography and the last image.
  21954. Still, assuming continuity of the video stream, this logic is
  21955. good enough.
  21956. */
  21957. }
  21958. }
  21959. // find a polyline surrounding the target
  21960. return this._findPolyline(homography, DEFAULT_TARGET_SPACE_SIZE);
  21961. }).then(polyline => {
  21962. // continue a little longer in the scanning state
  21963. if (++this._counter < SCAN_CONSECUTIVE_FRAMES) {
  21964. return {
  21965. nextState: this.name,
  21966. trackerOutput: Object.assign({ polyline: polyline }, trackerOutput),
  21967. };
  21968. }
  21969. // this image should correspond to the best homography
  21970. const snapshot = this._pipeline.node('imagePortalSink');
  21971. // the reference image that we'll track
  21972. const referenceImage = this._imageTracker._referenceImageOfKeypoint(matchedKeypoints[0].matches[0].index);
  21973. // let's track the target!
  21974. return {
  21975. nextState: 'pre-tracking',
  21976. nextStateSettings: {
  21977. homography: this._bestHomography,
  21978. snapshot: snapshot,
  21979. referenceImage: referenceImage,
  21980. },
  21981. trackerOutput: Object.assign({ polyline: polyline }, trackerOutput),
  21982. };
  21983. }).catch(() => {
  21984. // continue in the scanning state
  21985. return {
  21986. nextState: this.name,
  21987. trackerOutput: trackerOutput,
  21988. };
  21989. });
  21990. }
  21991. else {
  21992. // not enough matches...!
  21993. this._counter = 0;
  21994. this._bestScore = 0;
  21995. }
  21996. // we'll continue to scan the scene
  21997. return speedy_vision_default().Promise.resolve({
  21998. nextState: this.name,
  21999. trackerOutput: trackerOutput,
  22000. });
  22001. }
  22002. /**
  22003. * Find "high quality" matches of a single reference image
  22004. * @param keypoints
  22005. * @returns high quality matches
  22006. */
  22007. _goodMatches(keypoints) {
  22008. const matchedKeypointsPerImageIndex = Object.create(null);
  22009. // filter "good matches"
  22010. for (let j = keypoints.length - 1; j >= 0; j--) {
  22011. const keypoint = keypoints[j];
  22012. if (keypoint.matches[0].index >= 0 && keypoint.matches[1].index >= 0) {
  22013. const d1 = keypoint.matches[0].distance, d2 = keypoint.matches[1].distance;
  22014. // the best match should be "much better" than the second best match,
  22015. // which means that they are "distinct enough"
  22016. if (d1 <= SCAN_MATCH_RATIO * d2) {
  22017. const idx1 = this._imageTracker._referenceImageIndexOfKeypoint(keypoint.matches[0].index);
  22018. //const idx2 = this._imageTracker._referenceImageIndexOfKeypoint(keypoint.matches[1].index);
  22019. //if(idx1 == idx2 && idx1 >= 0) {
  22020. if (idx1 >= 0) {
  22021. if (!Object.prototype.hasOwnProperty.call(matchedKeypointsPerImageIndex, idx1))
  22022. matchedKeypointsPerImageIndex[idx1] = [];
  22023. matchedKeypointsPerImageIndex[idx1].push(keypoint);
  22024. }
  22025. }
  22026. }
  22027. }
  22028. // find the image with the most matches
  22029. let matchedKeypoints = [];
  22030. for (const imageIndex in matchedKeypointsPerImageIndex) {
  22031. if (matchedKeypointsPerImageIndex[imageIndex].length > matchedKeypoints.length)
  22032. matchedKeypoints = matchedKeypointsPerImageIndex[imageIndex];
  22033. }
  22034. // done!
  22035. return matchedKeypoints;
  22036. }
  22037. /**
  22038. * Find a homography matrix using matched keypoints
  22039. * @param matchedKeypoints "good" matches only
  22040. * @returns homography from reference image space to AR screen space & homography "quality" score
  22041. */
  22042. _findHomography(matchedKeypoints) {
  22043. const srcCoords = [];
  22044. const dstCoords = [];
  22045. // find matching coordinates of the keypoints
  22046. for (let i = matchedKeypoints.length - 1; i >= 0; i--) {
  22047. const matchedKeypoint = matchedKeypoints[i];
  22048. const referenceKeypoint = this._imageTracker._referenceKeypoint(matchedKeypoint.matches[0].index);
  22049. if (referenceKeypoint != null) {
  22050. srcCoords.push(referenceKeypoint.x);
  22051. srcCoords.push(referenceKeypoint.y);
  22052. dstCoords.push(matchedKeypoint.x);
  22053. dstCoords.push(matchedKeypoint.y);
  22054. }
  22055. else {
  22056. // this shouldn't happen
  22057. return speedy_vision_default().Promise.reject(new DetectionError(`Invalid keypoint match index: ${matchedKeypoint.matches[0].index} from ${matchedKeypoint.toString()}`));
  22058. }
  22059. }
  22060. // too few points?
  22061. const n = srcCoords.length / 2;
  22062. if (n < 4) {
  22063. return speedy_vision_default().Promise.reject(new DetectionError(`Too few points to compute a homography`));
  22064. }
  22065. // compute a homography
  22066. const src = speedy_vision_default().Matrix(2, n, srcCoords);
  22067. const dst = speedy_vision_default().Matrix(2, n, dstCoords);
  22068. const mask = speedy_vision_default().Matrix.Zeros(1, n);
  22069. const homography = speedy_vision_default().Matrix.Zeros(3);
  22070. return speedy_vision_default().Matrix.findHomography(homography, src, dst, {
  22071. method: 'pransac',
  22072. reprojectionError: SCAN_RANSAC_REPROJECTIONERROR,
  22073. numberOfHypotheses: 512,
  22074. bundleSize: 128,
  22075. mask: mask,
  22076. }).then(homography => {
  22077. // check if this is a valid homography
  22078. const a00 = homography.at(0, 0);
  22079. if (Number.isNaN(a00))
  22080. throw new DetectionError(`Can't compute homography`);
  22081. // count the number of inliers
  22082. const inliers = mask.read();
  22083. let inlierCount = 0;
  22084. for (let i = inliers.length - 1; i >= 0; i--)
  22085. inlierCount += inliers[i];
  22086. const score = inlierCount / inliers.length;
  22087. // done!
  22088. return [homography, score];
  22089. });
  22090. }
  22091. /**
  22092. * Create & setup the pipeline
  22093. * @returns pipeline
  22094. */
  22095. _createPipeline() {
  22096. const pipeline = speedy_vision_default().Pipeline();
  22097. const source = speedy_vision_default().Image.Source('source');
  22098. const screen = speedy_vision_default().Transform.Resize('screen');
  22099. const greyscale = speedy_vision_default().Filter.Greyscale();
  22100. const blur = speedy_vision_default().Filter.GaussianBlur();
  22101. const nightvision = speedy_vision_default().Filter.Nightvision();
  22102. const nightvisionMux = speedy_vision_default().Image.Multiplexer('nightvisionMux');
  22103. const pyramid = speedy_vision_default().Image.Pyramid();
  22104. const detector = speedy_vision_default().Keypoint.Detector.FAST();
  22105. const descriptor = speedy_vision_default().Keypoint.Descriptor.ORB();
  22106. const clipper = speedy_vision_default().Keypoint.Clipper();
  22107. const lshTables = speedy_vision_default().Keypoint.Matcher.StaticLSHTables('lshTables');
  22108. const knn = speedy_vision_default().Keypoint.Matcher.LSHKNN();
  22109. const keypointSink = speedy_vision_default().Keypoint.SinkOfMatchedKeypoints('keypoints');
  22110. const imagePortalSink = speedy_vision_default().Image.Portal.Sink('imagePortalSink');
  22111. const imagePortalSource = speedy_vision_default().Image.Portal.Source('imagePortalSource');
  22112. const imagePortalMux = speedy_vision_default().Image.Multiplexer('imagePortalMux');
  22113. const imagePortalBuffer = speedy_vision_default().Image.Buffer();
  22114. const imagePortalCopy = speedy_vision_default().Transform.Resize();
  22115. //const imageSink = Speedy.Image.Sink('image');
  22116. source.media = null;
  22117. screen.size = speedy_vision_default().Size(0, 0);
  22118. blur.kernelSize = speedy_vision_default().Size(ORB_GAUSSIAN_KSIZE, ORB_GAUSSIAN_KSIZE);
  22119. blur.sigma = speedy_vision_default().Vector2(ORB_GAUSSIAN_SIGMA, ORB_GAUSSIAN_SIGMA);
  22120. nightvision.gain = NIGHTVISION_GAIN;
  22121. nightvision.offset = NIGHTVISION_OFFSET;
  22122. nightvision.decay = NIGHTVISION_DECAY;
  22123. nightvision.quality = NIGHTVISION_QUALITY;
  22124. nightvisionMux.port = SCAN_WITH_NIGHTVISION ? 1 : 0; // 1 = enable nightvision
  22125. detector.levels = SCAN_PYRAMID_LEVELS;
  22126. detector.scaleFactor = SCAN_PYRAMID_SCALEFACTOR;
  22127. detector.threshold = SCAN_FAST_THRESHOLD;
  22128. detector.capacity = 2048;
  22129. clipper.size = SCAN_MAX_KEYPOINTS;
  22130. lshTables.keypoints = [];
  22131. lshTables.numberOfTables = SCAN_LSH_TABLES;
  22132. lshTables.hashSize = SCAN_LSH_HASHSIZE;
  22133. knn.k = 2;
  22134. knn.quality = 'default';
  22135. //knn.quality = 'fastest';
  22136. imagePortalSource.source = imagePortalSink;
  22137. imagePortalMux.port = PORT_CAMERA; // 0 = camera stream; 1 = lock image
  22138. imagePortalCopy.size = speedy_vision_default().Size(0, 0);
  22139. imagePortalCopy.scale = speedy_vision_default().Vector2(1, 1);
  22140. keypointSink.turbo = true;
  22141. // prepare input
  22142. source.output().connectTo(screen.input());
  22143. screen.output().connectTo(greyscale.input());
  22144. // preprocess image
  22145. greyscale.output().connectTo(blur.input());
  22146. greyscale.output().connectTo(nightvisionMux.input('in0'));
  22147. greyscale.output().connectTo(nightvision.input());
  22148. nightvision.output().connectTo(nightvisionMux.input('in1'));
  22149. nightvisionMux.output().connectTo(pyramid.input());
  22150. // keypoint detection
  22151. pyramid.output().connectTo(detector.input());
  22152. detector.output().connectTo(clipper.input());
  22153. // keypoint description
  22154. blur.output().connectTo(descriptor.input('image'));
  22155. clipper.output().connectTo(descriptor.input('keypoints'));
  22156. // keypoint matching
  22157. descriptor.output().connectTo(knn.input('keypoints'));
  22158. lshTables.output().connectTo(knn.input('lsh'));
  22159. // prepare output
  22160. clipper.output().connectTo(keypointSink.input());
  22161. knn.output().connectTo(keypointSink.input('matches'));
  22162. //pyramid.output().connectTo(imageSink.input());
  22163. // memorize image
  22164. source.output().connectTo(imagePortalBuffer.input());
  22165. imagePortalBuffer.output().connectTo(imagePortalMux.input('in0'));
  22166. imagePortalSource.output().connectTo(imagePortalCopy.input());
  22167. imagePortalCopy.output().connectTo(imagePortalMux.input('in1'));
  22168. imagePortalMux.output().connectTo(imagePortalSink.input());
  22169. // done!
  22170. pipeline.init(source, screen, greyscale, blur, nightvision, nightvisionMux, pyramid, detector, descriptor, clipper, lshTables, knn, keypointSink, imagePortalSink, imagePortalSource, imagePortalMux, imagePortalBuffer, imagePortalCopy);
  22171. return pipeline;
  22172. }
  22173. }
  22174. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/pre-tracking.ts
  22175. /*
  22176. * MARTINS.js Free Edition
  22177. * GPU-accelerated Augmented Reality for the web
  22178. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  22179. * https://github.com/alemart/martins-js
  22180. *
  22181. * This program is free software: you can redistribute it and/or modify
  22182. * it under the terms of the GNU Affero General Public License version 3
  22183. * as published by the Free Software Foundation.
  22184. *
  22185. * This program is distributed in the hope that it will be useful,
  22186. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22187. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22188. * GNU Affero General Public License for more details.
  22189. *
  22190. * You should have received a copy of the GNU Affero General Public License
  22191. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  22192. *
  22193. * pre-tracking.ts
  22194. * Pre-tracking state of the Image Tracker
  22195. */
  22196. /** Default target space size (used when training) */
  22197. const pre_tracking_DEFAULT_TARGET_SPACE_SIZE = speedy_vision_default().Size(TRAIN_TARGET_NORMALIZED_SIZE, TRAIN_TARGET_NORMALIZED_SIZE);
  22198. /** Use the camera stream as the input of the pipeline */
  22199. const PORT_CAMERA_IMAGE = 1;
  22200. /** Use the reference image as the input of the pipeline */
  22201. const PORT_REFERENCE_IMAGE = 0;
  22202. /**
  22203. * The pre-tracking state of the Image Tracker is a new training
  22204. * phase for the particular, actual target we'll be tracking
  22205. */
  22206. class ImageTrackerPreTrackingState extends ImageTrackerState {
  22207. /**
  22208. * Constructor
  22209. * @param imageTracker
  22210. */
  22211. constructor(imageTracker) {
  22212. super('pre-tracking', imageTracker);
  22213. this._homography = speedy_vision_default().Matrix.Eye(3);
  22214. this._referenceImage = null;
  22215. this._step = 'read-reference-image';
  22216. this._referenceKeypoints = [];
  22217. this._iterations = 0;
  22218. }
  22219. /**
  22220. * Called as soon as this becomes the active state, just before update() runs for the first time
  22221. * @param settings
  22222. */
  22223. onEnterState(settings) {
  22224. const imagePortalSource = this._pipeline.node('imagePortalSource');
  22225. const muxOfReferenceKeypoints = this._pipeline.node('muxOfReferenceKeypoints');
  22226. const muxOfBufferOfReferenceKeypoints = this._pipeline.node('muxOfBufferOfReferenceKeypoints');
  22227. const bufferOfReferenceKeypoints = this._pipeline.node('bufferOfReferenceKeypoints');
  22228. const homography = settings.homography;
  22229. const referenceImage = settings.referenceImage;
  22230. const snapshot = settings.snapshot;
  22231. // this shouldn't happen
  22232. if (!referenceImage)
  22233. throw new TrackingError(`Can't track a null reference image`);
  22234. // set attributes
  22235. this._homography = homography;
  22236. this._referenceImage = referenceImage;
  22237. this._step = 'read-reference-image';
  22238. this._referenceKeypoints = [];
  22239. this._iterations = 0;
  22240. // setup the pipeline
  22241. imagePortalSource.source = snapshot;
  22242. muxOfReferenceKeypoints.port = 0;
  22243. muxOfBufferOfReferenceKeypoints.port = 0;
  22244. bufferOfReferenceKeypoints.frozen = false;
  22245. }
  22246. /**
  22247. * Called just before the GPU processing
  22248. * @returns promise
  22249. */
  22250. _beforeUpdate() {
  22251. const referenceImage = this._referenceImage;
  22252. const source = this._pipeline.node('source');
  22253. const sourceMux = this._pipeline.node('sourceMux');
  22254. const imageRectifier = this._pipeline.node('imageRectifier');
  22255. const keypointRectifier = this._pipeline.node('keypointRectifier');
  22256. const borderClipper = this._pipeline.node('borderClipper');
  22257. const screenSize = this.screenSize;
  22258. // set the source media to the reference image we're going to track
  22259. const targetMedia = this._imageTracker.database._findMedia(referenceImage.name);
  22260. source.media = targetMedia;
  22261. // setup the source multiplexer
  22262. if (this._step == 'read-reference-image')
  22263. sourceMux.port = PORT_REFERENCE_IMAGE;
  22264. else
  22265. sourceMux.port = PORT_CAMERA_IMAGE;
  22266. // clip keypoints from the borders of the target image
  22267. borderClipper.imageSize = screenSize;
  22268. borderClipper.borderSize = speedy_vision_default().Vector2(screenSize.width * TRACK_CLIPPING_BORDER, screenSize.height * TRACK_CLIPPING_BORDER);
  22269. // rectify the image
  22270. const rectify = (this._step == 'read-reference-image') ?
  22271. this._findRectificationMatrixOfFullscreenImage(targetMedia, screenSize) :
  22272. this._findRectificationMatrixOfCameraImage(this._homography, pre_tracking_DEFAULT_TARGET_SPACE_SIZE, targetMedia, screenSize);
  22273. return rectify.then(rectificationMatrix => {
  22274. imageRectifier.transform = rectificationMatrix;
  22275. });
  22276. }
  22277. /**
  22278. * Post processing that takes place just after the GPU processing
  22279. * @param result pipeline results
  22280. * @returns state output
  22281. */
  22282. _afterUpdate(result) {
  22283. const referenceImage = this._referenceImage;
  22284. const imagePortalSink = this._pipeline.node('imagePortal');
  22285. const keypointPortalSink = this._pipeline.node('keypointPortalSink');
  22286. const muxOfReferenceKeypoints = this._pipeline.node('muxOfReferenceKeypoints');
  22287. const muxOfBufferOfReferenceKeypoints = this._pipeline.node('muxOfBufferOfReferenceKeypoints');
  22288. const bufferOfReferenceKeypoints = this._pipeline.node('bufferOfReferenceKeypoints');
  22289. const keypoints = result.keypoints;
  22290. const image = result.image;
  22291. // tracker output
  22292. const trackerOutput = {
  22293. keypoints: image !== undefined ? keypoints : undefined,
  22294. image: image,
  22295. screenSize: this.screenSize,
  22296. };
  22297. // decide what to do next
  22298. switch (this._step) {
  22299. case 'read-reference-image': {
  22300. // enable matching
  22301. muxOfReferenceKeypoints.port = 1;
  22302. // store reference keypoints
  22303. this._referenceKeypoints = keypoints;
  22304. // next step
  22305. this._step = 'warp-camera-image';
  22306. return speedy_vision_default().Promise.resolve({
  22307. nextState: 'pre-tracking',
  22308. trackerOutput: trackerOutput,
  22309. });
  22310. }
  22311. case 'warp-camera-image': {
  22312. // freeze reference keypoints
  22313. bufferOfReferenceKeypoints.frozen = true;
  22314. muxOfBufferOfReferenceKeypoints.port = 1;
  22315. // refine warp?
  22316. if (++this._iterations < TRACK_REFINEMENT_ITERATIONS)
  22317. this._step = 'warp-camera-image';
  22318. else
  22319. this._step = 'train-camera-image';
  22320. // warp image & go to next step
  22321. return this._findWarp(keypoints, this._referenceKeypoints).then(warp => this._homography.setTo(this._homography.times(warp))).then(_ => ({
  22322. nextState: 'pre-tracking',
  22323. trackerOutput: trackerOutput,
  22324. })).catch(err => {
  22325. Utils.warning(`Can't pre-track target image "${referenceImage.name}". ${err.toString()}`);
  22326. return {
  22327. nextState: 'scanning',
  22328. trackerOutput: trackerOutput,
  22329. };
  22330. });
  22331. }
  22332. case 'train-camera-image': {
  22333. // log
  22334. Utils.log(`Took a snapshot of target image "${referenceImage.name}". Found ${keypoints.length} keypoints.`);
  22335. // change the coordinates
  22336. return this._changeSpace(this._homography, this.screenSize).then(homography => {
  22337. // we're ready to track the target!
  22338. return speedy_vision_default().Promise.resolve({
  22339. //nextState: 'pre-tracking',
  22340. nextState: 'tracking',
  22341. trackerOutput: trackerOutput,
  22342. nextStateSettings: {
  22343. homography: homography,
  22344. referenceImage: referenceImage,
  22345. templateKeypoints: keypoints,
  22346. keypointPortalSink: keypointPortalSink,
  22347. imagePortalSink: imagePortalSink,
  22348. screenSize: this.screenSize,
  22349. },
  22350. });
  22351. });
  22352. }
  22353. }
  22354. }
  22355. /**
  22356. * Find an adjustment warp between the camera image and the reference image
  22357. * @param dstKeypoints destination
  22358. * @param srcKeypoints source
  22359. * @returns a promise that resolves to a 3x3 homography
  22360. */
  22361. _findWarp(dstKeypoints, srcKeypoints) {
  22362. //return Speedy.Promise.resolve(Speedy.Matrix.Eye(3));
  22363. const srcCoords = [];
  22364. const dstCoords = [];
  22365. // find matching coordinates of the keypoints
  22366. for (let i = 0; i < dstKeypoints.length; i++) {
  22367. const dstKeypoint = dstKeypoints[i];
  22368. if (dstKeypoint.matches[0].index >= 0 && dstKeypoint.matches[1].index >= 0) {
  22369. const d1 = dstKeypoint.matches[0].distance, d2 = dstKeypoint.matches[1].distance;
  22370. // the best match should be "much better" than the second best match,
  22371. // which means that they are "distinct enough"
  22372. if (d1 <= TRACK_MATCH_RATIO * d2) {
  22373. const srcKeypoint = srcKeypoints[dstKeypoint.matches[0].index];
  22374. srcCoords.push(srcKeypoint.x);
  22375. srcCoords.push(srcKeypoint.y);
  22376. dstCoords.push(dstKeypoint.x);
  22377. dstCoords.push(dstKeypoint.y);
  22378. }
  22379. }
  22380. }
  22381. // too few points?
  22382. const n = srcCoords.length / 2;
  22383. if (n < 4) {
  22384. return speedy_vision_default().Promise.reject(new TrackingError('Too few points to compute a warp'));
  22385. }
  22386. // compute warp
  22387. const model = speedy_vision_default().Matrix.Eye(3);
  22388. return this._findKeypointWarp().then(transform =>
  22389. // rectify keypoints
  22390. speedy_vision_default().Matrix.applyAffineTransform(speedy_vision_default().Matrix.Zeros(2, 2 * n), speedy_vision_default().Matrix(2, 2 * n, srcCoords.concat(dstCoords)), transform.block(0, 1, 0, 2))).then(points =>
  22391. // find warp
  22392. speedy_vision_default().Matrix.findAffineTransform(model.block(0, 1, 0, 2), points.block(0, 1, 0, n - 1), points.block(0, 1, n, 2 * n - 1), {
  22393. method: 'pransac',
  22394. reprojectionError: TRACK_RANSAC_REPROJECTIONERROR,
  22395. numberOfHypotheses: 512 * 4,
  22396. bundleSize: 128,
  22397. })).then(_ => {
  22398. // validate the model
  22399. const a00 = model.at(0, 0);
  22400. if (Number.isNaN(a00))
  22401. throw new TrackingError(`Can't compute warp: bad keypoints`);
  22402. // done!
  22403. return model;
  22404. });
  22405. }
  22406. /**
  22407. * Find a warp to be applied to the keypoints
  22408. * @returns affine transform
  22409. */
  22410. _findKeypointWarp() {
  22411. const referenceImage = this._referenceImage;
  22412. const media = this._imageTracker.database._findMedia(referenceImage.name);
  22413. const screenSize = this.screenSize;
  22414. // no rotation is needed
  22415. if (!this._mustRotateWarpedImage(media, screenSize))
  22416. return speedy_vision_default().Promise.resolve(speedy_vision_default().Matrix.Eye(3));
  22417. // rotate by 90 degrees clockwise around the pivot
  22418. const px = screenSize.width / 2, py = screenSize.height / 2; // pivot
  22419. return speedy_vision_default().Promise.resolve(speedy_vision_default().Matrix(3, 3, [
  22420. 0, 1, 0,
  22421. -1, 0, 0,
  22422. py + px, py - px, 1,
  22423. ]));
  22424. }
  22425. /**
  22426. * Change the space of the homography in order to improve tracking quality
  22427. * @param homography mapping coordinates from normalized target space to AR screen space
  22428. * @param screenSize AR screen size
  22429. * @returns homography mapping coordinates from AR screen space to AR screen space
  22430. */
  22431. _changeSpace(homography, screenSize) {
  22432. const sw = screenSize.width, sh = screenSize.height;
  22433. const screen = speedy_vision_default().Matrix(2, 4, [0, 0, sw, 0, sw, sh, 0, sh]);
  22434. const mat = speedy_vision_default().Matrix.Zeros(3);
  22435. return this._findPolylineCoordinates(homography, pre_tracking_DEFAULT_TARGET_SPACE_SIZE).then(polyline => speedy_vision_default().Matrix.perspective(mat, screen, polyline));
  22436. }
  22437. /**
  22438. * Create & setup the pipeline
  22439. * @returns pipeline
  22440. */
  22441. _createPipeline() {
  22442. const pipeline = speedy_vision_default().Pipeline();
  22443. const source = speedy_vision_default().Image.Source('source');
  22444. const imagePortalSource = speedy_vision_default().Image.Portal.Source('imagePortalSource');
  22445. const sourceMux = speedy_vision_default().Image.Multiplexer('sourceMux');
  22446. const screen = speedy_vision_default().Transform.Resize('screen');
  22447. const greyscale = speedy_vision_default().Filter.Greyscale();
  22448. const imageRectifier = speedy_vision_default().Transform.PerspectiveWarp('imageRectifier');
  22449. const nightvision = speedy_vision_default().Filter.Nightvision();
  22450. const nightvisionMux = speedy_vision_default().Image.Multiplexer();
  22451. const detector = speedy_vision_default().Keypoint.Detector.Harris();
  22452. const descriptor = speedy_vision_default().Keypoint.Descriptor.ORB();
  22453. const blur = speedy_vision_default().Filter.GaussianBlur();
  22454. const clipper = speedy_vision_default().Keypoint.Clipper();
  22455. const borderClipper = speedy_vision_default().Keypoint.BorderClipper('borderClipper');
  22456. const denoiser = speedy_vision_default().Filter.GaussianBlur();
  22457. const subpixel = speedy_vision_default().Keypoint.SubpixelRefiner();
  22458. const matcher = speedy_vision_default().Keypoint.Matcher.BFKNN();
  22459. const keypointRectifier = speedy_vision_default().Keypoint.Transformer('keypointRectifier');
  22460. const keypointPortalSink = speedy_vision_default().Keypoint.Portal.Sink('keypointPortalSink');
  22461. const keypointPortalSource = speedy_vision_default().Keypoint.Portal.Source('keypointPortalSource');
  22462. const muxOfReferenceKeypoints = speedy_vision_default().Keypoint.Multiplexer('muxOfReferenceKeypoints');
  22463. const bufferOfReferenceKeypoints = speedy_vision_default().Keypoint.Buffer('bufferOfReferenceKeypoints');
  22464. const muxOfBufferOfReferenceKeypoints = speedy_vision_default().Keypoint.Multiplexer('muxOfBufferOfReferenceKeypoints');
  22465. const keypointSink = speedy_vision_default().Keypoint.SinkOfMatchedKeypoints('keypoints');
  22466. const imageSink = speedy_vision_default().Image.Sink('image');
  22467. source.media = null;
  22468. screen.size = speedy_vision_default().Size(0, 0);
  22469. imagePortalSource.source = null;
  22470. imageRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  22471. sourceMux.port = PORT_REFERENCE_IMAGE;
  22472. nightvision.gain = NIGHTVISION_GAIN;
  22473. nightvision.offset = NIGHTVISION_OFFSET;
  22474. nightvision.decay = NIGHTVISION_DECAY;
  22475. nightvision.quality = NIGHTVISION_QUALITY;
  22476. nightvisionMux.port = TRACK_WITH_NIGHTVISION ? 1 : 0; // 1 = enable nightvision
  22477. blur.kernelSize = speedy_vision_default().Size(ORB_GAUSSIAN_KSIZE, ORB_GAUSSIAN_KSIZE);
  22478. blur.sigma = speedy_vision_default().Vector2(ORB_GAUSSIAN_SIGMA, ORB_GAUSSIAN_SIGMA);
  22479. denoiser.kernelSize = speedy_vision_default().Size(SUBPIXEL_GAUSSIAN_KSIZE, SUBPIXEL_GAUSSIAN_KSIZE);
  22480. denoiser.sigma = speedy_vision_default().Vector2(SUBPIXEL_GAUSSIAN_SIGMA, SUBPIXEL_GAUSSIAN_SIGMA);
  22481. detector.quality = TRACK_HARRIS_QUALITY;
  22482. detector.capacity = TRACK_DETECTOR_CAPACITY;
  22483. subpixel.method = SUBPIXEL_METHOD;
  22484. clipper.size = TRACK_MAX_KEYPOINTS;
  22485. borderClipper.imageSize = screen.size;
  22486. borderClipper.borderSize = speedy_vision_default().Vector2(0, 0);
  22487. matcher.k = 2;
  22488. keypointRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  22489. keypointPortalSource.source = keypointPortalSink;
  22490. muxOfReferenceKeypoints.port = 0;
  22491. muxOfBufferOfReferenceKeypoints.port = 0;
  22492. bufferOfReferenceKeypoints.frozen = false;
  22493. keypointSink.turbo = false;
  22494. // prepare input
  22495. source.output().connectTo(sourceMux.input('in0')); // port 0: reference image
  22496. imagePortalSource.output().connectTo(sourceMux.input('in1')); // port 1: camera image (via portal)
  22497. sourceMux.output().connectTo(screen.input());
  22498. screen.output().connectTo(greyscale.input());
  22499. // preprocess images
  22500. greyscale.output().connectTo(imageRectifier.input());
  22501. imageRectifier.output().connectTo(nightvisionMux.input('in0'));
  22502. imageRectifier.output().connectTo(nightvision.input());
  22503. nightvision.output().connectTo(nightvisionMux.input('in1'));
  22504. nightvisionMux.output().connectTo(blur.input());
  22505. // keypoint detection & clipping
  22506. nightvisionMux.output().connectTo(detector.input());
  22507. detector.output().connectTo(borderClipper.input());
  22508. borderClipper.output().connectTo(clipper.input());
  22509. // keypoint refinement
  22510. imageRectifier.output().connectTo(denoiser.input());
  22511. denoiser.output().connectTo(subpixel.input('image'));
  22512. clipper.output().connectTo(subpixel.input('keypoints'));
  22513. // keypoint description
  22514. blur.output().connectTo(descriptor.input('image'));
  22515. subpixel.output().connectTo(descriptor.input('keypoints'));
  22516. // keypoint matching
  22517. descriptor.output().connectTo(muxOfReferenceKeypoints.input('in0'));
  22518. muxOfBufferOfReferenceKeypoints.output().connectTo(muxOfReferenceKeypoints.input('in1'));
  22519. muxOfReferenceKeypoints.output().connectTo(matcher.input('database'));
  22520. descriptor.output().connectTo(matcher.input('keypoints'));
  22521. // store reference keypoints
  22522. keypointPortalSource.output().connectTo(muxOfBufferOfReferenceKeypoints.input('in0'));
  22523. bufferOfReferenceKeypoints.output().connectTo(muxOfBufferOfReferenceKeypoints.input('in1'));
  22524. keypointPortalSource.output().connectTo(bufferOfReferenceKeypoints.input());
  22525. // portals
  22526. descriptor.output().connectTo(keypointPortalSink.input());
  22527. // prepare output
  22528. descriptor.output().connectTo(keypointRectifier.input());
  22529. keypointRectifier.output().connectTo(keypointSink.input());
  22530. matcher.output().connectTo(keypointSink.input('matches'));
  22531. //imageRectifier.output().connectTo(imageSink.input());
  22532. // done!
  22533. pipeline.init(source, imagePortalSource, sourceMux, screen, greyscale, imageRectifier, nightvision, nightvisionMux, blur, detector, subpixel, clipper, borderClipper, denoiser, descriptor, keypointPortalSource, muxOfReferenceKeypoints, matcher, bufferOfReferenceKeypoints, muxOfBufferOfReferenceKeypoints, keypointRectifier, keypointSink, keypointPortalSink);
  22534. return pipeline;
  22535. }
  22536. }
  22537. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/image-tracker-event.ts
  22538. /*
  22539. * MARTINS.js Free Edition
  22540. * GPU-accelerated Augmented Reality for the web
  22541. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  22542. * https://github.com/alemart/martins-js
  22543. *
  22544. * This program is free software: you can redistribute it and/or modify
  22545. * it under the terms of the GNU Affero General Public License version 3
  22546. * as published by the Free Software Foundation.
  22547. *
  22548. * This program is distributed in the hope that it will be useful,
  22549. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22550. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22551. * GNU Affero General Public License for more details.
  22552. *
  22553. * You should have received a copy of the GNU Affero General Public License
  22554. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  22555. *
  22556. * image-tracker-event.ts
  22557. * Events emitted by an Image Tracker
  22558. */
  22559. /**
  22560. * An event emitted by an Image Tracker
  22561. */
  22562. class ImageTrackerEvent extends AREvent {
  22563. /**
  22564. * Constructor
  22565. * @param type event type
  22566. * @param referenceImage optional reference image
  22567. */
  22568. constructor(type, referenceImage) {
  22569. super(type);
  22570. this._referenceImage = referenceImage;
  22571. }
  22572. /**
  22573. * Reference image
  22574. */
  22575. get referenceImage() {
  22576. return this._referenceImage;
  22577. }
  22578. }
  22579. ;// CONCATENATED MODULE: ./src/geometry/camera-model.ts
  22580. /*
  22581. * MARTINS.js Free Edition
  22582. * GPU-accelerated Augmented Reality for the web
  22583. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  22584. * https://github.com/alemart/martins-js
  22585. *
  22586. * This program is free software: you can redistribute it and/or modify
  22587. * it under the terms of the GNU Affero General Public License version 3
  22588. * as published by the Free Software Foundation.
  22589. *
  22590. * This program is distributed in the hope that it will be useful,
  22591. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22592. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22593. * GNU Affero General Public License for more details.
  22594. *
  22595. * You should have received a copy of the GNU Affero General Public License
  22596. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  22597. *
  22598. * camera-model.ts
  22599. * Camera model
  22600. */
  22601. /** Number of samples we'll be keeping to help calibrate the camera */
  22602. const INTRISICS_SAMPLES = 401; //201; //31; // odd number
  22603. /** Whether or not to auto-calibrate the camera */
  22604. const FOVY_AUTODETECT = false; //true;
  22605. /** A guess of the vertical field-of-view of a generic camera, in degrees */
  22606. const FOVY_GUESS = 45; //50; // will be part of the viewing frustum
  22607. /** Number of iterations used to refine the estimated pose */
  22608. const POSE_ITERATIONS = 30;
  22609. /** Number of samples used in the rotation filter */
  22610. const ROTATION_FILTER_SAMPLES = 10;
  22611. /** Number of samples used in the translation filter */
  22612. const TRANSLATION_FILTER_SAMPLES = 10;
  22613. /** Convert degrees to radians */
  22614. const DEG2RAD = 0.017453292519943295; // pi / 180
  22615. /** Convert radians to degrees */
  22616. const RAD2DEG = 57.29577951308232; // 180 / pi
  22617. /** Numerical tolerance */
  22618. const EPSILON = 1e-6;
  22619. /** Index of the horizontal focal length in the camera intrinsics matrix (column-major format) */
  22620. const FX = 0;
  22621. /** Index of the vertical focal length in the camera intrinsics matrix */
  22622. const FY = 4;
  22623. /** Index of the horizontal position of the principal point in the camera intrinsics matrix */
  22624. const U0 = 6;
  22625. /** Index of the vertical position of the principal point in the camera intrinsics matrix */
  22626. const V0 = 7;
  22627. /** Translation refinement: predefined buffers for efficiency */
  22628. const TRANSLATION_REFINEMENT_BUFFERS = (() => {
  22629. const l = 1.0;
  22630. const x = [0, l, 0, -l, 0];
  22631. const y = [-l, 0, l, 0, 0];
  22632. const n = x.length;
  22633. return Object.freeze({
  22634. x, y,
  22635. a1: new Array(n),
  22636. a2: new Array(n),
  22637. a3: new Array(n),
  22638. m: new Array(3 * n * 3),
  22639. v: new Array(3 * n),
  22640. t: new Array(3),
  22641. r: new Array(3 * n),
  22642. c: new Array(3),
  22643. Mc: new Array(3 * n),
  22644. });
  22645. })();
  22646. /** Translation refinement: number of iterations */
  22647. const TRANSLATION_REFINEMENT_ITERATIONS = 3; // 1; // 5;
  22648. /** Translation refinement: number of samples */
  22649. const TRANSLATION_REFINEMENT_SAMPLES = 5; // TRANSLATION_REFINEMENT_BUFFERS.x.length;
  22650. /** Translation refinement: the triple of the number of samples */
  22651. const TRANSLATION_REFINEMENT_SAMPLES_3X = 15; //3 * TRANSLATION_REFINEMENT_SAMPLES;
  22652. /**
  22653. * Camera model
  22654. */
  22655. class CameraModel {
  22656. /**
  22657. * Constructor
  22658. */
  22659. constructor() {
  22660. this._screenSize = speedy_vision_default().Size(0, 0);
  22661. this._matrix = speedy_vision_default().Matrix.Eye(3, 4);
  22662. this._intrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1]; // identity matrix
  22663. this._extrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]; // no rotation & no translation [ R | t ] = [ I | 0 ]
  22664. this._f = (new Array(INTRISICS_SAMPLES)).fill(this._intrinsics[FY]);
  22665. this._fp = 0;
  22666. this._partialRotationBuffer = [];
  22667. this._translationBuffer = [];
  22668. }
  22669. /**
  22670. * Initialize the model
  22671. * @param screenSize
  22672. */
  22673. init(screenSize) {
  22674. // validate
  22675. if (screenSize.area() == 0)
  22676. throw new IllegalArgumentError(`Can't initialize the camera model with screenSize = ${screenSize.toString()}`);
  22677. // set the screen size
  22678. this._screenSize.width = screenSize.width;
  22679. this._screenSize.height = screenSize.height;
  22680. // reset the model
  22681. this._resetIntrinsics();
  22682. this._resetExtrinsics();
  22683. // log
  22684. Utils.log(`Initializing the camera model...`);
  22685. }
  22686. /**
  22687. * Release the model
  22688. */
  22689. release() {
  22690. this.reset();
  22691. return null;
  22692. }
  22693. /**
  22694. * Update the camera model
  22695. * @param homography 3x3 perspective transform
  22696. * @param screenSize may change over time (e.g., when going from portrait to landscape or vice-versa)
  22697. * @returns promise that resolves to a camera matrix
  22698. */
  22699. update(homography, screenSize) {
  22700. // validate the shape of the homography
  22701. if (homography.rows != 3 || homography.columns != 3)
  22702. throw new IllegalArgumentError(`Camera model: provide a homography matrix`);
  22703. // validate screenSize
  22704. if (screenSize.area() == 0)
  22705. throw new IllegalArgumentError(`Camera model: invalid screenSize = ${screenSize.toString()}`);
  22706. // changed screen size?
  22707. if (!this._screenSize.equals(screenSize)) {
  22708. Utils.log(`Camera model: detected a change in screen size...`);
  22709. // update the screen size
  22710. this._screenSize.width = screenSize.width;
  22711. this._screenSize.height = screenSize.height;
  22712. // reset camera
  22713. this.reset();
  22714. }
  22715. // read the entries of the homography
  22716. const h = homography.read();
  22717. const h11 = h[0], h12 = h[3], h13 = h[6], h21 = h[1], h22 = h[4], h23 = h[7], h31 = h[2], h32 = h[5], h33 = h[8];
  22718. // validate the homography (homography matrices aren't singular)
  22719. const det = h13 * (h21 * h32 - h22 * h31) - h23 * (h11 * h32 - h12 * h31) + h33 * (h11 * h22 - h12 * h21);
  22720. if (Math.abs(det) < EPSILON) {
  22721. Utils.warning(`Can't update the camera model using an invalid homography matrix`);
  22722. return speedy_vision_default().Promise.resolve(this._matrix);
  22723. }
  22724. // estimate the focal length (auto-calibration)
  22725. const f = this._estimateFocal(homography);
  22726. if (f > 0)
  22727. this._storeFocal(f);
  22728. //console.log(this.fovy * RAD2DEG);
  22729. // estimate the pose
  22730. const pose = this._estimatePose(homography);
  22731. this._storePose(pose);
  22732. // compute the camera matrix
  22733. const C = this.denormalizer();
  22734. const K = speedy_vision_default().Matrix(3, 3, this._intrinsics);
  22735. const E = speedy_vision_default().Matrix(3, 4, this._extrinsics);
  22736. this._matrix.setToSync(K.times(E).times(C));
  22737. //console.log("intrinsics -----------", K.toString());
  22738. //console.log("matrix ----------------",this._matrix.toString());
  22739. return speedy_vision_default().Promise.resolve(this._matrix);
  22740. }
  22741. /**
  22742. * Reset camera model
  22743. */
  22744. reset() {
  22745. this._resetIntrinsics();
  22746. this._resetExtrinsics();
  22747. }
  22748. /**
  22749. * The camera matrix that maps the 3D normalized space [-1,1]^3 to the
  22750. * 2D AR screen space (measured in pixels)
  22751. * @returns 3x4 camera matrix
  22752. */
  22753. get matrix() {
  22754. return this._matrix;
  22755. }
  22756. /**
  22757. * Camera intrinsics matrix
  22758. * @returns 3x3 intrinsics matrix in column-major format
  22759. */
  22760. get intrinsics() {
  22761. return this._intrinsics;
  22762. }
  22763. /**
  22764. * Camera extrinsics matrix
  22765. * @returns 3x4 extrinsics matrix [ R | t ] in column-major format
  22766. */
  22767. get extrinsics() {
  22768. return this._extrinsics;
  22769. }
  22770. /**
  22771. * Convert coordinates from normalized space [-1,1]^3 to a
  22772. * "3D pixel space" based on the dimensions of the AR screen.
  22773. *
  22774. * We perform a 180-degrees rotation around the x-axis so that
  22775. * it looks nicer (the y-axis grows downwards in image space).
  22776. *
  22777. * The final camera matrix is P = K * [ R | t ] * C, where
  22778. * C is this conversion matrix. The intent behind this is to
  22779. * make tracking independent of target and screen sizes.
  22780. *
  22781. * Reminder: we use a right-handed coordinate system in 3D!
  22782. * In 2D image space the coordinate system is left-handed.
  22783. *
  22784. * @returns 4x4 conversion matrix C
  22785. */
  22786. denormalizer() {
  22787. const w = this._screenSize.width / 2; // half width, in pixels
  22788. const h = this._screenSize.height / 2; // half height, in pixels
  22789. const d = Math.min(w, h); // virtual unit length, in pixels
  22790. /*
  22791. return Speedy.Matrix(4, 4, [
  22792. 1, 0, 0, 0,
  22793. 0,-1, 0, 0,
  22794. 0, 0,-1, 0,
  22795. w/d, h/d, 0, 1/d
  22796. ]);
  22797. */
  22798. return speedy_vision_default().Matrix(4, 4, [
  22799. d, 0, 0, 0,
  22800. 0, -d, 0, 0,
  22801. 0, 0, -d, 0,
  22802. w, h, 0, 1,
  22803. ]);
  22804. }
  22805. /**
  22806. * Size of the AR screen space, in pixels
  22807. * @returns size in pixels
  22808. */
  22809. get screenSize() {
  22810. return this._screenSize;
  22811. }
  22812. /**
  22813. * Focal length in pixel units (projection distance in the pinhole camera model)
  22814. * same as (focal length in mm) * (number of pixels per world unit in pixels/mm)
  22815. * @returns focal length
  22816. */
  22817. get focalLength() {
  22818. return this._intrinsics[FY]; // fx == fy
  22819. }
  22820. /**
  22821. * Horizontal field-of-view, given in radians
  22822. * @returns vertical field-of-view
  22823. */
  22824. get fovx() {
  22825. return 2 * Math.atan(this._intrinsics[U0] / this._intrinsics[FX]);
  22826. }
  22827. /**
  22828. * Vertical field-of-view, given in radians
  22829. * @returns vertical field-of-view
  22830. */
  22831. get fovy() {
  22832. return 2 * Math.atan(this._intrinsics[V0] / this._intrinsics[FY]);
  22833. }
  22834. /**
  22835. * Principal point
  22836. * @returns principal point, in pixel coordinates
  22837. */
  22838. principalPoint() {
  22839. return speedy_vision_default().Point2(this._intrinsics[U0], this._intrinsics[V0]);
  22840. }
  22841. /**
  22842. * Reset camera extrinsics
  22843. */
  22844. _resetExtrinsics() {
  22845. // set the rotation matrix to the identity
  22846. this._extrinsics.fill(0);
  22847. this._extrinsics[0] = this._extrinsics[4] = this._extrinsics[8] = 1;
  22848. // reset filters
  22849. this._partialRotationBuffer.length = 0;
  22850. this._translationBuffer.length = 0;
  22851. }
  22852. /**
  22853. * Reset camera intrinsics
  22854. */
  22855. _resetIntrinsics() {
  22856. const u0 = this._screenSize.width / 2;
  22857. const v0 = this._screenSize.height / 2;
  22858. const f = v0 / Math.tan(DEG2RAD * FOVY_GUESS / 2);
  22859. this._intrinsics[FX] = f;
  22860. this._intrinsics[FY] = f;
  22861. this._intrinsics[U0] = u0;
  22862. this._intrinsics[V0] = v0;
  22863. this._f.fill(this._intrinsics[FY]);
  22864. this._fp = 0;
  22865. }
  22866. /**
  22867. * Estimate the focal length
  22868. * @param homography valid homography
  22869. * @returns estimated focal length, or 0 on error
  22870. */
  22871. _estimateFocal(homography) {
  22872. // auto-detect the focal length?
  22873. if (!FOVY_AUTODETECT)
  22874. return 0;
  22875. // read the entries of the homography
  22876. const h = homography.read();
  22877. const h11 = h[0], h12 = h[3]; //, h13 = h[6];
  22878. const h21 = h[1], h22 = h[4]; //, h23 = h[7];
  22879. const h31 = h[2], h32 = h[5]; //, h33 = h[8];
  22880. // read the principal point
  22881. const u0 = this._intrinsics[U0];
  22882. const v0 = this._intrinsics[V0];
  22883. // estimate the focal length based on the orthogonality
  22884. // constraint r1'r2 = 0 of a rotation matrix
  22885. const f2 = -((h11 / h31 - u0) * (h12 / h32 - u0) + (h21 / h31 - v0) * (h22 / h32 - v0));
  22886. // can't estimate it?
  22887. if (f2 < 0)
  22888. return this._intrinsics[FY];
  22889. //return 0;
  22890. // done!
  22891. return Math.sqrt(f2);
  22892. }
  22893. /**
  22894. * Store an estimated focal length
  22895. * @param f estimated focal length
  22896. */
  22897. _storeFocal(f) {
  22898. // store the focal length
  22899. this._f[this._fp] = f;
  22900. this._fp = (this._fp + 1) % INTRISICS_SAMPLES;
  22901. // take the median of the estimated focal lengths
  22902. const sorted = this._f.concat([]).sort((a, b) => a - b);
  22903. const median = sorted[sorted.length >>> 1];
  22904. // update the intrinsics matrix
  22905. this._intrinsics[FX] = this._intrinsics[FY] = median;
  22906. /*
  22907. // test
  22908. const u0 = this._intrinsics[U0];
  22909. const v0 = this._intrinsics[V0];
  22910. const fovx = 2 * Math.atan(u0 / median) * RAD2DEG;
  22911. const fovy = 2 * Math.atan(v0 / median) * RAD2DEG;
  22912. console.log('---------------');
  22913. console.log("fov:",fovx,fovy);
  22914. console.log("f:",median);
  22915. */
  22916. }
  22917. /**
  22918. * Compute a normalized homography H' = K^(-1) * H for an
  22919. * ideal pinhole with f = 1 and principal point = (0,0)
  22920. * @param homography homography H to be normalized
  22921. * @param f focal length
  22922. * @returns normalized homography H'
  22923. */
  22924. _normalizeHomography(homography, f = this._intrinsics[FY]) {
  22925. const h = homography.read();
  22926. const u0 = this._intrinsics[U0];
  22927. const v0 = this._intrinsics[V0];
  22928. const h11 = h[0] - u0 * h[2], h12 = h[3] - u0 * h[5], h13 = h[6] - u0 * h[8];
  22929. const h21 = h[1] - v0 * h[2], h22 = h[4] - v0 * h[5], h23 = h[7] - v0 * h[8];
  22930. const h31 = h[2] * f, h32 = h[5] * f, h33 = h[8] * f;
  22931. return speedy_vision_default().Matrix(3, 3, [
  22932. h11, h21, h31,
  22933. h12, h22, h32,
  22934. h13, h23, h33,
  22935. ]);
  22936. }
  22937. /**
  22938. * Estimate [ r1 | r2 | t ], where r1, r2 are orthonormal and t is a translation vector
  22939. * @param normalizedHomography based on the ideal pinhole (where calibration K = I)
  22940. * @returns a 3x3 matrix
  22941. */
  22942. _estimatePartialPose(normalizedHomography) {
  22943. const h = normalizedHomography.read();
  22944. const h11 = h[0], h12 = h[3], h13 = h[6];
  22945. const h21 = h[1], h22 = h[4], h23 = h[7];
  22946. const h31 = h[2], h32 = h[5], h33 = h[8];
  22947. // select the sign so that t3 = tz > 0
  22948. const sign = h33 >= 0 ? 1 : -1;
  22949. // compute the scale factor
  22950. const h1norm = Math.sqrt(h11 * h11 + h21 * h21 + h31 * h31);
  22951. const h2norm = Math.sqrt(h12 * h12 + h22 * h22 + h32 * h32);
  22952. //const scale = sign * 2 / (h1norm + h2norm);
  22953. //const scale = sign / h1norm;
  22954. //const scale = sign / h2norm;
  22955. const scale = sign / Math.max(h1norm, h2norm); // this seems to work. why?
  22956. // invalid homography?
  22957. if (Number.isNaN(scale))
  22958. return speedy_vision_default().Matrix(3, 3, (new Array(9)).fill(Number.NaN));
  22959. // we expect h1norm to be approximately h2norm, but sometimes there is a lot of noise
  22960. // if h1norm is not approximately h2norm, it means that the first two columns of
  22961. // the normalized homography are not really encoding a rotation (up to a scale)
  22962. // what is causing this? does h3 (and h33) tell us anything about it?
  22963. // what about the intrinsics matrix? the principal point...? the fov...?
  22964. //console.log("h1,h2",h1norm,h2norm);
  22965. //console.log(normalizedHomography.toString());
  22966. // recover the translation and the rotation
  22967. const t1 = scale * h13;
  22968. const t2 = scale * h23;
  22969. const t3 = scale * h33;
  22970. const r11 = scale * h11;
  22971. const r21 = scale * h21;
  22972. const r31 = scale * h31;
  22973. const r12 = scale * h12;
  22974. const r22 = scale * h22;
  22975. const r32 = scale * h32;
  22976. // refine the pose
  22977. const r = this._refineRotation(r11, r21, r31, r12, r22, r32);
  22978. const t = this._refineTranslation(normalizedHomography, r, [t1, t2, t3]);
  22979. //const t = [t1, t2, t3]; // faster, but less accurate
  22980. // done!
  22981. return speedy_vision_default().Matrix(3, 3, r.concat(t)); // this is possibly NaN... why? homography...
  22982. }
  22983. /**
  22984. * Make two non-zero and non-parallel input vectors, r1 and r2, orthonormal
  22985. * @param r11 x of r1
  22986. * @param r21 y of r1
  22987. * @param r31 z of r1
  22988. * @param r12 x of r2
  22989. * @param r22 y of r2
  22990. * @param r32 z of r2
  22991. * @returns a 3x2 matrix R such that R'R = I (column-major format)
  22992. */
  22993. _refineRotation(r11, r21, r31, r12, r22, r32) {
  22994. /*
  22995. A little technique I figured out to correct the rotation vectors
  22996. ----------------------------------------------------------------
  22997. We are given two 3x1 column-vectors r1 and r2 as input in a 3x2 matrix
  22998. R = [ r1 | r2 ]. We would like that R'R = I, but that won't be the case
  22999. because vectors r1 and r2 are not perfectly orthonormal due to noise.
  23000. Let's first notice that R'R is symmetric. You can easily check that its
  23001. two eigenvalues are both real and positive (as long as r1, r2 != 0 and
  23002. r1 is not parallel to r2, but we never take such vectors as input).
  23003. R'R = [ r1'r1 r1'r2 ] is of rank 2, positive-definite
  23004. [ r1'r2 r2'r2 ]
  23005. We proceed by computing an eigendecomposition Q D Q' of R'R, where Q is
  23006. chosen to be orthogonal and D is a diagonal matrix whose entries are
  23007. the eigenvalues of R'R.
  23008. Let LL' be the Cholesky decomposition of D. Such decomposition exists
  23009. and is trivially computed: just take the square roots of the entries of
  23010. D. Since L is diagonal, we have L = L'. Its inverse is also trivially
  23011. computed - call it Linv.
  23012. Now, define a 2x2 correction matrix C as follows:
  23013. C = Q * Linv * Q'
  23014. This matrix rotates the input vector, scales it by some amount, and
  23015. then rotates it back to where it was (i.e., Q'Q = Q Q' = I).
  23016. We compute RC in order to correct the rotation vectors. We take its
  23017. two columns as the corrected vectors.
  23018. In order to show that the two columns of RC are orthonormal, we can
  23019. show that (RC)'(RC) = I. Indeed, noticing that C is symmetric, let's
  23020. expand the expression:
  23021. (RC)'(RC) = C'R'R C = C R'R C = (Q Linv Q') (Q D Q') (Q Linv Q') =
  23022. Q Linv (Q'Q) D (Q'Q) Linv Q' = Q Linv D Linv Q' =
  23023. Q Linv (L L) Linv Q' = Q (Linv L) (L Linv) Q' = Q Q' = I
  23024. I have provided below a closed formula to correct the rotation vectors.
  23025. What C does to R is very interesting: it makes the singular values
  23026. become 1. If U S V' is a SVD of R, then R'R = V S^2 V'. The singular
  23027. values of R are the square roots of the eigenvalues of R'R. Letting
  23028. S = L and V = Q, it follows that RC = U S V' V Linv V' = U V'. This
  23029. means that RC is equivalent to the correction "trick" using the SVD
  23030. found in the computer vision literature (i.e., compute the SVD and
  23031. return U V'). That "trick" is known to return the rotation matrix that
  23032. minimizes the Frobenius norm of the difference between the input and
  23033. the output. Consequently, the technique I have just presented is also
  23034. optimal in that sense!
  23035. By the way, the input matrix R does not need to be 3x2.
  23036. */
  23037. // compute the entries of R'R
  23038. const r1tr1 = r11 * r11 + r21 * r21 + r31 * r31;
  23039. const r2tr2 = r12 * r12 + r22 * r22 + r32 * r32;
  23040. const r1tr2 = r11 * r12 + r21 * r22 + r31 * r32;
  23041. // compute the two real eigenvalues of R'R
  23042. const delta = (r1tr1 - r2tr2) * (r1tr1 - r2tr2) + 4 * r1tr2 * r1tr2;
  23043. const sqrt = Math.sqrt(delta); // delta >= 0 always
  23044. const eigval1 = (r1tr1 + r2tr2 + sqrt) / 2;
  23045. const eigval2 = (r1tr1 + r2tr2 - sqrt) / 2;
  23046. // compute two unit eigenvectors qi = (xi,yi) of R'R
  23047. const alpha1 = (r2tr2 - eigval1) - r1tr2 * (1 + r1tr2) / (r1tr1 - eigval1);
  23048. const x1 = Math.sqrt((alpha1 * alpha1) / (1 + alpha1 * alpha1));
  23049. const y1 = x1 / alpha1;
  23050. const alpha2 = (r2tr2 - eigval2) - r1tr2 * (1 + r1tr2) / (r1tr1 - eigval2);
  23051. const x2 = Math.sqrt((alpha2 * alpha2) / (1 + alpha2 * alpha2));
  23052. const y2 = x2 / alpha2;
  23053. // compute the Cholesky decomposition LL' of the diagonal matrix D
  23054. // whose entries are the two eigenvalues of R'R and then invert L
  23055. const s1 = Math.sqrt(eigval1), s2 = Math.sqrt(eigval2); // singular values of R (pick s1 >= s2)
  23056. const Linv = speedy_vision_default().Matrix(2, 2, [1 / s1, 0, 0, 1 / s2]); // L inverse
  23057. // compute the correction matrix C = Q * Linv * Q', where Q = [q1|q2]
  23058. // is orthogonal and Linv is computed as above
  23059. const Q = speedy_vision_default().Matrix(2, 2, [x1, y1, x2, y2]);
  23060. const Qt = speedy_vision_default().Matrix(2, 2, [x1, x2, y1, y2]);
  23061. const C = Q.times(Linv).times(Qt);
  23062. // correct the rotation vectors r1 and r2 using C
  23063. const R = speedy_vision_default().Matrix(3, 2, [r11, r21, r31, r12, r22, r32]);
  23064. return speedy_vision_default().Matrix(R.times(C)).read();
  23065. }
  23066. /**
  23067. * Compute a refined translation vector
  23068. * @param normalizedHomography ideal pinhole K = I
  23069. * @param rot rotation vectors [ r1 | r2 ] in column-major format
  23070. * @param t0 initial estimate for the translation vector
  23071. * @returns 3x1 translation vector in column-major format
  23072. */
  23073. _refineTranslation(normalizedHomography, rot, t0) {
  23074. /*
  23075. Given a normalized homography H, the rotation vectors r1, r2, and a
  23076. translation vector t, we know that [ r1 | r2 | t ] = s H for a non-zero
  23077. scale factor s.
  23078. If we take a homogeneous vector u = [ x y w ]' (i.e., w = 1), then
  23079. [ r1 | r2 | t ] u is parallel to H u, which means that their cross
  23080. product is zero:
  23081. [ r1 | r2 | t ] u x H u = ( x r1 + y r2 + w t ) x H u = 0
  23082. The following code finds an optimal translation vector t based on the
  23083. above observation. H, r1, r2 are known.
  23084. */
  23085. const B = TRANSLATION_REFINEMENT_BUFFERS;
  23086. const n = TRANSLATION_REFINEMENT_SAMPLES;
  23087. const n3 = TRANSLATION_REFINEMENT_SAMPLES_3X;
  23088. Utils.assert(B.x.length === n);
  23089. const h = normalizedHomography.read();
  23090. const h11 = h[0], h12 = h[3], h13 = h[6];
  23091. const h21 = h[1], h22 = h[4], h23 = h[7];
  23092. const h31 = h[2], h32 = h[5], h33 = h[8];
  23093. const r11 = rot[0], r12 = rot[3];
  23094. const r21 = rot[1], r22 = rot[4];
  23095. const r31 = rot[2], r32 = rot[5];
  23096. // get sample points (xi, yi), 0 <= i < n
  23097. const x = B.x, y = B.y;
  23098. // set auxiliary values: ai = H [ xi yi 1 ]'
  23099. const a1 = B.a1, a2 = B.a2, a3 = B.a3;
  23100. for (let i = 0; i < n; i++) {
  23101. a1[i] = x[i] * h11 + y[i] * h12 + h13;
  23102. a2[i] = x[i] * h21 + y[i] * h22 + h23;
  23103. a3[i] = x[i] * h31 + y[i] * h32 + h33;
  23104. }
  23105. // solve M t = v for t; M: 3n x 3, v: 3n x 1, t: 3 x 1 (linear least squares)
  23106. const m = B.m, v = B.v;
  23107. for (let i = 0, k = 0; k < n; i += 3, k++) {
  23108. m[i] = m[i + n3 + 1] = m[i + n3 + n3 + 2] = 0;
  23109. m[i + n3] = -(m[i + 1] = a3[k]);
  23110. m[i + 2] = -(m[i + n3 + n3] = a2[k]);
  23111. m[i + n3 + n3 + 1] = -(m[i + n3 + 2] = a1[k]);
  23112. v[i] = a3[k] * (x[k] * r21 + y[k] * r22) - a2[k] * (x[k] * r31 + y[k] * r32);
  23113. v[i + 1] = -a3[k] * (x[k] * r11 + y[k] * r12) + a1[k] * (x[k] * r31 + y[k] * r32);
  23114. v[i + 2] = a2[k] * (x[k] * r11 + y[k] * r12) - a1[k] * (x[k] * r21 + y[k] * r22);
  23115. }
  23116. /*
  23117. // this works, but I want more lightweight
  23118. const M = Speedy.Matrix(n3, 3, m);
  23119. const v_ = Speedy.Matrix(n3, 1, v);
  23120. return Speedy.Matrix(M.ldiv(v_)).read();
  23121. */
  23122. /*
  23123. Gradient descent with optimal step size / learning rate
  23124. -------------------------------------------------------
  23125. Let's find the column-vector x that minimizes the error function
  23126. E(x) = r'r, where r = Ax - b, using gradient descent. This is linear
  23127. least squares. We want to find x easily, QUICKLY and iteratively.
  23128. The update rule of gradient descent is set to:
  23129. x := x - w * grad(E)
  23130. where w is the learning rate and grad(E) is the gradient of E(x):
  23131. grad(E) = 2 A'r = 2 A'(Ax - b) = 2 A'A x - 2 A'b
  23132. Let's adjust w to make x "converge quickly". Define function S(w) as:
  23133. S(w) = x - w * grad(E) (step)
  23134. and another function F(w) as:
  23135. F(w) = E(S(w))
  23136. which is the error of the step. We minimize F by setting its derivative
  23137. to zero:
  23138. 0 = dF = dF dS
  23139. dw dS dw
  23140. What follows is a fair amount of algebra. Do the math and you'll find
  23141. the following optimal update rule:
  23142. (c'c)
  23143. x := x - --------- c
  23144. (Ac)'(Ac)
  23145. where c = A'r = A'(Ax - b)
  23146. */
  23147. // initial guess
  23148. const t = B.t;
  23149. t[0] = t0[0];
  23150. t[1] = t0[1];
  23151. t[2] = t0[2];
  23152. // gradient descent: super lightweight implementation
  23153. const r = B.r, c = B.c, Mc = B.Mc;
  23154. for (let it = 0; it < TRANSLATION_REFINEMENT_ITERATIONS; it++) {
  23155. // compute residual r = Mt - v
  23156. for (let i = 0; i < n3; i++) {
  23157. r[i] = 0;
  23158. for (let j = 0; j < 3; j++)
  23159. r[i] += m[j * n3 + i] * t[j];
  23160. r[i] -= v[i];
  23161. }
  23162. // compute c = M'r
  23163. for (let i = 0; i < 3; i++) {
  23164. c[i] = 0;
  23165. for (let j = 0; j < n3; j++)
  23166. c[i] += m[i * n3 + j] * r[j];
  23167. }
  23168. // compute Mc
  23169. for (let i = 0; i < n3; i++) {
  23170. Mc[i] = 0;
  23171. for (let j = 0; j < 3; j++)
  23172. Mc[i] += m[j * n3 + i] * c[j];
  23173. }
  23174. // compute num = c'c and den = (Mc)'(Mc)
  23175. let num = 0, den = 0;
  23176. for (let i = 0; i < 3; i++)
  23177. num += c[i] * c[i];
  23178. for (let i = 0; i < n3; i++)
  23179. den += Mc[i] * Mc[i];
  23180. // compute num / den
  23181. const frc = num / den;
  23182. if (Number.isNaN(frc))
  23183. break;
  23184. // iterate: t = t - (num / den) * c
  23185. for (let i = 0; i < 3; i++)
  23186. t[i] -= frc * c[i];
  23187. }
  23188. //console.log("OLD t:\n\n",t0.join('\n'));
  23189. //console.log("new t:\n\n",t.join('\n'));
  23190. // done!
  23191. return t;
  23192. }
  23193. /**
  23194. * Apply a smoothing filter to the partial pose
  23195. * @param partialPose 3x3 [ r1 | r2 | t ]
  23196. * @returns filtered partial pose
  23197. */
  23198. _filterPartialPose(partialPose) {
  23199. const avg = new Array(9).fill(0);
  23200. const entries = partialPose.read();
  23201. const rotationBlock = entries.slice(0, 6);
  23202. const translationBlock = entries.slice(6, 9);
  23203. // how many samples should we store, at most?
  23204. const div = (Settings.powerPreference == 'low-power') ? 1.5 : 1; // low-power ~ half the fps
  23205. const N = Math.ceil(ROTATION_FILTER_SAMPLES / div);
  23206. const M = Math.ceil(TRANSLATION_FILTER_SAMPLES / div);
  23207. // is it a valid partial pose?
  23208. if (!Number.isNaN(entries[0])) {
  23209. // store samples
  23210. this._partialRotationBuffer.unshift(rotationBlock);
  23211. if (this._partialRotationBuffer.length > N)
  23212. this._partialRotationBuffer.length = N;
  23213. this._translationBuffer.unshift(translationBlock);
  23214. if (this._translationBuffer.length > M)
  23215. this._translationBuffer.length = M;
  23216. }
  23217. else if (this._partialRotationBuffer.length == 0) {
  23218. // invalid pose, no samples
  23219. return speedy_vision_default().Matrix.Eye(3);
  23220. }
  23221. // average *nearby* rotations
  23222. const n = this._partialRotationBuffer.length;
  23223. for (let i = 0; i < n; i++) {
  23224. const r = this._partialRotationBuffer[i];
  23225. for (let j = 0; j < 6; j++)
  23226. avg[j] += r[j] / n;
  23227. }
  23228. const r = this._refineRotation(avg[0], avg[1], avg[2], avg[3], avg[4], avg[5]);
  23229. // average translations
  23230. const m = this._translationBuffer.length;
  23231. for (let i = 0; i < m; i++) {
  23232. const t = this._translationBuffer[i];
  23233. for (let j = 0; j < 3; j++)
  23234. avg[6 + j] += (m - i) * t[j] / ((m * m + m) / 2);
  23235. //avg[6 + j] += t[j] / m;
  23236. }
  23237. const t = [avg[6], avg[7], avg[8]];
  23238. // done!
  23239. return speedy_vision_default().Matrix(3, 3, r.concat(t));
  23240. }
  23241. /**
  23242. * Estimate extrinsics [ R | t ] given a partial pose [ r1 | r2 | t ]
  23243. * @param partialPose
  23244. * @returns 3x4 matrix
  23245. */
  23246. _estimateFullPose(partialPose) {
  23247. const p = partialPose.read();
  23248. const r11 = p[0], r12 = p[3], t1 = p[6];
  23249. const r21 = p[1], r22 = p[4], t2 = p[7];
  23250. const r31 = p[2], r32 = p[5], t3 = p[8];
  23251. // r3 = +- ( r1 x r2 )
  23252. let r13 = r21 * r32 - r31 * r22;
  23253. let r23 = r31 * r12 - r11 * r32;
  23254. let r33 = r11 * r22 - r21 * r12;
  23255. // let's make sure that det R = +1 (keep the orientation)
  23256. const det = r11 * (r22 * r33 - r23 * r32) - r21 * (r12 * r33 - r13 * r32) + r31 * (r12 * r23 - r13 * r22);
  23257. if (det < 0) {
  23258. r13 = -r13;
  23259. r23 = -r23;
  23260. r33 = -r33;
  23261. }
  23262. // done!
  23263. return speedy_vision_default().Matrix(3, 4, [
  23264. r11, r21, r31,
  23265. r12, r22, r32,
  23266. r13, r23, r33,
  23267. t1, t2, t3,
  23268. ]);
  23269. }
  23270. /**
  23271. * Estimate the pose [ R | t ] given a homography in AR screen space
  23272. * @param homography must be valid
  23273. * @param f focal length
  23274. * @returns 3x4 matrix
  23275. */
  23276. _estimatePose(homography, f = this._intrinsics[FY]) {
  23277. const normalizedHomography = this._normalizeHomography(homography, f);
  23278. const partialPose = speedy_vision_default().Matrix.Eye(3);
  23279. // we want the estimated partial pose [ r1 | r2 | t ] to be as close
  23280. // as possible to the normalized homography, up to a scale factor;
  23281. // i.e., H * [ r1 | r2 | t ]^(-1) = s * I for a non-zero scalar s
  23282. // it won't be a perfect equality due to noise in the homography
  23283. const residual = speedy_vision_default().Matrix(normalizedHomography);
  23284. for (let k = 0; k < POSE_ITERATIONS; k++) {
  23285. // incrementally improve the partial pose
  23286. const rt = this._estimatePartialPose(residual); // rt should converge to the identity matrix
  23287. partialPose.setToSync(rt.times(partialPose));
  23288. residual.setToSync(residual.times(rt.inverse()));
  23289. //console.log("residual",residual.toString());
  23290. }
  23291. //console.log('-----------');
  23292. /*
  23293. // test
  23294. const result = Speedy.Matrix.Zeros(3);
  23295. result.setToSync(partialPose.times(normalizedHomography.inverse()));
  23296. const m11 = result.at(0,0);
  23297. result.setToSync(result.times(1/m11));
  23298. console.log("Pose * NORMALIZED HOM^-1", result.toString());
  23299. */
  23300. /*
  23301. const rt = partialPose.read();
  23302. const r = rt.slice(0, 6);
  23303. const t = this._refineTranslation(normalizedHomography, r, rt.slice(6, 9));
  23304. const refinedPartialPose = Speedy.Matrix(3, 3, r.concat(t));
  23305. const filteredPartialPose = this._filterPartialPose(refinedPartialPose);
  23306. */
  23307. // filter the partial pose
  23308. const filteredPartialPose = this._filterPartialPose(partialPose);
  23309. // estimate the full pose
  23310. return this._estimateFullPose(filteredPartialPose);
  23311. }
  23312. /**
  23313. * Store an estimated pose
  23314. * @param pose 3x4 matrix
  23315. */
  23316. _storePose(pose) {
  23317. this._extrinsics = pose.read();
  23318. }
  23319. }
  23320. ;// CONCATENATED MODULE: ./src/geometry/pose.ts
  23321. /*
  23322. * MARTINS.js Free Edition
  23323. * GPU-accelerated Augmented Reality for the web
  23324. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23325. * https://github.com/alemart/martins-js
  23326. *
  23327. * This program is free software: you can redistribute it and/or modify
  23328. * it under the terms of the GNU Affero General Public License version 3
  23329. * as published by the Free Software Foundation.
  23330. *
  23331. * This program is distributed in the hope that it will be useful,
  23332. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23333. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23334. * GNU Affero General Public License for more details.
  23335. *
  23336. * You should have received a copy of the GNU Affero General Public License
  23337. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23338. *
  23339. * pose.ts
  23340. * A pose represents a position and an orientation in a 3D space
  23341. */
  23342. /**
  23343. * A pose represents a position and an orientation in a 3D space
  23344. * (and sometimes a scale, too...)
  23345. */
  23346. class Pose {
  23347. /**
  23348. * Constructor
  23349. * @param transform usually a rigid transform in a 3D space (e.g., world space, viewer space or other)
  23350. */
  23351. constructor(transform) {
  23352. this._transform = transform;
  23353. }
  23354. /**
  23355. * A transform describing the position and the orientation
  23356. * of the pose relative to the 3D space to which it belongs
  23357. */
  23358. get transform() {
  23359. return this._transform;
  23360. }
  23361. }
  23362. ;// CONCATENATED MODULE: ./src/geometry/transform.ts
  23363. /*
  23364. * MARTINS.js Free Edition
  23365. * GPU-accelerated Augmented Reality for the web
  23366. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23367. * https://github.com/alemart/martins-js
  23368. *
  23369. * This program is free software: you can redistribute it and/or modify
  23370. * it under the terms of the GNU Affero General Public License version 3
  23371. * as published by the Free Software Foundation.
  23372. *
  23373. * This program is distributed in the hope that it will be useful,
  23374. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23375. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23376. * GNU Affero General Public License for more details.
  23377. *
  23378. * You should have received a copy of the GNU Affero General Public License
  23379. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23380. *
  23381. * transform.ts
  23382. * 3D geometrical transforms
  23383. */
  23384. /**
  23385. * A 3D transformation
  23386. */
  23387. class BaseTransform {
  23388. /**
  23389. * Constructor
  23390. * @param matrix a 4x4 matrix
  23391. */
  23392. constructor(matrix) {
  23393. if (matrix.rows != 4 || matrix.columns != 4)
  23394. throw new IllegalArgumentError('A 3D transform expects a 4x4 matrix');
  23395. this._matrix = matrix;
  23396. }
  23397. /**
  23398. * The 4x4 transformation matrix (read-only)
  23399. */
  23400. get matrix() {
  23401. return this._matrix;
  23402. }
  23403. }
  23404. /**
  23405. * An invertible 3D transformation
  23406. */
  23407. class InvertibleTransform extends BaseTransform {
  23408. /**
  23409. * Constructor
  23410. * @param matrix a 4x4 matrix
  23411. */
  23412. constructor(matrix) {
  23413. // WARNING: we do not check if the matrix actually encodes an invertible transform!
  23414. super(matrix);
  23415. }
  23416. /**
  23417. * The inverse of the transform
  23418. */
  23419. get inverse() {
  23420. const inverseMatrix = speedy_vision_default().Matrix(this._matrix.inverse());
  23421. return new InvertibleTransform(inverseMatrix);
  23422. }
  23423. }
  23424. /**
  23425. * A 3D transformation described by translation, rotation and scale
  23426. */
  23427. class StandardTransform extends InvertibleTransform {
  23428. // TODO: position, rotation and scale attributes
  23429. /**
  23430. * Constructor
  23431. * @param matrix a 4x4 matrix
  23432. */
  23433. constructor(matrix) {
  23434. // WARNING: we do not check if the matrix actually encodes a standard transform!
  23435. super(matrix);
  23436. }
  23437. /**
  23438. * The inverse of the transform
  23439. */
  23440. get inverse() {
  23441. /*
  23442. The inverse of a 4x4 standard transform T * R * S...
  23443. [ RS t ] is [ ZR' -ZR't ]
  23444. [ 0' 1 ] [ 0' 1 ]
  23445. where S is 3x3, R is 3x3, t is 3x1, 0' is 1x3 and Z is the inverse of S
  23446. */
  23447. return super.inverse;
  23448. }
  23449. }
  23450. /**
  23451. * A 3D transformation described by position and orientation
  23452. */
  23453. class RigidTransform extends StandardTransform {
  23454. // TODO: position and rotation attributes (need to decompose the matrix)
  23455. /**
  23456. * Constructor
  23457. * @param matrix a 4x4 matrix
  23458. */
  23459. constructor(matrix) {
  23460. // WARNING: we do not check if the matrix actually encodes a rigid transform!
  23461. super(matrix);
  23462. }
  23463. /**
  23464. * The inverse of the transform
  23465. */
  23466. get inverse() {
  23467. /*
  23468. The inverse of a 4x4 rigid transform
  23469. [ R t ] is [ R' -R't ]
  23470. [ 0' 1 ] [ 0' 1 ]
  23471. where R is 3x3, t is 3x1 and 0' is 1x3
  23472. */
  23473. const m = this._matrix.read();
  23474. if (m[15] == 0) // error? abs()??
  23475. throw new IllegalOperationError('Not a rigid transform');
  23476. const s = 1 / m[15]; // should be 1 (normalize homogeneous coordinates)
  23477. const r11 = m[0] * s, r12 = m[4] * s, r13 = m[8] * s;
  23478. const r21 = m[1] * s, r22 = m[5] * s, r23 = m[9] * s;
  23479. const r31 = m[2] * s, r32 = m[6] * s, r33 = m[10] * s;
  23480. const t1 = m[12] * s, t2 = m[13] * s, t3 = m[14] * s;
  23481. const rt1 = r11 * t1 + r21 * t2 + r31 * t3;
  23482. const rt2 = r12 * t1 + r22 * t2 + r32 * t3;
  23483. const rt3 = r13 * t1 + r23 * t2 + r33 * t3;
  23484. const inverseMatrix = speedy_vision_default().Matrix(4, 4, [
  23485. r11, r12, r13, 0,
  23486. r21, r22, r23, 0,
  23487. r31, r32, r33, 0,
  23488. -rt1, -rt2, -rt3, 1
  23489. ]);
  23490. return new RigidTransform(inverseMatrix);
  23491. }
  23492. }
  23493. ;// CONCATENATED MODULE: ./src/geometry/viewer-pose.ts
  23494. /*
  23495. * MARTINS.js Free Edition
  23496. * GPU-accelerated Augmented Reality for the web
  23497. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23498. * https://github.com/alemart/martins-js
  23499. *
  23500. * This program is free software: you can redistribute it and/or modify
  23501. * it under the terms of the GNU Affero General Public License version 3
  23502. * as published by the Free Software Foundation.
  23503. *
  23504. * This program is distributed in the hope that it will be useful,
  23505. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23506. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23507. * GNU Affero General Public License for more details.
  23508. *
  23509. * You should have received a copy of the GNU Affero General Public License
  23510. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23511. *
  23512. * viewer-pose.ts
  23513. * The pose of a virtual camera in 3D world space at a moment in time
  23514. */
  23515. /**
  23516. * The pose of a virtual camera in 3D world space at a moment in time
  23517. */
  23518. class ViewerPose extends Pose {
  23519. /**
  23520. * Constructor
  23521. * @param camera camera model
  23522. */
  23523. constructor(camera) {
  23524. // compute the view matrix and its inverse in AR screen space
  23525. const viewMatrix = ViewerPose._computeViewMatrix(camera);
  23526. const inverseTransform = new RigidTransform(viewMatrix);
  23527. super(inverseTransform.inverse);
  23528. this._viewMatrix = viewMatrix;
  23529. }
  23530. /**
  23531. * This 4x4 matrix moves 3D points from world space to viewer space. We
  23532. * assume that the camera is looking in the direction of the negative
  23533. * z-axis (WebGL-friendly)
  23534. */
  23535. get viewMatrix() {
  23536. return this._viewMatrix;
  23537. }
  23538. /**
  23539. * Compute the view matrix in AR screen space, measured in pixels
  23540. * @param camera
  23541. * @returns a 4x4 matrix describing a rotation and a translation
  23542. */
  23543. static _computeViewMatrix(camera) {
  23544. /*
  23545. // this is the view matrix in AR screen space, measured in pixels
  23546. // we augment the extrinsics matrix, making it 4x4 by adding a
  23547. // [ 0 0 0 1 ] row. Below, E is a 3x4 extrinsics matrix
  23548. const V = Speedy.Matrix(4, 4, [
  23549. E[0], E[1], E[2], 0,
  23550. E[3], E[4], E[5], 0,
  23551. E[6], E[7], E[8], 0,
  23552. E[9], E[10], E[11], 1
  23553. ]);
  23554. // we premultiply V by F, which performs a rotation around the
  23555. // x-axis by 180 degrees, so that we get the 3D objects in front
  23556. // of the camera pointing in the direction of the negative z-axis
  23557. const F = Speedy.Matrix(4, 4, [
  23558. 1, 0, 0, 0,
  23559. 0,-1, 0, 0,
  23560. 0, 0,-1, 0,
  23561. 0, 0, 0, 1
  23562. ]);
  23563. Matrix F * V is matrix V with the second and third rows negated
  23564. */
  23565. const E = camera.extrinsics;
  23566. return speedy_vision_default().Matrix(4, 4, [
  23567. E[0], -E[1], -E[2], 0,
  23568. E[3], -E[4], -E[5], 0,
  23569. E[6], -E[7], -E[8], 0,
  23570. E[9], -E[10], -E[11], 1
  23571. ]);
  23572. }
  23573. }
  23574. ;// CONCATENATED MODULE: ./src/geometry/view.ts
  23575. /*
  23576. * MARTINS.js Free Edition
  23577. * GPU-accelerated Augmented Reality for the web
  23578. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23579. * https://github.com/alemart/martins-js
  23580. *
  23581. * This program is free software: you can redistribute it and/or modify
  23582. * it under the terms of the GNU Affero General Public License version 3
  23583. * as published by the Free Software Foundation.
  23584. *
  23585. * This program is distributed in the hope that it will be useful,
  23586. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23587. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23588. * GNU Affero General Public License for more details.
  23589. *
  23590. * You should have received a copy of the GNU Affero General Public License
  23591. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23592. *
  23593. * view.ts
  23594. * A view of the 3D world at a moment in time,
  23595. * featuring the means to project points into clip space
  23596. */
  23597. /** Default distance in pixels of the near plane to the optical center of the camera */
  23598. const DEFAULT_NEAR = 1;
  23599. /** Default distance in pixels of the far plane to the optical center of the camera */
  23600. const DEFAULT_FAR = 20000;
  23601. /**
  23602. * A PerspectiveView is a View defining a symmetric frustum around the z-axis
  23603. * (perspective projection)
  23604. */
  23605. class PerspectiveView {
  23606. /**
  23607. * Constructor
  23608. * @param camera camera model
  23609. * @param near distance of the near plane
  23610. * @param far distance of the far plane
  23611. */
  23612. constructor(camera, near = DEFAULT_NEAR, far = DEFAULT_FAR) {
  23613. const intrinsics = camera.intrinsics;
  23614. const screenSize = camera.screenSize;
  23615. this._near = Math.max(0, +near);
  23616. this._far = Math.max(0, +far);
  23617. if (this._near >= this._far)
  23618. throw new IllegalArgumentError(`View expects near < far (found near = ${this._near} and far = ${this._far})`);
  23619. this._aspect = screenSize.width / screenSize.height;
  23620. this._tanOfHalfFovy = intrinsics[V0] / intrinsics[FY];
  23621. this._projectionMatrix = PerspectiveView._computeProjectionMatrix(intrinsics, this._near, this._far);
  23622. }
  23623. /**
  23624. * A 4x4 projection matrix for WebGL
  23625. */
  23626. get projectionMatrix() {
  23627. return this._projectionMatrix;
  23628. }
  23629. /**
  23630. * Aspect ratio of the frustum
  23631. */
  23632. get aspect() {
  23633. return this._aspect;
  23634. }
  23635. /**
  23636. * Vertical field-of-view of the frustum, measured in radians
  23637. */
  23638. get fovy() {
  23639. return 2 * Math.atan(this._tanOfHalfFovy);
  23640. }
  23641. /**
  23642. * Distance of the near plane
  23643. */
  23644. get near() {
  23645. return this._near;
  23646. }
  23647. /**
  23648. * Distance of the far plane
  23649. */
  23650. get far() {
  23651. return this._far;
  23652. }
  23653. /**
  23654. * Compute a perspective projection matrix for WebGL
  23655. * @param K camera intrinsics
  23656. * @param near distance of the near plane
  23657. * @param far distance of the far plane
  23658. */
  23659. static _computeProjectionMatrix(K, near, far) {
  23660. // we assume that the principal point is at the center of the image
  23661. const top = near * (K[V0] / K[FY]);
  23662. const right = near * (K[U0] / K[FX]);
  23663. const bottom = -top, left = -right; // symmetric frustum
  23664. // a derivation of this projection matrix can be found at
  23665. // https://www.songho.ca/opengl/gl_projectionmatrix.html
  23666. // http://learnwebgl.brown37.net/08_projections/projections_perspective.html
  23667. return speedy_vision_default().Matrix(4, 4, [
  23668. 2 * near / (right - left), 0, 0, 0,
  23669. 0, 2 * near / (top - bottom), 0, 0,
  23670. (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1,
  23671. 0, 0, -2 * far * near / (far - near), 0
  23672. ]);
  23673. }
  23674. }
  23675. ;// CONCATENATED MODULE: ./src/geometry/viewer.ts
  23676. /*
  23677. * MARTINS.js Free Edition
  23678. * GPU-accelerated Augmented Reality for the web
  23679. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23680. * https://github.com/alemart/martins-js
  23681. *
  23682. * This program is free software: you can redistribute it and/or modify
  23683. * it under the terms of the GNU Affero General Public License version 3
  23684. * as published by the Free Software Foundation.
  23685. *
  23686. * This program is distributed in the hope that it will be useful,
  23687. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23688. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23689. * GNU Affero General Public License for more details.
  23690. *
  23691. * You should have received a copy of the GNU Affero General Public License
  23692. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23693. *
  23694. * view.ts
  23695. * A viewer represents a virtual camera in 3D world space
  23696. */
  23697. /**
  23698. * A viewer represents a virtual camera in 3D world space
  23699. */
  23700. class Viewer {
  23701. /**
  23702. * Constructor
  23703. * @param camera camera model
  23704. */
  23705. constructor(camera) {
  23706. this._pose = new ViewerPose(camera);
  23707. this._views = [new PerspectiveView(camera)];
  23708. }
  23709. /**
  23710. * The pose of this viewer
  23711. */
  23712. get pose() {
  23713. return this._pose;
  23714. }
  23715. /**
  23716. * The view of this viewer (only for monoscopic rendering)
  23717. */
  23718. get view() {
  23719. /*
  23720. if(this._views.length > 1)
  23721. throw new IllegalOperationError('Use viewer.views for stereoscopic rendering');
  23722. */
  23723. return this._views[0];
  23724. }
  23725. /**
  23726. * The views of this viewer
  23727. */
  23728. /*
  23729. get views(): View[]
  23730. {
  23731. return this._views.concat([]);
  23732. }
  23733. */
  23734. /**
  23735. * Convert a pose from world space to viewer space
  23736. * @param pose a pose in world space
  23737. * @returns a pose in viewer space
  23738. */
  23739. convertToViewerSpace(pose) {
  23740. const modelMatrix = pose.transform.matrix;
  23741. const viewMatrix = this._pose.viewMatrix;
  23742. const modelViewMatrix = speedy_vision_default().Matrix(viewMatrix.times(modelMatrix));
  23743. const transform = new StandardTransform(modelViewMatrix);
  23744. return new Pose(transform);
  23745. }
  23746. }
  23747. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/states/tracking.ts
  23748. /*
  23749. * MARTINS.js Free Edition
  23750. * GPU-accelerated Augmented Reality for the web
  23751. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  23752. * https://github.com/alemart/martins-js
  23753. *
  23754. * This program is free software: you can redistribute it and/or modify
  23755. * it under the terms of the GNU Affero General Public License version 3
  23756. * as published by the Free Software Foundation.
  23757. *
  23758. * This program is distributed in the hope that it will be useful,
  23759. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23760. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23761. * GNU Affero General Public License for more details.
  23762. *
  23763. * You should have received a copy of the GNU Affero General Public License
  23764. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  23765. *
  23766. * tracking.ts
  23767. * Tracking state of the Image Tracker
  23768. */
  23769. /** Whether or not we want to accelerate GPU-CPU transfers. Using turbo costs a slight delay on the tracking */
  23770. const USE_TURBO = true;
  23771. /** Number of PBOs; meaningful only when using turbo */
  23772. const NUMBER_OF_PBOS = 2;
  23773. /** Frame skipping; meaningful only when using turbo */
  23774. const TURBO_SKIP = 2;
  23775. /**
  23776. * The tracking state of the Image Tracker tracks
  23777. * keypoints of the image target and updates the
  23778. * rectification matrix
  23779. */
  23780. class ImageTrackerTrackingState extends ImageTrackerState {
  23781. /**
  23782. * Constructor
  23783. * @param imageTracker
  23784. */
  23785. constructor(imageTracker) {
  23786. super('tracking', imageTracker);
  23787. this._referenceImage = null;
  23788. this._warpHomography = speedy_vision_default().Matrix.Eye(3);
  23789. this._poseHomography = speedy_vision_default().Matrix.Eye(3);
  23790. this._initialHomography = speedy_vision_default().Matrix.Eye(3);
  23791. this._initialKeypoints = [];
  23792. this._counter = 0;
  23793. this._camera = new CameraModel();
  23794. this._predictedKeypoints = [];
  23795. this._lastPipelineOutput = { keypoints: [] };
  23796. this._pipelineCounter = 0;
  23797. this._lastOutput = {};
  23798. this._lostCounter = 0;
  23799. // we need at least 4 correspondences of points to compute a homography matrix
  23800. Utils.assert(TRACK_MIN_MATCHES >= 4);
  23801. }
  23802. /**
  23803. * Called as soon as this becomes the active state, just before update() runs for the first time
  23804. * @param settings
  23805. */
  23806. onEnterState(settings) {
  23807. const homography = settings.homography;
  23808. const referenceImage = settings.referenceImage;
  23809. const templateKeypoints = settings.templateKeypoints;
  23810. const keypointPortalSink = settings.keypointPortalSink;
  23811. const screenSize = settings.screenSize; // this.screenSize is not yet set
  23812. const keypointPortalSource = this._pipeline.node('keypointPortalSource');
  23813. // this shouldn't happen
  23814. if (!referenceImage)
  23815. throw new IllegalOperationError(`Can't track a null reference image`);
  23816. // set attributes
  23817. this._referenceImage = referenceImage;
  23818. this._warpHomography = speedy_vision_default().Matrix(homography);
  23819. this._poseHomography = speedy_vision_default().Matrix(homography);
  23820. this._initialHomography = speedy_vision_default().Matrix(homography);
  23821. this._initialKeypoints = templateKeypoints;
  23822. this._counter = 0;
  23823. this._predictedKeypoints = [];
  23824. this._lastPipelineOutput = { keypoints: [] };
  23825. this._pipelineCounter = 0;
  23826. this._lastOutput = {};
  23827. this._lostCounter = 0;
  23828. // setup portals
  23829. keypointPortalSource.source = keypointPortalSink;
  23830. // setup camera
  23831. this._camera.init(screenSize);
  23832. // emit event
  23833. const ev = new ImageTrackerEvent('targetfound', referenceImage);
  23834. this._imageTracker.dispatchEvent(ev);
  23835. // log
  23836. Utils.log(`Tracking image "${referenceImage.name}"...`);
  23837. }
  23838. /**
  23839. * Called when leaving the state
  23840. */
  23841. onLeaveState() {
  23842. const referenceImage = this._referenceImage;
  23843. // release the camera
  23844. this._camera.release();
  23845. // emit event
  23846. const ev = new ImageTrackerEvent('targetlost', referenceImage);
  23847. this._imageTracker.dispatchEvent(ev);
  23848. }
  23849. /**
  23850. * Called just before the GPU processing
  23851. * @returns promise
  23852. */
  23853. _beforeUpdate() {
  23854. const imageRectifier = this._pipeline.node('imageRectifier');
  23855. const borderClipper = this._pipeline.node('borderClipper');
  23856. const keypointRectifier = this._pipeline.node('keypointRectifier');
  23857. const screenSize = this.screenSize;
  23858. /*
  23859. // pause media (test)
  23860. const source = this._pipeline.node('source') as SpeedyPipelineNodeImageSource;
  23861. const media = source.media as SpeedyMedia;
  23862. (media.source as HTMLVideoElement).pause();
  23863. */
  23864. // clip keypoints from the borders of the target image
  23865. borderClipper.imageSize = screenSize;
  23866. borderClipper.borderSize = speedy_vision_default().Vector2(screenSize.width * TRACK_CLIPPING_BORDER, screenSize.height * TRACK_CLIPPING_BORDER);
  23867. // rectify the image
  23868. return this._findImageWarp(this._warpHomography, screenSize).then(warp => {
  23869. imageRectifier.transform = warp;
  23870. });
  23871. }
  23872. /**
  23873. * GPU processing
  23874. * @returns promise with the pipeline results
  23875. */
  23876. _gpuUpdate() {
  23877. //return super._gpuUpdate();
  23878. // No turbo?
  23879. if (!USE_TURBO || Settings.powerPreference == 'low-power')
  23880. return super._gpuUpdate();
  23881. // When using turbo, we reduce the GPU usage by skipping every other frame
  23882. const counter = this._pipelineCounter;
  23883. this._pipelineCounter = (this._pipelineCounter + 1) % TURBO_SKIP;
  23884. // Skip frame
  23885. if (counter != 0) {
  23886. if (this._lastPipelineOutput.keypoints !== undefined) {
  23887. this._predictedKeypoints = this._predictKeypoints(this._lastPipelineOutput.keypoints, this._initialKeypoints);
  23888. }
  23889. else
  23890. this._predictedKeypoints.length = 0;
  23891. this._lastPipelineOutput.keypoints = this._predictedKeypoints;
  23892. return speedy_vision_default().Promise.resolve(this._lastPipelineOutput);
  23893. }
  23894. // Run the pipeline and store the results
  23895. return super._gpuUpdate().then(results => {
  23896. this._lastPipelineOutput = results;
  23897. return results;
  23898. });
  23899. }
  23900. /**
  23901. * Post processing that takes place just after the GPU processing
  23902. * @param result pipeline results
  23903. * @returns state output
  23904. */
  23905. _afterUpdate(result) {
  23906. const imageRectifier = this._pipeline.node('imageRectifier');
  23907. const keypoints = result.keypoints;
  23908. const image = result.image;
  23909. const referenceImage = this._referenceImage;
  23910. // find the best keypoint matches
  23911. return this._preprocessMatches(keypoints, this._initialKeypoints).then(matches => {
  23912. // find motion models
  23913. return speedy_vision_default().Promise.all([
  23914. this._findAffineMotion(matches),
  23915. this._findPerspectiveMotion(matches)
  23916. ]);
  23917. }).then(([affineMotion, perspectiveMotion]) => {
  23918. const lowPower = (Settings.powerPreference == 'low-power');
  23919. const frozen = !(!USE_TURBO || lowPower || this._counter % TURBO_SKIP == 0);
  23920. // update warp homography
  23921. const delay = NUMBER_OF_PBOS * (!lowPower ? TURBO_SKIP : 1);
  23922. const remainder = delay >>> 1; // we want remainder > 0, so it skips the first frame
  23923. if (!USE_TURBO || this._counter % delay == remainder)
  23924. this._warpHomography.setToSync(this._warpHomography.times(affineMotion));
  23925. // update pose homography
  23926. if (!frozen)
  23927. this._poseHomography.setToSync(this._warpHomography.times(perspectiveMotion));
  23928. // update counter
  23929. this._counter = (this._counter + 1) % delay;
  23930. // update the camera
  23931. if (!frozen)
  23932. return this._camera.update(this._poseHomography, this.screenSize);
  23933. else
  23934. return this._camera.matrix;
  23935. }).then(_ => {
  23936. // find the inverse of the rectification matrix
  23937. const rectificationMatrix = imageRectifier.transform;
  23938. const inverseRectificationMatrix = speedy_vision_default().Matrix(rectificationMatrix.inverse());
  23939. // move keypoints from rectified space back to image space
  23940. const n = keypoints.length;
  23941. const coords = new Array(2 * n);
  23942. for (let i = 0, j = 0; i < n; i++, j += 2) {
  23943. coords[j] = keypoints[i].position.x;
  23944. coords[j + 1] = keypoints[i].position.y;
  23945. }
  23946. return speedy_vision_default().Matrix.applyPerspectiveTransform(speedy_vision_default().Matrix.Zeros(2, n), speedy_vision_default().Matrix(2, n, coords), inverseRectificationMatrix);
  23947. /*
  23948. // test image center
  23949. const coords2: number[] = new Array(2 * n);
  23950. for(let i = 0, j = 0; i < n; i++, j += 2) {
  23951. coords2[j] = this._imageTracker.screenSize.width / 2;
  23952. coords2[j+1] = this._imageTracker.screenSize.height / 2;
  23953. if(i % 2 == 0) {
  23954. coords2[j] = this._imageTracker.screenSize.width / 4;
  23955. coords2[j+1] = this._imageTracker.screenSize.height / 4;
  23956. }
  23957. }
  23958. return Speedy.Matrix.applyPerspectiveTransform(
  23959. Speedy.Matrix.Zeros(2, n),
  23960. Speedy.Matrix(2, n, coords2),
  23961. this._poseHomography
  23962. //this._warpHomography
  23963. );
  23964. */
  23965. }).then(mat => {
  23966. /*
  23967. const n = keypoints.length;
  23968. const coords = mat.read();
  23969. // ** this will interfere with the calculations when frame skipping is on **
  23970. // get keypoints in image space
  23971. for(let i = 0, j = 0; i < n; i++, j += 2) {
  23972. keypoints[i].position.x = coords[j];
  23973. keypoints[i].position.y = coords[j+1];
  23974. }
  23975. */
  23976. // find a polyline surrounding the target
  23977. return this._findPolyline(this._poseHomography, this.screenSize);
  23978. //return this._findPolyline(this._warpHomography, this.screenSize);
  23979. }).then(polyline => {
  23980. // we let the target object be at the origin of the world space
  23981. // (identity transform). We also perform a change of coordinates,
  23982. // so that we move out from pixel space and into normalized space
  23983. const modelMatrix = this._camera.denormalizer(); // ~ "identity matrix"
  23984. const transform = new StandardTransform(modelMatrix);
  23985. const pose = new Pose(transform);
  23986. // given the current state of the camera model, we get a viewer
  23987. // compatible with the pose of the target
  23988. const viewer = new Viewer(this._camera);
  23989. // the trackable object
  23990. const trackable = {
  23991. pose: pose,
  23992. referenceImage: referenceImage
  23993. };
  23994. // the result generated by the image tracker
  23995. const result = {
  23996. tracker: this._imageTracker,
  23997. trackables: [trackable],
  23998. viewer: viewer
  23999. };
  24000. // build and save the output
  24001. this._lastOutput = {
  24002. exports: result,
  24003. cameraMatrix: this._camera.matrix,
  24004. homography: this._warpHomography,
  24005. //keypoints: keypoints,
  24006. screenSize: this.screenSize,
  24007. image: image,
  24008. polyline: polyline,
  24009. };
  24010. // we have successfully tracked the target in this frame
  24011. this._lostCounter = 0;
  24012. // done!
  24013. return {
  24014. nextState: 'tracking',
  24015. trackerOutput: this._lastOutput
  24016. };
  24017. }).catch(err => {
  24018. // give some tolerance to tracking errors
  24019. if (err instanceof TrackingError) {
  24020. if (++this._lostCounter <= TRACK_LOST_TOLERANCE) {
  24021. //console.log("ABSORB",this._lostCounter,err.toString())
  24022. // absorb the error
  24023. return {
  24024. nextState: 'tracking',
  24025. trackerOutput: this._lastOutput
  24026. };
  24027. }
  24028. }
  24029. // lost tracking
  24030. Utils.warning(`The target has been lost! ${err.toString()}`);
  24031. this._camera.reset();
  24032. // go back to the scanning state
  24033. return {
  24034. nextState: 'scanning',
  24035. trackerOutput: {
  24036. image: image,
  24037. screenSize: this.screenSize,
  24038. },
  24039. };
  24040. });
  24041. }
  24042. /**
  24043. * Find quality matches between two sets of keypoints
  24044. * @param currKeypoints keypoints of the current frame
  24045. * @param prevKeypoints keypoints of the previous frame
  24046. * @returns quality matches
  24047. */
  24048. _findQualityMatches(currKeypoints, prevKeypoints) {
  24049. const result = [[], []];
  24050. const n = currKeypoints.length;
  24051. for (let i = 0; i < n; i++) {
  24052. const currKeypoint = currKeypoints[i];
  24053. if (currKeypoint.matches[0].index >= 0 && currKeypoint.matches[1].index >= 0) {
  24054. const d1 = currKeypoint.matches[0].distance;
  24055. const d2 = currKeypoint.matches[1].distance;
  24056. if (d1 <= TRACK_MATCH_RATIO * d2) {
  24057. const prevKeypoint = prevKeypoints[currKeypoint.matches[0].index];
  24058. result[0].push(currKeypoint);
  24059. result[1].push(prevKeypoint);
  24060. }
  24061. }
  24062. }
  24063. return result;
  24064. }
  24065. /**
  24066. * Find a better spatial distribution of the input matches
  24067. * @param matches quality matches
  24068. * @returns refined quality matches
  24069. */
  24070. _refineQualityMatches(matches) {
  24071. const currKeypoints = matches[0];
  24072. const prevKeypoints = matches[1];
  24073. // find a better spatial distribution of the keypoints
  24074. const indices = this._distributeKeypoints(currKeypoints, TRACK_GRID_GRANULARITY);
  24075. const n = indices.length; // number of refined matches
  24076. // assemble output
  24077. const result = [new Array(n), new Array(n)];
  24078. for (let i = 0; i < n; i++) {
  24079. result[0][i] = currKeypoints[indices[i]];
  24080. result[1][i] = prevKeypoints[indices[i]];
  24081. }
  24082. // done!
  24083. return result;
  24084. }
  24085. /**
  24086. * Spatially distribute keypoints over a grid
  24087. * @param keypoints keypoints to be distributed
  24088. * @param gridCells number of grid elements in each axis
  24089. * @returns a list of indices of keypoints[]
  24090. */
  24091. _distributeKeypoints(keypoints, gridCells) {
  24092. // get the coordinates of the keypoints
  24093. const n = keypoints.length;
  24094. const points = new Array(2 * n);
  24095. for (let i = 0, j = 0; i < n; i++, j += 2) {
  24096. points[j] = keypoints[i].x;
  24097. points[j + 1] = keypoints[i].y;
  24098. }
  24099. // normalize the coordinates to [0,1] x [0,1]
  24100. this._normalizePoints(points);
  24101. // distribute the keypoints over a grid
  24102. const numberOfCells = gridCells * gridCells;
  24103. const grid = (new Array(numberOfCells)).fill(-1);
  24104. for (let i = 0, j = 0; i < n; i++, j += 2) {
  24105. // find the grid location of the i-th point
  24106. const xg = Math.floor(points[j] * gridCells); // 0 <= xg,yg < gridCells
  24107. const yg = Math.floor(points[j + 1] * gridCells);
  24108. // store the index of the i-th point in the grid
  24109. grid[yg * gridCells + xg] = i;
  24110. }
  24111. // retrieve points of the grid
  24112. const indices = [];
  24113. for (let g = 0; g < numberOfCells; g++) {
  24114. if (grid[g] >= 0) {
  24115. const i = grid[g];
  24116. indices.push(i);
  24117. }
  24118. }
  24119. // done!
  24120. return indices;
  24121. }
  24122. /**
  24123. * Normalize points to [0,1)^2
  24124. * @param points 2 x n matrix of points in column-major format
  24125. * @returns points
  24126. */
  24127. _normalizePoints(points) {
  24128. Utils.assert(points.length % 2 == 0);
  24129. const n = points.length / 2;
  24130. if (n == 0)
  24131. return points;
  24132. let xmin = Number.POSITIVE_INFINITY, xmax = Number.NEGATIVE_INFINITY;
  24133. let ymin = Number.POSITIVE_INFINITY, ymax = Number.NEGATIVE_INFINITY;
  24134. for (let i = 0, j = 0; i < n; i++, j += 2) {
  24135. const x = points[j], y = points[j + 1];
  24136. xmin = x < xmin ? x : xmin;
  24137. ymin = y < ymin ? y : ymin;
  24138. xmax = x > xmax ? x : xmax;
  24139. ymax = y > ymax ? y : ymax;
  24140. }
  24141. const xlen = xmax - xmin + 1; // +1 is a correction factor, so that 0 <= x,y < 1
  24142. const ylen = ymax - ymin + 1;
  24143. for (let i = 0, j = 0; i < n; i++, j += 2) {
  24144. points[j] = (points[j] - xmin) / xlen;
  24145. points[j + 1] = (points[j + 1] - ymin) / ylen;
  24146. }
  24147. return points;
  24148. }
  24149. /**
  24150. * Find a matrix with the coordinates of quality matches
  24151. * @param matches n quality matches
  24152. * @returns a 2 x 2n matrix split into two 2 x n blocks [ prevKeypoints | currKeypoints ]
  24153. */
  24154. _findMatrixOfMatches(matches) {
  24155. const n = matches[0].length;
  24156. Utils.assert(n > 0);
  24157. // sets of keypoints
  24158. const currKeypoints = matches[0];
  24159. const prevKeypoints = matches[1];
  24160. // get the coordinates of the keypoints of the set of refined matches
  24161. const src = new Array(2 * n);
  24162. const dst = new Array(2 * n);
  24163. for (let i = 0, j = 0; i < n; i++, j += 2) {
  24164. src[j] = prevKeypoints[i].x;
  24165. src[j + 1] = prevKeypoints[i].y;
  24166. dst[j] = currKeypoints[i].x;
  24167. dst[j + 1] = currKeypoints[i].y;
  24168. }
  24169. // assemble the matrix
  24170. return speedy_vision_default().Matrix(2, 2 * n, src.concat(dst));
  24171. }
  24172. /**
  24173. * Preprocess keypoint matches
  24174. * @param currKeypoints keypoints of the current frame
  24175. * @param prevKeypoints keypoints of the previous frame
  24176. * @returns a promise that is rejected if there are not enough "good" matches, or that is resolved to a
  24177. * 2 x 2n matrix split into two 2 x n blocks [ source x,y coordinates | dest x,y coordinates ]
  24178. */
  24179. _preprocessMatches(currKeypoints, prevKeypoints) {
  24180. // find and refine quality matches
  24181. const qualityMatches = this._findQualityMatches(currKeypoints, prevKeypoints);
  24182. const refinedMatches = this._refineQualityMatches(qualityMatches);
  24183. // not enough matches?
  24184. const n = refinedMatches[0].length;
  24185. if (n < TRACK_MIN_MATCHES)
  24186. return speedy_vision_default().Promise.reject(new TrackingError('Not enough data to compute a motion model'));
  24187. // find matrix of matches
  24188. const matrixOfMatches = this._findMatrixOfMatches(refinedMatches);
  24189. // warp matrix of matches
  24190. const result = speedy_vision_default().Matrix.Zeros(2, 2 * n);
  24191. return this._findKeypointWarp().then(transform => speedy_vision_default().Matrix.applyAffineTransform(result, matrixOfMatches, transform.block(0, 1, 0, 2)));
  24192. }
  24193. /**
  24194. * Find an affine motion model of the target image
  24195. * @param preprocessedMatches 2 x 2n matrix split into two 2 x n blocks [ src | dest ]
  24196. * @returns a promise that resolves to a 3x3 affine motion model (last row is [ 0 0 1 ])
  24197. */
  24198. _findAffineMotion(preprocessedMatches) {
  24199. const model = speedy_vision_default().Matrix.Eye(3);
  24200. const n = preprocessedMatches.columns / 2; // number of preprocessed matches
  24201. // find motion model
  24202. return speedy_vision_default().Matrix.findAffineTransform(model.block(0, 1, 0, 2), preprocessedMatches.block(0, 1, 0, n - 1), preprocessedMatches.block(0, 1, n, 2 * n - 1), {
  24203. method: 'pransac',
  24204. reprojectionError: TRACK_RANSAC_REPROJECTIONERROR,
  24205. numberOfHypotheses: 512,
  24206. bundleSize: 128,
  24207. }).then(_ => {
  24208. // validate the model
  24209. const a00 = model.at(0, 0);
  24210. if (Number.isNaN(a00))
  24211. throw new TrackingError(`Can't compute affine motion model: bad keypoints`);
  24212. // done!
  24213. return model;
  24214. });
  24215. }
  24216. /**
  24217. * Find a perspective motion model of the target image
  24218. * @param preprocessedMatches 2 x 2n matrix split into two 2 x n blocks [ src | dest ]
  24219. * @returns a promise that resolves to a 3x3 perspective motion model
  24220. */
  24221. _findPerspectiveMotion(preprocessedMatches) {
  24222. /*
  24223. We can probably get more accurate motion estimates if we
  24224. work in 3D rather than in 2D. We're currently estimating
  24225. an affine transform in image space. What if we projected
  24226. the keypoints into world space, estimated the camera motion
  24227. (rotation and translation) that best describes the observed
  24228. observed motion of the keypoints, and then projected things
  24229. back to image space? Need to figure this out; we'll get a
  24230. homography matrix.
  24231. Note: keypoints are in rectified image space.
  24232. Note: work with a 6 DoF perspective transform instead of 8.
  24233. */
  24234. const model = speedy_vision_default().Matrix.Zeros(3);
  24235. const n = preprocessedMatches.columns / 2; // number of preprocessed matches
  24236. // find motion model
  24237. return speedy_vision_default().Matrix.findHomography(model, preprocessedMatches.block(0, 1, 0, n - 1), preprocessedMatches.block(0, 1, n, 2 * n - 1), {
  24238. method: 'pransac',
  24239. reprojectionError: TRACK_RANSAC_REPROJECTIONERROR,
  24240. numberOfHypotheses: 512 * 2,
  24241. bundleSize: 128 * 4, //*4
  24242. }).then(_ => {
  24243. // validate the model
  24244. const a00 = model.at(0, 0);
  24245. if (Number.isNaN(a00))
  24246. throw new TrackingError(`Can't compute perspective motion model: bad keypoints`);
  24247. // done!
  24248. return model;
  24249. });
  24250. }
  24251. /**
  24252. * Find a rectification matrix to be applied to the target image
  24253. * @param homography maps a reference image to the AR screen
  24254. * @param media target
  24255. * @param screenSize AR screen
  24256. * @returns promise that resolves to a rectification matrix
  24257. */
  24258. _findImageWarp(homography, screenSize) {
  24259. const referenceImage = this._referenceImage;
  24260. const media = this._imageTracker.database._findMedia(referenceImage.name);
  24261. const mat = speedy_vision_default().Matrix.Zeros(3);
  24262. return this._findRectificationMatrixOfFullscreenImage(media, screenSize).then(warp => mat.setTo(warp.times(homography.inverse())));
  24263. }
  24264. /**
  24265. * Find a warp to be applied to the keypoints
  24266. * @returns affine transform
  24267. */
  24268. _findKeypointWarp() {
  24269. const referenceImage = this._referenceImage;
  24270. const media = this._imageTracker.database._findMedia(referenceImage.name);
  24271. const screenSize = this.screenSize;
  24272. const sw = screenSize.width, sh = screenSize.height;
  24273. const mat = speedy_vision_default().Matrix.Eye(3, 3);
  24274. // no rotation is needed
  24275. if (!this._mustRotateWarpedImage(media, screenSize))
  24276. return speedy_vision_default().Promise.resolve(mat);
  24277. // rotate by 90 degrees clockwise and scale
  24278. return speedy_vision_default().Matrix.affine(mat.block(0, 1, 0, 2), speedy_vision_default().Matrix(2, 3, [0, sh, 0, 0, sw, 0]), speedy_vision_default().Matrix(2, 3, [0, 0, sw, 0, sw, sh])).then(_ => mat);
  24279. }
  24280. /**
  24281. * Predict the keypoints without actually looking at the image
  24282. * @param curr keypoints at time t (will modify the contents)
  24283. * @param initial keypoints at time t-1 (not just t = 0)
  24284. * @returns keypoints at time t+1
  24285. */
  24286. _predictKeypoints(curr, initial) {
  24287. // the target image is likely to be moving roughly in
  24288. // the same manner as it was in the previous frame
  24289. const next = [];
  24290. const n = curr.length;
  24291. for (let i = 0; i < n; i++) {
  24292. const cur = curr[i];
  24293. if (cur.matches[0].index < 0 || cur.matches[1].index < 0)
  24294. continue;
  24295. /*
  24296. else if(cur.matches[0].distance > TRACK_MATCH_RATIO * cur.matches[1].distance)
  24297. continue;
  24298. */
  24299. const ini = initial[cur.matches[0].index];
  24300. const dx = cur.position.x - ini.position.x;
  24301. const dy = cur.position.y - ini.position.y;
  24302. // a better mathematical model is needed
  24303. const alpha = 0.8; //0.2;
  24304. cur.position.x = ini.position.x + alpha * dx;
  24305. cur.position.y = ini.position.y + alpha * dy;
  24306. next.push(cur);
  24307. }
  24308. // done!
  24309. return next;
  24310. }
  24311. /**
  24312. * Create & setup the pipeline
  24313. * @returns pipeline
  24314. */
  24315. _createPipeline() {
  24316. const pipeline = speedy_vision_default().Pipeline();
  24317. const source = speedy_vision_default().Image.Source('source');
  24318. const screen = speedy_vision_default().Transform.Resize('screen');
  24319. const greyscale = speedy_vision_default().Filter.Greyscale();
  24320. const imageRectifier = speedy_vision_default().Transform.PerspectiveWarp('imageRectifier');
  24321. const nightvision = speedy_vision_default().Filter.Nightvision();
  24322. const nightvisionMux = speedy_vision_default().Image.Multiplexer();
  24323. const blur = speedy_vision_default().Filter.GaussianBlur();
  24324. const detector = speedy_vision_default().Keypoint.Detector.Harris();
  24325. const descriptor = speedy_vision_default().Keypoint.Descriptor.ORB();
  24326. const matcher = speedy_vision_default().Keypoint.Matcher.BFKNN();
  24327. const subpixel = speedy_vision_default().Keypoint.SubpixelRefiner();
  24328. const denoiser = speedy_vision_default().Filter.GaussianBlur();
  24329. const borderClipper = speedy_vision_default().Keypoint.BorderClipper('borderClipper');
  24330. const clipper = speedy_vision_default().Keypoint.Clipper();
  24331. const keypointRectifier = speedy_vision_default().Keypoint.Transformer('keypointRectifier');
  24332. const keypointPortalSource = speedy_vision_default().Keypoint.Portal.Source('keypointPortalSource');
  24333. const keypointSink = speedy_vision_default().Keypoint.SinkOfMatchedKeypoints('keypoints');
  24334. const imageSink = speedy_vision_default().Image.Sink('image');
  24335. source.media = null;
  24336. screen.size = speedy_vision_default().Size(0, 0);
  24337. imageRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  24338. nightvision.gain = NIGHTVISION_GAIN;
  24339. nightvision.offset = NIGHTVISION_OFFSET;
  24340. nightvision.decay = NIGHTVISION_DECAY;
  24341. nightvision.quality = NIGHTVISION_QUALITY;
  24342. nightvisionMux.port = TRACK_WITH_NIGHTVISION ? 1 : 0; // 1 = enable nightvision
  24343. blur.kernelSize = speedy_vision_default().Size(ORB_GAUSSIAN_KSIZE, ORB_GAUSSIAN_KSIZE);
  24344. blur.sigma = speedy_vision_default().Vector2(ORB_GAUSSIAN_SIGMA, ORB_GAUSSIAN_SIGMA);
  24345. denoiser.kernelSize = speedy_vision_default().Size(SUBPIXEL_GAUSSIAN_KSIZE, SUBPIXEL_GAUSSIAN_KSIZE);
  24346. denoiser.sigma = speedy_vision_default().Vector2(SUBPIXEL_GAUSSIAN_SIGMA, SUBPIXEL_GAUSSIAN_SIGMA);
  24347. detector.quality = TRACK_HARRIS_QUALITY;
  24348. detector.capacity = TRACK_DETECTOR_CAPACITY;
  24349. subpixel.method = SUBPIXEL_METHOD;
  24350. clipper.size = TRACK_MAX_KEYPOINTS;
  24351. borderClipper.imageSize = screen.size;
  24352. borderClipper.borderSize = speedy_vision_default().Vector2(0, 0);
  24353. keypointRectifier.transform = speedy_vision_default().Matrix.Eye(3);
  24354. matcher.k = 2;
  24355. keypointPortalSource.source = null;
  24356. keypointSink.turbo = USE_TURBO;
  24357. // prepare input
  24358. source.output().connectTo(screen.input());
  24359. screen.output().connectTo(greyscale.input());
  24360. // preprocess images
  24361. greyscale.output().connectTo(imageRectifier.input());
  24362. imageRectifier.output().connectTo(nightvisionMux.input('in0'));
  24363. imageRectifier.output().connectTo(nightvision.input());
  24364. nightvision.output().connectTo(nightvisionMux.input('in1'));
  24365. // keypoint detection & clipping
  24366. nightvisionMux.output().connectTo(detector.input());
  24367. detector.output().connectTo(borderClipper.input());
  24368. borderClipper.output().connectTo(clipper.input());
  24369. // keypoint refinement
  24370. imageRectifier.output().connectTo(denoiser.input());
  24371. denoiser.output().connectTo(subpixel.input('image'));
  24372. clipper.output().connectTo(subpixel.input('keypoints'));
  24373. // keypoint description
  24374. imageRectifier.output().connectTo(blur.input());
  24375. blur.output().connectTo(descriptor.input('image'));
  24376. subpixel.output().connectTo(descriptor.input('keypoints'));
  24377. // keypoint matching
  24378. keypointPortalSource.output().connectTo(matcher.input('database'));
  24379. descriptor.output().connectTo(matcher.input('keypoints'));
  24380. // prepare output
  24381. descriptor.output().connectTo(keypointRectifier.input());
  24382. //preMatcher.output().connectTo(keypointRectifier.input());
  24383. keypointRectifier.output().connectTo(keypointSink.input());
  24384. matcher.output().connectTo(keypointSink.input('matches'));
  24385. //imageRectifier.output().connectTo(imageSink.input());
  24386. // done!
  24387. pipeline.init(source, screen, greyscale, imageRectifier, nightvision, nightvisionMux, blur, detector, subpixel, borderClipper, clipper, denoiser, descriptor, matcher, keypointPortalSource, keypointRectifier, keypointSink);
  24388. return pipeline;
  24389. }
  24390. }
  24391. ;// CONCATENATED MODULE: ./src/trackers/image-tracker/image-tracker.ts
  24392. /*
  24393. * MARTINS.js Free Edition
  24394. * GPU-accelerated Augmented Reality for the web
  24395. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24396. * https://github.com/alemart/martins-js
  24397. *
  24398. * This program is free software: you can redistribute it and/or modify
  24399. * it under the terms of the GNU Affero General Public License version 3
  24400. * as published by the Free Software Foundation.
  24401. *
  24402. * This program is distributed in the hope that it will be useful,
  24403. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24404. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24405. * GNU Affero General Public License for more details.
  24406. *
  24407. * You should have received a copy of the GNU Affero General Public License
  24408. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24409. *
  24410. * image-tracker.ts
  24411. * Image Tracker
  24412. */
  24413. /** A helper */
  24414. const formatSize = (size) => `${size.width}x${size.height}`;
  24415. /**
  24416. * The ImageTracker tracks an image (one at a time)
  24417. */
  24418. class ImageTracker extends AREventTarget {
  24419. /**
  24420. * Constructor
  24421. */
  24422. constructor() {
  24423. super();
  24424. // the states
  24425. this._state = {
  24426. 'initial': new ImageTrackerInitialState(this),
  24427. 'training': new ImageTrackerTrainingState(this),
  24428. 'scanning': new ImageTrackerScanningState(this),
  24429. 'pre-tracking': new ImageTrackerPreTrackingState(this),
  24430. 'tracking': new ImageTrackerTrackingState(this),
  24431. };
  24432. // initial setup
  24433. this._session = null;
  24434. this._activeStateName = 'initial';
  24435. this._lastOutput = {};
  24436. this._database = new ReferenceImageDatabase();
  24437. // user settings
  24438. this._resolution = DEFAULT_TRACKING_RESOLUTION;
  24439. }
  24440. /**
  24441. * The type of the tracker
  24442. */
  24443. get type() {
  24444. return 'image-tracker';
  24445. }
  24446. /**
  24447. * Current state name
  24448. */
  24449. get state() {
  24450. return this._activeStateName;
  24451. }
  24452. /**
  24453. * Reference Image Database
  24454. * Must be configured before training the tracker
  24455. */
  24456. get database() {
  24457. return this._database;
  24458. }
  24459. /**
  24460. * Resolution of the AR screen space
  24461. */
  24462. get resolution() {
  24463. return this._resolution;
  24464. }
  24465. /**
  24466. * Resolution of the AR screen space
  24467. */
  24468. set resolution(resolution) {
  24469. this._resolution = resolution;
  24470. }
  24471. /**
  24472. * Size of the AR screen space, in pixels
  24473. * @internal
  24474. */
  24475. get screenSize() {
  24476. return this._state[this._activeStateName].screenSize;
  24477. }
  24478. /**
  24479. * Last emitted output
  24480. * @internal
  24481. */
  24482. get _output() {
  24483. return this._lastOutput;
  24484. }
  24485. /**
  24486. * Stats related to this tracker
  24487. * @internal
  24488. */
  24489. get _stats() {
  24490. return `${formatSize(this.screenSize)} ${this.state}`;
  24491. }
  24492. /**
  24493. * Initialize this tracker
  24494. * @param session
  24495. * @returns promise that resolves after the tracker has been initialized
  24496. * @internal
  24497. */
  24498. _init(session) {
  24499. // store the session
  24500. this._session = session;
  24501. // initialize states
  24502. for (const state of Object.values(this._state))
  24503. state.init();
  24504. // done!
  24505. return speedy_vision_default().Promise.resolve();
  24506. }
  24507. /**
  24508. * Release this tracker
  24509. * @returns promise that resolves after the tracker has been released
  24510. * @internal
  24511. */
  24512. _release() {
  24513. // release states
  24514. for (const state of Object.values(this._state))
  24515. state.release();
  24516. // unlink session
  24517. this._session = null;
  24518. // done!
  24519. return speedy_vision_default().Promise.resolve();
  24520. }
  24521. /**
  24522. * Update the tracker
  24523. * @returns promise
  24524. * @internal
  24525. */
  24526. _update() {
  24527. // validate
  24528. if (this._session == null)
  24529. return speedy_vision_default().Promise.reject(new IllegalOperationError(`Uninitialized tracker`));
  24530. // compute the screen size for image processing purposes
  24531. // note: this may change over time...!
  24532. const media = this._session.media;
  24533. const aspectRatio = media.width / media.height;
  24534. const screenSize = Utils.resolution(this._resolution, aspectRatio);
  24535. // run the active state
  24536. const activeState = this._state[this._activeStateName];
  24537. return activeState.update(media, screenSize).then(({ trackerOutput, nextState, nextStateSettings }) => {
  24538. // update the output of the tracker
  24539. this._lastOutput = trackerOutput;
  24540. // need to change the state?
  24541. if (this._activeStateName != nextState) {
  24542. activeState.onLeaveState();
  24543. this._activeStateName = nextState;
  24544. this._state[nextState].onEnterState(nextStateSettings || {});
  24545. }
  24546. });
  24547. }
  24548. /**
  24549. * Get reference image
  24550. * @param keypointIndex -1 if not found
  24551. * @returns reference image
  24552. * @internal
  24553. */
  24554. _referenceImageOfKeypoint(keypointIndex) {
  24555. const training = this._state.training;
  24556. return training.referenceImageOfKeypoint(keypointIndex);
  24557. }
  24558. /**
  24559. * Get reference image index
  24560. * @param keypointIndex -1 if not found
  24561. * @returns reference image index, or -1 if not found
  24562. * @internal
  24563. */
  24564. _referenceImageIndexOfKeypoint(keypointIndex) {
  24565. const training = this._state.training;
  24566. return training.referenceImageIndexOfKeypoint(keypointIndex);
  24567. }
  24568. /**
  24569. * Get a keypoint of the trained set
  24570. * @param keypointIndex
  24571. * @returns a keypoint
  24572. * @internal
  24573. */
  24574. _referenceKeypoint(keypointIndex) {
  24575. const training = this._state.training;
  24576. return training.referenceKeypoint(keypointIndex);
  24577. }
  24578. }
  24579. ;// CONCATENATED MODULE: ./src/trackers/tracker-factory.ts
  24580. /*
  24581. * MARTINS.js Free Edition
  24582. * GPU-accelerated Augmented Reality for the web
  24583. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24584. * https://github.com/alemart/martins-js
  24585. *
  24586. * This program is free software: you can redistribute it and/or modify
  24587. * it under the terms of the GNU Affero General Public License version 3
  24588. * as published by the Free Software Foundation.
  24589. *
  24590. * This program is distributed in the hope that it will be useful,
  24591. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24592. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24593. * GNU Affero General Public License for more details.
  24594. *
  24595. * You should have received a copy of the GNU Affero General Public License
  24596. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24597. *
  24598. * tracker-factory.ts
  24599. * Tracker factory
  24600. */
  24601. /**
  24602. * Tracker factory
  24603. */
  24604. class TrackerFactory {
  24605. /**
  24606. * Create an Image Tracker
  24607. */
  24608. static ImageTracker() {
  24609. return new ImageTracker();
  24610. }
  24611. }
  24612. ;// CONCATENATED MODULE: ./src/sources/media-source.ts
  24613. /*
  24614. * MARTINS.js Free Edition
  24615. * GPU-accelerated Augmented Reality for the web
  24616. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24617. * https://github.com/alemart/martins-js
  24618. *
  24619. * This program is free software: you can redistribute it and/or modify
  24620. * it under the terms of the GNU Affero General Public License version 3
  24621. * as published by the Free Software Foundation.
  24622. *
  24623. * This program is distributed in the hope that it will be useful,
  24624. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24625. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24626. * GNU Affero General Public License for more details.
  24627. *
  24628. * You should have received a copy of the GNU Affero General Public License
  24629. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24630. *
  24631. * media-source.ts
  24632. * SpeedyMedia-based source of data
  24633. */
  24634. /**
  24635. * SpeedyMedia-based source of data
  24636. */
  24637. class MediaSource {
  24638. /**
  24639. * Constructor
  24640. */
  24641. constructor(source) {
  24642. this._media = null;
  24643. this._source = source;
  24644. }
  24645. /**
  24646. * A type-identifier of the source of data
  24647. * @internal
  24648. */
  24649. get _type() {
  24650. return 'video';
  24651. }
  24652. /**
  24653. * Get media
  24654. * @internal
  24655. */
  24656. get _data() {
  24657. if (this._media == null)
  24658. throw new IllegalOperationError(`The media of the source of data isn't loaded`);
  24659. return this._media;
  24660. }
  24661. /**
  24662. * Initialize this source of data
  24663. * @returns a promise that resolves as soon as this source of data is initialized
  24664. * @internal
  24665. */
  24666. _init() {
  24667. return speedy_vision_default().load(this._source).then(media => {
  24668. Utils.log(`Source of data is ${media.width}x${media.height}`);
  24669. this._media = media;
  24670. });
  24671. }
  24672. /**
  24673. * Release this source of data
  24674. * @returns a promise that resolves as soon as this source of data is released
  24675. * @internal
  24676. */
  24677. _release() {
  24678. if (this._media)
  24679. this._media.release();
  24680. this._media = null;
  24681. return speedy_vision_default().Promise.resolve();
  24682. }
  24683. /**
  24684. * A string featuring the size of the media, in pixels
  24685. */
  24686. get _size() {
  24687. const media = this._media;
  24688. if (media != null)
  24689. return `${media.width}x${media.height}`;
  24690. else
  24691. return '-';
  24692. }
  24693. }
  24694. ;// CONCATENATED MODULE: ./src/sources/video-source.ts
  24695. /*
  24696. * MARTINS.js Free Edition
  24697. * GPU-accelerated Augmented Reality for the web
  24698. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24699. * https://github.com/alemart/martins-js
  24700. *
  24701. * This program is free software: you can redistribute it and/or modify
  24702. * it under the terms of the GNU Affero General Public License version 3
  24703. * as published by the Free Software Foundation.
  24704. *
  24705. * This program is distributed in the hope that it will be useful,
  24706. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24707. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24708. * GNU Affero General Public License for more details.
  24709. *
  24710. * You should have received a copy of the GNU Affero General Public License
  24711. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24712. *
  24713. * video-source.ts
  24714. * <video>-based source of data
  24715. */
  24716. /**
  24717. * <video>-based source of data
  24718. */
  24719. class VideoSource extends MediaSource {
  24720. /**
  24721. * Constructor
  24722. */
  24723. constructor(video) {
  24724. Utils.assert(video instanceof HTMLVideoElement, 'Expected a video element');
  24725. super(video);
  24726. }
  24727. /**
  24728. * Stats related to this source of data
  24729. * @internal
  24730. */
  24731. get _stats() {
  24732. return `${this._size} video`;
  24733. }
  24734. }
  24735. ;// CONCATENATED MODULE: ./src/sources/canvas-source.ts
  24736. /*
  24737. * MARTINS.js Free Edition
  24738. * GPU-accelerated Augmented Reality for the web
  24739. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24740. * https://github.com/alemart/martins-js
  24741. *
  24742. * This program is free software: you can redistribute it and/or modify
  24743. * it under the terms of the GNU Affero General Public License version 3
  24744. * as published by the Free Software Foundation.
  24745. *
  24746. * This program is distributed in the hope that it will be useful,
  24747. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24748. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24749. * GNU Affero General Public License for more details.
  24750. *
  24751. * You should have received a copy of the GNU Affero General Public License
  24752. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24753. *
  24754. * canvas-source.ts
  24755. * <canvas>-based source of data
  24756. */
  24757. /**
  24758. * <canvas>-based source of data
  24759. */
  24760. class CanvasSource extends MediaSource {
  24761. /**
  24762. * Constructor
  24763. */
  24764. constructor(canvas) {
  24765. Utils.assert(canvas instanceof HTMLCanvasElement, 'Expected a canvas element');
  24766. super(canvas);
  24767. }
  24768. /**
  24769. * Stats related to this source of data
  24770. * @internal
  24771. */
  24772. get _stats() {
  24773. return `${this._size} canvas`;
  24774. }
  24775. }
  24776. ;// CONCATENATED MODULE: ./src/sources/camera-source.ts
  24777. /*
  24778. * MARTINS.js Free Edition
  24779. * GPU-accelerated Augmented Reality for the web
  24780. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24781. * https://github.com/alemart/martins-js
  24782. *
  24783. * This program is free software: you can redistribute it and/or modify
  24784. * it under the terms of the GNU Affero General Public License version 3
  24785. * as published by the Free Software Foundation.
  24786. *
  24787. * This program is distributed in the hope that it will be useful,
  24788. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24789. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24790. * GNU Affero General Public License for more details.
  24791. *
  24792. * You should have received a copy of the GNU Affero General Public License
  24793. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24794. *
  24795. * camera-source.ts
  24796. * Webcam-based source of data
  24797. */
  24798. /** Default options for camera sources */
  24799. const DEFAULT_CAMERA_OPTIONS = {
  24800. resolution: 'md',
  24801. aspectRatio: 16 / 9,
  24802. constraints: { facingMode: 'environment' },
  24803. };
  24804. /**
  24805. * Webcam-based source of data
  24806. */
  24807. class CameraSource extends VideoSource {
  24808. /**
  24809. * Constructor
  24810. */
  24811. constructor(options) {
  24812. const video = document.createElement('video');
  24813. super(video);
  24814. this._video = video;
  24815. this._options = Object.assign({}, DEFAULT_CAMERA_OPTIONS, options);
  24816. }
  24817. /**
  24818. * Camera resolution
  24819. */
  24820. get resolution() {
  24821. return this._options.resolution;
  24822. }
  24823. /**
  24824. * Stats related to this source of data
  24825. * @internal
  24826. */
  24827. get _stats() {
  24828. return `${this._size} webcam`;
  24829. }
  24830. /**
  24831. * Initialize this source of data
  24832. * @returns a promise that resolves as soon as this source of data is initialized
  24833. * @internal
  24834. */
  24835. _init() {
  24836. Utils.log('Accessing the webcam...');
  24837. // validate
  24838. if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)
  24839. throw new NotSupportedError('Unsupported browser: no navigator.mediaDevices.getUserMedia()');
  24840. // set up media constraints
  24841. const options = this._options;
  24842. const size = Utils.resolution(options.resolution, options.aspectRatio);
  24843. const constraints = {
  24844. audio: false,
  24845. video: Object.assign({ width: size.width, height: size.height }, options.constraints)
  24846. };
  24847. // load camera stream
  24848. return new (speedy_vision_default()).Promise((resolve, reject) => {
  24849. navigator.mediaDevices.getUserMedia(constraints).then(stream => {
  24850. const video = this._video;
  24851. video.onloadedmetadata = () => {
  24852. video.play();
  24853. Utils.log('Access to the webcam has been granted.');
  24854. resolve(video);
  24855. };
  24856. video.srcObject = stream;
  24857. video.muted = true;
  24858. }).catch(err => {
  24859. reject(new AccessDeniedError('Please give access to the webcam and reload the page.', err));
  24860. });
  24861. }).then(_ => super._init());
  24862. }
  24863. /**
  24864. * Release this source of data
  24865. * @returns a promise that resolves as soon as this source of data is released
  24866. * @internal
  24867. */
  24868. _release() {
  24869. const stream = this._video.srcObject;
  24870. const tracks = stream.getTracks();
  24871. // stop camera feed
  24872. tracks.forEach(track => track.stop());
  24873. this._video.onloadedmetadata = null;
  24874. this._video.srcObject = null;
  24875. // release the media
  24876. return super._release();
  24877. }
  24878. }
  24879. ;// CONCATENATED MODULE: ./src/sources/source-factory.ts
  24880. /*
  24881. * MARTINS.js Free Edition
  24882. * GPU-accelerated Augmented Reality for the web
  24883. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24884. * https://github.com/alemart/martins-js
  24885. *
  24886. * This program is free software: you can redistribute it and/or modify
  24887. * it under the terms of the GNU Affero General Public License version 3
  24888. * as published by the Free Software Foundation.
  24889. *
  24890. * This program is distributed in the hope that it will be useful,
  24891. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24892. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24893. * GNU Affero General Public License for more details.
  24894. *
  24895. * You should have received a copy of the GNU Affero General Public License
  24896. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24897. *
  24898. * source-factory.ts
  24899. * Factory of sources of data
  24900. */
  24901. /**
  24902. * Factory of sources of data
  24903. */
  24904. class SourceFactory {
  24905. /**
  24906. * Create a <video>-based source of data
  24907. * @param video video element
  24908. */
  24909. static Video(video) {
  24910. return new VideoSource(video);
  24911. }
  24912. /**
  24913. * Create a <canvas>-based source of data
  24914. * @param canvas canvas element
  24915. */
  24916. static Canvas(canvas) {
  24917. return new CanvasSource(canvas);
  24918. }
  24919. /**
  24920. * Create a Webcam-based source of data
  24921. * @param options optional options object
  24922. */
  24923. static Camera(options = {}) {
  24924. return new CameraSource(options);
  24925. }
  24926. }
  24927. ;// CONCATENATED MODULE: ./src/main.ts
  24928. /*
  24929. * MARTINS.js Free Edition
  24930. * GPU-accelerated Augmented Reality for the web
  24931. * Copyright (C) 2022 Alexandre Martins <alemartf(at)gmail.com>
  24932. * https://github.com/alemart/martins-js
  24933. *
  24934. * This program is free software: you can redistribute it and/or modify
  24935. * it under the terms of the GNU Affero General Public License version 3
  24936. * as published by the Free Software Foundation.
  24937. *
  24938. * This program is distributed in the hope that it will be useful,
  24939. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24940. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24941. * GNU Affero General Public License for more details.
  24942. *
  24943. * You should have received a copy of the GNU Affero General Public License
  24944. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  24945. *
  24946. * main.ts
  24947. * Entry point
  24948. */
  24949. /**
  24950. * GPU-accelerated Augmented Reality for the web
  24951. */
  24952. class Martins {
  24953. /**
  24954. * Start a new session
  24955. * @param options
  24956. * @returns a promise that resolves to a new session
  24957. */
  24958. static startSession(options) {
  24959. return Session.instantiate(options);
  24960. }
  24961. /**
  24962. * Trackers
  24963. */
  24964. static get Tracker() {
  24965. return TrackerFactory;
  24966. }
  24967. /**
  24968. * Sources of data
  24969. */
  24970. static get Source() {
  24971. return SourceFactory;
  24972. }
  24973. /**
  24974. * Create a viewport
  24975. * @param settings
  24976. * @returns a new viewport with the specified settings
  24977. */
  24978. static Viewport(settings) {
  24979. return new BaseViewport(settings);
  24980. }
  24981. /**
  24982. * Global Settings
  24983. */
  24984. static get Settings() {
  24985. return Settings;
  24986. }
  24987. /**
  24988. * Engine version
  24989. */
  24990. static get version() {
  24991. if (false)
  24992. {}
  24993. else
  24994. return "0.1.1";
  24995. }
  24996. /**
  24997. * Engine edition
  24998. */
  24999. static get edition() {
  25000. return 'Free Edition';
  25001. }
  25002. /**
  25003. * Speedy Vision
  25004. */
  25005. static get Speedy() {
  25006. return (speedy_vision_default());
  25007. }
  25008. /**
  25009. * Checks if the engine can be run in the browser the client is using
  25010. * @returns true if the engine is compatible with the browser
  25011. */
  25012. static isSupported() {
  25013. return Session.isSupported();
  25014. }
  25015. }
  25016. // Freeze the namespace
  25017. Object.freeze(Martins);
  25018. // Add Speedy Vision to global scope
  25019. ((window) => window.Speedy = window.Speedy || (speedy_vision_default()))(window);
  25020. // Display a notice
  25021. Utils.log(`MARTINS.js ${Martins.edition} version ${Martins.version}. ` +
  25022. `GPU-accelerated Augmented Reality for the web by Alexandre Martins. ` +
  25023. "https://github.com/alemart/martins-js");
  25024. })();
  25025. __webpack_exports__ = __webpack_exports__["default"];
  25026. /******/ return __webpack_exports__;
  25027. /******/ })()
  25028. ;
  25029. });