Farbige Bitmap in Graustufen Bitmap und Schwarz-Weiß Bitmap konvertieren

    • C#

    Es gibt 1 Antwort in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

      Farbige Bitmap in Graustufen Bitmap und Schwarz-Weiß Bitmap konvertieren

      Hallo Leute,

      ich beschäftige mich momentan mit Image Comparing.
      Hierbei wird oftmals ein Schwarz-Weiß oder Graustufen Bild benötigt bzw. ist von Vorteil.
      Beim erstellen von Schwarz-Weiß Bitmaps und granstufigen Bitmaps ist mir die schlechte performance von System.Drawing aufgefallen.
      Aufgrund der schlechten Performance habe ich zwei Funktionen zusammengestellt welche etwas schneller durchlaufen als Standard System.Drawing Objekte und Klassen wie ColorMatrix, Graphics und ImageAttributes.
      Diese Seite hat mir enorm bei der Erstellung der Funktionen geholfen: csharpexamples.com/fast-image-processing-c/

      Standard Grayscaling mit System.Drawing (langsam):
      Spoiler anzeigen

      C#-Quellcode

      1. public Bitmap ToGrayScale(Bitmap target)
      2. {
      3. Bitmap cpy = new Bitmap(target.Width, target.Height, target.PixelFormat);
      4. Graphics g = Graphics.FromImage(cpy);
      5. ColorMatrix colorMatrix = new ColorMatrix(
      6. new float[][] {
      7. new float[] {.3f, .3f, .3f, 0, 0},
      8. new float[] {.59f, .59f, .59f, 0, 0},
      9. new float[] {.11f, .11f, .11f, 0, 0},
      10. new float[] {0, 0, 0, 1, 0},
      11. new float[] {0, 0, 0, 0, 1}
      12. });
      13. ImageAttributes attributes = new ImageAttributes();
      14. attributes.SetColorMatrix(colorMatrix);
      15. g.DrawImage(target, new Rectangle(0, 0, target.Width, target.Height),
      16. 0, 0, target.Width, target.Height, GraphicsUnit.Pixel, attributes);
      17. g.Dispose();
      18. return cpy;
      19. }


      Grayscaling mit System.Drawing + LockBits + unsafe + Parallel:
      Spoiler anzeigen

      C#-Quellcode

      1. public Bitmap ToGrayScaleUnsafe(Bitmap target)
      2. {
      3. unsafe
      4. {
      5. BitmapData bmpLB = target.LockBits(
      6. new Rectangle(0, 0, target.Width, target.Height),
      7. ImageLockMode.ReadWrite,
      8. target.PixelFormat);
      9. int bpp = Bitmap.GetPixelFormatSize(target.PixelFormat) / 8;
      10. int hip = bmpLB.Height;
      11. int wib = bmpLB.Width * bpp;
      12. byte* ptrPx = (byte*)bmpLB.Scan0; // Pointer to first pixel
      13. Parallel.For(0, hip, y =>
      14. {
      15. byte* cLine = ptrPx + (y * bmpLB.Stride);
      16. for (int x=0; x<wib; x=x+bpp)
      17. {
      18. int b = cLine[x ];
      19. int g = cLine[x + 1];
      20. int r = cLine[x + 2];
      21. int rgb = (r << 16 | g << 8 | b);
      22. float avg = ((r & 0xff) / 255f +
      23. (g & 0xff) / 255f +
      24. (b & 0xff) / 255f) / 3;
      25. float alpha = (((rgb >> 24) & 0xff) / 255f);
      26. avg = Math.Min(1.0f, 0.35f + 0.65f * avg);
      27. Color c = Color.FromArgb(
      28. (int)(alpha * 255f) << 24 |
      29. (int)(avg * 255f) << 16 |
      30. (int)(avg * 255f) << 8 |
      31. (int)(avg * 255f));
      32. cLine[x ] = (byte)c.B;
      33. cLine[x + 1] = (byte)c.G;
      34. cLine[x + 2] = (byte)c.R;
      35. }
      36. });
      37. target.UnlockBits(bmpLB);
      38. }
      39. return target;
      40. }


      Black-and-White mit System.Drawing + LockBits + unsafe + Parallel:
      Spoiler anzeigen

      C#-Quellcode

      1. public Bitmap ToBlackAndWhiteUnsafe(Bitmap target)
      2. {
      3. unsafe
      4. {
      5. BitmapData bmpLB = target.LockBits(
      6. new Rectangle(0, 0, target.Width, target.Height),
      7. ImageLockMode.ReadWrite,
      8. target.PixelFormat);
      9. int bpp = Bitmap.GetPixelFormatSize(target.PixelFormat) / 8;
      10. int hip = bmpLB.Height;
      11. int wib = bmpLB.Width * bpp;
      12. byte* ptrPx = (byte*)bmpLB.Scan0; // Pointer to first pixel
      13. Parallel.For(0, hip, y =>
      14. {
      15. byte* cLine = ptrPx + (y * bmpLB.Stride);
      16. for (int x=0; x<wib; x = x + bpp)
      17. {
      18. int b = cLine[x ];
      19. int g = cLine[x + 1];
      20. int r = cLine[x + 2];
      21. int rgb = (r << 16 | g << 8 | b);
      22. float avg = ((r & 0xff) / 255f +
      23. (g & 0xff) / 255f +
      24. (b & 0xff) / 255f) / 3;
      25. avg = Math.Min(1.0f, 0.35f + 0.65f * avg);
      26. Color c = avg < 0.5 ? Color.Black : Color.White;
      27. cLine[x ] = (byte)c.B;
      28. cLine[x + 1] = (byte)c.G;
      29. cLine[x + 2] = (byte)c.R;
      30. }
      31. });
      32. target.UnlockBits(bmpLB);
      33. }
      34. return target;
      35. }


      Für das Messen der Laufzeiten habe ich das StopWatch Objekt aus System.Diagnostics verwendet.
      Getestet mit 16 jpg Files.
      Reihenfolge der Funktionsaufrufe: ToGrayScale, ToGrayScaleUnsafe, ToBlackAndWhiteUnsafe
      Dateigrößen zwischen 4MiB und 30MiB
      Abmessungen zwischen 4861x3241 Pixel bis 6000x4000 Pixel.
      RAM: 4GB DDR3
      CPU: Intel i5-4300U (1.90GHz - 2.49GHz)

      Testergebnis:
      Spoiler anzeigen
      ============================================================================
      Filesize: 30MiB
      Dimensions: 6000x4000
      ============================================================================
      2910 ms (ToGrayScale)
      1446 ms (ToGrayScaleUnsafe)
      1442 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 30MiB
      Dimensions: 6000x4000
      ============================================================================
      1773 ms (ToGrayScale)
      1309 ms (ToGrayScaleUnsafe)
      1441 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 16MiB
      Dimensions: 6000x4000
      ============================================================================
      1798 ms (ToGrayScale)
      2022 ms (ToGrayScaleUnsafe)
      2094 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 28MiB
      Dimensions: 6000x4000
      ============================================================================
      1880 ms (ToGrayScale)
      1318 ms (ToGrayScaleUnsafe)
      1451 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 8MiB
      Dimensions: 6000x4000
      ============================================================================
      1856 ms (ToGrayScale)
      1097 ms (ToGrayScaleUnsafe)
      1179 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 10MiB
      Dimensions: 6000x4000
      ============================================================================
      2283 ms (ToGrayScale)
      1440 ms (ToGrayScaleUnsafe)
      1227 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 4MiB
      Dimensions: 4861x3241
      ============================================================================
      1314 ms (ToGrayScale)
      685 ms (ToGrayScaleUnsafe)
      736 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 8MiB
      Dimensions: 6000x4000
      ============================================================================
      1854 ms (ToGrayScale)
      1060 ms (ToGrayScaleUnsafe)
      1141 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 8MiB
      Dimensions: 6000x4000
      ============================================================================
      1849 ms (ToGrayScale)
      1100 ms (ToGrayScaleUnsafe)
      1181 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 8MiB
      Dimensions: 3452x5178
      ============================================================================
      1481 ms (ToGrayScale)
      814 ms (ToGrayScaleUnsafe)
      933 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 15MiB
      Dimensions: 4000x6000
      ============================================================================
      2216 ms (ToGrayScale)
      1131 ms (ToGrayScaleUnsafe)
      1226 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 18MiB
      Dimensions: 6000x4000
      ============================================================================
      1862 ms (ToGrayScale)
      1177 ms (ToGrayScaleUnsafe)
      1314 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 17MiB
      Dimensions: 6000x4000
      ============================================================================
      1802 ms (ToGrayScale)
      1153 ms (ToGrayScaleUnsafe)
      1304 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 8MiB
      Dimensions: 4000x6000
      ============================================================================
      2001 ms (ToGrayScale)
      1089 ms (ToGrayScaleUnsafe)
      1188 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 9MiB
      Dimensions: 4000x6000
      ============================================================================
      1857 ms (ToGrayScale)
      1134 ms (ToGrayScaleUnsafe)
      1147 ms (ToBackAndWhiteUnsafe)
      ============================================================================

      ============================================================================
      Filesize: 6MiB
      Dimensions: 4000x6000
      ============================================================================
      2294 ms (ToGrayScale)
      1038 ms (ToGrayScaleUnsafe)
      1193 ms (ToBackAndWhiteUnsafe)
      ============================================================================


      Durschnitt in s:
      ToGrayScale hat eine durchschnittliche Laufzeit von 1.9s (1939,375ms)
      ToGrayScaleUnsafe hat eine durchschnittliche Laufzeit von 1.2s (1188,313ms)
      ToBlackAndWhite hat eine durschnittliche Laufzeit von 1.3s (1262,313ms)

      Einen Einbruch bzw. eine Abweichung der Performance gibt es, wenn man ein Schwarz-Weiß Bild durch ToGrayScaleUnsafe und ToBlackAndWhiteUnsafe jagt.
      Diese Abweichung ist in den Daten des Tests der 3ten Datei zu sehen:
      1798 ms (ToGrayScale)
      2022 ms (ToGrayScaleUnsafe)
      2094 ms (ToBackAndWhiteUnsafe)
      ToGrayScale schneidet hier besser ab!
      @Petersilie Vielleicht noch ein paar Verbesserungen:
      cLine ist vom Typ byte*.
      Mach r, g, b ebenfalls zu byte. Da kannst Du das & 0xff sparen.
      Die Division / 255 zieh aus der Klammer raus und fasse sie mit der Division / 3 zusammen.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      VB-Fragen über PN / Konversation werden ignoriert!