Autor Beitrag
Christoph1972
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 690
Erhaltene Danke: 16


VS2015 Pro / C# & VB.Net
BeitragVerfasst: Di 09.03.10 15:07 
Hallo Leute,

ich möchte Pixel von einem „schwarz“ –weiß Image verändern. Und zwar möchte ich die Farbe der schwarzen Pixel in eine beliebige Farbe ändern. Bisher habe ich das so gemacht und bin damit gut gefahren:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
private Bitmap ChangeColor(Image image, Color color)
{
    Bitmap pic = new Bitmap(image);
    Bitmap newPic = new Bitmap(pic.Width, pic.Height);

    ColorMap[] cMap = new ColorMap[1];

    cMap[0] = new ColorMap();
    cMap[0].OldColor = Color.Black;
    cMap[0].NewColor = color;

    ImageAttributes imageAtributes = new ImageAttributes();
    imageAtributes.SetRemapTable(cMap);

    using (Graphics g = Graphics.FromImage(newPic))
    {
        g.DrawImage(pic, new Rectangle(00, pic.Width, pic.Height), 00, pic.Width, pic.Height, GraphicsUnit.Pixel, imageAtributes);
    }

    return newPic;
}


Nun ist es aber so, das in einigen Images die Grafik abgestuft ist, also dunkel grau - bis schwarze Pixel. Da komme ich mit der Methode natürlich nicht weiter.

Es wäre kein Problem, wenn alle Pixel die nicht weiß sind, in schwarz umgewandelt werden. Das wäre genau das was ich benötige.

Hat jemand eine Idee, wie alle Farben die in dem Image enthalten sind in eine ColorMap bekomme? Wobei ich nicht die GetPixel Methode mit einer Schleife verwenden möchte, das dauert viel zulange.

Mit einer ColorMatrix könnte es auch gehen, ich habe nur keine Vorstellung, wie die Matrix für schwarz abgebildet werden muss.Diese Matrix macht ein Image schwarz weiß, mit Grauabstufungen:

ausblenden C#-Quelltext
1:
ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[] { 0.299F, 0.299F, 0.299F, 00 }, new float[] { 0.587F, 0.587F, 0.587F, 00 }, new float[] { 0.114F, 0.114F, 0.114F, 00 }, new float[] { 00010 }, new float[] { 00001 } });					


Ehrlich gesagt verstehe ich die ColorMatrix nicht wirklich und bin daher nicht in der Lage sie so zu ändern, dass sie nur schwarz abbildet.


Besteht eventuell eine Möglichkeit es "einfach" über die ImageAtributes zu lösen?


Vielleicht hat ja jemand eine Idee. Ich befürchte das es viel einfacher ist als ich denke, aber wer weis.......

_________________
Gruß
Christoph
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Di 09.03.10 22:58 
Hast Du mal geschaut, wie schnell das ist, wenn Du es mittels LockBits und den entsprechenden Operationen direkt an den Bytes machst? Ich habe das ein paar Mal benutzt und der Geschwindigkeitsvorteil gegenüber GetPixel / SetPixel ist sehr, sehr deutlich.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Christoph1972 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 690
Erhaltene Danke: 16


VS2015 Pro / C# & VB.Net
BeitragVerfasst: Mi 10.03.10 00:08 
Ah, vielen Dank für die Info! Von LookBits und den entsprechenden Operationen habe ich bisher nichts gehört. Ich werde mich darüber informieren. Anregungen und Hinweise sind wie immer willkommen!

_________________
Gruß
Christoph
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Mi 10.03.10 09:22 
Hallo,

schau mal hier habe ich ein Tutorial mit einem hilfreichen Vergleich gefunden. Selber habe ich damals für Bildoperationen auch die Bitlock-Methode verwendent, wie sie Christian angesprochen hat. Müsste aber erst nachschauen wie ich das damals 'genau' gemacht hab. Ansatzweise sah es so aus.

Wenn du damit nicht weiter kommst, kann ich gerne mal mein Projekt laden (gerade kein Zugriff) und schauen wie ich es da gemacht hab.

Gruß Daniel
Christoph1972 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 690
Erhaltene Danke: 16


VS2015 Pro / C# & VB.Net
BeitragVerfasst: Do 11.03.10 20:50 
Hallo Leute,

ich musste leider feststellen, dass es doch keine gute Lösung ist, das Image komplett einzuschwärzen. Von daher hat sich die Fragestellung erledigt.

Was mich aber doch interessiert, ist die Optimierung der GetPixel Methode, mittels unsafe Aufruf. So wie ich es gemacht habe dauert es immer noch recht lange.


ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
unsafe void Test(Bitmap image)
{
        Color color;

        for (Int32 y = 0; y < image.Height; y++)
        {
            for (Int32 x = 0; x < image.Width; x++)
            {
                color = image.GetPixel(x, y);
            }
        }
    }
}



Ist das so korrekt?

_________________
Gruß
Christoph
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 11.03.10 20:59 
Wird unsafe nicht nur dann schneller, wenn man auch unsafe Operationen ausführt? :gruebel:

Auch hier würde ich wieder zum LockBits-Schema raten.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
danielf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1012
Erhaltene Danke: 24

Windows XP
C#, Visual Studio
BeitragVerfasst: Do 11.03.10 21:04 
Nein, so einfach ist es nicht ;)

Du hast die Methode zwar als unsafe deklariert, aber verwendest dennoch mit der GetPixel-Methode eine Methode die im managed Bereich läuft.

Zum Beispiel für 24bppRGB:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
Bitmap oBitmap;

bitmapData data = oBitmap.LockBits( rBounds, ImageLockMode.Read, oBitmap.PixelFormat );

int iCurrentPosition = iY * data.Stride + (iX * 3);

Color color = Color.FromArgb(data[ iCurrentPosition+2 ],
                             data[ iCurrentPosition+1 ],
                             data[ iCurrentPosition ] );


Besser ist es aber das LockBits nur einmal zu machen, am besten in einer Art Helper-Class der du das bitmap übergibts auf dem du arbeiten willst.

Gruß daniel
Christoph1972 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 690
Erhaltene Danke: 16


VS2015 Pro / C# & VB.Net
BeitragVerfasst: Do 11.03.10 21:25 
Hi,

vielen Dank für die schnellen Antworten! Ich hatte das mit unsafe aus der Hilfe, weiter wird da nicht drauf eingegangen. Ok, das LookBits werde ich mir mal anschauen.

_________________
Gruß
Christoph
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 11.03.10 21:49 
Hi!

Ich habe noch was bei mir auf der Platte gefunden. In grauer Vorzeit habe ich mal eine solche Klasse geschrieben, und nachdem ich gerade mal kurz drüber geguckt habe, scheint sie keine allzu schlimmen Jugendsünden zu enthalten. Außer einer: Das Disposable-Pattern war nicht richtig implementiert, was ich in Delphi Prism aber durch das hinzufügen eines Aspekts mit einer Zeile korrigieren konnte :mrgreen:

Ich hänge mal Quelltext und Kompilat an. Das Assembly behauptet, .NET 3.5 zu brauchen (das hängt mit dem Aspekt zusammen), läuft bei mir aber auch in einer .NET 2.0 Anwendung problemlos, wenn man die Warnungen ignoriert. ;-)

Quelltext (pas, 13.07 KB)
Kompilat mit unvollständiger XML-Doku (zip, 4.64 KB)

Benutzen tust Du's dann z.B. so:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
            var bmp = new Bitmap(80006000, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            var fast = new FastBitmap(bmp, true);

            for (int x = 0; x < 8000; x++)
                for (int y = 0; y < 6000; y++)
                fast.SetPixel(x, y, Color.Blue);

            pictureBox1.Image = fast.Bitmap;;

Beachte in der XML-Doku bitte aber auch die Hinweise zur AutoUpdate-Eigenschaft und dem entsprechenden Parameter in den Konstruktoren.

Grüße
Christian
Einloggen, um Attachments anzusehen!
_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".