SoSe24 - Praktikum Systementwurf - Segmentierung der Fahrbahnmarkierungen: Unterschied zwischen den Versionen
(→PAP) |
|||
(17 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
[[Datei: | [[Datei:GeradeInKurve SegmenteGIF.gif|600px|thumb|right|Abb. 1: Das Ergebnis unseres Algorithmus.]] | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
Zeile 12: | Zeile 12: | ||
== Einleitung == | == Einleitung == | ||
Aufgabe war es einen Algorithmus zu entwickeln, welcher die Fahrbahnmarkierungen erkennt. Dieses wurde mit Hilfe von Matlab und der bwconncomp Methode umgesetzt. | |||
== PAP == | == PAP == | ||
PAP | Das PAP des Hauptprogramms liefert einen Überblick über das generelle Programm, während das PAP des Algorithmus sich mehr auf die Details bezieht wie die Fahrbahn erkannt wird. | ||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| <strong>Programmablaufplan </strong> | | <strong>Programmablaufplan des Hauptprogramms </strong> | ||
|- | |- | ||
| PAP | |[[Datei:SegmentiereFahrbahnmarkierungen Team2.png|600px|thumb|Abb. 2: PAP des Hauptprogramms]] | ||
|} | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Programmablaufplan des Algorithmus </strong> | |||
|- | |||
|[[Datei:MarkRoadway-Methode.png|600px|thumb|Abb. 2: PAP der Methode markRoadway]] | |||
|} | |} | ||
Zeile 28: | Zeile 34: | ||
|- | |- | ||
|<source line lang="matlab" style="font-size:medium"> | |<source line lang="matlab" style="font-size:medium"> | ||
clear all, | |||
close all | |||
clc | |||
%% Video laden | |||
video = VideoReader('GeradeInKurve_IPT.mp4'); | |||
n = video.NumFrames; | |||
% Video Writer initialisieren | |||
outputVideoFile = 'GeradeInKurve_Segmente.mp4'; | |||
outputVideo = VideoWriter(outputVideoFile, 'MPEG-4'); | |||
outputVideo.FrameRate = video.FrameRate; % gleiche Bildrate wie das Originalvideo | |||
open(outputVideo); | |||
centerX = 450; | |||
centerY = 325; | |||
areaDistance = 150; | |||
% Frames extrahieren, bearbeiten und in das neue Video schreiben | |||
while hasFrame(video) | |||
frame = readFrame(video); | |||
% Frame bearbeiten | |||
%grayFrame = rgb2gray(frame); | |||
processedFrame = markRoadway(frame, centerX, centerY, areaDistance); | |||
% Bearbeitete Frames in das neue Video schreiben | |||
writeVideo(outputVideo, im2uint8(processedFrame)); | |||
end | |||
% Video Writer schließen | |||
close(outputVideo); | |||
function markedIm = markRoadway(image, centerX, centerY, areaDistance) | |||
binIm = imbinarize(image); | |||
CC = bwconncomp(binIm); | |||
imSize = CC.ImageSize; | |||
n = CC.NumObjects; | |||
centerArea = [centerX-areaDistance, centerX; centerY-areaDistance, centerY+areaDistance]; | |||
nearestLeft = Inf; | |||
leftObject = []; | |||
nearestRight = Inf; | |||
rightObject = []; | |||
middleObjects = {}; | |||
arrayLength = 0; | |||
for i = 1:n | |||
object = CC.PixelIdxList{i}; | |||
[x, y] = ind2sub(imSize, object); | |||
[~, maxIndex] = max(x); | |||
maxY = y(maxIndex); | |||
distanceY = centerY - maxY; | |||
if inBetweenArea(centerArea, x, y) | |||
arrayLength = arrayLength + 1; | |||
middleObjects{arrayLength} = object; | |||
disp("BETWEEN"); | |||
elseif distanceY > 0 && distanceY < nearestLeft && touchingArea(centerArea, x, y) | |||
nearestLeft = distanceY; | |||
leftObject = object; | |||
%disp("FOUND LEFT " + num2str(distanceY)); | |||
elseif distanceY < 0 && abs(distanceY) < nearestRight && touchingArea(centerArea, x, y) | |||
nearestRight = abs(distanceY); | |||
rightObject = object; | |||
%disp("FOUND RIGHT " + num2str(distanceY)); | |||
end | |||
end | |||
leftY = 0; | |||
rightY = 100; | |||
if ~isempty(rightObject) | |||
[x, y] = ind2sub(imSize, rightObject); | |||
[~, maxIndex] = max(x); | |||
rightY = y(maxIndex); | |||
end | |||
if ~isempty(leftObject) | |||
[x, y] = ind2sub(imSize, leftObject); | |||
[~, maxIndex] = max(x); | |||
leftY = y(maxIndex); | |||
end | |||
%% Darstellung | |||
markedIm = drawRectangle(image, centerArea(1,1), centerArea(1,2), centerArea(2,1), centerArea(2,2), 0, 0, 255); | |||
for i = 1:arrayLength | |||
object = middleObjects{i}; | |||
[x, y] = ind2sub(imSize, object); | |||
[~, maxIndex] = max(x); | |||
maxY = y(maxIndex); | |||
if maxY >= leftY && maxY <= rightY | |||
markedIm = paintArea(markedIm, x, y, 255, 0, 0); | |||
disp("FOUND MIDDLE"); | |||
else | |||
disp(["[FAILED] maxY:", num2str(maxY), " leftY:", num2str(leftY), " rightY:", num2str(rightY)]); | |||
end | |||
end | |||
if ~isempty(rightObject) | |||
[x, y] = ind2sub(imSize, rightObject); | |||
markedIm = paintArea(markedIm, x, y, 255, 255, 0); | |||
end | |||
if ~isempty(leftObject) | |||
[x, y] = ind2sub(imSize, leftObject); | |||
markedIm = paintArea(markedIm, x, y, 0, 255, 0); | |||
end | |||
end | |||
function result = inBetweenArea(area, objectX, objectY) | |||
resX = all(objectX >= area(1, 1) & objectX <= area(1, 2)); | |||
resY = all(objectY >= area(2, 1) & objectY <= area(2, 2)); | |||
result = resX & resY; | |||
end | |||
function result = touchingArea(area, objectX, objectY) | |||
resX = any(objectX >= area(1, 1) & objectX <= area(1, 2)); | |||
resY = any(objectY >= area(2, 1) & objectY <= area(2, 2)); | |||
result = resX & resY; | |||
end | |||
function outImage = drawRectangle(image, x1, x2, y1, y2, r, g, b) | |||
imSize = size(image); | |||
sizeX = imSize(1); | |||
sizeY = imSize(2); | |||
if x1 < 0 | |||
x1 = 0; | |||
end | |||
if y1 < 0 | |||
y1 = 0; | |||
end | |||
if x2 > sizeX | |||
x2 = sizeX; | |||
end | |||
if y2 > sizeY | |||
y2 = sizeY; | |||
end | |||
outImage = image; | |||
for x = x1:x2 | |||
for y = y1:y2 | |||
%disp([num2str(x), num2str(y)]); | |||
outImage = paintPixel(outImage, x, y, r, g, b); | |||
end | |||
end | |||
end | |||
function outImage = paintArea(image, xArr, yArr, r, g, b) | |||
for i = 1:length(xArr) | |||
image = paintPixel(image, xArr(i), yArr(i), r, g, b); | |||
end | |||
outImage = image; | |||
end | |||
function image = paintPixel(image, x, y , r, g, b) | |||
if x >= 1 && x <= size(image, 1) && y >= 1 && y <= size(image, 2) | |||
image(x, y, 1) = r; | |||
image(x, y, 2) = g; | |||
image(x, y, 3) = b; | |||
else | |||
%disp(['Ungültiger Index: x=', num2str(x), ', y=', num2str(y)]); | |||
end | |||
end | |||
</source> | </source> | ||
|} | |} | ||
== Ergebnisse == | == Ergebnisse == | ||
* Darstellung der Ergebnisse | * '''Darstellung der Ergebnisse''' | ||
[[Datei:Unbearbeitete Fahrbahn.jpg|600px|thumb|Abb. 3: Das ist ein biniarisiertes Bild von einer Aufnahme der Kamera. Man sieht die Fahrbahnmarkierungen und eine weitere.]] | |||
[[Datei:Erkannte fahrbahn.jpg|600px|thumb|Abb. 4: Das ist das bearbeitete Bild welches aus der Aufnahme durch den Algorithmus entstanden ist.]] | |||
* '''Links zu den Arbeitsergebnissen''' | * '''Links zu den Arbeitsergebnissen''' | ||
[https://svn.hshl.de/svn/MTR_SDE_Praktikum/trunk/_Semesterordner/SS2024/Team_2_Sander_Fleer/Termin_9/9_5/ Link zu dem SVN-Ordner der Arbeitsergebnisse] | |||
== Analyse == | == Analyse == | ||
Zeile 41: | Zeile 228: | ||
! Beschreibung !! Das Problem ist.. !! Das Problem ist nicht... | ! Beschreibung !! Das Problem ist.. !! Das Problem ist nicht... | ||
|- | |- | ||
| Was genau ist das Problem? || | | Was genau ist das Problem? || Äußere Einflüsse wie Licht oder Objekte werfen Flecken || | ||
|- | |- | ||
| Wo tritt das Problem auf? || Beispiel || Beispiel | | Wo tritt das Problem auf? || Beispiel || Beispiel | ||
Zeile 69: | Zeile 256: | ||
== Zusammenfassung == | == Zusammenfassung == | ||
* Zusammenfassung | * Zusammenfassung | ||
Der Algorithmus funktioniert auf Bilderebene einwandfrei, allerdings tut er sich aus unerklärlichen Gründen bei einem Video deutlich schwerer, wobei eigentlich ein Video auch nur aus hintereinander gereihten Bildern besteht. | |||
* Diskussion der Ergebnisse | * Diskussion der Ergebnisse | ||
Die Ergebnisse sind nicht wirklich zufriedenstellend. Der Algorithmus hat noch viele Fehler weswegen eine Spurführung quasi unmöglich wäre. | |||
* Ausblick | * Ausblick | ||
Eine deutliche Verbesserung des Algorithmus wäre eine Weiterführung der Mittleren Linien durch die Gradientenvektoren. | |||
* Lessons Learned | * Lessons Learned | ||
So einen Algorithmus zu entwerfen macht Spaß ist aber extrem zeit intensiv. Die Entwicklung für den Algorithmus hat ca. 20 Stunden gebraucht und er funktioniert immernoch nicht richtig, was sehr frustrierend ist. | |||
== Beantwortung der Lernzielkontrollfragen == | == Beantwortung der Lernzielkontrollfragen == | ||
# Mit welchen Ansätzen lassen sich die Mittle- und rechte Fahrspur segmentieren? | # '''Mit welchen Ansätzen lassen sich die Mittle- und rechte Fahrspur segmentieren?''' Wir haben den Einsatz einer Ebene gewählt, damit schließt man im ersten Schritt viele der äußeren Einflüsse wie Lichtreflektionen und ähnliches aus. Im nächsten Schritt haben wir versucht Objekte zu finden, die größer sind als die Ebene, aber dennoch diese in ihren untersten Punkten berühren. Im Anschluss sortieren wir die gefundenen Objekte nach der Nähe zum Mittelpunkt. Und so finden wir die Linke und Rechte Fahrbahnmarkierungen. Die mittlere finden wir durch die Linke und Rechte Begrenzung, jedes weitere gefundene Objekt muss sich dazwischen befinden um als eine Mittellinie erkannt zu werden. Die außerhalb liegenden Mittellinien können dann über die Gradienten der gefundenen Mittellinien berechnet werden. | ||
# Wieso sollten alle Fahrbahnränder segmentiert werden? | # '''Wieso sollten alle Fahrbahnränder segmentiert werden?''' Bei Kurvenfahrten kann es passieren, dass eine der Fahrbahnränder nicht mehr von der Kamera gesehen wird und dementsprechend muss darauf reagiert werden können. Wenn ich mindestens Links und Rechts nehme habe ich das Problem der Kurvenfahrt nicht mehr, da immer ein Fahrbahnrand übrig ist. Die Mittellinien braucht man, damit das Auto nicht auf der falschen Seite fährt und es so zu Unfällen kommen kann. | ||
# Welche Vor- und Nachteile hat die Segmentierung? | # '''Welche Vor- und Nachteile hat die Segmentierung?''' Die Segmentierung ist ein schnelles Verfahren welches in Echtzeit angewendet werden kann. Ein großer Nachteil sind Lichteinflüsse da diese mehrere Segmente miteinander verbinden, so kann nicht mehr alles richtig segmentiert werden kann. | ||
# Wie könnten die Nachteile behandelt werden? | |||
# '''Wie könnten die Nachteile behandelt werden?''' Man könnte das ganze mit der Hough Transformation machen, da diese Präzise auf Linien reagieren kann. Hough Transformationen haben eine höhere Resistenz gegenüber äußeren Einflüssen, dafür ist diese allerdings langsamer. | |||
---- | ---- | ||
→ zurück zum Hauptartikel: [[Praktikum_SDE|Praktikum SDE]] | [[SDE-Team 2024/25]] | [[SoSe24_-_Praktikum_Systementwurf_-_Lernzielkontrolle_3|Lernzielkontrolle 3]] | → zurück zum Hauptartikel: [[Praktikum_SDE|Praktikum SDE]] | [[SDE-Team 2024/25]] | [[SoSe24_-_Praktikum_Systementwurf_-_Lernzielkontrolle_3|Lernzielkontrolle 3]] |
Version vom 3. Juli 2024, 16:33 Uhr
Autoren: | Dennis Fleer, Philipp Sander |
Thema: | Segmentierung der Fahrbahnmarkierungen |
Workshoptermin 9: | 20.06.2024 |
Lernzielkontrolle 3: | 04.07.2024 |
Einleitung
Aufgabe war es einen Algorithmus zu entwickeln, welcher die Fahrbahnmarkierungen erkennt. Dieses wurde mit Hilfe von Matlab und der bwconncomp Methode umgesetzt.
PAP
Das PAP des Hauptprogramms liefert einen Überblick über das generelle Programm, während das PAP des Algorithmus sich mehr auf die Details bezieht wie die Fahrbahn erkannt wird.
Programmablaufplan des Hauptprogramms |
Programmablaufplan des Algorithmus |
Quelltext
- MATLAB Quelltext Ihrer Lösung mit Header und Kommentaren.
- Beachten Sie die Programmierrichtlinien für MATLAB®.
segmentiereFahrbahnmarkierungen.m |
clear all,
close all
clc
%% Video laden
video = VideoReader('GeradeInKurve_IPT.mp4');
n = video.NumFrames;
% Video Writer initialisieren
outputVideoFile = 'GeradeInKurve_Segmente.mp4';
outputVideo = VideoWriter(outputVideoFile, 'MPEG-4');
outputVideo.FrameRate = video.FrameRate; % gleiche Bildrate wie das Originalvideo
open(outputVideo);
centerX = 450;
centerY = 325;
areaDistance = 150;
% Frames extrahieren, bearbeiten und in das neue Video schreiben
while hasFrame(video)
frame = readFrame(video);
% Frame bearbeiten
%grayFrame = rgb2gray(frame);
processedFrame = markRoadway(frame, centerX, centerY, areaDistance);
% Bearbeitete Frames in das neue Video schreiben
writeVideo(outputVideo, im2uint8(processedFrame));
end
% Video Writer schließen
close(outputVideo);
function markedIm = markRoadway(image, centerX, centerY, areaDistance)
binIm = imbinarize(image);
CC = bwconncomp(binIm);
imSize = CC.ImageSize;
n = CC.NumObjects;
centerArea = [centerX-areaDistance, centerX; centerY-areaDistance, centerY+areaDistance];
nearestLeft = Inf;
leftObject = [];
nearestRight = Inf;
rightObject = [];
middleObjects = {};
arrayLength = 0;
for i = 1:n
object = CC.PixelIdxList{i};
[x, y] = ind2sub(imSize, object);
[~, maxIndex] = max(x);
maxY = y(maxIndex);
distanceY = centerY - maxY;
if inBetweenArea(centerArea, x, y)
arrayLength = arrayLength + 1;
middleObjects{arrayLength} = object;
disp("BETWEEN");
elseif distanceY > 0 && distanceY < nearestLeft && touchingArea(centerArea, x, y)
nearestLeft = distanceY;
leftObject = object;
%disp("FOUND LEFT " + num2str(distanceY));
elseif distanceY < 0 && abs(distanceY) < nearestRight && touchingArea(centerArea, x, y)
nearestRight = abs(distanceY);
rightObject = object;
%disp("FOUND RIGHT " + num2str(distanceY));
end
end
leftY = 0;
rightY = 100;
if ~isempty(rightObject)
[x, y] = ind2sub(imSize, rightObject);
[~, maxIndex] = max(x);
rightY = y(maxIndex);
end
if ~isempty(leftObject)
[x, y] = ind2sub(imSize, leftObject);
[~, maxIndex] = max(x);
leftY = y(maxIndex);
end
%% Darstellung
markedIm = drawRectangle(image, centerArea(1,1), centerArea(1,2), centerArea(2,1), centerArea(2,2), 0, 0, 255);
for i = 1:arrayLength
object = middleObjects{i};
[x, y] = ind2sub(imSize, object);
[~, maxIndex] = max(x);
maxY = y(maxIndex);
if maxY >= leftY && maxY <= rightY
markedIm = paintArea(markedIm, x, y, 255, 0, 0);
disp("FOUND MIDDLE");
else
disp(["[FAILED] maxY:", num2str(maxY), " leftY:", num2str(leftY), " rightY:", num2str(rightY)]);
end
end
if ~isempty(rightObject)
[x, y] = ind2sub(imSize, rightObject);
markedIm = paintArea(markedIm, x, y, 255, 255, 0);
end
if ~isempty(leftObject)
[x, y] = ind2sub(imSize, leftObject);
markedIm = paintArea(markedIm, x, y, 0, 255, 0);
end
end
function result = inBetweenArea(area, objectX, objectY)
resX = all(objectX >= area(1, 1) & objectX <= area(1, 2));
resY = all(objectY >= area(2, 1) & objectY <= area(2, 2));
result = resX & resY;
end
function result = touchingArea(area, objectX, objectY)
resX = any(objectX >= area(1, 1) & objectX <= area(1, 2));
resY = any(objectY >= area(2, 1) & objectY <= area(2, 2));
result = resX & resY;
end
function outImage = drawRectangle(image, x1, x2, y1, y2, r, g, b)
imSize = size(image);
sizeX = imSize(1);
sizeY = imSize(2);
if x1 < 0
x1 = 0;
end
if y1 < 0
y1 = 0;
end
if x2 > sizeX
x2 = sizeX;
end
if y2 > sizeY
y2 = sizeY;
end
outImage = image;
for x = x1:x2
for y = y1:y2
%disp([num2str(x), num2str(y)]);
outImage = paintPixel(outImage, x, y, r, g, b);
end
end
end
function outImage = paintArea(image, xArr, yArr, r, g, b)
for i = 1:length(xArr)
image = paintPixel(image, xArr(i), yArr(i), r, g, b);
end
outImage = image;
end
function image = paintPixel(image, x, y , r, g, b)
if x >= 1 && x <= size(image, 1) && y >= 1 && y <= size(image, 2)
image(x, y, 1) = r;
image(x, y, 2) = g;
image(x, y, 3) = b;
else
%disp(['Ungültiger Index: x=', num2str(x), ', y=', num2str(y)]);
end
end
|
Ergebnisse
- Darstellung der Ergebnisse
- Links zu den Arbeitsergebnissen
Link zu dem SVN-Ordner der Arbeitsergebnisse
Analyse
Beschreibung | Das Problem ist.. | Das Problem ist nicht... |
---|---|---|
Was genau ist das Problem? | Äußere Einflüsse wie Licht oder Objekte werfen Flecken | |
Wo tritt das Problem auf? | Beispiel | Beispiel |
Wie zeigt sich das Problem? | Beispiel | Beispiel |
Wann tritt das Problem auf? | Beispiel | Beispiel |
Warum ist es ein Problem? | Beispiel | Beispiel |
Nr. | Beschreibung |
---|---|
1 | Warum? |
Nr. | Maßnahme | Verantwortung | Termin | Status |
---|---|---|---|---|
1 | Max Mustermann |
Hinweis: Die Maßnahmen müssen nicht umgesetzt werden.
Zusammenfassung
- Zusammenfassung
Der Algorithmus funktioniert auf Bilderebene einwandfrei, allerdings tut er sich aus unerklärlichen Gründen bei einem Video deutlich schwerer, wobei eigentlich ein Video auch nur aus hintereinander gereihten Bildern besteht.
- Diskussion der Ergebnisse
Die Ergebnisse sind nicht wirklich zufriedenstellend. Der Algorithmus hat noch viele Fehler weswegen eine Spurführung quasi unmöglich wäre.
- Ausblick
Eine deutliche Verbesserung des Algorithmus wäre eine Weiterführung der Mittleren Linien durch die Gradientenvektoren.
- Lessons Learned
So einen Algorithmus zu entwerfen macht Spaß ist aber extrem zeit intensiv. Die Entwicklung für den Algorithmus hat ca. 20 Stunden gebraucht und er funktioniert immernoch nicht richtig, was sehr frustrierend ist.
Beantwortung der Lernzielkontrollfragen
- Mit welchen Ansätzen lassen sich die Mittle- und rechte Fahrspur segmentieren? Wir haben den Einsatz einer Ebene gewählt, damit schließt man im ersten Schritt viele der äußeren Einflüsse wie Lichtreflektionen und ähnliches aus. Im nächsten Schritt haben wir versucht Objekte zu finden, die größer sind als die Ebene, aber dennoch diese in ihren untersten Punkten berühren. Im Anschluss sortieren wir die gefundenen Objekte nach der Nähe zum Mittelpunkt. Und so finden wir die Linke und Rechte Fahrbahnmarkierungen. Die mittlere finden wir durch die Linke und Rechte Begrenzung, jedes weitere gefundene Objekt muss sich dazwischen befinden um als eine Mittellinie erkannt zu werden. Die außerhalb liegenden Mittellinien können dann über die Gradienten der gefundenen Mittellinien berechnet werden.
- Wieso sollten alle Fahrbahnränder segmentiert werden? Bei Kurvenfahrten kann es passieren, dass eine der Fahrbahnränder nicht mehr von der Kamera gesehen wird und dementsprechend muss darauf reagiert werden können. Wenn ich mindestens Links und Rechts nehme habe ich das Problem der Kurvenfahrt nicht mehr, da immer ein Fahrbahnrand übrig ist. Die Mittellinien braucht man, damit das Auto nicht auf der falschen Seite fährt und es so zu Unfällen kommen kann.
- Welche Vor- und Nachteile hat die Segmentierung? Die Segmentierung ist ein schnelles Verfahren welches in Echtzeit angewendet werden kann. Ein großer Nachteil sind Lichteinflüsse da diese mehrere Segmente miteinander verbinden, so kann nicht mehr alles richtig segmentiert werden kann.
- Wie könnten die Nachteile behandelt werden? Man könnte das ganze mit der Hough Transformation machen, da diese Präzise auf Linien reagieren kann. Hough Transformationen haben eine höhere Resistenz gegenüber äußeren Einflüssen, dafür ist diese allerdings langsamer.
→ zurück zum Hauptartikel: Praktikum SDE | SDE-Team 2024/25 | Lernzielkontrolle 3