Laden...

LowLevelGraphicsLibrary

Letzter Beitrag vor 10 Jahren 80 Posts 129.569 Views
LowLevelGraphicsLibrary

EDIT: 28.01.2014:

**Ich bin jetzt den Schritt gegangen und habe das Projekt auf

https://imagerecognition2.codeplex.com/

gehostet.**++

EDIT 26.04.2012:

Lange nicht alle Menüpunkte funktionieren und das Rechteck das man mit der Maus aufziehen kann hat momentan auch keine Funktion... aber alles im entwickeln

Die wichtigsten Funktionen und Kürzel:

Fenster
CTLR-N -> neues Fenster aufmachen
STRG-ALT-C -> Fenster kaskadieren
STRG-ALT-H -> Horizontal anordnen
STRG-ALT-V -> Vertikal anordnen
New Window (open copy) -> vom aktuellen Fenster aus eine Kopie in einem neuen Fenster erstellen
New Window (last loaded) -> neues Fenster mit dem zuletzt geladenen Bild

Filter
CTRL-F -> Filter ausführen

Windows->Script:

Filter ausführen (oberer Execute-button)
hier auch Kanal auswählen, A,R,G,B, Mask (unterer Execute-button)

Oder direkt im Menü entsprechenden Filter auswählen

Lambdaausdrücke:
Oben im Filter eingeben oder aus Combobox auswählen

Menüpunkt Windows->Script: Script ausführen....

Bilder verknüpfen/Contextmenü oder Toolleiste:
Bilder im Fenster aus Childwindowliste auswählen...

**EDIT: 17.01.2012

Hier gibt's ab jetzt kleine Tutorials usw. über diese Library:

http://lowlevelgraphicslibrary.blogspot.com/

**EDIT: 22.04.2010
Als Dateianhang am Ende dieses Beitrags verfügbar.

Es wird immer mal wieder von mir ein Testprojekt hochgeladen, aber das wird nicht explizit hier jedesmal vermerkt. **

EDIT: Prerelease Versionen gibt es immer - wenn vorhanden - hier:

Anmerkung: Ich behalte mir vor, die Datei umzubenennen oder herauszunehmen.

Der Code kann jetzt hier
heruntergeladen werden (s. Ende dieses Posts).

Achtung: Das Projekt ist noch nicht gegen Fehler getestet.

Zudem hat die Basis Klasse das Interface IFilter bekommen.

Dieses wird beinhalten:

  • Steps (Quasi Pixel in X-Richtung und Y-Richtung überspringen)
  • Rectangle (Ausschnitt auswählen, auf den der Filter angewendet werden kann)
  • einige grundlegende Funktionen wie in der System.Drawing.Bitmaps-Klasse z.B. Height / Width, GetPixel / SetPixel

Was schon drin ist:

**Einige Experimentelle Filter: **

  • Neue Filter, z.B. Background-Estimation

  • Farben runden

  • Segmentierungen

  • Colorspaces, Umrechnungen von RGB in verschiedene Farbräume und zurück u.a.
    YUV, YCbCr, HCL, HSV, XYZ, CIELUV, CIELAB usw.

  • verschiedene Kantenfilter und ein neuer Konturfilter

  • verschiedene rudimentäre Segmentierungsfilter.

  • Viele statische RGB-Funktionen unter ColorFunctions wie z.B. Summe der Channels,
    MaxChannel, MinChannel, Channels vertauschen per String z.B. mach BGG oder RBG oder BGR aus Original RGB, Channel-Ratio,
    usw. alle diese Funktionen sind in ColorFunctions ausprogrammiert.

  • BitmapFunctions-Klasse um ein Bild auf verschiedene Arten z.B. in einen Stream oder Byte-Array und wieder zurück umzuwandeln, zu resizen und zu rotieren.

Einen Filter benutzen:

Bitmap bitmap = (Bitmap)Image.FromFile("blub.jpg");
IFilter filter = new GrayScale();
filter.Execute(bitmap);

Die erste Zeile lädt das Bild,
die 2. Zeile instantiiert den Filter.
Dann wird der Filter angewendet

Zur Ausführung gibt es 3 Möglichkeiten:

1.) void Execute(bitmapSource);
Führt den Filter aus und bitmapSource enthält die neuen - veränderten - Informationen

2.) Bitmap ExecuteCloned(bitmapSource);
Führt den Filter geclont aus, d.h. bitmapSource wird nicht verändert, und die veränderte Bitmap wird zurückgegeben.

3.) void ExecuteMasked(bitmapSource, bitmapMask);
Führt den Filter aus und er wird nur an den Stellen angewendet in dem im Maskenbild weiße Pixel sind.

EDIT:

Als nächstes gibt es dann noch die Möglichkeiten:

4.) ExecuteChannelled

Für jeden Kanal kann angegegeben werden, ob das Ergebnis übernommen wird.

5.) ExecuteMaskedChannelled

Für jeden Kanal kann in Bezug auf die Maske angegeben werden, ob das Ergebnis übernommen wird.

EDIT: 4. und 5 sind jetzt implementiert.

Abkürzung des obigen Codes:

new GrayScale().Execute(bitmapSource); //Bild in Grau umwandeln.

Es gibt bisher ( mind.) folgende

Filterkategorien:

  • Farb-filter
  • Konvolutions-Filter
  • Morphologie-Filter
  • Histogramm-Filter
  • Kanten-Filter
  • Ecken-Filter
  • Frequenz-Filter
  • Binarisierungs-Filter (Thresholding)
  • Kontur-Filter
  • Korrektur-Filter
  • Korrelations-Filter
  • Deplatzierungs-Filter
  • Segmentierungs-Filter
  • Makro-Filter
  • Textur-Filter
  • Mathematische Filter (algebraisch, logisch)

Über ein UnsafeBitmap Objekt kann auf einfache und schnelle Weise auf ein Bitmap zugegriffen und es verändert werden:


UnsafeBitmap bitmap = new UnsafeBitmap(_bitmapSource);
//hier die Veränderungen durchführen
bitmap.Dispose(); //Und dann unbedingt Dispose aufrufen, um den Lock wieder freizugeben.

UnsafeBitmap bekommt als Eingang die originale Bitmap übergeben.
Dann wird intern alles durchgeführt um Unsafe auf die Bitmap zugreifen zu können.
Von außen sieht es aber aus, als würden wir ganz normal zugreifen.


            List<Color> m_aColor = new List<Color>();
            m_aColor.Add(Color.FromArgb(255,255,255));

            UnsafeBitmap bitmap = new UnsafeBitmap(_bitmap);
            for (int y = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    Color color = bitmap.GetPixel(x, y);
                    if (!m_aColor.Contains(color))
                    {
                        bitmap.SetPixel(x, y, m_ColorToReplaceWith);
                    }
                }
            }
            bitmap.Dispose();

ImageRecognition2.rar (3 MB, 42 mal heruntergeladen)

Hinweise:
Was tut sich aktuell?

EDIT: 15.03.2012

Aktuell geht es um alles fürs Vermessen und die Erkennung von Bildern, was eingebaut wird.

  • Neuronale Netzwerke
  • Snakes / Active Contours

3D:

  • Parität / Depthmap
  • Stereo: Anaglyph / Interlaced / 3d-Modellschätzung

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Ganz nett, aber man könnte die Lib noch etwas mehr in Richtung OO bringen. Alle Filter sind einfache statische Funktionen. Kann es sein, dass du die aus einer ehemaligen C Library konvertiert hast?
Die Filter könnte man übrigens prima als Plugin in Paint.NET integrieren 😉 http://www.eecs.wsu.edu/paint.net/

I am Jack's smirking revenge.
I am Jack's raging bile duct.
I am Jack's cold sweat.
I am Jack's complete lack of surprise.
I am Jack's broken heart.
I am Jack's wasted life.

Klingt nach einer Menge Arbeit! Super das du das beisteuerst!

irgendwie mekkert #Develop rum, wenn ich versuche den kram zu Kompilieren:

PFAD\cImageFilters.cs(35,4): error CS0227: Nicht gesicherter Code wird nur angezeigt, wenn mit '/unsafe' kompiliert wird

Das kommt überall da vor wo mit unsafe {} gearbeitet wurde.
Beim Kompilieren wird nur die .manifest Datei erstellt.
Wie kann ich das Lösen?

Du musst in den Projekt Einstellungen Unsafe Code zulassen

Wir Arbeiten eigendlich nicht wir nehmen nur das geld

ok, sorry, da hab ich ja auch schon geguckt, ich hab die Option nur übersehen... 😁

Hallo!

Die Komponente gefällt mir sehr gut, Kompliment!
Kurze Frage von einem Nicht-Experten in Sachen Bildbearbeitung:
Gibt es bzgl. der abgefragten Werte z.B. für Helligkeit, Kontrast, Gamma, ... bestimmte Grenzwerte?

EDIT: OK, lässt sich im Quellcode ablesen (0..255).

Nobody is perfect. I'm sad, i'm not nobody 🙁

Hallo!

Nächste Frage:
Wo ist der Unterschied zwischen cGraphics.cs und cImageFilters.cs (ist eine davon schneller oder genauer)?

Nobody is perfect. I'm sad, i'm not nobody 🙁

Ist das Beispielprojekt [im neuen Download] iwie flötengegangen?
Bei mir findet sich nur ein Project, und zwar ganz ohne Property-Ordner - wo issn nun niedergelegt, dasses eine Dll ist, weil kommt beim Start schon die Fehlermeldung "Klassenbibliotheks-Projekt kann nicht StartProjekt sein"

Nee, flötengegangen auch nicht, verschiedene Forms sind ja noch vorhanden.
Also iwie ein unvollständiger Upload?

Der frühe Apfel fängt den Wurm.

@ErfinderDesRades:

EDIT 18.12.2009: Das komplette Projekt kann im 1. Thread heruntergeladen werden.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Ohne Beispielprojekt findich schade, weil willichmal einen Blick reinwerfen, mussich erstmal iwas proggen, dassich ühaupt was zu sehen kriege.
Habich jetzt ja gemacht, und noch folgendes gefunden:

CGraphics scheint versehentlich dringeblieben, weil die Arbeit scheint ja CImageFilters zu machen.
Von den Forms ist nur FormMain im Designer darstellbar, allen anderen melden: "Method 'System.Windows.Forms.Form.CenterToParent' not found."
Bei vielen Filtern kommt ein Eingabefenster "Value eingeben", da kann man dann einen Value eingeben - nirgends ein Hinweis, was der Value bewirkt.

Und dass das Projekt keine Properties hat, scheint mir, wie gesagt, an einem fehlerhaften Upload zu liegen, odr?

Der frühe Apfel fängt den Wurm.

EDIT 18.12.2009:

Das Projekt wird immer hier im 1. Post dieses Threads hochgeladen.
Es ist aber immer noch kein endgültiges Release angesagt.

Ich stelle einfach hier die Prerelease-Versionen zur Verfügung.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Neuer Mechanismus

Preview:

Wie im angehängten Bild zu sehen, können beim nächsten Upload auch farbige Blobs anhand der Rechtecke ermittelt werden.

Bildanalyse:

Mit einem "JOIN" können Rechtecke ähnlicher Farben zu größeren Rechtecken verschmolzen werden.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Hier noch zum Vergleich das Originalbild:

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Preview Applikation

Hier gibt's jetzt die Preview Applikation.

Der Code ist noch nicht gecleant und viele Filter sind noch mit Bitmap.SetPixel GetPixel implementiert und deswegen langsam.

Es ist eben noch ein Entwicklungsprojekt. Aber solange kann jeder ja mal damit rumspielen.

Z.B. wird die Klasse ImageFilters noch in LowLevelGraphicsLibrary wandern, ebenso wie die Blobs usw.

EDIT: Graue Funktionen sind momentan nicht aktiviert/implementiert...

EDIT: Download s. oberster Post.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Hier ein Screenshot dazu:

Screenshot1.jpg

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

[EDIT] 18.12.2009:

  • Viele neue Filter, z.B. Segmentierung
  • Color-Blob-Extraktor mit neuem Verfahren
  • ColorSpaces, Umrechnung von RGB in andere Farbräume...
  • RGB-Funktionen (z.B. Abfrage auf RGB-Range, Maxchannel, Minchannel usw.)

Einfach dazu das Projekt im ersten Post dieses Threads herunterladen.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Ich muss dir ein großes Kompliment machen, die Bibliothek ist einfach genial 😃

@MagicAndre1981: Dankeschön. Das ist ein super Kompliment und erfreut mich ungemein. Läuft runter wie Öl. verneig 😃

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Habe heute ein erstes Prerelease veröffentlicht. Damit man sich den Code schon mal anschauen kann. Und nein, der Code bleibt nicht so. An vielen Stellen wird es noch Änderungen und Optimierungen geben.

Die Syntax der Filter bleibt so.

Es wird noch ein ExecuteCloned hinzukommen, bei dem man das bearbeitete Bitmap als Ergebnis erhalten wird und das Original-Bild bleibt dabei wie es ist.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Ihr dürft aber gerne schon Rückmeldungen geben, vielleicht fehlt euch noch ein Filter oder ihr habt grundsätzliche Fehler entdeckt, ich werde die Vorschläge aufnehmen, prüfen und falls sinnvoll ggf. berücksichtigen.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Die Beschreibung der Filter werde ich heute noch hier online stellen:

[EDIT] die erste Anleitung ließ sich nicht online laden, deshalb bis ich wieder dazu komme wird es noch wohl eine Weile dauern.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Neues Prerelease hochgeladen. s. ganz oben, 1. Post in diesem Thread.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Neues Prerelease erstellt.

Unter anderem funktionieren jetzt:

  • Houghtransform
  • Moravec
  • ZeroCrossing
  • AdaptiveThresholding

Funtionen in ColorFunctions:

u.a.

  • Mul(Color, Color)
  • Sub (Color, Color)
  • Div(Color, Color)

EDIT: noch nicht hochgeladen

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Neue Version hochgeladen.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Hm sieht ganz interessant aus. Muss ich mir mal anschauen.

PS: Ich suche noch nach einer Funktion die weiße Ränder an Grafiken entfernen kann falls dir da was einfallen sollte 😉

@HeRaider: So eine Funktion gibt es eigentlich schon. Benutze (ab der nächsten Version) Autocrop. Und übergebe Autocrop die Bedingung.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Die Bibliothek ist eigentlich ausgelegt für Stills (Einzelbilder), nicht für Videobearbeitung

  • Viele kleine Korrekturen (Fehlende Konstruktoren, Falsche Berechnungen, fehlende Benutzung von UnsafeBitmap und dazugehöriges UnsafeBitmap.Dispose() an manchen Stellen )

  • Autocrop ist jetzt rudimentär implementiert, kann benutzt werden.
    Funktioniert fürs erste IMHO relativ gut.

  • Korrektur von Umrechnungen für Farbmodelle und redundante Farbmodelle entfernt

  • Alle vorgesehenen Filter zum Funktionieren gebracht

  • Objektextraktor begonnen

Es gibt jetzt im wesentlichen 4 Komponentenarten:

  • Extractors (Klassen um bestimmte Features/Objekt usw. zu extrahieren)
  • Colorspaces (Farbräume)
  • Filter (z.B. Farbfilter-, Morphologie-, Kanten-, Eck-Filter usw.)
  • Histogramm und Statistikfunktionen

(- sowie Hilfsfunktionen (BitmapFunctions, ColorFunctions))

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Hi!

als ich vor längerer Zeit mal reingeguckt hab, fandich das mit den Filtern suboptimal - für jeden Filter eine eigene klasse.
Dabei sind die meisten Filter ja ConvolutionFilter, nur je mit verschiedenen Parametern.
Das kann man wesentlich vereinfachen, indem man einen ConvolutionFilter schreibt, und den mit verschiedenen Parametern aufruft.

Ich hab sowas mal gemacht, da habich die verschiedenen Parameter in einer DataTable zusammengefasst., und User kann wählen.
Das hat den lustigen NebenEffekt, der User kann seine eigenen Filter erfinden, indem er der DataTable weitere Datensätze zufügt.
gugge Convolution-Filter

Der frühe Apfel fängt den Wurm.

@ErfinderDesRades:

Das ist nicht mehr so, dass die meisten Filter Convolution-Filter sind.

Außerdem werde ich einige Filter sowieso zusammenfassen (Es macht z.B. keinen Sinn einen Filter Contours und einen Contours-Filter zu haben.)

Außerdem sind die Filter von BaseImageFilter abgeleitet und haben die eigene Schnittstelle IFilter. So kann also jeder seinen eigenen Filter kreieren und hinzufügen.

Außerdem veröffentliche ich hier einfach die Fortschritte damit jeder damit arbeiten kann.

z.B. gibt es auch noch keine sinnvolle Namespace-Aufteilung, die IMHO aber inzwischen nötig ist. z.B. in Convolution, Morphology, Color usw.

Bis dahin. 😉 Viel Spass damit.

Probiers doch einfach mal aus.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

du hast geschrieben das du eine gekürzte version hier online gestellt hast. gibt es eine möglichkeit die volle version der library zu bekommen? ich finde das projekt super und würde die lib gerne in mein projekt einbetten.

grüße viperneo

Nach Weihnachten, werde ich diese Version veröffentlichen:

Dann können einige dieser Extraktoren benutzt werden.

  • **Impainter: **kann benutzt werden, um ein Bild zu restaurieren

  • **Freistellungstool: **kann benutzt werden, um Bereiche eines Bildes über eine Maske freizustellen

  • **AutoCrop: **Wird benutzt, um ein Bild vollautomisch auszuschneiden (unwichtige Bereiche werden abgeschnitten)

Bei Vorschau wird ein rotes Rechteck in das Bild eingeblendet.

  • **Color-Blob-Extraktor: **Schon bekannt von dem Knopf links unten. 😉

  • Objekt-Extraktor: Das Herzstück des Projekts (deswegen hab ich eigentlich mal das ganze angefangen in dieser Dimension auszuarbeiten)

Wenn der Objekt-Extraktor RICHTIG(!) funktioniert können in einem beliebigen Bild,
mittels des angewendeten von mir entwickelten One-Pass-Verfahrens, Objekte vollautomatisch extrahiert werden.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Tolle Funktionen... einige sind ja so auch in der AForge drinne von CodeProject.

Du solltest vielleicht auch ein SVN anlegen für neue Versionen. Wenn zum Beispiel die Funktionen geupdated werden mit und die SetPixel und GetPixel weg sind.

Gruß,
Digi333

ich krittel mal ein bischen herum.
zunächst die Test-Anwendung: ich finde, man bräuchte was, wo man vorher und nachher nebeneinander vergleichen kann, vlt sogar Tabpages, wo man verschiedene Filter-Ausgaben durchblättern kann.
Und das bei der Ausgabe angegeben ist, was man eingegeben hat, am liebsten was mit Abspeichern.
also ich jedenfalls hab nach 3 Sekunden vergessen, welches MenuItem ich geklickst hatte, und was in die EingabeMaske eingegeben.

Ich hab grad angemacht, ein Bild geladen, und dann mal bei den Filtern Binarisierung-BarCode geklickst, was immer das sein mag, darüber hoffte ich ja was zu erfahren.
Da geht ein Dialog auf, da soll ich einen Grenzwert eingeben, und checken (oder nicht), ob "nur diesen grenzwert".

Damit kann ich überhaupt nichts anfangen, was denn für ein Grenzwert?
habich 142 eingegeben.
Dann steht die Anwendung, und nach ca. 10s kommt ein schwarzweiß-Bild, bei dem scheinbar die Graustufen entfernt sind.
Vermutlich ist das die Binarisierung, dasses nurnoch schwarz-weiß gibt, aber warum Barcode? - na, so heißt es eben.

Nächster Test: Binarisierung-treshold MinMax - da muß man keinen Grenzwert angeben, aber die Anwendung steht für 20s.

Dafür gibts dann aber eine Ausgabe, bei der das Bild viel besser wieder zu erkennen ist - ein wirklich interessanter Filter. Blos wie gesagt - ich kann die Ausgabe nicht mit der Eingabe vergleichen, das ist schade.

Guck ich mal in den Code, da sehe ich gleich, warum das immer so lange steht: ist voll mit GetPixel und SetPixel. Wo ich denken täte, in etwas, was sich "LowLevel..." nennt, haben die nix verloren.
Man kann doch sicherlich alle Bildformate nach 24RGB umwandeln (bei Transparenz-Unterstützung 32ARGB), die Bitmap locken, und auf einem Array mit den Farbwerten arbeiten. Für 24RGB habich das mal selbst gemacht, und habe den Scan-Pointer in ein 2-dim ArbeitsArray kopiert, da kann man dann direkt mit x und y auf jeden Farbwert jedes Pixels zugreifen. Ich müsste mal probieren, ob mans nicht sogar in ein 3-dim Array bekommt, dann könnte man RGB quasi als Z-Achse auffassen.
Etwas, was danach aussieht, ist ja enthalten "UnsafeBitmap", nur wird es scheinbar nicht verwendet.

Als nächstes hab ich in die Convolutions geguckt, und scheint doch immer noch so, dass für jeden Filter eine eigene Klasse gebaut ist, dabei ist es immer derselbe Filter, nur mit verschieden beschickter 3*3-Matrix.
Sowas kann man doch variabel programmieren, dass im Button-Handler dann die Matrix beschickt wird, nicht für jeden filter eine extra-Klasse.

Einige Convolutions gehen dann auch wieder andere Wege, "SimpleConvolution" zB. wendet Bitmap-Locking an, und greift auf die Farbwerte direkt zu, aber eben ohne die "UnsafeBitmap" zu verwenden, wozu ist die denn nun eiglich da?

Oder im Ordner "Edges" guck ich den ersten an, da ist der Code komplett auskommentiert.
Und im 2. Edges-Filter, namens "Compass" findet sich wieder etwas, was sehr nach Convolution-Filter aussieht, allerdings sind es 688 Zeilen, die sich endlos wiederholen, und Get/SetPixel ist wieder dabei.
Zu Get/SetPixel habich mich schon geäußert, nun, solche "Compass"-Code-Wiederholungs-Wüsten sollte man aber auch unbedingt parametrisieren, also dass am Ende ein Algo mit geeigneten Parametern beschickt wird, anstatt für jede Variante den gleichen Algo re-implementieren.

In Corners.Moravec fund ich diese Minimum-Funktion:



        private int Min(int x, int y, int[,,] aSum)
        {
            int[] aInt = new int[8];
            for (int i = 0; i < 8;i++ )
            {
                aInt[i] = aSum[x,y,i];
            }
            Array.Sort(aInt);
            return aInt[0];
        }

Verstehe ich das richtig, dass alle 8 Werte in ein int-Array geschrieben werden, dieses sortiert, und dann das oberste Element zurückgegeben? - isnichdeinErnst, odr?

Das mit den BarCodes habichjetzt auch nochmal nachgeguckt



        public override void Execute(Bitmap _bitmap) {
           Bitmap bitmap = _bitmap;
           List<Color> aColor = new List<Color>();
           int y = 0;
           int x = 0;

           int nCount = 0;
           aColor.Add(bitmap.GetPixel(x, y));
           aColor.Add(bitmap.GetPixel(x, y));
           nCount++;

           Color colorToSet = Color.Transparent;
           for(y = 0; y < bitmap.Height; y++) {
              for(x = 0; x < bitmap.Width; x++) {
                 List<Color> aColorLine = new List<Color>();
                 Color color = bitmap.GetPixel(x, y);
                 aColor.Add(color);
                 aColorLine.Add(color);
                 Color colorPrev = aColor[nCount - 1];
                 Color colorCurrent = aColor[nCount];

                 Color colorAvg = ColorFunctions.AverageColor(aColorLine);
                 int nRGBSum = ColorFunctions.RGBChannelSum(colorAvg);
                 if(bOnlyThreshold) {
                    if(nRGBSum == nThreshold) {
                       colorToSet = Color.White;
                       aColorLine.Clear();
                    } else {
                       colorToSet = Color.Black;
                    }
                 } else {
                    if(nRGBSum > nThreshold) {
                       colorToSet = Color.White;
                       aColorLine.Clear();
                    } else {
                       colorToSet = Color.Black;
                    }
                 }
                 bitmap.SetPixel(x, y, colorToSet);
                 nCount++;
              }
           }
        }

Interessant.
Da wird von den bisher durchlaufenen Pixeln ein Durchschnittspixel gebildet, und wenn die Summe der Farbwerte des Durchschnittspixels den Schwellwert (Threshold) überschreitet, wird weiß gesetzt, und die Liste der durchlaufenen Pixel gelöscht. (Ich hoffe, richtig verstanden zu haben, bischen Kommentation wäre nicht schlecht).
Welche Funktion hat aber die zweite Liste, "aColor"?

Forms.FormConvolution kann unnötigerweise im Designer nicht geöffnet werden. Das liegt am Aufruf von

         this.CenterToParent();

innerhalb von InitializeComponent(), wohl weil der Designer .CenterToParent() nicht ausführen kann.
Jedenfalls eine Verlegung des Aufrufes in den Konstruktor, nach InitializeComponent() schafft Abhilfe.

Was hat es mit diesem Interface auf sich?


    public interface ICommand
    {
        string Description { get; set; }
        object Owner { get; set; }
        void Run(object sender, EventArgs e);
    }

Description: wird im ganzen Code nirgends gesetzt
Owner: desgleichen
Run: Was sollen die Argumente sender und e? Die werden zwar übergeben, aber nirgends dann auch verwendet - ich wüsste auch nicht, was ein filter mit einem toolstripMenuItem anfangen sollte, und e ist immer empty.

Auch die vielen Actions verstehe ich nicht. ist auch immer wieder ganz ähnlicher Code


namespace ImageRecognition2.Action
{
    class ActionEdge : AbstractCommand
    {
        protected PictureBox m_PictureBox = null;
        private short m_shType = -1;

        public ActionEdge(PictureBox _pictureBox, short _shType)
        {
            m_PictureBox = _pictureBox;
            m_shType = _shType;
        }

        public override void Run(object sender, EventArgs e)
        {
            FormParameter parameter = new FormParameter();
            if (parameter.ShowDialog() == DialogResult.OK)
            {
                Bitmap bitmap = (Bitmap)m_PictureBox.BackgroundImage;
                new EdgeDetectConvolution(m_shType, (byte)parameter.nValue).Execute(bitmap);
            }
        }    
    }
}

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


        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);
            };
        }

Also, ich mach Schluß für heut, hofflich habich dich nicht zu sehr geärgert.

Der frühe Apfel fängt den Wurm.

ja, geht tatsächlich, die BitmapScan als 3-dim - Pointer aufzufassen. Wenn man dann die Matrix als 2-dim Array auffasst, ergibt sich z.B. ein sehr übersichtlicher Convolution-Filter, ich habs leider nur in VB



   Private Sub ApplyCurrentFilter()
      'Über jedes Pixel wird eine 3*3-Gewichtungs-Matrix gelegt, die darunter liegenden Werte
      '! gewichtet aufsummiert. Die Gesamtsumme wird durch den Divisor geteilt, um den
      '! Durchschnitts-Wert wieder herzustellen. 
      'Heben sich positive und negative Gewichtungen auf (Summe der Matrix = 0) so wird die
      '! Durchschnitts-Helligkeit des Bildes gewährleistet durch Addition eines Offsets von 127.
      If FilterBindingSource.Position < 0 Then Return
      Dim Filter As FilterRow = GetRow(Of FilterRow)(Me.FilterBindingSource.Current)
      Dim Img As Image = DirectCast(cmbSourcePic.SelectedValue, Image)
      Dim Helper As New PixelHelper(Img, PixelFormat.Format24bppRgb, ckGray.Checked)
      'Filter-Daten
      Dim Matrix As SByte(,) = Me.UclMatrixGrid1.GetMatrix
      Dim Offset As Short = Filter.Offset
      Dim Divisor As Single = Filter.Divisor
      '3-dim Pixel-Arrays
      Dim ReadPixels As Byte(,,) = Helper.ReadPixels
      Dim WritePixels As Byte(,,) = Helper.CreateWritePixels(PixelFormat.Format24bppRgb)
      Dim YUbound As Integer = Img.Height - 1
      Dim XUbound As Integer = Img.Width - 1
      'die Hauptschleife läßt die Ränder aus, da die Anwendung der Matrix auf Randpixel
      '! zu Array-Überschreitungen führt (s. Start- und End-Werte von Y, X).
      For Y As Integer = 1 To YUbound - 1
         For X As Integer = 1 To XUbound - 1
            For Z As Integer = 0 To 2 'auf der "Z-Achse" liegen die 3 Farbwerte 
               Dim WeightedSum As Double = 0
               For mtrY As Integer = 0 To 2
                  For mtrX As Integer = 0 To 2
                     Dim rpY As Integer = Y + mtrY - 1
                     Dim rpX As Integer = X + mtrX - 1
                     ' rpY, rpX, die Indizees der ReadPixel, beinhalten den Offset des Matrix-Punktes,
                     '°der grad abgefragt wird
                     WeightedSum += ReadPixels(rpY, rpX, Z) * Matrix(mtrY, mtrX)
                  Next
               Next
               WeightedSum = ClipBetween(0.0, WeightedSum / Divisor + Offset, 255.0)
               WritePixels(Y, X, Z) = CByte(WeightedSum)
            Next
         Next
      Next
      'BackgroundImage austauschen - der PixelHelper erstellt aus den WritePixels die Bitmap
      ExchangeDisposable(Me.SplitContainer1.Panel2.BackgroundImage, Helper.GetResultBitmap)
   End Sub

  • aus LowLevelGraphics.Filter.Convolution3x3


        public override void Execute(Bitmap _bitmap) {
           Bitmap b = _bitmap;
           // Avoid divide by zero errors
           if(0 == m_ConvolutionMatrix.Factor) return;

           Bitmap bSrc = (Bitmap)b.Clone();

           // GDI+ still lies to us - the return format is BGR, NOT RGB.
           BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
           BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

           int stride = bmData.Stride;
           int stride2 = stride * 2;
           IntPtr Scan0 = bmData.Scan0;
           IntPtr SrcScan0 = bmSrc.Scan0;

           unsafe {
              byte* p = (byte*)(void*)Scan0;
              byte* pSrc = (byte*)(void*)SrcScan0;

              int nOffset = stride - b.Width * 3;
              int nWidth = b.Width - 2;
              int nHeight = b.Height - 2;

              int nPixel;

              for(int y = 0; y < nHeight; ++y) {
                 for(int x = 0; x < nWidth; ++x) {
                    nPixel = ((((pSrc[2] * m_ConvolutionMatrix.TopLeft) + (pSrc[5] * m_ConvolutionMatrix.TopMid) + (pSrc[8] * m_ConvolutionMatrix.TopRight) +
                       (pSrc[2 + stride] * m_ConvolutionMatrix.MidLeft) + (pSrc[5 + stride] * m_ConvolutionMatrix.Pixel) + (pSrc[8 + stride] * m_ConvolutionMatrix.MidRight) +
                       (pSrc[2 + stride2] * m_ConvolutionMatrix.BottomLeft) + (pSrc[5 + stride2] * m_ConvolutionMatrix.BottomMid) + (pSrc[8 + stride2] * m_ConvolutionMatrix.BottomRight)) / m_ConvolutionMatrix.Factor) + m_ConvolutionMatrix.Offset);

                    if(nPixel < 0) nPixel = 0;
                    if(nPixel > 255) nPixel = 255;

                    p[5 + stride] = (byte)nPixel;

                    nPixel = ((((pSrc[1] * m_ConvolutionMatrix.TopLeft) + (pSrc[4] * m_ConvolutionMatrix.TopMid) + (pSrc[7] * m_ConvolutionMatrix.TopRight) +
                       (pSrc[1 + stride] * m_ConvolutionMatrix.MidLeft) + (pSrc[4 + stride] * m_ConvolutionMatrix.Pixel) + (pSrc[7 + stride] * m_ConvolutionMatrix.MidRight) +
                       (pSrc[1 + stride2] * m_ConvolutionMatrix.BottomLeft) + (pSrc[4 + stride2] * m_ConvolutionMatrix.BottomMid) + (pSrc[7 + stride2] * m_ConvolutionMatrix.BottomRight)) / m_ConvolutionMatrix.Factor) + m_ConvolutionMatrix.Offset);

                    if(nPixel < 0) nPixel = 0;
                    if(nPixel > 255) nPixel = 255;

                    p[4 + stride] = (byte)nPixel;

                    nPixel = ((((pSrc[0] * m_ConvolutionMatrix.TopLeft) + (pSrc[3] * m_ConvolutionMatrix.TopMid) + (pSrc[6] * m_ConvolutionMatrix.TopRight) +
                       (pSrc[0 + stride] * m_ConvolutionMatrix.MidLeft) + (pSrc[3 + stride] * m_ConvolutionMatrix.Pixel) + (pSrc[6 + stride] * m_ConvolutionMatrix.MidRight) +
                       (pSrc[0 + stride2] * m_ConvolutionMatrix.BottomLeft) + (pSrc[3 + stride2] * m_ConvolutionMatrix.BottomMid) + (pSrc[6 + stride2] * m_ConvolutionMatrix.BottomRight)) / m_ConvolutionMatrix.Factor) + m_ConvolutionMatrix.Offset);

                    if(nPixel < 0) nPixel = 0;
                    if(nPixel > 255) nPixel = 255;

                    p[3 + stride] = (byte)nPixel;

                    p += 3;
                    pSrc += 3;
                 }
                 p += nOffset;
                 pSrc += nOffset;
              }
           }

           b.UnlockBits(bmData);
           bSrc.UnlockBits(bmSrc);
        }

dabei sollte es in c# noch viel cooler sein, weil da muß man nicht in ein Array umkopieren, sondern kann Scan0 gleich als (byte ***) auffassen.
Dreimal dieselbe sehr lange Zeile zur Berechnung jedes der 3 Farbwerte ist jedenfalls nicht nötig, und wiederspricht dem DRY-Grundsatz (don't repeat yourself) von Clean Code Developer (CCD)

Und ich denke eben, so ein 3-D-Pointer ließe sich für fast alle Filter einheitlich verwenden - Get/Set-Pixel muß weg.

Der frühe Apfel fängt den Wurm.

Habe jetzt fleißig dran rumgeforscht, und (als erstes) gemerkt, dass das mit mehrdim Pointern nicht geht.
Und die superlangen Additionen eignen sich hervorragend als Optimierung. Elegant wäre gewesen, die Matrix in einer geschachtelten Schleife zu durchlaufen (wie im VBCode gezeigt), aber das ist 5 mal langsamer, als alle 9 Durchgänge in einer einzigen Addition aneinander zu hängen.
Ich find, Optimierungen sollte man kommentieren, weil der Code sieht üblicherweise grauenhaft und umständlich aus, und wenn man nicht weiß, dasses eine Optimierung ist, will man das natürlich gleich vereinfachen.
Ist auch ein Bug drin, nämlich vor und nach der X-Schleife musstenoch die Pointer um 3 hochsetzen, da du die Randpunkte ja nicht bearbeitest.
Der Bug führt zu falsch addressierten Pixeln, die sich im Filter-Ergebnis als Diagonale Linie zeigen, von obere rechte Ecke an.
Sieht man zB. beim Laplace-Filter.

Der frühe Apfel fängt den Wurm.

@ErfinderDesRades:

ich krittel mal ein bischen herum.

zunächst die Test-Anwendung: ich finde, man bräuchte was, wo man vorher und nachher nebeneinander vergleichen kann, vlt sogar Tabpages, wo man verschiedene Filter-Ausgaben durchblättern kann.
Und das bei der Ausgabe angegeben ist, was man eingegeben hat, am liebsten was mit Abspeichern.
also ich jedenfalls hab nach 3 Sekunden vergessen, welches MenuItem ich geklickst hatte, und was in die EingabeMaske eingegeben.

Mdi Anwendung mit mehreren Fenstern ist jedenfalls wirklich eine gute Idee.
Intern wird durch die Actions sowieso gemerkt, welche Aktion zuletzt ausgeführt werde, muss ich noch überlegen ob und wenn ja, wie ich das mache.

Ich hab grad angemacht, ein Bild geladen, und dann mal bei den Filtern Binarisierung-BarCode geklickst, was immer das sein mag, darüber hoffte ich ja was zu erfahren.
Da geht ein Dialog auf, da soll ich einen Grenzwert eingeben, und checken (oder nicht), ob "nur diesen grenzwert".

Damit kann ich überhaupt nichts anfangen, was denn für ein Grenzwert?
habich 142 eingegeben.
Dann steht die Anwendung, und nach ca. 10s kommt ein schwarzweiß-Bild, bei dem scheinbar die Graustufen entfernt sind.
Vermutlich ist das die Binarisierung, dasses nurnoch schwarz-weiß gibt, aber warum Barcode? - na, so heißt es eben.

Vielleicht weil es helfen könnte einen Barcode zu erkennen!? Also willkürlich sind die Namen für die Filter jedenfalls nicht gewählt.

Nächster Test: Binarisierung-treshold MinMax - da muß man keinen Grenzwert angeben, aber die Anwendung steht für 20s.

Erstens: Die Filter sind noch nicht alle optimiert,
deswegen, lies bitte auch alles was hier steht:

**
EDIT: Vorabversion mit neuen Filtern hochgeladen. Bisher ungetestet.
Code an vielen Stellen jetzt gecleant(er).

Als Dateianhang am Ende dieses Beitrags verfügbar:**

**
Habe heute ein erstes Prerelease veröffentlicht. Damit man sich den Code schon mal anschauen kann. Und nein, der Code bleibt nicht so. An vielen Stellen wird es noch Änderungen und Optimierungen geben.

Die Syntax der Filter bleibt so.

Es wird noch ein ExecuteCloned hinzukommen, bei dem man das bearbeitete Bitmap als Ergebnis erhalten wird und das Original-Bild bleibt dabei wie es ist.**

Dafür gibts dann aber eine Ausgabe, bei der das Bild viel besser wieder zu erkennen ist - ein wirklich interessanter Filter. Blos wie gesagt - ich kann die Ausgabe nicht mit der Eingabe vergleichen, das ist schade.

Das wird sich ändern.

Guck ich mal in den Code, da sehe ich gleich, warum das immer so lange steht: ist voll mit GetPixel und SetPixel. Wo ich denken täte, in etwas, was sich "LowLevel..." nennt, haben die nix verloren.
Man kann doch sicherlich alle Bildformate nach 24RGB umwandeln (bei Transparenz-Unterstützung 32ARGB), die Bitmap locken, und auf einem Array mit den Farbwerten arbeiten. Für 24RGB habich das mal selbst gemacht, und habe den Scan-Pointer in ein 2-dim ArbeitsArray kopiert, da kann man dann direkt mit x und y auf jeden Farbwert jedes Pixels zugreifen. Ich müsste mal probieren, ob mans nicht sogar in ein 3-dim Array bekommt, dann könnte man RGB quasi als Z-Achse auffassen.
Etwas, was danach aussieht, ist ja enthalten "UnsafeBitmap", nur wird es scheinbar nicht verwendet.

Bitte? Natürlich wird das verwendet aber noch nicht überall...

Als nächstes hab ich in die Convolutions geguckt, und scheint doch immer noch so, dass für jeden Filter eine eigene Klasse gebaut ist, dabei ist es immer derselbe Filter, nur mit verschieden beschickter 3*3-Matrix.
Sowas kann man doch variabel programmieren, dass im Button-Handler dann die Matrix beschickt wird, nicht für jeden filter eine extra-Klasse.

Die 3x3 Convolution ist ein Relikt von der ursprünglichen LowLevelGraphicsLibrary die am 07.07.2005 verwendet wurde, den Filter möchte ich denen die vielleicht schon Code mit der Lib aufgebaut haben nicht unbedingt wegnehmen, möglich ist aber das
er intern die anderen Convolutions benutzt, da hier ja mehrere Klassen inzwischen existieren.

Einige Convolutions gehen dann auch wieder andere Wege, "SimpleConvolution" zB. wendet Bitmap-Locking an, und greift auf die Farbwerte direkt zu, aber eben ohne die "UnsafeBitmap" zu verwenden, wozu ist die denn nun eiglich da?

Erstens: Sowohl UnsafeBitmap als auch SimpleConvolution wenden BitmapLocking an, nur dass bei SimpleConvolution die Pixel der Reihe nach iteriert werden (hintereinander), wobei es mit UnsafeBitmap möglich ist eine 2dimensionale Schleife
á la


UnsafeBitmap bitmap = new UnsafeBitmap(_bitmap);
for y...
{
   for x... 
   {
        Color color = bitmap.GetPixel(x,y);
   }
}

Oder im Ordner "Edges" guck ich den ersten an, da ist der Code komplett auskommentiert.
Und im 2. Edges-Filter, namens "Compass" findet sich wieder etwas, was sehr nach Convolution-Filter aussieht, allerdings sind es 688 Zeilen, die sich endlos wiederholen, und Get/SetPixel ist wieder dabei.

Dann sieh Dir bitte mal an, warum Crimmins Speckle Removal so funktioniert und warum es so heißt. Außerdem: Lies Dir bitte die Kommentare im Code durch:

 
   /// This is crimmins speckle removal. Momentarily totally unoptimized.
    /// Crimmins is an operator that applies the Crimmins Speckle Reduction 
    /// Algorithm.

Zu Get/SetPixel habich mich schon geäußert, nun, solche "Compass"-Code-Wiederholungs-Wüsten sollte man aber auch unbedingt parametrisieren, also dass am Ende ein Algo mit geeigneten Parametern beschickt wird, anstatt für jede Variante den gleichen Algo re-implementieren.

Und nochmals: es ist IMMER NOCH eine Vorabversion.

Habe jetzt fleißig dran rumgeforscht, und (als erstes) gemerkt, dass das mit mehrdim Pointern nicht geht.
Und die superlangen Additionen eignen sich hervorragend als Optimierung. Elegant wäre gewesen, die Matrix in einer geschachtelten Schleife zu durchlaufen (wie im VBCode gezeigt), aber das ist 5 mal langsamer, als alle 9 Durchgänge in einer einzigen Addition aneinander zu hängen.
Ich find, Optimierungen sollte man kommentieren, weil der Code sieht üblicherweise grauenhaft und umständlich aus, und wenn man nicht weiß, dasses eine Optimierung ist, will man das natürlich gleich vereinfachen.

Na fein, schön dass DU es selbst herausgefunden hast.
Die Fehler sind mir übrigens bekannt. Aber danke für den Hinweis. Es sind auch noch viel mehr Fehler in der Library. Deshalb wird es auch von nun ab ne Weile dauern bis wieder eine neue Version rauskommt.

Ist auch ein Bug drin, nämlich vor und nach der X-Schleife musstenoch die Pointer um 3 hochsetzen, da du die Randpunkte ja nicht bearbeitest.
Der Bug führt zu falsch addressierten Pixeln, die sich im Filter-Ergebnis als Diagonale Linie zeigen, von obere rechte Ecke an.
Sieht man zB. beim Laplace-Filter.

Dass es ab und zu zu der berühmt-berüchtigten Diagonale kommt, ist mir schon längst bekannt, es ist nicht nur beim Laplace Filter ab und zu der Fall.
Wenn Du jetzt noch weiter rausfindest, siehst Du dass GetPixel und SetPixel an fast allen Stellen von einer Klasse namens UnsafeBitmap benutzt wird.

Und auch dass es einige Klassen ibt, die gar nicht benutzt werden usw.

Aber um jetzt mal langer Rede langen Sinn einfach sich selbst zu überlassen:

Was möchtest Du denn programmieren oder ausprobieren? Bin einfach neugierig für was Du die Lib momentan verwendest.

Gruß, dr4g0n76

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Angekündigt:

Diese Features werden mit dem nächsten Upload veröffentlicht:

  • Kuwahara Filter hinzugefügt (Rauschverringerungsfilter der Kanten erhält)

  • Photoshopmodus-Filter (Farbig abwedeln, Multiplizieren, Weiches Licht, Hartes Licht, Umgekehrt Multiplizieren usw...)

  • Bernsen Operator

  • Lipschitz Filter

  • Windowed Sinc Filter

  • Non Maximum Suppression

  • ChannelDifference Filter hinzugefügt (Unterschiede in Kanälen

  • EntropyThreshold

  • EnergyMap

  • EntropyMap

  • Lambda-Erweiterung LambdaPixel (Bitmap, x,y, Color, Rectangle Area)
    Damit können auch auf ganz einfache Weise Flips u.ä. realisiert werden

  • Bitmap 2 LINQ (Bitmap kann aufgrund Neighbouringsfunktionen als LINQ Objekt zurückgegeben werden)

Die neue Version gibt's diesmal erst, wenn alles andere auch durchgetestet sind.
Außerdem werden einige Filter wesentlich verschnellert werden.

  • Einführung von Neighbouring zur eigenen Benutzung.
    Durch ein GetNeighbour kann ein Window mit Größe s direkt erhalten werden:

Bsp. für die Neighbour von P für Window mit s = 3:

***
*){blue}P(*
***

Bsp. für die Neighbours von P für Window mit s = 5:

*****
*****
*){blue}P(*
*****
*****

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Hi,

bin gerade auf diesen Post gestoßen. Hast du schon (neben Grayscale) einen Brightness- und Contrastfilter implementiert? Das ist nämlich gerade genau das was ich suche. Wenn ja, arbeitet der schon mit Scan0 ? Das ganze muss so schnell wie möglich laufen damit es für mich ineteressant ist.

In jedem Fall aber ein großes Lob an dich, das ganze sieht doch sehr vielversprechend aus!

Gruß -Hades-

Hast du schon (neben Grayscale) einen Brightness- und Contrastfilter implementiert?
Das ist nämlich gerade genau das was ich suche. Wenn ja, arbeitet der schon mit Scan0 ? Das ganze muss so schnell wie möglich laufen damit es für mich ineteressant ist.

Die Filter befinden sich in dem Namespace LowLevelGraphics.Filter und heißen:

und heißen:

GrayScale,
Brightness,
Contrast

Alle benutzen Scan0.

Anwendungsbeispiele:


new GrayScale().Execute(bitmap);
new Brightness(10).Execute(bitmap);
new Contrast(10).Execute(bitmap);

usw.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Ausblick für neue Version:

Diese Features werden mit dem nächsten Upload veröffentlicht:

  • Kuwahara Filter hinzugefügt (Rauschverringerungsfilter der Kanten erhält)
  • Photoshopmodus-Filter (Farbig abwedeln, Multiplizieren, Weiches Licht, Hartes Licht, Umgekehrt Multiplizieren usw...)
  • Bernsen Operator
  • Lipschitz Filter
  • Windowed Sinc Filter
  • Non Maximum Suppression
  • ChannelDifference Filter hinzugefügt (Unterschiede in Kanälen z.B. als Graustufenbilddarstellen)
  • EntropyThreshold
  • EnergyMap
  • EntropyMap

Die neue Version gibt's diesmal erst, wenn alles andere auch durchgetestet sind.
Außerdem werden einige Filter wesentlich verschnellert werden.

  • Einführung von Neighbouring zur eigenen Benutzung.
    Durch ein GetNeighbour kann ein Window mit Größe s direkt erhalten werden:

Bsp. für die Neighbour von P für Window mit s = 3:

***
*){blue}P(*
***

Bsp. für die Neighbours von P für Window mit s = 5:

*****
*****
*){blue}P(*
*****
*****

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Das mit den Neighbouring und deine zukünftigen Filter finde ich gut... das brauch man häufig. Ich würde mich freuen, wenn du deine GUI etwas besser benennst, da ich manchmal probiere und dann nicht weiß was "Test 1" oder "2" machen soll. Dennoch ein schönes Projekt. Vielleicht solltest du ein SVN starten indem Leute deinen SourceCode optimieren.

Hallo digi333,

danke für deine Anregungen.
Es wird diesmal etwas dauern bis die neue Library verfügbar sein wird, da ich mir jetzt zum Ziel gesetzt habe, alles noch einmal durchzutesten, im Hinblick auf Benutzbarkeit und Geschwindigkeit sowie auf Funktion, denn was bringt einem z.B. ein

Canny-Edge-Filter

wenn er nicht richtig funktioniert?

Danke für Deine Anregungen. Ich werde diese auf jeden Fall teilweise mit aufnehmen und ins Projekt einbringen.

Das Interface wird so bald ich Zeit habe (aber erst nach den o.g. Tests und Änderungen) in ein MDI Interface umgewandelt werden.

Außerdem folgt, wenn alles funktioniert, eine Beschreibung. Die benötige ich sowieso auch für mich selbst.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Du machst ja viel mit Segmentierung und Farbräume. Es gibt einige sehr schöne Segmentierungsalgorithmen in Java die es in C# noch nicht gibt. Ich fand die folgende Segmentierung sehr interessant. Der Nutzer markiert mit der rechten Maustaste den Vordergrund und mit der linken Taste den Hintergrund und aufbauend auf Lab segmantiert er dann. Das würde ich gerne noch sehen von dir. Die Funktionen und Tools hast du. Schau es dir mal in Java an. openSource auf link.

Hab schon viele Fragen und Wünsche in C# nach dem Algorithmus gefunden.

Ab wann kann man mit der neuen Version rechnen?

Ab wann kann man mit der neuen Version rechnen?

Hallo Digi333.

das wird noch ein wenig dauern.

Momentan bin ich gerade dabei, alles der Reihe nach durchzuprüfen mit vorrangig zuerst 2 Zielen:

1.) Die Funktionalität zu gewährleisten.
2.) Die Geschwindigkeit zu optimieren.

Insgesamt soll sich die Library möglichst flexibel einsetzen lassen.

Ich hatte mir schon bevor ich diese umgeschrieben habe, einige Funktionen von Matlab, Halcon und OpenCV angesehen.

Ich möchte so weit wie möglich an diese Funktionalitäten herankommen, oder wenn das zuviel des guten ist, sollte zumindest so viel in der Library drinstecken, dass man sich diese Funktionalitäten einfach bauen kann.

Momentan schreibe ich den Test-Editor (ImageRecognition2) um.

Dieser hat jetzt ein MDI-interface bekommen.
Zusätzlich kann eingestellt werden, ob nach jeder Aktion die man ausführt (Filter) ein neues Fenster geöffnet werden soll.

Für Filter die mehrere Sourcen benötigen, wird es dann eine Auswahl geben.

Außerdem entsteht eine neue Komponente namens Scripter (die war schon zuvor angedacht unter Fenster->Script). Diese wurde bisher aber nie von mir richtig ausprogrammiert. Das ändert sich dann mit der neuen Version.

Hier ein
Screenshot als Beispiel:

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Für alle die wissen wollen, was momentan passiert, Auszug aus dem History-File:

27.02.2010

  • Formel für AdaptiveThreshold Mean korrigiert

25.02.2010

  • UnsafeBitmap bResult = b1 * b1 + b1 / b1; ≤ jetzt können Formeln mit Bitmaps
    dank Operatorüberladung auch in dieser Form geschrieben werden
  • RaiseToPower: Konstruktor ergänzt, so dass jetzt auch die Parameter übergeben werden können
  • PhotoshopFillmodi: UnsafeImage image = new UnsafeImage(bitmap) hat doppelte Sperrung ausgelöst, korrigiert.
  • Konstruktor von Exponential und Radical ergänzt
  • Bresenham nach Drawing verschoben
  • Formel Für PixelFormat erweitert, jetzt müssen aber vorerst alle Filter die nur unsafe Code benutzen,
    nochmals getestet werden,
    Median enthält noch Fehler

24.02.2010

  • Lambda und GreaterLambdaCommand Filter in LowLevelGraphics eingebaut und überflüssigen Code entfernt
    LambdaImageProcessingTools.dll wird deswegen nicht mehr benötigt
    Auch hier wird jetzt sofort UnsafeBitmap verwendet, dadurch konnte die Geschwindigkeit nochmals erhöht werden
  • Monotony benutzt keine Nachbarschaftsoperationen mehr, sondern eine schnellere Implementierung
  • Hartemischung nach Photoshop Fillmodi verschoben
  • ColorPaletteMatching hat zwei neue Konstruktoren bekommen (ColorMap, ColorMatrix)
  • BaseImageFilter um "SupportedPixelFormats" erweitert.
  • Nicht mehr benötigten Code gelöscht

23.02.2010

  • Alle Filter und Interfaces benutzen jetzt soweit möglich UnsafeBitmap
  • Filter "Distance" in "DistanceTransform" umbenannt

11.02.2010

  • Alle Filter klonbar gemacht
  • Alle Variablen die für Einstellungen verantwortlich sind auf Protected gesetzt
  • Ebenso für diese Variablen Properties eingeführt, wenn sinnvoll
  • Skalierungsfaktor für ColorDifference eingeführt, IMHO ist der Filter sonst unbrauchbar

10.02.2010

  • FishEyeFilter ist jetzt vom Typ BaseImageFilter
  • AdaptiveThresholding: WindowSize und Constant werden jetzt berücksichtigt bei allen 3 Modi
  • ColorFunctions.ToIntRGB korrigiert, falsche Berechnungsformel wurde benutzt.
  • RoundColorsUnsafe kann jetzt nicht mehr mit bUnsafe TRUE/FALSE benutzt werden, es wird immer die schnellste Methode benutzt
  • SameColor in SameColorValues umbenannt und implementiert
  • EntropyThreshold: Beginn der Implementierung

08.02.2010
Offset-Filter eingefügt, war zuvor in der Klasse CGraphics vorhanden, jetzt in LowLevelGraphics.filter Namespace

02.02.2010
Optimierungen

  • Test der gesamten Funktionalität
  • Überall lokale Variablen eingeführt,
    so dass diese nicht mehr in der Schleife angelegt werden müssen

30.01.2010
Optimierung und Idealisierung des Konzeptes

  • Segmentation,
    FastSegmentation,
    FastSegmentation2,
    BarcodeFilter,
    CenterPoint,
    SortChannels,
    ExchangeChannels
    benutzen jetzt nur noch UnsafeBitmaps

  • Bearbeitungsroutine von

    ExchangeChannels
    RotateChannels
    RoundColors
    RotateChannels
    korrigiert,

    nicht alle Pixel wurden bearbeitet

  • FilterMuliples benutzt jetzt UnsafeBitmap, vergessen

  • Gray2Color benutzt jetzt UnsafeBitmap, vergessen

15.12.2009
Alle Filter - soweit möglich - in verschiedene Ordner verschoben.
Die Namespaces dazu existieren noch nicht.

01.10.2009
ConnectedComponents.cs

- Invert Methode gelöscht, da es diese schon gibt  

Datei-Download s. 1 Post

Ziel ist alles was momentan enthalten ist, richtig zum Funktionieren zu bringen und zu optimieren.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Version noch nicht online

Der Script-Editor der angedacht war, funktioniert endlich so wie er schon immer sollte.
Es gibt aber auch ein paar Erweiterungen

EDIT:

Beschreibung hinzugefügt:
Dies wird vorerst über die Klasse RuntimeInterpreter abgewickelt.
Diese kann Zeilen einzeln abarbeiten. Momentan wird nur eine relativ starre Syntax unterstützt.

  • 27.02 - 12.03 Ausprogrammierung der Scriptsprache:

Integrierte Befehle:

  • Load "PicName" //wird benutzt, um PicName zu laden.
  • Display //zeigt ein Ausgabefenster an
  • Filtername //führt den Filter "FilterName" aus
  • Save "PicName" //speichert das aktuelle Pic unter "PicName" ab.

Noch zu integrieren:

  • Filtername Parameter1 = Wert1, Parameter2 = Wert2, Parameter3 = Wert3 ...

weitere Ideen vorbehalten.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Es gibt vorerst keine Ankündigungen mehr. Erst wenn das Projekt m.E. für die erste Version fertig ist.

Hier noch die versprochenen Videos:

Image scripting console

Verkehrsschilderkennung:

Verkehrsschilderkennung

Auswirkung Processingmode:

Processing Modes

Vorschaufenster:

Vorschaufenster

Bitte im ersten Post dieses Threads nachsehen, falls sich was geändert hat.
Oder per PM nachfragen.

Danke.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

Neue Version heute hochgeladen.

Alles von den Videos sollte nachvollzogen werden können.

Viele kleine Änderungen.
Viele Filter korrigiert.

In einige Filter einige Processing_Modes eingebaut u.a. Invert.

s. auch erster Post. die URL mit Party-Crackers

http://www.the-party-crackers.de/Imagerecognition2.rar

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.