Comment fonctionne un code-barres?

Salut à tous!

De nos jours, tout le monde utilise des codes-barres, la plupart du temps sans s'en rendre compte. Lorsque nous achetons les produits d'épicerie dans le magasin, leurs identifiants proviennent des codes à barres. C'est également la même chose avec les marchandises dans les entrepôts, les colis postaux, etc. Mais peu de gens savent réellement comment cela fonctionne.

Qu'est-ce qui se trouve à l'intérieur du code-barres et qu'est-ce qui est codé sur cette image?



Permet de le comprendre et permet également d'écrire notre propre décodeur de barres.

Présentation


L'utilisation de codes-barres a une longue histoire. Les premières tentatives d'automatisation ont été faites dans les années 50, le brevet d'un système de lecture de codes a été accordé. David Collins, qui travaillait au Pennsylvania Railroad, a décidé de faciliter le processus de tri des wagons. L'idée était évidente: coder les identificateurs de voiture avec des bandes de couleurs différentes et les lire à l'aide d'une cellule photoélectrique. En 1962, un tel code est devenu un standard de l'Association of American Railroads. (le système KarTrak ). En 1968, la lampe a été remplacée par un laser, cela a permis d'augmenter la précision et de réduire la taille du lecteur. En 1973, le code universel des produits a été développé et en 1974, le premier produit d'épicerie (un chewing-gum Wrigley - c'était évidemment aux États-Unis;) a été vendu. En 1984, la troisième partie de tous les magasins a utilisé des codes à barres, dans d'autres pays, il est devenu populaire plus tard.

Il existe de nombreux types de codes à barres différents pour différentes applications, par exemple, la chaîne "12345678" peut être codée de cette façon (et ce n'est pas tous):



Commençons l'analyse. Toutes les informations ci-dessous porteront sur le type "Code-128" - simplement parce que son principe est facile à comprendre. Ceux qui veulent tester d'autres modes peuvent utiliser le générateur de codes-barres en ligne et tester d'autres types par eux-mêmes.

À première vue, un code-barres ressemble à un ensemble aléatoire de nombres, mais en fait sa structure est bien organisée:



1 - Espace vide, nécessaire pour déterminer la position de départ du code.
2 - Symbole de départ. Trois types de Code-128 sont disponibles (appelés A, B et C), et les symboles de début peuvent être respectivement 11010000100, 11010010000 ou 11010011100. Pour ces types, les tables de codage sont différentes (voir la description de Code_128 pour plus de détails ).
3 - Le code lui-même, contenant les données utilisateur.
4 - Somme de contrôle.
5 - Symbole d'arrêt, pour Code-128 son 1100011101011.
6 (1) - Espace vide.

Voyons maintenant comment les bits sont encodés. C'est vraiment facile - si nous prenons la largeur de ligne la plus mince à "1", alors la ligne à double largeur sera "11", la ligne à triple largeur sera "111", et ainsi de suite. L'espace vide sera respectivement "0", "00" ou "000", selon le même principe. Ceux qui sont intéressés peuvent comparer la séquence de départ sur l'image ci-dessus, pour voir que la règle est respectée.

Nous pouvons maintenant commencer à coder.

Obtenir la séquence de bits


En général, c'est la partie la plus compliquée, et cela peut se faire de différentes manières. Je ne suis pas sûr que mon approche soit optimale, mais pour notre tâche, c'est certainement suffisant.

Tout d'abord, permet de charger l'image, d'étirer sa largeur, de recadrer une ligne horizontale à partir du milieu, de la convertir en couleur n / b et de l'enregistrer en tant que tableau.

from PIL import Image import numpy as np import matplotlib.pyplot as plt image_path = "barcode.jpg" img = Image.open(image_path) width, height = img.size basewidth = 4*width img = img.resize((basewidth, height), Image.ANTIALIAS) hor_line_bw = img.crop((0, int(height/2), basewidth, int(height/2) + 1)).convert('L') hor_data = np.asarray(hor_line_bw, dtype="int32")[0] 

Sur la ligne noire du code à barres correspond à "1", mais en RVB le noir est au contraire 0, donc le tableau doit être inversé. Nous calculerons également la valeur moyenne.

 hor_data = 255 - hor_data avg = np.average(hor_data) plt.plot(hor_data) plt.show() 

Permet d'exécuter le programme pour vérifier que le code-barres a été correctement chargé:



Nous devons maintenant déterminer une largeur d'un «bit». Pour ce faire, nous allons extraire la séquence, en sauvegardant les positions du franchissement de ligne moyen.

 pos1, pos2 = -1, -1 bits = "" for p in range(basewidth - 2): if hor_data[p] < avg and hor_data[p + 1] > avg: bits += "1" if pos1 == -1: pos1 = p if bits == "101": pos2 = p break if hor_data[p] > avg and hor_data[p + 1] < avg: bits += "0" bit_width = int((pos2 - pos1)/3) 

Nous ne sauvegardons que les passages de ligne moyens, donc le code "1101" sera enregistré en tant que "101", un bit suffisant pour obtenir la largeur de ses pixels.

Permet maintenant de faire le décodage lui-même. Nous devons trouver chaque passage de ligne moyen et trouver le nombre de bits dans le dernier intervalle trouvé. Les nombres ne correspondront pas parfaitement (le code peut être étiré ou plié un peu), nous devons donc arrondir la valeur en entier.

 bits = "" for p in range(basewidth - 2): if hor_data[p] > avg and hor_data[p + 1] < avg: interval = p - pos1 cnt = interval/bit_width bits += "1"*int(round(cnt)) pos1 = p if hor_data[p] < avg and hor_data[p + 1] > avg: interval = p - pos1 cnt = interval/bit_width bits += "0"*int(round(cnt)) pos1 = p 

Il y a peut-être une meilleure façon de le faire, les lecteurs peuvent écrire des commentaires.

Si tout était parfait, nous obtiendrons une séquence comme celle-ci:

11010010000110001010001000110100010001101110100011011101000111011011
01100110011000101000101000110001000101100011000101110110011011001111
00010101100011101011


Décodage


En général, c'est assez facile. Les symboles du Code-128 sont codés avec du code 11 bits, qui peut avoir un codage différent (selon ce codage - A, B ou C, il peut s'agir de lettres ou de chiffres de 00 à 99).

Dans notre cas, le début de la séquence est 11010010000, ce qui correspond à un "Code B". J'étais trop paresseux pour entrer tous les codes manuellement, donc je viens de les copier-coller à partir d'une page Wikipedia. L'analyse de ces lignes a également été effectuée sur Python (indice - ne faites pas des choses comme ça en production).

  CODE128_CHART = """ 0 _ _ 00 32 S 11011001100 212222 1 ! ! 01 33 ! 11001101100 222122 2 " " 02 34 " 11001100110 222221 3 # # 03 35 # 10010011000 121223 ... 93 GS } 93 125 } 10100011110 111341 94 RS ~ 94 126 ~ 10001011110 131141 103 Start Start A 208 SCA 11010000100 211412 104 Start Start B 209 SCB 11010010000 211214 105 Start Start C 210 SCC 11010011100 211232 106 Stop Stop - - - 11000111010 233111""".split() SYMBOLS = [value for value in CODE128_CHART[6::8]] VALUESB = [value for value in CODE128_CHART[2::8]] CODE128B = dict(zip(SYMBOLS, VALUESB)) 

Les dernières parties sont faciles. Tout d'abord, permet de diviser la séquence en blocs de 11 bits:

 sym_len = 11 symbols = [bits[i:i+sym_len] for i in range(0, len(bits), sym_len)] 

Enfin, permet de générer la chaîne de sortie et de l'afficher:

 str_out = "" for sym in symbols: if CODE128A[sym] == 'Start': continue if CODE128A[sym] == 'Stop': break str_out += CODE128A[sym] print(" ", sym, CODE128A[sym]) print("Str:", str_out) 

Je ne montrerai pas ici le résultat décodé de l'image du haut, que ce soit le devoir des lecteurs (l'utilisation des applications téléchargées pour smartphones sera considérée comme de la triche :).

La vérification CRC n'est pas implémentée dans ce code, ceux qui le souhaitent peuvent le faire eux-mêmes.

Pour sûr, cet algorithme n'est pas parfait, il a été fait en une demi-heure. Pour les tâches professionnelles, il existe des bibliothèques prêtes à l'emploi, par exemple pyzbar . Pour décoder l'image, 4 lignes de code suffisent:

 from pyzbar.pyzbar import decode img = Image.open(image_path) decode = decode(img) print(decode) 

(la bibliothèque doit d'abord être installée à l'aide de la commande "pip install pyzbar")

Ajout : l'utilisateur du site vinograd19 a envoyé un commentaire intéressant sur l'historique de calcul de la somme de contrôle des codes à barres.

Le calcul du nombre de chèques est intéressant, il est né évolutivement.
La somme de contrôle est évidemment nécessaire pour éviter un mauvais décodage. Si le code-barres était 1234 et a été décodé en 7234, nous avons besoin d'une méthode pour rejeter le remplacement de 1 à 7. La validation peut ne pas être parfaite, mais au moins 90% des codes doivent être vérifiés correctement.

1ère approche: Prenons simplement la somme, pour avoir 0 comme reste de la division. Les premiers symboles contiennent des données, et le dernier chiffre est tel, que la somme de tous les nombres est divisée par 10. Après le décodage, si le montant n'est pas divisible par 10 - le décodage est incorrect et doit être répété. Par exemple, le code 1234 est valide - 1 + 2 + 3 + 4 = 10. Le code 1216 - est également valide, mais 1218 ne l'est pas.

Cela permet d'éviter les problèmes de décodage. Mais les codes peuvent également être saisis manuellement, à l'aide du clavier matériel. En utilisant cela, un autre mauvais cas a été trouvé - si l'ordre de deux chiffres sera changé, la somme de contrôle sera toujours correcte, c'est définitivement mauvais. Par exemple, si le code à barres 1234 a été entré comme 2134, la somme de contrôle sera la même. Il a été constaté qu'un mauvais ordre des chiffres était le cas commun, si une personne essayait d'entrer rapidement des chiffres.

2ème approche. Permet d'améliorer l'algorithme de somme de contrôle - permet de calculer deux fois les nombres impairs. Ensuite, si la commande est modifiée, la somme sera incorrecte. Par exemple, le code 2364 est valide (2 + 3 * 2 + 6 + 4 * 2 = 20), mais le code 3264 ne l'est pas (3 + 2 * 2 + 6 + 4 * 2 = 19). C'est mieux, mais un autre cas est apparu. Il y a des claviers, ayant 10 touches sur deux rangées, la première rangée est 12345 et la seconde est 67890. Si au lieu de "1" l'utilisateur tape "2", la vérification de la somme de contrôle échouera. Mais si l'utilisateur entre «6» au lieu de «1» - la somme de contrôle peut parfois être correcte. C'est parce que 6 = 1 + 5, et si le chiffre a une place étrange, nous obtenons 2 * 6 = 2 * 1 + 2 * 5 - la somme a augmenté de 10. La même erreur se produira, si l'utilisateur entre "7 "Au lieu de" 2 "," 8 "au lieu de" 3 ", etc.

3ème approche. Reprenons la somme, mais obtenons des nombres impairs ... 3 fois. Par exemple, le code 1234565 - est valide, car 1 + 2 * 3 + 3 + 4 * 3 + 5 + 6 * 3 +5 = 50.

Cette méthode est devenue une norme pour le code EAN13, avec quelques modifications: le nombre de chiffres est fixe et égal à 13, où le 13e chiffre - est la somme de contrôle. Les nombres aux endroits impairs sont comptés trois fois, aux endroits pairs une fois.

Soit dit en passant, le code EAN-13 est le plus utilisé dans les centres commerciaux et commerciaux, de sorte que les gens le voient plus souvent que les autres types de code. Son codage en bits est le même que dans Code-128, la structure des données se trouve dans l'article Wikipedia .

Conclusion


Comme nous pouvons le voir, même une chose aussi simple qu'un code à barres peut contenir des trucs sympas. Soit dit en passant, une autre petite bouée de sauvetage pour les lecteurs, qui ont été assez patients pour lire jusqu'à cet endroit - le texte sous le code-barres est entièrement identique aux données du code-barres. Il a été fait pour les opérateurs, qui peuvent saisir manuellement le code, s'il n'est pas lisible par le scanner. Il est donc facile de connaître le contenu du code-barres - il suffit de lire le texte ci-dessous.

Merci d'avoir lu.

Source: https://habr.com/ru/post/fr439768/


All Articles