SigSys15 Stereo-View: Unterschied zwischen den Versionen
(14 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 23: | Zeile 23: | ||
== HARDWARE-KOMPONENTEN == | == HARDWARE-KOMPONENTEN == | ||
[[Datei:3D-Webcam.jpg|right|thumb|Abbildung 1: Verschiedene Ansichten der "3D-Webcam"]] | |||
Für den Aufbau des stereoskopischen Systems wurden zwei gleiche Webcams (Watson, Modell CAM-M130) verwendet. | Für den Aufbau des stereoskopischen Systems wurden zwei gleiche Webcams (Watson, Modell CAM-M130) verwendet. | ||
Die Webcams wurden nahezu parallel, auf einem Plastikdeckel, aufgebaut, siehe Abbildung 1. Der Seitliche Abstand der Webcams beträgt 11,2 cm. | Die Webcams wurden nahezu parallel, auf einem Plastikdeckel, aufgebaut, siehe Abbildung 1. Der Seitliche Abstand der Webcams beträgt 11,2 cm. | ||
== SOFTWARE == | == SOFTWARE == | ||
Zeile 35: | Zeile 33: | ||
Für die Aufnahme der Bilder für die Kalibrierung soll die Datei bilderFuerKalibrie-rung.m ausgeführt werden. | Für die Aufnahme der Bilder für die Kalibrierung soll die Datei bilderFuerKalibrie-rung.m ausgeführt werden. | ||
Dabei werden in der Zeile 4, | Dabei werden in der Zeile 4, | ||
<source lang="matlab"> | |||
camL = webcam(1); camR = webcam(2); | |||
</source> | |||
die Webcams initialisiert und in Zeile 6 wird die Auflösung der Bilder auf 1280 x 960 geändert. | die Webcams initialisiert und in Zeile 6 wird die Auflösung der Bilder auf 1280 x 960 geändert. | ||
Anschließend werden die erforderlichen Bilder aufgenommen | Anschließend werden die erforderlichen Bilder aufgenommen | ||
<source lang="matlab"> | |||
linkesBild = snapshot(camL); rechtesBild = snapshot(camR); | |||
</source> | |||
und in dem Zielorder gespeichert. | und in dem Zielorder gespeichert. | ||
<source lang="matlab"> | |||
imwrite(linkesBild, fullfile('LinkesAuge', sprintf('left%02d.png', i))); | |||
imwrite(rechtesBild, fullfile('RechtesAuge', sprintf('right%02d.png', i))); | imwrite(rechtesBild, fullfile('RechtesAuge', sprintf('right%02d.png', i))); | ||
</source> | |||
Durch die While-Schleife kann der Benutzer die Anzahl der Aufnahmen bestimmen. Es empfiehlt sich eine Mindestanzahl von 10 Bildern (im Programm sind mindestens 10 Bilder erforderlich). | Durch die While-Schleife kann der Benutzer die Anzahl der Aufnahmen bestimmen. Es empfiehlt sich eine Mindestanzahl von 10 Bildern (im Programm sind mindestens 10 Bilder erforderlich). | ||
=== Kalibrierung des Kamerasystems === | === Kalibrierung des Kamerasystems === | ||
[[Datei:Kalibrierung.jpg|right|thumb|Abbildung 2: Anzeige der gefundenen Schachbrettmuster im Bild."]] | |||
[[Datei:Kalibrierung2.jpg|right|thumb|Abbildung 3: Durchgeführte Kalibrierung und die Bestimmung der Umgebung."]] | |||
Um die Kalibrierung zu initiieren ist es zunächst einmal erforderlich die Bilder für die Kalibrierung zu laden. Hierbei wird der Nutzer nach dem Ordner gefragt indem sich die Bilder, zunächst von der linken Webkamera und anschließen von der rechten Webkamera, befinden. | Um die Kalibrierung zu initiieren ist es zunächst einmal erforderlich die Bilder für die Kalibrierung zu laden. Hierbei wird der Nutzer nach dem Ordner gefragt indem sich die Bilder, zunächst von der linken Webkamera und anschließen von der rechten Webkamera, befinden. | ||
Nachdem die Quellorder definiert wurden, werden aus den Ordnern alle Bilddateien mit der Endung PNG geladen (Zeile 30 bis 35) und die Anzahl der Bilder im jeweili-gen Ordner wird definiert (Zeiele 38 und 39). | Nachdem die Quellorder definiert wurden, werden aus den Ordnern alle Bilddateien mit der Endung PNG geladen (Zeile 30 bis 35) und die Anzahl der Bilder im jeweili-gen Ordner wird definiert (Zeiele 38 und 39). | ||
In der Zeile 42 wird überprüft ob sich in dem Ordner mindestens 10 Bilder befinden. Enthält einer der beiden Ordner weniger als 10 PNG-Dateien wird der | In der Zeile 42 wird überprüft ob sich in dem Ordner mindestens 10 Bilder befinden. Enthält einer der beiden Ordner weniger als 10 PNG-Dateien wird der Programmverlauf abgebrochen und die Fehlermeldung „Achtung!!! Die Anzahl der Bilder ist für die Kalibrierung nicht ausreichend!“ erscheint im Matlab Command Window. | ||
Die Matlab Funktion detectCheckerboardPoint sucht das Bild nach einem Schach-brettmuster ab und liefert die Postition des Schachbretts im Bild, sowie die Schach-brettgröße und die Anzahl der verwendeten Bilder für die suche des Schachbretts. Dabei erwartet die Funktion detectCheckerboardPoint die Pfade der Bilder als Einga-beparameter. | Die Matlab Funktion detectCheckerboardPoint sucht das Bild nach einem Schach-brettmuster ab und liefert die Postition des Schachbretts im Bild, sowie die Schach-brettgröße und die Anzahl der verwendeten Bilder für die suche des Schachbretts. Dabei erwartet die Funktion detectCheckerboardPoint die Pfade der Bilder als Einga-beparameter. | ||
Anschließend wir überprüft ob ein Schachbrett gefunden wurde. Falls die Funktion kein Schachbrett im Bild gefunden hat wird der weitere Verlauf mit der | Anschließend wir überprüft ob ein Schachbrett gefunden wurde. Falls die Funktion kein Schachbrett im Bild gefunden hat wird der weitere Verlauf mit der Fehlermeldung '''„Achtung!!! Es wurde kein Schachbrettmuster erkannt!“''' abgebrochen. | ||
Ab der Zeile 91 bis 114 werden die verwendeten Bilder für die detectCheckerboard-Point Funktion geladen und angezeigt, siehe Abbildung | Ab der Zeile 91 bis 114 werden die verwendeten Bilder für die detectCheckerboard-Point Funktion geladen und angezeigt, siehe Abbildung 2. | ||
Dabei wird in das geladen Bild das erkannte Schachbrett kenntlich gemacht und der Nutzer muss entscheiden ob das gefundene Schachbrett dem tatsächlichen Schach-brett entsprich oder ob es sich um einen Fehler handelt. Die Abfrage hierzu erfolgt in der Ziele 120 | Dabei wird in das geladen Bild das erkannte Schachbrett kenntlich gemacht und der Nutzer muss entscheiden ob das gefundene Schachbrett dem tatsächlichen Schach-brett entsprich oder ob es sich um einen Fehler handelt. Die Abfrage hierzu erfolgt in der Ziele 120 | ||
<source lang="matlab"> | |||
(abfrageOK = input('\n\nWurde das Schachbrettmuster richtig erkannt? JA/NEIN\n', 's');) | |||
</source> | |||
mithilfe der Eingabe im Matlab Command Window. | mithilfe der Eingabe im Matlab Command Window. | ||
Sollte das Schachbrett dem tatsächlichen Schachbrett entsprechen, so werden in der Zeile 149 die Kameraparameter bestimmt. Bevor die Kameraparameter bestimmt werden können, muss zunächst in der Zeile 143 die Kantenlänge der Schachbrettfel-der definiert werden um in der Zeile 146 die Koordinaten der Schachbrettfelder, unter Zuhilfenahme der Matlab-Funktion generateCheckerboardPoints, in der realen Welt zu bestimmen. | |||
Anschließend werden ab der Zeile 152 die Pixel-Abweichungen und die Umgebung zum Zeitpunkt der Aufnahme der Bilder zur Kalibrierung simuliert, siehe Abbildung 3. | |||
=== Bestimmung der Position, der erkannten Objekte in der | === Bestimmung der Position, der erkannten Objekte in der realen Welt === | ||
[[Datei:3D-Bild.png|right|thumb|Abbildung 4: 3D-Projektion der Bilder und die Darstellung der Objekte in Weltkoordinaten]] | |||
Nachdem die Kalibrierung des Kamerasystems erfolgt ist, und die Funktion „kalibrierung“ verlassen wurde schauen wir uns wieder die stereoview.m an. Zunächst werden zwei aktuelle Kamerabilder geladen (Zeile 37 bis 44) oder zwei Standbilder (Zeile 46 und 47). Das laden der Kamerabilder ist analog der Aufnahme der Bilder für die Ka-librierung (siehe Aufnahme der erforderlichen Bilder zur Kalibrierung). | Nachdem die Kalibrierung des Kamerasystems erfolgt ist, und die Funktion „kalibrierung“ verlassen wurde schauen wir uns wieder die stereoview.m an. Zunächst werden zwei aktuelle Kamerabilder geladen (Zeile 37 bis 44) oder zwei Standbilder (Zeile 46 und 47). Das laden der Kamerabilder ist analog der Aufnahme der Bilder für die Ka-librierung (siehe Aufnahme der erforderlichen Bilder zur Kalibrierung). | ||
Anschließend werden die geladenen Bilder berichtigt (Zeile 54) und als Anaglyphen-Bilder dargestellt (siehe Abbildung | Anschließend werden die geladenen Bilder berichtigt (Zeile 54) und als Anaglyphen-Bilder dargestellt (siehe Abbildung 4). | ||
Die Berichtigung der Bilder erfolgt mithilfe der Matlab-Funktion „rectifyS-tereoImages“. Diese korrigiert die Bilder anhand der Kameraparameter. | Die Berichtigung der Bilder erfolgt mithilfe der Matlab-Funktion „rectifyS-tereoImages“. Diese korrigiert die Bilder anhand der Kameraparameter. | ||
Anschließend wird ab der Zeile der Sichtbereich der Kamera eingestellt und er wer-den die Objekte in dem Weltkoordinaten-System dargestellt (siehe Abbildung | Anschließend wird ab der Zeile der Sichtbereich der Kamera eingestellt und er wer-den die Objekte in dem Weltkoordinaten-System dargestellt (siehe Abbildung 4). | ||
== Quellcode - Aufnahme der Bilder für die Kalibrierung == | |||
<source lang="matlab"> | |||
clear all; close all; clc; | |||
% Webcams laden | |||
camL = webcam(1); camR = webcam(2); | |||
% Auflösung einstellen | |||
camL.Resolution = '1280x960'; camR.Resolution = '1280x960'; | |||
% Laufvariable | |||
i = 1 | |||
nachstesBild = 'nein'; | |||
while ~strcmpi(nachstesBild,'n') | |||
% Bild machen | |||
linkesBild = snapshot(camL); rechtesBild = snapshot(camR); | |||
% Bild speichern | |||
imwrite(linkesBild, fullfile('LinkesAuge', sprintf('left%02d.png', i))); | |||
imwrite(rechtesBild, fullfile('RechtesAuge', sprintf('right%02d.png', i))); | |||
% Abfrage ob das Schachbrettmuster richtig erkannt wurde | |||
nachstesBild = input('\n\nSoll noch ein Bild aufgenommen werden? JA/NEIN\n', 's'); | |||
i = i + 1 | |||
end | |||
</source> | |||
== Quellcode - Hauptprogramm == | |||
<source lang="matlab"> | |||
%% Dieses Matlab-Programm wurde im Rahmen der Veranstalltung | |||
% Signalverarbeitende Systeme bei Prof. Ulricht Schneider erstellt. Das | |||
% Programm kalibriert zwei Webcams und erzeugt anschließend ein 3D-Bild. | |||
% Die genau Aufgabenstellung sowie die Beschreibung kann unter dem | |||
% folgendem Link nachgelesen werden. http://193.175.248.171/wiki/index.php/SigSys15_Stereo-View | |||
%**************************************************************** | |||
% Hochschule Hamm-Lippstadt * | |||
%**************************************************************** | |||
% Modul : StereoView * | |||
% * | |||
% Datum : 31-Mai-2015 * | |||
% * | |||
% Funktion : siehe Oben * | |||
% * | |||
% Implementierung: MATLAB R2015a * | |||
% * | |||
% Notw. Toolbox : Image Processing Toolbox * | |||
% * | |||
% Author : Miladin Ceranic * | |||
% * | |||
% Bemerkung : Projektaufgabe - Signalverarbeitende Systeme * | |||
% * | |||
% Letzte Änderung: 19. Juni 2015 * | |||
% * | |||
%***************************************************************/ | |||
% Workspace löschen, offene Fenster schließen und Command Window leeren | |||
clear all; close all; clc; | |||
%% Definition benötigter Variablen | |||
abfrageOK = 'UNDEFINED'; | |||
%% Kamera kalibrieren | |||
kalibrierung | |||
% Kamera starten | |||
% camL = webcam(1); camR = webcam(2); | |||
% | |||
% % Auflösung der Kamera einstellen | |||
% camL.Resolution = '1280x960'; camR.Resolution = '1280x960'; | |||
% | |||
% linkesBild = snapshot(camL); rechtesBild = snapshot(camR); | |||
% imwrite(linkesBild, 'linkesBild.jpg'); imwrite(rechtesBild, 'rechtesBild.jpg'); | |||
linkesBild = imread('linkesBild.jpg'); | |||
rechtesBild = imread('rechtesBild.jpg'); | |||
%% Bilder laden und in 3D (anaglyphen) anzeigen | |||
bildVorherLA = linkesBild; | |||
bildVorherRA = rechtesBild; | |||
% Bilder optimieren | |||
[bildNachherLA, bildNachherRA] = rectifyStereoImages(linkesBild, rechtesBild, kameraParameter);%,'OutputView','full'); | |||
% 3D-Bild anzeigen vor und nach der Kalibrierung | |||
handle3D = figure('Name','3D Vorschau','NumberTitle','off'); | |||
% Vor der Bearbeitung | |||
handleVorher = subplot(2,2,1); | |||
imshow(stereoAnaglyph(bildVorherLA, bildVorherRA), 'InitialMagnification', 50); | |||
hold on; | |||
title('Vor der Berichtigung'); | |||
% Nach der Bearbeitung | |||
handleNachher = subplot(2,2,2); | |||
imshow(stereoAnaglyph(bildNachherLA, bildNachherRA), 'InitialMagnification', 50); | |||
hold on; | |||
title('Nach der Berichtigung'); | |||
% Ungleichheiten in den Bildern | |||
disparityMap = disparity(rgb2gray(bildNachherLA), rgb2gray(bildNachherRA)); | |||
handleDisparity = subplot(2,2,3); | |||
imshow(disparityMap, 'InitialMagnification', 50); | |||
colormap('jet'); | |||
colorbar; | |||
title('Disparity Map'); | |||
% Reconstruct the 3-D world coordinates of points corresponding to each | |||
% pixel from the disparity map. | |||
pointCloud = reconstructScene(disparityMap, kameraParameter); | |||
pointCloud = pointCloud / 10; | |||
% Anzeigebereich einstellen | |||
handleRek = subplot(2,2,4); | |||
% Anzeige einstellen | |||
% X-Achse | |||
x = pointCloud(:, :, 1); | |||
% maxX = 150; minX = -150; | |||
% xdisp = x; | |||
% xdisp(x < minX | x > maxX) = NaN; | |||
% Y-Achse | |||
y = pointCloud(:, :, 2); | |||
% maxY = 70; minY = -70; | |||
% ydisp = y; | |||
% ydisp(y < minY | y > maxY) = NaN; | |||
% Z-Achse | |||
z = pointCloud(:, :, 3); | |||
% maxZ = 700; minZ = 300; | |||
% zdisp = z; | |||
% zdisp(z < minZ | z > maxZ) = NaN; | |||
% point3Ddisp = pointCloud; | |||
point3Ddisp(:,:,1) = x;%disp; | |||
point3Ddisp(:,:,2) = y;%disp; | |||
point3Ddisp(:,:,3) = z;%disp; | |||
imwrite(bildNachherLA, 'linkesBild1.jpg') | |||
imwrite(bildNachherRA, 'rechtesBild1.jpg') | |||
showPointCloud(point3Ddisp, bildNachherLA, 'VerticalAxis', 'Y',... | |||
'VerticalAxisDir', 'Down' ); | |||
xlabel('X in mm'); | |||
ylabel('Y in mm'); | |||
zlabel('Z in mm'); | |||
</source> | |||
== Quellcode - Kalibrierung der Kamera == | |||
<source lang="matlab"> | |||
%**************************************************************** | |||
% Hochschule Hamm-Lippstadt * | |||
%**************************************************************** | |||
% Modul : Kalibrierung der Kameras * | |||
% * | |||
% Datum : 31-Mai-2015 * | |||
% * | |||
% Funktion : siehe Oben * | |||
% * | |||
% Implementierung: MATLAB R2015a * | |||
% * | |||
% Notw. Toolbox : Image Processing Toolbox * | |||
% * | |||
% Author : Miladin Ceranic * | |||
% * | |||
% Bemerkung : Projektaufgabe - Signalverarbeitende Systeme * | |||
% * | |||
% Letzte Änderung: 19. Juni 2015 * | |||
% * | |||
%***************************************************************/ | |||
%% Kalibrieren der Kameras | |||
% Auswahl des Pfads aufgenommener Bilder für das linke Auge | |||
pfadOrdnerLA = 'LinkesAuge'; %uigetdir('','Ordner mit Bildern für das linke Auge auswählen!'); | |||
% Auswahl des Pfads aufgenommener Bilder für das rechte Auge | |||
pfadOrdnerRA = 'RechtesAuge'; %uigetdir('','Ordner mit Bildern für das linke Auge auswählen!'); | |||
% Laden der Bildeigenschaften | |||
% Linkes Auge als Struct und dann als Cell | |||
imgEigenschaftenStructLA = dir(fullfile(pfadOrdnerLA, '*.png')); | |||
imgEigenschaftenLA = struct2cell(imgEigenschaftenStructLA)'; | |||
% Rechtes Auge als Struct und dann als Cell | |||
imgEigenschaftenStructRA = dir(fullfile(pfadOrdnerRA, '*.png')); | |||
imgEigenschaftenRA = struct2cell(imgEigenschaftenStructRA)'; | |||
% Anzahl Bilder in den Ordner | |||
anzImgLA = length(imgEigenschaftenLA(:,1)); | |||
anzImgRA = length(imgEigenschaftenRA(:,1)); | |||
% Fehlermeldung falls die Anzahl der Bilder nicht ausreichend ist | |||
if anzImgLA < 2 || anzImgRA < 2 | |||
error('Achtung!!! Die Anzahl der Bilder ist für die Kalibrierung nicht ausreichend!') | |||
% Bestimmung der Anzahl der Bilder für die Kalibrierung | |||
elseif anzImgLA <= anzImgRA | |||
anzImgKalibrierung = anzImgLA; | |||
else | |||
anzImgKalibrierung = anzImgRA; | |||
end | |||
% Bildpfade laden linkes Auge | |||
pfadBilderLA = fullfile(pfadOrdnerLA, imgEigenschaftenLA(1:anzImgKalibrierung,1)); | |||
== Weblinks | % Bildpfade laden rechtes Auge | ||
pfadBilderRA = fullfile(pfadOrdnerRA, imgEigenschaftenRA(1:anzImgKalibrierung,1)); | |||
% Durchführen bis das Schachbrettmuster richtig ekrannt wirt | |||
while ~strcmpi(abfrageOK,'JA') | |||
% Offene Fenster schließen | |||
close all; | |||
% Schachbrettmuster suchen linkes und rechtes Auge | |||
[schachBrettPkt, schachBrettGr, verwendetesImg] = detectCheckerboardPoints(pfadBilderLA, pfadBilderRA); | |||
% Erkannte Schachbrettpunkte nach Auge trennen | |||
schachBrettPktLA = schachBrettPkt(:,:,1,1); | |||
schachBrettPktRA = schachBrettPkt(:,:,1,2); | |||
% Positionen des Schachbretts im Bild linkes Auge | |||
% in X Richtung | |||
xMinLA = min(schachBrettPktLA(:,1)); | |||
xMaxLA = max(schachBrettPktLA(:,1)); | |||
% in Y Richtung | |||
yMinLA = min(schachBrettPktLA(:,2)); | |||
yMaxLA = max(schachBrettPktLA(:,2)); | |||
% Positionen des Schachbretts im Bild linkes Auge | |||
% in X Richtung | |||
xMinRA = min(schachBrettPktRA(:,1)); | |||
xMaxRA = max(schachBrettPktRA(:,1)); | |||
% in Y Richtung | |||
yMinRA = min(schachBrettPktRA(:,2)); | |||
yMaxRA = max(schachBrettPktRA(:,2)); | |||
% Überprüfung ob ein Schachbrettmuster erkannt wurde | |||
if max(verwendetesImg) == 0 || max(verwendetesImg) == 0 | |||
error('Achtung!!! Es wurde kein Schachbrettmuster erkannt!') | |||
end | |||
% Verwendete Bilder laden | |||
imgLA = imread(pfadBilderLA{find(verwendetesImg, 1 )}); | |||
imgRA = imread(pfadBilderRA{find(verwendetesImg, 1 )}); | |||
% Bild mit Schachbrettmuster anzeigen - Überschrift des Fensters | |||
handleSchachBrett = figure('Name','Kalibrierung','NumberTitle','off'); | |||
% Linkes Bild | |||
handleLA = subplot(2,2,1); | |||
imshow(imgLA, 'InitialMagnification', 50); | |||
hold on; | |||
title('Linkes Bild bzw. Auge'); | |||
% Rechtes Bild | |||
handleRA = subplot(2,2,2); | |||
imshow(imgRA, 'InitialMagnification', 50); | |||
hold on; | |||
title('Rechtes Bild bzw. Auge'); | |||
% Erkanntes Schachbrettmuster anzeichnen, linkes Bild | |||
plot(handleLA, schachBrettPktLA(:, 1), schachBrettPktLA(:, 2), '*r'); | |||
% Erkanntes Schachbrettmuster anzeichnen, rechtes Bild | |||
plot(handleRA, schachBrettPktRA(:, 1), schachBrettPktRA(:, 2), '*r'); | |||
% Überprüfung ob ein Schachbrettmuster erkannt wurde | |||
% Abfrage ob das Schachbrettmuster richtig erkannt wurde | |||
abfrageOK = input('\n\nWurde das Schachbrettmuster richtig erkannt? JA/NEIN\n', 's'); | |||
% Hier wird überprüft ob das gefundene Schachbrettmuster dem | |||
% tatsächlichen Schachbrettmuster entspricht. Sollte dies der | |||
% Fall sein muss der Nutzer in dem Matlab Command Window mit JA | |||
% bestättigen. Andernfalls wird das gefundene Schachbrettmuster in der | |||
% Bilddatei schwarz übermalt und die Erkennung des Schachbrettmusters | |||
% fängt von vorne an. | |||
if ~strcmpi(abfrageOK,'JA') | |||
% Überlagere die gefunde Fläche | |||
bildTempLA = imread(pfadBilderLA{find(verwendetesImg,1)}); | |||
bildTempLA(yMinLA:yMaxLA,xMinLA:xMaxLA,:) = 0; | |||
imwrite(bildTempLA, pfadBilderLA{find(verwendetesImg,1)}); | |||
% Überlagere die gefunde Fläche | |||
bildTempRA = imread(pfadBilderRA{find(verwendetesImg,1)}); | |||
bildTempRA(yMinRA:yMaxRA,xMinRA:xMaxRA,:) = 0; | |||
imwrite(bildTempRA, pfadBilderRA{find(verwendetesImg,1)}); | |||
end | |||
end | |||
% Weltkoordinaten von dem Schachbrettmuster erstellen | |||
% Feldgröße in mm! | |||
kantenLaenge = 25; | |||
% Berechne die Weltkoordinaten des Schachbretts | |||
schachBrettWeltPkt = generateCheckerboardPoints(schachBrettGr, kantenLaenge); | |||
% Kalibriere die Kamera | |||
kameraParameter = estimateCameraParameters(schachBrettPkt, schachBrettWeltPkt); | |||
% Kalibrierungsfehler | |||
handleKalErr = subplot(2,2,3); | |||
showReprojectionErrors(kameraParameter, 'BarGraph'); | |||
title('Kalibrierungsfehler'); | |||
% Extrinsische Kameraparameter | |||
handleExtParam = subplot(2,2,4); | |||
showExtrinsics(kameraParameter, 'CameraCentric'); | |||
title('Kameraparameter (Kalibrierungsaufnahmen)'); | |||
</source> | |||
= Weblinks = | |||
*[http://www.somikon.de/3D-Webcam-PX-3663-919.shtml Stereo-Webcam] | *[http://www.somikon.de/3D-Webcam-PX-3663-919.shtml Stereo-Webcam] | ||
*[http://www.mathworks.de/discovery/stereo-vision.html Stereo Vision mit Matlab] | *[http://www.mathworks.de/discovery/stereo-vision.html Stereo Vision mit Matlab] | ||
Zeile 108: | Zeile 387: | ||
*[http://wiki.zimt.uni-siegen.de/fertigungsautomatisierung/index.php/3D-Geometrieerfassung_mit_Stereovision 3D-Geometrieerfassung mit Stereovision] | *[http://wiki.zimt.uni-siegen.de/fertigungsautomatisierung/index.php/3D-Geometrieerfassung_mit_Stereovision 3D-Geometrieerfassung mit Stereovision] | ||
*[http://www.intorobotics.com/fundamental-guide-for-stereo-vision-cameras-in-robotics-tutorials-and-resources/ Stereo Webcam-Übersicht] | *[http://www.intorobotics.com/fundamental-guide-for-stereo-vision-cameras-in-robotics-tutorials-and-resources/ Stereo Webcam-Übersicht] | ||
*[http://www2.informatik.hu-berlin.de/~stuebing/public/Studienarbeit_Sascha_Stuebing_2010.pdf HU-Berlin] | |||
*[http://de.mathworks.com/help/vision/examples/uncalibrated-stereo-image-rectification.html Uncalibrated stereo image rectification] | |||
*[http://de.mathworks.com/help/vision/examples/stereo-calibration-and-scene-reconstruction.html Stereo calibration and scene reconstrucion] | |||
*[http://www.vision.caltech.edu/bouguetj/calib_doc/ Camera Calibration Toolbox for Matlab] | |||
---- | ---- | ||
→ zurück zum Hauptartikel: [[SigSys_SoSe2015| Signalverarbeitende Systeme SoSe2015]] | → zurück zum Hauptartikel: [[SigSys_SoSe2015| Signalverarbeitende Systeme SoSe2015]] |
Aktuelle Version vom 22. Juni 2015, 10:27 Uhr
Autor:
Betreuer: Prof. Schneider
Motivation
Durch die Verwendung von zwei Mono-Kameras lässt sich eine Tiefeninformation gewinnen.
Ziel
Verarbeiten Sie die Bilder zweier Mono-Webcams mit Matlab zu einem Bild mit Tiefeninformation.
Aufgabe
- Montieren Sie zwei Webcams mit festem seitlichen Abstand auf einem Stativ.
- Triangulieren Sie aus beiden Bildern eine Tiefeninformation
- Kalibrieren Sie die Kameras.
- Transformieren Sie ein Objekt aus der Kameraperspektive in Weltkoordinaten.
- Stellen Sie die Objekte im Sichtfeld in der Draufsich dar.
- Schätzen Sie die Genauigkeit Ihres 3D-Sensors ab.
Lösungen
EINLEITUNG
Die hier erläuterte Projektarbeit wurde im Rahmen der Veranstaltung „Signalverar-beitenden Systeme“, bei Prof. Dr.-Ing. Ulrich Schneider, im Sommer Semester 2015 realisiert. Ziel der Projektarbeit ist es eine 3D-Kamera mithilfe von zwei handelsübli-chen Webcams zu realisieren und so ein 3D-Bild zu erhalten.
HARDWARE-KOMPONENTEN
Für den Aufbau des stereoskopischen Systems wurden zwei gleiche Webcams (Watson, Modell CAM-M130) verwendet. Die Webcams wurden nahezu parallel, auf einem Plastikdeckel, aufgebaut, siehe Abbildung 1. Der Seitliche Abstand der Webcams beträgt 11,2 cm.
SOFTWARE
Die Software zur Projektarbeit ist aufgebaut aus der Hauptdatei stereoview.m. Diese teilt sich auf in die Kalibrierung (siehe Zeile 35) und das laden und auswerten der Bilder und die Erzeugung eines 3D-Bildes ab Zeile 37. Bevor die stereoview.m-Datei ausgeführt werden kann, müssen zuerst einmal die Bilder für die Kalibrierung aufgenommen werden.
Aufnahme der erforderlichen Bilder zur Kalibrierung
Für die Aufnahme der Bilder für die Kalibrierung soll die Datei bilderFuerKalibrie-rung.m ausgeführt werden. Dabei werden in der Zeile 4,
camL = webcam(1); camR = webcam(2);
die Webcams initialisiert und in Zeile 6 wird die Auflösung der Bilder auf 1280 x 960 geändert. Anschließend werden die erforderlichen Bilder aufgenommen
linkesBild = snapshot(camL); rechtesBild = snapshot(camR);
und in dem Zielorder gespeichert.
imwrite(linkesBild, fullfile('LinkesAuge', sprintf('left%02d.png', i)));
imwrite(rechtesBild, fullfile('RechtesAuge', sprintf('right%02d.png', i)));
Durch die While-Schleife kann der Benutzer die Anzahl der Aufnahmen bestimmen. Es empfiehlt sich eine Mindestanzahl von 10 Bildern (im Programm sind mindestens 10 Bilder erforderlich).
Kalibrierung des Kamerasystems
Um die Kalibrierung zu initiieren ist es zunächst einmal erforderlich die Bilder für die Kalibrierung zu laden. Hierbei wird der Nutzer nach dem Ordner gefragt indem sich die Bilder, zunächst von der linken Webkamera und anschließen von der rechten Webkamera, befinden. Nachdem die Quellorder definiert wurden, werden aus den Ordnern alle Bilddateien mit der Endung PNG geladen (Zeile 30 bis 35) und die Anzahl der Bilder im jeweili-gen Ordner wird definiert (Zeiele 38 und 39). In der Zeile 42 wird überprüft ob sich in dem Ordner mindestens 10 Bilder befinden. Enthält einer der beiden Ordner weniger als 10 PNG-Dateien wird der Programmverlauf abgebrochen und die Fehlermeldung „Achtung!!! Die Anzahl der Bilder ist für die Kalibrierung nicht ausreichend!“ erscheint im Matlab Command Window. Die Matlab Funktion detectCheckerboardPoint sucht das Bild nach einem Schach-brettmuster ab und liefert die Postition des Schachbretts im Bild, sowie die Schach-brettgröße und die Anzahl der verwendeten Bilder für die suche des Schachbretts. Dabei erwartet die Funktion detectCheckerboardPoint die Pfade der Bilder als Einga-beparameter. Anschließend wir überprüft ob ein Schachbrett gefunden wurde. Falls die Funktion kein Schachbrett im Bild gefunden hat wird der weitere Verlauf mit der Fehlermeldung „Achtung!!! Es wurde kein Schachbrettmuster erkannt!“ abgebrochen. Ab der Zeile 91 bis 114 werden die verwendeten Bilder für die detectCheckerboard-Point Funktion geladen und angezeigt, siehe Abbildung 2.
Dabei wird in das geladen Bild das erkannte Schachbrett kenntlich gemacht und der Nutzer muss entscheiden ob das gefundene Schachbrett dem tatsächlichen Schach-brett entsprich oder ob es sich um einen Fehler handelt. Die Abfrage hierzu erfolgt in der Ziele 120
(abfrageOK = input('\n\nWurde das Schachbrettmuster richtig erkannt? JA/NEIN\n', 's');)
mithilfe der Eingabe im Matlab Command Window.
Sollte das Schachbrett dem tatsächlichen Schachbrett entsprechen, so werden in der Zeile 149 die Kameraparameter bestimmt. Bevor die Kameraparameter bestimmt werden können, muss zunächst in der Zeile 143 die Kantenlänge der Schachbrettfel-der definiert werden um in der Zeile 146 die Koordinaten der Schachbrettfelder, unter Zuhilfenahme der Matlab-Funktion generateCheckerboardPoints, in der realen Welt zu bestimmen. Anschließend werden ab der Zeile 152 die Pixel-Abweichungen und die Umgebung zum Zeitpunkt der Aufnahme der Bilder zur Kalibrierung simuliert, siehe Abbildung 3.
Bestimmung der Position, der erkannten Objekte in der realen Welt
Nachdem die Kalibrierung des Kamerasystems erfolgt ist, und die Funktion „kalibrierung“ verlassen wurde schauen wir uns wieder die stereoview.m an. Zunächst werden zwei aktuelle Kamerabilder geladen (Zeile 37 bis 44) oder zwei Standbilder (Zeile 46 und 47). Das laden der Kamerabilder ist analog der Aufnahme der Bilder für die Ka-librierung (siehe Aufnahme der erforderlichen Bilder zur Kalibrierung). Anschließend werden die geladenen Bilder berichtigt (Zeile 54) und als Anaglyphen-Bilder dargestellt (siehe Abbildung 4).
Die Berichtigung der Bilder erfolgt mithilfe der Matlab-Funktion „rectifyS-tereoImages“. Diese korrigiert die Bilder anhand der Kameraparameter. Anschließend wird ab der Zeile der Sichtbereich der Kamera eingestellt und er wer-den die Objekte in dem Weltkoordinaten-System dargestellt (siehe Abbildung 4).
Quellcode - Aufnahme der Bilder für die Kalibrierung
clear all; close all; clc;
% Webcams laden
camL = webcam(1); camR = webcam(2);
% Auflösung einstellen
camL.Resolution = '1280x960'; camR.Resolution = '1280x960';
% Laufvariable
i = 1
nachstesBild = 'nein';
while ~strcmpi(nachstesBild,'n')
% Bild machen
linkesBild = snapshot(camL); rechtesBild = snapshot(camR);
% Bild speichern
imwrite(linkesBild, fullfile('LinkesAuge', sprintf('left%02d.png', i)));
imwrite(rechtesBild, fullfile('RechtesAuge', sprintf('right%02d.png', i)));
% Abfrage ob das Schachbrettmuster richtig erkannt wurde
nachstesBild = input('\n\nSoll noch ein Bild aufgenommen werden? JA/NEIN\n', 's');
i = i + 1
end
Quellcode - Hauptprogramm
%% Dieses Matlab-Programm wurde im Rahmen der Veranstalltung
% Signalverarbeitende Systeme bei Prof. Ulricht Schneider erstellt. Das
% Programm kalibriert zwei Webcams und erzeugt anschließend ein 3D-Bild.
% Die genau Aufgabenstellung sowie die Beschreibung kann unter dem
% folgendem Link nachgelesen werden. http://193.175.248.171/wiki/index.php/SigSys15_Stereo-View
%****************************************************************
% Hochschule Hamm-Lippstadt *
%****************************************************************
% Modul : StereoView *
% *
% Datum : 31-Mai-2015 *
% *
% Funktion : siehe Oben *
% *
% Implementierung: MATLAB R2015a *
% *
% Notw. Toolbox : Image Processing Toolbox *
% *
% Author : Miladin Ceranic *
% *
% Bemerkung : Projektaufgabe - Signalverarbeitende Systeme *
% *
% Letzte Änderung: 19. Juni 2015 *
% *
%***************************************************************/
% Workspace löschen, offene Fenster schließen und Command Window leeren
clear all; close all; clc;
%% Definition benötigter Variablen
abfrageOK = 'UNDEFINED';
%% Kamera kalibrieren
kalibrierung
% Kamera starten
% camL = webcam(1); camR = webcam(2);
%
% % Auflösung der Kamera einstellen
% camL.Resolution = '1280x960'; camR.Resolution = '1280x960';
%
% linkesBild = snapshot(camL); rechtesBild = snapshot(camR);
% imwrite(linkesBild, 'linkesBild.jpg'); imwrite(rechtesBild, 'rechtesBild.jpg');
linkesBild = imread('linkesBild.jpg');
rechtesBild = imread('rechtesBild.jpg');
%% Bilder laden und in 3D (anaglyphen) anzeigen
bildVorherLA = linkesBild;
bildVorherRA = rechtesBild;
% Bilder optimieren
[bildNachherLA, bildNachherRA] = rectifyStereoImages(linkesBild, rechtesBild, kameraParameter);%,'OutputView','full');
% 3D-Bild anzeigen vor und nach der Kalibrierung
handle3D = figure('Name','3D Vorschau','NumberTitle','off');
% Vor der Bearbeitung
handleVorher = subplot(2,2,1);
imshow(stereoAnaglyph(bildVorherLA, bildVorherRA), 'InitialMagnification', 50);
hold on;
title('Vor der Berichtigung');
% Nach der Bearbeitung
handleNachher = subplot(2,2,2);
imshow(stereoAnaglyph(bildNachherLA, bildNachherRA), 'InitialMagnification', 50);
hold on;
title('Nach der Berichtigung');
% Ungleichheiten in den Bildern
disparityMap = disparity(rgb2gray(bildNachherLA), rgb2gray(bildNachherRA));
handleDisparity = subplot(2,2,3);
imshow(disparityMap, 'InitialMagnification', 50);
colormap('jet');
colorbar;
title('Disparity Map');
% Reconstruct the 3-D world coordinates of points corresponding to each
% pixel from the disparity map.
pointCloud = reconstructScene(disparityMap, kameraParameter);
pointCloud = pointCloud / 10;
% Anzeigebereich einstellen
handleRek = subplot(2,2,4);
% Anzeige einstellen
% X-Achse
x = pointCloud(:, :, 1);
% maxX = 150; minX = -150;
% xdisp = x;
% xdisp(x < minX | x > maxX) = NaN;
% Y-Achse
y = pointCloud(:, :, 2);
% maxY = 70; minY = -70;
% ydisp = y;
% ydisp(y < minY | y > maxY) = NaN;
% Z-Achse
z = pointCloud(:, :, 3);
% maxZ = 700; minZ = 300;
% zdisp = z;
% zdisp(z < minZ | z > maxZ) = NaN;
% point3Ddisp = pointCloud;
point3Ddisp(:,:,1) = x;%disp;
point3Ddisp(:,:,2) = y;%disp;
point3Ddisp(:,:,3) = z;%disp;
imwrite(bildNachherLA, 'linkesBild1.jpg')
imwrite(bildNachherRA, 'rechtesBild1.jpg')
showPointCloud(point3Ddisp, bildNachherLA, 'VerticalAxis', 'Y',...
'VerticalAxisDir', 'Down' );
xlabel('X in mm');
ylabel('Y in mm');
zlabel('Z in mm');
Quellcode - Kalibrierung der Kamera
%****************************************************************
% Hochschule Hamm-Lippstadt *
%****************************************************************
% Modul : Kalibrierung der Kameras *
% *
% Datum : 31-Mai-2015 *
% *
% Funktion : siehe Oben *
% *
% Implementierung: MATLAB R2015a *
% *
% Notw. Toolbox : Image Processing Toolbox *
% *
% Author : Miladin Ceranic *
% *
% Bemerkung : Projektaufgabe - Signalverarbeitende Systeme *
% *
% Letzte Änderung: 19. Juni 2015 *
% *
%***************************************************************/
%% Kalibrieren der Kameras
% Auswahl des Pfads aufgenommener Bilder für das linke Auge
pfadOrdnerLA = 'LinkesAuge'; %uigetdir('','Ordner mit Bildern für das linke Auge auswählen!');
% Auswahl des Pfads aufgenommener Bilder für das rechte Auge
pfadOrdnerRA = 'RechtesAuge'; %uigetdir('','Ordner mit Bildern für das linke Auge auswählen!');
% Laden der Bildeigenschaften
% Linkes Auge als Struct und dann als Cell
imgEigenschaftenStructLA = dir(fullfile(pfadOrdnerLA, '*.png'));
imgEigenschaftenLA = struct2cell(imgEigenschaftenStructLA)';
% Rechtes Auge als Struct und dann als Cell
imgEigenschaftenStructRA = dir(fullfile(pfadOrdnerRA, '*.png'));
imgEigenschaftenRA = struct2cell(imgEigenschaftenStructRA)';
% Anzahl Bilder in den Ordner
anzImgLA = length(imgEigenschaftenLA(:,1));
anzImgRA = length(imgEigenschaftenRA(:,1));
% Fehlermeldung falls die Anzahl der Bilder nicht ausreichend ist
if anzImgLA < 2 || anzImgRA < 2
error('Achtung!!! Die Anzahl der Bilder ist für die Kalibrierung nicht ausreichend!')
% Bestimmung der Anzahl der Bilder für die Kalibrierung
elseif anzImgLA <= anzImgRA
anzImgKalibrierung = anzImgLA;
else
anzImgKalibrierung = anzImgRA;
end
% Bildpfade laden linkes Auge
pfadBilderLA = fullfile(pfadOrdnerLA, imgEigenschaftenLA(1:anzImgKalibrierung,1));
% Bildpfade laden rechtes Auge
pfadBilderRA = fullfile(pfadOrdnerRA, imgEigenschaftenRA(1:anzImgKalibrierung,1));
% Durchführen bis das Schachbrettmuster richtig ekrannt wirt
while ~strcmpi(abfrageOK,'JA')
% Offene Fenster schließen
close all;
% Schachbrettmuster suchen linkes und rechtes Auge
[schachBrettPkt, schachBrettGr, verwendetesImg] = detectCheckerboardPoints(pfadBilderLA, pfadBilderRA);
% Erkannte Schachbrettpunkte nach Auge trennen
schachBrettPktLA = schachBrettPkt(:,:,1,1);
schachBrettPktRA = schachBrettPkt(:,:,1,2);
% Positionen des Schachbretts im Bild linkes Auge
% in X Richtung
xMinLA = min(schachBrettPktLA(:,1));
xMaxLA = max(schachBrettPktLA(:,1));
% in Y Richtung
yMinLA = min(schachBrettPktLA(:,2));
yMaxLA = max(schachBrettPktLA(:,2));
% Positionen des Schachbretts im Bild linkes Auge
% in X Richtung
xMinRA = min(schachBrettPktRA(:,1));
xMaxRA = max(schachBrettPktRA(:,1));
% in Y Richtung
yMinRA = min(schachBrettPktRA(:,2));
yMaxRA = max(schachBrettPktRA(:,2));
% Überprüfung ob ein Schachbrettmuster erkannt wurde
if max(verwendetesImg) == 0 || max(verwendetesImg) == 0
error('Achtung!!! Es wurde kein Schachbrettmuster erkannt!')
end
% Verwendete Bilder laden
imgLA = imread(pfadBilderLA{find(verwendetesImg, 1 )});
imgRA = imread(pfadBilderRA{find(verwendetesImg, 1 )});
% Bild mit Schachbrettmuster anzeigen - Überschrift des Fensters
handleSchachBrett = figure('Name','Kalibrierung','NumberTitle','off');
% Linkes Bild
handleLA = subplot(2,2,1);
imshow(imgLA, 'InitialMagnification', 50);
hold on;
title('Linkes Bild bzw. Auge');
% Rechtes Bild
handleRA = subplot(2,2,2);
imshow(imgRA, 'InitialMagnification', 50);
hold on;
title('Rechtes Bild bzw. Auge');
% Erkanntes Schachbrettmuster anzeichnen, linkes Bild
plot(handleLA, schachBrettPktLA(:, 1), schachBrettPktLA(:, 2), '*r');
% Erkanntes Schachbrettmuster anzeichnen, rechtes Bild
plot(handleRA, schachBrettPktRA(:, 1), schachBrettPktRA(:, 2), '*r');
% Überprüfung ob ein Schachbrettmuster erkannt wurde
% Abfrage ob das Schachbrettmuster richtig erkannt wurde
abfrageOK = input('\n\nWurde das Schachbrettmuster richtig erkannt? JA/NEIN\n', 's');
% Hier wird überprüft ob das gefundene Schachbrettmuster dem
% tatsächlichen Schachbrettmuster entspricht. Sollte dies der
% Fall sein muss der Nutzer in dem Matlab Command Window mit JA
% bestättigen. Andernfalls wird das gefundene Schachbrettmuster in der
% Bilddatei schwarz übermalt und die Erkennung des Schachbrettmusters
% fängt von vorne an.
if ~strcmpi(abfrageOK,'JA')
% Überlagere die gefunde Fläche
bildTempLA = imread(pfadBilderLA{find(verwendetesImg,1)});
bildTempLA(yMinLA:yMaxLA,xMinLA:xMaxLA,:) = 0;
imwrite(bildTempLA, pfadBilderLA{find(verwendetesImg,1)});
% Überlagere die gefunde Fläche
bildTempRA = imread(pfadBilderRA{find(verwendetesImg,1)});
bildTempRA(yMinRA:yMaxRA,xMinRA:xMaxRA,:) = 0;
imwrite(bildTempRA, pfadBilderRA{find(verwendetesImg,1)});
end
end
% Weltkoordinaten von dem Schachbrettmuster erstellen
% Feldgröße in mm!
kantenLaenge = 25;
% Berechne die Weltkoordinaten des Schachbretts
schachBrettWeltPkt = generateCheckerboardPoints(schachBrettGr, kantenLaenge);
% Kalibriere die Kamera
kameraParameter = estimateCameraParameters(schachBrettPkt, schachBrettWeltPkt);
% Kalibrierungsfehler
handleKalErr = subplot(2,2,3);
showReprojectionErrors(kameraParameter, 'BarGraph');
title('Kalibrierungsfehler');
% Extrinsische Kameraparameter
handleExtParam = subplot(2,2,4);
showExtrinsics(kameraParameter, 'CameraCentric');
title('Kameraparameter (Kalibrierungsaufnahmen)');
Weblinks
- Stereo-Webcam
- Stereo Vision mit Matlab
- Behnisch, M.: Stereovision: Grundlagen. Uni-Bielefeld, 2005
- 3D-Geometrieerfassung mit Stereovision
- Stereo Webcam-Übersicht
- HU-Berlin
- Uncalibrated stereo image rectification
- Stereo calibration and scene reconstrucion
- Camera Calibration Toolbox for Matlab
→ zurück zum Hauptartikel: Signalverarbeitende Systeme SoSe2015