| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957 |
- /*Copyright (C) 2008-2009 Timothy B. Terriberry (tterribe@xiph.org)
- You can redistribute this library and/or modify it under the terms of the
- GNU Lesser General Public License as published by the Free Software
- Foundation; either version 2.1 of the License, or (at your option) any later
- version.*/
- //#include <stdlib.h>
- #include <limits.h>
- #include <string.h>
- #include <time.h>
- #include "qrcode.h"
- #include "qrdec.h"
- #include "bch15_5.h"
- #include "rs.h"
- #include "isaac.h"
- #include "util.h"
- #include "binarize.h"
- #include "image.h"
- #include "error.h"
- #include "svg.h"
- #include "zbar_config.h"
- typedef int qr_line[3];
- typedef struct qr_finder_cluster qr_finder_cluster;
- typedef struct qr_finder_edge_pt qr_finder_edge_pt;
- typedef struct qr_finder_center qr_finder_center;
- typedef struct qr_aff qr_aff;
- typedef struct qr_hom qr_hom;
- typedef struct qr_finder qr_finder;
- typedef struct qr_hom_cell qr_hom_cell;
- typedef struct qr_sampling_grid qr_sampling_grid;
- typedef struct qr_pack_buf qr_pack_buf;
- /*The number of bits in an int.
- Note the cast to (int): this prevents this value from "promoting" whole
- expressions to an (unsigned) size_t.*/
- #define QR_INT_BITS ((int)sizeof(int)*CHAR_BIT)
- #define QR_INT_LOGBITS (QR_ILOG(QR_INT_BITS))
- /*A 14 bit resolution for a homography ensures that the ideal module size for a
- version 40 code differs from that of a version 39 code by at least 2.*/
- #define QR_HOM_BITS (14)
- /*The number of bits of sub-module precision to use when searching for
- alignment patterns.
- Two bits allows an alignment pattern to be found even if the modules have
- been eroded by up to 50% (due to blurring, etc.).
- This must be at least one, since it affects the dynamic range of the
- transforms, and we sample at half-module resolution to compute a bounding
- quadrilateral for the code.*/
- #define QR_ALIGN_SUBPREC (2)
- /* collection of finder lines */
- typedef struct qr_finder_lines {
- qr_finder_line *lines;
- int nlines, clines;
- } qr_finder_lines;
- struct qr_reader {
- /*The GF(256) representation used in Reed-Solomon decoding.*/
- rs_gf256 gf;
- /*The random number generator used by RANSAC.*/
- isaac_ctx isaac;
- /* current finder state, horizontal and vertical lines */
- qr_finder_lines finder_lines[2];
- };
- /*Initializes a client reader handle.*/
- static void qr_reader_init (qr_reader *reader)
- {
- /*time_t now;
- now=time(NULL);
- isaac_init(&_reader->isaac,&now,sizeof(now));*/
- isaac_init(&reader->isaac, NULL, 0);
- rs_gf256_init(&reader->gf, QR_PPOLY);
- }
- /*Allocates a client reader handle.*/
- qr_reader *_zbar_qr_create (void)
- {
- qr_reader *reader = (qr_reader*)calloc(1, sizeof(*reader));
- qr_reader_init(reader);
- return(reader);
- }
- /*Frees a client reader handle.*/
- void _zbar_qr_destroy (qr_reader *reader)
- {
- zprintf(1, "max finder lines = %dx%d\n",
- reader->finder_lines[0].clines,
- reader->finder_lines[1].clines);
- if(reader->finder_lines[0].lines)
- free(reader->finder_lines[0].lines);
- if(reader->finder_lines[1].lines)
- free(reader->finder_lines[1].lines);
- free(reader);
- }
- /* reset finder state between scans */
- void _zbar_qr_reset (qr_reader *reader)
- {
- reader->finder_lines[0].nlines = 0;
- reader->finder_lines[1].nlines = 0;
- }
- /*A cluster of lines crossing a finder pattern (all in the same direction).*/
- struct qr_finder_cluster{
- /*Pointers to the lines crossing the pattern.*/
- qr_finder_line **lines;
- /*The number of lines in the cluster.*/
- int nlines;
- };
- /*A point on the edge of a finder pattern.
- These are obtained from the endpoints of the lines crossing this particular
- pattern.*/
- struct qr_finder_edge_pt{
- /*The location of the edge point.*/
- qr_point pos;
- /*A label classifying which edge this belongs to:
- 0: negative u edge (left)
- 1: positive u edge (right)
- 2: negative v edge (top)
- 3: positive v edge (bottom)*/
- int edge;
- /*The (signed) perpendicular distance of the edge point from a line parallel
- to the edge passing through the finder center, in (u,v) coordinates.
- This is also re-used by RANSAC to store inlier flags.*/
- int extent;
- };
- /*The center of a finder pattern obtained from the crossing of one or more
- clusters of horizontal finder lines with one or more clusters of vertical
- finder lines.*/
- struct qr_finder_center{
- /*The estimated location of the finder center.*/
- qr_point pos;
- /*The list of edge points from the crossing lines.*/
- qr_finder_edge_pt *edge_pts;
- /*The number of edge points from the crossing lines.*/
- int nedge_pts;
- };
- static int qr_finder_vline_cmp(const void *_a,const void *_b){
- const qr_finder_line *a;
- const qr_finder_line *b;
- a=(const qr_finder_line *)_a;
- b=(const qr_finder_line *)_b;
- return ((a->pos[0]>b->pos[0])-(a->pos[0]<b->pos[0])<<1)+
- (a->pos[1]>b->pos[1])-(a->pos[1]<b->pos[1]);
- }
- /*Clusters adjacent lines into groups that are large enough to be crossing a
- finder pattern (relative to their length).
- _clusters: The buffer in which to store the clusters found.
- _neighbors: The buffer used to store the lists of lines in each cluster.
- _lines: The list of lines to cluster.
- Horizontal lines must be sorted in ascending order by Y
- coordinate, with ties broken by X coordinate.
- Vertical lines must be sorted in ascending order by X coordinate,
- with ties broken by Y coordinate.
- _nlines: The number of lines in the set of lines to cluster.
- _v: 0 for horizontal lines, or 1 for vertical lines.
- Return: The number of clusters.*/
- static int qr_finder_cluster_lines(qr_finder_cluster *_clusters,
- qr_finder_line **_neighbors,qr_finder_line *_lines,int _nlines,int _v){
- unsigned char *mark;
- qr_finder_line **neighbors;
- int nneighbors;
- int nclusters;
- int i;
- /*TODO: Kalman filters!*/
- mark=(unsigned char *)calloc(_nlines,sizeof(*mark));
- neighbors=_neighbors;
- nclusters=0;
- for(i=0;i<_nlines-1;i++)if(!mark[i]){
- int len;
- int j;
- nneighbors=1;
- neighbors[0]=_lines+i;
- len=_lines[i].len;
- for(j=i+1;j<_nlines;j++)if(!mark[j]){
- const qr_finder_line *a;
- const qr_finder_line *b;
- int thresh;
- a=neighbors[nneighbors-1];
- b=_lines+j;
- /*The clustering threshold is proportional to the size of the lines,
- since minor noise in large areas can interrupt patterns more easily
- at high resolutions.*/
- thresh=a->len+7>>2;
- if(abs(a->pos[1-_v]-b->pos[1-_v])>thresh)break;
- if(abs(a->pos[_v]-b->pos[_v])>thresh)continue;
- if(abs(a->pos[_v]+a->len-b->pos[_v]-b->len)>thresh)continue;
- if(a->boffs>0&&b->boffs>0&&
- abs(a->pos[_v]-a->boffs-b->pos[_v]+b->boffs)>thresh){
- continue;
- }
- if(a->eoffs>0&&b->eoffs>0&&
- abs(a->pos[_v]+a->len+a->eoffs-b->pos[_v]-b->len-b->eoffs)>thresh){
- continue;
- }
- neighbors[nneighbors++]=_lines+j;
- len+=b->len;
- }
- /*We require at least three lines to form a cluster, which eliminates a
- large number of false positives, saving considerable decoding time.
- This should still be sufficient for 1-pixel codes with no noise.*/
- if(nneighbors<3)continue;
- /*The expected number of lines crossing a finder pattern is equal to their
- average length.
- We accept the cluster if size is at least 1/3 their average length (this
- is a very small threshold, but was needed for some test images).*/
- len=((len<<1)+nneighbors)/(nneighbors<<1);
- if(nneighbors*(5<<QR_FINDER_SUBPREC)>=len){
- _clusters[nclusters].lines=neighbors;
- _clusters[nclusters].nlines=nneighbors;
- for(j=0;j<nneighbors;j++)mark[neighbors[j]-_lines]=1;
- neighbors+=nneighbors;
- nclusters++;
- }
- }
- free(mark);
- return nclusters;
- }
- /*Adds the coordinates of the edge points from the lines contained in the
- given list of clusters to the list of edge points for a finder center.
- Only the edge point position is initialized.
- The edge label and extent are set by qr_finder_edge_pts_aff_classify()
- or qr_finder_edge_pts_hom_classify().
- _edge_pts: The buffer in which to store the edge points.
- _nedge_pts: The current number of edge points in the buffer.
- _neighbors: The list of lines in the cluster.
- _nneighbors: The number of lines in the list of lines in the cluster.
- _v: 0 for horizontal lines and 1 for vertical lines.
- Return: The new total number of edge points.*/
- static int qr_finder_edge_pts_fill(qr_finder_edge_pt *_edge_pts,int _nedge_pts,
- qr_finder_cluster **_neighbors,int _nneighbors,int _v){
- int i;
- for(i=0;i<_nneighbors;i++){
- qr_finder_cluster *c;
- int j;
- c=_neighbors[i];
- for(j=0;j<c->nlines;j++){
- qr_finder_line *l;
- l=c->lines[j];
- if(l->boffs>0){
- _edge_pts[_nedge_pts].pos[0]=l->pos[0];
- _edge_pts[_nedge_pts].pos[1]=l->pos[1];
- _edge_pts[_nedge_pts].pos[_v]-=l->boffs;
- _nedge_pts++;
- }
- if(l->eoffs>0){
- _edge_pts[_nedge_pts].pos[0]=l->pos[0];
- _edge_pts[_nedge_pts].pos[1]=l->pos[1];
- _edge_pts[_nedge_pts].pos[_v]+=l->len+l->eoffs;
- _nedge_pts++;
- }
- }
- }
- return _nedge_pts;
- }
- static int qr_finder_center_cmp(const void *_a,const void *_b){
- const qr_finder_center *a;
- const qr_finder_center *b;
- a=(const qr_finder_center *)_a;
- b=(const qr_finder_center *)_b;
- return ((b->nedge_pts>a->nedge_pts)-(b->nedge_pts<a->nedge_pts)<<2)+
- ((a->pos[1]>b->pos[1])-(a->pos[1]<b->pos[1])<<1)+
- (a->pos[0]>b->pos[0])-(a->pos[0]<b->pos[0]);
- }
- /*Determine if a horizontal line crosses a vertical line.
- _hline: The horizontal line.
- _vline: The vertical line.
- Return: A non-zero value if the lines cross, or zero if they do not.*/
- static int qr_finder_lines_are_crossing(const qr_finder_line *_hline,
- const qr_finder_line *_vline){
- return
- _hline->pos[0]<=_vline->pos[0]&&_vline->pos[0]<_hline->pos[0]+_hline->len&&
- _vline->pos[1]<=_hline->pos[1]&&_hline->pos[1]<_vline->pos[1]+_vline->len;
- }
- /*Finds horizontal clusters that cross corresponding vertical clusters,
- presumably corresponding to a finder center.
- _center: The buffer in which to store putative finder centers.
- _edge_pts: The buffer to use for the edge point lists for each finder
- center.
- _hclusters: The clusters of horizontal lines crossing finder patterns.
- _nhclusters: The number of horizontal line clusters.
- _vclusters: The clusters of vertical lines crossing finder patterns.
- _nvclusters: The number of vertical line clusters.
- Return: The number of putative finder centers.*/
- static int qr_finder_find_crossings(qr_finder_center *_centers,
- qr_finder_edge_pt *_edge_pts,qr_finder_cluster *_hclusters,int _nhclusters,
- qr_finder_cluster *_vclusters,int _nvclusters){
- qr_finder_cluster **hneighbors;
- qr_finder_cluster **vneighbors;
- unsigned char *hmark;
- unsigned char *vmark;
- int ncenters;
- int i;
- int j;
- hneighbors=(qr_finder_cluster **)malloc(_nhclusters*sizeof(*hneighbors));
- vneighbors=(qr_finder_cluster **)malloc(_nvclusters*sizeof(*vneighbors));
- hmark=(unsigned char *)calloc(_nhclusters,sizeof(*hmark));
- vmark=(unsigned char *)calloc(_nvclusters,sizeof(*vmark));
- ncenters=0;
- /*TODO: This may need some re-working.
- We should be finding groups of clusters such that _all_ horizontal lines in
- _all_ horizontal clusters in the group cross _all_ vertical lines in _all_
- vertical clusters in the group.
- This is equivalent to finding the maximum bipartite clique in the
- connectivity graph, which requires linear progamming to solve efficiently.
- In principle, that is easy to do, but a realistic implementation without
- floating point is a lot of work (and computationally expensive).
- Right now we are relying on a sufficient border around the finder patterns
- to prevent false positives.*/
- for(i=0;i<_nhclusters;i++)if(!hmark[i]){
- qr_finder_line *a;
- qr_finder_line *b;
- int nvneighbors;
- int nedge_pts;
- int y;
- a=_hclusters[i].lines[_hclusters[i].nlines>>1];
- y=nvneighbors=0;
- for(j=0;j<_nvclusters;j++)if(!vmark[j]){
- b=_vclusters[j].lines[_vclusters[j].nlines>>1];
- if(qr_finder_lines_are_crossing(a,b)){
- vmark[j]=1;
- y+=(b->pos[1]<<1)+b->len;
- if(b->boffs>0&&b->eoffs>0)y+=b->eoffs-b->boffs;
- vneighbors[nvneighbors++]=_vclusters+j;
- }
- }
- if(nvneighbors>0){
- qr_finder_center *c;
- int nhneighbors;
- int x;
- x=(a->pos[0]<<1)+a->len;
- if(a->boffs>0&&a->eoffs>0)x+=a->eoffs-a->boffs;
- hneighbors[0]=_hclusters+i;
- nhneighbors=1;
- j=nvneighbors>>1;
- b=vneighbors[j]->lines[vneighbors[j]->nlines>>1];
- for(j=i+1;j<_nhclusters;j++)if(!hmark[j]){
- a=_hclusters[j].lines[_hclusters[j].nlines>>1];
- if(qr_finder_lines_are_crossing(a,b)){
- hmark[j]=1;
- x+=(a->pos[0]<<1)+a->len;
- if(a->boffs>0&&a->eoffs>0)x+=a->eoffs-a->boffs;
- hneighbors[nhneighbors++]=_hclusters+j;
- }
- }
- c=_centers+ncenters++;
- c->pos[0]=(x+nhneighbors)/(nhneighbors<<1);
- c->pos[1]=(y+nvneighbors)/(nvneighbors<<1);
- c->edge_pts=_edge_pts;
- nedge_pts=qr_finder_edge_pts_fill(_edge_pts,0,
- hneighbors,nhneighbors,0);
- nedge_pts=qr_finder_edge_pts_fill(_edge_pts,nedge_pts,
- vneighbors,nvneighbors,1);
- c->nedge_pts=nedge_pts;
- _edge_pts+=nedge_pts;
- }
- }
- free(vmark);
- free(hmark);
- free(vneighbors);
- free(hneighbors);
- /*Sort the centers by decreasing numbers of edge points.*/
- qsort(_centers,ncenters,sizeof(*_centers),qr_finder_center_cmp);
- return ncenters;
- }
- /*Locates a set of putative finder centers in the image.
- First we search for horizontal and vertical lines that have
- (dark:light:dark:light:dark) runs with size ratios of roughly (1:1:3:1:1).
- Then we cluster them into groups such that each subsequent pair of endpoints
- is close to the line before it in the cluster.
- This will locate many line clusters that don't cross a finder pattern, but
- qr_finder_find_crossings() will filter most of them out.
- Where horizontal and vertical clusters cross, a prospective finder center is
- returned.
- _centers: Returns a pointer to a freshly-allocated list of finder centers.
- This must be freed by the caller.
- _edge_pts: Returns a pointer to a freshly-allocated list of edge points
- around those centers.
- This must be freed by the caller.
- _img: The binary image to search.
- _width: The width of the image.
- _height: The height of the image.
- Return: The number of putative finder centers located.*/
- static int qr_finder_centers_locate(qr_finder_center **_centers,
- qr_finder_edge_pt **_edge_pts, qr_reader *reader,
- int _width,int _height){
- qr_finder_line *hlines = reader->finder_lines[0].lines;
- int nhlines = reader->finder_lines[0].nlines;
- qr_finder_line *vlines = reader->finder_lines[1].lines;
- int nvlines = reader->finder_lines[1].nlines;
- qr_finder_line **hneighbors;
- qr_finder_cluster *hclusters;
- int nhclusters;
- qr_finder_line **vneighbors;
- qr_finder_cluster *vclusters;
- int nvclusters;
- int ncenters;
- /*Cluster the detected lines.*/
- hneighbors=(qr_finder_line **)malloc(nhlines*sizeof(*hneighbors));
- /*We require more than one line per cluster, so there are at most nhlines/2.*/
- hclusters=(qr_finder_cluster *)malloc((nhlines>>1)*sizeof(*hclusters));
- nhclusters=qr_finder_cluster_lines(hclusters,hneighbors,hlines,nhlines,0);
- /*We need vertical lines to be sorted by X coordinate, with ties broken by Y
- coordinate, for clustering purposes.
- We scan the image in the opposite order for cache efficiency, so sort the
- lines we found here.*/
- qsort(vlines,nvlines,sizeof(*vlines),qr_finder_vline_cmp);
- vneighbors=(qr_finder_line **)malloc(nvlines*sizeof(*vneighbors));
- /*We require more than one line per cluster, so there are at most nvlines/2.*/
- vclusters=(qr_finder_cluster *)malloc((nvlines>>1)*sizeof(*vclusters));
- nvclusters=qr_finder_cluster_lines(vclusters,vneighbors,vlines,nvlines,1);
- /*Find line crossings among the clusters.*/
- if(nhclusters>=3&&nvclusters>=3){
- qr_finder_edge_pt *edge_pts;
- qr_finder_center *centers;
- int nedge_pts;
- int i;
- nedge_pts=0;
- for(i=0;i<nhclusters;i++)nedge_pts+=hclusters[i].nlines;
- for(i=0;i<nvclusters;i++)nedge_pts+=vclusters[i].nlines;
- nedge_pts<<=1;
- edge_pts=(qr_finder_edge_pt *)malloc(nedge_pts*sizeof(*edge_pts));
- centers=(qr_finder_center *)malloc(
- QR_MINI(nhclusters,nvclusters)*sizeof(*centers));
- ncenters=qr_finder_find_crossings(centers,edge_pts,
- hclusters,nhclusters,vclusters,nvclusters);
- *_centers=centers;
- *_edge_pts=edge_pts;
- }
- else ncenters=0;
- free(vclusters);
- free(vneighbors);
- free(hclusters);
- free(hneighbors);
- return ncenters;
- }
- static void qr_point_translate(qr_point _point,int _dx,int _dy){
- _point[0]+=_dx;
- _point[1]+=_dy;
- }
- static unsigned qr_point_distance2(const qr_point _p1,const qr_point _p2){
- return (_p1[0]-_p2[0])*(_p1[0]-_p2[0])+(_p1[1]-_p2[1])*(_p1[1]-_p2[1]);
- }
- /*Returns the cross product of the three points, which is positive if they are
- in CCW order (in a right-handed coordinate system), and 0 if they're
- colinear.*/
- static int qr_point_ccw(const qr_point _p0,
- const qr_point _p1,const qr_point _p2){
- return (_p1[0]-_p0[0])*(_p2[1]-_p0[1])-(_p1[1]-_p0[1])*(_p2[0]-_p0[0]);
- }
- /*Evaluates a line equation at a point.
- _line: The line to evaluate.
- _x: The X coordinate of the point.
- _y: The y coordinate of the point.
- Return: The value of the line equation _line[0]*_x+_line[1]*_y+_line[2].*/
- static int qr_line_eval(qr_line _line,int _x,int _y){
- return _line[0]*_x+_line[1]*_y+_line[2];
- }
- /*Computes a line passing through the given point using the specified second
- order statistics.
- Given a line defined by the equation
- A*x+B*y+C = 0 ,
- the least squares fit to n points (x_i,y_i) must satisfy the two equations
- A^2 + (Syy - Sxx)/Sxy*A*B - B^2 = 0 ,
- C = -(xbar*A+ybar*B) ,
- where
- xbar = sum(x_i)/n ,
- ybar = sum(y_i)/n ,
- Sxx = sum((x_i-xbar)**2) ,
- Sxy = sum((x_i-xbar)*(y_i-ybar)) ,
- Syy = sum((y_i-ybar)**2) .
- The quadratic can be solved for the ratio (A/B) or (B/A):
- A/B = (Syy + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Sxx)/(-2*Sxy) ,
- B/A = (Sxx + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Syy)/(-2*Sxy) .
- We pick the one that leads to the larger ratio to avoid destructive
- cancellation (and e.g., 0/0 for horizontal or vertical lines).
- The above solutions correspond to the actual minimum.
- The other solution of the quadratic corresponds to a saddle point of the
- least squares objective function.
- _l: Returns the fitted line values A, B, and C.
- _x0: The X coordinate of the point the line is supposed to pass through.
- _y0: The Y coordinate of the point the line is supposed to pass through.
- _sxx: The sum Sxx.
- _sxy: The sum Sxy.
- _syy: The sum Syy.
- _res: The maximum number of bits occupied by the product of any two of
- _l[0] or _l[1].
- Smaller numbers give less angular resolution, but allow more overhead
- room for computations.*/
- static void qr_line_fit(qr_line _l,int _x0,int _y0,
- int _sxx,int _sxy,int _syy,int _res){
- int dshift;
- int dround;
- int u;
- int v;
- int w;
- u=abs(_sxx-_syy);
- v=-_sxy<<1;
- w=qr_ihypot(u,v);
- /*Computations in later stages can easily overflow with moderate sizes, so we
- compute a shift factor to scale things down into a managable range.
- We ensure that the product of any two of _l[0] and _l[1] fits within _res
- bits, which allows computation of line intersections without overflow.*/
- dshift=QR_MAXI(0,QR_MAXI(qr_ilog(u),qr_ilog(abs(v)))+1-(_res+1>>1));
- dround=(1<<dshift)>>1;
- if(_sxx>_syy){
- _l[0]=v+dround>>dshift;
- _l[1]=u+w+dround>>dshift;
- }
- else{
- _l[0]=u+w+dround>>dshift;
- _l[1]=v+dround>>dshift;
- }
- _l[2]=-(_x0*_l[0]+_y0*_l[1]);
- }
- /*Perform a least-squares line fit to a list of points.
- At least two points are required.*/
- static void qr_line_fit_points(qr_line _l,qr_point *_p,int _np,int _res){
- int sx;
- int sy;
- int xmin;
- int xmax;
- int ymin;
- int ymax;
- int xbar;
- int ybar;
- int dx;
- int dy;
- int sxx;
- int sxy;
- int syy;
- int sshift;
- int sround;
- int i;
- sx=sy=0;
- ymax=xmax=INT_MIN;
- ymin=xmin=INT_MAX;
- for(i=0;i<_np;i++){
- sx+=_p[i][0];
- xmin=QR_MINI(xmin,_p[i][0]);
- xmax=QR_MAXI(xmax,_p[i][0]);
- sy+=_p[i][1];
- ymin=QR_MINI(ymin,_p[i][1]);
- ymax=QR_MAXI(ymax,_p[i][1]);
- }
- xbar=(sx+(_np>>1))/_np;
- ybar=(sy+(_np>>1))/_np;
- sshift=QR_MAXI(0,qr_ilog(_np*QR_MAXI(QR_MAXI(xmax-xbar,xbar-xmin),
- QR_MAXI(ymax-ybar,ybar-ymin)))-(QR_INT_BITS-1>>1));
- sround=(1<<sshift)>>1;
- sxx=sxy=syy=0;
- for(i=0;i<_np;i++){
- dx=_p[i][0]-xbar+sround>>sshift;
- dy=_p[i][1]-ybar+sround>>sshift;
- sxx+=dx*dx;
- sxy+=dx*dy;
- syy+=dy*dy;
- }
- qr_line_fit(_l,xbar,ybar,sxx,sxy,syy,_res);
- }
- static void qr_line_orient(qr_line _l,int _x,int _y){
- if(qr_line_eval(_l,_x,_y)<0){
- _l[0]=-_l[0];
- _l[1]=-_l[1];
- _l[2]=-_l[2];
- }
- }
- static int qr_line_isect(qr_point _p,const qr_line _l0,const qr_line _l1){
- int d;
- int x;
- int y;
- d=_l0[0]*_l1[1]-_l0[1]*_l1[0];
- if(d==0)return -1;
- x=_l0[1]*_l1[2]-_l1[1]*_l0[2];
- y=_l1[0]*_l0[2]-_l0[0]*_l1[2];
- if(d<0){
- x=-x;
- y=-y;
- d=-d;
- }
- _p[0]=QR_DIVROUND(x,d);
- _p[1]=QR_DIVROUND(y,d);
- return 0;
- }
- /*An affine homography.
- This maps from the image (at subpel resolution) to a square domain with
- power-of-two sides (of res bits) and back.*/
- struct qr_aff{
- int fwd[2][2];
- int inv[2][2];
- int x0;
- int y0;
- int res;
- };
- static void qr_aff_init(qr_aff *_aff,
- const qr_point _p0,const qr_point _p1,const qr_point _p2,int _res){
- int det;
- int dx1;
- int dy1;
- int dx2;
- int dy2;
- /*det is ensured to be positive by our caller.*/
- det=qr_point_ccw(_p0,_p1,_p2);
- dx1=_p1[0]-_p0[0];
- dx2=_p2[0]-_p0[0];
- dy1=_p1[1]-_p0[1];
- dy2=_p2[1]-_p0[1];
- _aff->fwd[0][0]=dx1;
- _aff->fwd[0][1]=dx2;
- _aff->fwd[1][0]=dy1;
- _aff->fwd[1][1]=dy2;
- _aff->inv[0][0]=QR_DIVROUND(dy2<<_res,det);
- _aff->inv[0][1]=QR_DIVROUND(-dx2<<_res,det);
- _aff->inv[1][0]=QR_DIVROUND(-dy1<<_res,det);
- _aff->inv[1][1]=QR_DIVROUND(dx1<<_res,det);
- _aff->x0=_p0[0];
- _aff->y0=_p0[1];
- _aff->res=_res;
- }
- /*Map from the image (at subpel resolution) into the square domain.*/
- static void qr_aff_unproject(qr_point _q,const qr_aff *_aff,
- int _x,int _y){
- _q[0]=_aff->inv[0][0]*(_x-_aff->x0)+_aff->inv[0][1]*(_y-_aff->y0);
- _q[1]=_aff->inv[1][0]*(_x-_aff->x0)+_aff->inv[1][1]*(_y-_aff->y0);
- }
- /*Map from the square domain into the image (at subpel resolution).*/
- static void qr_aff_project(qr_point _p,const qr_aff *_aff,
- int _u,int _v){
- _p[0]=(_aff->fwd[0][0]*_u+_aff->fwd[0][1]*_v+(1<<_aff->res-1)>>_aff->res)
- +_aff->x0;
- _p[1]=(_aff->fwd[1][0]*_u+_aff->fwd[1][1]*_v+(1<<_aff->res-1)>>_aff->res)
- +_aff->y0;
- }
- /*A full homography.
- Like the affine homography, this maps from the image (at subpel resolution)
- to a square domain with power-of-two sides (of res bits) and back.*/
- struct qr_hom{
- int fwd[3][2];
- int inv[3][2];
- int fwd22;
- int inv22;
- int x0;
- int y0;
- int res;
- };
- static void qr_hom_init(qr_hom *_hom,int _x0,int _y0,
- int _x1,int _y1,int _x2,int _y2,int _x3,int _y3,int _res){
- int dx10;
- int dx20;
- int dx30;
- int dx31;
- int dx32;
- int dy10;
- int dy20;
- int dy30;
- int dy31;
- int dy32;
- int a20;
- int a21;
- int a22;
- int b0;
- int b1;
- int b2;
- int s1;
- int s2;
- int r1;
- int r2;
- dx10=_x1-_x0;
- dx20=_x2-_x0;
- dx30=_x3-_x0;
- dx31=_x3-_x1;
- dx32=_x3-_x2;
- dy10=_y1-_y0;
- dy20=_y2-_y0;
- dy30=_y3-_y0;
- dy31=_y3-_y1;
- dy32=_y3-_y2;
- a20=dx32*dy10-dx10*dy32;
- a21=dx20*dy31-dx31*dy20;
- a22=dx32*dy31-dx31*dy32;
- /*Figure out if we need to downscale anything.*/
- b0=qr_ilog(QR_MAXI(abs(dx10),abs(dy10)))+qr_ilog(abs(a20+a22));
- b1=qr_ilog(QR_MAXI(abs(dx20),abs(dy20)))+qr_ilog(abs(a21+a22));
- b2=qr_ilog(QR_MAXI(QR_MAXI(abs(a20),abs(a21)),abs(a22)));
- s1=QR_MAXI(0,_res+QR_MAXI(QR_MAXI(b0,b1),b2)-(QR_INT_BITS-2));
- r1=(1<<s1)>>1;
- /*Compute the final coefficients of the forward transform.
- The 32x32->64 bit multiplies are really needed for accuracy with large
- versions.*/
- _hom->fwd[0][0]=QR_FIXMUL(dx10,a20+a22,r1,s1);
- _hom->fwd[0][1]=QR_FIXMUL(dx20,a21+a22,r1,s1);
- _hom->x0=_x0;
- _hom->fwd[1][0]=QR_FIXMUL(dy10,a20+a22,r1,s1);
- _hom->fwd[1][1]=QR_FIXMUL(dy20,a21+a22,r1,s1);
- _hom->y0=_y0;
- _hom->fwd[2][0]=a20+r1>>s1;
- _hom->fwd[2][1]=a21+r1>>s1;
- _hom->fwd22=s1>_res?a22+(r1>>_res)>>s1-_res:a22<<_res-s1;
- /*Now compute the inverse transform.*/
- b0=qr_ilog(QR_MAXI(QR_MAXI(abs(dx10),abs(dx20)),abs(dx30)))+
- qr_ilog(QR_MAXI(abs(_hom->fwd[0][0]),abs(_hom->fwd[1][0])));
- b1=qr_ilog(QR_MAXI(QR_MAXI(abs(dy10),abs(dy20)),abs(dy30)))+
- qr_ilog(QR_MAXI(abs(_hom->fwd[0][1]),abs(_hom->fwd[1][1])));
- b2=qr_ilog(abs(a22))-s1;
- s2=QR_MAXI(0,QR_MAXI(b0,b1)+b2-(QR_INT_BITS-3));
- r2=(1<<s2)>>1;
- s1+=s2;
- r1<<=s2;
- /*The 32x32->64 bit multiplies are really needed for accuracy with large
- versions.*/
- _hom->inv[0][0]=QR_FIXMUL(_hom->fwd[1][1],a22,r1,s1);
- _hom->inv[0][1]=QR_FIXMUL(-_hom->fwd[0][1],a22,r1,s1);
- _hom->inv[1][0]=QR_FIXMUL(-_hom->fwd[1][0],a22,r1,s1);
- _hom->inv[1][1]=QR_FIXMUL(_hom->fwd[0][0],a22,r1,s1);
- _hom->inv[2][0]=QR_FIXMUL(_hom->fwd[1][0],_hom->fwd[2][1],
- -QR_EXTMUL(_hom->fwd[1][1],_hom->fwd[2][0],r2),s2);
- _hom->inv[2][1]=QR_FIXMUL(_hom->fwd[0][1],_hom->fwd[2][0],
- -QR_EXTMUL(_hom->fwd[0][0],_hom->fwd[2][1],r2),s2);
- _hom->inv22=QR_FIXMUL(_hom->fwd[0][0],_hom->fwd[1][1],
- -QR_EXTMUL(_hom->fwd[0][1],_hom->fwd[1][0],r2),s2);
- _hom->res=_res;
- }
- /*Map from the image (at subpel resolution) into the square domain.
- Returns a negative value if the point went to infinity.*/
- static int qr_hom_unproject(qr_point _q,const qr_hom *_hom,int _x,int _y){
- int x;
- int y;
- int w;
- _x-=_hom->x0;
- _y-=_hom->y0;
- x=_hom->inv[0][0]*_x+_hom->inv[0][1]*_y;
- y=_hom->inv[1][0]*_x+_hom->inv[1][1]*_y;
- w=_hom->inv[2][0]*_x+_hom->inv[2][1]*_y
- +_hom->inv22+(1<<_hom->res-1)>>_hom->res;
- if(w==0){
- _q[0]=x<0?INT_MIN:INT_MAX;
- _q[1]=y<0?INT_MIN:INT_MAX;
- return -1;
- }
- else{
- if(w<0){
- x=-x;
- y=-y;
- w=-w;
- }
- _q[0]=QR_DIVROUND(x,w);
- _q[1]=QR_DIVROUND(y,w);
- }
- return 0;
- }
- /*Finish a partial projection, converting from homogeneous coordinates to the
- normal 2-D representation.
- In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
- and _w incrementally, but we cannot avoid the divisions, done here.*/
- static void qr_hom_fproject(qr_point _p,const qr_hom *_hom,
- int _x,int _y,int _w){
- if(_w==0){
- _p[0]=_x<0?INT_MIN:INT_MAX;
- _p[1]=_y<0?INT_MIN:INT_MAX;
- }
- else{
- if(_w<0){
- _x=-_x;
- _y=-_y;
- _w=-_w;
- }
- _p[0]=QR_DIVROUND(_x,_w)+_hom->x0;
- _p[1]=QR_DIVROUND(_y,_w)+_hom->y0;
- }
- }
- #if defined(QR_DEBUG)
- /*Map from the square domain into the image (at subpel resolution).
- Currently only used directly by debug code.*/
- static void qr_hom_project(qr_point _p,const qr_hom *_hom,
- int _u,int _v){
- qr_hom_fproject(_p,_hom,
- _hom->fwd[0][0]*_u+_hom->fwd[0][1]*_v,
- _hom->fwd[1][0]*_u+_hom->fwd[1][1]*_v,
- _hom->fwd[2][0]*_u+_hom->fwd[2][1]*_v+_hom->fwd22);
- }
- #endif
- /*All the information we've collected about a finder pattern in the current
- configuration.*/
- struct qr_finder{
- /*The module size along each axis (in the square domain).*/
- int size[2];
- /*The version estimated from the module size along each axis.*/
- int eversion[2];
- /*The list of classified edge points for each edge.*/
- qr_finder_edge_pt *edge_pts[4];
- /*The number of edge points classified as belonging to each edge.*/
- int nedge_pts[4];
- /*The number of inliers found after running RANSAC on each edge.*/
- int ninliers[4];
- /*The center of the finder pattern (in the square domain).*/
- qr_point o;
- /*The finder center information from the original image.*/
- qr_finder_center *c;
- };
- static int qr_cmp_edge_pt(const void *_a,const void *_b){
- const qr_finder_edge_pt *a;
- const qr_finder_edge_pt *b;
- a=(const qr_finder_edge_pt *)_a;
- b=(const qr_finder_edge_pt *)_b;
- return ((a->edge>b->edge)-(a->edge<b->edge)<<1)+
- (a->extent>b->extent)-(a->extent<b->extent);
- }
- /*Computes the index of the edge each edge point belongs to, and its (signed)
- distance along the corresponding axis from the center of the finder pattern
- (in the square domain).
- The resulting list of edge points is sorted by edge index, with ties broken
- by extent.*/
- static void qr_finder_edge_pts_aff_classify(qr_finder *_f,const qr_aff *_aff){
- qr_finder_center *c;
- int i;
- int e;
- c=_f->c;
- for(e=0;e<4;e++)_f->nedge_pts[e]=0;
- for(i=0;i<c->nedge_pts;i++){
- qr_point q;
- int d;
- qr_aff_unproject(q,_aff,c->edge_pts[i].pos[0],c->edge_pts[i].pos[1]);
- qr_point_translate(q,-_f->o[0],-_f->o[1]);
- d=abs(q[1])>abs(q[0]);
- e=d<<1|(q[d]>=0);
- _f->nedge_pts[e]++;
- c->edge_pts[i].edge=e;
- c->edge_pts[i].extent=q[d];
- }
- qsort(c->edge_pts,c->nedge_pts,sizeof(*c->edge_pts),qr_cmp_edge_pt);
- _f->edge_pts[0]=c->edge_pts;
- for(e=1;e<4;e++)_f->edge_pts[e]=_f->edge_pts[e-1]+_f->nedge_pts[e-1];
- }
- /*Computes the index of the edge each edge point belongs to, and its (signed)
- distance along the corresponding axis from the center of the finder pattern
- (in the square domain).
- The resulting list of edge points is sorted by edge index, with ties broken
- by extent.*/
- static void qr_finder_edge_pts_hom_classify(qr_finder *_f,const qr_hom *_hom){
- qr_finder_center *c;
- int i;
- int e;
- c=_f->c;
- for(e=0;e<4;e++)_f->nedge_pts[e]=0;
- for(i=0;i<c->nedge_pts;i++){
- qr_point q;
- int d;
- if(qr_hom_unproject(q,_hom,
- c->edge_pts[i].pos[0],c->edge_pts[i].pos[1])>=0){
- qr_point_translate(q,-_f->o[0],-_f->o[1]);
- d=abs(q[1])>abs(q[0]);
- e=d<<1|(q[d]>=0);
- _f->nedge_pts[e]++;
- c->edge_pts[i].edge=e;
- c->edge_pts[i].extent=q[d];
- }
- else{
- c->edge_pts[i].edge=4;
- c->edge_pts[i].extent=q[0];
- }
- }
- qsort(c->edge_pts,c->nedge_pts,sizeof(*c->edge_pts),qr_cmp_edge_pt);
- _f->edge_pts[0]=c->edge_pts;
- for(e=1;e<4;e++)_f->edge_pts[e]=_f->edge_pts[e-1]+_f->nedge_pts[e-1];
- }
- /*TODO: Perhaps these thresholds should be on the module size instead?
- Unfortunately, I'd need real-world images of codes with larger versions to
- see if these thresholds are still effective, but such versions aren't used
- often.*/
- /*The amount that the estimated version numbers are allowed to differ from the
- real version number and still be considered valid.*/
- #define QR_SMALL_VERSION_SLACK (1)
- /*Since cell phone cameras can have severe radial distortion, the estimated
- version for larger versions can be off by larger amounts.*/
- #define QR_LARGE_VERSION_SLACK (3)
- /*Estimates the size of a module after classifying the edge points.
- _width: The distance between UL and UR in the square domain.
- _height: The distance between UL and DL in the square domain.*/
- static int qr_finder_estimate_module_size_and_version(qr_finder *_f,
- int _width,int _height){
- qr_point offs;
- int sums[4];
- int nsums[4];
- int usize;
- int nusize;
- int vsize;
- int nvsize;
- int uversion;
- int vversion;
- int e;
- offs[0]=offs[1]=0;
- for(e=0;e<4;e++)if(_f->nedge_pts[e]>0){
- qr_finder_edge_pt *edge_pts;
- int sum;
- int mean;
- int n;
- int i;
- /*Average the samples for this edge, dropping the top and bottom 25%.*/
- edge_pts=_f->edge_pts[e];
- n=_f->nedge_pts[e];
- sum=0;
- for(i=(n>>2);i<n-(n>>2);i++)sum+=edge_pts[i].extent;
- n=n-((n>>2)<<1);
- mean=QR_DIVROUND(sum,n);
- offs[e>>1]+=mean;
- sums[e]=sum;
- nsums[e]=n;
- }
- else nsums[e]=sums[e]=0;
- /*If we have samples on both sides of an axis, refine our idea of where the
- unprojected finder center is located.*/
- if(_f->nedge_pts[0]>0&&_f->nedge_pts[1]>0){
- _f->o[0]-=offs[0]>>1;
- sums[0]-=offs[0]*nsums[0]>>1;
- sums[1]-=offs[0]*nsums[1]>>1;
- }
- if(_f->nedge_pts[2]>0&&_f->nedge_pts[3]>0){
- _f->o[1]-=offs[1]>>1;
- sums[2]-=offs[1]*nsums[2]>>1;
- sums[3]-=offs[1]*nsums[3]>>1;
- }
- /*We must have _some_ samples along each axis... if we don't, our transform
- must be pretty severely distorting the original square (e.g., with
- coordinates so large as to cause overflow).*/
- nusize=nsums[0]+nsums[1];
- if(nusize<=0)return -1;
- /*The module size is 1/3 the average edge extent.*/
- nusize*=3;
- usize=sums[1]-sums[0];
- usize=((usize<<1)+nusize)/(nusize<<1);
- if(usize<=0)return -1;
- /*Now estimate the version directly from the module size and the distance
- between the finder patterns.
- This is done independently using the extents along each axis.
- If either falls significantly outside the valid range (1 to 40), reject the
- configuration.*/
- uversion=(_width-8*usize)/(usize<<2);
- if(uversion<1||uversion>40+QR_LARGE_VERSION_SLACK)return -1;
- /*Now do the same for the other axis.*/
- nvsize=nsums[2]+nsums[3];
- if(nvsize<=0)return -1;
- nvsize*=3;
- vsize=sums[3]-sums[2];
- vsize=((vsize<<1)+nvsize)/(nvsize<<1);
- if(vsize<=0)return -1;
- vversion=(_height-8*vsize)/(vsize<<2);
- if(vversion<1||vversion>40+QR_LARGE_VERSION_SLACK)return -1;
- /*If the estimated version using extents along one axis is significantly
- different than the estimated version along the other axis, then the axes
- have significantly different scalings (relative to the grid).
- This can happen, e.g., when we have multiple adjacent QR codes, and we've
- picked two finder patterns from one and the third finder pattern from
- another, e.g.:
- X---DL UL---X
- |.... |....
- X.... UR....
- Such a configuration might even pass any other geometric checks if we
- didn't reject it here.*/
- if(abs(uversion-vversion)>QR_LARGE_VERSION_SLACK)return -1;
- _f->size[0]=usize;
- _f->size[1]=vsize;
- /*We intentionally do not compute an average version from the sizes along
- both axes.
- In the presence of projective distortion, one of them will be much more
- accurate than the other.*/
- _f->eversion[0]=uversion;
- _f->eversion[1]=vversion;
- return 0;
- }
- /*Eliminate outliers from the classified edge points with RANSAC.*/
- static void qr_finder_ransac(qr_finder *_f,const qr_aff *_hom,
- isaac_ctx *_isaac,int _e){
- qr_finder_edge_pt *edge_pts;
- int best_ninliers;
- int n;
- edge_pts=_f->edge_pts[_e];
- n=_f->nedge_pts[_e];
- best_ninliers=0;
- if(n>1){
- int max_iters;
- int i;
- int j;
- /*17 iterations is enough to guarantee an outlier-free sample with more
- than 99% probability given as many as 50% outliers.*/
- max_iters=17;
- for(i=0;i<max_iters;i++){
- qr_point q0;
- qr_point q1;
- int ninliers;
- int thresh;
- int p0i;
- int p1i;
- int *p0;
- int *p1;
- int j;
- /*Pick two random points on this edge.*/
- p0i=isaac_next_uint(_isaac,n);
- p1i=isaac_next_uint(_isaac,n-1);
- if(p1i>=p0i)p1i++;
- p0=edge_pts[p0i].pos;
- p1=edge_pts[p1i].pos;
- /*If the corresponding line is not within 45 degrees of the proper
- orientation in the square domain, reject it outright.
- This can happen, e.g., when highly skewed orientations cause points to
- be misclassified into the wrong edge.
- The irony is that using such points might produce a line which _does_
- pass the corresponding validity checks.*/
- qr_aff_unproject(q0,_hom,p0[0],p0[1]);
- qr_aff_unproject(q1,_hom,p1[0],p1[1]);
- qr_point_translate(q0,-_f->o[0],-_f->o[1]);
- qr_point_translate(q1,-_f->o[0],-_f->o[1]);
- if(abs(q0[_e>>1]-q1[_e>>1])>abs(q0[1-(_e>>1)]-q1[1-(_e>>1)]))continue;
- /*Identify the other edge points which are inliers.
- The squared distance should be distributed as a \Chi^2 distribution
- with one degree of freedom, which means for a 95% confidence the
- point should lie within a factor 3.8414588 ~= 4 times the expected
- variance of the point locations.
- We grossly approximate the standard deviation as 1 pixel in one
- direction, and 0.5 pixels in the other (because we average two
- coordinates).*/
- thresh=qr_isqrt(qr_point_distance2(p0,p1)<<2*QR_FINDER_SUBPREC+1);
- ninliers=0;
- for(j=0;j<n;j++){
- if(abs(qr_point_ccw(p0,p1,edge_pts[j].pos))<=thresh){
- edge_pts[j].extent|=1;
- ninliers++;
- }
- else edge_pts[j].extent&=~1;
- }
- if(ninliers>best_ninliers){
- for(j=0;j<n;j++)edge_pts[j].extent<<=1;
- best_ninliers=ninliers;
- /*The actual number of iterations required is
- log(1-\alpha)/log(1-r*r),
- where \alpha is the required probability of taking a sample with
- no outliers (e.g., 0.99) and r is the estimated ratio of inliers
- (e.g. ninliers/n).
- This is just a rough (but conservative) approximation, but it
- should be good enough to stop the iteration early when we find
- a good set of inliers.*/
- if(ninliers>n>>1)max_iters=(67*n-63*ninliers-1)/(n<<1);
- }
- }
- /*Now collect all the inliers at the beginning of the list.*/
- for(i=j=0;j<best_ninliers;i++)if(edge_pts[i].extent&2){
- if(j<i){
- qr_finder_edge_pt tmp;
- *&tmp=*(edge_pts+i);
- *(edge_pts+j)=*(edge_pts+i);
- *(edge_pts+i)=*&tmp;
- }
- j++;
- }
- }
- _f->ninliers[_e]=best_ninliers;
- }
- /*Perform a least-squares line fit to an edge of a finder pattern using the
- inliers found by RANSAC.*/
- static int qr_line_fit_finder_edge(qr_line _l,
- const qr_finder *_f,int _e,int _res){
- qr_finder_edge_pt *edge_pts;
- qr_point *pts;
- int npts;
- int i;
- npts=_f->ninliers[_e];
- if(npts<2)return -1;
- /*We could write a custom version of qr_line_fit_points that accesses
- edge_pts directly, but this saves on code size and doesn't measurably slow
- things down.*/
- pts=(qr_point *)malloc(npts*sizeof(*pts));
- edge_pts=_f->edge_pts[_e];
- for(i=0;i<npts;i++){
- pts[i][0]=edge_pts[i].pos[0];
- pts[i][1]=edge_pts[i].pos[1];
- }
- qr_line_fit_points(_l,pts,npts,_res);
- /*Make sure the center of the finder pattern lies in the positive halfspace
- of the line.*/
- qr_line_orient(_l,_f->c->pos[0],_f->c->pos[1]);
- free(pts);
- return 0;
- }
- /*Perform a least-squares line fit to a pair of common finder edges using the
- inliers found by RANSAC.
- Unlike a normal edge fit, we guarantee that this one succeeds by creating at
- least one point on each edge using the estimated module size if it has no
- inliers.*/
- static void qr_line_fit_finder_pair(qr_line _l,const qr_aff *_aff,
- const qr_finder *_f0,const qr_finder *_f1,int _e){
- qr_point *pts;
- int npts;
- qr_finder_edge_pt *edge_pts;
- qr_point q;
- int n0;
- int n1;
- int i;
- n0=_f0->ninliers[_e];
- n1=_f1->ninliers[_e];
- /*We could write a custom version of qr_line_fit_points that accesses
- edge_pts directly, but this saves on code size and doesn't measurably slow
- things down.*/
- npts=QR_MAXI(n0,1)+QR_MAXI(n1,1);
- pts=(qr_point *)malloc(npts*sizeof(*pts));
- if(n0>0){
- edge_pts=_f0->edge_pts[_e];
- for(i=0;i<n0;i++){
- pts[i][0]=edge_pts[i].pos[0];
- pts[i][1]=edge_pts[i].pos[1];
- }
- }
- else{
- q[0]=_f0->o[0];
- q[1]=_f0->o[1];
- q[_e>>1]+=_f0->size[_e>>1]*(2*(_e&1)-1);
- qr_aff_project(pts[0],_aff,q[0],q[1]);
- n0++;
- }
- if(n1>0){
- edge_pts=_f1->edge_pts[_e];
- for(i=0;i<n1;i++){
- pts[n0+i][0]=edge_pts[i].pos[0];
- pts[n0+i][1]=edge_pts[i].pos[1];
- }
- }
- else{
- q[0]=_f1->o[0];
- q[1]=_f1->o[1];
- q[_e>>1]+=_f1->size[_e>>1]*(2*(_e&1)-1);
- qr_aff_project(pts[n0],_aff,q[0],q[1]);
- n1++;
- }
- qr_line_fit_points(_l,pts,npts,_aff->res);
- /*Make sure at least one finder center lies in the positive halfspace.*/
- qr_line_orient(_l,_f0->c->pos[0],_f0->c->pos[1]);
- free(pts);
- }
- static int qr_finder_quick_crossing_check(const unsigned char *_img,
- int _width,int _height,int _x0,int _y0,int _x1,int _y1,int _v){
- /*The points must be inside the image, and have a !_v:_v:!_v pattern.
- We don't scan the whole line initially, but quickly reject if the endpoints
- aren't !_v, or the midpoint isn't _v.
- If either end point is out of the image, or we don't encounter a _v pixel,
- we return a negative value, indicating the region should be considered
- empty.
- Otherwise, we return a positive value to indicate it is non-empty.*/
- if(_x0<0||_x0>=_width||_y0<0||_y0>=_height||
- _x1<0||_x1>=_width||_y1<0||_y1>=_height){
- return -1;
- }
- if(!_img[_y0*_width+_x0]!=_v||!_img[_y1*_width+_x1]!=_v)return 1;
- if(!_img[(_y0+_y1>>1)*_width+(_x0+_x1>>1)]==_v)return -1;
- return 0;
- }
- /*Locate the midpoint of a _v segment along a !_v:_v:!_v line from (_x0,_y0) to
- (_x1,_y1).
- All coordinates, which are NOT in subpel resolution, must lie inside the
- image, and the endpoints are already assumed to have the value !_v.
- The returned value is in subpel resolution.*/
- static int qr_finder_locate_crossing(const unsigned char *_img,
- int _width,int _height,int _x0,int _y0,int _x1,int _y1,int _v,qr_point _p){
- qr_point x0;
- qr_point x1;
- qr_point dx;
- int step[2];
- int steep;
- int err;
- int derr;
- /*Use Bresenham's algorithm to trace along the line and find the exact
- transitions from !_v to _v and back.*/
- x0[0]=_x0;
- x0[1]=_y0;
- x1[0]=_x1;
- x1[1]=_y1;
- dx[0]=abs(_x1-_x0);
- dx[1]=abs(_y1-_y0);
- steep=dx[1]>dx[0];
- err=0;
- derr=dx[1-steep];
- step[0]=((_x0<_x1)<<1)-1;
- step[1]=((_y0<_y1)<<1)-1;
- /*Find the first crossing from !_v to _v.*/
- for(;;){
- /*If we make it all the way to the other side, there's no crossing.*/
- if(x0[steep]==x1[steep])return -1;
- x0[steep]+=step[steep];
- err+=derr;
- if(err<<1>dx[steep]){
- x0[1-steep]+=step[1-steep];
- err-=dx[steep];
- }
- if(!_img[x0[1]*_width+x0[0]]!=_v)break;
- }
- /*Find the last crossing from _v to !_v.*/
- err=0;
- for(;;){
- if(x0[steep]==x1[steep])break;
- x1[steep]-=step[steep];
- err+=derr;
- if(err<<1>dx[steep]){
- x1[1-steep]-=step[1-steep];
- err-=dx[steep];
- }
- if(!_img[x1[1]*_width+x1[0]]!=_v)break;
- }
- /*Return the midpoint of the _v segment.*/
- _p[0]=(x0[0]+x1[0]+1<<QR_FINDER_SUBPREC)>>1;
- _p[1]=(x0[1]+x1[1]+1<<QR_FINDER_SUBPREC)>>1;
- return 0;
- }
- static int qr_aff_line_step(const qr_aff *_aff,qr_line _l,
- int _v,int _du,int *_dv){
- int shift;
- int round;
- int dv;
- int n;
- int d;
- n=_aff->fwd[0][_v]*_l[0]+_aff->fwd[1][_v]*_l[1];
- d=_aff->fwd[0][1-_v]*_l[0]+_aff->fwd[1][1-_v]*_l[1];
- if(d<0){
- n=-n;
- d=-d;
- }
- shift=QR_MAXI(0,qr_ilog(_du)+qr_ilog(abs(n))+3-QR_INT_BITS);
- round=(1<<shift)>>1;
- n=n+round>>shift;
- d=d+round>>shift;
- /*The line should not be outside 45 degrees of horizontal/vertical.
- TODO: We impose this restriction to help ensure the loop below terminates,
- but it should not technically be required.
- It also, however, ensures we avoid division by zero.*/
- if(abs(n)>=d)return -1;
- n=-_du*n;
- dv=QR_DIVROUND(n,d);
- if(abs(dv)>=_du)return -1;
- *_dv=dv;
- return 0;
- }
- /*Computes the Hamming distance between two bit patterns (the number of bits
- that differ).
- May stop counting after _maxdiff differences.*/
- static int qr_hamming_dist(unsigned _y1,unsigned _y2,int _maxdiff){
- unsigned y;
- int ret;
- y=_y1^_y2;
- for(ret=0;ret<_maxdiff&&y;ret++)y&=y-1;
- return ret;
- }
- /*Retrieve a bit (guaranteed to be 0 or 1) from the image, given coordinates in
- subpel resolution which have not been bounds checked.*/
- static int qr_img_get_bit(const unsigned char *_img,int _width,int _height,
- int _x,int _y){
- _x>>=QR_FINDER_SUBPREC;
- _y>>=QR_FINDER_SUBPREC;
- return _img[QR_CLAMPI(0,_y,_height-1)*_width+QR_CLAMPI(0,_x,_width-1)]!=0;
- }
- #if defined(QR_DEBUG)
- #include "image.h"
- static void qr_finder_dump_aff_undistorted(qr_finder *_ul,qr_finder *_ur,
- qr_finder *_dl,qr_aff *_aff,const unsigned char *_img,int _width,int _height){
- unsigned char *gimg;
- FILE *fout;
- int lpsz;
- int pixel_size;
- int dim;
- int min;
- int max;
- int u;
- int y;
- int i;
- int j;
- lpsz=qr_ilog(_ur->size[0]+_ur->size[1]+_dl->size[0]+_dl->size[1])-6;
- pixel_size=1<<lpsz;
- dim=(1<<_aff->res-lpsz)+128;
- gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
- for(i=0;i<dim;i++)for(j=0;j<dim;j++){
- qr_point p;
- qr_aff_project(p,_aff,(j-64)<<lpsz,(i-64)<<lpsz);
- gimg[i*dim+j]=_img[
- QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
- QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
- }
- {
- min=(_ur->o[0]-7*_ur->size[0]>>lpsz)+64;
- if(min<0)min=0;
- max=(_ur->o[0]+7*_ur->size[0]>>lpsz)+64;
- if(max>dim)max=dim;
- for(y=-7;y<=7;y++){
- i=(_ur->o[1]+y*_ur->size[1]>>lpsz)+64;
- if(i<0||i>=dim)continue;
- for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
- }
- min=(_ur->o[1]-7*_ur->size[1]>>lpsz)+64;
- if(min<0)min=0;
- max=(_ur->o[1]+7*_ur->size[1]>>lpsz)+64;
- if(max>dim)max=dim;
- for(u=-7;u<=7;u++){
- j=(_ur->o[0]+u*_ur->size[0]>>lpsz)+64;
- if(j<0||j>=dim)continue;
- for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
- }
- }
- {
- min=(_dl->o[0]-7*_dl->size[0]>>lpsz)+64;
- if(min<0)min=0;
- max=(_dl->o[0]+7*_dl->size[0]>>lpsz)+64;
- if(max>dim)max=dim;
- for(y=-7;y<=7;y++){
- i=(_dl->o[1]+y*_dl->size[1]>>lpsz)+64;
- if(i<0||i>=dim)continue;
- for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
- }
- min=(_dl->o[1]-7*_dl->size[1]>>lpsz)+64;
- if(min<0)min=0;
- max=(_dl->o[1]+7*_dl->size[1]>>lpsz)+64;
- if(max>dim)max=dim;
- for(u=-7;u<=7;u++){
- j=(_dl->o[0]+u*_dl->size[0]>>lpsz)+64;
- if(j<0||j>=dim)continue;
- for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
- }
- }
- fout=fopen("undistorted_aff.png","wb");
- image_write_png(gimg,dim,dim,fout);
- fclose(fout);
- free(gimg);
- }
- static void qr_finder_dump_hom_undistorted(qr_finder *_ul,qr_finder *_ur,
- qr_finder *_dl,qr_hom *_hom,const unsigned char *_img,int _width,int _height){
- unsigned char *gimg;
- FILE *fout;
- int lpsz;
- int pixel_size;
- int dim;
- int min;
- int max;
- int u;
- int v;
- int i;
- int j;
- lpsz=qr_ilog(_ur->size[0]+_ur->size[1]+_dl->size[0]+_dl->size[1])-6;
- pixel_size=1<<lpsz;
- dim=(1<<_hom->res-lpsz)+256;
- gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
- for(i=0;i<dim;i++)for(j=0;j<dim;j++){
- qr_point p;
- qr_hom_project(p,_hom,(j-128)<<lpsz,(i-128)<<lpsz);
- gimg[i*dim+j]=_img[
- QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
- QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
- }
- {
- min=(_ur->o[0]-7*_ur->size[0]>>lpsz)+128;
- if(min<0)min=0;
- max=(_ur->o[0]+7*_ur->size[0]>>lpsz)+128;
- if(max>dim)max=dim;
- for(v=-7;v<=7;v++){
- i=(_ur->o[1]+v*_ur->size[1]>>lpsz)+128;
- if(i<0||i>=dim)continue;
- for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
- }
- min=(_ur->o[1]-7*_ur->size[1]>>lpsz)+128;
- if(min<0)min=0;
- max=(_ur->o[1]+7*_ur->size[1]>>lpsz)+128;
- if(max>dim)max=dim;
- for(u=-7;u<=7;u++){
- j=(_ur->o[0]+u*_ur->size[0]>>lpsz)+128;
- if(j<0||j>=dim)continue;
- for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
- }
- }
- {
- min=(_dl->o[0]-7*_dl->size[0]>>lpsz)+128;
- if(min<0)min=0;
- max=(_dl->o[0]+7*_dl->size[0]>>lpsz)+128;
- if(max>dim)max=dim;
- for(v=-7;v<=7;v++){
- i=(_dl->o[1]+v*_dl->size[1]>>lpsz)+128;
- if(i<0||i>=dim)continue;
- for(j=min;j<max;j++)gimg[i*dim+j]=0x7F;
- }
- min=(_dl->o[1]-7*_dl->size[1]>>lpsz)+128;
- if(min<0)min=0;
- max=(_dl->o[1]+7*_dl->size[1]>>lpsz)+128;
- if(max>dim)max=dim;
- for(u=-7;u<=7;u++){
- j=(_dl->o[0]+u*_dl->size[0]>>lpsz)+128;
- if(j<0||j>=dim)continue;
- for(i=min;i<max;i++)gimg[i*dim+j]=0x7F;
- }
- }
- fout=fopen("undistorted_hom.png","wb");
- image_write_png(gimg,dim,dim,fout);
- fclose(fout);
- free(gimg);
- }
- #endif
- /*A homography from one region of the grid back to the image.
- Unlike a qr_hom, this does not include an inverse transform and maps directly
- from the grid points, not a square with power-of-two sides.*/
- struct qr_hom_cell{
- int fwd[3][3];
- int x0;
- int y0;
- int u0;
- int v0;
- };
- static void qr_hom_cell_init(qr_hom_cell *_cell,int _u0,int _v0,
- int _u1,int _v1,int _u2,int _v2,int _u3,int _v3,int _x0,int _y0,
- int _x1,int _y1,int _x2,int _y2,int _x3,int _y3){
- int du10;
- int du20;
- int du30;
- int du31;
- int du32;
- int dv10;
- int dv20;
- int dv30;
- int dv31;
- int dv32;
- int dx10;
- int dx20;
- int dx30;
- int dx31;
- int dx32;
- int dy10;
- int dy20;
- int dy30;
- int dy31;
- int dy32;
- int a00;
- int a01;
- int a02;
- int a10;
- int a11;
- int a12;
- int a20;
- int a21;
- int a22;
- int i00;
- int i01;
- int i10;
- int i11;
- int i20;
- int i21;
- int i22;
- int b0;
- int b1;
- int b2;
- int shift;
- int round;
- int x;
- int y;
- int w;
- /*First, correct for the arrangement of the source points.
- We take advantage of the fact that we know the source points have a very
- limited dynamic range (so there will never be overflow) and a small amount
- of projective distortion.*/
- du10=_u1-_u0;
- du20=_u2-_u0;
- du30=_u3-_u0;
- du31=_u3-_u1;
- du32=_u3-_u2;
- dv10=_v1-_v0;
- dv20=_v2-_v0;
- dv30=_v3-_v0;
- dv31=_v3-_v1;
- dv32=_v3-_v2;
- /*Compute the coefficients of the forward transform from the unit square to
- the source point configuration.*/
- a20=du32*dv10-du10*dv32;
- a21=du20*dv31-du31*dv20;
- if(a20||a21)a22=du32*dv31-du31*dv32;
- /*If the source grid points aren't in a non-affine arrangement, there's no
- reason to scale everything by du32*dv31-du31*dv32.
- Not doing so allows a much larger dynamic range, and is the only way we can
- initialize a base cell that covers the whole grid.*/
- else a22=1;
- a00=du10*(a20+a22);
- a01=du20*(a21+a22);
- a10=dv10*(a20+a22);
- a11=dv20*(a21+a22);
- /*Now compute the inverse transform.*/
- i00=a11*a22;
- i01=-a01*a22;
- i10=-a10*a22;
- i11=a00*a22;
- i20=a10*a21-a11*a20;
- i21=a01*a20-a00*a21;
- i22=a00*a11-a01*a10;
- /*Invert the coefficients.
- Since i22 is the largest, we divide it by all the others.
- The quotient is often exact (e.g., when the source points contain no
- projective distortion), and is never zero.
- Hence we can use zero to signal "infinity" when the divisor is zero.*/
- if(i00)i00=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i00)),i00);
- if(i01)i01=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i01)),i01);
- if(i10)i10=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i10)),i10);
- if(i11)i11=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i11)),i11);
- if(i20)i20=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i20)),i20);
- if(i21)i21=QR_FLIPSIGNI(QR_DIVROUND(i22,abs(i21)),i21);
- /*Now compute the map from the unit square into the image.*/
- dx10=_x1-_x0;
- dx20=_x2-_x0;
- dx30=_x3-_x0;
- dx31=_x3-_x1;
- dx32=_x3-_x2;
- dy10=_y1-_y0;
- dy20=_y2-_y0;
- dy30=_y3-_y0;
- dy31=_y3-_y1;
- dy32=_y3-_y2;
- a20=dx32*dy10-dx10*dy32;
- a21=dx20*dy31-dx31*dy20;
- a22=dx32*dy31-dx31*dy32;
- /*Figure out if we need to downscale anything.*/
- b0=qr_ilog(QR_MAXI(abs(dx10),abs(dy10)))+qr_ilog(abs(a20+a22));
- b1=qr_ilog(QR_MAXI(abs(dx20),abs(dy20)))+qr_ilog(abs(a21+a22));
- b2=qr_ilog(QR_MAXI(QR_MAXI(abs(a20),abs(a21)),abs(a22)));
- shift=QR_MAXI(0,QR_MAXI(QR_MAXI(b0,b1),b2)-(QR_INT_BITS-3-QR_ALIGN_SUBPREC));
- round=(1<<shift)>>1;
- /*Compute the final coefficients of the forward transform.*/
- a00=QR_FIXMUL(dx10,a20+a22,round,shift);
- a01=QR_FIXMUL(dx20,a21+a22,round,shift);
- a10=QR_FIXMUL(dy10,a20+a22,round,shift);
- a11=QR_FIXMUL(dy20,a21+a22,round,shift);
- /*And compose the two transforms.
- Since we inverted the coefficients above, we divide by them here instead
- of multiplying.
- This lets us take advantage of the full dynamic range.
- Note a zero divisor is really "infinity", and thus the quotient should also
- be zero.*/
- _cell->fwd[0][0]=(i00?QR_DIVROUND(a00,i00):0)+(i10?QR_DIVROUND(a01,i10):0);
- _cell->fwd[0][1]=(i01?QR_DIVROUND(a00,i01):0)+(i11?QR_DIVROUND(a01,i11):0);
- _cell->fwd[1][0]=(i00?QR_DIVROUND(a10,i00):0)+(i10?QR_DIVROUND(a11,i10):0);
- _cell->fwd[1][1]=(i01?QR_DIVROUND(a10,i01):0)+(i11?QR_DIVROUND(a11,i11):0);
- _cell->fwd[2][0]=(i00?QR_DIVROUND(a20,i00):0)+(i10?QR_DIVROUND(a21,i10):0)
- +(i20?QR_DIVROUND(a22,i20):0)+round>>shift;
- _cell->fwd[2][1]=(i01?QR_DIVROUND(a20,i01):0)+(i11?QR_DIVROUND(a21,i11):0)
- +(i21?QR_DIVROUND(a22,i21):0)+round>>shift;
- _cell->fwd[2][2]=a22+round>>shift;
- /*Mathematically, a02 and a12 are exactly zero.
- However, that concentrates all of the rounding error in the (_u3,_v3)
- corner; we compute offsets which distribute it over the whole range.*/
- x=_cell->fwd[0][0]*du10+_cell->fwd[0][1]*dv10;
- y=_cell->fwd[1][0]*du10+_cell->fwd[1][1]*dv10;
- w=_cell->fwd[2][0]*du10+_cell->fwd[2][1]*dv10+_cell->fwd[2][2];
- a02=dx10*w-x;
- a12=dy10*w-y;
- x=_cell->fwd[0][0]*du20+_cell->fwd[0][1]*dv20;
- y=_cell->fwd[1][0]*du20+_cell->fwd[1][1]*dv20;
- w=_cell->fwd[2][0]*du20+_cell->fwd[2][1]*dv20+_cell->fwd[2][2];
- a02+=dx20*w-x;
- a12+=dy20*w-y;
- x=_cell->fwd[0][0]*du30+_cell->fwd[0][1]*dv30;
- y=_cell->fwd[1][0]*du30+_cell->fwd[1][1]*dv30;
- w=_cell->fwd[2][0]*du30+_cell->fwd[2][1]*dv30+_cell->fwd[2][2];
- a02+=dx30*w-x;
- a12+=dy30*w-y;
- _cell->fwd[0][2]=a02+2>>2;
- _cell->fwd[1][2]=a12+2>>2;
- _cell->x0=_x0;
- _cell->y0=_y0;
- _cell->u0=_u0;
- _cell->v0=_v0;
- }
- /*Finish a partial projection, converting from homogeneous coordinates to the
- normal 2-D representation.
- In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
- and _w incrementally, but we cannot avoid the divisions, done here.*/
- static void qr_hom_cell_fproject(qr_point _p,const qr_hom_cell *_cell,
- int _x,int _y,int _w){
- if(_w==0){
- _p[0]=_x<0?INT_MIN:INT_MAX;
- _p[1]=_y<0?INT_MIN:INT_MAX;
- }
- else{
- if(_w<0){
- _x=-_x;
- _y=-_y;
- _w=-_w;
- }
- _p[0]=QR_DIVROUND(_x,_w)+_cell->x0;
- _p[1]=QR_DIVROUND(_y,_w)+_cell->y0;
- }
- }
- static void qr_hom_cell_project(qr_point _p,const qr_hom_cell *_cell,
- int _u,int _v,int _res){
- _u-=_cell->u0<<_res;
- _v-=_cell->v0<<_res;
- qr_hom_cell_fproject(_p,_cell,
- _cell->fwd[0][0]*_u+_cell->fwd[0][1]*_v+(_cell->fwd[0][2]<<_res),
- _cell->fwd[1][0]*_u+_cell->fwd[1][1]*_v+(_cell->fwd[1][2]<<_res),
- _cell->fwd[2][0]*_u+_cell->fwd[2][1]*_v+(_cell->fwd[2][2]<<_res));
- }
- /*Retrieves the bits corresponding to the alignment pattern template centered
- at the given location in the original image (at subpel precision).*/
- static unsigned qr_alignment_pattern_fetch(qr_point _p[5][5],int _x0,int _y0,
- const unsigned char *_img,int _width,int _height){
- unsigned v;
- int i;
- int j;
- int k;
- int dx;
- int dy;
- dx=_x0-_p[2][2][0];
- dy=_y0-_p[2][2][1];
- v=0;
- for(k=i=0;i<5;i++)for(j=0;j<5;j++,k++){
- v|=qr_img_get_bit(_img,_width,_height,_p[i][j][0]+dx,_p[i][j][1]+dy)<<k;
- }
- return v;
- }
- /*Searches for an alignment pattern near the given location.*/
- static int qr_alignment_pattern_search(qr_point _p,const qr_hom_cell *_cell,
- int _u,int _v,int _r,const unsigned char *_img,int _width,int _height){
- qr_point c[4];
- int nc[4];
- qr_point p[5][5];
- qr_point pc;
- unsigned best_match;
- int best_dist;
- int bestx;
- int besty;
- unsigned match;
- int dist;
- int u;
- int v;
- int x0;
- int y0;
- int w0;
- int x;
- int y;
- int w;
- int dxdu;
- int dydu;
- int dwdu;
- int dxdv;
- int dydv;
- int dwdv;
- int dx;
- int dy;
- int i;
- int j;
- /*Build up a basic template using _cell to control shape and scale.
- We project the points in the template back to the image just once, since if
- the alignment pattern has moved, we don't really know why.
- If it's because of radial distortion, or the code wasn't flat, or something
- else, there's no reason to expect that a re-projection around each
- subsequent search point would be any closer to the actual shape than our
- first projection.
- Therefore we simply slide this template around, as is.*/
- u=(_u-2)-_cell->u0;
- v=(_v-2)-_cell->v0;
- x0=_cell->fwd[0][0]*u+_cell->fwd[0][1]*v+_cell->fwd[0][2];
- y0=_cell->fwd[1][0]*u+_cell->fwd[1][1]*v+_cell->fwd[1][2];
- w0=_cell->fwd[2][0]*u+_cell->fwd[2][1]*v+_cell->fwd[2][2];
- dxdu=_cell->fwd[0][0];
- dydu=_cell->fwd[1][0];
- dwdu=_cell->fwd[2][0];
- dxdv=_cell->fwd[0][1];
- dydv=_cell->fwd[1][1];
- dwdv=_cell->fwd[2][1];
- for(i=0;i<5;i++){
- x=x0;
- y=y0;
- w=w0;
- for(j=0;j<5;j++){
- qr_hom_cell_fproject(p[i][j],_cell,x,y,w);
- x+=dxdu;
- y+=dydu;
- w+=dwdu;
- }
- x0+=dxdv;
- y0+=dydv;
- w0+=dwdv;
- }
- bestx=p[2][2][0];
- besty=p[2][2][1];
- best_match=qr_alignment_pattern_fetch(p,bestx,besty,_img,_width,_height);
- best_dist=qr_hamming_dist(best_match,0x1F8D63F,25);
- if(best_dist>0){
- u=_u-_cell->u0;
- v=_v-_cell->v0;
- x=_cell->fwd[0][0]*u+_cell->fwd[0][1]*v+_cell->fwd[0][2]<<QR_ALIGN_SUBPREC;
- y=_cell->fwd[1][0]*u+_cell->fwd[1][1]*v+_cell->fwd[1][2]<<QR_ALIGN_SUBPREC;
- w=_cell->fwd[2][0]*u+_cell->fwd[2][1]*v+_cell->fwd[2][2]<<QR_ALIGN_SUBPREC;
- /*Search an area at most _r modules around the target location, in
- concentric squares..*/
- for(i=1;i<_r<<QR_ALIGN_SUBPREC;i++){
- int side_len;
- side_len=(i<<1)-1;
- x-=dxdu+dxdv;
- y-=dydu+dydv;
- w-=dwdu+dwdv;
- for(j=0;j<4*side_len;j++){
- int dir;
- qr_hom_cell_fproject(pc,_cell,x,y,w);
- match=qr_alignment_pattern_fetch(p,pc[0],pc[1],_img,_width,_height);
- dist=qr_hamming_dist(match,0x1F8D63F,best_dist+1);
- if(dist<best_dist){
- best_match=match;
- best_dist=dist;
- bestx=pc[0];
- besty=pc[1];
- }
- if(j<2*side_len){
- dir=j>=side_len;
- x+=_cell->fwd[0][dir];
- y+=_cell->fwd[1][dir];
- w+=_cell->fwd[2][dir];
- }
- else{
- dir=j>=3*side_len;
- x-=_cell->fwd[0][dir];
- y-=_cell->fwd[1][dir];
- w-=_cell->fwd[2][dir];
- }
- if(!best_dist)break;
- }
- if(!best_dist)break;
- }
- }
- /*If the best result we got was sufficiently bad, reject the match.
- If we're wrong and we include it, we can grossly distort the nearby
- region, whereas using the initial starting point should at least be
- consistent with the geometry we already have.*/
- if(best_dist>6){
- _p[0]=p[2][2][0];
- _p[1]=p[2][2][1];
- return -1;
- }
- /*Now try to get a more accurate location of the pattern center.*/
- dx=bestx-p[2][2][0];
- dy=besty-p[2][2][1];
- memset(nc,0,sizeof(nc));
- memset(c,0,sizeof(c));
- /*We consider 8 lines across the finder pattern in turn.
- If we actually found a symmetric pattern along that line, search for its
- exact center in the image.
- There are plenty more lines we could use if these don't work, but if we've
- found anything remotely close to an alignment pattern, we should be able
- to use most of these.*/
- for(i=0;i<8;i++){
- static const unsigned MASK_TESTS[8][2]={
- {0x1040041,0x1000001},{0x0041040,0x0001000},
- {0x0110110,0x0100010},{0x0011100,0x0001000},
- {0x0420084,0x0400004},{0x0021080,0x0001000},
- {0x0006C00,0x0004400},{0x0003800,0x0001000},
- };
- static const unsigned char MASK_COORDS[8][2]={
- {0,0},{1,1},{4,0},{3,1},{2,0},{2,1},{0,2},{1,2}
- };
- if((best_match&MASK_TESTS[i][0])==MASK_TESTS[i][1]){
- int x0;
- int y0;
- int x1;
- int y1;
- x0=p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][0]+dx>>QR_FINDER_SUBPREC;
- if(x0<0||x0>=_width)continue;
- y0=p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][1]+dy>>QR_FINDER_SUBPREC;
- if(y0<0||y0>=_height)continue;
- x1=p[4-MASK_COORDS[i][1]][4-MASK_COORDS[i][0]][0]+dx>>QR_FINDER_SUBPREC;
- if(x1<0||x1>=_width)continue;
- y1=p[4-MASK_COORDS[i][1]][4-MASK_COORDS[i][0]][1]+dy>>QR_FINDER_SUBPREC;
- if(y1<0||y1>=_height)continue;
- if(!qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,i&1,pc)){
- int w;
- int cx;
- int cy;
- cx=pc[0]-bestx;
- cy=pc[1]-besty;
- if(i&1){
- /*Weight crossings around the center dot more highly, as they are
- generally more reliable.*/
- w=3;
- cx+=cx<<1;
- cy+=cy<<1;
- }
- else w=1;
- nc[i>>1]+=w;
- c[i>>1][0]+=cx;
- c[i>>1][1]+=cy;
- }
- }
- }
- /*Sum offsets from lines in orthogonal directions.*/
- for(i=0;i<2;i++){
- int a;
- int b;
- a=nc[i<<1];
- b=nc[i<<1|1];
- if(a&&b){
- int w;
- w=QR_MAXI(a,b);
- c[i<<1][0]=QR_DIVROUND(w*(b*c[i<<1][0]+a*c[i<<1|1][0]),a*b);
- c[i<<1][1]=QR_DIVROUND(w*(b*c[i<<1][1]+a*c[i<<1|1][1]),a*b);
- nc[i<<1]=w<<1;
- }
- else{
- c[i<<1][0]+=c[i<<1|1][0];
- c[i<<1][1]+=c[i<<1|1][1];
- nc[i<<1]+=b;
- }
- }
- /*Average offsets from pairs of orthogonal lines.*/
- c[0][0]+=c[2][0];
- c[0][1]+=c[2][1];
- nc[0]+=nc[2];
- /*If we actually found any such lines, apply the adjustment.*/
- if(nc[0]){
- dx=QR_DIVROUND(c[0][0],nc[0]);
- dy=QR_DIVROUND(c[0][1],nc[0]);
- /*But only if it doesn't make things worse.*/
- match=qr_alignment_pattern_fetch(p,bestx+dx,besty+dy,_img,_width,_height);
- dist=qr_hamming_dist(match,0x1F8D63F,best_dist+1);
- if(dist<=best_dist){
- bestx+=dx;
- besty+=dy;
- }
- }
- _p[0]=bestx;
- _p[1]=besty;
- return 0;
- }
- static int qr_hom_fit(qr_hom *_hom,qr_finder *_ul,qr_finder *_ur,
- qr_finder *_dl,qr_point _p[4],const qr_aff *_aff,isaac_ctx *_isaac,
- const unsigned char *_img,int _width,int _height){
- qr_point *b;
- int nb;
- int cb;
- qr_point *r;
- int nr;
- int cr;
- qr_line l[4];
- qr_point q;
- qr_point p;
- int ox;
- int oy;
- int ru;
- int rv;
- int dru;
- int drv;
- int bu;
- int bv;
- int dbu;
- int dbv;
- int rx;
- int ry;
- int drxi;
- int dryi;
- int drxj;
- int dryj;
- int rdone;
- int nrempty;
- int rlastfit;
- int bx;
- int by;
- int dbxi;
- int dbyi;
- int dbxj;
- int dbyj;
- int bdone;
- int nbempty;
- int blastfit;
- int shift;
- int round;
- int version4;
- int brx;
- int bry;
- int i;
- /*We attempt to correct large-scale perspective distortion by fitting lines
- to the edge of the code area.
- We could also look for an alignment pattern now, but that wouldn't work for
- version 1 codes, which have no alignment pattern.
- Even if the code is supposed to have one, there's go guarantee we'd find it
- intact.*/
- /*Fitting lines is easy for the edges on which we have two finder patterns.
- After the fit, UL is guaranteed to be on the proper side, but if either of
- the other two finder patterns aren't, something is wrong.*/
- qr_finder_ransac(_ul,_aff,_isaac,0);
- qr_finder_ransac(_dl,_aff,_isaac,0);
- qr_line_fit_finder_pair(l[0],_aff,_ul,_dl,0);
- if(qr_line_eval(l[0],_dl->c->pos[0],_dl->c->pos[1])<0||
- qr_line_eval(l[0],_ur->c->pos[0],_ur->c->pos[1])<0){
- return -1;
- }
- qr_finder_ransac(_ul,_aff,_isaac,2);
- qr_finder_ransac(_ur,_aff,_isaac,2);
- qr_line_fit_finder_pair(l[2],_aff,_ul,_ur,2);
- if(qr_line_eval(l[2],_dl->c->pos[0],_dl->c->pos[1])<0||
- qr_line_eval(l[2],_ur->c->pos[0],_ur->c->pos[1])<0){
- return -1;
- }
- /*The edges which only have one finder pattern are more difficult.
- We start by fitting a line to the edge of the one finder pattern we do
- have.
- This can fail due to an insufficient number of sample points, and even if
- it succeeds can be fairly inaccurate, because all of the points are
- clustered in one corner of the QR code.
- If it fails, we just use an axis-aligned line in the affine coordinate
- system.
- Then we walk along the edge of the entire code, looking for
- light:dark:light patterns perpendicular to the edge.
- Wherever we find one, we take the center of the dark portion as an
- additional sample point.
- At the end, we re-fit the line using all such sample points found.*/
- drv=_ur->size[1]>>1;
- qr_finder_ransac(_ur,_aff,_isaac,1);
- if(qr_line_fit_finder_edge(l[1],_ur,1,_aff->res)>=0){
- if(qr_line_eval(l[1],_ul->c->pos[0],_ul->c->pos[1])<0||
- qr_line_eval(l[1],_dl->c->pos[0],_dl->c->pos[1])<0){
- return -1;
- }
- /*Figure out the change in ru for a given change in rv when stepping along
- the fitted line.*/
- if(qr_aff_line_step(_aff,l[1],1,drv,&dru)<0)return -1;
- }
- else dru=0;
- ru=_ur->o[0]+3*_ur->size[0]-2*dru;
- rv=_ur->o[1]-2*drv;
- dbu=_dl->size[0]>>1;
- qr_finder_ransac(_dl,_aff,_isaac,3);
- if(qr_line_fit_finder_edge(l[3],_dl,3,_aff->res)>=0){
- if(qr_line_eval(l[3],_ul->c->pos[0],_ul->c->pos[1])<0||
- qr_line_eval(l[3],_ur->c->pos[0],_ur->c->pos[1])<0){
- return -1;
- }
- /*Figure out the change in bv for a given change in bu when stepping along
- the fitted line.*/
- if(qr_aff_line_step(_aff,l[3],0,dbu,&dbv)<0)return -1;
- }
- else dbv=0;
- bu=_dl->o[0]-2*dbu;
- bv=_dl->o[1]+3*_dl->size[1]-2*dbv;
- /*Set up the initial point lists.*/
- nr=rlastfit=_ur->ninliers[1];
- cr=nr+(_dl->o[1]-rv+drv-1)/drv;
- r=(qr_point *)malloc(cr*sizeof(*r));
- for(i=0;i<_ur->ninliers[1];i++){
- memcpy(r[i],_ur->edge_pts[1][i].pos,sizeof(r[i]));
- }
- nb=blastfit=_dl->ninliers[3];
- cb=nb+(_ur->o[0]-bu+dbu-1)/dbu;
- b=(qr_point *)malloc(cb*sizeof(*b));
- for(i=0;i<_dl->ninliers[3];i++){
- memcpy(b[i],_dl->edge_pts[3][i].pos,sizeof(b[i]));
- }
- /*Set up the step parameters for the affine projection.*/
- ox=(_aff->x0<<_aff->res)+(1<<_aff->res-1);
- oy=(_aff->y0<<_aff->res)+(1<<_aff->res-1);
- rx=_aff->fwd[0][0]*ru+_aff->fwd[0][1]*rv+ox;
- ry=_aff->fwd[1][0]*ru+_aff->fwd[1][1]*rv+oy;
- drxi=_aff->fwd[0][0]*dru+_aff->fwd[0][1]*drv;
- dryi=_aff->fwd[1][0]*dru+_aff->fwd[1][1]*drv;
- drxj=_aff->fwd[0][0]*_ur->size[0];
- dryj=_aff->fwd[1][0]*_ur->size[0];
- bx=_aff->fwd[0][0]*bu+_aff->fwd[0][1]*bv+ox;
- by=_aff->fwd[1][0]*bu+_aff->fwd[1][1]*bv+oy;
- dbxi=_aff->fwd[0][0]*dbu+_aff->fwd[0][1]*dbv;
- dbyi=_aff->fwd[1][0]*dbu+_aff->fwd[1][1]*dbv;
- dbxj=_aff->fwd[0][1]*_dl->size[1];
- dbyj=_aff->fwd[1][1]*_dl->size[1];
- /*Now step along the lines, looking for new sample points.*/
- nrempty=nbempty=0;
- for(;;){
- int ret;
- int x0;
- int y0;
- int x1;
- int y1;
- /*If we take too many steps without encountering a non-zero pixel, assume
- we have wandered off the edge and stop looking before we hit the other
- side of the quiet region.
- Otherwise, stop when the lines cross (if they do so inside the affine
- region) or come close to crossing (outside the affine region).
- TODO: We don't have any way of detecting when we've wandered into the
- code interior; we could stop if the outside sample ever shows up dark,
- but this could happen because of noise in the quiet region, too.*/
- rdone=rv>=QR_MINI(bv,_dl->o[1]+bv>>1)||nrempty>14;
- bdone=bu>=QR_MINI(ru,_ur->o[0]+ru>>1)||nbempty>14;
- if(!rdone&&(bdone||rv<bu)){
- x0=rx+drxj>>_aff->res+QR_FINDER_SUBPREC;
- y0=ry+dryj>>_aff->res+QR_FINDER_SUBPREC;
- x1=rx-drxj>>_aff->res+QR_FINDER_SUBPREC;
- y1=ry-dryj>>_aff->res+QR_FINDER_SUBPREC;
- if(nr>=cr){
- cr=cr<<1|1;
- r=(qr_point *)realloc(r,cr*sizeof(*r));
- }
- ret=qr_finder_quick_crossing_check(_img,_width,_height,x0,y0,x1,y1,1);
- if(!ret){
- ret=qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,1,r[nr]);
- }
- if(ret>=0){
- if(!ret){
- qr_aff_unproject(q,_aff,r[nr][0],r[nr][1]);
- /*Move the current point halfway towards the crossing.
- We don't move the whole way to give us some robustness to noise.*/
- ru=ru+q[0]>>1;
- /*But ensure that rv monotonically increases.*/
- if(q[1]+drv>rv)rv=rv+q[1]>>1;
- rx=_aff->fwd[0][0]*ru+_aff->fwd[0][1]*rv+ox;
- ry=_aff->fwd[1][0]*ru+_aff->fwd[1][1]*rv+oy;
- nr++;
- /*Re-fit the line to update the step direction periodically.*/
- if(nr>QR_MAXI(1,rlastfit+(rlastfit>>2))){
- qr_line_fit_points(l[1],r,nr,_aff->res);
- if(qr_aff_line_step(_aff,l[1],1,drv,&dru)>=0){
- drxi=_aff->fwd[0][0]*dru+_aff->fwd[0][1]*drv;
- dryi=_aff->fwd[1][0]*dru+_aff->fwd[1][1]*drv;
- }
- rlastfit=nr;
- }
- }
- else nrempty=0;
- }
- else nrempty++;
- ru+=dru;
- /*Our final defense: if we overflow, stop.*/
- if(rv+drv>rv)rv+=drv;
- else nrempty=INT_MAX;
- rx+=drxi;
- ry+=dryi;
- }
- else if(!bdone){
- x0=bx+dbxj>>_aff->res+QR_FINDER_SUBPREC;
- y0=by+dbyj>>_aff->res+QR_FINDER_SUBPREC;
- x1=bx-dbxj>>_aff->res+QR_FINDER_SUBPREC;
- y1=by-dbyj>>_aff->res+QR_FINDER_SUBPREC;
- if(nb>=cb){
- cb=cb<<1|1;
- b=(qr_point *)realloc(b,cb*sizeof(*b));
- }
- ret=qr_finder_quick_crossing_check(_img,_width,_height,x0,y0,x1,y1,1);
- if(!ret){
- ret=qr_finder_locate_crossing(_img,_width,_height,x0,y0,x1,y1,1,b[nb]);
- }
- if(ret>=0){
- if(!ret){
- qr_aff_unproject(q,_aff,b[nb][0],b[nb][1]);
- /*Move the current point halfway towards the crossing.
- We don't move the whole way to give us some robustness to noise.*/
- /*But ensure that bu monotonically increases.*/
- if(q[0]+dbu>bu)bu=bu+q[0]>>1;
- bv=bv+q[1]>>1;
- bx=_aff->fwd[0][0]*bu+_aff->fwd[0][1]*bv+ox;
- by=_aff->fwd[1][0]*bu+_aff->fwd[1][1]*bv+oy;
- nb++;
- /*Re-fit the line to update the step direction periodically.*/
- if(nb>QR_MAXI(1,blastfit+(blastfit>>2))){
- qr_line_fit_points(l[3],b,nb,_aff->res);
- if(qr_aff_line_step(_aff,l[3],0,dbu,&dbv)>=0){
- dbxi=_aff->fwd[0][0]*dbu+_aff->fwd[0][1]*dbv;
- dbyi=_aff->fwd[1][0]*dbu+_aff->fwd[1][1]*dbv;
- }
- blastfit=nb;
- }
- }
- nbempty=0;
- }
- else nbempty++;
- /*Our final defense: if we overflow, stop.*/
- if(bu+dbu>bu)bu+=dbu;
- else nbempty=INT_MAX;
- bv+=dbv;
- bx+=dbxi;
- by+=dbyi;
- }
- else break;
- }
- /*Fit the new lines.
- If we _still_ don't have enough sample points, then just use an
- axis-aligned line from the affine coordinate system (e.g., one parallel
- to the opposite edge in the image).*/
- if(nr>1)qr_line_fit_points(l[1],r,nr,_aff->res);
- else{
- qr_aff_project(p,_aff,_ur->o[0]+3*_ur->size[0],_ur->o[1]);
- shift=QR_MAXI(0,
- qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),abs(_aff->fwd[1][1])))
- -(_aff->res+1>>1));
- round=(1<<shift)>>1;
- l[1][0]=_aff->fwd[1][1]+round>>shift;
- l[1][1]=-_aff->fwd[0][1]+round>>shift;
- l[1][2]=-(l[1][0]*p[0]+l[1][1]*p[1]);
- }
- free(r);
- if(nb>1)qr_line_fit_points(l[3],b,nb,_aff->res);
- else{
- qr_aff_project(p,_aff,_dl->o[0],_dl->o[1]+3*_dl->size[1]);
- shift=QR_MAXI(0,
- qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),abs(_aff->fwd[1][1])))
- -(_aff->res+1>>1));
- round=(1<<shift)>>1;
- l[3][0]=_aff->fwd[1][0]+round>>shift;
- l[3][1]=-_aff->fwd[0][0]+round>>shift;
- l[3][2]=-(l[1][0]*p[0]+l[1][1]*p[1]);
- }
- free(b);
- for(i=0;i<4;i++){
- if(qr_line_isect(_p[i],l[i&1],l[2+(i>>1)])<0)return -1;
- /*It's plausible for points to be somewhat outside the image, but too far
- and too much of the pattern will be gone for it to be decodable.*/
- if(_p[i][0]<-_width<<QR_FINDER_SUBPREC||
- _p[i][0]>=_width<<QR_FINDER_SUBPREC+1||
- _p[i][1]<-_height<<QR_FINDER_SUBPREC||
- _p[i][1]>=_height<<QR_FINDER_SUBPREC+1){
- return -1;
- }
- }
- /*By default, use the edge intersection point for the bottom-right corner.*/
- brx=_p[3][0];
- bry=_p[3][1];
- /*However, if our average version estimate is greater than 1, NOW we try to
- search for an alignment pattern.
- We get a much better success rate by doing this after our initial attempt
- to promote the transform to a homography than before.
- You might also think it would be more reliable to use the interior finder
- pattern edges, since the outer ones may be obscured or damaged, and it
- would save us a reprojection below, since they would form a nice square
- with the location of the alignment pattern, but this turns out to be a bad
- idea.
- Non-linear distortion is usually maximal on the outside edge, and thus
- estimating the grid position from points on the interior means we might
- get mis-aligned by the time we reach the edge.*/
- version4=_ul->eversion[0]+_ul->eversion[1]+_ur->eversion[0]+_dl->eversion[1];
- if(version4>4){
- qr_hom_cell cell;
- qr_point p3;
- int dim;
- dim=17+version4;
- qr_hom_cell_init(&cell,0,0,dim-1,0,0,dim-1,dim-1,dim-1,
- _p[0][0],_p[0][1],_p[1][0],_p[1][1],
- _p[2][0],_p[2][1],_p[3][0],_p[3][1]);
- if(qr_alignment_pattern_search(p3,&cell,dim-7,dim-7,4,
- _img,_width,_height)>=0){
- int c21;
- int dx21;
- int dy21;
- int mask;
- int w;
- /*There's no real need to update the bounding box corner, and in fact we
- actively perform worse if we do.
- Clearly it was good enough for us to find this alignment pattern, so
- it should be good enough to use for grid initialization.
- The point of doing the search was to get more accurate version
- estimates and a better chance of decoding the version and format info.
- This is particularly important for small versions that have no encoded
- version info, since any mismatch in version renders the code
- undecodable.*/
- /*We do, however, need four points in a square to initialize our
- homography, so project the point from the alignment center to the
- corner of the code area.*/
- c21=_p[2][0]*_p[1][1]-_p[2][1]*_p[1][0];
- dx21=_p[2][0]-_p[1][0];
- dy21=_p[2][1]-_p[1][1];
- w=(dim-7)*c21
- +(dim-13)*(_p[0][0]*dy21-_p[0][1]*dx21)+6*(p3[0]*dy21-p3[1]*dx21);
- mask=QR_SIGNMASK(w);
- w=abs(w);
- brx=(int)QR_DIVROUND(QR_EXTMUL((dim-7)*_p[0][0],p3[0]*dy21,
- QR_EXTMUL((dim-13)*p3[0],c21-_p[0][1]*dx21,
- QR_EXTMUL(6*_p[0][0],c21-p3[1]*dx21,0)))+mask^mask,w);
- bry=(int)QR_DIVROUND(QR_EXTMUL((dim-7)*_p[0][1],-p3[1]*dx21,
- QR_EXTMUL((dim-13)*p3[1],c21+_p[0][0]*dy21,
- QR_EXTMUL(6*_p[0][1],c21+p3[0]*dy21,0)))+mask^mask,w);
- }
- }
- /*Now we have four points that map to a square: initialize the projection.*/
- qr_hom_init(_hom,_p[0][0],_p[0][1],_p[1][0],_p[1][1],
- _p[2][0],_p[2][1],brx,bry,QR_HOM_BITS);
- return 0;
- }
- /*The BCH(18,6,3) codes are only used for version information, which must lie
- between 7 and 40 (inclusive).*/
- static const unsigned BCH18_6_CODES[34]={
- 0x07C94,
- 0x085BC,0x09A99,0x0A4D3,0x0BBF6,0x0C762,0x0D847,0x0E60D,0x0F928,
- 0x10B78,0x1145D,0x12A17,0x13532,0x149A6,0x15683,0x168C9,0x177EC,
- 0x18EC4,0x191E1,0x1AFAB,0x1B08E,0x1CC1A,0x1D33F,0x1ED75,0x1F250,
- 0x209D5,0x216F0,0x228BA,0x2379F,0x24B0B,0x2542E,0x26A64,0x27541,
- 0x28C69
- };
- /*Corrects a BCH(18,6,3) code word.
- _y: Contains the code word to be checked on input, and the corrected value on
- output.
- Return: The number of errors.
- If more than 3 errors are detected, returns a negative value and
- performs no correction.*/
- static int bch18_6_correct(unsigned *_y){
- unsigned x;
- unsigned y;
- int nerrs;
- y=*_y;
- /*Check the easy case first: see if the data bits were uncorrupted.*/
- x=y>>12;
- if(x>=7&&x<=40){
- nerrs=qr_hamming_dist(y,BCH18_6_CODES[x-7],4);
- if(nerrs<4){
- *_y=BCH18_6_CODES[x-7];
- return nerrs;
- }
- }
- /*Exhaustive search is faster than field operations in GF(19).*/
- for(x=0;x<34;x++)if(x+7!=y>>12){
- nerrs=qr_hamming_dist(y,BCH18_6_CODES[x],4);
- if(nerrs<4){
- *_y=BCH18_6_CODES[x];
- return nerrs;
- }
- }
- return -1;
- }
- #if 0
- static unsigned bch18_6_encode(unsigned _x){
- return (-(_x&1)&0x01F25)^(-(_x>>1&1)&0x0216F)^(-(_x>>2&1)&0x042DE)^
- (-(_x>>3&1)&0x085BC)^(-(_x>>4&1)&0x10B78)^(-(_x>>5&1)&0x209D5);
- }
- #endif
- /*Reads the version bits near a finder module and decodes the version number.*/
- static int qr_finder_version_decode(qr_finder *_f,const qr_hom *_hom,
- const unsigned char *_img,int _width,int _height,int _dir){
- qr_point q;
- unsigned v;
- int x0;
- int y0;
- int w0;
- int dxi;
- int dyi;
- int dwi;
- int dxj;
- int dyj;
- int dwj;
- int ret;
- int i;
- int j;
- int k;
- v=0;
- q[_dir]=_f->o[_dir]-7*_f->size[_dir];
- q[1-_dir]=_f->o[1-_dir]-3*_f->size[1-_dir];
- x0=_hom->fwd[0][0]*q[0]+_hom->fwd[0][1]*q[1];
- y0=_hom->fwd[1][0]*q[0]+_hom->fwd[1][1]*q[1];
- w0=_hom->fwd[2][0]*q[0]+_hom->fwd[2][1]*q[1]+_hom->fwd22;
- dxi=_hom->fwd[0][1-_dir]*_f->size[1-_dir];
- dyi=_hom->fwd[1][1-_dir]*_f->size[1-_dir];
- dwi=_hom->fwd[2][1-_dir]*_f->size[1-_dir];
- dxj=_hom->fwd[0][_dir]*_f->size[_dir];
- dyj=_hom->fwd[1][_dir]*_f->size[_dir];
- dwj=_hom->fwd[2][_dir]*_f->size[_dir];
- for(k=i=0;i<6;i++){
- int x;
- int y;
- int w;
- x=x0;
- y=y0;
- w=w0;
- for(j=0;j<3;j++,k++){
- qr_point p;
- qr_hom_fproject(p,_hom,x,y,w);
- v|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
- x+=dxj;
- y+=dyj;
- w+=dwj;
- }
- x0+=dxi;
- y0+=dyi;
- w0+=dwi;
- }
- ret=bch18_6_correct(&v);
- /*TODO: I'd certainly hope the order the version bits is accessed in is
- well-defined, but I seem to have images for two different codes with the
- same version using two different orders?
- Maybe the other one is a model 1 code?
- Even if I parse the version here, I can't decode the rest of the code.
- If this is really needed, we should just re-order the bits.*/
- #if 0
- if(ret<0){
- /*17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- 0 3 6 9 12 15 1 4 7 10 13 16 2 5 8 11 14 17
- 17 13 9 5 1 -3 10 6 2 -2 -6-10 3 -1 -5 -9-13-17*/
- v=0;
- for(k=i=0;i<3;i++){
- p[_dir]=_f->o[_dir]+_f->size[_dir]*(-5-i);
- for(j=0;j<6;j++,k++){
- qr_point q;
- p[1-_dir]=_f->o[1-_dir]+_f->size[1-_dir]*(2-j);
- qr_hom_project(q,_hom,p[0],p[1]);
- v|=qr_img_get_bit(_img,_width,_height,q[0],q[1])<<k;
- }
- }
- ret=bch18_6_correct(&v);
- }
- #endif
- return ret>=0?(int)(v>>12):ret;
- }
- /*Reads the format info bits near the finder modules and decodes them.*/
- static int qr_finder_fmt_info_decode(qr_finder *_ul,qr_finder *_ur,
- qr_finder *_dl,const qr_hom *_hom,
- const unsigned char *_img,int _width,int _height){
- qr_point p;
- unsigned lo[2];
- unsigned hi[2];
- int u;
- int v;
- int x;
- int y;
- int w;
- int dx;
- int dy;
- int dw;
- int fmt_info[4];
- int count[4];
- int nerrs[4];
- int nfmt_info;
- int besti;
- int imax;
- int di;
- int i;
- int k;
- /*Read the bits around the UL corner.*/
- lo[0]=0;
- u=_ul->o[0]+5*_ul->size[0];
- v=_ul->o[1]-3*_ul->size[1];
- x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
- y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
- w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
- dx=_hom->fwd[0][1]*_ul->size[1];
- dy=_hom->fwd[1][1]*_ul->size[1];
- dw=_hom->fwd[2][1]*_ul->size[1];
- for(k=i=0;;i++){
- /*Skip the timing pattern row.*/
- if(i!=6){
- qr_hom_fproject(p,_hom,x,y,w);
- lo[0]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k++;
- /*Don't advance q in the last iteration... we'll start the next loop from
- the current position.*/
- if(i>=8)break;
- }
- x+=dx;
- y+=dy;
- w+=dw;
- }
- hi[0]=0;
- dx=-_hom->fwd[0][0]*_ul->size[0];
- dy=-_hom->fwd[1][0]*_ul->size[0];
- dw=-_hom->fwd[2][0]*_ul->size[0];
- while(i-->0){
- x+=dx;
- y+=dy;
- w+=dw;
- /*Skip the timing pattern column.*/
- if(i!=6){
- qr_hom_fproject(p,_hom,x,y,w);
- hi[0]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k++;
- }
- }
- /*Read the bits next to the UR corner.*/
- lo[1]=0;
- u=_ur->o[0]+3*_ur->size[0];
- v=_ur->o[1]+5*_ur->size[1];
- x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
- y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
- w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
- dx=-_hom->fwd[0][0]*_ur->size[0];
- dy=-_hom->fwd[1][0]*_ur->size[0];
- dw=-_hom->fwd[2][0]*_ur->size[0];
- for(k=0;k<8;k++){
- qr_hom_fproject(p,_hom,x,y,w);
- lo[1]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
- x+=dx;
- y+=dy;
- w+=dw;
- }
- /*Read the bits next to the DL corner.*/
- hi[1]=0;
- u=_dl->o[0]+5*_dl->size[0];
- v=_dl->o[1]-3*_dl->size[1];
- x=_hom->fwd[0][0]*u+_hom->fwd[0][1]*v;
- y=_hom->fwd[1][0]*u+_hom->fwd[1][1]*v;
- w=_hom->fwd[2][0]*u+_hom->fwd[2][1]*v+_hom->fwd22;
- dx=_hom->fwd[0][1]*_dl->size[1];
- dy=_hom->fwd[1][1]*_dl->size[1];
- dw=_hom->fwd[2][1]*_dl->size[1];
- for(k=8;k<15;k++){
- qr_hom_fproject(p,_hom,x,y,w);
- hi[1]|=qr_img_get_bit(_img,_width,_height,p[0],p[1])<<k;
- x+=dx;
- y+=dy;
- w+=dw;
- }
- /*For the 8th bit we have 3 samples... use the majority value.
- TODO: The DL bit appears to be wrong as much as right? Guess it's not
- really a third copy after all, but doesn't appear to be used for data.
- i=((lo[0]>>7&1)+(lo[1]>>7&1)+(hi[1]>>7&1)>>1)<<7;
- lo[0]=lo[0]&~0x80|i;
- lo[1]=lo[1]&~0x80|i;
- hi[1]&=~0x80;*/
- /*For the remaining bits we have two samples... try them in all
- combinations and pick the most popular valid code, breaking ties using
- the number of bit errors.*/
- imax=2<<(hi[0]!=hi[1]);
- di=1+(lo[0]==lo[1]);
- nfmt_info=0;
- for(i=0;i<imax;i+=di){
- unsigned v;
- int ret;
- int j;
- v=(lo[i&1]|hi[i>>1])^0x5412;
- ret=bch15_5_correct(&v);
- v>>=10;
- if(ret<0)ret=4;
- for(j=0;;j++){
- if(j>=nfmt_info){
- fmt_info[j]=v;
- count[j]=1;
- nerrs[j]=ret;
- nfmt_info++;
- break;
- }
- if(fmt_info[j]==(int)v){
- count[j]++;
- if(ret<nerrs[j])nerrs[j]=ret;
- break;
- }
- }
- }
- besti=0;
- for(i=1;i<nfmt_info;i++){
- if(nerrs[besti]>3&&nerrs[i]<=3||
- count[i]>count[besti]||count[i]==count[besti]&&nerrs[i]<nerrs[besti]){
- besti=i;
- }
- }
- return nerrs[besti]<4?fmt_info[besti]:-1;
- }
- /*The grid used to sample the image bits.
- The grid is divided into separate cells bounded by finder patterns and/or
- alignment patterns, and a separate map back to the original image is
- constructed for each cell.
- All of these structural elements, as well as the timing patterns, version
- info, and format info, are marked in fpmask so they can easily be skipped
- during decode.*/
- struct qr_sampling_grid{
- qr_hom_cell *cells[6];
- unsigned *fpmask;
- int cell_limits[6];
- int ncells;
- };
- /*Mark a given region as belonging to the function pattern.*/
- static void qr_sampling_grid_fp_mask_rect(qr_sampling_grid *_grid,int _dim,
- int _u,int _v,int _w,int _h){
- int i;
- int j;
- int stride;
- stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
- /*Note that we store bits column-wise, since that's how they're read out of
- the grid.*/
- for(j=_u;j<_u+_w;j++)for(i=_v;i<_v+_h;i++){
- _grid->fpmask[j*stride+(i>>QR_INT_LOGBITS)]|=1<<(i&QR_INT_BITS-1);
- }
- }
- /*Determine if a given grid location is inside the function pattern.*/
- static int qr_sampling_grid_is_in_fp(const qr_sampling_grid *_grid,int _dim,
- int _u,int _v){
- return _grid->fpmask[_u*(_dim+QR_INT_BITS-1>>QR_INT_LOGBITS)
- +(_v>>QR_INT_LOGBITS)]>>(_v&QR_INT_BITS-1)&1;
- }
- /*The spacing between alignment patterns after the second for versions >= 7.
- We could compact this more, but the code to access it would eliminate the
- gains.*/
- static const unsigned char QR_ALIGNMENT_SPACING[34]={
- 16,18,20,22,24,26,28,
- 20,22,24,24,26,28,28,
- 22,24,24,26,26,28,28,
- 24,24,26,26,26,28,28,
- 24,26,26,26,28,28
- };
- static inline void qr_svg_points(const char *cls,
- qr_point *p,
- int n)
- {
- svg_path_start(cls, 1, 0, 0);
- int i;
- for(i = 0; i < n; i++, p++)
- svg_path_moveto(SVG_ABS, p[0][0], p[0][1]);
- svg_path_end();
- }
- /*Initialize the sampling grid for each region of the code.
- _version: The (decoded) version number.
- _ul_pos: The location of the UL finder pattern.
- _ur_pos: The location of the UR finder pattern.
- _dl_pos: The location of the DL finder pattern.
- _p: On input, contains estimated positions of the four corner modules.
- On output, contains a bounding quadrilateral for the code.
- _img: The binary input image.
- _width: The width of the input image.
- _height: The height of the input image.
- Return: 0 on success, or a negative value on error.*/
- static void qr_sampling_grid_init(qr_sampling_grid *_grid,int _version,
- const qr_point _ul_pos,const qr_point _ur_pos,const qr_point _dl_pos,
- qr_point _p[4],const unsigned char *_img,int _width,int _height){
- qr_hom_cell base_cell;
- int align_pos[7];
- int dim;
- int nalign;
- int i;
- dim=17+(_version<<2);
- nalign=(_version/7)+2;
- /*Create a base cell to bootstrap the alignment pattern search.*/
- qr_hom_cell_init(&base_cell,0,0,dim-1,0,0,dim-1,dim-1,dim-1,
- _p[0][0],_p[0][1],_p[1][0],_p[1][1],_p[2][0],_p[2][1],_p[3][0],_p[3][1]);
- /*Allocate the array of cells.*/
- _grid->ncells=nalign-1;
- _grid->cells[0]=(qr_hom_cell *)malloc(
- (nalign-1)*(nalign-1)*sizeof(*_grid->cells[0]));
- for(i=1;i<_grid->ncells;i++)_grid->cells[i]=_grid->cells[i-1]+_grid->ncells;
- /*Initialize the function pattern mask.*/
- _grid->fpmask=(unsigned *)calloc(dim,
- (dim+QR_INT_BITS-1>>QR_INT_LOGBITS)*sizeof(*_grid->fpmask));
- /*Mask out the finder patterns (and separators and format info bits).*/
- qr_sampling_grid_fp_mask_rect(_grid,dim,0,0,9,9);
- qr_sampling_grid_fp_mask_rect(_grid,dim,0,dim-8,9,8);
- qr_sampling_grid_fp_mask_rect(_grid,dim,dim-8,0,8,9);
- /*Mask out the version number bits.*/
- if(_version>6){
- qr_sampling_grid_fp_mask_rect(_grid,dim,0,dim-11,6,3);
- qr_sampling_grid_fp_mask_rect(_grid,dim,dim-11,0,3,6);
- }
- /*Mask out the timing patterns.*/
- qr_sampling_grid_fp_mask_rect(_grid,dim,9,6,dim-17,1);
- qr_sampling_grid_fp_mask_rect(_grid,dim,6,9,1,dim-17);
- /*If we have no alignment patterns (e.g., this is a version 1 code), just use
- the base cell and hope it's good enough.*/
- if(_version<2)memcpy(_grid->cells[0],&base_cell,sizeof(base_cell));
- else{
- qr_point *q;
- qr_point *p;
- int j;
- int k;
- q=(qr_point *)malloc(nalign*nalign*sizeof(*q));
- p=(qr_point *)malloc(nalign*nalign*sizeof(*p));
- /*Initialize the alignment pattern position list.*/
- align_pos[0]=6;
- align_pos[nalign-1]=dim-7;
- if(_version>6){
- int d;
- d=QR_ALIGNMENT_SPACING[_version-7];
- for(i=nalign-1;i-->1;)align_pos[i]=align_pos[i+1]-d;
- }
- /*Three of the corners use a finder pattern instead of a separate
- alignment pattern.*/
- q[0][0]=3;
- q[0][1]=3;
- p[0][0]=_ul_pos[0];
- p[0][1]=_ul_pos[1];
- q[nalign-1][0]=dim-4;
- q[nalign-1][1]=3;
- p[nalign-1][0]=_ur_pos[0];
- p[nalign-1][1]=_ur_pos[1];
- q[(nalign-1)*nalign][0]=3;
- q[(nalign-1)*nalign][1]=dim-4;
- p[(nalign-1)*nalign][0]=_dl_pos[0];
- p[(nalign-1)*nalign][1]=_dl_pos[1];
- /*Scan for alignment patterns using a diagonal sweep.*/
- for(k=1;k<2*nalign-1;k++){
- int jmin;
- int jmax;
- jmax=QR_MINI(k,nalign-1)-(k==nalign-1);
- jmin=QR_MAXI(0,k-(nalign-1))+(k==nalign-1);
- for(j=jmin;j<=jmax;j++){
- qr_hom_cell *cell;
- int u;
- int v;
- int k;
- i=jmax-(j-jmin);
- k=i*nalign+j;
- u=align_pos[j];
- v=align_pos[i];
- q[k][0]=u;
- q[k][1]=v;
- /*Mask out the alignment pattern.*/
- qr_sampling_grid_fp_mask_rect(_grid,dim,u-2,v-2,5,5);
- /*Pick a cell to use to govern the alignment pattern search.*/
- if(i>1&&j>1){
- qr_point p0;
- qr_point p1;
- qr_point p2;
- /*Each predictor is basically a straight-line extrapolation from two
- neighboring alignment patterns (except possibly near the opposing
- finder patterns).*/
- qr_hom_cell_project(p0,_grid->cells[i-2]+j-1,u,v,0);
- qr_hom_cell_project(p1,_grid->cells[i-2]+j-2,u,v,0);
- qr_hom_cell_project(p2,_grid->cells[i-1]+j-2,u,v,0);
- /*Take the median of the predictions as the search center.*/
- QR_SORT2I(p0[0],p1[0]);
- QR_SORT2I(p0[1],p1[1]);
- QR_SORT2I(p1[0],p2[0]);
- QR_SORT2I(p1[1],p2[1]);
- QR_SORT2I(p0[0],p1[0]);
- QR_SORT2I(p0[1],p1[1]);
- /*We need a cell that has the target point at a known (u,v) location.
- Since our cells don't have inverses, just construct one from our
- neighboring points.*/
- cell=_grid->cells[i-1]+j-1;
- qr_hom_cell_init(cell,
- q[k-nalign-1][0],q[k-nalign-1][1],q[k-nalign][0],q[k-nalign][1],
- q[k-1][0],q[k-1][1],q[k][0],q[k][1],
- p[k-nalign-1][0],p[k-nalign-1][1],p[k-nalign][0],p[k-nalign][1],
- p[k-1][0],p[k-1][1],p1[0],p1[1]);
- }
- else if(i>1&&j>0)cell=_grid->cells[i-2]+j-1;
- else if(i>0&&j>1)cell=_grid->cells[i-1]+j-2;
- else cell=&base_cell;
- /*Use a very small search radius.
- A large displacement here usually means a false positive (e.g., when
- the real alignment pattern is damaged or missing), which can
- severely distort the projection.*/
- qr_alignment_pattern_search(p[k],cell,u,v,2,_img,_width,_height);
- if(i>0&&j>0){
- qr_hom_cell_init(_grid->cells[i-1]+j-1,
- q[k-nalign-1][0],q[k-nalign-1][1],q[k-nalign][0],q[k-nalign][1],
- q[k-1][0],q[k-1][1],q[k][0],q[k][1],
- p[k-nalign-1][0],p[k-nalign-1][1],p[k-nalign][0],p[k-nalign][1],
- p[k-1][0],p[k-1][1],p[k][0],p[k][1]);
- }
- }
- }
- qr_svg_points("align", p, nalign * nalign);
- free(q);
- free(p);
- }
- /*Set the limits over which each cell is used.*/
- memcpy(_grid->cell_limits,align_pos+1,
- (_grid->ncells-1)*sizeof(*_grid->cell_limits));
- _grid->cell_limits[_grid->ncells-1]=dim;
- /*Produce a bounding square for the code (to mark finder centers with).
- Because of non-linear distortion, this might not actually bound the code,
- but it should be good enough.
- I don't think it's worth computing a convex hull or anything silly like
- that.*/
- qr_hom_cell_project(_p[0],_grid->cells[0]+0,-1,-1,1);
- qr_hom_cell_project(_p[1],_grid->cells[0]+_grid->ncells-1,(dim<<1)-1,-1,1);
- qr_hom_cell_project(_p[2],_grid->cells[_grid->ncells-1]+0,-1,(dim<<1)-1,1);
- qr_hom_cell_project(_p[3],_grid->cells[_grid->ncells-1]+_grid->ncells-1,
- (dim<<1)-1,(dim<<1)-1,1);
- /*Clamp the points somewhere near the image (this is really just in case a
- corner is near the plane at infinity).*/
- for(i=0;i<4;i++){
- _p[i][0]=QR_CLAMPI(-_width<<QR_FINDER_SUBPREC,_p[i][0],
- _width<<QR_FINDER_SUBPREC+1);
- _p[i][1]=QR_CLAMPI(-_height<<QR_FINDER_SUBPREC,_p[i][1],
- _height<<QR_FINDER_SUBPREC+1);
- }
- /*TODO: Make fine adjustments using the timing patterns.
- Possible strategy: scan the timing pattern at QR_ALIGN_SUBPREC (or finer)
- resolution, use dynamic programming to match midpoints between
- transitions to the ideal grid locations.*/
- }
- static void qr_sampling_grid_clear(qr_sampling_grid *_grid){
- free(_grid->fpmask);
- free(_grid->cells[0]);
- }
- #if defined(QR_DEBUG)
- static void qr_sampling_grid_dump(qr_sampling_grid *_grid,int _version,
- const unsigned char *_img,int _width,int _height){
- unsigned char *gimg;
- FILE *fout;
- int dim;
- int u;
- int v;
- int x;
- int y;
- int w;
- int i;
- int j;
- int r;
- int s;
- dim=17+(_version<<2)+8<<QR_ALIGN_SUBPREC;
- gimg=(unsigned char *)malloc(dim*dim*sizeof(*gimg));
- for(i=0;i<dim;i++)for(j=0;j<dim;j++){
- qr_hom_cell *cell;
- if(i>=(4<<QR_ALIGN_SUBPREC)&&i<=dim-(5<<QR_ALIGN_SUBPREC)&&
- j>=(4<<QR_ALIGN_SUBPREC)&&j<=dim-(5<<QR_ALIGN_SUBPREC)&&
- ((!(i&(1<<QR_ALIGN_SUBPREC)-1))^(!(j&(1<<QR_ALIGN_SUBPREC)-1)))){
- gimg[i*dim+j]=0x7F;
- }
- else{
- qr_point p;
- u=(j>>QR_ALIGN_SUBPREC)-4;
- v=(i>>QR_ALIGN_SUBPREC)-4;
- for(r=0;r<_grid->ncells-1;r++)if(u<_grid->cell_limits[r])break;
- for(s=0;s<_grid->ncells-1;s++)if(v<_grid->cell_limits[s])break;
- cell=_grid->cells[s]+r;
- u=j-(cell->u0+4<<QR_ALIGN_SUBPREC);
- v=i-(cell->v0+4<<QR_ALIGN_SUBPREC);
- x=cell->fwd[0][0]*u+cell->fwd[0][1]*v+(cell->fwd[0][2]<<QR_ALIGN_SUBPREC);
- y=cell->fwd[1][0]*u+cell->fwd[1][1]*v+(cell->fwd[1][2]<<QR_ALIGN_SUBPREC);
- w=cell->fwd[2][0]*u+cell->fwd[2][1]*v+(cell->fwd[2][2]<<QR_ALIGN_SUBPREC);
- qr_hom_cell_fproject(p,cell,x,y,w);
- gimg[i*dim+j]=_img[
- QR_CLAMPI(0,p[1]>>QR_FINDER_SUBPREC,_height-1)*_width+
- QR_CLAMPI(0,p[0]>>QR_FINDER_SUBPREC,_width-1)];
- }
- }
- for(v=0;v<17+(_version<<2);v++)for(u=0;u<17+(_version<<2);u++){
- if(qr_sampling_grid_is_in_fp(_grid,17+(_version<<2),u,v)){
- j=u+4<<QR_ALIGN_SUBPREC;
- i=v+4<<QR_ALIGN_SUBPREC;
- gimg[(i-1)*dim+j-1]=0x7F;
- gimg[(i-1)*dim+j]=0x7F;
- gimg[(i-1)*dim+j+1]=0x7F;
- gimg[i*dim+j-1]=0x7F;
- gimg[i*dim+j+1]=0x7F;
- gimg[(i+1)*dim+j-1]=0x7F;
- gimg[(i+1)*dim+j]=0x7F;
- gimg[(i+1)*dim+j+1]=0x7F;
- }
- }
- fout=fopen("grid.png","wb");
- image_write_png(gimg,dim,dim,fout);
- fclose(fout);
- free(gimg);
- }
- #endif
- /*Generate the data mask corresponding to the given mask pattern.*/
- static void qr_data_mask_fill(unsigned *_mask,int _dim,int _pattern){
- int stride;
- int i;
- int j;
- stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
- /*Note that we store bits column-wise, since that's how they're read out of
- the grid.*/
- switch(_pattern){
- /*10101010 i+j+1&1
- 01010101
- 10101010
- 01010101*/
- case 0:{
- int m;
- m=0x55;
- for(j=0;j<_dim;j++){
- memset(_mask+j*stride,m,stride*sizeof(*_mask));
- m^=0xFF;
- }
- }break;
- /*11111111 i+1&1
- 00000000
- 11111111
- 00000000*/
- case 1:memset(_mask,0x55,_dim*stride*sizeof(*_mask));break;
- /*10010010 (j+1)%3&1
- 10010010
- 10010010
- 10010010*/
- case 2:{
- unsigned m;
- m=0xFF;
- for(j=0;j<_dim;j++){
- memset(_mask+j*stride,m&0xFF,stride*sizeof(*_mask));
- m=m<<8|m>>16;
- }
- }break;
- /*10010010 (i+j+1)%3&1
- 00100100
- 01001001
- 10010010*/
- case 3:{
- unsigned mi;
- unsigned mj;
- mj=0;
- for(i=0;i<(QR_INT_BITS+2)/3;i++)mj|=1<<3*i;
- for(j=0;j<_dim;j++){
- mi=mj;
- for(i=0;i<stride;i++){
- _mask[j*stride+i]=mi;
- mi=mi>>QR_INT_BITS%3|mi<<3-QR_INT_BITS%3;
- }
- mj=mj>>1|mj<<2;
- }
- }break;
- /*11100011 (i>>1)+(j/3)+1&1
- 11100011
- 00011100
- 00011100*/
- case 4:{
- unsigned m;
- m=7;
- for(j=0;j<_dim;j++){
- memset(_mask+j*stride,(0xCC^-(m&1))&0xFF,stride*sizeof(*_mask));
- m=m>>1|m<<5;
- }
- }break;
- /*11111111 !((i*j)%6)
- 10000010
- 10010010
- 10101010*/
- case 5:{
- for(j=0;j<_dim;j++){
- unsigned m;
- m=0;
- for(i=0;i<6;i++)m|=!((i*j)%6)<<i;
- for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
- for(i=0;i<stride;i++){
- _mask[j*stride+i]=m;
- m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
- }
- }
- }break;
- /*11111111 (i*j)%3+i*j+1&1
- 11100011
- 11011011
- 10101010*/
- case 6:{
- for(j=0;j<_dim;j++){
- unsigned m;
- m=0;
- for(i=0;i<6;i++)m|=((i*j)%3+i*j+1&1)<<i;
- for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
- for(i=0;i<stride;i++){
- _mask[j*stride+i]=m;
- m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
- }
- }
- }break;
- /*10101010 (i*j)%3+i+j+1&1
- 00011100
- 10001110
- 01010101*/
- default:{
- for(j=0;j<_dim;j++){
- unsigned m;
- m=0;
- for(i=0;i<6;i++)m|=((i*j)%3+i+j+1&1)<<i;
- for(i=6;i<QR_INT_BITS;i<<=1)m|=m<<i;
- for(i=0;i<stride;i++){
- _mask[j*stride+i]=m;
- m=m>>QR_INT_BITS%6|m<<6-QR_INT_BITS%6;
- }
- }
- }break;
- }
- }
- static void qr_sampling_grid_sample(const qr_sampling_grid *_grid,
- unsigned *_data_bits,int _dim,int _fmt_info,
- const unsigned char *_img,int _width,int _height){
- int stride;
- int u0;
- int u1;
- int j;
- /*We initialize the buffer with the data mask and XOR bits into it as we read
- them out of the image instead of unmasking in a separate step.*/
- qr_data_mask_fill(_data_bits,_dim,_fmt_info&7);
- stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
- u0=0;
- svg_path_start("sampling-grid", 1, 0, 0);
- /*We read data cell-by-cell to avoid having to constantly change which
- projection we're using as we read each bit.
- This (and the position-dependent data mask) is the reason we buffer the
- bits we read instead of converting them directly to codewords here.
- Note that bits are stored column-wise, since that's how we'll scan them.*/
- for(j=0;j<_grid->ncells;j++){
- int i;
- int v0;
- int v1;
- u1=_grid->cell_limits[j];
- v0=0;
- for(i=0;i<_grid->ncells;i++){
- qr_hom_cell *cell;
- int x0;
- int y0;
- int w0;
- int u;
- int du;
- int dv;
- v1=_grid->cell_limits[i];
- cell=_grid->cells[i]+j;
- du=u0-cell->u0;
- dv=v0-cell->v0;
- x0=cell->fwd[0][0]*du+cell->fwd[0][1]*dv+cell->fwd[0][2];
- y0=cell->fwd[1][0]*du+cell->fwd[1][1]*dv+cell->fwd[1][2];
- w0=cell->fwd[2][0]*du+cell->fwd[2][1]*dv+cell->fwd[2][2];
- for(u=u0;u<u1;u++){
- int x;
- int y;
- int w;
- int v;
- x=x0;
- y=y0;
- w=w0;
- for(v=v0;v<v1;v++){
- /*Skip doing all the divisions and bounds checks if the bit is in the
- function pattern.*/
- if(!qr_sampling_grid_is_in_fp(_grid,_dim,u,v)){
- qr_point p;
- qr_hom_cell_fproject(p,cell,x,y,w);
- _data_bits[u*stride+(v>>QR_INT_LOGBITS)]^=
- qr_img_get_bit(_img,_width,_height,p[0],p[1])<<(v&QR_INT_BITS-1);
- svg_path_moveto(SVG_ABS, p[0], p[1]);
- }
- x+=cell->fwd[0][1];
- y+=cell->fwd[1][1];
- w+=cell->fwd[2][1];
- }
- x0+=cell->fwd[0][0];
- y0+=cell->fwd[1][0];
- w0+=cell->fwd[2][0];
- }
- v0=v1;
- }
- u0=u1;
- }
- svg_path_end();
- }
- /*Arranges the sample bits read by qr_sampling_grid_sample() into bytes and
- groups those bytes into Reed-Solomon blocks.
- The individual block pointers are destroyed by this routine.*/
- static void qr_samples_unpack(unsigned char **_blocks,int _nblocks,
- int _nshort_data,int _nshort_blocks,const unsigned *_data_bits,
- const unsigned *_fp_mask,int _dim){
- unsigned bits;
- int biti;
- int stride;
- int blocki;
- int blockj;
- int i;
- int j;
- stride=_dim+QR_INT_BITS-1>>QR_INT_LOGBITS;
- /*If _all_ the blocks are short, don't skip anything (see below).*/
- if(_nshort_blocks>=_nblocks)_nshort_blocks=0;
- /*Scan columns in pairs from right to left.*/
- bits=0;
- for(blocki=blockj=biti=0,j=_dim-1;j>0;j-=2){
- unsigned data1;
- unsigned data2;
- unsigned fp_mask1;
- unsigned fp_mask2;
- int nbits;
- int l;
- /*Scan up a pair of columns.*/
- nbits=(_dim-1&QR_INT_BITS-1)+1;
- l=j*stride;
- for(i=stride;i-->0;){
- data1=_data_bits[l+i];
- fp_mask1=_fp_mask[l+i];
- data2=_data_bits[l+i-stride];
- fp_mask2=_fp_mask[l+i-stride];
- while(nbits-->0){
- /*Pull a bit from the right column.*/
- if(!(fp_mask1>>nbits&1)){
- bits=bits<<1|data1>>nbits&1;
- biti++;
- }
- /*Pull a bit from the left column.*/
- if(!(fp_mask2>>nbits&1)){
- bits=bits<<1|data2>>nbits&1;
- biti++;
- }
- /*If we finished a byte, drop it in a block.*/
- if(biti>=8){
- biti-=8;
- *_blocks[blocki++]++=(unsigned char)(bits>>biti);
- /*For whatever reason, the long blocks are at the _end_ of the list,
- instead of the beginning.
- Even worse, the extra bytes they get come at the end of the data
- bytes, before the parity bytes.
- Hence the logic here: when we've filled up the data portion of the
- short blocks, skip directly to the long blocks for the next byte.
- It's also the reason we increment _blocks[blocki] on each store,
- instead of just indexing with blockj (after this iteration the
- number of bytes in each block differs).*/
- if(blocki>=_nblocks)blocki=++blockj==_nshort_data?_nshort_blocks:0;
- }
- }
- nbits=QR_INT_BITS;
- }
- j-=2;
- /*Skip the column with the vertical timing pattern.*/
- if(j==6)j--;
- /*Scan down a pair of columns.*/
- l=j*stride;
- for(i=0;i<stride;i++){
- data1=_data_bits[l+i];
- fp_mask1=_fp_mask[l+i];
- data2=_data_bits[l+i-stride];
- fp_mask2=_fp_mask[l+i-stride];
- nbits=QR_MINI(_dim-(i<<QR_INT_LOGBITS),QR_INT_BITS);
- while(nbits-->0){
- /*Pull a bit from the right column.*/
- if(!(fp_mask1&1)){
- bits=bits<<1|data1&1;
- biti++;
- }
- data1>>=1;
- fp_mask1>>=1;
- /*Pull a bit from the left column.*/
- if(!(fp_mask2&1)){
- bits=bits<<1|data2&1;
- biti++;
- }
- data2>>=1;
- fp_mask2>>=1;
- /*If we finished a byte, drop it in a block.*/
- if(biti>=8){
- biti-=8;
- *_blocks[blocki++]++=(unsigned char)(bits>>biti);
- /*See comments on the "up" loop for the reason behind this mess.*/
- if(blocki>=_nblocks)blocki=++blockj==_nshort_data?_nshort_blocks:0;
- }
- }
- }
- }
- }
- /*Bit reading code blatantly stolen^W^Wadapted from libogg/libtheora (because
- I've already debugged it and I know it works).
- Portions (C) Xiph.Org Foundation 1994-2008, BSD-style license.*/
- struct qr_pack_buf{
- const unsigned char *buf;
- int endbyte;
- int endbit;
- int storage;
- };
- static void qr_pack_buf_init(qr_pack_buf *_b,
- const unsigned char *_data,int _ndata){
- _b->buf=_data;
- _b->storage=_ndata;
- _b->endbyte=_b->endbit=0;
- }
- /*Assumes 0<=_bits<=16.*/
- static int qr_pack_buf_read(qr_pack_buf *_b,int _bits){
- const unsigned char *p;
- unsigned ret;
- int m;
- int d;
- m=16-_bits;
- _bits+=_b->endbit;
- d=_b->storage-_b->endbyte;
- if(d<=2){
- /*Not the main path.*/
- if(d*8<_bits){
- _b->endbyte+=_bits>>3;
- _b->endbit=_bits&7;
- return -1;
- }
- /*Special case to avoid reading p[0] below, which might be past the end of
- the buffer; also skips some useless accounting.*/
- else if(!_bits)return 0;
- }
- p=_b->buf+_b->endbyte;
- ret=p[0]<<8+_b->endbit;
- if(_bits>8){
- ret|=p[1]<<_b->endbit;
- if(_bits>16)ret|=p[2]>>8-_b->endbit;
- }
- _b->endbyte+=_bits>>3;
- _b->endbit=_bits&7;
- return (ret&0xFFFF)>>m;
- }
- static int qr_pack_buf_avail(const qr_pack_buf *_b){
- return (_b->storage-_b->endbyte<<3)-_b->endbit;
- }
- /*The characters available in QR_MODE_ALNUM.*/
- static const unsigned char QR_ALNUM_TABLE[45]={
- '0','1','2','3','4','5','6','7','8','9',
- 'A','B','C','D','E','F','G','H','I','J',
- 'K','L','M','N','O','P','Q','R','S','T',
- 'U','V','W','X','Y','Z',' ','$','%','*',
- '+','-','.','/',':'
- };
- static int qr_code_data_parse(qr_code_data *_qrdata,int _version,
- const unsigned char *_data,int _ndata){
- qr_pack_buf qpb;
- int centries;
- int len_bits_idx;
- /*Entries are stored directly in the struct during parsing.
- Caller cleans up any allocated data on failure.*/
- _qrdata->entries=NULL;
- _qrdata->nentries=0;
- _qrdata->sa_size=0;
- centries=0;
- /*The versions are divided into 3 ranges that each use a different number of
- bits for length fields.*/
- len_bits_idx=(_version>9)+(_version>26);
- qr_pack_buf_init(&qpb,_data,_ndata);
- /*While we have enough bits to read a mode...*/
- while(qr_pack_buf_avail(&qpb)>=4){
- qr_code_data_entry *entry;
- int mode;
- mode=qr_pack_buf_read(&qpb,4);
- /*Mode 0 is a terminator.*/
- if(!mode)break;
- if(_qrdata->nentries>=centries){
- centries=centries<<1|1;
- _qrdata->entries=(qr_code_data_entry *)realloc(_qrdata->entries,
- centries*sizeof(*_qrdata->entries));
- }
- entry=_qrdata->entries+_qrdata->nentries++;
- /*Set the mode to an invalid value until we allocate a buffer for it.
- This ensures we don't try to free it on clean-up until then.*/
- entry->mode=-1;
- switch(mode){
- /*The number of bits used to encode the character count for each version
- range and each data mode.*/
- static const unsigned char LEN_BITS[3][4]={
- {10, 9, 8, 8},
- {12,11,16,10},
- {14,13,16,12}
- };
- case QR_MODE_NUM:{
- unsigned char *buf;
- unsigned bits;
- int len;
- int count;
- int rem;
- len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][0]);
- if(len<0)return -1;
- /*Check to see if there are enough bits left now, so we don't have to
- in the decode loop.*/
- count=len/3;
- rem=len%3;
- if(qr_pack_buf_avail(&qpb)<10*count+7*(rem>>1&1)+4*(rem&1))return -1;
- entry->mode=mode;
- entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
- entry->payload.data.len=len;
- /*Read groups of 3 digits encoded in 10 bits.*/
- while(count-->0){
- bits=qr_pack_buf_read(&qpb,10);
- if(bits>=1000)return -1;
- *buf++=(unsigned char)('0'+bits/100);
- bits%=100;
- *buf++=(unsigned char)('0'+bits/10);
- *buf++=(unsigned char)('0'+bits%10);
- }
- /*Read the last two digits encoded in 7 bits.*/
- if(rem>1){
- bits=qr_pack_buf_read(&qpb,7);
- if(bits>=100)return -1;
- *buf++=(unsigned char)('0'+bits/10);
- *buf++=(unsigned char)('0'+bits%10);
- }
- /*Or the last one digit encoded in 4 bits.*/
- else if(rem){
- bits=qr_pack_buf_read(&qpb,4);
- if(bits>=10)return -1;
- *buf++=(unsigned char)('0'+bits);
- }
- }break;
- case QR_MODE_ALNUM:{
- unsigned char *buf;
- unsigned bits;
- int len;
- int count;
- int rem;
- len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][1]);
- if(len<0)return -1;
- /*Check to see if there are enough bits left now, so we don't have to
- in the decode loop.*/
- count=len>>1;
- rem=len&1;
- if(qr_pack_buf_avail(&qpb)<11*count+6*rem)return -1;
- entry->mode=mode;
- entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
- entry->payload.data.len=len;
- /*Read groups of two characters encoded in 11 bits.*/
- while(count-->0){
- bits=qr_pack_buf_read(&qpb,11);
- if(bits>=2025)return -1;
- *buf++=QR_ALNUM_TABLE[bits/45];
- *buf++=QR_ALNUM_TABLE[bits%45];
- len-=2;
- }
- /*Read the last character encoded in 6 bits.*/
- if(rem){
- bits=qr_pack_buf_read(&qpb,6);
- if(bits>=45)return -1;
- *buf++=QR_ALNUM_TABLE[bits];
- }
- }break;
- /*Structured-append header.*/
- case QR_MODE_STRUCT:{
- int bits;
- entry->mode=mode;
- bits=qr_pack_buf_read(&qpb,16);
- if(bits<0)return -1;
- /*We also save a copy of the data in _qrdata for easy reference when
- grouping structured-append codes.
- If for some reason the code has multiple S-A headers, last one wins
- (TODO: should we return an error instead?).*/
- _qrdata->sa_index=entry->payload.sa.sa_index=
- (unsigned char)(bits>>12&0xF);
- _qrdata->sa_size=entry->payload.sa.sa_size=
- (unsigned char)((bits>>8&0xF)+1);
- _qrdata->sa_parity=entry->payload.sa.sa_parity=
- (unsigned char)(bits&0xFF);
- }break;
- case QR_MODE_BYTE:{
- unsigned char *buf;
- int len;
- len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][2]);
- if(len<0)return -1;
- /*Check to see if there are enough bits left now, so we don't have to
- in the decode loop.*/
- if(qr_pack_buf_avail(&qpb)<len<<3)return -1;
- entry->mode=mode;
- entry->payload.data.buf=buf=(unsigned char *)malloc(len*sizeof(*buf));
- entry->payload.data.len=len;
- while(len-->0)*buf++=(unsigned char)qr_pack_buf_read(&qpb,8);
- }break;
- /*FNC1 first position marker.*/
- case QR_MODE_FNC1_1ST:entry->mode=mode;break;
- /*Extended Channel Interpretation data.*/
- case QR_MODE_ECI:{
- unsigned val;
- int bits;
- /*ECI uses a variable-width encoding similar to UTF-8*/
- bits=qr_pack_buf_read(&qpb,8);
- if(bits<0)return -1;
- /*One byte:*/
- if(!(bits&0x80))val=bits;
- /*Two bytes:*/
- else if(!(bits&0x40)){
- val=bits&0x3F<<8;
- bits=qr_pack_buf_read(&qpb,8);
- if(bits<0)return -1;
- val|=bits;
- }
- /*Three bytes:*/
- else if(!(bits&0x20)){
- val=bits&0x1F<<16;
- bits=qr_pack_buf_read(&qpb,16);
- if(bits<0)return -1;
- val|=bits;
- /*Valid ECI values are 0...999999.*/
- if(val>=1000000)return -1;
- }
- /*Invalid lead byte.*/
- else return -1;
- entry->mode=mode;
- entry->payload.eci=val;
- }break;
- case QR_MODE_KANJI:{
- unsigned char *buf;
- unsigned bits;
- int len;
- len=qr_pack_buf_read(&qpb,LEN_BITS[len_bits_idx][3]);
- if(len<0)return -1;
- /*Check to see if there are enough bits left now, so we don't have to
- in the decode loop.*/
- if(qr_pack_buf_avail(&qpb)<13*len)return -1;
- entry->mode=mode;
- entry->payload.data.buf=buf=(unsigned char *)malloc(2*len*sizeof(*buf));
- entry->payload.data.len=2*len;
- /*Decode 2-byte SJIS characters encoded in 13 bits.*/
- while(len-->0){
- bits=qr_pack_buf_read(&qpb,13);
- bits=(bits/0xC0<<8|bits%0xC0)+0x8140;
- if(bits>=0xA000)bits+=0x4000;
- /*Are values 0xXX7F, 0xXXFD...0xXXFF always invalid?
- Should we reject them here?*/
- *buf++=(unsigned char)(bits>>8);
- *buf++=(unsigned char)(bits&0xFF);
- }
- }break;
- /*FNC1 second position marker.*/
- case QR_MODE_FNC1_2ND:entry->mode=mode;break;
- /*Unknown mode number:*/
- default:{
- /*Unfortunately, because we have to understand the format of a mode to
- know how many bits it occupies, we can't skip unknown modes.
- Therefore we have to fail.*/
- return -1;
- }break;
- }
- }
- /*TODO: If there was a S-A header, we should compute the parity of this
- code; how are non-data modes handled (ECI, FNC1)?*/
- _qrdata->self_parity=0;
- /*Success.*/
- _qrdata->entries=(qr_code_data_entry *)realloc(_qrdata->entries,
- _qrdata->nentries*sizeof(*_qrdata->entries));
- return 0;
- }
- static void qr_code_data_clear(qr_code_data *_qrdata){
- int i;
- for(i=0;i<_qrdata->nentries;i++){
- if(QR_MODE_HAS_DATA(_qrdata->entries[i].mode)){
- free(_qrdata->entries[i].payload.data.buf);
- }
- }
- free(_qrdata->entries);
- }
- void qr_code_data_list_init(qr_code_data_list *_qrlist){
- _qrlist->qrdata=NULL;
- _qrlist->nqrdata=_qrlist->cqrdata=0;
- }
- void qr_code_data_list_clear(qr_code_data_list *_qrlist){
- int i;
- for(i=0;i<_qrlist->nqrdata;i++)qr_code_data_clear(_qrlist->qrdata+i);
- free(_qrlist->qrdata);
- qr_code_data_list_init(_qrlist);
- }
- static void qr_code_data_list_add(qr_code_data_list *_qrlist,
- qr_code_data *_qrdata){
- if(_qrlist->nqrdata>=_qrlist->cqrdata){
- _qrlist->cqrdata=_qrlist->cqrdata<<1|1;
- _qrlist->qrdata=(qr_code_data *)realloc(_qrlist->qrdata,
- _qrlist->cqrdata*sizeof(*_qrlist->qrdata));
- }
- memcpy(_qrlist->qrdata+_qrlist->nqrdata++,_qrdata,sizeof(*_qrdata));
- }
- #if 0
- static const unsigned short QR_NCODEWORDS[40]={
- 26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
- 404, 466, 532, 581, 655, 733, 815, 901, 991,1085,
- 1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,
- 2323,2465,2611,2761,2876,3034,3196,3362,3532,3706
- };
- #endif
- /*The total number of codewords in a QR code.*/
- static int qr_code_ncodewords(unsigned _version){
- unsigned nalign;
- /*This is 24-27 instructions on ARM in thumb mode, or a 26-32 byte savings
- over just using a table (not counting the instructions that would be
- needed to do the table lookup).*/
- if(_version==1)return 26;
- nalign=(_version/7)+2;
- return (_version<<4)*(_version+8)
- -(5*nalign)*(5*nalign-2)+36*(_version<7)+83>>3;
- }
- #if 0
- /*The number of parity bytes per Reed-Solomon block for each version and error
- correction level.*/
- static const unsigned char QR_RS_NPAR[40][4]={
- { 7,10,13,17},{10,16,22,28},{15,26,18,22},{20,18,26,16},
- {26,24,18,22},{18,16,24,28},{20,18,18,26},{24,22,22,26},
- {30,22,20,24},{18,26,24,28},{20,30,28,24},{24,22,26,28},
- {26,22,24,22},{30,24,20,24},{22,24,30,24},{24,28,24,30},
- {28,28,28,28},{30,26,28,28},{28,26,26,26},{28,26,30,28},
- {28,26,28,30},{28,28,30,24},{30,28,30,30},{30,28,30,30},
- {26,28,30,30},{28,28,28,30},{30,28,30,30},{30,28,30,30},
- {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
- {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
- {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30}
- };
- #endif
- /*Bulk data for the number of parity bytes per Reed-Solomon block.*/
- static const unsigned char QR_RS_NPAR_VALS[71]={
- /*[ 0]*/ 7,10,13,17,
- /*[ 4]*/10,16,22, 28,26,26, 26,22, 24,22,22, 26,24,18,22,
- /*[19]*/15,26,18, 22,24, 30,24,20,24,
- /*[28]*/18,16,24, 28, 28, 28,28,30,24,
- /*[37]*/20,18, 18,26, 24,28,24, 30,26,28, 28, 26,28,30, 30,22,20,24,
- /*[55]*/20,18,26,16,
- /*[59]*/20,30,28, 24,22,26, 28,26, 30,28,30,30
- };
- /*An offset into QR_RS_NPAR_DATA for each version that gives the number of
- parity bytes per Reed-Solomon block for each error correction level.*/
- static const unsigned char QR_RS_NPAR_OFFS[40]={
- 0, 4,19,55,15,28,37,12,51,39,
- 59,62,10,24,22,41,31,44, 7,65,
- 47,33,67,67,48,32,67,67,67,67,
- 67,67,67,67,67,67,67,67,67,67
- };
- /*The number of Reed-Solomon blocks for each version and error correction
- level.*/
- static const unsigned char QR_RS_NBLOCKS[40][4]={
- { 1, 1, 1, 1},{ 1, 1, 1, 1},{ 1, 1, 2, 2},{ 1, 2, 2, 4},
- { 1, 2, 4, 4},{ 2, 4, 4, 4},{ 2, 4, 6, 5},{ 2, 4, 6, 6},
- { 2, 5, 8, 8},{ 4, 5, 8, 8},{ 4, 5, 8,11},{ 4, 8,10,11},
- { 4, 9,12,16},{ 4, 9,16,16},{ 6,10,12,18},{ 6,10,17,16},
- { 6,11,16,19},{ 6,13,18,21},{ 7,14,21,25},{ 8,16,20,25},
- { 8,17,23,25},{ 9,17,23,34},{ 9,18,25,30},{10,20,27,32},
- {12,21,29,35},{12,23,34,37},{12,25,34,40},{13,26,35,42},
- {14,28,38,45},{15,29,40,48},{16,31,43,51},{17,33,45,54},
- {18,35,48,57},{19,37,51,60},{19,38,53,63},{20,40,56,66},
- {21,43,59,70},{22,45,62,74},{24,47,65,77},{25,49,68,81}
- };
- /*Attempts to fully decode a QR code.
- _qrdata: Returns the parsed code data.
- _gf: Used for Reed-Solomon error correction.
- _ul_pos: The location of the UL finder pattern.
- _ur_pos: The location of the UR finder pattern.
- _dl_pos: The location of the DL finder pattern.
- _version: The (decoded) version number.
- _fmt_info: The decoded format info.
- _img: The binary input image.
- _width: The width of the input image.
- _height: The height of the input image.
- Return: 0 on success, or a negative value on error.*/
- static int qr_code_decode(qr_code_data *_qrdata,const rs_gf256 *_gf,
- const qr_point _ul_pos,const qr_point _ur_pos,const qr_point _dl_pos,
- int _version,int _fmt_info,
- const unsigned char *_img,int _width,int _height){
- qr_sampling_grid grid;
- unsigned *data_bits;
- unsigned char **blocks;
- unsigned char *block_data;
- int nblocks;
- int nshort_blocks;
- int ncodewords;
- int block_sz;
- int ecc_level;
- int ndata;
- int npar;
- int dim;
- int ret;
- int i;
- /*Read the bits out of the image.*/
- qr_sampling_grid_init(&grid,_version,_ul_pos,_ur_pos,_dl_pos,_qrdata->bbox,
- _img,_width,_height);
- #if defined(QR_DEBUG)
- qr_sampling_grid_dump(&grid,_version,_img,_width,_height);
- #endif
- dim=17+(_version<<2);
- data_bits=(unsigned *)malloc(
- dim*(dim+QR_INT_BITS-1>>QR_INT_LOGBITS)*sizeof(*data_bits));
- qr_sampling_grid_sample(&grid,data_bits,dim,_fmt_info,_img,_width,_height);
- /*Group those bits into Reed-Solomon codewords.*/
- ecc_level=(_fmt_info>>3)^1;
- nblocks=QR_RS_NBLOCKS[_version-1][ecc_level];
- npar=*(QR_RS_NPAR_VALS+QR_RS_NPAR_OFFS[_version-1]+ecc_level);
- ncodewords=qr_code_ncodewords(_version);
- block_sz=ncodewords/nblocks;
- nshort_blocks=nblocks-(ncodewords%nblocks);
- blocks=(unsigned char **)malloc(nblocks*sizeof(*blocks));
- block_data=(unsigned char *)malloc(ncodewords*sizeof(*block_data));
- blocks[0]=block_data;
- for(i=1;i<nblocks;i++)blocks[i]=blocks[i-1]+block_sz+(i>nshort_blocks);
- qr_samples_unpack(blocks,nblocks,block_sz-npar,nshort_blocks,
- data_bits,grid.fpmask,dim);
- qr_sampling_grid_clear(&grid);
- free(blocks);
- free(data_bits);
- /*Perform the error correction.*/
- ndata=0;
- ncodewords=0;
- ret=0;
- for(i=0;i<nblocks;i++){
- int block_szi;
- int ndatai;
- block_szi=block_sz+(i>=nshort_blocks);
- if(rs_correct(_gf,QR_M0,block_data+ncodewords,block_szi,npar,NULL,0)<0){
- ret=-1;
- break;
- }
- ndatai=block_szi-npar;
- memmove(block_data+ndata,block_data+ncodewords,ndatai*sizeof(*block_data));
- ncodewords+=block_szi;
- ndata+=ndatai;
- }
- /*Parse the corrected bitstream.*/
- if(ret>=0){
- ret=qr_code_data_parse(_qrdata,_version,block_data,ndata);
- /*We could return any partially decoded data, but then we'd have to have
- API support for that; a mode ignoring ECC errors might also be useful.*/
- if(ret<0)qr_code_data_clear(_qrdata);
- _qrdata->version=_version;
- _qrdata->ecc_level=ecc_level;
- }
- free(block_data);
- return ret;
- }
- /*Searches for an arrangement of these three finder centers that yields a valid
- configuration.
- _c: On input, the three finder centers to consider in any order.
- Return: The detected version number, or a negative value on error.*/
- static int qr_reader_try_configuration(qr_reader *_reader,
- qr_code_data *_qrdata,const unsigned char *_img,int _width,int _height,
- qr_finder_center *_c[3]){
- int ci[7];
- unsigned maxd;
- int ccw;
- int i0;
- int i;
- /*Sort the points in counter-clockwise order.*/
- ccw=qr_point_ccw(_c[0]->pos,_c[1]->pos,_c[2]->pos);
- /*Colinear points can't be the corners of a quadrilateral.*/
- if(!ccw)return -1;
- /*Include a few extra copies of the cyclical list to avoid mods.*/
- ci[6]=ci[3]=ci[0]=0;
- ci[4]=ci[1]=1+(ccw<0);
- ci[5]=ci[2]=2-(ccw<0);
- /*Assume the points farthest from each other are the opposite corners, and
- find the top-left point.*/
- maxd=qr_point_distance2(_c[1]->pos,_c[2]->pos);
- i0=0;
- for(i=1;i<3;i++){
- unsigned d;
- d=qr_point_distance2(_c[ci[i+1]]->pos,_c[ci[i+2]]->pos);
- if(d>maxd){
- i0=i;
- maxd=d;
- }
- }
- /*However, try all three possible orderings, just to be sure (a severely
- skewed projection could move opposite corners closer than adjacent).*/
- for(i=i0;i<i0+3;i++){
- qr_aff aff;
- qr_hom hom;
- qr_finder ul;
- qr_finder ur;
- qr_finder dl;
- int res;
- int ur_version;
- int dl_version;
- int fmt_info;
- ul.c=_c[ci[i]];
- ur.c=_c[ci[i+1]];
- dl.c=_c[ci[i+2]];
- /*Estimate the module size and version number from the two opposite corners.
- The module size is not constant in the image, so we compute an affine
- projection from the three points we have to a square domain, and
- estimate it there.
- Although it should be the same along both axes, we keep separate
- estimates to account for any remaining projective distortion.*/
- res=QR_INT_BITS-2-QR_FINDER_SUBPREC-qr_ilog(QR_MAXI(_width,_height)-1);
- qr_aff_init(&aff,ul.c->pos,ur.c->pos,dl.c->pos,res);
- qr_aff_unproject(ur.o,&aff,ur.c->pos[0],ur.c->pos[1]);
- qr_finder_edge_pts_aff_classify(&ur,&aff);
- if(qr_finder_estimate_module_size_and_version(&ur,1<<res,1<<res)<0)continue;
- qr_aff_unproject(dl.o,&aff,dl.c->pos[0],dl.c->pos[1]);
- qr_finder_edge_pts_aff_classify(&dl,&aff);
- if(qr_finder_estimate_module_size_and_version(&dl,1<<res,1<<res)<0)continue;
- /*If the estimated versions are significantly different, reject the
- configuration.*/
- if(abs(ur.eversion[1]-dl.eversion[0])>QR_LARGE_VERSION_SLACK)continue;
- qr_aff_unproject(ul.o,&aff,ul.c->pos[0],ul.c->pos[1]);
- qr_finder_edge_pts_aff_classify(&ul,&aff);
- if(qr_finder_estimate_module_size_and_version(&ul,1<<res,1<<res)<0||
- abs(ul.eversion[1]-ur.eversion[1])>QR_LARGE_VERSION_SLACK||
- abs(ul.eversion[0]-dl.eversion[0])>QR_LARGE_VERSION_SLACK){
- continue;
- }
- #if defined(QR_DEBUG)
- qr_finder_dump_aff_undistorted(&ul,&ur,&dl,&aff,_img,_width,_height);
- #endif
- /*If we made it this far, upgrade the affine homography to a full
- homography.*/
- if(qr_hom_fit(&hom,&ul,&ur,&dl,_qrdata->bbox,&aff,
- &_reader->isaac,_img,_width,_height)<0){
- continue;
- }
- qr_hom_unproject(ul.o,&hom,ul.c->pos[0],ul.c->pos[1]);
- qr_hom_unproject(ur.o,&hom,ur.c->pos[0],ur.c->pos[1]);
- qr_hom_unproject(dl.o,&hom,dl.c->pos[0],dl.c->pos[1]);
- qr_finder_edge_pts_hom_classify(&ur,&hom);
- if(qr_finder_estimate_module_size_and_version(&ur,
- ur.o[0]-ul.o[0],ur.o[0]-ul.o[0])<0){
- continue;
- }
- qr_finder_edge_pts_hom_classify(&dl,&hom);
- if(qr_finder_estimate_module_size_and_version(&dl,
- dl.o[1]-ul.o[1],dl.o[1]-ul.o[1])<0){
- continue;
- }
- #if defined(QR_DEBUG)
- qr_finder_dump_hom_undistorted(&ul,&ur,&dl,&hom,_img,_width,_height);
- #endif
- /*If we have a small version (less than 7), there's no encoded version
- information.
- If the estimated version on the two corners matches and is sufficiently
- small, we assume this is the case.*/
- if(ur.eversion[1]==dl.eversion[0]&&ur.eversion[1]<7){
- /*We used to do a whole bunch of extra geometric checks for small
- versions, because with just an affine correction, it was fairly easy
- to estimate two consistent module sizes given a random configuration.
- However, now that we're estimating a full homography, these appear to
- be unnecessary.*/
- #if 0
- static const signed char LINE_TESTS[12][6]={
- /*DL left, UL > 0, UR > 0*/
- {2,0,0, 1,1, 1},
- /*DL right, UL > 0, UR < 0*/
- {2,1,0, 1,1,-1},
- /*UR top, UL > 0, DL > 0*/
- {1,2,0, 1,2, 1},
- /*UR bottom, UL > 0, DL < 0*/
- {1,3,0, 1,2,-1},
- /*UR left, DL < 0, UL < 0*/
- {1,0,2,-1,0,-1},
- /*UR right, DL > 0, UL > 0*/
- {1,1,2, 1,0, 1},
- /*DL top, UR < 0, UL < 0*/
- {2,2,1,-1,0,-1},
- /*DL bottom, UR > 0, UL > 0*/
- {2,3,1, 1,0, 1},
- /*UL left, DL > 0, UR > 0*/
- {0,0,2, 1,1, 1},
- /*UL right, DL > 0, UR < 0*/
- {0,1,2, 1,1,-1},
- /*UL top, UR > 0, DL > 0*/
- {0,2,1, 1,2, 1},
- /*UL bottom, UR > 0, DL < 0*/
- {0,3,1, 1,2,-1}
- };
- qr_finder *f[3];
- int j;
- /*Start by decoding the format information.
- This is cheap, but unlikely to reject invalid configurations.
- 56.25% of all bitstrings are valid, and we mix and match several pieces
- until we find a valid combination, so our real chances of finding a
- valid codeword in random bits are even higher.*/
- fmt_info=qr_finder_fmt_info_decode(&ul,&ur,&dl,&aff,_img,_width,_height);
- if(fmt_info<0)continue;
- /*Now we fit lines to the edges of each finder pattern and check to make
- sure the centers of the other finder patterns lie on the proper side.*/
- f[0]=&ul;
- f[1]=&ur;
- f[2]=&dl;
- for(j=0;j<12;j++){
- const signed char *t;
- qr_line l0;
- int *p;
- t=LINE_TESTS[j];
- qr_finder_ransac(f[t[0]],&aff,&_reader->isaac,t[1]);
- /*We may not have enough points to fit a line accurately here.
- If not, we just skip the test.*/
- if(qr_line_fit_finder_edge(l0,f[t[0]],t[1],res)<0)continue;
- p=f[t[2]]->c->pos;
- if(qr_line_eval(l0,p[0],p[1])*t[3]<0)break;
- p=f[t[4]]->c->pos;
- if(qr_line_eval(l0,p[0],p[1])*t[5]<0)break;
- }
- if(j<12)continue;
- /*All tests passed.*/
- #endif
- ur_version=ur.eversion[1];
- }
- else{
- /*If the estimated versions are significantly different, reject the
- configuration.*/
- if(abs(ur.eversion[1]-dl.eversion[0])>QR_LARGE_VERSION_SLACK)continue;
- /*Otherwise we try to read the actual version data from the image.
- If the real version is not sufficiently close to our estimated version,
- then we assume there was an unrecoverable decoding error (so many bit
- errors we were within 3 errors of another valid code), and throw that
- value away.
- If no decoded version could be sufficiently close, we don't even try.*/
- if(ur.eversion[1]>=7-QR_LARGE_VERSION_SLACK){
- ur_version=qr_finder_version_decode(&ur,&hom,_img,_width,_height,0);
- if(abs(ur_version-ur.eversion[1])>QR_LARGE_VERSION_SLACK)ur_version=-1;
- }
- else ur_version=-1;
- if(dl.eversion[0]>=7-QR_LARGE_VERSION_SLACK){
- dl_version=qr_finder_version_decode(&dl,&hom,_img,_width,_height,1);
- if(abs(dl_version-dl.eversion[0])>QR_LARGE_VERSION_SLACK)dl_version=-1;
- }
- else dl_version=-1;
- /*If we got at least one valid version, or we got two and they match,
- then we found a valid configuration.*/
- if(ur_version>=0){
- if(dl_version>=0&&dl_version!=ur_version)continue;
- }
- else if(dl_version<0)continue;
- else ur_version=dl_version;
- }
- qr_finder_edge_pts_hom_classify(&ul,&hom);
- if(qr_finder_estimate_module_size_and_version(&ul,
- ur.o[0]-dl.o[0],dl.o[1]-ul.o[1])<0||
- abs(ul.eversion[1]-ur.eversion[1])>QR_SMALL_VERSION_SLACK||
- abs(ul.eversion[0]-dl.eversion[0])>QR_SMALL_VERSION_SLACK){
- continue;
- }
- fmt_info=qr_finder_fmt_info_decode(&ul,&ur,&dl,&hom,_img,_width,_height);
- if(fmt_info<0)continue;
- if(qr_code_decode(_qrdata,&_reader->gf,ul.c->pos,ur.c->pos,dl.c->pos,
- ur_version,fmt_info,_img,_width,_height)<0){
- /*TODO: Maybe somebody flipped the code?
- We'd still get a valid version, and probably valid (but incorrect)
- format info.
- After we've come this far, it should be a simple matter to check.*/
- continue;
- }
- return ur_version;
- }
- return -1;
- }
- void qr_reader_match_centers(qr_reader *_reader,qr_code_data_list *_qrlist,
- qr_finder_center *_centers,int _ncenters,
- const unsigned char *_img,int _width,int _height){
- /*The number of centers should be small, so an O(n^3) exhaustive search of
- which ones go together should be reasonable.*/
- unsigned char *mark;
- int i;
- int j;
- int k;
- mark=(unsigned char *)calloc(_ncenters,sizeof(*mark));
- for(i=0;i<_ncenters;i++){
- /*TODO: We might be able to accelerate this step significantly by
- considering the remaining finder centers in a more intelligent order,
- based on the first finder center we just chose.*/
- for(j=i+1;!mark[i]&&j<_ncenters;j++){
- for(k=j+1;!mark[j]&&k<_ncenters;k++)if(!mark[k]){
- qr_finder_center *c[3];
- qr_code_data qrdata;
- int version;
- c[0]=_centers+i;
- c[1]=_centers+j;
- c[2]=_centers+k;
- version=qr_reader_try_configuration(_reader,&qrdata,
- _img,_width,_height,c);
- if(version>=0){
- int ninside;
- int l;
- /*Add the data to the list.*/
- qr_code_data_list_add(_qrlist,&qrdata);
- /*Convert the bounding box we're returning to the user to normal
- image coordinates.*/
- for(l=0;l<4;l++){
- _qrlist->qrdata[_qrlist->nqrdata-1].bbox[l][0]>>=QR_FINDER_SUBPREC;
- _qrlist->qrdata[_qrlist->nqrdata-1].bbox[l][1]>>=QR_FINDER_SUBPREC;
- }
- /*Mark these centers as used.*/
- mark[i]=mark[j]=mark[k]=1;
- /*Find any other finder centers located inside this code.*/
- for(l=ninside=0;l<_ncenters;l++)if(!mark[l]){
- if(qr_point_ccw(qrdata.bbox[0],qrdata.bbox[1],_centers[l].pos)>=0&&
- qr_point_ccw(qrdata.bbox[1],qrdata.bbox[3],_centers[l].pos)>=0&&
- qr_point_ccw(qrdata.bbox[3],qrdata.bbox[2],_centers[l].pos)>=0&&
- qr_point_ccw(qrdata.bbox[2],qrdata.bbox[0],_centers[l].pos)>=0){
- mark[l]=2;
- ninside++;
- }
- }
- if(ninside>=3){
- /*We might have a "Double QR": a code inside a code.
- Copy the relevant centers to a new array and do a search confined
- to that subset.*/
- qr_finder_center *inside;
- inside=(qr_finder_center *)malloc(ninside*sizeof(*inside));
- for(l=ninside=0;l<_ncenters;l++){
- if(mark[l]==2)*&inside[ninside++]=*&_centers[l];
- }
- qr_reader_match_centers(_reader,_qrlist,inside,ninside,
- _img,_width,_height);
- free(inside);
- }
- /*Mark _all_ such centers used: codes cannot partially overlap.*/
- for(l=0;l<_ncenters;l++)if(mark[l]==2)mark[l]=1;
- }
- }
- }
- }
- free(mark);
- }
- int _zbar_qr_found_line (qr_reader *reader,
- int dir,
- const qr_finder_line *line)
- {
- /* minimally intrusive brute force version */
- qr_finder_lines *lines = &reader->finder_lines[dir];
- if(lines->nlines >= lines->clines) {
- lines->clines *= 2;
- lines->lines = realloc(lines->lines,
- ++lines->clines * sizeof(*lines->lines));
- }
- memcpy(lines->lines + lines->nlines++, line, sizeof(*line));
- return(0);
- }
- static inline void qr_svg_centers (const qr_finder_center *centers,
- int ncenters)
- {
- int i, j;
- svg_path_start("centers", 1, 0, 0);
- for(i = 0; i < ncenters; i++)
- svg_path_moveto(SVG_ABS, centers[i].pos[0], centers[i].pos[1]);
- svg_path_end();
- svg_path_start("edge-pts", 1, 0, 0);
- for(i = 0; i < ncenters; i++) {
- const qr_finder_center *cen = centers + i;
- for(j = 0; j < cen->nedge_pts; j++)
- svg_path_moveto(SVG_ABS,
- cen->edge_pts[j].pos[0], cen->edge_pts[j].pos[1]);
- }
- svg_path_end();
- }
- int _zbar_qr_decode (qr_reader *reader,
- zbar_image_scanner_t *iscn,
- zbar_image_t *img)
- {
- int nqrdata = 0;
- qr_finder_edge_pt *edge_pts = NULL;
- qr_finder_center *centers = NULL;
- if(reader->finder_lines[0].nlines < 9 ||
- reader->finder_lines[1].nlines < 9)
- return(0);
- svg_group_start("finder", 0, 1. / (1 << QR_FINDER_SUBPREC), 0, 0, 0);
- int ncenters = qr_finder_centers_locate(¢ers, &edge_pts, reader, 0, 0);
- zprintf(14, "%dx%d finders, %d centers:\n",
- reader->finder_lines[0].nlines,
- reader->finder_lines[1].nlines,
- ncenters);
- qr_svg_centers(centers, ncenters);
- if(ncenters >= 3) {
- // void *bin = qr_binarize(img->data, img->width, img->height);
- void *bin = qr_binarize2(img->data, img->width, img->height);
- qr_code_data_list qrlist;
- qr_code_data_list_init(&qrlist);
- qr_reader_match_centers(reader, &qrlist, centers, ncenters,
- bin, img->width, img->height);
- if(qrlist.nqrdata > 0)
- nqrdata = qr_code_data_list_extract_text(&qrlist, iscn, img);
- qr_code_data_list_clear(&qrlist);
- // free(bin);
- }
- svg_group_end();
- if(centers)
- free(centers);
- if(edge_pts)
- free(edge_pts);
- return(nqrdata);
- }
|