QR-Code erzeugen und lesen
Autor: Hauke Ludwig
Betreuer: Prof. Schneider
Motivation
QR-Codes sind omnipräsent, aber wie codiert man Informationen als QR-Code?
Ziel
Erzeugen Sie ein Matlab Executable, welches aus einer eingegebenen URL einen QR-Code mit beliebigem Logo in der Mitte erzeugt.
Aufgabe
- Arbeiten Sie sich in die Erstellung von QR-Codes ein.
- Erzeugen Sie ein Matlab Executable, welches aus einer eingegebenen URL einen QR-Code mit beliebigem Logo in der Mitte erzeugt.
- Lesen Sie mit Matlab diesen QR-Code ein, so dass dieser Sie auf eine Webpage verlinkt.
Lösung
Vorbearbeitung
Als erser Schritt wird das zu verarbeitende Bild in ein Schwarz/Weiß-Bild konvertiert. Bei dieser Konvertierung werden gleichzeitig alle Bildelemente welche nicht einem Grauwert entsprechen eleminiert. Grauwertentsprechende Werte sind Werte, welche gleichmäßige Anteile an Rot-, Grün- und Blautanteile haben. Das Ergebnis der Eleminierung einzelner Pixel ist deutlich an den schwarzen Flecken im Grayscale-Bild zu erkennen.
Extrahierung
Die Extrahierung des QR-Codes aus dem Bild erfolgt anhand eines Box-Find-Algorithmus, welcher bereits in MatLab implementiert ist [1]
Code
%****************************************************************
% Hochschule Hamm-Lippstadt *
%****************************************************************
% Modul : QR Code Extractor *
% *
% Datum : 15-Jun-2014 *
% *
% Funktion : Extrahierung eines QR_Codes aus Bildern *
% *
% Implementation : MATLAB R2013a *
% *
% Author : Hauke Ludwig *
% *
% Letzte Änderung : 15-Jun-2014 *
% *
% Copyright (c) 2014, Hauke Ludwig *
% All rights reserved. *
%***************************************************************/
function [Pair] = extract (Image)
%% extract
% returns extracted QR-Code as bitfield from Image
% (as RGB-Matrix (uint8) width x heigh x RGB )
%% Defines
distSizeThresh = 10;
distPosThresh = 100;
distDensityThresh = 15;
diff_Density = 0.04;
Padding_Crop = 50;
%% Matrix
Pair = [0 0];
DensityPassed = [0 0 0];
%% Code
% Image Convertion
gray= rgb2gray(Image);
gray(~(abs(Image(:,:,1)-Image(:,:,2))+abs(Image(:,:,2)-Image(:,:,3))+abs(Image(:,:,1)-Image(:,:,3))<40))=0;
BW=~im2bw(Image,graythresh(Image));
BW(~(abs(Image(:,:,1)-Image(:,:,2))+abs(Image(:,:,2)-Image(:,:,3))+abs(Image(:,:,1)-Image(:,:,3))<40))=0;
cAll = edge(BW,'sobel','vertical')+edge(BW,'sobel','horizontal')+edge(gray,'sobel','horizontal')+edge(gray,'sobel','vertical');
%% DISPLAY RESULT
figure
subplot(2,4,1)
imshow(Image)
title('Source')
subplot(2,4,4)
imshow(cAll)
title('Canny')
subplot(2,4,2)
imshow(gray)
title('Grayscale')
subplot(2,4,3)
imshow(~BW)
title('Black/White')
%% Find boxes in image
stat = regionprops(logical(bwareaopen(cAll,100)),'boundingbox');
for cnt = 1 : numel(stat)
if stat(cnt).BoundingBox(3)/stat(cnt).BoundingBox(4)>0.5 && stat(cnt).BoundingBox(3)/stat(cnt).BoundingBox(4)<1.2 %like rectangle will be filtered
bb(cnt,:) = stat(cnt).BoundingBox;
else
bb(cnt,:)=[-1 -1 -1 -1];
end
end
bb(bb(:,:)==-1)=[];
bb=reshape(bb,size(bb,2)/4,4);
%% Calculate distance between Size of squares
distSize = sqrt(bsxfun(@minus,bb(:,3),bb(:,3)').^2 + bsxfun(@minus,bb(:,4),bb(:,4)').^2);
distSize(distSize(:,:)>distSizeThresh)=0;
%% Calculate distance between position of squares
distPos = sqrt(bsxfun(@minus,bb(:,1),bb(:,1)').^2 + bsxfun(@minus,bb(:,2),bb(:,2)').^2);
distPos(distPos(:,:)>distPosThresh)=0;
%% DISPLAY RESULT
subplot(2,4,6)
imshow(cAll)
title('Canny operated / equal square detection')
hold on
%% Filter boxes for euqal squares
for k=1:size(distSize,1)
for l=1:k
if distSize(k,l)~= 0 && size(find(distSize==distSize(k,l)),1)>=6
Pair(end+1,:)=[k l];
end
end
end
Pair(1,:)=[];
for k=1:size(Pair,1)
CropImage1=imcrop(cAll,bb(Pair(k,1),:));
Density(k,1)=sum(sum(size(find(CropImage1~=0),1)))/(bb(Pair(k,1),3)*bb(Pair(k,1),4));
CropImage2=imcrop(cAll,bb(Pair(k,2),:));
Density(k,2)=sum(sum(size(find(CropImage2~=0),1)))/(bb(Pair(k,2),3)*bb(Pair(k,2),4));
if abs(Density(k,1)-Density(k,2)) < diff_Density
if Density(k,1)<0.3 && Density(k,1)>0.1
rectangle('position',bb(Pair(k,1),:),'edgecolor','g','linewidth',2);
Padding_Crop = max([Padding_Crop bb(Pair(k,1),3:4)./1.1]);
if size(find(DensityPassed(:,1)==Pair(k,1)),1) == 0
DensityPassed(end+1,:)=[Pair(k,1) bb(Pair(k,1),1)+0.5*bb(Pair(k,1),3) bb(Pair(k,1),2)+0.5*bb(Pair(k,1),4)];
end
end
if Density(k,2)<0.3 && Density(k,2)>0.1
rectangle('position',bb(Pair(k,2),:),'edgecolor','g','linewidth',2);
Padding_Crop = max([Padding_Crop bb(Pair(k,1),3:4)]./1.1);
if size(find(DensityPassed(:,1)==Pair(k,2)),1) == 0
DensityPassed(end+1,:)=[Pair(k,2) bb(Pair(k,2),1)+0.5*bb(Pair(k,2),3) bb(Pair(k,2),2)+0.5*bb(Pair(k,2),4)];
end
end
end
end
if size(DensityPassed,1)>1
DensityPassed(1,:)=[];
end
if size(DensityPassed,1)>1
distDensity = sqrt(bsxfun(@minus,DensityPassed(:,2),DensityPassed(:,2)').^2 + bsxfun(@minus,DensityPassed(:,3),DensityPassed(:,3)').^2);
for k=1:size(distDensity,1)
for l=k+1:size(distDensity,2)
PairDensity(k,1)=k;
if distDensity(k,l) < distDensityThresh
if sum(sum(ismember(PairDensity(1:k-1,:),k))) ~= 0
PairDensity(k,:)=[];
for x=1:size(PairDensity,1)-1
if sum(ismember(PairDensity(x,:),k)) ~= 0 && sum(ismember(PairDensity(x,:),l)) == 0
PairDensity(x,end+1)= l;
end
end
else
PairDensity(k,end+1)= l;
end
end
end
if size(PairDensity,1) >= k
if sum(PairDensity(k,2:end)) == 0
PairDensity(k,:)=[];
end
end
end
Passed = [-1 -1];
for k=1:size(PairDensity,1)
if sum(PairDensity(k,2:end))>0 % Pair found
summean = [0 0];
count = 0;
for x=1:size(PairDensity,2)
if PairDensity(k,x) ~= 0
summean = [DensityPassed(PairDensity(k,x),2)+summean(1) DensityPassed(PairDensity(k,x),3)+summean(2)];
count = count +1;
end
end
Passed(end+1,:)=[summean(1)/count summean(2)/count];
else if PairDensity(k,1) ~= 0 % no Pair
Passed(end+1,:)= DensityPassed(PairDensity(k,1),2:3);
end
end
end
subplot(2,4,6)
plot(Passed(:,1),Passed(:,2),'*r');
Passed(1,:)=[];
%% Crop Image on Area of Interest
while size(Passed,1)>3
kick=mean(sqrt(bsxfun(@minus,Passed(:,1),Passed(:,1)').^2 + bsxfun(@minus,Passed(:,2),Passed(:,2)').^2));
Passed(find(kick==max(kick)),:)=[];
end
% get dynamic crop area
Padding_Crop=mean(mean(sqrt(bsxfun(@minus,Passed(:,1),Passed(:,1)').^2 + bsxfun(@minus,Passed(:,2),Passed(:,2)').^2)))/3.5;
minCrop = [min(Passed(:,1))-Padding_Crop min(Passed(:,2))-Padding_Crop];
maxCrop = [max(Passed(:,1))+Padding_Crop max(Passed(:,2))+Padding_Crop];
% grop image
cAllcropped = imcrop(Image, [minCrop maxCrop-minCrop]);
%% DISPLAY RESULT
subplot(2,4,5)
imshow(cAllcropped);
title('croped image from source')
normCropped = im2bw(cAllcropped);
subplot(2,4,7)
imshow(cAllcropped);
hold on
plot(Passed(:,1)-minCrop(1),Passed(:,2)-minCrop(2),'*r');
title('croped image from source with equal squares')
subplot(2,4,8)
imshow(normCropped);
hold on
plot(Passed(:,1)-minCrop(1),Passed(:,2)-minCrop(2),'*r');
title('croped image from black/white')
DensityPassed = [ DensityPassed(:,1) DensityPassed(:,2)-minCrop(1) DensityPassed(:,3)-minCrop(2)];
%% Find cornerpairs
cPair=sqrt(bsxfun(@minus,Passed(:,1),Passed(:,1)').^2 + bsxfun(@minus,Passed(:,2),Passed(:,2)').^2);
cPair(cPair(:,:)==0)=NaN;
minPair=min(cPair);
else
fprintf('Less equal Square to find a QR Code!\n');
end
end
Siehe auch
Weblinks
- QR Generator
- Open Source QR Code Generator
- Mobile Tagging
- YouTube: How to Decode a QR Code by Hand
- Wikipedia: QR Code
Einzelnachweis
→ zurück zum Hauptartikel: Digitale Signal- und Bildverarbeitung SoSe2014