diff --git a/.vscode/ltex.dictionary.de-DE.txt b/.vscode/ltex.dictionary.de-DE.txt
index 51871205ab0b6095e06cecdae2257e99c35f4927..cd72a623bde1b68b2771b9e0e7ebdf1681252614 100644
--- a/.vscode/ltex.dictionary.de-DE.txt
+++ b/.vscode/ltex.dictionary.de-DE.txt
@@ -42,3 +42,11 @@ JetBot
 Canny-Edge-Detektor
 Gradientenbetrag
 Gradientenrichtung
+Topics
+canny
+For-Schleifen
+numpy
+if
+überischtlcikeit
+For-Schleife
+Debuggmöglichkeiten
diff --git a/.vscode/ltex.hiddenFalsePositives.de-DE.txt b/.vscode/ltex.hiddenFalsePositives.de-DE.txt
index 90ce5fda704b46bb7e06f629cb9986a44696f9ac..e8ee7517b39bdb49c8d3cf228e525c8bcdb2c570 100644
--- a/.vscode/ltex.hiddenFalsePositives.de-DE.txt
+++ b/.vscode/ltex.hiddenFalsePositives.de-DE.txt
@@ -12,3 +12,5 @@
 {"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QDie Beziehung der Dummies ist in \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q Grafisch dargestellt.\\E$"}
 {"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QUm die Laufzeit der \\E(?:Dummy|Ina|Jimmy-)[0-9]+\\Q zu bestimmen wird die aktuelle Zeit wie sie von der Funktion ros::Time::now() zurückgegeben wird verwendet.\\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 verwendend.\\E$"}
+{"rule":"GERMAN_SPELLER_RULE","sentence":"^\\QHierzu wird wieder das ROS-Paket cv_bridge und dessen Funktion toCvCopy() verwendet.\\E$"}
+{"rule":"DE_AGREEMENT","sentence":"^\\QFür jeden Pixel wird wieder überprüft, ob er ein Startpixel ist.\\E$"}
diff --git a/Bachelorarbeit.pdf b/Bachelorarbeit.pdf
index e3f956c25688d3e9281dba65d5e7577b923eba8f..c9097257d30ac5cd33225133bfc701967866ca77 100644
Binary files a/Bachelorarbeit.pdf and b/Bachelorarbeit.pdf differ
diff --git a/chap/implementation.tex b/chap/implementation.tex
index 284cbb1ee1a183edc450b2dd85b49d7f55aed494..ae9fcd49224467f5a2cedb1ec11b45fd5da3d49f 100644
--- a/chap/implementation.tex
+++ b/chap/implementation.tex
@@ -393,9 +393,282 @@
 
 	\section{Implementierung in eine ROS Node}
 
-		\subsection{Performance Betrachtung}
+		Um den Spurmarkererkennungs-Algorithmus auf jedes Kamerabild anwenden zu können, wird er in einer \gls{ROS Node} umgesetzt. Da der Python-Code
+		bereits auf einem leistungsfähigen Entwickler-PC Laufzeiten von $>0,25\,\s$ hat, wird diese im \gls{C++} implementiert. Dies wird die
+		Performance deutlich verbessern.
+
+		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 die \gls{ROS Node} wir mit dem Namen \lstinline{lane_marker_detection} inizialisiert 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,
+		detektierten Spurmarkern wird nach Durchlauf des Algorithmus auf dem eigenen \gls{Topic} \lstinline{/img/lanemarkings} veröffentlichte.
+
+		Beim Abonnieren des \lstinline{/img/gray} Topics wird die \gls{Callback} \lstinline{callback_image()} angehängt, sodass diese von \gls{ROS}
+		für jedes Bild aufgerufen und das Bild an sie übergeben wird. Da dieses in einem \gls{ROS} eigenen Bild-Datentyp übergeben wird, \gls{OpenCV}
+		diesen aber nicht verwenden kann, ist es nötig das Bild zuerst einmal in einen anderen Datentyp umzuwandeln. Hierzu wird wieder das ROS-Paket
+		\lstinline{cv_bridge} und dessen Funktion \lstinline{toCvCopy()} verwendet.
+
+
+		\subsubsection{Kantenerkennung und Klassifizierung}
+
+			Das so konvertierte Bild kann nun an die Funktion \lstinline{edgeDetectionClassification()} übergeben werden, welche die Erkennung und
+			Klassifizierung der Kanten durchführt. Wie bereits in der \gls{python}-Version wird wieder der \gls{canny} aus \gls{OpenCV} verwendet. Dadurch
+			können die Parameter einfach übernommen werden. Der \autoref{code: canny c++} zeigt den Aufruf. Das Ergebnis mit den detektierten Kanten wird
+			in der Variable \lstinline{canny} abgespeichert.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Aufruf des \gls{canny} in \gls{C++}},
+				label=code: canny c++,
+				language=C++
+			]
+				cv::Mat canny;
+				cv::Canny(image, canny, 180, 50);
+			\end{lstlisting}
+
+			Die Implementierung der Kantenklassifizierung in \gls{C++} lauf im groben sehr ähnlich zur \gls{python}, die wichtigsten Unterschied sind
+			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.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Inizialisieren des leeren Bildes und iteriert über jenes.},
+				label=code: schleifen klassifizierung,
+				language=C++
+			]
+				cv::Mat classified_edges = cv::Mat::zeros(cv::Size(image.cols,image.rows), CV_8U);
+				for (int u=1; u < image.rows-1; u++) {
+					for (int v=1; v < image.cols-1; v++) {
+						if ( ! canny.at<uint8_t>(u,v) )
+							continue;
+			\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
+			Elemente mit dem \gls{Kernel} multipliziert und aufsummiert, wie in \autoref{code: sobel c++} zu sehen.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Bestimmung der Gradienten mittels Sobel},
+				label=code: sobel c++,
+				language=C++
+			]
+				uint8_t e;
+				int dx=0, dy=0;
+				for (int y=0; y<3; y++) {
+					for (int x=0; x<3; x++) {
+						e = image.at<uint8_t>(u+y-1,v+x-1);
+						dx += SOBEL_X[y*3+x] * e;
+						dy += SOBEL_Y[y*3+x] * e;
+					}
+				}
+			\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.
+			Wie es implementiert ist, ist in \autoref{code: klassen c++} dargestellt.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Bestimmung der Gradienten mittels Sobel},
+				label=code: klassen c++,
+				language=C++
+			]
+				double arc = atan2(dy,dx) / 3.1415 * 180.0;
+
+				uint8_t clsif = 0;
+				if (arc < 0)
+					clsif = 0x10;
+				arc = fabsf(arc);
+
+				if (arc<=22.5f || arc>157.5f ) {
+					clsif |= V;
+				} else if ( 67.5f<=arc && arc<112.5f ) {
+					clsif |= H;
+				} else if (( !clsif && arc<67.5f )||( clsif && 112.5f<=arc )) {
+					clsif |= D1;
+				} else if (( clsif && arc<67.5f )||( !clsif && 112.5f<=arc )) {
+					clsif |= D2;
+				}
+				classified_edges.at<uint8_t>(u,v) = clsif;
+			\end{lstlisting}
+
+			Das Ergebnisbild mit den klassifizierten Pixeln wird von der Funktion zurückgegeben und dort weiterverarbeitet.
+
+
+		\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.
+			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.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={For-Schleifen über alle Klassifizierten Pixel},
+				label=code: loop for lines c++,
+				language=C++
+			]
+				for (int u=1; u < classified_edges.rows-1; u++) {
+					for (int v=1; v < classified_edges.cols-1; v++) {
+						uint8_t clsif_org = classified_edges.at<uint8_t>(u,v);
+						if ( ! clsif_org )
+							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
+			\autoref{code: test start c++} gezeigt.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Überprüfen, ob ein Pixel ein Startpixel ist},
+				label=code: test start c++,
+				language=C++
+			]
+				// get only classification without direction:
+				uint8_t clsif = 0x0f & clsif_org;
+				bool has_neighbour = false;
+				switch (clsif) {
+					case V:
+						if ( /* any of the relevant neighbours */ )
+							has_neighbour = true;
+					case D1:
+						if ( /* any of the relevant neighbours */ )
+							has_neighbour = true;
+					case H:
+						if ( /* any of the relevant neighbours */ )
+							has_neighbour = true;
+					case D2:
+						if ( /* any of the relevant neighbours */ )
+							has_neighbour = true;
+				}
+				if ( has_neighbour )
+					continue;
+			\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++}.
+
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Line verfolgen, bis keine Nachbarn mehr existieren},
+				label=code: follow c++,
+				language=C++
+			]
+				pnt start(v,u);
+				// folow line to its end
+				do {
+					classified_edges.at<uint8_t>(u,v) = 0;
+					has_neighbour = false;
+					switch (clsif) {
+						case V:
+							if ( /* any neighbour existis */ )
+								// u+-;v+-; change u,v to new coordinates
+								has_neighbour = true;
+						case D1:
+							if ( /* any neighbour existis */ )
+								// u+-;v+-; change u,v to new coordinates
+								has_neighbour = true;
+						case D2:
+							if ( /* any neighbour existis */ )
+								// u+-;v+-; change u,v to new coordinates
+								has_neighbour = true;
+							}
+						case H:
+							if ( /* any neighbour existis */ )
+								// u+-;v+-; change u,v to new coordinates
+								has_neighbour = true;
+					}
+				} while ( has_neighbour );
+			\end{lstlisting}
+
+			\pagebreak
+			Die so gefunden Linien werden wieder auf ihre Länge überprüft und als Objekte abgespeichert. Dabei werden einzelne Listen für jede Klasse
+			angelegt, sodass diese Später verglichen werden können.
+
+			Besonders wichtig ist es, dass im Gegensatz zu \gls{python} die Schleifenvariablen \lstinline{u,v} manuell wieder auf die
+			Startkoordinaten zurückgesetzt werden müssen.
+
+		\subsubsection{Paarbildung}
+
+			Auch die Bildung von Linienpaaren aus einer rechten und linken Linie Erfolg analog zu \gls{python}. Hier gibt es auch keine großartigen
+			Unterschiede in der Umsetzung, wie \autoref{code: pairing c++} zu sehen ist.
 
+			\begin{lstlisting}[
+				float,
+				style=example,
+				caption={Line verfolgen, bis keine Nachbarn mehr existieren},
+				label=code: pairing c++,
+				language=C++
+			]
+				for(const Line& a : left_D1_edges) {
+					for(auto it = right_D1_edges.begin(); it != right_D1_edges.end(); it++ ) {
+						const Line b = *it;
+						if (
+							( a.start.y - 10 < b.start.y && b.start.y < a.start.y + 10 ) &&
+							( a.start.x < b.start.x && b.start.x < a.start.x + 25 ) &&
+							( a.end.y - 10 < b.end.y && b.end.y < a.end.y + 10 ) &&
+							( a.end.x < b.end.x && b.end.x < a.end.x + 25 )
+						) {
+							markings_found.push_back(LineMarking(a,b, D1));
+							left_D1_edges.erase(it);
+							break;
+						}
+					}
+				}
+			\end{lstlisting}
 
-	\section{Optimierung durch eigene Implementierung des Canny-Edge-Detectors}
 
 		\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}
+			ist ja bereits die Performance mit laufender Kamera- und Entzerrer-Node bekannt. Zum Vergleich wurde wieder die Systemauslastung,
+			insbesondere die der CPU, mit dem Programm jtop aufgenommen. Dies ist in \autoref{fig: jtop markings} Abgebildet.
+
+			\begin{figure}
+				\caption{CPU Auslastung des JetBots mit laufender Kamera, Entzerrung und Markierungserkennung}
+				\label{fig: jtop markings}
+			\end{figure}
+
+
+			\todo[inline]{Robo will nicht booten...}
+
+			Die Performance der \gls{C++} implementiert ist wie erwartet deutlich besser als bei der \gls{python}-Version. Vom Erhalt des Bildes bis
+			zur Veröffentlichung des Ergebnisses mit den gefundenen Linienmarkierungen dauert es
+
+
+			\begin{table}
+				\caption{Gemessene Laufzeit bei 10 Durchläufen der \gls{Callback}}
+				\begin{tabular}{r|S}
+					Durchlauf Nr. & \multicolumn{1}{c}{gemessene Laufzeit} \\\hline
+					1             & 3,885214 \,\ms                         \\
+					2             & 4,068192 \,\ms                         \\
+					3             & 3,968679 \,\ms                         \\
+					4             & 3,711925 \,\ms                         \\
+					5             & 3,969982 \,\ms                         \\
+					6             & 4,085944 \,\ms                         \\
+					7             & 4,024673 \,\ms                         \\
+					8             & 3,897130 \,\ms                         \\
+					9             & 3,752863 \,\ms                         \\
+					10            & 4,095999 \,\ms                         \\
+				\end{tabular}
+				\todo[inline]{ist die Tabelle überhaupt sinnvoll?}
+			\end{table}
+
+
+	% \section{Optimierung durch eigene Implementierung des Canny-Edge-Detectors}
+
+	% 	\subsection{Performance Betrachtung}