2010-02-15 4 views
46

Gibt es eine Möglichkeit, ein Bild in ein Graustufenformat von 16 Pixeln pro Bit zu konvertieren, anstatt jede der Komponenten r, g und b auf Luminanz zu setzen. Ich habe momentan einen bmp aus Datei.Konvertieren eines Bilds in Graustufen

Bitmap c = new Bitmap("filename"); 

Ich möchte ein Bitmap d, das ist Graustufen-Version von c. Ich sehe einen Konstruktor, der System.Drawing.Imaging.PixelFormat enthält, aber ich verstehe nicht, wie man das benutzt. Ich bin neu in der Bildverarbeitung und den relevanten C# -Bibliotheken, habe aber eine mäßige Erfahrung mit C# selbst.

Jede Hilfe, Verweis auf eine Online-Quelle, Hinweis oder Vorschlag wird geschätzt.

Vielen Dank.

BEARBEITEN: d ist die Graustufenversion von c.

Antwort

56

„Ich möchte ein Bitmap d, dass Graustufen ist. sehe ich einen consructor die System.Drawing.Imaging.PixelFormat enthält, aber ich verstehe nicht, wie das zu nutzen.“

Hier ist, wie diese EDIT

Bitmap grayScaleBP = new 
     System.Drawing.Bitmap(2, 2, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale); 

tun: zu Graustufen- für die vollständige Analyse

   Bitmap c = new Bitmap("fromFile"); 
      Bitmap d; 
      int x, y; 

      // Loop through the images pixels to reset color. 
      for (x = 0; x < c.Width; x++) 
      { 
       for (y = 0; y < c.Height; y++) 
       { 
        Color pixelColor = c.GetPixel(x, y); 
        Color newColor = Color.FromArgb(pixelColor.R, 0, 0); 
        c.SetPixel(x, y, newColor); // Now greyscale 
       } 
      } 
      d = c; // d is grayscale version of c 

Schnellere Version von switchonthecode folgendem Link zu konvertieren:

public static Bitmap MakeGrayscale3(Bitmap original) 
{ 
    //create a blank bitmap the same size as original 
    Bitmap newBitmap = new Bitmap(original.Width, original.Height); 

    //get a graphics object from the new image 
    Graphics g = Graphics.FromImage(newBitmap); 

    //create the grayscale ColorMatrix 
    ColorMatrix colorMatrix = new ColorMatrix(
     new float[][] 
     { 
     new float[] {.3f, .3f, .3f, 0, 0}, 
     new float[] {.59f, .59f, .59f, 0, 0}, 
     new float[] {.11f, .11f, .11f, 0, 0}, 
     new float[] {0, 0, 0, 1, 0}, 
     new float[] {0, 0, 0, 0, 1} 
     }); 

    //create some image attributes 
    ImageAttributes attributes = new ImageAttributes(); 

    //set the color matrix attribute 
    attributes.SetColorMatrix(colorMatrix); 

    //draw the original image on the new image 
    //using the grayscale color matrix 
    g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 
     0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); 

    //dispose the Graphics object 
    g.Dispose(); 
    return newBitmap; 
} 
+0

Es tut mir leid, ich hätte sagen sollen, dass ich in meiner Frage, dass ich die Graustufen-Version meiner ursprünglichen Bitmap habe ich den Beitrag bearbeitet, um dies zu reflektieren. – 0fnt

+11

Diese Methode (Pixel für Pixel ist zu langsam) finden Sie in diesem Artikel hier: http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale – Luis

+6

Auch die Pixel-by -pixel-Methode verwendet nur den Rotwert .... – mpen

27
Bitmap d = new Bitmap(c.Width, c.Height); 

for (int i = 0; i < c.Width; i++) 
{ 
    for (int x = 0; x < c.Height; x++) 
    { 
     Color oc = c.GetPixel(i, x); 
     int grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11)); 
     Color nc = Color.FromArgb(oc.A, grayScale, grayScale, grayScale); 
     d.SetPixel(i, x, nc); 
    } 
} 

So behält es auch den Alpha-Kanal.
Genießen.

+4

Warum habe ich einen Downvote bekommen? Diese Antwort ist vollkommen in Ordnung und zum Thema. – Vercas

+1

Ich weiß, es ist eine alte Antwort, aber könnten Sie näher auf die Konstanten eingehen, die Sie mit den R, G, B Werten multiplizieren? Ich sehe es auf "1.0", aber gibt es eine Erklärung warum? –

+3

@LarsKristensen Sehen Sie dies: https://en.wikipedia.org/wiki/Grayscale – lukegravitt

6

Keines der obigen Beispiele erstellt 8-Bit (8bpp) -Bitmap-Bilder. Einige Software, wie die Bildverarbeitung, unterstützt nur 8bpp. Leider haben die MS .NET Bibliotheken keine Lösung. Das Format PixelFormat.Format8bppIndexed sieht vielversprechend aus, aber nach vielen Versuchen konnte ich es nicht zum Laufen bringen.

Um eine echte 8-Bit-Bitmap-Datei zu erstellen, müssen Sie die proper headers erstellen. Letztendlich fand ich die Grayscale library Lösung zum Erstellen von 8-Bit Bitmap (BMP) -Dateien. Der Code ist sehr einfach:

Image image = Image.FromFile("c:/path/to/image.jpg"); 
GrayBMP_File.CreateGrayBitmapFile(image, "c:/path/to/8bpp/image.bmp"); 

Der Code für dieses Projekt ist noch lange nicht schön, aber es funktioniert, mit einem kleinen einfach zu fix Problem. Der Autor hat die Bildauflösung auf 10x10 fest codiert. Bildverarbeitungsprogramme mögen das nicht. Das Update ist offen GrayBMP_File.cs (ja, funky Dateibenennung, ich weiß) und ersetzen Zeilen 50 und 51 mit dem Code unten. Im Beispiel wird die Auflösung auf 200x200 festgelegt, aber Sie sollten es in die richtige Anzahl ändern.

int resX = 200; 
int resY = 200; 
// horizontal resolution 
Copy_to_Index(DIB_header, BitConverter.GetBytes(resX * 100), 24); 
// vertical resolution 
Copy_to_Index(DIB_header, BitConverter.GetBytes(resY * 100), 28); 
+0

Ich möchte es testen und Upvote, aber gerade jetzt pünktlich. Danke für die Antwort. – 0fnt

+0

Der Trick mit 8bpp ist, dass Sie das rohe interne Array bearbeiten müssen, das das Image unterstützt. Sie können das erreichen, indem Sie 'image.LockBits()' aufrufen und dann die Daten mit 'Marshal.Copy' ein/auskopieren. Google es, um den vollständigen Prozess zu erhalten. Beachten Sie, dass die Schrittweite eines Bildes (eine aus den Daten gelesene Zeile) oft länger ist als die tatsächliche Breite, da es auf das nächste Vielfache von 4 Byte gerundet wird. – Nyerguds

6

um ein paar Punkte hier zusammenfassen: Es gibt einige Pixel-für-Pixel sind Optionen, die bei einfacher sind einfach nicht schnell.

@Luis Kommentar Verlinkung zu: (archiviert) https://web.archive.org/web/20110827032809/http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale ist hervorragend.

Er läuft durch drei verschiedene Optionen und enthält Timings für jeden.

+3

Das dritte Beispiel in der obigen Verbindung ist super effizient und direkt gelöst mein Problem – ford

+0

Leider ist dieser Link jetzt tot ... –

+3

@RichardEverett In der Tat. Web-Archiv zur Rettung! Fest. – jeffreypriebe

3

Der folgende Code ist die einfachste Lösung:

Bitmap bt = new Bitmap("imageFilePath"); 

for (int y = 0; y < bt.Height; y++) 
{ 
    for (int x = 0; x < bt.Width; x++) 
    { 
     Color c = bt.GetPixel(x, y); 

     int r = c.R; 
     int g = c.G; 
     int b = c.B; 
     int avg = (r + g + b)/3; 
     bt.SetPixel(x, y, Color.FromArgb(avg,avg,avg)); 
    } 
} 

bt.Save("d:\\out.bmp"); 
9

Es gibt eine statische Methode in ToolStripRenderer Klasse, genannt CreateDisabledImage. Seine Benutzung ist so einfach wie:

Bitmap c = new Bitmap("filename"); 
Image d = ToolStripRenderer.CreateDisabledImage(c); 

Es verwendet ein wenig anders Matrix als die in der akzeptierten Antwort und zusätzlich multipliziert sie mit einer Transparenz von Wert 0,7, so dass der Effekt ist etwas anders als nur Graustufen, Aber wenn Sie Ihr Bild nur grau erscheinen lassen möchten, ist es die einfachste und beste Lösung.

+2

Oh Mann, danke dafür. Dies entspricht dem Aussehen von Bildern in deaktivierten Steuerelementen in WinForms, wodurch alles konsistent bleibt. – Jimmy