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

glossar: Pixel /+Nachbarschaft

parent 8c39cb90
Branches
No related tags found
No related merge requests found
......@@ -17,7 +17,7 @@
Dies ist möglicherweise bereits Teileweise durch den vorherigen Punkt mit abgedeckt, bedarf aber trotzdem einer weiteren Erklärung. Derzeit
werden vor allem bei weiter von der Kamera entfernten Linien, also vor allem den Spurmarkierungen benachbarter Spuren, viele
Fehlklassifizierungen durchgeführt. Wie in \autoref{fig: schlechte kante} gezeigt wird eine Kante durch fehlklassifizierte Pixel unterbrochen,
Fehlklassifizierungen durchgeführt. Wie in \autoref{fig: schlechte kante} gezeigt wird eine Kante durch fehlklassifizierte \gls{Pixel} unterbrochen,
sodass eine durchgängige Linienverfolgung nicht möglich ist.
Hier könnten zuerst einmal Ansätze zum Verbinden von sehr eng zusammen liegenden Linien Abhilfe schaffen. Aber eine Verbesserung der
......
......@@ -51,9 +51,9 @@
Kegelgröße und der Wert für $\sigma$ übergeben wird.
Die eigentliche Kantenerkennung wird mittels eines \glspl{canny} durchgeführt. Dabei handelt es sich um einen von John Canny 19983
entwickelten und in \cite{Canny:computationAlapproachEdgeDetection} veröffentlichten Algorithmus. Dieser bestimmt für jeden Pixel den
Gradientenbetrag der Gradienten in X- und Y-Richtung. Dann werden diejenigen Pixel unterdrückt, welche entlang der Gradientenrichtung kein
Maximum darstellen. Zum Abschluss wird das Bild mit einem Hysterese-Schwellwert binarisiert. Das bedeutet, dass alle Pixel über einem
entwickelten und in \cite{Canny:computationAlapproachEdgeDetection} veröffentlichten Algorithmus. Dieser bestimmt für jeden \gls{Pixel} den
Gradientenbetrag der Gradienten in X- und Y-Richtung. Dann werden diejenigen \gls{Pixel} unterdrückt, welche entlang der Gradientenrichtung kein
Maximum darstellen. Zum Abschluss wird das Bild mit einem Hysterese-Schwellwert binarisiert. Das bedeutet, dass alle \gls{Pixel} über einem
initialen, oberen Schwellwert als Kanten gesetzt werden und mittels eines zweiten, niedrigeren Schwellwerte, Lücken zwischen diesen Pixeln
geschlossen werden. \cite{Nischwitz:Computergrafik2}
......@@ -78,7 +78,7 @@
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 Grabentenbetrachtung, liefert der \gls{canny}
Kantenmarkierungen (hier in weiß) die nur ein\todo{einen?} Pixel breit sind. Dies ermöglicht die in den folgenden Unterkapiteln
Kantenmarkierungen (hier in weiß) die nur ein\todo{einen?} \gls{Pixel} breit sind. Dies ermöglicht die in den folgenden Unterkapiteln
beschriebenen Schritte.
\begin{figure}
......@@ -127,8 +127,8 @@
\end{table}
Um die Klassifizierung in \gls{python} durchzuführen, wird zuerst ein weiteres, leere 8-Bit Bild mit identischer Größe angelegt. Dann wird
erneut über alle Pixel des Bildes iteriert. Da allerdings die meisten Pixel schwarz und damit uninteressant sind, können diese direkt
verworfen werden. Für alle verbleibenden, weißen Pixel wird die Klassifizierung durchgeführt.
erneut über alle \gls{Pixel} des Bildes iteriert. Da allerdings die meisten \gls{Pixel} schwarz und damit uninteressant sind, können diese direkt
verworfen werden. Für alle verbleibenden, weißen \gls{Pixel} wird die Klassifizierung durchgeführt.
\begin{lstlisting}[
float,
......@@ -173,10 +173,10 @@
\end{split}
\end{equation}
Zuerst die Gradienten $d_x$ und $d_y$ ermittel. Dazu wird die $3\!\times\!3$ Pixelnachbarschaft des aktuellen Pixels elementweise mit dem
Zuerst die Gradienten $d_x$ und $d_y$ ermittel. Dazu wird die $3\!\times\!3$ \gls{Pixelnachbarschaft} des aktuellen Pixels elementweise mit dem
jeweiligen Sobel-\gls{Kernel} multipliziert und die Summe der Ergebnismatrix gebildet (siehe \autoref{eq: dx dy}). Das Pythonpaket
\lstinline{numpy} stellt hierfür sehr hilfreiche Funktion zum Arbeiten mit Matrizen zu Verfügung. Dadurch lässt sich diese Operation in
wenigen Zeilen durchführen, wie \autoref{code dx dy} gezeigt.
wenigen Zeilen durchführen, wie \autoref{code: dx dy} gezeigt.
\begin{lstlisting}[
float,
......@@ -268,14 +268,14 @@
Fahrspurmarkierung.
Für den ersten Schritt ist es ein weiters mal nötig über das gesamte Bild zu iteriert. Auch diesmal können wieder alle schwarzen Pixel
übersprungen werden. Wird ein klassifiziertes 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 Pixel der \emph{Vertikal}
Klasse ein Startpixel, wenn sich direkt oder diagonal über ihm keine weiteren Pixel derselben Klasse befinden.
ü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}
Klasse ein Startpixel, wenn sich direkt oder diagonal über ihm keine weiteren \gls{Pixel} derselben Klasse befinden.
Ist ein Startpixel gefunden, wird es für später abgespeichert. Nun wird der Linie zu ihrem Ende gefolgt. Dazu wird der nächste
Nachbarpixel gesucht. Da die grobe Richtung entsprechend der Klasse bekannt ist, müssen hier nicht alle Nachbarpixel überprüft werden.
Beim Beispiel mit der \emph{Vertikal} Klasse müssten die Pixel direkt und diagonal unterhalb betrachtet werden. Existiert ein Nachbar wird
dieser ausgewählt und der Prozess wiederholt. Dabei werden alle bereits besuchten Pixel aus dem Bild gelöscht, damit sich nicht nocheinaml
Beim Beispiel mit der \emph{Vertikal} Klasse müssten die \gls{Pixel} direkt und diagonal unterhalb betrachtet werden. Existiert ein Nachbar wird
dieser ausgewählt und der Prozess wiederholt. Dabei werden alle bereits besuchten \gls{Pixel} aus dem Bild gelöscht, damit sich nicht nocheinaml
untersucht werden.
\begin{lstlisting}[
......@@ -302,7 +302,7 @@
lines.append(l)
\end{lstlisting}
Hat ein Pixel keine weiteren Nachbarn, ist er der Endpunkt dieser Linie. Start und Endpunkt werden in ein Linienobjekt zusammengefasst
Hat ein \gls{Pixel} keine weiteren Nachbarn, ist er der Endpunkt dieser Linie. Start und Endpunkt werden in ein Linienobjekt zusammengefasst
und abgespeichert. Zusätzliche wird ebenfalls die Orientierungsklasse mit abgespeichert.
Mittels Start- und Endpunkt kann außerdem die Länge der Linie bestimmt werden. Da durch die in \autoref{sub: genauigkeit klassifizierung}
......@@ -430,7 +430,7 @@
die For-Schleifen für beide Dimensionen des Bildes, welche explizit einzeln verwendet werden müssen, und die Beachtung von Datentypen.
Die Erstellung des benötigten, leeren Bildes und die For-Schleifen sind in \autoref{code: schleifen klassifizierung} zu sehen. Auch hier
werden wieder aller leeren Pixel übersprungen.
werden wieder aller leeren \gls{Pixel} übersprungen.
\begin{lstlisting}[
float,
......@@ -447,7 +447,7 @@
\end{lstlisting}
Die Bestimmung der Gradienten mittels Sobel 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$ Pixelnachbarschaft iteriert, die
\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.
\begin{lstlisting}[
......@@ -505,12 +505,12 @@
\subsubsection{Linienbildung}
Mit dem klassifizierten Bild kann nun dieselbe Methodik zur Identifizierung zusammenhängender Linien wie in Python angewendet werden.
Allerdings ist in \gls{C++} das Definieren und Testen der relevanten Pixelnachbarschaft nicht so übersichtlich möglich wie in Python.
Allerdings ist in \gls{C++} das Definieren und Testen der relevanten \gls{Pixelnachbarschaft} nicht so übersichtlich möglich wie in Python.
Daher müssen viele lange \lstinline{if} Bedingungen verwendet werden, welche in den folgenden Codebeispielen zur Übersichtlichkeit verkürzt
sind.
Begonnen wird wieder mit einer doppelten For-Schleife über das gesamte Bild, wie in \autoref{code: loop for lines c++} zu sehen. Dabei
werden wieder alle leeren Pixel vernachlässigt.
werden wieder alle leeren \gls{Pixel} vernachlässigt.
\begin{lstlisting}[
float,
......@@ -526,14 +526,14 @@
continue;
\end{lstlisting}
Für jeden Pixel wird wieder überprüft, ob er ein Startpixel ist. Genau wie in \gls{python} ist hierfür wieder der Klasse entsprechend eine
Pixelnachbarschaft relevant. Ist dort ein Nachbar gleicher Klasse vorhanden, wird mit dem nächsten Pixel weitergemacht. Dies ist in
Für jeden \gls{Pixel} wird wieder überprüft, ob er ein Startpixel ist. Genau wie in \gls{python} ist hierfür wieder der Klasse entsprechend eine
\gls{Pixelnachbarschaft} relevant. Ist dort ein Nachbar gleicher Klasse vorhanden, wird mit dem nächsten \gls{Pixel} weitergemacht. Dies ist in
\autoref{code: test start c++} gezeigt.
\begin{lstlisting}[
float,
style=example,
caption={Überprüfen, ob ein Pixel ein Startpixel ist},
caption={Überprüfen, ob ein \gls{Pixel} ein Startpixel ist},
label=code: test start c++,
language=C++
]
......@@ -559,7 +559,7 @@
\end{lstlisting}
Ist ein Startpixel gefunden, wird er gespeichert und wieder so lange der nächste Nachbar ausgewählt, bis kein Nachbar mehr vorhanden ist.
Dann ist die gesamte Linie nachverfolgt. Dabei werden alle besuchten Pixel aus dem Bild gelöscht. Siehe dazu \autoref{code: follow c++}.
Dann ist die gesamte Linie nachverfolgt. Dabei werden alle besuchten \gls{Pixel} aus dem Bild gelöscht. Siehe dazu \autoref{code: follow c++}.
\begin{lstlisting}[
float,
......
......@@ -222,10 +222,10 @@
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()}
verwendet, welche eine weiter Skalierte Kameramatrix ermittelt, mit der die Abmessungen zueinander passen. Diese liefert außerdem eine
\gls{ROI}, also den Bildbereich der nur relevante (nicht leere) Pixel enthält.
\gls{ROI}, also den Bildbereich der nur relevante (nicht leere) \gls{Pixel} enthält.
Mit dieser zusätzlichen Matrix kann nun die \gls{OpenCV} Funktion \lstinline{undistort()} auf das Bild angewandt werden. Diese Produziert das
entzerrte Bild mit leeren Pixeln in den Bereichen, wo keine Informationen im Originalbild vorlagen. Um diese leeren Pixel zu entfernen wird
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
......@@ -322,16 +322,16 @@
);
\end{lstlisting}
Mit diesen Werten können nun \emph{Mappings} erzeugt werden, welche die geometrische Beziehung zwischen einem Pixel im Originalbild und
einem Pixel im entzerrten Bild abspeichern. Es werden zwei \emph{Mappings} für die X und die Y-Koordinate erzeugt, welche in globalen
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 stehen.
Zuvor ist es aber noch sinnvoll, eine umskalierte, optimierte Kameramatrix zu erzeugen. \gls{OpenCV} stellt hierzu die Funktion
\lstinline{getOptimalNewCameraMatrix()} zur Verfügung. Diese erstellt die neue Matrix abhängig von einem freien Skalierungsparameter
$\alpha$. Für $\alpha=0$ ist die zurückgegebene Matrix so gewählt, dass das entzerrte Bild möglichst wenig unbekannte Pixel enthält. Das
bedeutet aber, dass einige Pixel des Originalbildes außerhalb des neuen Bildbereiches liegen und vernachlässigt werden. Mit $\alpha=1$
enthält das entzerrte Bild alle Pixel des Originalbildes, allerdings bleiben einige Pixel schwarz. Da die Funktion zusätzlichen eine
\gls{ROI} liefert, welches den Bildausschnitt ohne schwarze Pixel beschreibt, wird hier $\alpha=1$ verwendet. Die veröffentlichten Bilder
$\alpha$. Für $\alpha=0$ ist die zurückgegebene Matrix so gewählt, dass das entzerrte Bild möglichst wenig unbekannte \gls{Pixel} enthält. Das
bedeutet aber, dass einige \gls{Pixel} des Originalbildes außerhalb des neuen Bildbereiches liegen und vernachlässigt werden. Mit $\alpha=1$
enthält das entzerrte Bild alle \gls{Pixel} des Originalbildes, allerdings bleiben einige \gls{Pixel} schwarz. Da die Funktion zusätzlichen eine
\gls{ROI} liefert, welches den Bildausschnitt ohne schwarze \gls{Pixel} beschreibt, wird hier $\alpha=1$ verwendet. Die veröffentlichten Bilder
werden zwar auf die \gls{ROI} reduziert, aber die vorhanden Informationen werdenden grundsätzlich erhalten und bei Bedarf kann das
Programm einfach angepasst werden, um die vollständigen Bilder zu veröffentlichen.
......@@ -360,7 +360,7 @@
\lstinline{toCvCopy()} kopiert die Daten des Originalbildes in eine OpenCV Matrix, welche weiter verwendet werden kann.
Das Bild kann nun mit der OpenCV Funktion \lstinline{remap()} entzerrt werden. Diese benutzt die zuvor bestimmten \emph{Mappings}, um
jeden Pixel des Originalbildes an die korrekte Position im entzerrten Bild zu übertragen. Dabei wird linear interpoliert.
jeden \gls{Pixel} des Originalbildes an die korrekte Position im entzerrten Bild zu übertragen. Dabei wird linear interpoliert.
Das Erhalten 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).
......@@ -434,12 +434,12 @@
\end{table}
\section{Extrinsische Kalibrierung} \label{sec: extrensic}
% \section{Extrinsische Kalibrierung} \label{sec: extrensic}
\begin{figure}
\includegraphics[scale=.5]{svg/Sketch_JetBot_translation.pdf}
\end{figure}
% \begin{figure}
% \includegraphics[scale=.5]{svg/Sketch_JetBot_translation.pdf}
% \end{figure}
\begin{figure}
\includegraphics[scale=.5]{svg/Sketch_JetBot_front.pdf}
\end{figure}
% \begin{figure}
% \includegraphics[scale=.5]{svg/Sketch_JetBot_front.pdf}
% \end{figure}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment