Legosortiermaschine Bildverarbeitung: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
 
(150 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:


Dies ist ein Unterarikel von der [http://193.175.248.52/wiki/index.php/Legoteil_Z%C3%A4hlmaschine  Legoteil_Zählmaschine], welcher den genauen Aufbau der Bildverarbeitung beschreibt.
Dies ist ein Unterarikel von der [http://193.175.248.52/wiki/index.php/Legoteil_Z%C3%A4hlmaschine  Legoteil Zählmaschine], welcher die aktuellen Änderungen an dem Teilgebiet der Bildverarbeitung der Lego Sortiermaschine beschreibt.


= Ziele und Aufgaben im Semeseter 2017/2018 =
Autor: [[Benutzer:Torben Mueller|Torben Müller]]


Team: [[Benutzer:Jan Auf der Landwehr|Jan Auf der Landwehr]], [[Benutzer:Matthias Maas|Matthias Maas]]
= Einleitung =


Ziel: Alle Teile werden richtig erkannt und aufgelistet. Dabei soll eine GUI die Bedienung benutzerfreundlich machen und ein Teach-In von neuen Teilen zur Verfügung stellen.
Diese Unterseite des Artikels beschäftigt sich hauptsächlich mit der Bildverarbeitung zur Erkennung der Legoteile. Dies geschieht in der Bildverarbeitungsbox der Anlage (vgl. [http://193.175.248.52/wiki/index.php/Datei:VorderseiteLegoteilz%C3%A4hlmaschine1819.jpg Abbildung der Startseite] Punkt 4). Zusätzlich dazu werden auch alle anderen Arbeiten an der Software des Matlab Programmes hier behandelt und dokumentiert.  


Aufgaben:
Generell lässt sich das Programmes in drei Funktionalitäten aufteilen:
* Sortierung
* Anlernen
* Baukasten bearbeiten


- Hardware und Software starten und Bedienungsanleitung ergänzen
Die Funktion '''Sortierung''' stellt die Hauptfunktion dar. Sie beschreibt den laufenden Zustand der Anlage beim sortieren von Teilen. Hier spielt ein Großteil der Bildverarbeitung rein. Die Funktion '''Anlernen''' ist eine Nebenfunktion, die genutzt werden kann wenn die Anlage nicht sortiert. Hier können Legoteile angelernt werden, sodass die Anlage fähig ist diese Teile in einer späteren Sortierung zu erkennen. Die Funktion '''Baukasten bearbeiten''' dient als Wartungsfunktion um Informationen über Legobaukästen zu bearbeiten, denen jeweils die zu sortierenden Teile zugehören.
- GUI verbessern
- Datenbank pflegen


- Teach-In über GUI ermöglichen
= Anforderungen =


=== Schnittstellen ===
Basiered auf einer Liste offener Punkte aus dem Vorsemester wurden für das Sommersemester 18 und das Wintersemester 18/19 folgende Anforderungen festgelegt:


Damit die Bildverarbeitung und damit auch das Erkennen der Legoteile erfolgreich verlaufen kann, müssen zunächst die Legoteile vereinzelt in die Bildverarbeitungsbox gelangen ([http://193.175.248.52/wiki/index.php/Legoteil_Z%C3%A4hlmaschine_2016_2017#Gruppe:_Separierung Separierung]). Sobald ein Legoteil erkannt wurde, wird es aus der Box per Druckluft gefördert und muss anschließend sortiert werden. Damit das Legoteil richtig sortiert wird, wird dem jeweiligen Legoteil anhand der ID eine Box zugeorndet. Der Schnittstellenplan lässt sich zusammengefasst folgendermaßen darstellen:
{| class="wikitable"
<br /><br />
|-
[[Datei:Schnittstellen BV Legoteilzaehlmaschine.png|600px|thumb|zentriert|Abbildung 7: Schnittstellen der Legoteilerkennung]]
!Spezifikations-ID
<br />
!Anforderungs-ID
<ref name="Autor: Penner"> Autor Kevin Penner</ref> <ref name="Autor: Tsibadze"> Autor Christo Tsibadze</ref>
!Anforderungstitel
<br />
!Beschreibung der Spezifikation
<br />
!Link
|-
| 0060
| REQ10.2050
| Bauteile
| Unterstützung sämtlicher Legoteile. Fokus auf NXT und EV3.
|[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/32_Legoteile/Teileunterst%C3%BCtzung%20und%20manuelle%20Vorsortierung.xlsx Dokument]
|-
| 0060.1
| REQ10.2050
| Bauteile
| Visuelle Anleitung erstellen
| [http://193.175.248.52/wiki/index.php/Anleitung_Legoteilz%C3%A4hlmaschine Wiki]
|-
| 0061
| REQ10.2050
| Bauteile
| Basissatz wird unterstützt und alle entsprechenden Teile werden erkannt
|[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/32_Legoteile/Teileunterst%C3%BCtzung%20und%20manuelle%20Vorsortierung.xlsx Dokument]
|-
| 0062
| REQ10.2050
| Bauteile
| Erweiterungssatz wird unterstützt und alle entsprechenden Teile werden erkannt
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/32_Legoteile/Teileunterst%C3%BCtzung%20und%20manuelle%20Vorsortierung.xlsx Dokument]
|-
| 0063
| REQ10.2050
| Bauteile
| Vorsortierung via GUI
| [[#Sicherstellung vorhandener Funktionen | Wiki]]
|-
| 0120
| REQ10.2250
| Bildverarbeitung
| Echtzeit mit Matlab/Simulink
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/02_Versuchsprotokolle/Bildverarbeitung/Testbericht%20Echtzeitf%C3%A4higkeit%20Bildverarbeitung.docx Dokument]
|-
| 0120.1
| REQ10.2250
| Bildverarbeitung
| Echtzeit mit Matlab/Simulink. Teile werden erkannt und mit Seriennummer klassifiziert
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/25_Systemtests/Systemtest%20Teileerkennung%20Bildverarbeitung.docx Dokument]
|-
| 0122
| REQ10.2220
| Bildverarbeitung
| Geschwindingkeit erhöhen: Software analysieren und den Code beschleunigen z.B. Schleifen sparen, Variablen global speichern
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Test%20Bildverarbeitung%20beschleunigen.docx Dokument]
|-
| 0123
| REQ10.2220
| Bildverarbeitung
| Prozentsatz der erkannten Teile errechnen
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testbericht%20Inventurliste%20und%20Fehlteilliste.docx Dokument]
|-
| 0124
| REQ10.2220
| Bildverarbeitung
| Nicht erkannte Teile in der Position des nicht erkannten Teils anlernen
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/32_Legoteile/Teileunterst%C3%BCtzung%20und%20manuelle%20Vorsortierung.xlsx Dokument]
|-
| 0125
| REQ10.2220
| Bildverarbeitung
| HSV Farbraum testen, um Farberkennung zu verbessern
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/06_MATLAB/09_Bildverarbeitung/Verbesserung%20der%20Erkennung%20in%20der%20Bildverarbeitungsbox.docx Dokument]
|-
| 0126
| REQ10.2220
| Bildverarbeitung
| In Bilderkennungsbox zusätzliche LEDs hinzufügen für besseres Auflichtbild
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testprotokoll%20Neue%20LEDs%20Bildverarbeitungsbox.docx Dokument]
|-
| 0127
| REQ10.2220
| Bildverarbeitung
| Offline-Modus einfügen um basierend auf einem Video die Bildverarbeitung zu testen
| [http://193.175.248.52/wiki/index.php/Legosortiermaschine_gesamte_Anlage#Liste_offener_Punkte_.28LOP.29 Wiki]
|-
| 0140
| REQ10.2300
| Teileliste
| Inventurliste im xls-Format zeigt, wie viele Teile erkannt wurden und wie viele im Neuzustand des Kastens sind dadurch Differenz erkennbar. Fehlteilliste muss in geeignetem Format für Neubeschaffung ausgegeben werden
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testbericht%20Inventurliste%20und%20Fehlteilliste.docx Dokument]
|-
| 0141
| REQ10.2300
| Teileliste
| Geeignetes Format für eine Fehlteilliste planen, also welche Informationen enthalten sein müssen um eine Neubeschaffung zu ermöglichen zb Seriennummer oder Onlinelink
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testbericht%20-%20Fehlteilliste.docx Dokument]
|-
| 0142
| REQ10.2300
| Teileliste
| Fehlteiliste implementieren und ausgeben lassen
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testbericht%20-%20Fehlteilliste.docx Dokument]
|-
| 0143
| REQ10.2300
| Teileliste
| GUI erweitern um Fehlteilliste auszugeben
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/23_Testberichte/Testbericht%20-%20GUI%20erweitern%20um%20Fehlteilliste%20auszugeben.docx Dokument]
|-
| 0180
| REQ10.2330
| Teach-In
| Über GUI neue Teile anlernbar. Ein benutzerfreundliches Interface soll das Anlernen der Bauteile ermöglichen.
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/31_GUI/Anforderungen%20GUI.docx Dokument]
|-
| 0181
| REQ10.2330
| Teach-In
| Sicherstellung der vorhanden GUI- und Datenbankfunktionen
| [[#Sicherstellung vorhandener Funktionen|Wiki]]
|-
| 0182
| REQ10.2330
| Teach-In
| Fehlende Funktionen hinzufügen
| [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/31_GUI/Anforderungen%20GUI.docx Dokument]
|}
Tabelle 1: Anforderungen


=== Mechanischer Aufbau ===
= GUI =


Um die Lichtreflexionen und Schatten an den Legoteilen während der Bilderkennung zu vermeiden, wurde ein neues Konzept entwickelt. Wenn ein Legoteil sich auf einem halb-transparentem Milchglas befindet (siehe Skizze), wird zuerst die untere Beleuchtung eingeschaltet und mittels einem Durchlichtverfahren die genaue Kontur des Legoteils mit der Kamera ermittelt. Hier können bereits einige Merkmale genau extrahiert werden (geometrische) und eine Maske erzeugt werden. Anschließend wird das untere Licht ausgeschaltet und das obere Licht eingeschaltet. Nach diesem Schritt wird mit Hilfe der Maske, nur in dem Bereich wo das Legoteil liegt, die Farbe ermittelt.
Die Benutzeroberfläche für dieses Projekt wurde bereits von Vorsemestern erstellt und kann verwendet werden, um das Projekt zu steuern. Zuerst galt es, die vorhandenen Funktionen der GUI zu prüfen, um weitere Arbeitsschritte zu ermitteln.
<br />
[[Datei:Konzept Skizze.png|800px|thumb|zentriert|Abbildung 8: BV-Box Funktionskonzept Skizze]]
<br />
<br />
Im nächsten Schritt wurde die Idee mit Hilfe eines CAD-Programms ausgearbeitet. Die Konstruktion wurde für den ersten Prototypen einfach gehalten und sich so für miteinander verschraubte Holzbretter entschieden.
In der unteren Box am oberen Rand wurde die halb-transparente Plexiglasplatte angebracht. In einem bestimmten Abstand wurde unter der Plexiglasscheibe eine weitere Ebene mit LEDs platziert. Der Abstand wurde so gewählt, dass bei angeschalteten LEDs das Licht durch das Plexiglas optimal gestreut wird (ohne helle Punkte, ohne Licht-Spots).
In der oberen Box wurde im Deckel eine Bohrung durchgeführt, wo die Stromleitungen der Kamera und der LEDs durchlaufen können. Die LEDs wurden in rechteckiger Form angeordnet und von innen an Deckplatte befestigt (siehe Abbildung 9). Auf einer weiteren halb-transparenten Plexiglasplatte  wurde die Kamera befestigt. Für die Kamera wurde eine weitere Bohrung erzeugt. In der oberen Box wurden Ein- und Ausgänge für die Legoteile erzeugt, sowie eine Aussparung für eine flache Druckluftdüse. Zur besseren Vorstellung befindet sich unter den folgenden Link das CAD-Modell als 3dxml-Datei:
[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/05_3D_Modelle/CAD_NEUE_Bildverarbeitung/BV_CAD_2016_2017\BV_Box_Komplett.3dxml BV_Box_Komplett.3dxml]. Der 3dxml viewer ist unter folgenden Link zu finden: [https://www.3ds.com/de/produkte-und-services/3d-xml/download/ Link]
<br />
[[Datei:Mechanik BV-Box.JPG|800px|thumb|zentriert|Abbildung 9: CAD-Konzept BV-Box]]
<br />
<br />
Anhand des CAD-Modells wurde die Bildverarbeitungsbox fertiggestellt und in Gesamtsystem integriert.
Desweiteren wurde eine "Drosselklappe" prototypisch für die Vor-Separierung in Y-Richtung realisiert.
<br />
[[Datei:BV-Box.JPG|400px|thumb|zentriert|Abbildung 10: BV-Box fertiggestellt]]
<br />
<ref name="Autor: Penner"> Autor Kevin Penner</ref> <ref name="Autor: Tsibadze"> Autor Christo Tsibadze</ref>
<br />
<br />


=== Grober Ablauf der Legoteilerkennung ===
== Sicherstellung vorhandener Funktionen ==
<br />
[[Datei:Grober Ablaufplan Legoteilerkennung.png|1200px|thumb|zentriert|Abbildung 11: Grober Ablaufplan Legoteilerkennung]]
<br />
<ref name="Autor: Penner"> Autor Kevin Penner</ref> <ref name="Autor: Tsibadze"> Autor Christo Tsibadze</ref>
<br />
<br />


=== Matlabimplementierung ===
Für die Sicherstellung der vorhandenen GUI Funktionen wurde ein Test jedes Buttons innerhalb der Software durchgeführt und dokumentiert.
Das Programm für die Erkennung von Legoteilen befindet sich hier: [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung/AutomatischesZaehlen.m  AutomatischesZaehlen]. Der Funktion wird ein kalibriertes Kameraobjekt, die Schnittstelle zur Datenbank, die serielle Schnittstelle zum Arduino und das Kalibrierbild übergeben. Als Rückgabewert wird eine Liste mit den gezählten Legoteil-IDs zurückgegeben. Das Programm wird in der Hauptfunktion in einer Schleife abwechselnd mit dem Separierungsprogramm aufgerufen. Bei jedem Durchlauf werden dann die jeweiligen Kameras aufgerufen und ein Frame ausgewertet.  
<br /><br /><br />


<u>'''Ablaufplan:'''</u>
{|
<br />
!
[[Datei:Ablaufplan Legoteilerkennung2.png|250px|Ablaufplan Legoteilerkennung]]
!
<br /><br /><br />
!
|-
|[[Datei:LegoSortierGUI Main.PNG | 400px]]
|[[Datei:LegoSortierGUI Help.PNG | 400px]]
|
|-
|Abbildung 1: Hauptseite
|Abbildung 2: Hilfetexte
|
|-
|
|
|
|-
|Der Startbildschirm (1) führt zu den Bereichen Sortierung (2), Teach-In (3) und Baukasten bearbeiten (4).
|Die Hilfeknöpfe blenden einen Hilfetext für den jeweiligen Programmteil ein und beenden öffnet ein Bestätigungsfenster, welches das Programm beendet oder das Fenster wieder schließt.
|
|-
|[[Datei:LegoSortierGUI Sortierstart.PNG | 400px]]
|[[Datei:LegoSortierGUI Sortierrunning.PNG | 400px]]
|[[Datei:LegoSortierGUI TeachIn.PNG | 400px]]
|-
|Abbildung 3: Sortierung starten
|Abbildung 4: Kontrollbildschirm bei laufender Sortierung
|Abbildung 5: Teach In
|-
|
|
|
|-
|In dem Teilbereich der Sortierung lässt sich eine Kasten-ID auswählen, wodurch eine Tabelle mit allen in diesem Kasten enthaltenen Teilen angezeigt wird. Dort lässt sich eine manuelle Vorsortierung der Teile eintragen, wie in dem Abschnitt zur [[#Manuelle Vorsortierung | Vorsortierung]] beschrieben. '''Zurück''' führt zu dem Startbildschirm (1) und '''Beenden''' öffnet das Bestätigungsfenster zum Beenden oder abbrechen.
|Mit betätigen des '''Speichern''' Knopfes kommt man nach einem Fortschrittsbalken der Kamerakalibrierung zu einem Kontrollbildschirm, wo Echtzeitinformationen der Maschine angezeigt werden und die Maschine wird gestartet. Oben links wird das Kamerabild der Bildverarbeitung angezeigt und oben rechts ein Binärbild, welches bei der Bildverarbeitung aufgenommen wird. Unten links sieht man das Kamerabild der Seperierung und unten rechts das Binärbild aus der Seperierung. Mit Drücken der ''Escape''-Taste wird die Maschine beendet und eine Inventurliste generiert, wo die Anzahlen der erkannten Teile angezeigt werden.
|In dem Bereich Teach-In kann in dem ersten Fenster eine Bauteile-ID eingegeben werden. '''Zurück''' kehrt zu dem Startbildschirm (1) zurück und Beenden führt zu dem Bestätigungsfenster. Mit '''Speichern & Weiter''' wird die Kamera der Bildverarbeitung angezeigt. Mit ''Enter'' wird ein Foto aufgenommen und mit ''Space'' wird dieses Foto in ein Binärbild umgewandelt und neu angezeigt. Erneutes ''Space'' speichert das Teil mit der eingegebenen Nummer in der Datenbank
|-
|[[Datei:LegoSortierGUI BaukastenBearbeiten.PNG | 400px]]
|[[Datei:LegoSortierGUI TeilBearbeiten.PNG | 400px]]
|
|-
|Abbildung 6: Baukasten bearbeiten
|Abbildung 7: Einzelnes Teil im Baukasten bearbeiten
|
|-
|
|
|
|-
|Bei Baukasten bearbeiten lässt sich oben im Fenster mit dem Knopf '''Speichern & Weiter''' ein neuer Baukasten erzeugen. Danach kann mit '''Eingaben ändern''' die Kasten-ID und die Anzahl der Teile nachträglich angepasst werden. In der Tabelle darunter können Teile in diesen Kasten eintragen. '''Änderungen speichern''' speichert diese Änderungen an dem Kasten in der Datenbank. Unten links kann dann Wahlweise ein Bauteil aus dem Kasten, ein Teil komplett oder ein ganzer Kasten gelöscht werden. '''Auswahl anwenden''' führt dabei die jeweils gewählte Aktion aus.
|Unten rechts lassen sich einzelne Bauteile in dem Kasten hinsichtlich ihrer Anzahl und Fachnummer in dem Kasten bearbeiten. Diese Änderungen werden jedoch mit dem Betätigen des Knopfes '''Änderungen speichern''' nicht in die Datenbank übernommen. Diese Funktion wird in dem Abschnitt [[#Bearbeitung eines Kastens abspeichern | Kastenänderungen abspeichern]] hinzugefügt.
|
|-
|}


<u>'''Parametrisierung der Kamera:'''</u><br />
== Text der Oberfläche überarbeiten ==
Für die Einstellungen der Paramter wurde das Matlabtool '''Image Acquisition Toolbox''' benutzt. Dort wurden einzelne Parameter so ausgetestet/eingestellt, dass sich zum einen die Legoteile beim Durchlichtverfahren gut vom Hintergrund abgrenzen und zum anderen die unterschiedlichen Legofarben beim Auflichtverfahren erkennen lassen. Folgende Einstellungen wurden getroffen ([https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Kamerakalibrierung/KameraKalibrierungBild.m Die Einstellungsdatei ist hier zu finden]):
 
<source lang=matlab>
Bei der Sicherstellung der Funktionalität ist aufgefallen, dass einige Knöpfe und Hinweise in der GUI nicht aussagekräftig. Zudem hatten einige Fenster noch keinen angemessenen Titel. Diese Anzeigetexte wurden angepasst, sodass die GUI einfacher zu verstehen und für ungeübte User einfacher zu benutzen ist. Die neuen Beschriftungen im Zusammenhang der Schritt für Schritt Anleitung [http://193.175.248.52/wiki/index.php/Anleitung_Legoteilz%C3%A4hlmaschine#Anleitung_zur_Bedienung_des_GUI hier] zu sehen.
cam.BacklightCompensation = 0;
 
cam.Tilt = 0;
= Sortierung =
cam.Sharpness = 128;
 
cam.Pan = 0;
Die Sortierung ist die Hauptfunktion der Anlage. Zusammen mit dem Programm der Seperierung steuern beide die gesamte Anlage in ihrem sortierenden Zustand. Ein grober Ablauf der Sortierung kann der Abbildung 8 entnommen werden.
cam.Saturation = 128;
 
cam.Brightness = 128;
<gallery widths=200 heights=500>
cam.Contrast = 128;
  AblaufSortierung.png | Abb. 8: Ablauf der Funktion Sortierung
cam.Gain = 0;
</gallery>
 
Dieser Algorithmus deckt die Teilbereiche Erkennung und Ansteuerung der Sortierung ab. Nach diesem Ablauf wird von der Hauptschleife des Programmes in der Datei StartSortiermaschine ein Durchlauf der Separierung gestartet. Dieser steuert alle zur Seperierung gehörenden Komponenten. Danach wird der Ablauf wiederholt. So werden alle nötigen Funktionen zum Sortieren von Legoteilen abgedeckt.
 
== Funktionalität ==
 
Hier werden Themen behandelt, die direkt mit der Funktionalität und/oder der Effizienz der Sortierung zu tun haben. Diese Änderungen werden nicht direkt wahrgenommen und dienen dem steigern der Güte der Teileerkennung.
 
=== Bewegungserkennung ===
 
Es wurde eine Bewegungserkennung als erster Mechanismus in dem Algorithmus zum erkennen von Teilen eingefügt. Dieser Alorithmus funktioniert, indem zwei Bilder in einem kurzen Abstand voneinander aufgenommen werden. Diese Bilder werden in den Graubereich konvertiert von einander subtrahiert. In dem entstehenden Differenzbild wird das Maximum ermittelt und dieses dann mit einem Threshold verglichen.
 
Dieser Vorgang wird solange wiederholt, bis das Maximum des Differenzbildes kleiner ist als eine definierte Grenze, was bedeutet, dass das Teil ruht oder nur noch sehr langsam rutscht. Durch diesen Mechanismus können viele Aufnahmen verhindert werden, in denen das Bauteil noch nicht in Ruhe war und so ein verzerrtes Bild aufgenommen wurde, welches nicht korrekt analysiert werden kann.
 
=== Farberkennung ===
 
'''Ansatz 1:'''


cam.ExposureMode = 'manual';
Die Farberkennung in ihrem Ausgangszustand lieferte keine zuverlässigen Ergebnisse. Vor allem die die Farben rot, gelb, grün, blau und schwarz wurden oft in Grautönen erkannt. Um dieses Problem zu beheben, war der erste Ansatz eine Neukalibrierung der existierenden Farbwerte. Die Farbbeurteilung geschah in der Datei Farberkennung. Dort waren in dem Array Farbwerte für jede der möglichen 10 Farben Werte hinterlegt, mit denen ein aktuelles Bild verglichen wurde. Hier folgend die dort verwendeten Werte:
cam.FocusMode = 'manual';
cam.WhiteBalanceMode = 'manual';


cam.WhiteBalance = 4000;
<source lang="matlab">
cam.Focus = 10;
Farbwerte=[  0.5133 0.4578 0.4033; %'weiss'         
cam.Exposure = -3;
              0.4857 0.4154 0.3289; %'beige'       
              0.4522 0.1456 0.1868; %'rot'         
              0.1400 0.2129 0.3308; %'blau'         
              0.5817 0.4393 0.2213; %'gelb'         
              0.1637 0.1761 0.1961; %'schwarz'     
              0.1703 0.2396 0.2240; %'gruen'       
              0.3318 0.2959 0.2705; %'hellbraun'         
              0.3221 0.3228 0.3230; %'hell-grau'       
              0.2256 0.2302 0.2370; %'dunkel-grau'   
              ];
</source>
</source>
<br /><br /><br />


<u>'''Kamera-Kalibrierung:'''</u><br />
Um nun neue Farbkalibrierungswerte für jede Farbe zu erhalten und die vorhandenen damit zu überschreiben, wurden mehrere Teile jeder Farbe von der Bildverarbeitung analysiert und die berechneten Farbwerte wurden im Programm ausgelesen. Diese Farbwerte wurden dann in eine Tabelle eingetragen und über drei verschiedene Teile gemittelt. So konnte ein möglichst passender Wert für die jeweilige Legoteilfarbe ermittelt werden (vgl. Tabelle 2). Dieser Durchschnittswert wurde für alle Farben ermittelt und dann in die Farberkennung als neue Referenzwerte eingetragen.
Obwohl die Parameter der Kamera konstant und unverändert waren, stellte sich heraus, dass das Bild der Kamera bei einigen Programmstarts trotzdem heller war. Um Neustarts des Programms zu vermeiden wurde so eine Kalibrierfunktion geschrieben, welche anhand eines aufgenommenen Bildes erkennt, ob die Kameraeinstellungen korrekt vorgenommen.<br />
 
Dabei wird in einer Schleife ein Kameraobjekt erzeugt und mit den oben aufgeführten Einstelllungen/Parametern versehen. Nun wird ein Bild mit diesen Einstellungen geschossen (im Auflichtverfahren) und mit einem zuvor gespeicherten Bild (siehe Abbildung 12), welches die richtigen Einstellungen beinhaltet, verglichen. Sollten sich die durchschnittliche Helligkeiten der Bilder Unterschiede aufweisen, wird das Kameraobjekt neu erzeugt und der Vorgang wiederholt sich, bis die richtigen Einstellungen getroffen wurden.<br />
{| class="wikitable"
Zusammenfassend beschreibt folgendes Diagramm den Ablauf der Selbstkalibrierung:
!weiß
<br />
!R
[[Datei:Kalibrierbild.png|250px|rechts|thumb|Abbildung 12: Kalibrierbild]]
!G
[[Datei:Kamera Kalibrierung Legoteilerkennung.png|250px|Ablaufplan Kamerakalibrierung]]
!B
<br />
|-
Das Kalibrierbild befindet sich im folgenden Ordner: [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Kamerakalibrierung\Calib_Img.png  Calib_Img].
|
<br /><br /><br />
|0,5153
|0,4650
|0,4136
|-
|
|0,5092
|0,4570
|0,4020
|-
|
|0,5155
|0,4512
|0,3944
|-
|
|'''0,5133'''
|'''0,4578'''
|'''0,4033'''
|-
|}
Tabelle 2: Beispielwerte für weiß
 
 
'''Ansatz 2:'''
 
Nach der Neukalibrierung bestanden jedoch weiterhin Erkennnungsprobleme mit einigen Farben. Vor allem schwarz konnte selten als selbiges erkannt werden. Darum folgt ein zweiter Ansatz zum verbessern der Farberkennung: Die Verwendung von Farbmasken
<gallery widths=700 heights=500>
    Datei:ColorThresholder.png | Abb. 9: Matlab-App Color Thresholder zum Erstellen von Farbmasken für spezielle Farben
</gallery>
 
Mit der Matlab-App '''Color Thresholder''' (vgl. Abbildung 9) lassen sich Farbmasken für spezielle Farben erstellen. Angewendet auf ein Farbbild erzeugen diese Masken ein Binärbild, wo nur Bereiche in der jeweiligen eingestellten Farbe markiert werden. Die Idee besteht somit darin, für jede Farbe, die ein Legoteil haben kann, eine Farbmaske zu erstellen. Alle diese Masken werden dann auf ein Farbbild angewendet, welches ein Teil einer Farbe enthält. Um die Erkennung noch zu verbessern, wird das Farbbild vorher mit dem [[#Merkmal-Erkennung|Binärbild]] multipliziert. Dadurch bleibt ein Bild über, wo nur an der Stelle des Teiles die originalen Bildinformationen bestehen blieben. So wird sichergestellt, dass die Masken nur die Farbe des Teiles auswerten.


<u>'''Legoteilerkennung:'''</u><br />
Die Maske, welche auf die aktuelle Farbe eingestellt ist, wird die meiste Fläche markieren (im Idealfall die komplette Fläche des Teiles). So erzeugt also diese Maske ein Binärbild, wo die meisten Pixel aktiviert sind. Eine einfache Summierung aller Pixel in dem Bild zeigt, welche der Masken am meisten von dem eingegebenen Farbbild aktiviert wurde. Das bedeutet das die Maske mit der größten Pixelsumme auf die Farbe des aktuellen Teiles eingestellt ist und somit die Farbe bekannt ist.
Die Legoteilerkennung erfolgt in einer Schleife, in welcher jeder einzelne Frame ausgewertet wird. Zum Beenden der Schleife und damit des Programms muss hier die Escape-Taste gedrückt werden.
<br /><br /><br />


<u>''Vorverarbeitung, Segmentierung & Nachverarbeitung:''</u><br />
<source lang="matlab">
Zunächst wird das im Durchlichtverfahren aufgenommene Bild zugeschnitten, damit unnötige Bildregionen nicht bearbeitet werden müssen. Die Anzahl an Pixeln, welche in Höhe und Breite weggeschnitten werden, wurde experimentell ermittelt und so ausgelegt, dass sich das größte Legoteil immer im Blickfeld befindet.<br />
% Beurteilen, welche Maske am stärksten anschlägt, also am meisten Pixel auf eins setzt
Daraufhin erfolgt die Binarisierung bzw. Segmentierung. Die Schwellwerte für die jeweiligen Farbkanäle und die Funktion zur Binarisierung wurden mithilfe des Matlabtools '''Color Thresholder''' ermittelt. Sollte sich im Laufe des Projektes die Kamerabox verändern (z.B. mehr LEDs eingebaut oder ein anderer Lichteinfall) muss diese Funktion ersetzt werden, da es sonst zu Segmentierungsfehlern kommen kann.
maskenPixelSummen(1) = sum(sum(binaerBeige));
[[Datei:Thresholder Binaerbild Legoteilerkennung.PNG|500px|thumb|zentriert|Abbildung 13: Segmentierung der Legoteile mithilfe des Color Thresholder Tools]]
maskenPixelSummen(2) = sum(sum(binaerSchwarz));
<br />
maskenPixelSummen(3) = sum(sum(binaerBlau));
Die Funktion zur Segmentierung findet man hier: [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\createBinary_V3.m  createBinary_V3]<br />
maskenPixelSummen(4) = sum(sum(binaerGrau));
Im Anschluss werden noch kleine, einzelne Pixel im Hintergrund und im Legoteil gelöscht. Damit ist das Bild bereinigt und vollständig segmentiert.
maskenPixelSummen(5) = sum(sum(binaerGruen));
<br /><br /><br />
maskenPixelSummen(6) = sum(sum(binaerHellbraun));
maskenPixelSummen(7) = sum(sum(binaerHellgrau));
maskenPixelSummen(8) = sum(sum(binaerRot));
maskenPixelSummen(9) = sum(sum(binaerWeis));
maskenPixelSummen(10) = sum(sum(binaerGelb));


<u>''Legoteilerfassung:''</u><br />
[~, index] = max(maskenPixelSummen);
Damit ein Legoteil erfasst werden kann, müssen folgende Kriterien eingehalten werden:
#Legoteil muss sich an der Kante befinden
#Legoteil muss sich in einer Ruhelage befinden
#Es darf nur ein Legoteil im Bild vorhanden sein
Sollte mehr als ein Legoteil ein Bild sein, werden alle vorhandenen Legoteile in der Box herausgepustet und als "nicht erkannt" deklariert. Um zu verhindern, dass ein Teil rausgepustet wird, weil zum Beispiel anders beleuchtete Bereiche der Seiten/Löcher als einzelne Teile erkannt werden, wird das Teil zunächst um einige Pixel dilatiert (vergrößert) und anschließend dilatiert (verkleinert). Auf diese Art können kleine Lücken geschlossen werden und die Anzahl an falsch erkannten richtigen Teilen vermieden werden. 
<br /><br /><br />


<u>''Farbliches Merkmale extrahieren:''</u><br />
%Entsprechende Farbe speichern
[[Datei:Farberkennung.jpg|200px|thumb|right|Abbildung 14: Farberkennung]]
switch index
Damit die Farbe erkannt werden kann, wird das Auflichtverfahren angewendet.
    case 1
Die Funktion "[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\FARBERKENNUNG_V2.m FARBERKENNUNG_V2]" bekommt als Übergabewerte zwei Matrizen:
        Farbe='beige';
* RGB-Bild aus Auflichtverfahren und Binärbild vom erkannten Objekt
    case 2
* mit Hilfe der Übergabeparameter wird eine 3D-Farbmaske erstellt (3D --> RGB).
        Farbe='schwarz';
** Farbmaske: Aus dem Originalbild werden nur die Pixel in die Masken übernommen, die im Binärbild dem Objekt zugeordnet werden können (weiße Pixel)
    case 3
* Anschließend werden Mittelwerte für Rot-, Grün- und Blau-Anteil berechnet.
        Farbe='blau';
<br />
    case 4
Zuordnung zur nächstgelegenen Farbe:
        Farbe='dunkel-grau';
* Es werden die RGB-Mittelwerte mit einer Farbtabelle verglichen:
    case 5
** die Differenzen von jedem Farbanteil zur Farbtabelle werden ermittelt. Davon werden die Differenzen des Farbanteils mit dem größten Wert (Abweichung) gespeichert.
        Farbe='gruen';
** Anschließend wird der minimalste Wert von den maximalen Abweichungen ermittelt --> '''Es wird genau die Farbe ermittelt, welches die kleinste Abweichung zu der Legoteil-Farbe hat.'''
    case 6
<br />
        Farbe='hell-braun';
Die ermittelte Farbe wird als String zurückgegeben. Es können weitere Farben im Nachhinein hinzugefügt werden oder Farbschwellwerte verändert werden, falls sich die Lichtverhältnisse in der Kamerabox durch Umbauten verändern.
    case 7
        Farbe='hell-grau';
    case 8
        Farbe='rot';
    case 9
        Farbe='weiss';
    case 10
        Farbe='gelb';
    otherwise
        disp('ERROR with color detektion')
end
</source>
</source>
<br />
 
Die Farbe wird als Durchschnitt der an R-, G- und B-Anteile pro Fläche berechnet:
=== Merkmal-Erkennung ===
 
Die Merkmale eines Legoteiles werden aus dem Durchlichtbild extrahiert. Dazu wird das Bild zuerst in ein Binärbild konvertiert, um dann die einzelnen Merkmale kalkulieren zu können. Die Erstellung dieses Binärbildes hat sich im Ausgangszustand als Fehleranfällig erwiesen. Zudem war deutlich zu erkennen, dass das Teil nicht besonders genau abgebildet wurde, sodass Parameter wie Umfang und Fläche nicht sonderlich aussagekräftig waren.
 
Zur Besserung wurde hier ein neues Verfahren zur Erstellung des Binärbildes eingeführt. Eine Matlab-Funktion ''imbinarize'' ermöglicht die Berechnung eines Binärbildes durch einen vorher ermittelten Grenzwert aus einem Farbbild. Die Idee besteht darin, das Durchlichtbild an die Funktion ''imbinarize'' zu übergeben und dadurch ein Binärbild des Teiles zu erhalten. Anschließend müssen von der resultierenden Matrix die überflüssigen Tiefenkanäle abgeschnitten werden und das Bild von Salz- und Pfefferrauschen bereinigt werden.
 
<source lang="matlab">
    hintergrundLevel = graythresh(durchlichtbild);
    binaerbild = imbinarize(differenzFarbbild,hintergrundLevel);
    binaerbild = binaerbild(:,:,1);
    binaerbild = ~binaerbild;
    %Bereinigung des Binärbildes
    %Salz (weiße Pixel) auf Hintergrund entfernen
    binaerbild = bwareaopen(binaerbild,SalzPfeffer);
    %Pfeffer (schwarze Pixel) in Legoteilen entfernen
    binaerbild = ~bwareaopen(~binaerbild,SalzPfeffer);
</source>
 
 
Das Resultat ist ein einwandfreies Binärbild des Teiles (vgl. Abbildung 10).
<gallery widths=700 heights=400>
    Datei:NeuesBinaerBild.png | Abb. 10: Beispiel eines Auflicht und Binärbildes eines Legoteiles
</gallery>
 
=== Echtzeit ===
 
Zum Testen der Echtzeit der Bildverarbeitung wurde ein Versuch entworfen. Dabei werden Teile wie im folgenden Bild direkt vor der Bildverarbeitungsbox auf das Förderband gelegt (vgl. Abbildung 11) und zeitgleich eine Zeitmessung gestartet. Sobald ein Teil in die Bildverarbeitunngsbox gefallen ist, wird an die gleiche Stelle ein neues Teil gelegt, sodass fast permanent ein Teil in der Box liegt und die Pause zwischen den Teilen minimal ist.
 
<gallery widths=600 heights=500>
    Datei:LegoSortier Teile einlegen.jpg | Abb. 11: Einlegestelle der Teile
</gallery>
 
 
Um die Ausgangssituation zu bewerten, wurde dieser Test mit verschiedenen Teilearten und -mengen ausgeführt. (Test vom 31.05.18)
 
{| class="wikitable"
!Test
!Anzahl Teile
!Anzahl erkannt
!Gesamtzeit [s]
!Zeit pro Teil [s]
!Erkennungsrate [%]
!Teileart
|-
|1
|15
|10
|43
|2,86
|66,6
|gemischt
|-
|2
|30
|16
|86
|2,86
|53,3
|gemischt
|-
|3
|20
|15
|60
|3
|75
|klein
|-
|4
|15
|9
|42
|2,8
|60
|groß
|}
Tabelle 3: Tests und Ergebnisse zur Echtzeit
 
 
Hier kann man erkennen, dass die Zeit pro Teil nur leichte Änderungen aufweist zwischen den unterschiedlichen Teilegruppen und dadurch festgestellt werden kann, dass die Echtzeit nicht stark von der Teileart beeinflusst wird.
 
In einem zweiten Testdurchgang wurde dann eine zufällige Teilegruppe verwendet und keine externe Zeitmessung mehr durchgeführt, sondern nur das Ergebnis des Matlab Profilers analysiert um verschiedene Methoden zur Erhöhung der Geschwindigkeit zu testen. Dieses Tool verfolgt zur Laufzeit des Programmes die Anzahl von Funktionsaufrufen und deren Ausführungsdauer. So wird für jede ausgeführte Programmzeile die Gesamtzeit gemessen, die diese Zeile beansprucht. Außerdem wird eine Übersicht erstellt mit den zeitaufwändigsten Zeilen und wie viel Zeit diese prozentual von der Gesamtzeit beansprucht haben.
 
{|
!
!
|-
|Funktionsaufrufe: 267
|Funktionsaufrufe: 404
|-
|[[Datei:LegoSortier Ausgangszustand.PNG | 500px]]
|[[Datei:LegoSortier Iteration1.PNG | 500px]]
|-
|Ausgangszustand:
 
 
 
 
 
 
0,13s pro Call
 
 
|Erste Iteration:
*imshow verschoben -> wird nur auseführt wenn Teil auch ausgewertet wird
*Pause bei seriellen Befehlen entfernt
*Lightdelay um die Hälfte reduziert
 
 
0,082s pro Call
 
 
|-
|Funktionsaufrufe: 287
|Funktionsaufrufe: 297
|-
|[[Datei:LegoSortier Iteration2.PNG | 500px]]
|[[Datei:LegoSortier Iteration3.PNG | 500px]]
|-
|Zweite Iteration:
*0,2s Pause für Bewegungserkennung innerhalb der Bildverarbeitungsbox hinzugefügt
*Funktion figure(HauptFigure) entfernt
 
 
0,12s pro Call
|Dritte Iteration:
*Pause der Bewegungserkennung auf 0,1 reduziert
 
 
 
 
0,117s pro Call
|}
 
=== Erkennung der Teile ===
 
Um die Erkennung der Teile aus beiden Baukästen (Basisset 45544 und Erweiterungsset 45560) sicherzustellen, wurde eine [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Dokumentation/32_Legoteile/Teileunterst%C3%BCtzung%20und%20manuelle%20Vorsortierung.xlsx Excel Tabelle] angelegt und jedes Teil einzeln geprüft, ob es von der Anlagt erkannt wird.
 
Das entsprechende Ergebnis wurde in der richtigen Spalte der Tabelle festgehalten. Hier sieht man den Aufbau der Tabelle:
 
{| class="wikitable"
!Teile ID
!Kasten ID
!In Datenbank vorhanden
!Wird erkannt
!Muss manuell gezählt werden
!Bemerkungen
|-
|}
 
Wurde ein Teil nicht oder schwer erkannt, so wurde dies in der Spalte Bemerkung vermerkt, sodass später die kritischen Teile erneut angelernt werden konnten. Zusätzlich ließen sich hier Fehler in der Erkennung verdeutlichen, zum Beispiel das schwarze Teile zu beginn generell schwer erkannt werden konnten.
 
Mit dem Ende der Projektzeit sind alle Teile bearbeitet und so vermerkt, dass sie entweder von der Anlage erkannt werden können oder auf Grund von Größe oder Beschaffenheit manuell vorsortiert werden müssen.
 
== Interaktion ==
 
Dieser Absatz der Sortierung beschäftigt sich mit Aufgaben, die direkten Einfluss auf die Interaktion mit der Sortierung haben. Dazu zählen kosmetische aber auf performancerelevante Änderungen.
 
=== Manuelle Vorsortierung ===
 
In Abbildung 3 wird die GUI zum Starten der Sortierung angezeigt. Dort wird in der Mitte eine Tabelle dargestellt, die nach Auswählen der Kasten ID alle Teile in diesem Kasten anzeigt. Die erste Spalte beinhaltet die ID des Teils, die zweite die vorgesehene Anzahl dieses Teiles in dem Kasten und in der dritten Spalte sollte dann die Möglichkeit bestehen die Anzahl der Teile einzutragen, die bereits mit der Hand vorsortiert worden sind. Dazu muss zuerst der Data Array der Tabelle, welcher die Inhalte speichert um eine dritte Nullspalte erweitert werden. Dazu wird die Funktion horzcat verwendet, die zwei Arrays horizontal miteinander verbindet:
 
<source lang=matlab>
<source lang=matlab>
FARBE(1,1) = (sum(sum(Farbmaske(:,:,1))))/Pixel_Flaeche;                  
% Datei SortierStart.m
FARBE(1,2) = (sum(sum(Farbmaske(:,:,2))))/Pixel_Flaeche;
Nullreihe = cell(size(curs.Data,1),1);
FARBE(1,3) = (sum(sum(Farbmaske(:,:,3))))/Pixel_Flaeche;
Nullreihe(:,1) = {0};
handles.uitable1.Data = horzcat(curs.Data, Nullreihe);
 
global GUI_vorsortierteTeile
GUI_vorsortierteTeile = handles.uitable1.Data;
</source>
</source>
<br />
 
Sollten diese (z.B. nach einem Umbau der Bildverarbeitungsbox) von den Werten in der hinterlegten Tabelle stark abweichen, müssen diese mit dem gemessenen Wert überschrieben werden:  
 
Der Inhalt der Tabelle wird zuletzt in eine globale Variable gespeichert, um bei der Erstellung der Inventurliste auf die Anzahl der vorgezählten Teile zugreifen zu können. Dabei wird auf die Anzahl der automatisch gezählten Teile, gespeichert in der vierten Spalte von InventurListeContent, die Anzahl der manuell gezählten Teile, gespeichert in der dritten Spalte von GUI_vorsortierteTeile, addiert und später ausgegeben:
 
<source lang=matlab>
<source lang=matlab>
%% Farbwerte-Tabelle mit normierten Lego-Farben
% Datei InventurlistenTemplateMultiKaesten.m
% %          R(1) G(1) B(1)
InventurListeContent(2:end,4) = num2cell(cell2mat(InventurListeContent(2:end,4)) + cell2mat(GUI_vorsortierteTeile(:,3)));
Farbwerte=[  0.5273 0.5489 0.5362; %'weiss'           
...
              0.4138 0.3891 0.3115; %'beige'        
xlswrite(InventurlisteName,InventurListeContent);
              0.3230 0.0622 0.0623; %'rot'          
</source>
              0.0087 0.1275 0.3309; %'blau'        
 
              0.5409 0.4596 0.2026; %'gelb'        
 
              0.0450 0.0664 0.0659; %'schwarz'      
Für diese hinzugefügte Funktion wurde in der Anleitung für die Gesamtanlage der entsprechende Abschnitt bearbeitet: [http://193.175.248.52/wiki/index.php/Anleitung_Legoteilz%C3%A4hlmaschine#Teile_h.C3.A4ndisch_vorsortieren Teile vorsortieren]
              0.0509 0.1826 0.1287; %'gruen'        
 
              0.2182 0.2038 0.1518; %'hellbraun'        
=== Prozentsatz nicht erkannter Teile ===
              0.2709 0.3230 0.3345; %'hell-grau'      
 
              0.1391 0.1804 0.1878; %'dunkel-grau'  
In der Inventurliste soll zusammen mit den Anzahlen der einzelnen Teile auch eine Prozentzahl ausgegeben werden die angibt, wie viel Prozent der analysierten Teile nicht erkannt wurden. Der Array LegoTeile enthält die Anzahlen von allen Teilen zuzüglich der Anzahl der nicht erkannten Teile. Im nächsten Schritt müssen die einzelnen Mengen addiert werden um dann die Anzahl der nicht erkannten Teile in ein Verhältnis zu der Gesamtanzahl an analysierten Teilen setzen zu können. In der letzten Zeile wird die errechnete Zahl dann in die zweite Zeile unter der Inventurliste von Teilen in dem Kasten zusammen mit etwas Text ausgegeben ausgegeben
%              0.0565 0.0629 0.0552; %'dunkelbraun' 
<source lang="matlab">
              ];  
% Berechnen des Anteils nicht erkannter Teile
gesamtZahlTeile = sum(LegoTeile(:,2));
prozentsatzNichtErkannterTeile = LegoTeile(1,2)/gesamtZahlTeile;
 
% Anhängen der Information an die Daten für den Excel-Export
InventurListeContent(end+2,3) = {['Nicht erkannte Teile: ' num2str(prozentsatzNichtErkannterTeile*100) '%']};
</source>
 
 
=== Fehlteilliste ===
 
Um nach dem erfolgreichen Sortieren eines Kastens die Nachbestellung der fehlenden Teile zu vereinfachen, soll eine Fehlteilliste erstellt werden in der die Mengen der Fehlteile abgespeichert werden. Zuerst sollte dafür ein Layout erstellt werden (vgl. Abbildung 12). Dieses Layout sollte die Teile übersichtlich mit allen wichtigen Informationen darstellen und eine Nachbestellung dieses Teils vereinfachen. Das folgende Layout orientiert sich an den üblichen Materialbestellungslisten der Hochschule, ist aber ergänzt um die Spalte '''Kastenbezeichnung''', wo manuell die Nummer des Kastens eingetragen werden kann, die von der Hochschule auf den Kasten geklebt wurde. Die ersten drei Spalten sollen dann von der Software selbst ausgefüllt werden, sodass die generierte Liste dann verwendet werden kann, um den Nachbestellungsprozess zu dokumentieren und zu verwalten.
 
<gallery widths=900 heights=350>
Datei:LegoSortier Fehlteilliste.PNG | Abb. 12: Layout der Fehlteiliste
</gallery>
 
Da die Liste ähnliche Daten benötigt wie die Inventurliste, wird die Fehlteilliste mit den gleichen Parametern aufgerufen und ähnlich erzeugt:
<source lang="matlab">
% FEHLTEILLISTE generiert die Fehlteilliste aus den gezählten Legoteilen
%
% Syntax:
%      Fehlteilliste(KastenID, FehlteillisteName, Legoteile)
%
% Beschreibung:
%      Legt eine Kopie der Fehlteilliste-Template an und trägt die
%      ermittelten Differenzdaten aus Soll und Ist ein
%
% Eingangswerte:
%      KastenID:          Die ID des verwendeten Kastens
%
%      FehlteillisteName:  Pfad der Fehlteilliste-Template
%
%      Legoteile:         Die gezählten Legoteile nach ID sortiert
</source>
 
Der Parameter Legoteile wird bei der Berechnung der Daten der Fehlteilliste als Istdaten verwendet und stellt die vorhandenen, also erkannten, Teile dar. Um die fehlenden Teile zu ermitteln müssen die Istdaten von den Solldaten abgezogen werden. Somit muss aus der Datenbank die vorgesehene Anzahl jedes Teils ausgelesen werden. Davon wird die vorhandene sortierte Anzahl aller Teile subtrahiert und es entsteht die Menge der fehlenden Teile.
 
 
Durch die Subtraktion der Mengen werden Legoteile, die komplett vorhanden sind mit einer Anzahl von null aufgeführt. Änhliches gilt für Teile, die öfter erkannt wurden als sie in dem Kasten vorhanden sein sollten. Da jedoch nur fehlende Teile ausgegeben werden sollen, müssen alle Teile aus der Differenzmenge entfernt werden, die eine Anzahl kleiner oder gleich null aufweisen. Diese Funktionalität wird über folgende Zeile ausgeführt.  
 
<source lang="matlab">
% Zeilen, wo Anzahl der Legoteile <= 0 ist, werden entfernt
differenzdaten(any(differenzdaten <= 0, 2), :) = [];
</source>
 
Die Funktion ''any'' ermittelt jede Zeile wo ein Element kleiner oder gleich null ist und setzt diese auf einen leeren Wert. Dadurch wird diese Zeile entfernt und die Menge der Differenzteile ist aufgeräumt.
 
Diese Daten müssen dann in die Fehlteilliste geschrieben werden. Um das Layout zu behalten, legt das Script zuerst eine Kopie des Layouts an und füllt diese dann mit den Daten:
<source lang="matlab">
%% Excel-Datei genereieren %%
 
% Aus Template neue Liste generieren   
dateinameTemplate = [pwd '\Excel\FehlteillisteTemplate.xls'];
try
    copyfile(dateinameTemplate,FehlteillisteName);
catch
    disp('Fehlteilliste aktuell geöffnet. Konnte nicht überschrieben werden')
    return
end
 
% Sheet und Range festlegen
arbeitsblatt = 1;
startZelle = 'A12';
 
% Daten in Liste schreiben
xlswrite(FehlteillisteName,differenzdaten,arbeitsblatt,startZelle);
</source>
 
Die Parameter ''arbeitsblatt'' und ''startZelle'' werden festgelegt, damit die ermnittelten Differenzdaten an die richige Stelle geschrieben werden. Nun ist die Fehlteilliste fertig und kann verwendet werden (vgl. Abbildung 13)
<gallery widths=900 heights=350>
Datei:FehlteillisteAusgefüllt.png | Abb. 13: Eine fertige Fehlteilliste
</gallery>
 
Zum Ausgeben der Fehlteilliste wurde ein neues GUI-Element eingebaut. Es besteht aus einem kleinen Dialog mit zwei Buttons (vgl. Abbildung 14). Einer öffnet die Inventurliste, der andere die Fehlteilliste. Dazu wurde die Funktion ''winopen'' hinterlegt, welche mit dem jeweiligen Pfad der Datei die entsprechende Liste öffnet. Der besagte Dialog wird automatisch geöffnet, sobald die Sortierung mit der Taste '''Esc''' beendet wird und signalisiert ein erfolgreiches Beenden des Programmes.
 
<gallery widths=400 heights=300>
Datei:GuiElementListenAusgeben.png | Abb. 14: Dialog nach dem Beenden des Programmes zum Öffnen der automatisch erstellten Listen
</gallery>
 
=== Hauptfenster der Sortierung optimiert ===
 
<gallery widths=900 heights=500>
Datei:Sortierungshauptscreen.png | Abb. 15: Hauptbildschirm der Sortierung mit Kamerabildern und Informationen über die erkannten Legoteile
</gallery>
 
Abbildung 15 zeigt das Hauptfenster, welches während der Sortierung wichtige Informationen anzeigt. Punkte 1 und 2 zeigen die Bilder des letzten Teils in der Bilderkennungsbox und Punkte 4 und 5 die Livebilder aus der Separierung. Punkt 3 zeigt Informationen zu dem zuletzt erkannten Teil an.
 
Bei längeren Betriebszeiten der Anlage wurde es auffällig, dass die Anlage merklich langsamer wurde. Auch das Programm wurde sehr langsam. Dieses Problem konnte auf dieses Hauptfenster zurück geführt werden. Im speziellen lag der Fehler darin, wie die Informationen bei Punkt 3 angezeigt wurden. Es wird die Funktion ''annotation'' verwendet, um eine Textbox mit dem benötigten Inhalt anzuzeigen. In der Ausgangsversion des Programmes wurde für jede Erkennung eine neue Textbox erzeugt und somit die alte überdeckt. Mit der Zeit waren so viele Textboxen in dem Fenster, dass die Performace deutlich sank. Um dieses Problem zu beheben werden nun vor jedem Anzeigen einer Textbox alle aktiven Textboxen gelöscht:
<source lang="matlab">
delete(findall(gcf,'type','annotation'))
</source>
 
 
Zusätzlich dazu wurde die Anzeigeart der Livebilder 4 und 5 geändert. Diese wurden vorher mit der Funktion ''imshow''angezeigt, welches für eine Echtzeitverwendung nicht geeignet ist. Deutlich effizienter ist es, die Funktion ''imshow'' einmal im ersten Durchlauf auszuführen und später nur die Daten in dem bereits angezeigten Bild zu ändern.  
<source lang="matlab">
if isempty(HandleSepRGB)
    HandleSepRGB = imshow(orgImage);
    HandleSepRGBTitel = title('Live-Bild vom Förderband');
else
    HandleSepRGB.CData = orgImage;
end
</source>
 
Mit beiden Änderungen wurde das Programm wieder beschleunigt und kann nun auch lange Zeit laufen ohne zu verlangsamen.
 
= Anlernen =
 
Die Funktion Anlernen ist eine Nebenfunktion der Anlage. Sie dient dazu, Teile mit ihren Merkmalen in die Datenbank aufzunehmen, sodass diese in einer späteren Sortierung erkannt werden können. In Abbildung 16 ist der Ablauf der Funktion schematisiert dargestellt.
<gallery widths=200 heights=400>
  Datei:AblaufAnlernen.png | Abb. 16: Ablauf der Funktion Anlernen
</gallery>
 
== Funktionalität ==
 
Der Prozess zum Anlernen musste stetig dem aktuellen Zustand der Sortierung angepasst werden. Da hier auf die gleiche Weise Legoteile angelernt werden sollen, wie sie später erkannt werden, müssen die Mechanismen zwischen den Funktionen identisch sein. Hier lag zum Beispiel ein Unterschied in der Parametrierung der Rauschentfernung vor, welcher das erfolgreiche anlernen und später erkennen behindern könnte.
 
 
Zuerst jedoch musste die Stapelfunktion beim Anlernen wiederhergestellt werden.
Der Gedanke dabei ist, dass man nur einmal die ID eines Legoteiles eingeben möchte und dann einfach beliebig viele Bilder dieses Teils machen möchte um möglichst alle Perspektiven einzufangen, in denen das Teil in der Bildverarbeitungsbox landen kann. Dazu werden die Farb- und Durchlichtbilder nun in einem Array gespeichert und beim Auswerten dann in einer Schleife einzeln verarbeitet. Jedes Farbbild wird nach der Farbe untersucht und die jeweilige Farbe gespeichert. Am Ende wird geprüft ob alle erkannten Farben identisch sind. Falls ja wird das Ergebnis in der Oberfläche angezeigt und falls nicht wird der Vorgang abgebrochen.
 
Nun werden alle Durchlichtbilder nacheinander analysiert und jedes Bild ergibt einen Datensatz des Teiles welcher dann abgespeichert wird.
 
{| class="wikitable"
!Legoteile-ID
!Bezeichnung
!Farbe
!Form
!Umfang
!Fläche
!Max. Schwerpunkt
!Min. Schwerpunkt
!Anzahl Löcher
!Anzahl Perspektiven
!Scanbar
|-
|
|Legoteil
|
|Sonstiges
|
|
|
|
|
|1
|1
|}
Tabelle 4: Felder des Datensatzes und falls vorhanden ihre Standartwerte
 
In Tabelle 4 sind die Eigenschaften des Datensatzes zu sehen. Die zweite Zeile zeigt einen Beispieldatensatz, wobei nur die leeren Felder abhängig vom Legoteil ermittelt werden. Die übrigen Eigenschaften werden immer mit einem statischen Wert beschrieben. Nach dem Anlegen des Datensatzes wird dieser in die Datenbank eingefügt und somit kann das angelernte Teil nun erkannt werden.
 
== Oberfläche ==
 
Neben den bereits erwähten Anpassungen der Oberfläche wurde beim Anlernen ein zusätzliches GUI-Element hinzugefügt. Dieses sollte zu der eingegebenen Legoteile-ID ein Bild des gerade angelernten Teiles anzeigen.
 
Der erste Schritt hierfür sind die nötigen Bilder zu organisieren. Zum Glück lagen in dem Projektordner bereits eine Vielzahl von Bildern bereit, die jeweils unter der ID des jeweiligen Teiles abgespeichert waren (vgl. Abbildung 17).
 
<gallery widths=600 heights=470>
Datei:AusschnittBildersammlungLegoteile.PNG | Abb. 17: Ausschnitt aus der Sammlung der Teilebiler. [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/GUI/teileBilder Hier] können alle vorhandenen Bilder eingesehen werden.
</gallery>
 
Nun muss für das aktuelle Teil das passende Bild gefunden werden. Da ja beim starten des Anlernprozesses die ID des Legoteiles eingegeben werden muss, kann diese einfach verwendet werden, um den Pfad zu dem passenden Bild zu ermitteln:
<source lang="matlab">
% ID beinhaltet die Legoteile-ID als Text
pfad = [cd '\GUI\teileBilder\' num2str(ID) '.jpg'];
</source>
 
 
Im nächsten Schritt wird dieses Bild eingelesen. Falls dieser Prozess scheitern sollte, weil es kein Bild von der eingegebenen ID gibt, so wird in einem Fehlerauffangverfahren ein leeres weißes Bild mit dem Namen 0.jpg geladen. So wird sichergestellt, dass immer ein Bild zum anzeigen vorhanden ist.
<source lang="matlab">
try
    teilBild = imread(pfad);
    str={['Teil gespeichert'],['Zum Beenden ESC drücken']};
catch
    pfad = [cd '\GUI\teileBilder\' '0.jpg'];
    teilBild = imread(pfad);
    str={['Teil gespeichert'],['Bild zum Teil nicht vorhanden'],['Zum Beenden ESC drücken']};
end
</source>
 
 
Angezeigt wird das Bild dann in einer neuen Figur mit einer kleinen Textbox (vgl. Abbildung 18). Dieses Fenster kann dann mit '''Esc''' geschlossen werden, um den Anlernprozess für dieses Teil zu beenden und die Eingabe einer neuen ID zu ermöglichen.
<gallery widths=300 heights=300>
    Teach_In GUI 4.PNG|Abb. 18: Das von der ID abhängige ermittelte Bild wird angezeigt
</gallery>
 
= Baukasten bearbeiten =
 
Die Funktion Baukasten bearbeiten ist eine Nebenfunktion und dient dazu, einen Teil der Informationen aus der Datenbank einzusehen und zu verändern (vgl. Abbildung 19). Speziell können hier neue Baukästen hinzugefügt werden und der Inhalt von bestehenden Baukästen bearbeitet werden.
 
Ein Baukasten ist hierbei ein physikalischer Kasten, welcher eine gewisse Menge von Legoteilen beinhaltet. Das Projekt soll mindestens zwei verschiedene Kästen unterstützen. Das Lego Mindstorms EV3 Core Set 45544 und das Lego Mindstorms EV3 Extension Set 45560. Die Nummern stellen jeweils die Kasten-ID dar, welche im Programm verwendet wird um einen Kasten zu idenzifizieren.
 
<gallery widths="900" heights="500">
Datei:Baukasten bearbeiten.JPG | Abb. 19: Hier besteht die Möglichkeit, neue Sets einzufügen oder bestehende Sets/Teile zu löschen
</gallery>
 
== Bearbeitung eines Kastens abspeichern ==
 
Wie bei der Sicherstellung der [[#Sicherstellung vorhandener Funktionen | GUI-Funktionen]] festgestellt wurde, ist die Funktionalität für den Knopf zum Speichern von Änderungen an einem bestehenden Kasten nicht implementiert. Dies wurde die folgt umgesetzt:
 
Die Tabelle unter Punkt 3 in dem Bereich '''Bestehende Kästen bearbeiten''' soll ermöglich, dass die Anzahl und die Fachnummer eines Teiles in einem Kasten bearbeitet werden kann. Ein Ansatz könnte darin bestehen, mit dem Drücken des Knopfes alle Einträge, also jedes Teil in diesem Kasten, mit den dann vorhandenen Eigenschaften für Anzahl und Fachnummer in der Datenbank zu aktualisieren. Dieser Ansatz ist jedoch ineffizient.
 
Viel besser ist es, nur die Felder zu aktualisieren, die auch geändert wurden. Dazu wird kurz vor dem Anzeigen der Tabelle in einer Variable der originale Inhalt gespeichert. Wird nun der Button '''Änderungen speichern''' gedrückt, so wird jede Spalte der Tabelle geprüft ob sie im Vergleich zu den Originaldaten verändert wurde. Falls ja wird die Veränderung an die Datenbank übermittelt.
<source lang="matlab">
% Schematischer Code zur Übersicht
% originaldaten/aktuelleDaten Aufbau
% 1: Legoteile-ID
% 2: Anzahl des Teils in dem Kasten
% 3: Fachnummer des Teils in dem Kasten
 
% Für alle Teile in dem Kasten
for i=1:size(originaldaten,1)
    if originaldaten(i,2) ~= aktuelleDaten(i,2)
        % Anzahl hat sich verändert
        anfrage = strcat('UPDATE kasten SET Anzahl = ', aktuelleDaten(i,2), ' WHERE LegoteileID = ', originaldaten(i,1));
        curs = exec(datenbank, anfrage);
    end
    if originaldaten(i,3) ~= aktuelleDaten(i,3)
        % Fachnummer hat sich verändert
        anfrage = strcat('UPDATE kasten SET Fachnummer = ', aktuelleDaten(i,3), ' WHERE LegoteileID = ', originaldaten(i,1));
        curs = exec(datenbank, anfrage);
end
</source>
 
 
Zuletzt wird ein kurzer Ladebalken angezeigt, damit der Nutzer sich in seiner Aktion bestätigt fühlt und ein Feedback erhält.
<source lang="matlab">
h = waitbar(0, 'Loading...');
for i=1:5
    waitbar(i/5);
    pause(0.1);
end
close(h);
</source>
</source>
<br /><br />


<u>''Geometrische Merkmale extrahieren:''</u><br />
== Datenbank importieren und exportieren ==
[[Datei:Merkmalsextraktion.png|200px|thumb|right|Abbildung 15: geometrische Merkmalsextraktion]]
Die Funktion "[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\Merkmalsberechnung_V3.m Merkmalsberechnung_V3]" erhält als Übergabeparameter ein Binärbild eines einzelnen Objektes (Legoteil). Aus diesem Objekt werden dann folgende Merkmale extrahiert, welche dann zurückgegeben werden:
* Umfang --> Anzahl der Pixel, die sich am Rand des Objektes befinden
* Fläche --> Anzahl der Pixel, die sich innerhalb des Objektes befinden (Löcher ausgeschlossen)
* Flächenschwerpunkt --> Pixelkoordinaten {x/y}
* Minimaler Abstand von Flächenschwerpunkt zu äußerem Rand des Objektes
* Maximaler Abstand von Flächenschwerpunkt zu äußerem Rand des Objektes
<br />
Die Berechnung der Fläche erfolgt über die Summenbildung der Zeilen und Spalten des Binärbildes. Da so nur die weißen Pixel addiert werden, handelt es sich hierbei nur um die Pixel, die zum Objekt gehören.<br />
Die Schwerpunktskoordinaten lassen sich mit der Matlab-Funktion '''Regionprops''' berechnen, welche als Übergabeparameter das Binärbild des Objektes und die Option 'centroid' erhält.<br />
Mithilfe des Kantenbildes des Objektes (erzeugt mit der Matlab-Funktion '''bwperim'''), kann eine Liste mit allen Kantenkoordinaten erstellt werden (Matlab-Funktion: '''Regionprops(Kantenbild, 'Pixellist')'''). Aus der Differenz zwischen jedem einzelnen dieser Kantenpixel und dem Schwerpunkt bestimmt man nun die Abstände vom Schwerpunkt zum Rand, welche nach minimalen und maximalen Wert durchsucht werden.
Anhand der Größe der Kantenpixelliste kann außerdem der Umfang des Objektes bestimmt werden.
<br />
Diese Merkmale dienen, zusätzlich zu der Farbe des Objektes und die Anzahl der Löcher im Objekt, als Indikatoren für den Abgleich zwischen aktuellen Legoteil in der Box und den hinterlegten Daten in der Datenbank (siehe Funktion: "[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/SQL + Excel\Datenbankabgleich.m Datenbankabgleich.m]"). <br />
Sollten sich herausstellen, dass diese Merkmale nicht genügen, um alle Legoteile voneinander unterscheiden zu können, sind weitere Merkmalsberechnungen möglich (z.B. Die Seitenlängen einer um das Objekt aufgespannten Boundingbox).
<br /><br /><br />


<u>''Herauspusten der Legoteile:''</u><br />
Zusätzlich zum Bearbeiten der Kästen sollte die Oberfläche auch den Import und Export der Datenbank unterstützen. MySQL stellt dafür Hilfsprogramme zur Verfügung, die durch die Installation von XAMPP auch auf dem Computer vorhanden sind. Zum Exportieren einer Datenbank kann das Programm ''mysqldump.exe'' verwendet werden und für den Import das Programm ''mysql.exe''. Beide sind in dem Installationsordner von XAMPP zu finden.
Sobald alle Merkmale erfasst wurden, werden diese mit einer Datenbank abgeglichen und einer Legoteil-ID zugeordnet, anhand derer man die zugehörige Box (des Linearläufers) ermittelt und mitteilt (siehe Funktion: "[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/SQL + Excel\BoxausID_SwitchCaseDB.m BoxausID_SwitchCaseDB.m]"). Danach erfolgt das Herauspusten des Legoteils aus der Kamerabox. Um herauszufinden, wann der Herauspusten beendet werden kann, wird das aktuelle Kamerabild (bei Auflichtverfahren) mit dem Kalibrierbild verglichen. Sollten hier keine großen unterschiede vorliegen, ist die Box leer und das Ventil der Druckluftdüse kann geschlossen werden.
<br />
<ref name="Autor: Penner"> Autor Kevin Penner</ref> <ref name="Autor: Tsibadze"> Autor Christo Tsibadze</ref>
<ref name="Autor: Auf der Landwehr"> Autor Jan Auf der Landwehr</ref>
<br />
<br />


=== Teach In ===
Um mit diesen Programmen und der Datenbank zu arbeiten, müssen die ausführbaren Dateien mit bestimmten Parametern aufgerufen werden. Zuerst müssen die Anmeldedaten zu der Datenbank übergeben werden. Für die Datenbank der Sortiermaschine ist das lediglich der Benutzername '''root''' ohne ein Passwort. Diese Informationen werden durch "-u root" übergeben. Als nächstes benötigt man den Namen der Datenbank. Dieser lautet '''legoteileliste'''. Zuletzt muss eine Richtung angegeben werden, ob das Programm von der Datenbank in eine Datei speichern soll oder andersrum. Dies wird durch respektive ">" oder "<" signalisiert. Zuletzt muss der Pfad entweder zum Auslesen oder zum Abspeichern der SQL-Datei übergeben werden. Alles zusammen resultiert in folgendem Befehl:
Das Teach In erfolgt über die Auswahl im Hauptmenu. Dazu muss das Programm über die Funktion [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab\StartSortiermaschine.m StartSortiermaschine] gestartet werden.  
<br/>
[http://193.175.248.52/wiki/index.php/Anleitung_Legoteilz%C3%A4hlmaschine Die Anleitung, wie das die Hauptfunktion zu benutzen ist, ist hier zu finden.]


Zur Erkennung der Merkmale werden die gleichen Funktionen verwendet wie in der Hautpunktion. Nach der Aufnahme eines Bildes wird mit [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\createBinary_V3.m createBinary_V3] das Binärbild erstellt und die Merkmale über
<source lang="matlab">
[https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\Bildverarbeitung_Teach_In.m Bildverarbeitung_Teach_In] berechnet.
% Export
<br/>
command = ['C:\xampp\mysql\bin\mysqldump.exe -u root legoteileliste > ' dateipfad];
Mit [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/SRC/Matlab/Bildverarbeitung\FARBERKENNUNG_V2.m FARBERKENNUNG_V2] wird die Farbe des eingelegten Legoteils erkannt. Anschließend werden die Merkmale in einem cell-Array gespeichert.
 
<br/>
% Import
<source lang=matlab>
command = ['C:\xampp\mysql\bin\mysql.exe -u root legoteileliste < ' dateipfad];
    Header{1,1} = 'LegoteileID';
</source>
    Header{1,2} = 'Bezeichnung';
 
    Header{1,3} = 'Farbe';
 
    Header{1,4} = 'Form';
Der Dateipfad wird mit der Funktion ''uiputfile'' zum exportieren und ''uigetfile'' zum importieren erhalten. Das erstellte Kommando wird dann mit der Funktion ''system'' ausgeführt und zuletzt abgefragt, ob der Progress fehlgeschlagen ist.
    Header{1,5} = 'Umfang';
<source lang="matlab">
    Header{1,6} = 'Flaeche';
% Befehl ausführen
    Header{1,7} = 'MaxSchwerpunkt';
status = system(command);
    Header{1,8} = 'MinSchwerpunkt';
 
    Header{1,9} = 'Rundloch';
% Fehler abfragen
     Header{1,10} = 'AnzPerspektive';
if status ~= 0
    Header{1,11} = 'Scanbar';
     disp("Prozess fehlgeschlagen")
end
</source>
</source>


Die Einträge "Bezeichnung", "Form", "AnzPerspektive" und "Scanbar" werden in der aktuellen Version nicht verwendet und sind nur noch im Code, weil die Einträge an anderen Stellen erwartet werden (beispielsweise in der SQL Datenbank). Zur besseren Übersichtlichkeit des Codes können diese in zukünftigen Versionen noch entfernt werden.


<ref name="Autor: Auf der Landwehr"> Autor Jan Auf der Landwehr</ref>
Beendet wird der Ablauf mit einem kurzen Ladebalken und somit sind beide Funktionen erfolgreich implementiert.
 
= Zusammenfassung =
 
In dem gesamten Projektzeitraum wurden viele kleine und große Änderungen an der Bildverarbeitung eingebaut. Wie man der [http://193.175.248.52/wiki/index.php/Legosortiermaschine_gesamte_Anlage#Verlauf_der_Verarbeitungsrate Verarbeitungsrate] entnehmen kann, wurde das Programm definitiv verbessert und ist nun auf einem guten, funktionsfähigen Stand.


===Fortschritt im SoSe 2017===
Erreicht wurde in dem Zeitraum u.A.:
Am Anfang haben wir uns in das Programm eingearbeitet und uns mit verschiedenen Problemen auseinandergesetzt:
*Gute Erkennung der Teile mit Ermittlung der Fachnummer
*Wie funktioniert das Programm?
*Minimierung der Zeitanforderung
*Welche Unterprogramme sind entscheidend?
*Hinzufügen von kosmetischen Funktionen
*Wie funktioniert die Verbindung zu SQL?
*Wie funktioniert die GUI-Programmierung?
Danach haben wir begonnen, kleinere Bugfixes zu programmieren, damit das Programm allgemein runder läuft.
Es ist nun ohne Abstürze über eine GUI steuerbar und Teile werden direkt in SQL gespeichert.
Wir haben auch bereits begonnen, neue Teile einzuteachen.
Wir haben alles geschafft, was wir uns für dieses Semester vorgenommen haben und sogar mit Aufgaben begonnen, die eigentlich für das nächste Semester geplant waren.


<ref name="Autor: Auf der Landwehr"> Autor Jan Auf der Landwehr</ref> <ref name="Autor: Maas"> Autor Matthias Maas</ref>
Offene Punkte sind u.A.:
*Hinzufügen weiterer Merkmale für genauere Unterscheidung der Teile
*Verbauen von anderen Bildgebenden Sensoren, um unbeeinflussbare softwareseitige Optimierung zu vermeiden
*Stabilisieren der seriellen Kommunikation


===Fortschritt im WiSe 2017/18===
Eine umfangreichere Liste offener Punkte ist [https://svn.hshl.de/svn/MTR_SDE_Praktikum_2015/trunk/Teams/Bildverarbeitung/Teamspezifische%20Dokumente/Dokumentation%20offene%20Punkte%20Stand%20SS19.docx hier] zu finden.
In diesem Semester haben wir die Separierung mit dem Hauptprogramm zusammengeführt.
Außerdem wurde die Inventurliste in der SQL-Datenbank geleert, um leere Felder auszumerzen, und anschließend wieder vollständig mit den Daten des Grundsets und des Erweiterungssets gefüllt.
Das Grundset wurde vollständig eingeteacht (ausgenommen der großen Legoteile wie Motor, Sensoren und EV3 Brick, die vorher händisch aussortiert werden müssen).
Schließlich wurde der Wiki-Artikel auf den neuesten Stand aktualisiert.


<ref name="Autor: Maas"> Autor Matthias Maas</ref>


== Autoren ==
''Dies ist ein Unterartikel von der [http://193.175.248.52/wiki/index.php/Legoteil_Z%C3%A4hlmaschine  Legoteil Zählmaschine], welcher den genauen Aufbau der Bildbearbeitung beschreibt.''
<references />

Aktuelle Version vom 11. Februar 2019, 12:22 Uhr

Dies ist ein Unterarikel von der Legoteil Zählmaschine, welcher die aktuellen Änderungen an dem Teilgebiet der Bildverarbeitung der Lego Sortiermaschine beschreibt.

Autor: Torben Müller

Einleitung

Diese Unterseite des Artikels beschäftigt sich hauptsächlich mit der Bildverarbeitung zur Erkennung der Legoteile. Dies geschieht in der Bildverarbeitungsbox der Anlage (vgl. Abbildung der Startseite Punkt 4). Zusätzlich dazu werden auch alle anderen Arbeiten an der Software des Matlab Programmes hier behandelt und dokumentiert.

Generell lässt sich das Programmes in drei Funktionalitäten aufteilen:

  • Sortierung
  • Anlernen
  • Baukasten bearbeiten

Die Funktion Sortierung stellt die Hauptfunktion dar. Sie beschreibt den laufenden Zustand der Anlage beim sortieren von Teilen. Hier spielt ein Großteil der Bildverarbeitung rein. Die Funktion Anlernen ist eine Nebenfunktion, die genutzt werden kann wenn die Anlage nicht sortiert. Hier können Legoteile angelernt werden, sodass die Anlage fähig ist diese Teile in einer späteren Sortierung zu erkennen. Die Funktion Baukasten bearbeiten dient als Wartungsfunktion um Informationen über Legobaukästen zu bearbeiten, denen jeweils die zu sortierenden Teile zugehören.

Anforderungen

Basiered auf einer Liste offener Punkte aus dem Vorsemester wurden für das Sommersemester 18 und das Wintersemester 18/19 folgende Anforderungen festgelegt:

Spezifikations-ID Anforderungs-ID Anforderungstitel Beschreibung der Spezifikation Link
0060 REQ10.2050 Bauteile Unterstützung sämtlicher Legoteile. Fokus auf NXT und EV3. Dokument
0060.1 REQ10.2050 Bauteile Visuelle Anleitung erstellen Wiki
0061 REQ10.2050 Bauteile Basissatz wird unterstützt und alle entsprechenden Teile werden erkannt Dokument
0062 REQ10.2050 Bauteile Erweiterungssatz wird unterstützt und alle entsprechenden Teile werden erkannt Dokument
0063 REQ10.2050 Bauteile Vorsortierung via GUI Wiki
0120 REQ10.2250 Bildverarbeitung Echtzeit mit Matlab/Simulink Dokument
0120.1 REQ10.2250 Bildverarbeitung Echtzeit mit Matlab/Simulink. Teile werden erkannt und mit Seriennummer klassifiziert Dokument
0122 REQ10.2220 Bildverarbeitung Geschwindingkeit erhöhen: Software analysieren und den Code beschleunigen z.B. Schleifen sparen, Variablen global speichern Dokument
0123 REQ10.2220 Bildverarbeitung Prozentsatz der erkannten Teile errechnen Dokument
0124 REQ10.2220 Bildverarbeitung Nicht erkannte Teile in der Position des nicht erkannten Teils anlernen Dokument
0125 REQ10.2220 Bildverarbeitung HSV Farbraum testen, um Farberkennung zu verbessern Dokument
0126 REQ10.2220 Bildverarbeitung In Bilderkennungsbox zusätzliche LEDs hinzufügen für besseres Auflichtbild Dokument
0127 REQ10.2220 Bildverarbeitung Offline-Modus einfügen um basierend auf einem Video die Bildverarbeitung zu testen Wiki
0140 REQ10.2300 Teileliste Inventurliste im xls-Format zeigt, wie viele Teile erkannt wurden und wie viele im Neuzustand des Kastens sind dadurch Differenz erkennbar. Fehlteilliste muss in geeignetem Format für Neubeschaffung ausgegeben werden Dokument
0141 REQ10.2300 Teileliste Geeignetes Format für eine Fehlteilliste planen, also welche Informationen enthalten sein müssen um eine Neubeschaffung zu ermöglichen zb Seriennummer oder Onlinelink Dokument
0142 REQ10.2300 Teileliste Fehlteiliste implementieren und ausgeben lassen Dokument
0143 REQ10.2300 Teileliste GUI erweitern um Fehlteilliste auszugeben Dokument
0180 REQ10.2330 Teach-In Über GUI neue Teile anlernbar. Ein benutzerfreundliches Interface soll das Anlernen der Bauteile ermöglichen. Dokument
0181 REQ10.2330 Teach-In Sicherstellung der vorhanden GUI- und Datenbankfunktionen Wiki
0182 REQ10.2330 Teach-In Fehlende Funktionen hinzufügen Dokument

Tabelle 1: Anforderungen

GUI

Die Benutzeroberfläche für dieses Projekt wurde bereits von Vorsemestern erstellt und kann verwendet werden, um das Projekt zu steuern. Zuerst galt es, die vorhandenen Funktionen der GUI zu prüfen, um weitere Arbeitsschritte zu ermitteln.

Sicherstellung vorhandener Funktionen

Für die Sicherstellung der vorhandenen GUI Funktionen wurde ein Test jedes Buttons innerhalb der Software durchgeführt und dokumentiert.

Abbildung 1: Hauptseite Abbildung 2: Hilfetexte
Der Startbildschirm (1) führt zu den Bereichen Sortierung (2), Teach-In (3) und Baukasten bearbeiten (4). Die Hilfeknöpfe blenden einen Hilfetext für den jeweiligen Programmteil ein und beenden öffnet ein Bestätigungsfenster, welches das Programm beendet oder das Fenster wieder schließt.
Abbildung 3: Sortierung starten Abbildung 4: Kontrollbildschirm bei laufender Sortierung Abbildung 5: Teach In
In dem Teilbereich der Sortierung lässt sich eine Kasten-ID auswählen, wodurch eine Tabelle mit allen in diesem Kasten enthaltenen Teilen angezeigt wird. Dort lässt sich eine manuelle Vorsortierung der Teile eintragen, wie in dem Abschnitt zur Vorsortierung beschrieben. Zurück führt zu dem Startbildschirm (1) und Beenden öffnet das Bestätigungsfenster zum Beenden oder abbrechen. Mit betätigen des Speichern Knopfes kommt man nach einem Fortschrittsbalken der Kamerakalibrierung zu einem Kontrollbildschirm, wo Echtzeitinformationen der Maschine angezeigt werden und die Maschine wird gestartet. Oben links wird das Kamerabild der Bildverarbeitung angezeigt und oben rechts ein Binärbild, welches bei der Bildverarbeitung aufgenommen wird. Unten links sieht man das Kamerabild der Seperierung und unten rechts das Binärbild aus der Seperierung. Mit Drücken der Escape-Taste wird die Maschine beendet und eine Inventurliste generiert, wo die Anzahlen der erkannten Teile angezeigt werden. In dem Bereich Teach-In kann in dem ersten Fenster eine Bauteile-ID eingegeben werden. Zurück kehrt zu dem Startbildschirm (1) zurück und Beenden führt zu dem Bestätigungsfenster. Mit Speichern & Weiter wird die Kamera der Bildverarbeitung angezeigt. Mit Enter wird ein Foto aufgenommen und mit Space wird dieses Foto in ein Binärbild umgewandelt und neu angezeigt. Erneutes Space speichert das Teil mit der eingegebenen Nummer in der Datenbank
Abbildung 6: Baukasten bearbeiten Abbildung 7: Einzelnes Teil im Baukasten bearbeiten
Bei Baukasten bearbeiten lässt sich oben im Fenster mit dem Knopf Speichern & Weiter ein neuer Baukasten erzeugen. Danach kann mit Eingaben ändern die Kasten-ID und die Anzahl der Teile nachträglich angepasst werden. In der Tabelle darunter können Teile in diesen Kasten eintragen. Änderungen speichern speichert diese Änderungen an dem Kasten in der Datenbank. Unten links kann dann Wahlweise ein Bauteil aus dem Kasten, ein Teil komplett oder ein ganzer Kasten gelöscht werden. Auswahl anwenden führt dabei die jeweils gewählte Aktion aus. Unten rechts lassen sich einzelne Bauteile in dem Kasten hinsichtlich ihrer Anzahl und Fachnummer in dem Kasten bearbeiten. Diese Änderungen werden jedoch mit dem Betätigen des Knopfes Änderungen speichern nicht in die Datenbank übernommen. Diese Funktion wird in dem Abschnitt Kastenänderungen abspeichern hinzugefügt.

Text der Oberfläche überarbeiten

Bei der Sicherstellung der Funktionalität ist aufgefallen, dass einige Knöpfe und Hinweise in der GUI nicht aussagekräftig. Zudem hatten einige Fenster noch keinen angemessenen Titel. Diese Anzeigetexte wurden angepasst, sodass die GUI einfacher zu verstehen und für ungeübte User einfacher zu benutzen ist. Die neuen Beschriftungen im Zusammenhang der Schritt für Schritt Anleitung hier zu sehen.

Sortierung

Die Sortierung ist die Hauptfunktion der Anlage. Zusammen mit dem Programm der Seperierung steuern beide die gesamte Anlage in ihrem sortierenden Zustand. Ein grober Ablauf der Sortierung kann der Abbildung 8 entnommen werden.

Dieser Algorithmus deckt die Teilbereiche Erkennung und Ansteuerung der Sortierung ab. Nach diesem Ablauf wird von der Hauptschleife des Programmes in der Datei StartSortiermaschine ein Durchlauf der Separierung gestartet. Dieser steuert alle zur Seperierung gehörenden Komponenten. Danach wird der Ablauf wiederholt. So werden alle nötigen Funktionen zum Sortieren von Legoteilen abgedeckt.

Funktionalität

Hier werden Themen behandelt, die direkt mit der Funktionalität und/oder der Effizienz der Sortierung zu tun haben. Diese Änderungen werden nicht direkt wahrgenommen und dienen dem steigern der Güte der Teileerkennung.

Bewegungserkennung

Es wurde eine Bewegungserkennung als erster Mechanismus in dem Algorithmus zum erkennen von Teilen eingefügt. Dieser Alorithmus funktioniert, indem zwei Bilder in einem kurzen Abstand voneinander aufgenommen werden. Diese Bilder werden in den Graubereich konvertiert von einander subtrahiert. In dem entstehenden Differenzbild wird das Maximum ermittelt und dieses dann mit einem Threshold verglichen.

Dieser Vorgang wird solange wiederholt, bis das Maximum des Differenzbildes kleiner ist als eine definierte Grenze, was bedeutet, dass das Teil ruht oder nur noch sehr langsam rutscht. Durch diesen Mechanismus können viele Aufnahmen verhindert werden, in denen das Bauteil noch nicht in Ruhe war und so ein verzerrtes Bild aufgenommen wurde, welches nicht korrekt analysiert werden kann.

Farberkennung

Ansatz 1:

Die Farberkennung in ihrem Ausgangszustand lieferte keine zuverlässigen Ergebnisse. Vor allem die die Farben rot, gelb, grün, blau und schwarz wurden oft in Grautönen erkannt. Um dieses Problem zu beheben, war der erste Ansatz eine Neukalibrierung der existierenden Farbwerte. Die Farbbeurteilung geschah in der Datei Farberkennung. Dort waren in dem Array Farbwerte für jede der möglichen 10 Farben Werte hinterlegt, mit denen ein aktuelles Bild verglichen wurde. Hier folgend die dort verwendeten Werte:

Farbwerte=[   0.5133 0.4578 0.4033; %'weiss'          
              0.4857 0.4154 0.3289; %'beige'         
              0.4522 0.1456 0.1868; %'rot'           
              0.1400 0.2129 0.3308; %'blau'          
              0.5817 0.4393 0.2213; %'gelb'          
              0.1637 0.1761 0.1961; %'schwarz'       
              0.1703 0.2396 0.2240; %'gruen'         
              0.3318 0.2959 0.2705; %'hellbraun'          
              0.3221 0.3228 0.3230; %'hell-grau'        
              0.2256 0.2302 0.2370; %'dunkel-grau'     
              ];

Um nun neue Farbkalibrierungswerte für jede Farbe zu erhalten und die vorhandenen damit zu überschreiben, wurden mehrere Teile jeder Farbe von der Bildverarbeitung analysiert und die berechneten Farbwerte wurden im Programm ausgelesen. Diese Farbwerte wurden dann in eine Tabelle eingetragen und über drei verschiedene Teile gemittelt. So konnte ein möglichst passender Wert für die jeweilige Legoteilfarbe ermittelt werden (vgl. Tabelle 2). Dieser Durchschnittswert wurde für alle Farben ermittelt und dann in die Farberkennung als neue Referenzwerte eingetragen.

weiß R G B
0,5153 0,4650 0,4136
0,5092 0,4570 0,4020
0,5155 0,4512 0,3944
0,5133 0,4578 0,4033

Tabelle 2: Beispielwerte für weiß


Ansatz 2:

Nach der Neukalibrierung bestanden jedoch weiterhin Erkennnungsprobleme mit einigen Farben. Vor allem schwarz konnte selten als selbiges erkannt werden. Darum folgt ein zweiter Ansatz zum verbessern der Farberkennung: Die Verwendung von Farbmasken

Mit der Matlab-App Color Thresholder (vgl. Abbildung 9) lassen sich Farbmasken für spezielle Farben erstellen. Angewendet auf ein Farbbild erzeugen diese Masken ein Binärbild, wo nur Bereiche in der jeweiligen eingestellten Farbe markiert werden. Die Idee besteht somit darin, für jede Farbe, die ein Legoteil haben kann, eine Farbmaske zu erstellen. Alle diese Masken werden dann auf ein Farbbild angewendet, welches ein Teil einer Farbe enthält. Um die Erkennung noch zu verbessern, wird das Farbbild vorher mit dem Binärbild multipliziert. Dadurch bleibt ein Bild über, wo nur an der Stelle des Teiles die originalen Bildinformationen bestehen blieben. So wird sichergestellt, dass die Masken nur die Farbe des Teiles auswerten.

Die Maske, welche auf die aktuelle Farbe eingestellt ist, wird die meiste Fläche markieren (im Idealfall die komplette Fläche des Teiles). So erzeugt also diese Maske ein Binärbild, wo die meisten Pixel aktiviert sind. Eine einfache Summierung aller Pixel in dem Bild zeigt, welche der Masken am meisten von dem eingegebenen Farbbild aktiviert wurde. Das bedeutet das die Maske mit der größten Pixelsumme auf die Farbe des aktuellen Teiles eingestellt ist und somit die Farbe bekannt ist.

% Beurteilen, welche Maske am stärksten anschlägt, also am meisten Pixel auf eins setzt
maskenPixelSummen(1) = sum(sum(binaerBeige));
maskenPixelSummen(2) = sum(sum(binaerSchwarz));
maskenPixelSummen(3) = sum(sum(binaerBlau));
maskenPixelSummen(4) = sum(sum(binaerGrau));
maskenPixelSummen(5) = sum(sum(binaerGruen));
maskenPixelSummen(6) = sum(sum(binaerHellbraun));
maskenPixelSummen(7) = sum(sum(binaerHellgrau));
maskenPixelSummen(8) = sum(sum(binaerRot));
maskenPixelSummen(9) = sum(sum(binaerWeis));
maskenPixelSummen(10) = sum(sum(binaerGelb));

[~, index] = max(maskenPixelSummen);

%Entsprechende Farbe speichern
switch index
    case 1 
        Farbe='beige';
    case 2
        Farbe='schwarz';
    case 3
        Farbe='blau';
    case 4
        Farbe='dunkel-grau';
    case 5
        Farbe='gruen';
    case 6
        Farbe='hell-braun';
    case 7
        Farbe='hell-grau';
    case 8
        Farbe='rot';
    case 9
        Farbe='weiss';
    case 10
        Farbe='gelb';
    otherwise
        disp('ERROR with color detektion')
end

Merkmal-Erkennung

Die Merkmale eines Legoteiles werden aus dem Durchlichtbild extrahiert. Dazu wird das Bild zuerst in ein Binärbild konvertiert, um dann die einzelnen Merkmale kalkulieren zu können. Die Erstellung dieses Binärbildes hat sich im Ausgangszustand als Fehleranfällig erwiesen. Zudem war deutlich zu erkennen, dass das Teil nicht besonders genau abgebildet wurde, sodass Parameter wie Umfang und Fläche nicht sonderlich aussagekräftig waren.

Zur Besserung wurde hier ein neues Verfahren zur Erstellung des Binärbildes eingeführt. Eine Matlab-Funktion imbinarize ermöglicht die Berechnung eines Binärbildes durch einen vorher ermittelten Grenzwert aus einem Farbbild. Die Idee besteht darin, das Durchlichtbild an die Funktion imbinarize zu übergeben und dadurch ein Binärbild des Teiles zu erhalten. Anschließend müssen von der resultierenden Matrix die überflüssigen Tiefenkanäle abgeschnitten werden und das Bild von Salz- und Pfefferrauschen bereinigt werden.

    hintergrundLevel = graythresh(durchlichtbild);
    binaerbild = imbinarize(differenzFarbbild,hintergrundLevel);
    binaerbild = binaerbild(:,:,1);
    binaerbild = ~binaerbild;
    %Bereinigung des Binärbildes
    %Salz (weiße Pixel) auf Hintergrund entfernen
    binaerbild = bwareaopen(binaerbild,SalzPfeffer);
    %Pfeffer (schwarze Pixel) in Legoteilen entfernen
    binaerbild = ~bwareaopen(~binaerbild,SalzPfeffer);


Das Resultat ist ein einwandfreies Binärbild des Teiles (vgl. Abbildung 10).

Echtzeit

Zum Testen der Echtzeit der Bildverarbeitung wurde ein Versuch entworfen. Dabei werden Teile wie im folgenden Bild direkt vor der Bildverarbeitungsbox auf das Förderband gelegt (vgl. Abbildung 11) und zeitgleich eine Zeitmessung gestartet. Sobald ein Teil in die Bildverarbeitunngsbox gefallen ist, wird an die gleiche Stelle ein neues Teil gelegt, sodass fast permanent ein Teil in der Box liegt und die Pause zwischen den Teilen minimal ist.


Um die Ausgangssituation zu bewerten, wurde dieser Test mit verschiedenen Teilearten und -mengen ausgeführt. (Test vom 31.05.18)

Test Anzahl Teile Anzahl erkannt Gesamtzeit [s] Zeit pro Teil [s] Erkennungsrate [%] Teileart
1 15 10 43 2,86 66,6 gemischt
2 30 16 86 2,86 53,3 gemischt
3 20 15 60 3 75 klein
4 15 9 42 2,8 60 groß

Tabelle 3: Tests und Ergebnisse zur Echtzeit


Hier kann man erkennen, dass die Zeit pro Teil nur leichte Änderungen aufweist zwischen den unterschiedlichen Teilegruppen und dadurch festgestellt werden kann, dass die Echtzeit nicht stark von der Teileart beeinflusst wird.

In einem zweiten Testdurchgang wurde dann eine zufällige Teilegruppe verwendet und keine externe Zeitmessung mehr durchgeführt, sondern nur das Ergebnis des Matlab Profilers analysiert um verschiedene Methoden zur Erhöhung der Geschwindigkeit zu testen. Dieses Tool verfolgt zur Laufzeit des Programmes die Anzahl von Funktionsaufrufen und deren Ausführungsdauer. So wird für jede ausgeführte Programmzeile die Gesamtzeit gemessen, die diese Zeile beansprucht. Außerdem wird eine Übersicht erstellt mit den zeitaufwändigsten Zeilen und wie viel Zeit diese prozentual von der Gesamtzeit beansprucht haben.

Funktionsaufrufe: 267 Funktionsaufrufe: 404
Ausgangszustand:




0,13s pro Call


Erste Iteration:
  • imshow verschoben -> wird nur auseführt wenn Teil auch ausgewertet wird
  • Pause bei seriellen Befehlen entfernt
  • Lightdelay um die Hälfte reduziert


0,082s pro Call


Funktionsaufrufe: 287 Funktionsaufrufe: 297
Zweite Iteration:
  • 0,2s Pause für Bewegungserkennung innerhalb der Bildverarbeitungsbox hinzugefügt
  • Funktion figure(HauptFigure) entfernt


0,12s pro Call

Dritte Iteration:
  • Pause der Bewegungserkennung auf 0,1 reduziert



0,117s pro Call

Erkennung der Teile

Um die Erkennung der Teile aus beiden Baukästen (Basisset 45544 und Erweiterungsset 45560) sicherzustellen, wurde eine Excel Tabelle angelegt und jedes Teil einzeln geprüft, ob es von der Anlagt erkannt wird.

Das entsprechende Ergebnis wurde in der richtigen Spalte der Tabelle festgehalten. Hier sieht man den Aufbau der Tabelle:

Teile ID Kasten ID In Datenbank vorhanden Wird erkannt Muss manuell gezählt werden Bemerkungen

Wurde ein Teil nicht oder schwer erkannt, so wurde dies in der Spalte Bemerkung vermerkt, sodass später die kritischen Teile erneut angelernt werden konnten. Zusätzlich ließen sich hier Fehler in der Erkennung verdeutlichen, zum Beispiel das schwarze Teile zu beginn generell schwer erkannt werden konnten.

Mit dem Ende der Projektzeit sind alle Teile bearbeitet und so vermerkt, dass sie entweder von der Anlage erkannt werden können oder auf Grund von Größe oder Beschaffenheit manuell vorsortiert werden müssen.

Interaktion

Dieser Absatz der Sortierung beschäftigt sich mit Aufgaben, die direkten Einfluss auf die Interaktion mit der Sortierung haben. Dazu zählen kosmetische aber auf performancerelevante Änderungen.

Manuelle Vorsortierung

In Abbildung 3 wird die GUI zum Starten der Sortierung angezeigt. Dort wird in der Mitte eine Tabelle dargestellt, die nach Auswählen der Kasten ID alle Teile in diesem Kasten anzeigt. Die erste Spalte beinhaltet die ID des Teils, die zweite die vorgesehene Anzahl dieses Teiles in dem Kasten und in der dritten Spalte sollte dann die Möglichkeit bestehen die Anzahl der Teile einzutragen, die bereits mit der Hand vorsortiert worden sind. Dazu muss zuerst der Data Array der Tabelle, welcher die Inhalte speichert um eine dritte Nullspalte erweitert werden. Dazu wird die Funktion horzcat verwendet, die zwei Arrays horizontal miteinander verbindet:

% Datei SortierStart.m
Nullreihe = cell(size(curs.Data,1),1);
Nullreihe(:,1) = {0};
handles.uitable1.Data = horzcat(curs.Data, Nullreihe);

global GUI_vorsortierteTeile
GUI_vorsortierteTeile = handles.uitable1.Data;


Der Inhalt der Tabelle wird zuletzt in eine globale Variable gespeichert, um bei der Erstellung der Inventurliste auf die Anzahl der vorgezählten Teile zugreifen zu können. Dabei wird auf die Anzahl der automatisch gezählten Teile, gespeichert in der vierten Spalte von InventurListeContent, die Anzahl der manuell gezählten Teile, gespeichert in der dritten Spalte von GUI_vorsortierteTeile, addiert und später ausgegeben:

% Datei InventurlistenTemplateMultiKaesten.m
InventurListeContent(2:end,4) = num2cell(cell2mat(InventurListeContent(2:end,4)) + cell2mat(GUI_vorsortierteTeile(:,3)));
...
xlswrite(InventurlisteName,InventurListeContent);


Für diese hinzugefügte Funktion wurde in der Anleitung für die Gesamtanlage der entsprechende Abschnitt bearbeitet: Teile vorsortieren

Prozentsatz nicht erkannter Teile

In der Inventurliste soll zusammen mit den Anzahlen der einzelnen Teile auch eine Prozentzahl ausgegeben werden die angibt, wie viel Prozent der analysierten Teile nicht erkannt wurden. Der Array LegoTeile enthält die Anzahlen von allen Teilen zuzüglich der Anzahl der nicht erkannten Teile. Im nächsten Schritt müssen die einzelnen Mengen addiert werden um dann die Anzahl der nicht erkannten Teile in ein Verhältnis zu der Gesamtanzahl an analysierten Teilen setzen zu können. In der letzten Zeile wird die errechnete Zahl dann in die zweite Zeile unter der Inventurliste von Teilen in dem Kasten zusammen mit etwas Text ausgegeben ausgegeben

% Berechnen des Anteils nicht erkannter Teile
gesamtZahlTeile = sum(LegoTeile(:,2));
prozentsatzNichtErkannterTeile = LegoTeile(1,2)/gesamtZahlTeile;

% Anhängen der Information an die Daten für den Excel-Export
InventurListeContent(end+2,3) = {['Nicht erkannte Teile: ' num2str(prozentsatzNichtErkannterTeile*100) '%']};


Fehlteilliste

Um nach dem erfolgreichen Sortieren eines Kastens die Nachbestellung der fehlenden Teile zu vereinfachen, soll eine Fehlteilliste erstellt werden in der die Mengen der Fehlteile abgespeichert werden. Zuerst sollte dafür ein Layout erstellt werden (vgl. Abbildung 12). Dieses Layout sollte die Teile übersichtlich mit allen wichtigen Informationen darstellen und eine Nachbestellung dieses Teils vereinfachen. Das folgende Layout orientiert sich an den üblichen Materialbestellungslisten der Hochschule, ist aber ergänzt um die Spalte Kastenbezeichnung, wo manuell die Nummer des Kastens eingetragen werden kann, die von der Hochschule auf den Kasten geklebt wurde. Die ersten drei Spalten sollen dann von der Software selbst ausgefüllt werden, sodass die generierte Liste dann verwendet werden kann, um den Nachbestellungsprozess zu dokumentieren und zu verwalten.

Da die Liste ähnliche Daten benötigt wie die Inventurliste, wird die Fehlteilliste mit den gleichen Parametern aufgerufen und ähnlich erzeugt:

% FEHLTEILLISTE generiert die Fehlteilliste aus den gezählten Legoteilen
%
% Syntax:
%       Fehlteilliste(KastenID, FehlteillisteName, Legoteile)
%
% Beschreibung:
%       Legt eine Kopie der Fehlteilliste-Template an und trägt die
%       ermittelten Differenzdaten aus Soll und Ist ein
%
% Eingangswerte:
%       KastenID:           Die ID des verwendeten Kastens
%
%       FehlteillisteName:  Pfad der Fehlteilliste-Template
%
%       Legoteile:          Die gezählten Legoteile nach ID sortiert

Der Parameter Legoteile wird bei der Berechnung der Daten der Fehlteilliste als Istdaten verwendet und stellt die vorhandenen, also erkannten, Teile dar. Um die fehlenden Teile zu ermitteln müssen die Istdaten von den Solldaten abgezogen werden. Somit muss aus der Datenbank die vorgesehene Anzahl jedes Teils ausgelesen werden. Davon wird die vorhandene sortierte Anzahl aller Teile subtrahiert und es entsteht die Menge der fehlenden Teile.


Durch die Subtraktion der Mengen werden Legoteile, die komplett vorhanden sind mit einer Anzahl von null aufgeführt. Änhliches gilt für Teile, die öfter erkannt wurden als sie in dem Kasten vorhanden sein sollten. Da jedoch nur fehlende Teile ausgegeben werden sollen, müssen alle Teile aus der Differenzmenge entfernt werden, die eine Anzahl kleiner oder gleich null aufweisen. Diese Funktionalität wird über folgende Zeile ausgeführt.

% Zeilen, wo Anzahl der Legoteile <= 0 ist, werden entfernt
differenzdaten(any(differenzdaten <= 0, 2), :) = [];

Die Funktion any ermittelt jede Zeile wo ein Element kleiner oder gleich null ist und setzt diese auf einen leeren Wert. Dadurch wird diese Zeile entfernt und die Menge der Differenzteile ist aufgeräumt.

Diese Daten müssen dann in die Fehlteilliste geschrieben werden. Um das Layout zu behalten, legt das Script zuerst eine Kopie des Layouts an und füllt diese dann mit den Daten:

%% Excel-Datei genereieren %%

% Aus Template neue Liste generieren    
dateinameTemplate = [pwd '\Excel\FehlteillisteTemplate.xls'];
try
    copyfile(dateinameTemplate,FehlteillisteName);
catch
    disp('Fehlteilliste aktuell geöffnet. Konnte nicht überschrieben werden')
    return
end

% Sheet und Range festlegen
arbeitsblatt = 1;
startZelle = 'A12';

% Daten in Liste schreiben
xlswrite(FehlteillisteName,differenzdaten,arbeitsblatt,startZelle);

Die Parameter arbeitsblatt und startZelle werden festgelegt, damit die ermnittelten Differenzdaten an die richige Stelle geschrieben werden. Nun ist die Fehlteilliste fertig und kann verwendet werden (vgl. Abbildung 13)

Zum Ausgeben der Fehlteilliste wurde ein neues GUI-Element eingebaut. Es besteht aus einem kleinen Dialog mit zwei Buttons (vgl. Abbildung 14). Einer öffnet die Inventurliste, der andere die Fehlteilliste. Dazu wurde die Funktion winopen hinterlegt, welche mit dem jeweiligen Pfad der Datei die entsprechende Liste öffnet. Der besagte Dialog wird automatisch geöffnet, sobald die Sortierung mit der Taste Esc beendet wird und signalisiert ein erfolgreiches Beenden des Programmes.

Hauptfenster der Sortierung optimiert

Abbildung 15 zeigt das Hauptfenster, welches während der Sortierung wichtige Informationen anzeigt. Punkte 1 und 2 zeigen die Bilder des letzten Teils in der Bilderkennungsbox und Punkte 4 und 5 die Livebilder aus der Separierung. Punkt 3 zeigt Informationen zu dem zuletzt erkannten Teil an.

Bei längeren Betriebszeiten der Anlage wurde es auffällig, dass die Anlage merklich langsamer wurde. Auch das Programm wurde sehr langsam. Dieses Problem konnte auf dieses Hauptfenster zurück geführt werden. Im speziellen lag der Fehler darin, wie die Informationen bei Punkt 3 angezeigt wurden. Es wird die Funktion annotation verwendet, um eine Textbox mit dem benötigten Inhalt anzuzeigen. In der Ausgangsversion des Programmes wurde für jede Erkennung eine neue Textbox erzeugt und somit die alte überdeckt. Mit der Zeit waren so viele Textboxen in dem Fenster, dass die Performace deutlich sank. Um dieses Problem zu beheben werden nun vor jedem Anzeigen einer Textbox alle aktiven Textboxen gelöscht:

delete(findall(gcf,'type','annotation'))


Zusätzlich dazu wurde die Anzeigeart der Livebilder 4 und 5 geändert. Diese wurden vorher mit der Funktion imshowangezeigt, welches für eine Echtzeitverwendung nicht geeignet ist. Deutlich effizienter ist es, die Funktion imshow einmal im ersten Durchlauf auszuführen und später nur die Daten in dem bereits angezeigten Bild zu ändern.

if isempty(HandleSepRGB)
    HandleSepRGB = imshow(orgImage);
    HandleSepRGBTitel = title('Live-Bild vom Förderband');
else
    HandleSepRGB.CData = orgImage;
end

Mit beiden Änderungen wurde das Programm wieder beschleunigt und kann nun auch lange Zeit laufen ohne zu verlangsamen.

Anlernen

Die Funktion Anlernen ist eine Nebenfunktion der Anlage. Sie dient dazu, Teile mit ihren Merkmalen in die Datenbank aufzunehmen, sodass diese in einer späteren Sortierung erkannt werden können. In Abbildung 16 ist der Ablauf der Funktion schematisiert dargestellt.

Funktionalität

Der Prozess zum Anlernen musste stetig dem aktuellen Zustand der Sortierung angepasst werden. Da hier auf die gleiche Weise Legoteile angelernt werden sollen, wie sie später erkannt werden, müssen die Mechanismen zwischen den Funktionen identisch sein. Hier lag zum Beispiel ein Unterschied in der Parametrierung der Rauschentfernung vor, welcher das erfolgreiche anlernen und später erkennen behindern könnte.


Zuerst jedoch musste die Stapelfunktion beim Anlernen wiederhergestellt werden. Der Gedanke dabei ist, dass man nur einmal die ID eines Legoteiles eingeben möchte und dann einfach beliebig viele Bilder dieses Teils machen möchte um möglichst alle Perspektiven einzufangen, in denen das Teil in der Bildverarbeitungsbox landen kann. Dazu werden die Farb- und Durchlichtbilder nun in einem Array gespeichert und beim Auswerten dann in einer Schleife einzeln verarbeitet. Jedes Farbbild wird nach der Farbe untersucht und die jeweilige Farbe gespeichert. Am Ende wird geprüft ob alle erkannten Farben identisch sind. Falls ja wird das Ergebnis in der Oberfläche angezeigt und falls nicht wird der Vorgang abgebrochen.

Nun werden alle Durchlichtbilder nacheinander analysiert und jedes Bild ergibt einen Datensatz des Teiles welcher dann abgespeichert wird.

Legoteile-ID Bezeichnung Farbe Form Umfang Fläche Max. Schwerpunkt Min. Schwerpunkt Anzahl Löcher Anzahl Perspektiven Scanbar
Legoteil Sonstiges 1 1

Tabelle 4: Felder des Datensatzes und falls vorhanden ihre Standartwerte

In Tabelle 4 sind die Eigenschaften des Datensatzes zu sehen. Die zweite Zeile zeigt einen Beispieldatensatz, wobei nur die leeren Felder abhängig vom Legoteil ermittelt werden. Die übrigen Eigenschaften werden immer mit einem statischen Wert beschrieben. Nach dem Anlegen des Datensatzes wird dieser in die Datenbank eingefügt und somit kann das angelernte Teil nun erkannt werden.

Oberfläche

Neben den bereits erwähten Anpassungen der Oberfläche wurde beim Anlernen ein zusätzliches GUI-Element hinzugefügt. Dieses sollte zu der eingegebenen Legoteile-ID ein Bild des gerade angelernten Teiles anzeigen.

Der erste Schritt hierfür sind die nötigen Bilder zu organisieren. Zum Glück lagen in dem Projektordner bereits eine Vielzahl von Bildern bereit, die jeweils unter der ID des jeweiligen Teiles abgespeichert waren (vgl. Abbildung 17).

Nun muss für das aktuelle Teil das passende Bild gefunden werden. Da ja beim starten des Anlernprozesses die ID des Legoteiles eingegeben werden muss, kann diese einfach verwendet werden, um den Pfad zu dem passenden Bild zu ermitteln:

% ID beinhaltet die Legoteile-ID als Text
pfad = [cd '\GUI\teileBilder\' num2str(ID) '.jpg'];


Im nächsten Schritt wird dieses Bild eingelesen. Falls dieser Prozess scheitern sollte, weil es kein Bild von der eingegebenen ID gibt, so wird in einem Fehlerauffangverfahren ein leeres weißes Bild mit dem Namen 0.jpg geladen. So wird sichergestellt, dass immer ein Bild zum anzeigen vorhanden ist.

try
    teilBild = imread(pfad);
    str={['Teil gespeichert'],['Zum Beenden ESC drücken']};
catch
    pfad = [cd '\GUI\teileBilder\' '0.jpg'];
    teilBild = imread(pfad);
    str={['Teil gespeichert'],['Bild zum Teil nicht vorhanden'],['Zum Beenden ESC drücken']};
end


Angezeigt wird das Bild dann in einer neuen Figur mit einer kleinen Textbox (vgl. Abbildung 18). Dieses Fenster kann dann mit Esc geschlossen werden, um den Anlernprozess für dieses Teil zu beenden und die Eingabe einer neuen ID zu ermöglichen.

Baukasten bearbeiten

Die Funktion Baukasten bearbeiten ist eine Nebenfunktion und dient dazu, einen Teil der Informationen aus der Datenbank einzusehen und zu verändern (vgl. Abbildung 19). Speziell können hier neue Baukästen hinzugefügt werden und der Inhalt von bestehenden Baukästen bearbeitet werden.

Ein Baukasten ist hierbei ein physikalischer Kasten, welcher eine gewisse Menge von Legoteilen beinhaltet. Das Projekt soll mindestens zwei verschiedene Kästen unterstützen. Das Lego Mindstorms EV3 Core Set 45544 und das Lego Mindstorms EV3 Extension Set 45560. Die Nummern stellen jeweils die Kasten-ID dar, welche im Programm verwendet wird um einen Kasten zu idenzifizieren.

Bearbeitung eines Kastens abspeichern

Wie bei der Sicherstellung der GUI-Funktionen festgestellt wurde, ist die Funktionalität für den Knopf zum Speichern von Änderungen an einem bestehenden Kasten nicht implementiert. Dies wurde die folgt umgesetzt:

Die Tabelle unter Punkt 3 in dem Bereich Bestehende Kästen bearbeiten soll ermöglich, dass die Anzahl und die Fachnummer eines Teiles in einem Kasten bearbeitet werden kann. Ein Ansatz könnte darin bestehen, mit dem Drücken des Knopfes alle Einträge, also jedes Teil in diesem Kasten, mit den dann vorhandenen Eigenschaften für Anzahl und Fachnummer in der Datenbank zu aktualisieren. Dieser Ansatz ist jedoch ineffizient.

Viel besser ist es, nur die Felder zu aktualisieren, die auch geändert wurden. Dazu wird kurz vor dem Anzeigen der Tabelle in einer Variable der originale Inhalt gespeichert. Wird nun der Button Änderungen speichern gedrückt, so wird jede Spalte der Tabelle geprüft ob sie im Vergleich zu den Originaldaten verändert wurde. Falls ja wird die Veränderung an die Datenbank übermittelt.

% Schematischer Code zur Übersicht
% originaldaten/aktuelleDaten Aufbau
% 1: Legoteile-ID
% 2: Anzahl des Teils in dem Kasten
% 3: Fachnummer des Teils in dem Kasten

% Für alle Teile in dem Kasten
for i=1:size(originaldaten,1)
    if originaldaten(i,2) ~= aktuelleDaten(i,2)
        % Anzahl hat sich verändert
        anfrage = strcat('UPDATE kasten SET Anzahl = ', aktuelleDaten(i,2), ' WHERE LegoteileID = ', originaldaten(i,1));
        curs = exec(datenbank, anfrage);
    end
    if originaldaten(i,3) ~= aktuelleDaten(i,3)
        % Fachnummer hat sich verändert
        anfrage = strcat('UPDATE kasten SET Fachnummer = ', aktuelleDaten(i,3), ' WHERE LegoteileID = ', originaldaten(i,1));
        curs = exec(datenbank, anfrage);
end


Zuletzt wird ein kurzer Ladebalken angezeigt, damit der Nutzer sich in seiner Aktion bestätigt fühlt und ein Feedback erhält.

h = waitbar(0, 'Loading...');
for i=1:5
    waitbar(i/5);
    pause(0.1);
end
close(h);

Datenbank importieren und exportieren

Zusätzlich zum Bearbeiten der Kästen sollte die Oberfläche auch den Import und Export der Datenbank unterstützen. MySQL stellt dafür Hilfsprogramme zur Verfügung, die durch die Installation von XAMPP auch auf dem Computer vorhanden sind. Zum Exportieren einer Datenbank kann das Programm mysqldump.exe verwendet werden und für den Import das Programm mysql.exe. Beide sind in dem Installationsordner von XAMPP zu finden.

Um mit diesen Programmen und der Datenbank zu arbeiten, müssen die ausführbaren Dateien mit bestimmten Parametern aufgerufen werden. Zuerst müssen die Anmeldedaten zu der Datenbank übergeben werden. Für die Datenbank der Sortiermaschine ist das lediglich der Benutzername root ohne ein Passwort. Diese Informationen werden durch "-u root" übergeben. Als nächstes benötigt man den Namen der Datenbank. Dieser lautet legoteileliste. Zuletzt muss eine Richtung angegeben werden, ob das Programm von der Datenbank in eine Datei speichern soll oder andersrum. Dies wird durch respektive ">" oder "<" signalisiert. Zuletzt muss der Pfad entweder zum Auslesen oder zum Abspeichern der SQL-Datei übergeben werden. Alles zusammen resultiert in folgendem Befehl:

% Export
command = ['C:\xampp\mysql\bin\mysqldump.exe -u root legoteileliste > ' dateipfad];

% Import
command = ['C:\xampp\mysql\bin\mysql.exe -u root legoteileliste < ' dateipfad];


Der Dateipfad wird mit der Funktion uiputfile zum exportieren und uigetfile zum importieren erhalten. Das erstellte Kommando wird dann mit der Funktion system ausgeführt und zuletzt abgefragt, ob der Progress fehlgeschlagen ist.

% Befehl ausführen
status = system(command);

% Fehler abfragen
if status ~= 0 
    disp("Prozess fehlgeschlagen")
end


Beendet wird der Ablauf mit einem kurzen Ladebalken und somit sind beide Funktionen erfolgreich implementiert.

Zusammenfassung

In dem gesamten Projektzeitraum wurden viele kleine und große Änderungen an der Bildverarbeitung eingebaut. Wie man der Verarbeitungsrate entnehmen kann, wurde das Programm definitiv verbessert und ist nun auf einem guten, funktionsfähigen Stand.

Erreicht wurde in dem Zeitraum u.A.:

  • Gute Erkennung der Teile mit Ermittlung der Fachnummer
  • Minimierung der Zeitanforderung
  • Hinzufügen von kosmetischen Funktionen

Offene Punkte sind u.A.:

  • Hinzufügen weiterer Merkmale für genauere Unterscheidung der Teile
  • Verbauen von anderen Bildgebenden Sensoren, um unbeeinflussbare softwareseitige Optimierung zu vermeiden
  • Stabilisieren der seriellen Kommunikation

Eine umfangreichere Liste offener Punkte ist hier zu finden.


Dies ist ein Unterartikel von der Legoteil Zählmaschine, welcher den genauen Aufbau der Bildbearbeitung beschreibt.