SigSys15 Barcode erzeugen und lesen
Autor: Steffen Schulze Middendorf
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.
CODE39
Der CODE39 ist in der ISO/IEC 16388[1] spezifiziert, grundsätzlich besteht dieser aus Strichen und Lücken, jeweils in schmal und in breit.Es handelt sich um einen diskrten Code, das heisst jeder Buchstabe beginnt und endet mit einem Strich. Zwischen jedem Buchstaben findet sich zur Abgrenzung eine schmale Lücke. Jeder erzeugte Strichcode beginnt und endet mit einem Sternchen(*). Man spricht hier von einem Start/Stopp-Zeichen.
In der Tabelle rechts ist der gesamte verfügbare Zeichensatz dargestellt.
In der Standart Variante verfügt der CODE39 über keine Prüfziffern. Im folgenden sollen die Vor-und Nachteile stichpunktartig dargestellt werden.
Vorteile:
- realtiv einfach herzustellen und zu lesen
- hohe Drucktoleranzen akzeptabel
Nachteile:
- geringe Code Dichte
- keine Prüfsumme
Projektplan
Vorgang | Abgeschlossen bis |
---|---|
Semsterstart | KW10 / 2015 |
Themenauswahl | KW12 / 2015 |
Informationen sammeln | KW13 / 2015 |
Erzeugen von Barcode implementieren | KW15 / 2015 |
Funktionscheck - Erzeugen | KW17 / 2015 |
Lesen von Barcode implementieren | KW16 / 2015 |
Funktionscheck - Lesen | KW17 / 2015 |
Code Optimierung und Fehlerbehebung | KW18 / 2015 |
Kommentieren und dokumentieren abschließen | KW18 / 2015 |
Wiki-Artikel finalsieren | KW20 / 2015 |
Abgabe | KW25 / 2015 |
Implementierung Barcode erstellen
Die Funktion zum Erzeugen von Barcodes benötigt drei Eingaben. Den zu codierenden Text, sowie die Breiten der schmalen und Breiten Elemente. Ein Element bedeutet z.B. schmaler Strich oder breite Lücke. Grundsätzliches Vorgehen: Zunächst wird ein leeres Bild in der benötigten Länge erzeugt. Diese Länge resultiert direkt aus den Funktionsparametern. Danach wird der Eigabetext sukzessiv eingelesen und in die CODE39 Notation überführt. Jeder CODE39 Barcode startet und ended wie oben beschrieben mit einem Sternchen. Dieses wird automatisch hinzugefügt.
function barcode_erstellen(Eingabe,schmal,breit)
%%-------------------------------------------------------------------------
% PROGRAM: barcode_erstellen(Eingabe,schmal,breit)
% VERSION: 1.01
% DATE: 2015-05-02
% DESCRIPTION: Program creates user defiend barcodes in CODE39
% notation.
%
% AUTHOR: Steffen Schulze Middendorf
%
% INPUT: Eingabe: Type in what you want to transform into CODE39
% notation. Function works exclusively with
% capital letters and numbers.
% In addition: '-';'.';' ';'$';'/';'+';'%'
% schmal: Declare thickness of slender element in pixel
% breit: Declare thickness of a wide element in pixel
% pixel
%
% Relation between slender and wide have to be 1:2.
%
% OUTPUT: This progamm creates a new .JPG file in the program
% folder. Content of this image is the created barcode.
% Name of this file and data content of the barcode
% are the same. Each barcode starts and ends with a '*'
% automatically.
%
% EXAMPLE: barcode_erstellen('HSHL',50,100)
%
% DISCLAIMER: This program is freeware. Use at your own risk.
% Provided without any warranty
%--------------------------------------------------------------------------
%% Informationen einlesen und leeres Bild erstellen
%Größe des Barcodes in Pixel bestimmmen aus Anzahl Zeichen + Zusatzlücken
%+2 für START STOPP Zeichen -1 FÜR Lücke zum Schluss
Laenge=(6*schmal+3*breit)*(length(Eingabe)+2)+((length(Eingabe)+1)*schmal);
%Leeres schwarzes Bild(CODE39) in benötigter Breite und Höhe erstellen,
%Standarthöhe ist zehnfache breite eines breiten Elements.
CODE39 = zeros(10*breit,Laenge,3);
%Startpunkt in x festlegen(Pixelspalte)
Startpunkt=0;
%% Startzeichen, Eingabe und Endzeichen in CODE39 notation in leeres Bild einfügen
% Insgesamt besteht jeder CODE39 barcode aus 4 verschiedenen Elementen.
% Zur Erstellung jedes dieser Elemente existiert eine Erstellungsfunktion.
% schmal_strich(Startpunkt,Bild,schmal);
% schmal_luecke(Startpunkt,Bild,schmal);
% breit_luecke(Startpunkt,Bild,breit);
% breit_strich(Startpunkt,Bild,breit);
%Startzeichen "*" einfügen
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_luecke(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
%Jedes Zeichen beginnt mit einem Strich und endet mit einer schmalen Lücke
%Schleife durchläuft jedes einzelne Teichen der Eingabe und codiert es in
%die entsprechende Strich/Lücke Kombination. Nach CODE39 Standart.
for i=1:length(Eingabe)
if Eingabe(i) == '0'
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
%Jede Element-Erstellfunktion bekommt den bisherigen erstellten CODE
%die jeweiligen Paramter für breit und schmal sowie den Startpunkt
%für die Erstellung Ihres nächsen Elemements übergeben.
%Rückgabewerte sind der neue CODE und der neue Startpunkt.
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_luecke(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
end
if Eingabe(i) == '1'
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_luecke(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
end
.......
end
Zur besseren Übersicht wurde ein Teil des Codes entfernt. Letztlich wiederholen sich die IF-Abfragen und stellen jeweils einen Buchstaben da. Die Kombination von Strichen und Lücken wird direkt in das anfangs noch leere Bild übertragen.
%Endzeichen "*" einfügen
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_luecke(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = breit_strich(Startpunkt,CODE39,breit);
[Startpunkt,CODE39] = schmal_luecke(Startpunkt,CODE39,schmal);
[Startpunkt,CODE39] = schmal_strich(Startpunkt,CODE39,schmal);
%% Dateiname zusammensetzen aus Eingabetext und Endung '.JPG' und Bild auf Festplatte schreiben
%Dateiname zusammensetzen
a{1} = Eingabe;
a{2} = '.JPG';
Dateiname = [a{1} a{2}];
%Datei auf Festplatte schreiben
imwrite(CODE39,Dateiname)
Ausgabetext=['Generation and saving of ',Dateiname,' completed succesfully.'];
disp('-----------------------------------------------------------')
disp(Ausgabetext)
disp('-----------------------------------------------------------')
end
Letzlich wird ein neues Bild als .jpg im Funktionsordner auf die Festplatte geschrieben, der Dateiname einspricht der Eingabe beim Funktionsaufruf und enthält den erzeugten Barcode.
Exemplarisch noch der Inhalt einer verwendeten Funktionen hier breit_strich, der Aufbau der anderen drei Funktionen ist prinzipiell identisch:
function [Startpunkt,Bild] = breit_strich(Startpunkt,Bild,breit)
%Einfärben des aktiveren Bereichs ab Startpunkt bis Startpunkt plus
%Elementbreite
for k=1:breit
Bild(:,Startpunkt+k,1)=255;
Bild(:,Startpunkt+k,2)=255;
Bild(:,Startpunkt+k,3)=255;
end
%Berechnung des neuen Startpunkts
Startpunkt=Startpunkt+breit;
Jede Element-Erstellfunktion bekommt den bisherigen erstellten Code die jeweiligen Paramter für breit und schmal sowie den Startpunkt für die Erstellung Ihres nächsten Elemements übergeben. Rückgabewerte sind der neue Code und der neue Startpunkt für den nächsten Funktionsdurchlauf.
Implementierung Barcode lesen
function [Inhalt] = barcode_lesen(Barcode) %%------------------------------------------------------------------------- % PROGRAM: barcode_lesen(Barcode) % VERSION: 1.01 % DATE: 2015-05-02 % DESCRIPTION: Program reads user defiend barcodes in CODE39 % notation and is moderately fault tolerant. % % AUTHOR: Steffen Schulze Middendorf % % INPUT: Barcode: This progamm reads a '.JPG' file. % Content of this image have to be a barcode % in CODE39 notation. % % OUTPUT: Inhalt: Content of the barcode. % % EXAMPLE: barcode_lesen('C:\Users\HSHL.JPG') % % DISCLAIMER: This program is freeware. Use at your own risk. % Provided without any warranty %--------------------------------------------------------------------------
%% Bild einlesen und Filtern %Bild einlesen Barcode=imread(Barcode); %Umwandlung in Schwarz/Weiss Bild SWBarcode=~im2bw(Barcode); %Filter anwenden %Elemente kleiner 100 pixel löschen SWBarcode = bwareaopen(SWBarcode,100,8);
%Zerstörte Schwarze Striche wieder auffüllen Filterparameter = strel('square',9); SWBarcode = imclose(SWBarcode,Filterparameter);
%Faben wieder umkehren und kleine Striche entfernen SWBarcode=~SWBarcode; Filterparameter = strel('square',13); SWBarcode = imclose(SWBarcode,Filterparameter);
%% Anfang und Ende des Barcodes finden %Größe des eingelesenen Bildes feststellen Abmasse=size(SWBarcode); xmass=Abmasse(2); ymass=Abmasse(1); %Gesuchte Maße initialisieren yEnde=0; xEnde=0; yStart=0; xStart=0; CounterSchwarzePixel=0; Anfanggefunden=0; %Anfang des Barcodes finden in Y(Höhe), durch zählen der schwarzen Pixel %von oben beginnend
for i=1:ymass if Anfanggefunden==1 break end for k=1:xmass if SWBarcode(i,k)== 0 %Counter zählt schwarze Pixel um sicherzustellen das %nicht aufgrund eines nicht gefilterten schwarzen Pixels %der falsche Bereich ausgeschnitten wird CounterSchwarzePixel=CounterSchwarzePixel+1; end %Wenn Pixelcounter > 500 wird die Schleife abgebrochen und %und der yStart Wert gesichert if SWBarcode(i,k)== 0 && CounterSchwarzePixel > 10000 yStart=i; Anfanggefunden=1; break end end end
%Zurücksetzen der Zähler CounterSchwarzePixel=0; Anfanggefunden=0; %Ende des Barcodes finden in Y(Höhe), durch zählen der schwarzen Pixel von %unten beginnend for i=ymass:-1:1
if Anfanggefunden==1 break end for k=xmass:-1:1 if SWBarcode(i,k)== 0 CounterSchwarzePixel=CounterSchwarzePixel+1; %Counter zählt schwarze Pixel um sicherzustellen das %nicht aufgrund eines nicht gefilterten schwarzen Pixels %der falsche Bereich ausgeschnitten wird end %Wenn Pixelcounter > 500 wird die Schleife abgebrochen und %und der yStart Wert gesichert if SWBarcode(i,k)== 0 && CounterSchwarzePixel > 10000 yEnde=i; Anfanggefunden=1; break end end
end %Zurücksetzen der Zähler %Anfang des Barcodes finden in X(Länge) Anfanggefunden=0; for i=1:xmass
if Anfanggefunden==1 break end for k=yStart:yEnde if SWBarcode(k,i)== 0 xStart=i; Anfanggefunden=1; break end end
end %Ende des Barcodes finden in X(Länge) for i=1:xmass
for k=yStart:yEnde if SWBarcode(k,i)== 0 && i>xEnde xEnde=i; end end
end %% Barcode ausschneiden auf Bereich mit Code-Inhalt unter Berücksichtung der analysierten Anfang-Ende Maße CodeZentriert=SWBarcode(yStart:yEnde,xStart:xEnde); AbmasseZentriert = size(CodeZentriert); %Größe des neuen zentrierten Bildes feststellen xmassZ=AbmasseZentriert(2); ymassZ=AbmasseZentriert(1); %% Breite von breiten und schmalen Elementen herausfinden %Herausfinden wie breit (Pixel) ein breiter Strich ist %Initialisieren der gesuchten Variablen Breit=0; MaximalBreit=0; for i=1:xmassZ
if CodeZentriert(round(ymassZ/2),i) == 1 %Es wird so lange addiert wie durchgängig schwarze Pixel vorhanden %sind. Breit=Breit+1; end if CodeZentriert(round(ymassZ/2),i) == 0 %Sobald ein weißer Pixel unterbricht wird anaysiert ob es sich um %die längste Folge von schwarzen Pixeln gehandelt hat, wenn ja %wird die Länge in Maximalbreit gesichert. if Breit > MaximalBreit MaximalBreit=Breit; end Breit=0; end
end %Maximale Breite wird genutzt um auch die Breite des schmalen Elements %zu bestimmen Verhältnis 1:2 ist bekannt. Breit=MaximalBreit; Schmal=round(Breit/2); %Zugeschnittenes Bild anzeigen imshow(CodeZentriert) %% Toleranzen für Elemente festlegen %Toleranzen festlegen oT = obere Toleranz uT = unterere Toleranz %Breites Element oTBreit = round(Breit+Breit/3); uTBreit = round(Breit-Breit/3); %Schmales Element oTSchmal = round(Schmal+Schmal/3); uTSchmal = round(Schmal-Schmal/3); %% Code nacheinander einlesen und auswerten %Initialisieren der Variablen Breite=0; Ausgabe=[]; FarbeALT=0; Anfanggefunden=0; %Bild "CodeZentriert" durchlaufen und nach Elementen Strich/Lücke suchen %Anfang finden(wichtig für schräge codes) for i=1:xmassZ
Farbe=CodeZentriert((round(ymassZ/2)),i); if Anfanggefunden ~= 1 && Farbe==0 Anfanggefunden=1; end %Solange kein Farbwechsel stattfindet, Breiten aufaddieren if Anfanggefunden == 1 if Farbe==FarbeALT Breite=Breite+1; end %Wenn Farbwechsel stattfindet, vergleich um welches Element es %sich handelt unter Berücksichtung der Toleranzen %Schmaler Strich if Farbe ~= FarbeALT || i==xmassZ if (Breite>uTSchmal) && (Breite<oTSchmal) && (FarbeALT==1) %Ausgabe speichert ein Array mit den Zahlen 1,2,3,4 diese %stehen jeweils für ein Element Ausgabe=[Ausgabe 1]; end %Schmaler Strich if (Breite>uTSchmal) && (Breite<oTSchmal) && (FarbeALT==0) Ausgabe=[Ausgabe 2]; end %Breite Lücke if (Breite>uTBreit) && (Breite<oTBreit) && (FarbeALT==1) Ausgabe=[Ausgabe 3]; end %Breiter Strich if (Breite>uTBreit) && (Breite<oTBreit) && (FarbeALT==0) Ausgabe=[Ausgabe 4]; end Breite=1; FarbeALT=Farbe; end end
end k=0; q=0; Loesung=[]; Inhalt=[]; while numel(Ausgabe) > 0
if numel(Ausgabe) > 10 for k=1:10 %Immer 10 Zahlen(1,2,3,4) ergeben einen Buchstaben, daher %werden jetzt immer 10 aufeinander folgenden Zahlen zu einem %Lösungspaket zusammengechnürt Loesung=[Loesung Ausgabe(k)]; end for k=1:10 %Verwertete 10 Element löschen Ausgabe(1)=[]; end %Ausgabearray wird in den wahren Inhalt transformiert. Kombination %von 1,2,3,4 ergbit wieder ein Zeichen, dafür wird die Funktion %entschlüsseln genutzt [Zeichen] = entschluesseln(Loesung); %Zeichen wird in Inhalt(Ausgabearray) geschrieben Inhalt=[Inhalt Zeichen]; %Lösungsarray wieder leer setzen Loesung=[]; else %Wenn sich nur noch 10 Elemente im Ausgabe befindet wird noch einmal %der Inhalt von Ausgabe um 1(schmale Lücke) erweitert. Loesung=[Ausgabe 1]; [Zeichen] = entschluesseln(Loesung); Inhalt=[Inhalt Zeichen]; Ausgabe=[]; end
end end
Verbesserungvorschläge
Lessons learned
Beispielbilder
Siehe auch
Weblinks
- QR Generator
- Open Source QR Code Generator
- Mobile Tagging
- YouTube: How to Decode a QR Code by Hand
- Wikipedia: QR Code
→ zurück zum Hauptartikel: Signalverarbeitende Systeme SoSe2015