C# Winforms Histogramm (für Bitmaps oder zum Anzeigen in einer PictureBox)

C# Winforms Histogramm (für Bitmaps oder zum Anzeigen in einer PictureBox)

Es gibt immer wieder Standardaufgaben, für die es noch keine Lösung gibt. So, wie zu einer Bitmap ein Histogramm zu erzeugen – und zwar wieder in einer Bitmap. Das läßt sich dann sehr einfach z. B. mit einer PictureBox verknüpfen, und schon hat man eine passende Anzeige.

Auf Ästhetik habe ich wohl nicht so viel Wert gelegt.. da bin ich gerne für Vorschläge offen!

Dafür ist die Funktion sehr klein und läßt sich überall leicht mit Copy&Paste einfügen.

Oh ja, langsam ist sie auch.. obwohl leidlich live-fähig. U. a. habe ich direkt die Anzahl der ausgewerteten Pixel eingeschränkt, immerhin geht es ja nur um eine ungefähre Verteilung. Wer es genauer braucht oder nur sehr kleine Bitmaps hat kann diese hartcodierten 🙂 Parameter natürlich gerne anpassen. Oder den GetPixel rausschmeißen.. der hier aber sehr bequem ist (sonst könnte man direkt auf die Bitmap-Rohdaten zugreifen, muß hier aber die verschiedenen Pixelformate beachten – oder beschränkt sich eben auf ein Format).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 int[,] GetHistorgramValues(Bitmap bmp)
 {
     int[,] res = new int[3, 256];
     for (int i = 0; i < 3; ++i)
         for (int j = 0; j < 256; ++j)
             res[i, j] = 0;
 
     for (int i = 0; i < bmp.Width; i += 11)
         for (int j = 0; j < bmp.Height; j += 3)
         {
             var col = bmp.GetPixel(i, j);
             res[0, col.R]++;
             res[1, col.G]++;
             res[2, col.B]++;
         }
     return res;
 }
 
 Bitmap GenerateHistogram(Bitmap bmp)
 {
     var hist = GetHistorgramValues(bmp);
     // generate fixed size bitmap
     const int width = 256, height = 150;
     Bitmap res = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
     using (Graphics g = Graphics.FromImage(res))
     {
         for (int i = 0; i < 3; ++i)
         {
             using (Pen p = new Pen(i == 0 ? Color.Red : i == 1 ? Color.Green : Color.Blue))
             {
                 for (int j = 0; j < width; ++j)
                 {
                     var temp = hist[i, j];
                     if (temp < 1)
                         temp = 1;
                     int myHeight = (int)(Math.Log(temp)*10);
                     g.DrawLine(p, j, height, j, height - myHeight);
                 }
             }
         }
     }
     return res;
 }

2013-07-12 20_43_49-BookSamples (Running) - Microsoft Visual Studio

Links ist das Original, rechts das zugehörige Histogramm. Mit etwas Anstrengung lassen sich auch die einzelnen Farben unterscheiden. Und ja – ich wollte keine Bitmap einbinden, daher nehme ich einfach einen Bildschirmausschnitt.

Der ausführlichere Code zum Copy/Paste in eine frische WinForms Applikation (mit 2 PictureBoxen):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace WindowsFormsApplicationHistogram
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            Bitmap bmpScreenCapture = new Bitmap(300, 300);
            {
                using (Graphics g = Graphics.FromImage(bmpScreenCapture))
                {
                    g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X + 200,
                                     Screen.PrimaryScreen.Bounds.Y + 200,
                                     0, 0,
                                     bmpScreenCapture.Size,
                                     CopyPixelOperation.SourceCopy);
                }
                pictureBox1.Image = bmpScreenCapture;
                pictureBox2.Image = GenerateHistogram(bmpScreenCapture);
            }
        }
 
        int[,] GetHistorgramValues(Bitmap bmp)
        {
            int[,] res = new int[3, 256];
            for (int i = 0; i < 3; ++i)
                for (int j = 0; j < 256; ++j)
                    res[i, j] = 0;
 
            for (int i = 0; i < bmp.Width; i += 11)
                for (int j = 0; j < bmp.Height; j += 3)
                {
                    var col = bmp.GetPixel(i, j);
                    res[0, col.R]++;
                    res[1, col.G]++;
                    res[2, col.B]++;
                }
            return res;
        }
 
        Bitmap GenerateHistogram(Bitmap bmp)
        {
            var hist = GetHistorgramValues(bmp);
            // generate fixed size bitmap
            const int width = 256, height = 150;
            Bitmap res = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
            using (Graphics g = Graphics.FromImage(res))
            {
                for (int i = 0; i < 3; ++i)
                {
                    using (Pen p = new Pen(i == 0 ? Color.Red : i == 1 ? Color.Green : Color.Blue))
                    {
                        for (int j = 0; j < width; ++j)
                        {
                            var temp = hist[i, j];
                            if (temp < 1)
                                temp = 1;
                            int myHeight = (int)(Math.Log(temp) * 10);
                            g.DrawLine(p, j, height, j, height - myHeight);
                        }
                    }
                }
            }
            return res;
        }
    }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.