DSB18: Barcode erzeugen und lesen
Autor: Tobias Brandt
Betreuer: Prof. Schneider
Motivation
Barcodes begleiten unseren Alltag bereits seid Jahrzehnten. Sie codieren Preise im Einzelhandel, ermöglichen das Verfolgen von Briefen und Paketen oder sind als Teil der Stempelkarte Teil der Zeiterfassung in der Industrie. Doch wie werden Barcodes erzeugt und gelesen? Dieser Artikel soll einen kurzen Einblick in die Notation, die Erstellung und das letzlich das Lesen des speziellen CODE39 geben. Integration des Programms erfolgt in Matlab.
Aufgabenstellung
Erzeugen Sie ein Matlab Executable, welches ein Barcode erzeugt. Mit einer Webcam soll ein beliebiger Barcode auf einem Dokument unabhängig von Position und Lage eingescannt werden können.
Anforderungen
- Arbeiten Sie sich in die Erstellung von Barcodes ein.
- Erzeugen Sie ein Matlab Executable, welches aus einen Barcode erzeugt.
- Lesen Sie mit Matlab über eine Webcam diesen Barcode ein, so dass die dahinterliegenden Daten angezeigt werden.
- Wissenschaftliche Dokumentation als HSHL-Wiki Artikel
- Softwareentwicklung nach SDE Standard in SVN
- Funktionsnachweis als YouTube-Video (vgl. Veranstaltungsregeln)
Prinzip Code39
Der Code 39 ist ein diskreter Code mit variabler Codelänge (Wenn mehr Zeichen dargestllt werden sollen, verlängert sich auch der Code). Der Code wurde 1973 erfunden und war somit der erste alphanumerische Barcode. Im Grundsatz besteht der barcode aus weißen und schwarzen Strichen.
Der Name ("Code 3 of 9") geht auf die Struktur der Kodierung zurück. Dabei werden die Zeichen der zu kodierenden Nachricht durch 9 schwarze und weiße Balken repräsentiert. Drei dieser Balken sind breit und der rest schmal. Jeder Block, dieser ein Zeichen darstellt, besteht aus 5 Strichen und 4 Lücken. Getrennt sind die Blöcke durch eine schmale weiße Lücke. Eine nachricht im Code39 beginnt und endet jeweils mit einem Sternchen '*'. Dies wird auch als Start-oder Stoppzeichen bezeichnet.
Der Standartcode verfügt über keine Prüfziffern und kann folgende Zeichen darstellen:
0123456789[Space]ABCDEFGHIJKLMNOPQRSTUVWXYZ-.$/+%
Die Kodierung der einzelnen Zeichen ist in der rechts abgebildeten Zeichentabelle festgelegt.
In der Folgenden Auflistung werden die Vor-und Nachteile Stichpunktartig aufgeführt:
Vorteile:
- große Lesesicherheit
- sehr weit verbreitet
- einfach in der Produktion
Nachteile:
- geringe Code Dichte
- keine Prüfsumme
Implementierung Barcode erstellen
Um einen Barcode zu erstellen wird zunächst die erforderliche Höhe und Breite des Bilds was benötigt wird berechnet. Danach wird als Grundlage ein weißes Bild als JPG erstellt.
function barcode_erstellen (eingabe,s_element,b_element)
%%Funktionsbeschreibung
%--------------------------------------------------------------------------
% Programmname: barcode_erstellen(eingabe,s_element,b_breite)
% Version: 1.0.0
% Datum: 12.05.2018
% Beschreibung: Das Programm erstellt einen 1D Barcode in CODE39 Format
%
% Autor: Tobias Brandt
%
% INPUT: eingabe: Zeichen die in einen Code39 umgewandelt werden
% sollen. (Nur Großbuchstaben, Zahlen und
% Sonderzeichen '-';'.';' ';'$';'+';'%')
% s_element: Dicke eines schmalen Elments in Pixel
% b_element: Dicke eines breiten Elements in Pixel
%
% Die Relation von Höhe und Breite muss 1:2 sein.
%
% OUTPUT: Das Programm erstellt einen Bracode mit den
% eingegebenen Daten als .jpg.
% Der Code beginnt und endet jeweils mit einem *
%
% Beispiel: barcode_erstellen('HSHL',10,20)
%
%
%--------------------------------------------------------------------------
%% Leeres Bild erzeuegen
% Länge des Barcode in Pixel bestimmen
%(length(eingabe)+2)=Anzahl der Zeichen, wegen 2x Sterne
%*(6*schmal+3*breit) wegen 3 schmalen Strichen, 3schmalen Lücken, 2 breite Striche, 1 breiten Lücke
%((length(eingabe)+1))= Anzahl der Lücken
Laenge = ((length(eingabe)+2)*(6*s_element+3*b_element))+((length(eingabe)+1)*s_element);
% Höhe des Barcodes damit evtl. noch Platz ist für einen Text
Hoehe = 10*b_element;
Breite= b_element*6 + Hoehe;
% Schwarzes Bild erzeugen
Barcode = zeros(Breite,Laenge,3);
% schwarzes Bild zu weiß konvertieren
for k=1:3
for i=1:Breite
for j=1:Laenge+(4*b_element+s_element)
Barcode(i,j,k)=255;
end
end
end
Hier nach wird als Anfangszeichen ein Sternchen gezeichnet. Das bilden der Striche übernehmen hierfür extra angelegte Funktionen. Darauf folgen abfragen welches Zeichen codiert werden muss. dementsprechen werden die Funktionen um Striche und Lücken zu bilden aufgerufen. Aus Gründen der Übersichtlichkeit wird nur die Abfrage für den Buchstaben A dargestellt.
% "*" als erstes Zeichen einfügen
%Startzeichen "*" einfügen
[xkoordinate,Barcode] = breit_luecke(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = breit_luecke(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = breit_luecke(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = breit_strich(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode,] = breit_strich(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
for i=1:length(eingabe)
%Bei Eingabe von A wird der Code generiert
if eingabe(i) == 'A'
[xkoordinate,Barcode] = breit_strich(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = breit_luecke(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_strich(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
[xkoordinate,Barcode] = breit_strich(xkoordinate,Barcode,b_element,Hoehe);
[xkoordinate,Barcode] = schmal_luecke(xkoordinate,Barcode,s_element,Hoehe);
end
Anschließend wird der Barcode abgespeichert und angezeigt
%% Dateiname erstellen
a{1} = eingabe;
a{2} = '.JPG';
Dateiname = [a{1} a{2}];
%% Barcode speichern
imwrite(Barcode,Dateiname)
Ausgabetext=['Erstellen und Speichern von ',Dateiname,' fertig gestellt'];
disp('-----------------------------------------------------------')
disp(Ausgabetext)
disp('-----------------------------------------------------------')
%%Barcode anzeigen
imshow(Barcode);
end
Implementierung Barcode lesen
Der zuvor erstellte Barcode kann über diese Executable über eine Webcam eingelesen werden. Wenn ein Barcode erkannt wurde, wird dieser decodiert, angezeigt und das Programm beendet. Für einen weiteren Scan kann die executable erneut gestartet werden.
Im folgenden soll die Funktionsweise kurz Zusammengefasst werden, Detailangaben finden sich als Kommentare im Quelltext. Zunächst wird das zu analysierende Bild eingelesen und in ein Schwarz/Weiss Bild umgewandelt. Danach sorgen verschiedene Filter zunächst dazu kleine Partikel zu enfernen. Größere Objekte die den Bildrand berühren werden ebenfalls entfernt.
%--------------------------------------------------------------------------
% Programmname: Barcode_aus_Webcam_lesen
% Version: 1.0.0
% Datum: 01.07.2018
% Beschreibung: Das Programm liest einen 1D Barcode in CODE39 Format
% mit einer Webcam ein und stellt die dahinter liegenden
% Informationen dar.
%
% Autor: Tobias Brandt
%
% INPUT: Webcambild (image)
%
% OUTPUT: Der entschlüsselte Barcode
%
%
%--------------------------------------------------------------------------
%% Initialisierung
clear all;
close all;
clear cam; % alte Videoverbindungen schließen
clc;
%% Kamera initialisieren
camList = webcamlist % Verfügbare Webcams auflisten
cam = webcam(1); % zur Webcam verbinden, Einstellungen anzeigen
%% Endlosschleife für das Kamerabild
while 1
image = snapshot(cam); %Bild von Kamera erstellen
B = rgb2gray(image); %umwandeln des Bilds in ein Graustufenbild
subplot(3,3,1); %Bild zur Kontrolle ausgeben
imshow(B);
title('Grau');
thresh = graythresh(B); % automatische Bestimmung eines Schwellenwertes, um Vorder- und Hintergrund zu unterscheiden
C = im2bw(B,thresh); % Umwandeln des Graustufenbildes in ein b/w-Bild
C = ~C; % Bild invertieren
subplot(3,3,2); % Bild zur Kontrolle ausgeben
imshow(C);
title('BW');
C = imclearborder(C,4); % alle zusammenhängende Objekte mit Kontakt zum rand werden '0' geschrieben
ThresholdBarcode = imfill(C,'holes'); % alle schwarzen Bereiche, die komlett von weißen Bereichen umgeben sind, auf weiß gesetzt und damit zu dem Objekt hinzugefügt
Nach dem Aufbereiten des Bilds wird ein Blob erzeugt um den Code einfach in dem Bild zu lokalisiern. Durch die darauf folgenden Berechnungen kann eine Zeile des Barcodes seperiert werden. Die Bloberkennung und die Barcodelokalisierung werden hier nicht erwähnt.
%% Hoehe des Barcodes ermitteln um die mittlere Zeile zu berechnen
% Y-Barcodekoordinate oben links erkennen
yoben=0; %Variable um die Y-Barcodekoordinate oben links zu speichern
for y=1:1:RowNum
for x=1:1:ColumNum
if image(y,x,1)==255
if yoben==0
yoben=y;
end
end
end
end
%Y-Barcodekoordinate unten links erkennen
yunten=0; %Variable um die Y-Barcodekoordinate unten links zu speichern
for y=RowNum:-1:1
for x=1:1:ColumNum
if image(y,x,1)==255
if yunten==0
yunten=y;
end
end
end
end
ylang=yunten-yoben; % Die Höhe des Barcodes berechnen
%% mittlere zeile aus dem schwarz-weiß Barcode in Zeile[] kopieren
mitte=round(yoben+ylang/2);
zeile=[];
if mitte>0
for i=1:1:ColumNum
zeile(i) = ThresholdBarcode(mitte,i);
end
end
Für die spätere Dekodierung wird aus der erkannten Zeile mit Binärzahlen ein Array erstellt in dem die Striche und Luecken erkannt wurden.
schmaler Strich = b breiter Strich = B schmale Lücke =w breite Lücke = W
%% gleiche bereiche Zählen
bereiche=[]; % Arraay für gleiche Bereiche
zaehler=0; % Zähler für die gleichen Bereiche
%gleiche aufeinanderfolgende pixel in einem Bereich zusammen fassen
for i=1:1:length(zeile)
if i<length(zeile)
if zeile(i)==zeile(i+1)
zaehler=zaehler+1;
else
zaehler=zaehler+1;
bereiche= [bereiche zaehler]; % aneinanderfügen der Bereiche in dem Array
zaehler=0;
end
end
end
% Der letzte weiße Bereich nach dem Barcode wird nicht abgespeichert, da
% der else Fall nicht eintritt. Deswegen braucht das letzte Element nicht
% gelöscht werden
if(length(bereiche))>0
bereiche(1)=[]; %erstes Element des Arrays löschen, da dies der weiße Bereich vor dem Barcode ist
end
%% breite der Striche festlegen
breit = max(bereiche); %größtes Element des Arrays ist der breiteste Strich
schmal = min(bereiche); % kleinstes Element des arrays ist der schmalste Strich
luecke = floor((breit-schmal)/2); % Als Hysterese wird der Zwischenbereich gleichermaßen für schmal und groß aufgeteilt
%%Striche in Array erkennen
%b= schmaler Strich; B= breiter Strich
%w= schmale Lücke; W= breite Lücke
striche=[]; %Array in dem die Kennzeichen für Lücke und Striche gespeichert werden
% Striche werden erkannt und durch b oder B an jeder geraden Stelle abgespeichert
% da der Code immer mit einem Strich beginnt und abwechselnd eine Lücke
% folgt
for i=1:2:(length(bereiche))
if (bereiche(i)>=schmal && bereiche(i)<=schmal+luecke)
striche(i)='b';
end
if (bereiche(i)>=breit-luecke && bereiche(i)<=breit)
striche(i)='B';
end
end
%Luecken in Array erkennen
for i=2:2:(length(bereiche))
if (bereiche(i)>=schmal && bereiche(i)<=schmal+luecke)
striche(i)='w';
end
if (bereiche(i)>=breit-luecke && bereiche(i)<=breit)
striche(i)='W';
end
end
Für die Erkennung der einzelnen zeichen muss eine Startbedingung definiert werden, da ansonsten ein Fehler der Matzrixdimension entstehen würde. Also erkennung wurden hier die beiden Sternchen am Anfang und am Ende, sowie die Strichanzahl verwendet.
%% Bedingung für Entziffern definieren
% Ein Code39 Barcode beginnt und endet immer mit einem '*'
% Deswegen wird eine Anfangsbedingung definiert, dass die beiden Sterne
% erkannt werden müssen, bevor die Dekodierung beginnt. So werden Fehler
% vermieden.
l=1; % Anfangswert wo das nächste Zeichen entschlüsselt wird
s=''; % variable für das einzelne erkannte Zeichen
Output=[]; % gesamter Output
kontrolle=0; % Startvariable für die Dekodierung
compare=[]; % Wert aus dem Array der verglichen werden soll
stern='bWbwBwBwb'; % Zeichenfolge für einen Stern als Strich und Lücke
if mod((length(striche)-19),10)==0 % Nur starten wenn die Strich und Lückenanzahl zwei Sterne lang und der Rest durch 10 teilbar ist, ansonsten fehlt etwas oder ist zu viel
for i=1:1:9
compare(i)=striche(i); % gucken ob die ersten 9 Zeichen einem Stern entsprechen
end
if compare == stern;
for i=length(striche)-8:1:length(striche) % gucken ob die letzten 9 Zeichen einem Stern entsprechen
compare(i-(length(striche)-9))=striche(i);
end
if compare == stern;
kontrolle=1; % wenn die Anfangsbedingung erfüllt ist, Startvariable auf '1' setzen
end
end
end
%% Einzelne Zeichen erkennnen
% für jedes Zeichen ist eine Lücken und Strichfolge vorgegeben. Diese wird
% mit der abfolge in dem Array verglichen und der dahinter liegende Wert
% als Output abgespeichert z.B. entspricht 'bWbwBwBwb' einen Stern
if kontrolle==1
for i=9:10:length(striche) % Das Strice Array im 10er Schritt durchlaufen, da ein Zeichen aus 5 Strichen und 5 Lücken besteht
if striche(l:i) == 'bWbwBwBwb'
s ='*';
elseif striche(l:i) == 'bwbWBwBwb'
s ='0';
Das entschlüsselte Zeichen wird in einem letzten Schritt in das Ausgabearray "OUTPUT" hinzugefügt und ausgegeben.
Verwendete Geräte
Für das Einlesen des Barcodes wurde die Webcam Logitec HD Webcam C310 verwendet. Die Videoauflösung beträgt 1.280 x 720 Pixel.
Beispielbilder
Folgende Bilder wurden mit dem Programm Barcode_erstellen erstellt.
-
(1)*HSHL*
-
(2)*TEST*
-
(3)*123456789*
-
(4)*ABCDEFGHIJKLMNOPQRSTUVWXYZ*
Für das Einlesen der Barcodes wurden diese ausgedruckt und teilweise mit Störungen versehen. Im folgenden sind einige davon dargestellt. Es wird immer der HSHL Barcode dargestellt. Die Störungen sind unter den Bildern beschrieben.
-
(1) original
-
(2) Text oben und unten
-
(3) Objekte rings herum
-
(4) Striche durch den Code
Youtube Video
Weblinks
- Wikipedia: Strichcode
- Barcodes for Mobile Devices
- Steffen Schulze Middendorf: Barcode erzeugen und lesen
- Mobile Tagging
- A New Method for Bar Code Localization and Recognition
- Barcode recognition
- Barcode Recognition Using Live Video Acquisition
- Universal Product Code - UPC
- Barcode Recognition
- YouTube: How Barcodes Work
Literatur
- Bernhard Lenk: Handbuch der automatischen Identifikation. Band 1-3: 2D-Codes, Matrixcodes, Stapelcodes, Composite Codes, Dotcodes. Lenk Monika Fachbuchverlag, Kirchheim unter Teck 2002, ISBN 978-3-935551-01-4.
- ten Hompel, M., u.A.: Identifikationssysteme und Automatisierung. Heidelberg: Springer, 2008. ISBN 978-3-540-75880-8
BSD-Lizenzbedingung BSD-Lizenz
Copyright (c) 2018, Hochschule Hamm-Lippstadt, Dep. Lip. 1, Prof. Schneider
Hochschule Hamm-Lippstadt. Alle Rechte vorbehalten.
→ zurück zum Hauptartikel: Digitale Signal- und Bildverarbeitung SoSe2018