SigSys15 Stereo-View

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen

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

  1. Montieren Sie zwei Webcams mit festem seitlichen Abstand auf einem Stativ.
  2. Triangulieren Sie aus beiden Bildern eine Tiefeninformation
  3. Kalibrieren Sie die Kameras.
  4. Transformieren Sie ein Objekt aus der Kameraperspektive in Weltkoordinaten.
  5. Stellen Sie die Objekte im Sichtfeld in der Draufsich dar.
  6. 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

Abbildung 1: Verschiedene Ansichten der "3D-Webcam"

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

Abbildung 2: Anzeige der gefundenen Schachbrettmuster im Bild."
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. 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

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). 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


→ zurück zum Hauptartikel: Signalverarbeitende Systeme SoSe2015