Augmented Reality: Wörterbuch
Autor: Christoph Wiegand
Betreuer: Prof. Schneider
Motivation
Word Lens ist ein geniales App, welches Schilder in alle Weltsprachen übersetzt.
Ziel
Programmieren Sie eine Schildererkennung und Übersetzung in Deutsch.
Aufgabe
- Erkennen Sie die Schrift auf den Schildern
- Ersetzen Sie diese Schrift perspektivisch durch eine passende deutsche Beschriftung im Videobild.
- Präsentieren Sie Ihr Ergebnis in der Form des Videos von Word Lense.
Lösung
Diese Lösung übersetzt Wörter in Beispielbildern. Diese Bilder zeigen rechteckige Schilder mit Text.
1.Schritt: Einlesen der Daten
Zuerst müssen alle benötigten Daten eingelesen werden. In dem Skrip "buchstaben_einlesen;" werden die Schwarz/Weiß Tamplates geladen. Die Grundlage für die Übersetzung stellt das Cell Array "vokabeln", da der Schwerpunkt der Aufgabe in der Bildverarbeitung besteht, wird eine Wort für Wort Übersetzung angewendet.
%% Bild und Daten einlesen
buchstaben_einlesen;
load ('vokabeln.mat') ;
bild_org = imread('IMAG0460.jpg'); % Einlesen des Bildes
2.Schritt: Vorbereiten der Daten
Unter der Annahme eines rechteckigen Schildes welches sich gut von der Umgebung abhebt kann das Bild auf ein Kantenbild reduziert werden. Mit Hilfe dieser Reduzierung und der Trennung vom Hintergrund werden die Schild Informationen hervorgehoben.
%% Bilddaten umwandeln Ergebnis = Kanten Bild
bild_grau = rgb2gray(bild_org); % umwandeln des Bildes in ein Graustufenbild
bild_grau= imadjust(bild_grau); % Kontrast erhöhen
thresh = graythresh(bild_grau); % automatische Bestimmung eines Schwellenwertes, um Vorder- und Hintergrund zu unterscheiden
bild_bw = im2bw(bild_grau,thresh); % Umwandeln des Graustufenbildes in ein b/w-Bild in Abhängigkeit des vorherbestimmten Schwellenwertes
bild_bw_canny = edge(bild_bw, 'Canny'); % Kantenbild durch Canny
3.Schritt: Wichtige Region finden
Alle Regionen im Kantenbild, die von Weiß umgeben sind werden auf Weiß (1) gesetzt.Danach werden zu kleine Regionen gelöscht und das Bild erneut gefüllt. Danach werden die Informationen der noch übrigen Regionen gespeichert.
%% Roi erzeugen / finden und Bild reduzieren
bild_bw_roi = imfill(bild_bw_canny,'holes');% Hier werden alle schwarzen Bereiche, die komplett von weißen Bereichen umgeben sind, auf weiß gesetzt und damit zu dem Objekt hinzugefügt
bild_bw_roi = bwareaopen(bild_bw_roi,6000,4);
bild_bw_roi = imfill(bild_bw_roi,'holes');
bild_grau_roi = bild_grau .* uint8(bild_bw_roi);% Graubild auf ROI reduzieren
stats = regionprops(bild_bw_roi); % weiße Regionen finden
4.Schritt: Entzerrung der RoI
Bei der Entzerrung der Perspektive des Bildes ergab sich folgendes Problem: Die gefunden Bereiche haben abgerundete Ecken. Dadurch ist es nicht möglich die Ecken mit Hilfe der "Corner detection" zu finden. Diese Ecken sind notwendig um die Entzerrung der RoI durchführen zu können. Ansatz: Schnittpunkte der Geraden des Kantenbildes der Roi. Für die Bestimmung der Transformationsmatrix werden 4 Punkte im verzerrten Bild(siehe Ansatz oben) und die zugehörigen 4 Punkte im unverzerrten Bild benötigt. Da diese nicht bekannt und auch die Abmessungen des Schildes nicht gegeben sind, werden diese 4 Punkte als Eckpunkte der umgebenden BoundingBox (vgl.Abb RoI mit BoundingBox) angenommen.
%% Transformation / Entzerung des Bildes
bild_bw_roi_sobel = edge(bild_bw_roi,'Sobel'); % kanten der RoI
% Koordinaten der BoundingBox Ecken ergeben die unverzerrte Ecken --> Näherung an die Originalgröße des Schildes da nicht bekannt
% Oben Links Ecke
corner_Bb{1} = [stats(1).BoundingBox(1,1),stats(1).BoundingBox(1,2)];
% oben Rechts Ecke
corner_Bb{2} = [stats(1).BoundingBox(1,1)+stats(1).BoundingBox(1,3) ,stats(1).BoundingBox(1,2)];
% Unten Rechts Ecke
corner_Bb{3} = [stats(1).BoundingBox(1,1)+stats(1).BoundingBox(1,3),stats(1).BoundingBox(1,2)+stats(1).BoundingBox(1,4)];
% Unten Links Ecke
corner_Bb{4} = [stats(1).BoundingBox(1,1),stats(1).BoundingBox(1,2)+stats(1).BoundingBox(1,4)];
% Geraden erzeugen um Ecken in der Perspektive zu berechnen
[H,theta,rho] = hough(bild_bw_roi_sobel); % Hough Transformation
P = houghpeaks(H,5,'threshold',ceil(0.2*max(H(:)))); % in der Hough Transformation Maxima finden
lines = houghlines(bild_bw_roi_sobel,theta,rho,P,'FillGap',150,'MinLength',20); % Linen finden
Um auszuschließen, dass durch die Hough Transformation Geraden gefunden, werden die die gleiche Linie beschreiben (vgl. Abb. oben), müssen sobald mehr als 4 Geraden erkannt werden, "doppelte" aussortiert werden.
% Parallelen finden doppelte Linien aussortieren
if (size(lines,2)>4)
for cnt = 1 : size(lines,2)
lines_diff(cnt) = abs(lines(cnt).rho) - abs(lines(cnt).theta); % Differenz erstellen um Gleich gerichtete Linien zu finden
end
for cnt = 1 : size(lines,2)
for cnt2 = cnt : size(lines,2)
lines_diff_each(cnt2,cnt)=min(abs(lines_diff(cnt)-lines_diff(cnt2))); % Alle Differenzen von einander Abziehen um Ähnlichkeit zu finden
end
end
[lines_diff_row,lines_diff_colum ]= find (lines_diff_each<40&lines_diff_each>0); % Doppelte linen löschen
lines(lines_diff_row)=[];
end
for cnt = 1 : size(lines,2)
lines_theta(cnt) = lines(cnt).theta ; % theta ist der Winkel zur Achse bei ähnlichem winkel sind die Linien Paralle
end
[b,ix] = sort(lines_theta);% Nach Größe sotieren
% Ecken berechnen aus den Schnittpunkten
corner{4} = schneide ([lines(ix(2)).point1(1,1);lines(ix(2)).point1(1,2)],...
[lines(ix(2)).point2(1,1);lines(ix(2)).point2(1,2)],...
[lines(ix(3)).point1(1,1);lines(ix(3)).point1(1,2)],...
[lines(ix(3)).point2(1,1);lines(ix(3)).point2(1,2)]);
corner{1} = schneide ([lines(ix(1)).point1(1,1);lines(ix(1)).point1(1,2)],...
[lines(ix(1)).point2(1,1);lines(ix(1)).point2(1,2)],...
[lines(ix(3)).point1(1,1);lines(ix(3)).point1(1,2)],...
[lines(ix(3)).point2(1,1);lines(ix(3)).point2(1,2)]);
corner{2} = schneide ([lines(ix(1)).point1(1,1);lines(ix(1)).point1(1,2)],...
[lines(ix(1)).point2(1,1);lines(ix(1)).point2(1,2)],...
[lines(ix(4)).point1(1,1);lines(ix(4)).point1(1,2)],...
[lines(ix(4)).point2(1,1);lines(ix(4)).point2(1,2)]);
corner{3} = schneide ([lines(ix(2)).point1(1,1);lines(ix(2)).point1(1,2)],...
[lines(ix(2)).point2(1,1);lines(ix(2)).point2(1,2)],...
[lines(ix(4)).point1(1,1);lines(ix(4)).point1(1,2)],...
[lines(ix(4)).point2(1,1);lines(ix(4)).point2(1,2)]);
Die Funktion transformation_Ecken bekommt die Ecken der BoundingBox und die Ecken der verzerrten RoI übergeben. Aus diesen wird die Transformationsmatrix und die inverse Transformationsmatrix berechnet. Diese Funktion basiert auf dieser Quelle [1] aus dem Matlab File Exchange. Eine genauere Herleitung findet sich in dem Vorlesungsskript der Universität Münster. [ http://cvpr.uni-muenster.de/teaching/ss09/computerVisionSS09/script/CV14-Kalibrierung.pdf]
[T,invT] = transformation_Ecken (corner_Bb,corner); % Umrechnung der gegebenen Ecken in Transformationstrukturen
bild_rgb_entzert =imtransform(bild_org,T,'XData',[1 size(bild_org,2)],'YData',[1 size(bild_org,1)]);% Transformation des Bildes
bild_grau_entzert = rgb2gray(bild_rgb_entzert);
bild_bw_entzert = im2bw(bild_grau_entzert,thresh);
5.Schritt: Texterkennung , Übersetzung und Reintegration
%% Text erkennung im entzerten Bild / Übersetzung und einfügen der Übersetzung ins Bild
text = ocr(bild_rgb_entzert,stats(1).BoundingBox); % Sucht nach Schrift in der ROI
schrift = text.Text;
Um die gefunden Wörter zu ersetzen müssen diese verdeckt werden. Jede gefundene Wortboxen wird mit schwarz (0) gefüllt
for cnt = 1 : size(text.Words)
vokabel_englisch = text.Words(cnt,1);
% Im Wörterbuch nach Vokabel suchen
vokabel_ind = find(ismember(vokabeln,vokabel_englisch));
if vokabel_ind > 0
if vokabel_ind < size(vokabeln,1)
% Vokabel einfügen wenn im Wörter Buchvorhanden
vokabel_laenge = size (vokabeln{vokabel_ind,2},2);
% Länge der Übersetzung bestimmen umGröße der Buchstaben zu berechen
uebersetzungs_laenge = size (vokabeln{vokabel_ind,2},2);
% Größe der Buchstaben ind der breite berechen / Höhe übernehmen
breite_buchstaben = floor(text.WordBoundingBoxes(cnt,3)/uebersetzungs_laenge);
hoehe_buchstaben= text.WordBoundingBoxes(cnt,4);
% Bereich der Alten Wörter überdeken
% im BW Bild
bild_bw_entzert(text.WordBoundingBoxes(cnt,2):(text.WordBoundingBoxes(cnt,2)+text.WordBoundingBoxes(cnt,4)),...
text.WordBoundingBoxes(cnt,1):(text.WordBoundingBoxes(cnt,1)+text.WordBoundingBoxes(cnt,3)))= 0;
bild_grau_entzert = bild_grau_entzert.* uint8(bild_bw_entzert);
Die gefundenen Wörter werden 1 zu 1 in dem Wörterbuch (vokabeln) nachgeschlagen. Die gefundene Übersetzung wird in der breite der Buchstaben auf die breite der Buchstaben des alten Wortes angepasst. Diese werden dann in die geschwärzten Bereiche eingefügt.
% Vokabel ins Bild einfügen
for cnt2 = 1 : vokabel_laenge
bild_buchstabe_ind = find(ismember(buchstabe(:,1),vokabeln{vokabel_ind,2}(cnt2)));
if bild_buchstabe_ind > 0
% Buchstaben auf Größe anpassen
buchstabe_uebersetzung = imresize(buchstabe{bild_buchstabe_ind,2},[hoehe_buchstaben breite_buchstaben]);
% Buchstaben ins Bild integrienen
bild_bw_entzert(text.WordBoundingBoxes(cnt,2):(text.WordBoundingBoxes(cnt,2)+hoehe_buchstaben)-1,...
text.WordBoundingBoxes(cnt,1)+cnt2*breite_buchstaben-breite_buchstaben:(text.WordBoundingBoxes(cnt,1)+cnt2*breite_buchstaben)-1)=buchstabe_uebersetzung;
% Buchstaben ins Bild integrienen
bild_grau_entzert(text.WordBoundingBoxes(cnt,2):(text.WordBoundingBoxes(cnt,2)+hoehe_buchstaben)-1,...
text.WordBoundingBoxes(cnt,1)+cnt2*breite_buchstaben-breite_buchstaben:(text.WordBoundingBoxes(cnt,1)+cnt2*breite_buchstaben)-1)= 255 * uint8(buchstabe_uebersetzung);
end
end
end
end
end
6.Schritt:Rücktransformation
%% Rücktransformation und anpassen des Bildes
bild_grau_verzert =imtransform(bild_grau_entzert,invT,'XData',[1 size(bild_org,2)],'YData',[1 size(bild_org,1)]); % rücktransformation des BW Bildes
Siehe auch
Weblinks
- YouTube: Introducing Word Lens
- Automatically Detect and Recognize Text in Natural Images - Matlab R2014a
→ zurück zum Hauptartikel: Digitale Signal- und Bildverarbeitung SoSe2014