Search code examples
c#bmpgrayscale

greyscalevalue in colorvalue


I get from a camera greyscale values for each pixel in the format 23453... (16 bit values) And I set the pixelcolor for my .bmp with

image.SetPixel(cols, rows, color);

but how can I get my greyscale value into a correct color value? So the picture can be correct be displayed in grayscalevalues?

thanks


Solution

  •  public static Bitmap getGrayscale(Bitmap hc){
            Bitmap result = new Bitmap(hc.Width, hc.Height);
            ColorMatrix colorMatrix = new ColorMatrix(new float[][]{   
                new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0},
                new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0,0,0,1,0,0},
                new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
    
            using (Graphics g = Graphics.FromImage(result)) {
                ImageAttributes attributes = new ImageAttributes();
                attributes.SetColorMatrix(colorMatrix);
                g.DrawImage(hc, new Rectangle(0, 0, hc.Width, hc.Height),
                   0, 0, hc.Width, hc.Height, GraphicsUnit.Pixel, attributes);
            }
            return result;
        }
    

    That is actually quite complex problem. In my example, basically I create a filter and apply it to the existing bitmap, with some nifty matrix calculation. I solved it while ago, trying to solve this problem.

    Edit

    VB people like full examples, maybe do C# as well.

    enter image description here

    Drop 2 buttons and a picture box onto a form, and use code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Drawing.Imaging;
    
    namespace gray
    {
        public partial class Example : Form
        {
            public Example()
            {
                InitializeComponent();
            }
    
            public static Bitmap getGrayscale(Bitmap hc)
            {
                Bitmap result = new Bitmap(hc.Width, hc.Height);
                ColorMatrix colorMatrix = new ColorMatrix(new float[][]{   
                new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0},
                new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0,0,0,1,0,0},
                new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
    
                using (Graphics g = Graphics.FromImage(result))
                {
                    ImageAttributes attributes = new ImageAttributes();
                    attributes.SetColorMatrix(colorMatrix);
                    g.DrawImage(hc, new Rectangle(0, 0, hc.Width, hc.Height),
                       0, 0, hc.Width, hc.Height, GraphicsUnit.Pixel, attributes);
                }
                return result;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                OpenFileDialog fDialog = new OpenFileDialog();
                fDialog.Title = "Open Image File";
                fDialog.Filter = "PNG Files|*.png|Bitmap Files|*.bmp";
                fDialog.InitialDirectory = @"C:\";
    
                if (fDialog.ShowDialog() == DialogResult.OK)
                    this.pictureBox1.ImageLocation = fDialog.FileName.ToString();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                if (this.pictureBox1.Image == null)
                {
                    MessageBox.Show("Sorry no image to alter.");
                    return;
                }
                this.pictureBox1.Image = getGrayscale((Bitmap)this.pictureBox1.Image);
            }
        }
    }
    

    Yes, this works and colors are balanced correctly.

    But if you want an alternative, that has effective luminance, then:

        ColorMatrix colorMatrix = new ColorMatrix(new float[][]{   
                                  new float[]{ 0.3f, 0.3f, 0.3f,0,0},
                                  new float[]{0.59f,0.59f,0.59f,0,0},
                                  new float[]{0.11f,0.11f,0.11f,0,0},
                                  new float[]{    0,    0,    0,1,0,0},
                                  new float[]{    0,    0,    0,0,1,0},
                                  new float[]{    0,    0,    0,0,0,1}});
    

    Edit 2: @Hans Passant.

    Bitmap consists of pixels, that have color value RGBA {R ed, G reen, B lue, A lpha transparency}. To get grayscaled image from colored one, I multiply each pixel color value with my defined colorMatrix.

    Normal 2 matrix multiplying speed is Θ(n^2), but this GDI+ linear conversion uses Fast Fourier Transform to do it in Θ(n log(n)). This means for larger images, its vastly faster then other methods.

    Lets say I have input pixels In, with values {R, G, B, A} and I would like to get the formula for pixel values after matrix multiplication, and lets call it Out with values {Aout, Bout, Cout, Dout}.

    enter image description here

    Out:

    • Aout = r(4) A + r(3) B + r(2) G + r(1) R
    • Bout = g(4) A + g(3) B + g(2) G + g(1) R
    • Cout = b(4) A + b(3) B + b(2) G + b(1) R
    • Dout = a(4) A + a(3) B + a(2) G + a(1) R

    Or in this case:

    enter image description here

    Out = {
      0.11 B + 0.59 G + 0.3 R,
      0.11 B + 0.59 G + 0.3 R,
      0.11 B + 0.59 G + 0.3 R,
      A,
      0,
      0
    }
    

    Where formula of effective luminance of grayscale image is 0.11 blue + 0.59 green + 0.3 red. So it's correct.