Skip to content
Snippets Groups Projects
Commit 868d393b authored by Jan Wille's avatar Jan Wille
Browse files

fixups und schönheit

parent 4df511ba
No related branches found
No related tags found
No related merge requests found
......@@ -11,7 +11,7 @@ Kalibriermuster
Unkalibriertes
Kaliebreiung
Verzerrungsarten
Verzerrungskoeffizienten
Verzerrungs-Koeffizienten
Kalibrierungs-Parameter
Reprojektions-Fehler
Kalibriermusters
......
......@@ -71,3 +71,11 @@
{"rule":"IN_WEISS","sentence":"^\\QIm Gegensatz zu Alternativen, wie einer reinen Gradientenbetrachtung, liefert der \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q Kantenmarkierungen, hier in weiß, die nur einen \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q breit sind.\\E$"}
{"rule":"DE_CASE","sentence":"^\\QUm die Datenmenge gering und die Laufzeit schnell zu halten, werden lediglich die vier Klassen Vertikal, Horizontal, Diagonal 1 und Diagonal 2 verwendet.\\E$"}
{"rule":"DE_PHRASE_REPETITION","sentence":"^\\QHier wird der entwickelte Algorithmus und die Umsetzung als ROS Node ROS Node erläutert.\\E$"}
{"rule":"DE_CASE","sentence":"^\\QZum Testen des JetBots für diese Arbeit und andere Projekt wurde eine die Projektfläche Autonomes Fahren aufgebaut.\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QWährend einer Testfahrt des Dummies wurden von der Entzerrer-\\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q veröffentlichte Bilder abgespeichert, sodass sie zum lokalen Testen zur Verfügung stehen.\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QWie diese neuen \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q mit den bestehenden Dummies in Beziehung stehen soll, ist in \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q grafisch dargestellt.\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QWird dieser Code auf das Beispiel-Bild \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q angewendet und das Ergebnis des Dummies ausgegeben, ergibt sich \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q.\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QAußerdem wird das \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q /img/gray von der Entzerrer-\\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q abonniert, um jedes Grauwert-Bild zu bekommen.\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QJan Wille 1535115 Bachelorarbeit [Video-basierte Erkennung von Fahrspurmarkierungen auf mobilen Robotern]Video-basierte Erkennung von Fahrspurmarkierungen auf mobilen Robotern 12.09.2022 Prof. Dr.-Ing. Hanno Homann Prof. Dr.-Ing. Martin Mutz\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\Q[r] LaneDetector:driverAssistanceSystems\\E$"}
{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QAußerdem wird eine Grauwert-Version erzeugt und diese als /img/gray veröffentlicht, was hier aber nicht gezeigt ist.\\E$"}
No preview for this file type
\documentclass[
f1,
%twoside, % mutually exclude with `todos'
todos,
twoside, % mutually exclude with `todos'
%todos,
]{HsH-report} % documentclass
% include packages here
......@@ -38,8 +38,7 @@
\subject{Bachelorarbeit}
\title[Video-basierte Erkennung von Fahrspurmarkierungen auf mobilen Robotern]{Video-basierte Erkennung von Fahrspurmarkierungen\\ auf mobilen Robotern}
%\subtitle{Subtitle}
\date{09.05.2022 -- \today \todo{Nur Endatum oder ganzen Zeitraum?}}
\date{12.09.2022}
\erstpruefer{Prof. Dr.-Ing. Hanno Homann}
\zweitpruefer{Prof. Dr.-Ing. Martin Mutz}
......@@ -54,12 +53,8 @@
\include{chap/abstract}
\tableofcontents
\printglossary
\mainmatter
\todo[inline]{Schreibweise von langen Worten vereinheitlichen. Bindestrichen oder alles zusammen?}
\todo[inline]{Schwarzweißbild zu Grauwertbild und überall einheitlich}
\nocite{LaneDetector:driverAssistanceSystems}
\mainmatter
\include{chap/einleitung}
......
......@@ -3,7 +3,7 @@
\newglossaryentry{C++}{
name={C\nolinebreak[4]\hspace{-.05em}\raisebox{.3ex}{\footnotesize\textbf{++}}},
description={
Eine hardwarenahe, performante Programiersprache
Eine hardwarenahe, performante Programmiersprache.
}
}
\newglossaryentry{python}{
......@@ -72,7 +72,7 @@
name={Callback-Funktion},
description={
Eine Funktion, die unter bestimmten Bedingungen automatisch aufgerufen wird. Im Bezug auf \gls{ROS} geht es meistens um Funktionen die für
jede Nachricht auf einem abonnierten \gls{Topic} mit deren Inhalt aufgerufen werden.
jede \gls{ROS Message} auf einem abonnierten \gls{Topic} mit deren Inhalt aufgerufen werden.
}
}
......@@ -95,7 +95,7 @@
\newglossaryentry{Welt-coords}{
name={Weltkoordinaten},
text={Weltkoordinate},
plural={Bildkoordinaten},
plural={Weltkoordinaten},
description={
Ein 3D-Koordinatensystem, das die gesamte Scene/Welt des derzeitigen Systems umfasst.
},
......@@ -103,25 +103,36 @@
}
\newglossaryentry{Objekt-coords}{
name={Fahrzeugkoordinaten (Objektkoordinaten)},
text={Fahrzeugkoordinate},
plural={Fahrzeugkoordinaten},
name={Roboterkoordinaten (Objektkoordinaten)},
text={Roboterkoordinate},
plural={Roboterkoordinaten},
description={
Ein 3D-Koordinatensystem welches relativ zum Fahrzeug/Objekt liegt. Es bewegt sich mit dem Fahrzeug und hat seinen Uhrsprung im/nahe am
Ein 3D-Koordinatensystem welches relativ zum Roboter/Objekt liegt. Es bewegt sich mit dem Roboter und hat seinen Uhrsprung im/nahe am
Fahrzeug.
},
sort={koordinaten-fahrzeug}
sort={koordinaten-roboter}
}
\newglossaryentry{Bild-coords}{
name={Bildkoordinaten},
text={Bildkoordinate},
plural={Bildkoordinaten},
name={Kamerakoordinaten},
text={Kamerakoordinate},
plural={Kamerakoordinaten},
description={
Ein Koordinatensystem welches die sicht der Kamera Widerspiegelt. X- und Y-Koordinaten korrospondieren dabei zu pixelkoordinaten und die
Z-Achse stellt die Entfernung zur Kamera dar.
Ein 3D-Koordinatensystem, welches die sicht der Kamera Widerspiegelt. $x$ und $y$-Koor\-di\-na\-ten kor\-ros\-pondieren dabei zu \gls{pixel-coords} und
die $z$-Achse stellt die Entfernung zur Kamera dar.
},
sort={koordinaten-bild}
sort={koordinaten-kamera}
}
\newglossaryentry{pixel-coords}{
name={Pixelkoordinaten (Bildkoordinaten)},
text={Pixelkoordinate},
plural={Pixelkoordinaten},
description={
Ein 2D-Koordinatensystem, welches die Position der Bild-Pixel abbildet. Es liegt in der $x$/$y$-Ebene des \glspl{Bild-coords}, der Ursprung
ist aber um die halbe bildgröße nach links-oben verschoben.
},
sort={koordinaten-pixel}
}
\newglossaryentry{ROI}{
......@@ -133,7 +144,7 @@
\newglossaryentry{gauss-filter}{
name={Gaußscher Filter},
description={
Eine Filterfunktion um Bilder zu glätten. Sie bildet den mittels einer 2D-Gaußfunktion gewichteten Mittelwert einer Nachbarschaft.
Eine Filterfunktion um Bilder zu glätten. Sie bildet den mittels einer 2D-Gaußfunktion gewichteten Mittelwert einer \gls{Pixelnachbarschaft}.
}
}
......
......@@ -22,4 +22,4 @@
Bild bei $\approx 3,5\,\ms$ lag, war ein direkter Vergleich zwischen Originalbild und gefunden Konturen in Echtzeit möglich.
Eine weitere Optimierung durch eine eigene Implementierung des \gls{canny} und Kombinieren von diesem mit dem Klassifizierungsschritt, war nicht
möglich\todo{Stattdessen erfolgreich ?}. Hierdurch wurden deutlich schlechtere Laufzeiten erzielt.
möglich. Hierdurch wurden deutlich schlechtere Laufzeiten erzielt.
\chapter{Fahrspurerkennung} \label{chap: implementation}
\chapter{Erkennung von Fahrspurmarkierungen} \label{chap: implementation}
Dieses Kapitel thematisiert, wie die Erkennung der Fahrspurmarkierungen umgesetzt wird. Begonnen wird mit einer konzeptionellen Version in
Python, mit der der Ablauf des Algorithmus geplant und getestet wird. Danach wird die Logik in einer \gls{C++} \gls{ROS Node} umgesetzt, um die
......@@ -10,9 +10,9 @@
\label{fig: topics marker detection}
\end{figure}
Wie diese neuen \glspl{ROS Node} mit den bestehenden \glspl{ROS Node} in Beziehung stehen soll, ist in \autoref{fig: topics marker detection}
grafisch dargestellt. Neu ist dabei, dass diese \gls{ROS Node} das korrigierte Schwarz-Weiß Bild von der in \autoref{sec: undistort Node}
beschriebenen entzerrer \gls{ROS Node} abonniert und das eigene Ergebnis als neues \gls{Topic} zur Verfügung stellt.
Wie diese neuen \gls{ROS Node} mit den bestehenden \glspl{ROS Node} in Beziehung stehen soll, ist in \autoref{fig: topics marker detection}
grafisch dargestellt. Neu ist dabei, dass diese \gls{ROS Node} das korrigierte Grauwert-Bild von der in \autoref{sec: undistort Node}
beschriebenen Entzerrer-\gls{ROS Node} abonniert und das eigene Ergebnis als neues \gls{Topic} zur Verfügung stellt.
\section{Konzeptionierung in Python}
......@@ -21,7 +21,7 @@
Der Algorithmus lässt sich in mehrere Einzelschritte aufteilen, welche in den folgenden Unterkapiteln beschreiben im Einzelnen beschrieben
sind. Zur Übersicht ist aber der gesamte Ablauf in \autoref{fig: PAP} skizziert. Angefangen wird dort mit dem Erhalten des Bildes,
womit sowohl manuelles Laden eines Beispielbildes, als auch das Erhalten des Bildes über ein \gls{Topic} gemeint ist.
womit sowohl manuelles Laden eines Beispiel-Bildes, als auch das Erhalten des Bildes über ein \gls{Topic} gemeint ist.
\begin{figure}
\includegraphics[scale=.85]{svg/PAP_marker_erkennung.pdf}
......@@ -29,13 +29,13 @@
\label{fig: PAP}
\end{figure}
Während einer Testfahrt des \glspl{JetBot} wurden von der entzerrer \gls{ROS Node} veröffentlichte Bilder abgespeichert, sodass sie zum
Während einer Testfahrt des \glspl{JetBot} wurden von der Entzerrer-\gls{ROS Node} veröffentlichte Bilder abgespeichert, sodass sie zum
lokalen Testen zur Verfügung stehen. Diese wurden unter \cite{git:dataset-strassen} abgelegt. In \autoref{fig: beispiel bild} ist eines dieser
Bilder gezeigt, mit dem im Folgenden die Einzelschritte demonstriert werden.
\begin{figure}
\includegraphics[width=.6\textwidth]{img/Marks_original.png}
\caption{Beispielbild an dem der Ablauf demonstriert wird}
\caption{Beispiel-Bild an dem der Ablauf demonstriert wird}
\label{fig: beispiel bild}
\end{figure}
......@@ -75,9 +75,9 @@
canny = cv2.Canny(img, 180, 40)
\end{lstlisting}
Wird dieser Code auf das Beispielbild \ref{fig: beispiel bild} angewendet und das Ergebnis des \glspl{canny} ausgegeben, ergibt sich
\autoref{fig: canny edges}. Im Gegensatz zu Alternativen, wie einer reinen Gradientenbetrachtung, liefert der \gls{canny}
Kantenmarkierungen, hier in weiß, die nur einen \gls{Pixel} breit sind. Dies ermöglicht die in den folgenden Unterkapiteln
Wird dieser Code auf das Beispiel-Bild \ref{fig: beispiel bild} angewendet und das Ergebnis des \glslink{canny}{Canny-Edge-Detek\-tors}
ausgegeben, ergibt sich \autoref{fig: canny edges}. Im Gegensatz zu Alternativen, wie einer reinen Gradientenbetrachtung, liefert der
\gls{canny} Kantenmarkierungen, hier in weiß, die nur einen \gls{Pixel} breit sind. Dies ermöglicht die in den folgenden Unterkapiteln
beschriebenen Schritte.
\begin{figure}
......@@ -100,8 +100,8 @@
Die Klassifizierung erfolgt anhand der \gls{Gradientenorientierung} eines Pixels. Dazu werden mit $3\!\times\!3$ Sobel-\glspl{Kernel} die
Gradienten $d_x$ und $d_y$ bestimmt. Mit der \lstinline{atan2()} Funktion kann aus diesen beiden Größen der Winkel des Gradientenvektors
$\vec{G}$ berechnet werden. Mit diesem Winkel kann nun entsprechend der \autoref{fig: gadienten orientierung} die Klasse bestimmt werden.
Dabei ist zu beachten, dass $\vec{G}$ immer orthogonal auf der eigentlichen Kante steht. Deshalb ist die Klasse \emph{Vertikal} auch der
links-rechts Achse der Abbildung zu finden.
Dabei ist zu beachten, dass $\vec{G}$ immer orthogonal auf der eigentlichen Kante steht. Deshalb ist die Klasse \emph{Vertikal} auch auf
der links-rechts Achse der Abbildung zu finden.
\begin{figure}
\includegraphics[width=.4\textwidth]{svg/CannyEdge_Orientation.pdf}
......@@ -266,6 +266,7 @@
Schritte, das Zusammenfassen von gleich klassifizierten Kantenpixeln zu durchgängigen Linien und das Zusammenfassen von Linien zu einer
Fahrspurmarkierung.
\medskip
Für den ersten Schritt ist es ein weiteres Mal nötig, über das gesamte Bild zu iterieren. Auch diesmal können wieder alle schwarzen Pixel
übersprungen werden. Wird ein klassifiziertes \gls{Pixel} gefunden, muss überprüft werden, ob es sich um ein Startpixel handelt. Startpixel sind
Pixel, die keine Nachbarn in der ihrer Klasse entsprechenden Ursprungsrichtung haben. Zum Beispiel wäre ein \gls{Pixel} der \emph{Vertikal}
......@@ -301,6 +302,7 @@
lines.append(l)
\end{lstlisting}
\pagebreak
Hat ein \gls{Pixel} keine weiteren Nachbarn, ist er der Endpunkt dieser Linie. Start- und Endpunkt werden in ein Linienobjekt
zusammengefasst und abgespeichert. Zusätzlich wird ebenfalls die Orientierungsklasse mit abgespeichert.
......@@ -344,7 +346,7 @@
Linienpunkten abgespeichert. Außerdem wird der Mittelwert der beiden Start- und Endpunkte gebildet und somit die Mittellinie des
Linienmarkers angenähert.
So gefundene Linienmarker lassen sich wieder im Beispielbild markieren, wodurch sich \autoref{fig: found markings} ergibt. Wie man dort
So gefundene Linienmarker lassen sich wieder im Beispiel-Bild markieren, wodurch sich \autoref{fig: found markings} ergibt. Wie man dort
sehen kann, wurden die Linienmarker der eigenen linken und rechten Fahrspurbegrenzung erfolgreich identifiziert. Weitere Markierungen
anderer Spuren konnten aufgrund der unzuverlässigen Klassifizierung nicht erkannt werden.
......@@ -355,6 +357,7 @@
\end{figure}
\pagebreak
\subsubsection{Komplexere Szenen}
Nicht jede Situation, auf die der Roboter treffen kann, führt zu so guten Ergebnissen wie das gezeigte Beispiel. Daher sind in
......@@ -373,16 +376,16 @@
\begin{figure}
\subfigure[lange Linien]{ \label{subfig: demo C}
\includegraphics[width=.23\textwidth]{img/demo_org_C.png}
\includegraphics[width=.23\textwidth]{img/demo_found_C.png}
\includegraphics[width=.235\textwidth]{img/demo_org_C.png}
\includegraphics[width=.235\textwidth]{img/demo_found_C.png}
}
\subfigure[leichte Kurve]{ \label{subfig: demo A}
\includegraphics[width=.23\textwidth]{img/demo_org_A.png}
\includegraphics[width=.23\textwidth]{img/demo_found_A.png}
\includegraphics[width=.235\textwidth]{img/demo_org_A.png}
\includegraphics[width=.235\textwidth]{img/demo_found_A.png}
}
\subfigure[durchgezogene Linie]{ \label{subfig: demo B}
\includegraphics[width=.23\textwidth]{img/demo_org_B.png}
\includegraphics[width=.23\textwidth]{img/demo_found_B.png}
\includegraphics[width=.235\textwidth]{img/demo_org_B.png}
\includegraphics[width=.235\textwidth]{img/demo_found_B.png}
}
\caption{Ergebnisse bei komplexeren Szenen im Vergleich}
\label{fig: vergleich szenen}
......@@ -399,7 +402,7 @@
Die Beziehung der neuen \gls{ROS Node} zu den bestehenden \glspl{ROS Node} wurde bereits in \autoref{fig: topics marker detection} skizziert.
Dort sieht man, dass für diese \gls{ROS Node} der Namen \lstinline{lane_marker_detection} gewählt wird. Außerdem wird das \gls{Topic}
\lstinline{/img/gray} von der Entzerrer-\gls{ROS Node} abonniert, um jedes Schwarz-Weiß Bild zu bekommen. Das Bild mit den eingezeichneten,
\lstinline{/img/gray} von der Entzerrer-\gls{ROS Node} abonniert, um jedes Grauwert-Bild zu bekommen. Das Bild mit den eingezeichneten,
detektierten Spurmarkierungen wird nach Durchlauf des Algorithmus auf dem eigenen \gls{Topic} \lstinline{/img/lanemarkings} veröffentlicht.
Beim Abonnieren des \lstinline{/img/gray} Topics wird die \gls{Callback} \lstinline{callback_image()} angehängt, sodass diese von \gls{ROS}
......@@ -447,7 +450,8 @@
continue;
\end{lstlisting}
Die Bestimmung der Gradienten mittels Sobel wirkt in \gls{C++} deutlich komplizierter, da hier vieles manuell gemacht werden muss, was in
\pagebreak
Mittels Sobel die Gradienten zu bestimmen, wirkt in \gls{C++} deutlich komplizierter, da hier vieles manuell gemacht werden muss, was in
\gls{python} von \lstinline{numpy} erledigt wurde. Mit zwei For-Schleifen wird über die $3\!\times\!2$ \gls{Pixelnachbarschaft} iteriert, die
Elemente mit dem \gls{Kernel} multipliziert und aufsummiert, wie in \autoref{code: sobel c++} zu sehen.
......@@ -470,9 +474,8 @@
\end{lstlisting}
Die eigentliche Klassifizierung ist praktisch identisch zur \gls{python}-Version. Lediglich die Überprüfung der Winkelbereiche ist etwas
langwieriger, da nicht mehrere Vergleiche direkt nacheinander möglich sind. Die Codierung der Klassen Erfolg wieder über die einzelnen Bit
des Bytes der einzelnen Pixel.
Die Umsetzung ist in \autoref{code: klassen c++} dargestellt.
langwieriger, da nicht wie in \gls{python} auf einen Wertebereich überprüft werden kann. Die Codierung der Klassen Erfolg wieder über die
einzelnen Bit des Bytes der einzelnen Pixel. Die Umsetzung ist in \autoref{code: klassen c++} dargestellt.
\begin{lstlisting}[
float,
......@@ -503,6 +506,7 @@
Das Ergebnisbild mit den klassifizierten Pixeln wird von der Funktion zurückgegeben und dort weiterverarbeitet.
\pagebreak
\subsubsection{Linienbildung}
Mit dem klassifizierten Bild kann nun dieselbe Methodik zur Identifizierung zusammenhängender Linien wie in Python angewendet werden.
......@@ -638,10 +642,8 @@
zurzeit nicht veröffentlicht. Stattdessen wird analog zur Python-Implementierung ein Bild mit eingezeichneten Spurmarkern erzeugt und als
visuelles Ergebnis zur Verfügung gestellt. Dieses kann unter dem \gls{Topic} \lstinline{/img/temp} abgerufen und live angeschaut werden.
\bigskip
\todo{pagebreak?}
\pagebreak
\subsection{Performance Betrachtung}
Mit dieser zusätzlichen \gls{ROS Node} ist es erneut interessant, wie sich diese auf die Performance auswirkt. Aus \autoref{sec: intrinsic}
......@@ -649,7 +651,7 @@
Programm \lstinline{jtop} aufgenommen und die Durchlaufzeit nach Erhalt eines Bildes gemessen.
\begin{figure}
\includegraphics[width=.6\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistortDetection.png}
\includegraphics[width=.75\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistortDetection.png}
\caption{CPU Auslastung des JetBots mit laufender Kamera, Entzerrung und Markierungserkennung}
\label{fig: jtop markings}
\end{figure}
......@@ -721,6 +723,7 @@
};
\end{lstlisting}
\pagebreak
Die \gls{Callback} \lstinline{callback_image()} verläuft vollständig analog zur Implementierung mit \gls{OpenCV}. Der Unterschied liegt in
der Funktion \lstinline{edgeDetectionClassification()}. Diese führt nun die drei Schritte des \gls{canny} durch: Gradienten Bestimmung,
unterdrücken von nicht-lokalen-Maxima und Hysterese-Grenzwertbildung (siehe \cite{Canny:computationAlapproachEdgeDetection}).
......@@ -751,6 +754,7 @@
}
\end{lstlisting}
\pagebreak
Im zweiten Schritt werden nun zusätzlich zur Unterdrückung von Pixeln, welche kein lokales Maximum sind, auch die Klassen bestimmt und
abgespeichert. Da dieser Code sehr viele verschachtelte und gedoppelte \lstinline{if}-Abfragen aufweist, wird er in
\autoref{code: own canny 2} vereinfach gezeigt.
......@@ -807,13 +811,14 @@
\end{lstlisting}
\pagebreak
\subsection{Performance Betrachtung}
Die wichtigste Frage ist nun, wie sich diese Implementierung im Gegensatz zum Ansatz mit \gls{OpenCV} verhält. Dazu wurden wieder die
CPU-Auslastung mittels \lstinline{jtop} erfasst und die Durchlaufzeit des Algorithmus für jedes Bild gemessen.
\begin{figure}
\includegraphics[width=.6\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistortDetection_own.png}
\includegraphics[width=.75\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistortDetection_own.png}
\caption{CPU Auslastung des JetBots mit laufender Kamera, Entzerrung und Markierungserkennung mit eigener Implementierung}
\label{fig: jtop markings own}
\end{figure}
......
......@@ -35,7 +35,7 @@
\end{figure}
Mathematisch lässt dich die Veränderung eines Punktes durch die Verzerrung wie in \autoref{eq: radiale verzerrung} beschrieben berechnen.
Dabei beschreiben $x$ und $y$ die unverzerrten Pixelkoordinaten, $k_1$, $k_3$ und $k_3$ die Verzerrungskoeffizienten.
Dabei beschreiben $x$ und $y$ die unverzerrten Pixelkoordinaten, $k_1$, $k_3$ und $k_3$ die Verzerrungs-Koeffizienten.
Theoretisch existieren noch weitere Koeffizienten, aber in der Praxis haben sich die ersten drei als ausreichend herausgestellt.
\cite{Hanning:highPrecisionCamCalibration}
......@@ -76,7 +76,7 @@
\end{equation}
Somit werden beiden Verzerrungsarten zusammen durch fünf Parameter beschrieben, die sogenannten Verzerrungskoeffizienten. Historisch
Somit werden beiden Verzerrungsarten zusammen durch fünf Parameter beschrieben, die sogenannten Verzerrungs-Koeffizienten. Historisch
begründet wird dabei $k_3$ an das Ende geschrieben, da dieser Parameter früher kaum berücksichtigt wurde.
\begin{equation}
......@@ -153,7 +153,7 @@
\end{lstlisting}
Nun werden alle im aktuellen Ordner befindlichen Bilder eingelesen und in einer Liste abgespeichert. Jedes Listenelement wird eingelesen
und in ein Schwarzweißbild umgewandelt. Dieses wird dann an die \gls{OpenCV} Funktion \lstinline{findChessboardCorners()} übergeben,
und in ein Grauwert-Bild umgewandelt. Dieses wird dann an die \gls{OpenCV} Funktion \lstinline{findChessboardCorners()} übergeben,
welche die Kreuzungspunkte findet und zurückgibt.
\begin{lstlisting}[
......@@ -198,7 +198,7 @@
Jetzt kann die eigentliche Kalibrierung mittels der \gls{OpenCV} Funktion \lstinline{calibrateCamera()} durchgeführt werden. Diese nimmt
die zuvor erstellten Listen von Objektkoordinaten und Bildpunkten und löst damit die in \autoref{sec: intrinsic} beschriebenen
Gleichungen. Als Ergebnis liefert sie die Kameramatrix $K$ und die Verzerrungskoeffizienten $D_{coeff}$ zurück.
Gleichungen. Als Ergebnis liefert sie die Kameramatrix $K$ und die Verzerrungs-Koeffizienten $D_{coeff}$ zurück.
\cite{OpenCV:CameraCalibration}
\begin{lstlisting}[
......@@ -227,7 +227,7 @@
0 & 384,31 & 139,017\\
0 & 0 & 1 \\
\end{pmatrix}
\end{align*} \todo{Formel-Nummer?}
\end{align*}
Um zu zeigen, wie sich das Bild damit verbessern lässt, werden die Ergebnisse auf eines der Bilder angewandt. Da sich die Abmessungen des
entzerrten Bildes, von denen des verzehrten unterscheiden, wird zuerst die \gls{OpenCV} Funktion \lstinline{getOptimalNewCameraMatrix()}
......@@ -238,12 +238,11 @@
das entzerrte Bild mit leeren Pixeln in den Bereichen, wo keine Informationen im Originalbild vorlagen. Um diese leeren \gls{Pixel} zu
entfernen wird das Bild auf die \gls{ROI} reduziert.
\medskip
In \autoref{fig: intrinsik schritte} ist die Entzerrung des Beispielbildes mit dem Zwischenschritt mit Leerpixeln gezeigt.
\begin{figure}
\includegraphics[width=\textwidth]{img/kalibrieren_schritte.png}
\caption{Schritte der intrinsischen Kalibrierung}
\caption{Schritte der Bild-Entzerrung}
\label{fig: intrinsik schritte}
\end{figure}
......@@ -282,14 +281,14 @@
\subsection{Anwenden der Kalibrierung in einer ROS Node} \label{sec: undistort Node}
Um die Kalibrierungsergebnisse auf jedes Bild, dass vom Kamera Treiber veröffentlicht wird, anzuwenden, wird eine weitere \gls{ROS Node}
erstellt. Diese entzerrt jedes erhaltene Bild und veröffentlicht die korrigierte Version als eigenes \gls{Topic}. Das korrigierte Bild wird
sowohl in Farbe als auch in Schwarz-Weiß veröffentlicht. Die Beziehung der \glspl{Topic} ist in \autoref{fig: topics graph undistoreter node}
grafisch dargestellt.
Um die Kalibrierungsergebnisse auf jedes Bild, dass vom Kamera-Treiber veröffentlicht wird, anzuwenden, wird eine weitere \gls{ROS Node}
erstellt. Diese entzerrt jedes erhaltene Bild und veröffentlicht die korrigierte Version als eigenes \gls{Topic}. Das korrigierte Bild
wird sowohl in Farbe als auch in Graustufen veröffentlicht. Die Beziehung der \glspl{Topic} ist in \autoref{fig: topics graph undistoreter
node} grafisch dargestellt.
\begin{figure}
\includegraphics[scale=.85]{svg/Topics_undistorter.pdf}
\caption{Beziehungen der entzerrer Node zu bestehenden Nodes}
\caption{Beziehungen der Entzerrer-Node zu bestehenden Nodes}
\label{fig: topics graph undistoreter node}
\end{figure}
......@@ -332,6 +331,7 @@
);
\end{lstlisting}
\pagebreak
Mit diesen Werten können nun \emph{Mappings} erzeugt werden, welche die geometrische Beziehung zwischen einem \gls{Pixel} im
Originalbild und einem \gls{Pixel} im entzerrten Bild abspeichern. Es werden zwei \emph{Mappings} für die $x$ und die $y$-Koordinate
erzeugt, welche in globalen Variablen abgelegt werden. Das ist notwendig damit die Informationen der \gls{Callback} zur Verfügung
......@@ -364,7 +364,7 @@
Die \gls{Callback} \lstinline{callback_undistort_image()} wurde während der Initialisierung an das \gls{Topic} \lstinline{/img/raw}
angehängt und wird nun für jedes dort veröffentlichte Bild aufgerufen. Der \autoref{code: undistort callback} zeigt eine vereinfachte
Version der Implementierung, ohne Umwandlung in ein Schwarzweißbild und ohne Laufzeitmessung.
Version der Implementierung, ohne Umwandlung in ein Grauwert-Bild und ohne Laufzeitmessung.
Da das Bild als \gls{ROS} eigener Datentyp übergeben wird, muss es zuerst in ein mit \gls{OpenCV} kompatibles Format umgewandelt
werden. Die dazu notwendigen Funktionen sind im \gls{ROS}-Paket \lstinline{cv_bridge} zur Verfügung gestellt. Dessen Funktion
......@@ -374,8 +374,8 @@
jeden \gls{Pixel} des Originalbildes an die korrekte Position im entzerrten Bild zu übertragen. Dabei erfolgt eine lineare
Interpolation.
Das erhaltene Bild wird auf die \gls{ROI} reduziert und unter dem \gls{Topic} \lstinline{/img/color} veröffentlicht. Außerdem wird ein
Schwarz-Weiß Version erzeugt und diese als \lstinline{/img/gray} veröffentlicht, was hier aber nicht gezeigt ist.
Das erhaltene Bild wird auf die \gls{ROI} reduziert und unter dem \gls{Topic} \lstinline{/img/color} veröffentlicht. Außerdem wird
eine Grauwert-Version erzeugt und diese als \lstinline{/img/gray} veröffentlicht, was hier aber nicht gezeigt ist.
\begin{lstlisting}[
float,
......@@ -413,15 +413,15 @@
jedes Bild durchlaufen wird, gemessen.
\begin{figure}
\includegraphics[width=.6\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistort.png}
\caption{CPU Auslastung des JetBots mit laufender Kamera und entzerrer \gls{ROS Node}}
\includegraphics[width=.75\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_cameraUndistort.png}
\caption{CPU Auslastung des JetBots mit laufender Kamera und Entzerrer-\gls{ROS Node}}
\label{fig: jtop cam+undist}
\end{figure}
Der \lstinline{jtop} Screenshot in \autoref{fig: jtop cam+undist} zeigt die CPU Nutzung bei aktivem ROS Core, Kameratreiber und der
neu erstellten Entzerrer \gls{ROS Node}. Die durchschnittliche CPU Auslastung liegt bei ungefähr $35,25\,\percent$, ist also sogar
Der \lstinline{jtop} Screenshot in \autoref{fig: jtop cam+undist} zeigt die CPU Nutzung bei aktivem ROS-Core, Kamera-Treiber und der
neu erstellten Entzerrer-\gls{ROS Node}. Die durchschnittliche CPU-Auslastung liegt bei ungefähr $35,25\,\percent$, ist also sogar
sehr geringfügig niedriger als die in \autoref{sub: performance baseline} gemessene Grundauslastung ohne die neue \gls{ROS Node}. Das
ist aber auf die starke Fluktuation in der CPU Auslastung und die daher ungenauen Messung zurückzuführen. Die Auslastung wird daher
ist aber auf die starke Fluktuation in der CPU-Auslastung und die daher ungenauen Messung zurückzuführen. Die Auslastung wird daher
als identisch betrachtete.
Um die Laufzeit der \gls{ROS Node} zu bestimmen, wird die aktuelle Zeit, wie sie von der Funktion \lstinline{ros::Time::now()}
......
......@@ -13,7 +13,7 @@
Grundlage bilden hierbei verschiedene Operationen, mit welchen sich Bilder verändern lassen. Solche Operationen verknüpfen eine bestimmte
Menge an Pixeln eines Ursprungsbildes mittels einer mathematischen Operation, um ein neues \gls{Pixel} für das Zielbild zu ermitteln. Ein
relativ simples Beispiel hierfür ist das Bilden eines Mittelwertes von jeweils drei Farbpixeln, um ein Schwarzweißbild zu erzeugen.
relativ simples Beispiel hierfür ist das Bilden eines Mittelwertes von jeweils drei Farbpixeln, um ein Grauwert-Bild zu erzeugen.
\cite{szelisk:computerVision-algos+application}
% Häufig kommen bei diesen Operationen sogenannten \gls{Kernel} zum Einsatz. Dabei handelt es sich um Matrizen, welche je nach Anwendung
......@@ -28,7 +28,7 @@
Der sehr grobe Ablauf, welcher solche Operationen zu einem Algorithmus verknüpft, ist in \autoref{fig: genersich} skizziert. Dabei sind
die Einzelschritte in der Realität jedoch häufig sehr kompliziert. Begonnen wird eigentlich immer mit einem Vorbereitungs-Schritt, da die
Bilder einer Kamera nur selten direkt verwendet werden können. Teilweise ist eine solche Vorverarbeitung aber auch hardwareseitig oder in
vorgelagerten Programmteilen umgesetzt. Meisten wird das Bild außerdem in ein Schwarzweißbild umgewandelt, da so nur ein Drittel der
vorgelagerten Programmteilen umgesetzt. Meisten wird das Bild außerdem in ein Grauwert-Bild umgewandelt, da so nur ein Drittel der
Pixel untersucht werden müssen, was die Performance verbessert.
\begin{figure}
......@@ -171,6 +171,7 @@
implementiert und stellt alle $0,2\,\s$ ein aktuelles Bild auf dem \gls{Topic} \lstinline{/img/raw} zur Verfügung.
\pagebreak
\subsection{Performance Baseline} \label{sub: performance baseline}
Da die Leistungsfähigkeit des JetBots relativ eingeschränkt ist und eines der Ziele dieser Arbeit lautet, parallel zu anderen, zukünftigen
......@@ -182,7 +183,7 @@
viele Systeminformationen und Performance-Messwerte gesammelt anzeigt. Ein Screenshot ist in \autoref{fig: jtop baseline} gezeigt.
\begin{figure}
\includegraphics[width=.6\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_baseline.png}
\includegraphics[width=.75\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_baseline.png}
\caption{CPU Auslastung des JetBots ohne \gls{ROS}}
\label{fig: jtop baseline}
\end{figure}
......@@ -195,7 +196,7 @@
gestartet und erneut \lstinline{jtop} überprüft, ergibt sich die in \autoref{fig: jtop cam baseline} gezeigte Screenshot.
\begin{figure}
\includegraphics[width=.6\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_camera.png}
\includegraphics[width=.75\textwidth, trim={0 0 12px 31px}, clip]{img/jtop_camera.png}
\caption{CPU Auslastung mit laufender Kamera und ROS-Core}
\label{fig: jtop cam baseline}
\end{figure}
......@@ -205,13 +206,13 @@
sogenannte ROS Core gestartet sein. Diese geschieht automatisch beim Starten der ersten Node. Es ist für den Großteil der zusätzlichen
Auslastung verantwortlich, sodass zusätzliche \glspl{ROS Node} die Auslastung nur geringfügig erhöhen werden.
\pagebreak
\section{Aufgebaute Fahrbahnfläche} \label{sec: anlgae}
Zum Testen des JetBots für diese Arbeit und andere Projekt wurde eine Projektanlage aufgebaut. Diese besteht aus einer im Maßstab $1\!:\!18$
herunterskalierten Fläche mit aufgedruckter Fahrbahnfläche. Die folgende Abbildung zeigt die Testfläche. Diese hat eine Größe von $200\,\m^2$
und Abmessungen von $20\,\m\!\times\!10\,\m$. Weitere Informationen können dem Projektbericht \cite{bericht:FlächeAutonomesFahren} entnommen
werden.
Zum Testen des JetBots für diese Arbeit und andere Projekt wurde eine die Projektfläche \emph{Autonomes Fahren} aufgebaut. Diese besteht aus
einer im Maßstab $1\!:\!18$ herunterskalierten Fläche mit aufgedruckter Fahrbahn. Die folgende Abbildung zeigt die Projektfläche. Diese hat
eine Größe von $200\,\m^2$ und Abmessungen von $20\,\m\!\times\!10\,\m$. Weitere Informationen können dem Projektbericht
\cite{bericht:FlächeAutonomesFahren} entnommen werden.
\begin{figure}
\includegraphics[width=\textwidth]{img/Fläche_autonomes_Fahren.jpg}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment