Laden...
Avatar #avatar-1768.jpg
dr4g0n76 myCSharp.de - Experte
Software-Entwickler, momentan als Software Test Engineer tätig Deutschland Dabei seit 07.07.2005 2.921 Beiträge

Forenbeiträge von dr4g0n76 Ingesamt 2.921 Beiträge

22.05.2010 - 14:42 Uhr
  • Wichtig wäre dann zu wissen, was für Qualifikationen hast Du?
  • Wie hast Du dich weitergebildet seit der Ausbildung ?
  • Hast Du Zertifikate?
  • Was hast Du veröffentlicht?
  • Was hast Du sonst für Kentnnisse?

Ich habe festgestellt, manche beeindruckt es auch wenn man zeigt was man hier bei mycsharp.de veröffentlicht oder beigetragen hat.

Noch eine ganz andere Möglichkeit: Mach eine gute Software. Benutze sie täglich für Dich, um sie zu verbessern. Veröffentliche diese als Opensource.

Bei mir kam es schon 3 mal vor, dass Firmen die Software kaufen wollten.

Kennst Du vielleicht jemand der Chef bei einer IT Firma ist? Mit dem Du guten privaten Kontakt hast? Frag ihn mal worauf er bei Bewerbungen achtet.

Wenn Du niemanden kennst, vielleicht weiß jemand Deiner Freunde jemanden.

Mach Zertifizierungen. Problem dabei: Teuer.

Das ist alles was mir auf Anhieb einfällt ohne allzulange nachzudenken.

Wenn Du noch sonstiges mehr wissen willst, schreibs hier rein oder per PM.

21.05.2010 - 19:18 Uhr
  • Gabor Filter vorerst integriert (noch ziemlich ungetestet)

So, der Gabor Filter liefert jetzt etwas.
Ich muss das jetzt noch verifizieren, anscheinend ist aber auch die Phase verschoben.
Mal sehen.

  • Ebenso Mean Shift integriert.

Bin ich gerade am testen.

Offtopic Shilderkennung: Jetzt werden noch die EdgeFilter die schon in der ältesten Lib drin waren (bevor sie so groß wurde), korrigiert, da diese jetzt mit 32 Bit laufen müssen und dann gehts wieder weiter. 😉

21.05.2010 - 18:44 Uhr

@Isaac:

Es sind nicht nur die, manchmal sind es auch die Projektleiter die aktiv mitprogrammieren.

21.05.2010 - 08:48 Uhr

@centai

In diesem Sinne ist es natürlich wichtig, die Bilder vorzuverarbeiten, also am besten die Features zu extrahieren, die relevant für die Ähnlichkeit sind. Je nachdem, wie du Ähnlichkeit definierst, können das sehr unterschiedliche Features sein.

Ich finde das auch, deswegen hatte ich auch geschrieben,
dass DU hier ein paar Bilder posten sollst.

Sonst wird das schwer zu beurteilen.

20.05.2010 - 19:26 Uhr

@gfoidl: Damit Du (vorerst 😉 Ruhe gibst, ja ich habe es durchaus in Betracht gezogen. Aber mein Gabor Filter läuft noch nicht richtig, deswegen habe ich zuerst den anderen Ansatz gewählt. lach

20.05.2010 - 19:22 Uhr

Zeig bitte mal ein paar dieser Bilder dann wird es bestimmt viel einfacher.

(hier posten)

Da ich nicht weiß, wie die Bilder aussehen (bzgl. Ähnlichkeit usw.) kann ich sonst nämlich nichts dazu sagen.

20.05.2010 - 19:19 Uhr

@gfoidl: Ja, das habe ich in Betracht gezogen. Aber wir bzw. ich wollen ja einen neuen Ansatz finden.

Hier ein kleines Video für die ersten Gehversuche zur Lokalisierung, noch ohne perfektes Feintuning.

Detektion kommt als nächstes. (wenn die Lokalisierung passt).

Hier eine Avi-Datei für den ersten Test:

EDIT: Ach ja, das ist momentan Methode 1 (noch ohne gelbe Schilder)

20.05.2010 - 18:00 Uhr

Danke. 😉 @gfoidl.

Momentan bin ich daran folgende Filter Für das Projekt zu realisieren:

  • Junction Detection
  • PrintedTextRegion (wird vielleicht umbenannt in TextLocalization o. ä.)
  • Wavelet Edge Transform

sowie weitere Finetunings mit den vorher genannten 4 (+1 mit ObjektExtraktor) Vorgehensweisen.

20.05.2010 - 17:44 Uhr

Interessehalber:

Hat jemand von euch schon mal die Geschwindigkeitsunterschiede mittels

C++ .NET
C# .NET

gemessen, wenn in beiden Sprachen mit GDI gezeichnet wird?

Gibt es überhaupt deutlich merkbare Unterschiede?

Was könnt ihr mir dazu sagen.

Ich werde vorerst nicht dazu kommen das zu testen, aber auf Anhieb hab ich zumindest über Google und Bing keinen Vergleich gefunden.

Da ich momentan mit Vollgas an

Verkehrsschilderkennung in neuen Fahrzeugen

bin, werde ich vorerst nicht dazu kommen.

20.05.2010 - 16:59 Uhr

@Mansur: Danke. Dann werde ich das Archiv nochmals hochladen. Vermutlich ist mir beim letzten Hochladen ein Fehler passiert (FTP lädt noch im Hintergrund hoch und ich habe den Computer in Standby versetzt...)

@Mansur:

So, habe das Archiv nochmals hochgeladen.

Außerdem habe ich jetzt hier die Binaries angehängt.

Für das hier angehängte Archiv gilt:

Leider musste ich die PDBs löschen und ein anderer Dateidialog darf nicht ausgewählt werden.

Es kann also hiermit weder Debugged noch ein Dateidialog mit Vorschau ausgewählt werden.
Aber das Programm sollte ausprobiert werden können.

Ich habs ausprobiert bei mir auf dem Rechner lässt sich die Exe aus dem Binary Verzeichnis starten.

EDIT: Ergänzungen für Änderungen:

  • In die Child-Windows kann jetzt per Drag&Drop eine Bild-Datei hereingeladen werden.

  • Mehrere Bilder auf einmal laden ist möglich durch Drag&Drop mehrerer Bilder auf den Client-Bereich

  • Die Menüpunkte Same Size / Same Width / Same Height sind im Kontext-Menü für die Child Windows hinzugekommen

  • Einige Fehler in manchen Filtern beseitigt

  • Interpolation Filter (Für 2 Bilder) hinzugefügt

  • Neuer Video-Detektions-Filter hinzugefügt

-Copy Paste Fehler in "Add" korrigiert: "Add" hatte gleiche Auswirkung wie "Sub"
Außerdem unterstützen jetzt beide Filter "ClipColor"

  • Außerdem haben jetzt alle Comboboxen und andere Steuerelemente in denen Filter aufgerufen werden können AutoComplete aktiviert.

  • Shortcut CTRL-F (F wie Filter) öffnet eine Textbox in der einfach durch eintippen des Namens und anschließendes Return ein Filter ausprobiert werden kann.

20.05.2010 - 08:20 Uhr

Es wäre wichtig im voraus viel mehr über den Hintergrund des Projektes zu wissen.
Dann können wir Dir auch einen Schubs in die richtige Richtung geben.

Warum müssen die Videos abgespielt werden, was soll dargestellt werden und wie?

Werden irgendwelche Bildbearbeitungsfilter oder Videofilter benötigt?

Wichtig wäre auch zu wissen, müssen alle Streams 100% korrekt synchronisiert abgespielt werden?

und so weiter...

weil sonst reicht evtl. ein mit 4 ActiveX Media Playern bestückte Winform. die alle ihren Output an jeweils einen Beamer senden...? Vielleicht gibts dazu ja eine Konfigurationssoftware (schon bei der Beamer Software mitgeliefert oder eine Freeware) so dass die einzelnen Mediaplayer Streams umgeleitet werden können.

Wenn das alles nicht ausreichen sollte, ist sicherlich mehr Aufwand nötig.

19.05.2010 - 18:05 Uhr

Wird jetzt per Reflection geladen oder nicht!?

Dann hilft nur noch eins: Debuggen!

Außerdem sollte an der Stelle wo die DLL geladen wird, die innere Exception zumindest gelogged oder ausgegeben werden. Also gewisse Überprüfung wie

TypeLoadException einbauen und irgendwie mitteilen.

Tja, hoffe dass euch noch was einfällt. Ich habe keine Ahnung!

Also Deine Arbeit kann ich nicht tun. Nur helfen.

19.05.2010 - 18:03 Uhr

@Fabian: Dann gehts Dir so wie mir.

Ich könnte euch genügend Beispiele aus unserem Coding-Style Horror geben, der bei uns generiert wird.

Neuester Super-Gau: Alle Compiler und .NET-Runtime Sicherheitsmechanismen wurden abgeschalten. Begründung: Jetzt sind die Fehlermeldungen UND die Fehler weg.

Alles schwarz/weiß gedruckte bei Microsoft und weiteren einschlägigen sehr zuverlässigen Quellen wurde mit einem "Glaub ich nicht" weggewischt.

Tja da sag ich dann nur noch: Kürbis gedeihe. 😉

19.05.2010 - 17:50 Uhr

Bei "TargetInvocationException" kann man meist mit der Inner-Exception etwas anfangen, einfach mal die Exception die angezeigt wird (Im Visual Studio) weiter aufklappen, das sollte normalerweise den Fehler ans Licht bringen.

19.05.2010 - 17:48 Uhr

Dann müsste folgendes oder ähnlich der Fall sein:

Da dann die DLL vermutlich per Reflection geladen wird und dann per string Reflection.GetMethod oder so die Methode gesucht wird, ist vielleicht ein Tippfehler reingekommen?

Falls die verursachende Dll doch nicht per Reflection geladen wird:

Noch eine Alternative: Verweise überprüfen im Visual Studio, entweder einfach einen Doppelklick per Maus oder Verweis rauswerfen und manuell wieder reinsetzen.

Vielleicht verwendet er einen falschen Verweis.

Du kannst auch im Visual Studio auf den Verweis klicken, dann siehst Du im Fenster wo der Verweis genau liegt.

Das ist vorerst alles was mir an Überprüfungsmöglichkeiten einfällt.

19.05.2010 - 17:44 Uhr

Du musst das was die Lesemethoden von Stream ausgeben in einer Datei speichern, fertig.

Also statt

Console.Write(reader.ReadToEnd())

schreibst du

reader.ReadToEnd()

in eine Datei.

als z.B.



string sPath = "Dein Pfad";
string sText = reader.ReadToEnd();
System.IO.File.WriteAllText(sPath, sText);


oder Du benutzt

reader.Read und schreibst alle Bytes.



byte[] aAlleBytes = new byte[länge der Datei bzw. Streamlänge];
string sPath = "Dein Pfad";
reader.Read(aAlleBytes, 0, aAlleBytes.Length);
System.IO.File.WriteAllBytes(sPath, aAlleBytes)

19.05.2010 - 16:33 Uhr

@stud:

Mit Reflector oder ildasm erst mal sehen, ob die Methode wirklich nicht existiert, falls doch liegt ein Programmierfehler vor. Falls diese nicht gefunden wird, hast Du wahrscheinlich das falsche Binary.

Überprüf bitte diese Möglichkeiten und antworte dann ob der Fehler immer noch auftritt.

19.05.2010 - 16:30 Uhr

Hallo Andreas@Tricept.

Was meinst Du mit Expander Knopf?

Ansonsten könntest Du vielleicht mit einer umgewandelten Methode von

DropDownControl

weiterkommen.

Schick mal bitte Screenshot, wie das umgebaute Control aussieht und dann noch einen wie es aussehen soll, dann finden wir eine Lösung.

19.05.2010 - 09:46 Uhr

@gfoidl: Sehr gut. DIESEN kannte ich ausnahmsweise noch nicht. 😃 Super.

18.05.2010 - 14:46 Uhr

@gfoidl: Ich denke dass es nicht um die Triangulation vorrangig geht, sondern um das erstellen der Linienzüge.

IMHO wird der Begriff von Baensch falsch benutzt.

Oder Du konkretisierst ab jetzt Deine Frage genauer, Baensch. 😃

Wir helfen gerne dann weiter.

18.05.2010 - 13:03 Uhr

Wenn es immer "quasi die äußeren Punkte" der Hülle sein sollen, dann nimm den Algorithmus für die konvexe Hülle.

Verbinde dann die Punkte miteinander fertig.

Wenn dem nich so ist, muss Du deinem Programm sagen, welcher Punkt mit welchem verbunden werden soll. Ist es immer ein geschlossener Linienzug kannst Du die Punkte in ein Polygon adden und mit DrawPolygon zeichnen.

18.05.2010 - 12:16 Uhr

Hallo Kollegen.

Ich habe heute morgen schon damit angefangen einige Sequenzen zu identifizieren.
4 davon habe ich jetzt vorausgewählt.

Als Ausgangsbasis werden folgende Softwarekomponenten (DLLs) verwendet:

Komponenten
1.) LowLevelGraphicsLibrary
2.) ImageAcquiring

Eine gültige Erkennung liegt vor, wenn:

Der Bereich eindeutig identifiziert wurde.

Es gibt momentan noch 4 Ansätze:

1.) Ein kombinierter Farbansatz: Rote & Blaue & Gelbe Schilder in einem Schritt erkennen
Danach weitere Filter (noch nicht genau festgelegt, ein paar Experimente mit Blob Filtering und ähnlichem gemacht)

2.) Kantenbasierter Ansatz:

  • Lowpass
  • Highpass
  • Helle Pixel filtern
    Die Ausführung von Lowpass und Highpass in dieser Reihenfolge erstellt einige breitere Kanten

3.) Vor-Filterung in anderem Farbraum oder Channel-Verhältnisse (R/G, G/B, B/R)

4.) LaplaceTransformation und Pixelüberprüfung in den entsprechenden Farben innerhalb der Kanten.

Bisherige Ergebnisse zu jeder Sequenz:

1.) Identifiziert ziemlich gut verschiedene mögliche Verkehrsschildbereiche.
Hier gibt es mehrere Möglichkeiten:

Entweder können die Farbbereiche einzelnen Klassen für die Identifikation der Schilder zugeordnet werden, oder es werden die Bedingungen alle kombiniert und pro Pixel angewendet. Dann erhalten wir ein mehrfarbiges Bild mit allen möglichen Bereichen der Verkehrsschilder.

Vermutlich kann durch zusätzliche Normalisierung mit Schwellwerten eine bessere Erkennung erreicht werden, für eine bessere Identifizierung bei wechselndem Umgebungslicht...

Obwohl dies ein einfacher Farbfilter ist reicht er für die Lokalisierung komplett aus.

2.) Lokalisiert schon ziemlich viele Schilder richtig. Der Hintergrund wird dadurch meist größtenteils ausgeblendet. Es gibt aber Bilder bei denen die Erkennung komplett fehlschlägt.

3.) Liefert auch einige gute Ergebnisse. Hier müssen zuerst die Schwellwerte aufgrund von einigen Bildern vorermittelt werden.

Die Channel-Ratios heben einige Ungleichheiten der Beleuchtung zum Glück aus.

Wenn ein anderer Farbraum verwendet wird, können auch in vielen Bereichen gute Ergebnisse erzielt werden.

4.) hab ich noch nicht genügend ausgewertet. Aber zusammen mit einer speziellen Binarisierung und evl. HysteresisThreshold (wurde jetzt neu integriert in die Lib)
könnte ich mir denken, dass dieses Verfahren ebenso funktioniert.

Alle Möglichkeiten laufen bisher sehr schnell.

Zusatzbemerkung: Der Highpass und Lowpass wurde mit einer Konvolution realisiert. Die implementierten Highpass und Lowpass-Filter in der LowLevelGraphicsLibrary, die das Bild gleichzeitig in ein Graustufenbild umwandeln, sind aktuelle viel zu langsam. Problem ist bekannt.

Wenn alle 4 Möglichkeiten zur Lokalisierung durchgeprüft wurden, wird versucht
die Schilder zu klassifizieren (Erkennung).

Dabei werde ich verschiedene Ansätze wählen:

1.) - Template Matching vermutlich mit "Eigenschildern" (s. Eigenvektor)
2.) - BlobFilterung und Blob-Klassifizierung

Ich denke das die Kombination dieser Möglichkeiten (4 für Lokalisierung, 2 für Detektion) ausreicht um eine vollständige Erkennung zu ermöglichen.

Ob irgendwo noch weitere Filter oder Per-Pixel-Verarbeitungen zwischengeschaltet werden müssen wird sich noch rausstellen.

Alternativ-Test wird sein:

Neuer ObjectExtractor...

für den brauch ich aber noch eine Weile.

Dieser sollte u.U. alleine ausreichen um ein Schild zu erkennen.

17.05.2010 - 16:54 Uhr

Interessant wäre wie sich die verschiedenen Konzepte tatsächlich im Praxistest bewähren...aber das werden wir nicht so einfach herausfinden können...

Sobald ich dazu komme, werde ich auf jeden Fall meinen vorgeschlagenen Test durchführen. Ob Real ein Schild erkannt wird, werde ich vielleicht gleich heute abend ausprobieren. Wollt ihr ein youtube video? 😉

Danach würde dann das Ziel gelten: geschwindigkeit optimieren, so dass sich das ganze auf einem Mobile Device (Handy?) abspielen liesse...

17.05.2010 - 16:43 Uhr

@Gfoidl: Ich denke das was ich vorhin geschrieben habe, werde ich wirklich machen, wenn mein Framework soweit ist.

Um die folgenden 2 Schritte durchführen zu können, ist vermutlich noch eine Kalibrierung der Kamera nötig:

  1. Step) Laptop ins Auto und sehen, ob etwas erkannt wird.
    mit einer Kombination der oben genannten Algorithmen (JunctionDetection, BlobDetection usw. oder wie oben schon genannt evtl. der neue Filter - Kombination aus mehrerer dieser Filter)

  2. Step) Algorithmen evaluieren bzw. Sequenzen identifizieren

Die Videokamera kann aktuell schon mit dem Programm ImageRecognition2 mit beliebigen Filtern angesteuert werden, allerdings momentan nur aus der Entwicklungsumgebung heraus. (EDIT: Grund: hab das Delegate nicht richtig behandelt, Fehler bekannt... 😉

Die Geschwindigkeit reicht auf diesem Laptop locker aus um ein paar Bilder pro Sekunde zu analysieren.

17.05.2010 - 16:13 Uhr

Man kann es aber so aussehen lassen, s. dazu:

DropDownControl

17.05.2010 - 16:08 Uhr

nur mit dem kleinen Unterschied dass nicht nur das Schild erkannt werden soll - bringt ja nicht viel - sondern auch der Zahlenwert auf dem Schild erkannt und verarbeitet werden soll.

Zum Zahlenwert ohne OCR: JunctionDetection und Template Matching sind das Stichwort, sowie Histogramm und BlobDetector. Welche davon wie kombiniert werden müssen (und das müssen diese in diesem Fall sicher teilweise um maximale Geschwindigkeit zu erreichen) kann ich so aus dem Stegreif nicht sagen.

Auf jeden Fall wären Template Matching sowie JunctionDetection alleine Schon mächtig genug um ein "P" (Parkplatzschild) oder z.B. eine "80" (Geschwindigkeitsbeschränkung) zu erkennen.

Außerdem könnte durch eine blockbasierte Bearbeitung noch mehr Geschwindigkeit erreicht werden (quasi das Bild als 1/2 Breite, 1/2 Höhe skaliert betrachten und nachher wieder malnehmen)

Die Erkennung des Verkehrsschildes ist dabei nur der 1. Schritt 😉

Es geht bei Bilderkennung ja immer(!) um die Identifzierung der bestmöglichen (Filter-)Sequenz.

rechenleistung verfrisst es dennoch ohne ende...

DIESER Farbfilter nicht wirklich.

Außerdem liesse sich durch ein ActiveContourTracer der Aufwand noch wesentlich reduzieren, sprich es wird nur noch der Kontour in dem Bereich gefolgt, wo ein Schild gefunden worden sein könnte.

17.05.2010 - 15:49 Uhr

lach @gfoidl & jack30lena,

und wahrscheinlich werde ich das wirklich ausprobieren (noch mehr lachen muss)

Denn meine Verkehrsschildlokalisierung funktioniert ja bestens.

s. dazu auch Bild des folgenden Posts:

(unterster Post)

Bilderkennung von Verkehrszeichen

17.05.2010 - 14:44 Uhr

Somit ist die einfachste Möglichkeit für experimentelle Selbstzwecke:

Laptop ins Auto (zumindest ne halbe Stunde bis 2 Stunden oder so hält der Akku)
und Usb-Cam.

Dann kann man selbst testen. 😉

17.05.2010 - 14:42 Uhr

@gfoidl:

Danke für die konkreten Ausführungen deinerseits.

In den Fällen die ich bisher betrachtet habe, war es noch nie nötig eine 3er Schritt Sequenz á la

1.) 2d->1d Transformation ausführen

2.) explizite 1d Operation ausführen

3.) 1d->2d Rücktransformation ausführen

durchzuführen

Sicher ist aber, wenn ein(!) Vektor benötigt wird, dass man mit entsprechender Programmierung sicher evtl. Geschwindigkeit gewinnen kann. Vor allem unter der Voraussetzung, dass das Bild als 1d Vektor gemerkt, und dann evlt. mehrere Transformationen durchgeführt werden.

Ich habe schon ein paar mal die Unterschiede bei einfachen Filtern untersucht (Laufzeitanalyse).

Entweder fielen diese dann kaum ins Gewicht (nicht über dem Rauschen identifizierbar) weil ich noch keine Transformation hatte bei der dieses immanent wichtig gewesen wäre, oder meine Messungen waren zu wenig und zu ungenau.

Jedenfalls laufen die Filter die ich in meinem Framework komplett fertig getestet habe, schnell genug, um sie in Echtzeit mit einem 640x480 Bild verwenden zu können.

Den langsameren gehts auch noch an den Kragen. 😉

Auf jeden Fall werde ich die Möglichkeit in Betracht ziehen ein Bild als 1d Int/Long/Float Array bearbeiten zu können, diese wird dann integriert werden, wenn sie das 1. Mal unbedingt gebraucht wird (falls weniger Aufwand als 2d)

17.05.2010 - 09:59 Uhr

@Gfoidl

Dann würde es also Deiner Meinung nach Sinn machen, Klassen zu erstellen, mit denen man ein Bild auf diese Weise (in 1d Int-Array, Float-Array usw.) konvertiert bearbeiten zu können.

17.05.2010 - 08:51 Uhr

EDIT: Falls es um die Known Colors gehen sollte, wie z.B. Colors.Black, Colors.White, Colors.Yellow u. ä.


        private static Color[] InitializeKnownColors()
        {
            Array ca = Enum.GetValues(typeof(KnownColor));

            Color[] aColor = new Color[ca.Length];
            int i = 0;
            foreach (KnownColor color in ca)
            {
                aColor[i++] = Color.FromKnownColor(color);
            }
            return aColor;
        }


14.05.2010 - 13:45 Uhr

Um den Beitrag hier zu ergänzen:

Die Lokalisation eines Verkehrsschildes ist sogar wirklich einfach, da einfache Farb- oder Linienfilter genügen.

Aber die weitere Auswertung um das GENAUE SCHILD festzustellen (Ist das Blaue Schild ein Autobahnschild? Ein Gebotsschild? Ein Parkplatzschild mit einem Weißen P?)
ist aufwändiger.

Dafür gibt es mindestens die Möglichkeiten:

1.) - Neuronales Netzwerk
2.) - Auwertung mittels Merkmaldeskriptoren( Schild muß rund sein, ein P muß im runden Schild enthalten sein usw.)
3.) - Stochastische Auswertung (Schild blau, mit ca. 35 weiß in der Blauen Fläche)

14.05.2010 - 13:02 Uhr

Neue Version auf

Work-In-Progress

(oder siehe Link 1. Post in diesem Thread)

Ich habe mich dazu entschieden hier mal wieder eine Version online zu laden.

Es gibt (schon seit Anfang an) einen grundlegenden Konzeptunterschied zu anderen Frameworks im Programm "ImageRecognition2":

Alle Filter können immer benutzt werden, diese liefern dann aber nicht unbedingt ein Ergebnis, d.h. es kann z.B. BinaryDilation für ein Farbbild aufgerufen werden, ohne dieses vorher binarisiert zu haben. Deswegen erhält man aber keine Exception.
Grund: Es wäre ja möglich, dass wir ein teilbinarisiertes Bild haben. Dann funktioniert der Filter normalerweise an den binarisierten Stellen.
IMHO hat man so mehr Freiheit.

Es gibt folgende Änderungen:

Einzelbildbearbeitungsfilter

  • Es wurden wieder einige Filter korrigiert (u.a. MorphologieFilter)

  • Binarisierungsfilter können jetzt mit verschiedenen Farben betrachtet werden
    (z.B. kann bei Close Weiß als Hintergrundfarbe und Schwarz als Vordergrundfarbe betrachtet werden, obwohl das Bild vorher mit Weiß als Vordergrundfarbe

  • Einige kleine Änderungen an den Objektextraktorn

  • Es gibt jetzt einen frei definierbaren Konvolutionsfilter der auch funktioniert

  • SkinningFilter sollte jetzt besser funktionieren

  • ColorBlobExtractor benutzt jetzt "UnsafeBitmap" (schneller)

  • ContourExtractionTwoSteps benutzt keinen Lambda-Filter mehr, viel schneller, da keine Vor-Kompilierung mehr benötigt wird.

  • AnaglyphExtract hinzugefügt

  • AnaglyphFilter aktiviert (funktioniert jetzt)

  • Depthmapcreation für Stereobilder hinzugefügt

  • PerPixelFilter mit Delegate hinzugefügt, dieser kann mit beliebigen einfachen
    delegates initialisiert werden, die Delegate Funktion wird dann auf jedes Pixel angewendet

  • Lipschitz Filter weiter ausprogrammiert

  • SimpleBlobExtractor hinzugefügt (Labelling noch fehlerhaft)

  • WindowedSinc Filter weiter ausprogrammiert

  • Mehr Filter in der Frequenzdomäne vorgesehen

  • ChainCode Filter hinzugefügt

  • Color Filter für jeden Farbraum hinzugefügt

  • Mit UnsafeBitmap.FromImage können jetzt sowohl PGM, PBM als auch PPM, PCX und TIF geladen werden (noch weitestgehend ungetestet)

  • Mit UnsafeBitmap[x,y,channel] kann jetzt ein Pixel gesetzt oder geholt werden (kanalweise)

  • Funktion für den Graudurchschnitt gleichgroßer Bilder in einem Ordner

  • PixelDivision, Addition, Subtraktion, Modulo usw. funktionieren jetzt (auch vom Testinterface Imagerecognition2 aus) ebenso Bool'sche Operatoren wie NAND, NOR, XOR, OR, AND, NOT usw.

Videofilter

  • Videofilter vorgesehen: MotionDetection hinzugefügt

In ImageRecognition2:

  • Im Interface unter dem Menüpunkt Script sind jetzt alle Filter vorhanden
  • Ein paar Funktionen haben eine Maske bekommen á la Photoshop, mit Preview-Funktion
    (Es sind zwar schon für fast alle Filter Masken vorprogrammiert, aber diese sind noch längst nicht alle eingebaut.)
  • Settings werden gespeichert (Open new window after action usw.)

Viele kleine programmatische Änderungen, wie z.B. private Variablen in protected umgeändert und falls gefehlt, Public Properties hinzugefügt wo benötigt

Was ist geplant?

Funktionalität:

  • Bessere Objekterkennungen

  • Backprojections

  • Histogrammfunktionen

  • Bildstatistikfunktionen

  • Klassifizierungsfunktionen

  • Merkmalsdeskriptoren

  • Ein paar komplexe Filter:
    Segmentieren von Menschen in einem Bild (voll gekleidet)

Allgemein:

  • Natürlich weitere Verbesserungen vorhandener Filter gemacht
  • Geschwindigkeitsverbesserungen
  • Erweiterung des Interfaces mit allen Masken für ImageRecognition2

Was ist das allgemeine langfristige Ziel dieses Frameworks:

Es soll sich dem Funktionsumfang von MATLAB Image Processing Toolbox, sowie Halcon immer mehr annähern

Was ist das allgemeine kurzfristige Ziel dieses Frameworks:

Einzelne Probleme die hier gestellt werden beantworten und lösen zu können, im Idealfall ohne Extraprogrammieraufwand, d.h. ausprobieren der Filtersequenz und evtl. Objekt-Extraktor soll ausreichen, um die Informationen zu bekommen die man will.

Und warum gibt es ImageRecognition2, die Oberfläche mit den vielen Menüpunkten?

Manchmal ist es ziemlich schwierig die richtigen Filter und vor allem die richtige Sequenz herauszufinden. ImageRecognition2 soll helfen die Sequenzen herausfinden zu können. Dazu werden viele Masken mit Einstellungen benötigt.

Solange die Masken noch nicht alle existieren können über den Menüpunkt "Window->Script" und den Button "Propertygrid" alle Einstellungen getestet und ausprobiert werden.

Auch für Echtzeitvideobearbeitung gibt es einen Menüpunkt:

Wird der entsprechende Menüpunkt eingeschaltet, wird - falls vorhanden - eine Liste der verfügbaren Devices angezeigt. Dieses kann dann ausgewählt werden. Es erscheint ein Dialog mit 2 Live-Bildern (links original, rechts das Bild auf das der Filter angewendet wird). In der Combobox kann dann der entsprechende Filter ausgewählt werden.

Weiterhin gibt es die Möglichkeiten einstellbare Verzeichnisse zu überwachen, online Flickr, Google pics und weitere Plattformen zu durchsuchen, sowie Screenshots von offenen Fenstern oder Controls über eine Auswahlliste vorzunehmen usw.

In einer späteren Version werden wahrscheinlich auch einzelne Frames von Videos ausgelesen werden können... wir wollen ja schließlich alle Bildquellen nutzen? 😉

13.05.2010 - 21:48 Uhr

Da ich das neulich gebraucht habe, will ich euch das nicht vorenthalten, eine Listbox mit beliebig vielen Controls (auch nebeneinander in einem Item):


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
using System.Drawing;

namespace ImageRecognition2.CustomControls
{
    /// <summary>
    /// 
    /// </summary>
    public class CustomControlListBox : ListBox
    {
        protected bool m_bAutoSizeControls = false;
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomListBox"/> class.
        /// </summary>
        public CustomControlListBox()
            : base()
        {
            DrawMode = DrawMode.OwnerDrawVariable;
            this.BackColor = SystemColors.Control;
            this.DoubleBuffered = true;
        }

        /// <summary>
        /// Gets or sets a value indicating whether [auto size controls].
        /// </summary>
        /// <value><c>true</c> if [auto size controls]; otherwise, <c>false</c>.</value>
        public bool AutoSizeControls
        {
            get { return m_bAutoSizeControls; }
            set { m_bAutoSizeControls = value; }
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.ListBox.MeasureItem"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.MeasureItemEventArgs"/> that contains the event data.</param>
        protected override void OnMeasureItem(MeasureItemEventArgs e)
        {
            if (this.Items.Count == 0) return;
            if (e.Index == -1) return;
            IEnumerable<Control> aControl = GetControlItems(e.Index);

            if (m_bAutoSizeControls)
            {
                int nCount = 0;
                int nCompleteWidth = 0;

                int nMaxControlHeight = -1;

                ListBoxControlItem item = null;
                foreach (Control control in aControl)
                {
                    nCompleteWidth += control.Width;
                    nCount++;
                    if (control.Height > nMaxControlHeight) nMaxControlHeight = control.Height;
                    item = this.Items[e.Index] as ListBoxControlItem;
                    item.CompleteControlWidth = nCompleteWidth;
                    control.Parent = this;
                }
                item.Count = nCount;
                int nWidthOfSingleControl = 0;
                e.ItemHeight = nMaxControlHeight;
                e.ItemWidth = nCompleteWidth;
            }
            else
            {
                foreach (Control control in aControl)
                {
                    control.Parent = this;
                    e.ItemHeight = control.Height;
                    e.ItemWidth = control.Width;
                }
            }
            base.OnMeasureItem(e);
        }

        public void AddItem(ListBoxControlItem item)
        {
            //item.Control.MouseLeave += new EventHandler(this.Control_MouseLeave);
            foreach (Control control in item.Controls)
            {
                if (control is Button)
                {
                    control.MouseClick += new MouseEventHandler(this.CloseForm);
                }
                else if (control is ComboBox)
                {
                    ComboBox cob = (ComboBox)control;
                    cob.SelectedIndexChanged += new EventHandler(this.CloseForm);
                }
                else if (control is TextBox)
                {
                    TextBox tb = (TextBox)control;
                    tb.KeyDown += new KeyEventHandler(tb_KeyDown);
                }
                else if (control is ListBox || control is ListView)
                {
                    ListBox lb = (ListBox)control;
                    lb.MouseDoubleClick += new MouseEventHandler(this.CloseForm);
                }
            }
            this.Items.Add(item);
        }

        /// <summary>
        /// Handles the KeyDown event of the tb control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
        void tb_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return || e.KeyCode == Keys.Enter)
            {
                this.CloseForm(sender, e);
            }
        }

        /// <summary>
        /// Handles the MouseLeave event of the Control control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void Control_MouseLeave(object sender, EventArgs e)
        {
            Form form = (Form)this.Parent;
            if (form != null)
            {
                form.Close();
            }
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.ListBox.DrawItem"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.DrawItemEventArgs"/> that contains the event data.</param>
        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            if (this.Items.Count == 0) return;
            if (e.Index == -1) return;
            Graphics g = e.Graphics;
            g.DrawRectangle(new Pen(Brushes.White), e.Bounds);

            IEnumerable<Control> aControl = GetControlItems(e.Index);

            int nCount = (this.Items[e.Index] as ListBoxControlItem).Count;
            if (m_bAutoSizeControls)
            {
                DrawAutoSizedControls(e, aControl, nCount);
            }
            if (!m_bAutoSizeControls || nCount == 1)
            {
                foreach (Control control in aControl)
                {
                    control.Location = e.Bounds.Location;
                    control.Size = e.Bounds.Size;
                }
            }
            e.DrawFocusRectangle();
            base.OnDrawItem(e);
        }

        /// <summary>
        /// Draws the auto sized controls.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.DrawItemEventArgs"/> instance containing the event data.</param>
        /// <param name="aControl">A control.</param>
        /// <param name="nCount">The n count.</param>
        private void DrawAutoSizedControls(DrawItemEventArgs e, IEnumerable<Control> aControl, int nCount)
        {
            int nCompleteWidth = 0;
            int nWidthOfSingleControl = this.Bounds.Size.Width / nCount;
            if (nCount > 1)
            {
                int nOffset = e.Bounds.Location.X;
                foreach (Control control in aControl)
                {
                    control.Location = new Point(nOffset, e.Bounds.Location.Y);
                    control.Size = new Size(nWidthOfSingleControl - this.Margin.Right, e.Bounds.Height);
                    nOffset += nWidthOfSingleControl;
                }
            }
        }

        /// <summary>
        /// Paints the background of the control.
        /// </summary>
        /// <param name="pevent">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains information about the control to paint.</param>
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            pevent.Graphics.FillRectangle(new SolidBrush(SystemColors.Control), pevent.ClipRectangle);
            base.OnPaintBackground(pevent);
        }

        /// <summary>
        /// Gets the control items.
        /// </summary>
        /// <param name="nIndex">Index of the n.</param>
        /// <returns></returns>
        private IEnumerable<Control> GetControlItems(int nIndex)
        {
            if (nIndex == -1) return null;
            ListBoxControlItem item = (ListBoxControlItem)this.Items[nIndex];
            return item.Controls;
        }

        /// <summary>
        /// Closes the form.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void CloseForm(object sender, EventArgs e)
        {
            ((Form)this.Parent).Hide();
        }
    }
}

Das Bild dazu könnt ihr im Anhang sehen, die Numeric-Updown controls sind hier in der Listbox. Immer 6 Stück nebeneinander.

12.05.2010 - 17:03 Uhr

Ganz andere Möglichkeit noch im Hinblick auf das Command-Pattern


namespace ImageRecognition2.Action
{
    public class ActionDither : AbstractCommand
    {
        private PictureBox m_PictureBox = null;

        public ActionDither(PictureBox _pictureBox)
        {
            m_PictureBox = _pictureBox;
        }

        public override void Run(object sender, EventArgs e)
        {
            Bitmap bitmap = (Bitmap)m_PictureBox.BackgroundImage;
            BaseImageFilter filter = new Dither();
            filter.Execute(bitmap);
            Bitmap bitmapDithered = filter.Bitmap;
            m_PictureBox.BackgroundImage = bitmapDithered;
        }
    }
}

Ist zwar ähnlich, aber nicht gleich - warum nicht? beide Filter erben von einer gemeinsamen BasisFilterKlasse - trotzdem wird der EdgeFilter nur executet, beim Dither aber noch zusätzlich filter.Bitmap abgerufen.?.

Die Run-Methode hat dieselbe Signatur wie ein üblicher Eventhandler, und ich fänds glaub einfacher, den Code auch tatsächlich in einen echten Eventhandler reinzuschreiben, statt des in Form1 gegangenen Umwegs über eine Methode SetEventHandler

C#-Code:


        public void SetEventHandler(ToolStripMenuItem _item, ICommand _icommand)
        {
            _item.Tag = _icommand;
            _item.Enabled = true;
            _item.Click += delegate(object sender, EventArgs e)
            {
                ExecuteAction(_item.Tag,EventArgs.Empty);
                this.pictureBox1.Invalidate();
                Debug.WriteLine(_icommand.Description);
            };
        }

12.05.2010 - 16:52 Uhr

@Marc611:

Es ist ganz wichtig zu wissen:

  • Hast Du mehrere solche aussehenden Teile in einem Bild oder suchst Du nur nach dem inneren Rechteck?

  • Ein Objekt (das was Dich interessiert) gilt bei Objekterkennung als erkannt, wenn man es farblich markieren kann, s. dazu Möglichkeit 3.

  • Was ist der Hintergrund für den Du die Erkennung brauchst?

Wenn Du in einem Bild nur das genau hast, was Du hier hochkopiert hast, funktioniert z.B. folgendes:

  1. Möglichkeit 1:

a) - Farben runden auf Wert von 200
(Dadurch erhältst Du ein Schwarzweißbild ohne die Störungen der JPG-Kompression)

b) - Laplace-Transformation durchführen
(Dadurch erhältst Du ein Kantenbild)

c) - Thresholding durchführen mit einem Schwellenwert von 127 (alles was größer 127 ist als Vordergrundfarbe definieren, alles andere wird dann automatisch zum Hintergrund)

d) - Bild merken und einen Filter durchführen der nur horizontale oder vertikale Linien durchlässt (Faltung per Konvolution)
Kannst Du auch in 2 Schritten machen:

d1) - vorheriges Ausgangsbild Bild kopieren, merken und Horizontale Konvolution für Linien ausführen

d2) - vorheriges Ausgangsbild kopieren, merken und Vertikale Konvolution für Linien durchführen

2.) Möglichkeit, wenn Du alles komplett selbst programmieren möchtest:

  • Farben immer noch auf 200 Runden um die JPG-Artefakte zu entfernen

  • Bild nach horizontalen Linien durchscannen.

  • Bild nach vertikalen Linien durchscannen.

Sehr einfache Methode.

Wenn Du Hilfe beim Linien scannen brauchst, sag Bescheid. Das sind 2 Minischleifen.

Warum funktioniert Methode 2? Weil die anderen Linien diagonal sind. Nur das Rechteck bleibt übrig.

EDIT: 3.) Methode:

  • Farben auch hier auf 200 Runden um die JPG-Artefakte zu entfernen
    (in diesem Fall ist es dann schon schwarzweiß und der Blobextraktor kann angewendet werden)

  • einmal Erosion aufrufen damit das innere Rechteck vom Umgebungsrechteck (äußeres schrägstehendes Rechteck) getrennt wird

  • Blobextraktor benutzen

Ergebnis: s. angehängtes Bild

Da das gesuchte Rechteck gelb markiert wurde, gilt es als erkannt.

P.s.: Wie eingangs gesagt alle Vorschläge gehen davon aus, dass Du nur diese Figur und diese nur einmalig über das ganze Bild verteilt irgendwo hast.

P.P.S.: Ich hab dieses Problem mal mit meinem Programm gelöst. Es geht.

12.05.2010 - 09:49 Uhr

Die Bilder werden bei mir nicht angezeigt.

12.05.2010 - 09:41 Uhr

Ist es möglich, das Immediate Window von Visual Studio in eigenen Anwendungen zu benutzen? So, dass wir in einer unabhängigen Anwendung quasi eine Art Script-Interpreter zur Verfügung haben, der die gleiche Funktionalität bietet?

Hintergrund: Ich möchte die ImageScriptConsole meines GfxFrameworks so anpassen, dass man vielfältiger und viel einfacher damit arbeiten kann.

EDIT: Wenn es nicht möglich sein sollte, werde ich einfach die Console erweitern.

Aber vielleicht weiß ja jemand, OB und wenn ja, WIE das geht.

11.05.2010 - 10:26 Uhr

In vielen Bildverarbeitungsframeworks wie in ImageJ und einigen anderen gibt es Klassen die ein Bild in ein 1D Array überführen können.

Folgende Verarbeitungskette tritt dabei auf:

  1. Bild in 1D Array umwandeln
  2. Bilddaten im 1D Array bearbeiten

evtl. 3a) Bild zurück in ein 2D Array umwandeln
3b) Bild zurück ins ursprüngliche Obekt kopieren

Seht ihr dabei irgendwelche Vorteile, bei NICHT-PER-PIXEL-Filtern?

Dass es Vorteile bringen mag, Bilder in Float/Int/Byte umzuwandeln intern, kann ich mir ja noch vorstellen, aber in ein 1D Array bei nicht PER-PIXEL-Filtern?

Ich hab noch keine Vorteile gesehen.

Übersehe ich da was?

Wer von euch kann mir dazu was sagen?

10.05.2010 - 07:52 Uhr

edit: Code als CSharp-Blöcke markiert

bei uns seit neuestem:

CheckForIllegalCrossThreadCalls = false

(In jedem Form und Control)

und

if (b==true)

wenn ich das wirklich machen muss, werd ich ab jetzt überall (wenn b ein Wert sein sollte) auch schreiben:

if (b > 5 == true) 

usw.

So ein Quatsch.

08.05.2010 - 10:21 Uhr

Hallo Schoizei,

wenn die Umsetzung des FFT - Algorithmus mit komplexen Zahlen der Hinderungsgrund sein sollte:

Opensource Quelle dazu hier:

Ecocortex.DSP - FFT und Complex Number Library

Den Rest musst Du aber trotzdem selbst bewerkstelligen, so wie Herbivore sagt.

Hinweis:

Die Samples in 10ms (oder bei Fourier sollte das immer quadratisch sein, deswegen 2er Potenzen benutzen und wenn nicht möglich den Rest mit 0 auffüllen bis man eine 2er Potenz hat, vielleicht kann das aber auch schon die Lib)

07.05.2010 - 20:04 Uhr

Und falls Du meintest alle Events die gerade gefeuert werden (Der Mechanismus liest übrigens alle Events im aktuellen Klassenobjekt aus, das angegeben wird):

EventLogger / EventSpy

04.05.2010 - 10:27 Uhr

@serial: Was sagt denn der IL-Code wenn Du beide Varianten ansiehst mit ILDasm? Wo sind die Unterschiede?

Beim Timeout: Wird da eine Exception zurückgegeben?

Erhältst Du sonst noch irgendwelche Fehlercodes?

03.05.2010 - 13:18 Uhr

such mal in Google Nach Reflector und GraphViz o. ä.

01.05.2010 - 11:00 Uhr

Ergänzung:

2 andere Möglichkeiten bieten sich

1.) Durch Template Matching. Es wird das Ausgangsbild mit einem konkreten Teilbild gematcht.

Dabei wird in gewisser Weise nichts anderes gemacht als jedes Pixel des Teilbilds mit dem Ausgangsbild zu vergleichen. (Das kann natürlich dann auch über eine Matrix als Konvolution bzw. Faltung passieren.)

Um die Berechnungen zu reduzieren, können auch beide vorher in grau umgewandelt werden. Da ein Kreuz symmetrisch ist (gehen wir davon aus es ist nicht um ein paar Grad verdreht im Bild, sondern ganz gerade) ist möglicherweise dessen Matrix separierbar. Dann reduziert sich der Aufwand nochmals.

2.) Durch ein Teilhistogramm. Man erstellt ein Histogramm des Kreuzes (falls man vorher schon weiß wie es aussieht.) und sucht dann nach diesem Histogramm im Ausgangsbild: Histogram based template matching.

Ein ganz anderer Ansatz wäre noch das Suchen von (geschlossenen) Linienzügen, aber das hier ansatzweisie zu erklären führt zu weit.

26.04.2010 - 15:20 Uhr

@TheGuardian: Siehe auch

P.S.: Auch wenn das ganze schon zwei Jahre her ist, der Vollständigkeit halber.

Linienerkennung in Grauwert Bildern [Uni]

oder auch:

Linienerkennung

EDIT:

Eigener Approach:

1.) Suche im Bild von Links nach Rechts und von oben nach unten kontrastreiche Pixel (d.h. linker und rechter Nachbar haben eine starke Abweichung der Farbdifferenz)

2.) Das so erhaltene Bild durchparsen und die Anfangs- und Endpunkte einer jeweiligen "Linienpunktestrecke" finden lassen.

3.) Die von 2.) erhaltenen Abschnitte per Bresenham-Line matchen lassen.

Wir erhalten dann vom angefangenen Abschnitt in 2.) bis zum ersten Abbruch (Punkt liegt nicht mehr auf der Bresenham-Linie) den 1. Linienabschnitt.

Der Abbruchpunkt (letzter Punkt auf der Original Linienestrecke der mit der 1. gefundenen Bresenham Linie übereinstimmt)
kann wieder als neuer Aufpunkt für einen Teilabschnitt von 2.) verwendet werden.

Wenn fertig, nächste Linie suchen.

P.S.: zwischen 2 und 3 sind ziemlich viele Abwandlungen des Algorithmus möglich.

23.04.2010 - 20:30 Uhr

s. auch ProFormX
und von dort GfxFramework für die Initialisierung.

23.04.2010 - 11:24 Uhr

@ErfinderDesRades:

ich möchte controls (buttons, labels, etc) auf den bildschirm zeichnen

IMHO geht es also wirklich Tempelbauer um das zeichnen auf den Desktop, nicht um das Hinzufügen bzw. Lösen von Controls um es dem Desktop hinzuzufügen.

23.04.2010 - 09:48 Uhr

Ohne Form heißt direkt auf den Desktop?

Wenn ja, dann siehe u.a.:

Über ein Applikationsfenster "schreiben"

so wie:

Button Renderere Klasse u. ä.

als auch:

Über Form und Controls zeichen (Overlay).

22.04.2010 - 12:55 Uhr

@Mossi:

Habs mir nicht genauer angesehen, aber vielleicht hilft das ja weiter:

Alle verfügbaren Kulturen [dotnetsnippets]