Josep Portella

Com funciona Màgia DNI

Desembre de 2011
Traduït: març de 2012
Actualitzat: febrer de 2017

© 2012, 2017 Josep Portella Florit
Aquesta obra està sota una llicència de
Reconeixement-SenseObraDerivada 3.0 Creative Commons.

Contingut

Introducció

Màgia DNI és una aplicació per Android que fa servir la càmera del dispositiu per llegir les dades OCR del DNI espanyol, tant l'electrònic com el tradicional, i calcular el dígit de control, aplicant el que s'explica al meu article Desmitificant els números del DNI. El propòsit de l'aplicació és demostrar de forma gràfica que el que es diu del dígit de control és un mite, i per això vaig fer que funcionàs igualment amb el dígit de control tapat.

En publicar Màgia DNI diverses persones es van interessar en saber com havia fet el reconeixement de caràcters. En aquest article pretenc explicar el mètode utilitzat.

No vaig fer servir biblioteques de tercers (si no comptem l'SDK d'Android) però, per fer més fàcil d'implementar, més precís i més ràpid, vaig aprofitar les peculiaritats de les dades OCR del DNI que els sistemes OCR genèrics no poden tenir en compte.

El codi font de Màgia DNI està disponible sota llicència GPL.

Localització de les files de caràcters

La imatge de la càmera es tracta a Màgia DNI com una matriu de 2 dimensions amb valors de 0 a 255 que representen la lluminositat de cada píxel, sent 0 totalment fosc i 255 el valor màxim de llum.

[Foto en escala de grisos d'unes línies de dades OCR d'un DNI
inventat]

Per cada línia horitzontal de píxels s'obté la mitjana de lluminositat. El resultat d'aquest procés és una gràfica semblant a aquesta:

[Gràfica que mostra 3 endinsades corresponents a la posició vertical
de les línies]

A continuació, cada valor entre el valor màxim i mínim de la gràfica és utilitzat com a llindar per calcular una gràfica de col·lisions. Les col·lisions són una sèrie de segments dels quals es sap la posició, longitud i el fet de si estan per sobre o per sota del llindar, és a dir, si col·lisionen o no col·lisionen amb la gràfica. Per exemple, establint el llindar a una posició entre el valor màxim i mínim de la gràfica anterior:

[La gràfica anterior amb una línia horitzontal que travessa les
endinsades]

s'obté aquesta gràfica de col·lisions:

[Línia horitzontal amb unes osques que representen les pujades i
baixades respecte el llindar]

A cada gràfica de col·lisions es cerca el patró que solen deixar les files de dades OCR del DNI; si es troba el patró es guarden les posicions de les files a partir de les dades dels segments corresponents, però si anteriorment ja s'havia trobat una coincidència, aquesta només es substitueix per l'actual en el cas de que l'actual sigui millor.

El patró que deixen les files de dades OCR del DNI consisteix en tres segments que no col·lisionen, diguem-ne files, separats per segments més petits que col·lisionen, diguem-ne separadors. Es comprova que les files tinguin certa mida com a mínim, proporcional a la mida de la imatge, i que la desviació estàndard de les mides de les files no excedeixi el 12% de la mitjana de les mides, i es fa el mateix amb els separadors. A més es comprova que la mida màxima de les files sigui major a la mida màxima dels separadors, però menor que les col·lisions a l'esquerra de la primera fila i a la dreta de la darrera fila.

Una coincidència del patró es considera millor que un altra quan la suma de la mida de les seves files és major que la de l'altre.

Una vegada acabat el procés, es descarta la darrera fila de la millor coincidència, ja que no serveix per al propòsit de l'aplicació; també es descarten els separadors, i les dues files restants s'ajusten a esquerra i dreta segons la separació entre ambdues.

[Seqüència de gràfics que representa l'ajustament de les 2 primeres
files]

D'aquesta manera es disminueix la possibilitat de que es talli part dels caràcters.

Localització de les columnes de caràcters

Tenint en compte la posició i la mida de les dues primeres files, veiem la imatge així:

[La foto retallada per incloure només les 2 primeres
files]

Per cada línia vertical de la imatge retallada es troben el valor mínim i el valor màxim i es resten, obtenint una gràfica similar a aquesta:

[Gràfica amb endinsades que indiquen la posició de les columnes de
caràcters]

Igual que amb les files, s'han d'obtenir gràfiques de col·lisions per cada valor entre el valor màxim i el valor mínim de la gràfica. En cada gràfica de col·lisions es cerquen coincidències amb el patró de les columnes per quedar-se amb la millor de totes les coincidències.

Diguem columnes als segments que no col·lisionen i coincideixen amb la posició de les columnes de caràcters. El patró a cercar és semblant al de les files; la diferència és que el valor màxim de la desviació estàndard de les mides de les columnes i separadors serà la mitjana de les mides. Es dóna per bo si hi ha 24 columnes (les necessàries per al càlcul del dígit de control), i igual que amb les files, les columnes tenen certa mida com a mínim i la mida màxima de les columnes és major que la mida màxima dels separadors.

Perquè una coincidència sigui considerada millor que un altre, a més que la suma de les mides de les seves columnes sigui major, ha de començar a la mateixa posició o estar més a l'esquerra.

Finalment es descarten els separadors de la millor coincidència i s'ajusten les columnes de la mateixa manera que s'han ajustat les files.

Conversió de caràcters a 2 bits

Havent localitzat les files i les columnes de caràcters ja disposem de posició, alçada i amplada dels caràcters que ens interessen. Abans de poder reconèixer els caràcters s'han de transformar d'escala de grisos a 2 bits, eliminant el màxim soroll possible. Per això es calcula el llindar òptim: el 70% del valor mitjà dels píxels del caràcter a processar.

[Seqüència d'imatges amb un caràcter representat amb diversos
llindars]

Reconeixement de caràcters

Sabent el llindar òptim d'un caràcter retallem els marges de manera que quedi ajustat.

[Comparació d'un caràcter amb marges i sense
 marges]

A l'hora de reconèixer un caràcter es tenen en compte els diferents valors que pot tenir segons la fila i la columna del caràcter. Per exemple, les dates de la segona fila sempre seran dígits. D'aquesta manera el procés es fa més precís i ràpid.

L'aplicació disposa d'una plantilla per cada caràcter possible. Per cada caràcter possible es comparen píxel a píxel la imatge a reconèixer amb la corresponent plantilla, tenint en compte el ràtio ja que el normal serà que no coincideixin en mida. Es comença assignant la puntuació de la plantilla a zero. Si coincideix un píxel, es suma 1 a la puntuació; si no coincideix, es resta 1. El resultat serà el valor de la plantilla amb major puntuació.

Reconeixement del tipus de DNI

Per saber si les dades OCR que s'estan llegint pertanyen a un DNI electrònic o a un DNI tradicional, es reconeix el caràcter a la columna 23 de la fila 1. Si el caràcter és un dígit, llavors es tracta d'un DNI electrònic; si el caràcter és el símbol de menor-que, llavor es tracta d'un DNI tradicional.

El tipus de DNI es té en compte a l'hora de calcular el dígit de control, perquè varien les dades que s'empren per això.

Detecció d'errors

Abans de mostrar el dígit de control calculat, es comproven els altres dígits de control, incloent la lletra del DNI, per evitar mostrar el dígit incorrecte. Tot i això, pot passar que 2 o més errors de reconeixement inoportuns facin possible superar les comprovacions, resultant en un dígit de control final incorrecte. Per fer això menys probable, no es mostra el dígit fins que es calcula el mateix per segona vegada, descartant-se si s'obté un altre dígit.