Talking about Visual C Image Processing (Reading Saving and Visiting Pixels)

  • 2021-09-12 01:57:19
  • OfStack

The reason why I say "shallow talk" here is that I only briefly introduce how to use Visual C # to read, save and access pixels of images. Without involving too many algorithms.

1. Read the image

In Visual C # we can use an Picture Box control to display the picture, as follows:


private void btnOpenImage_Click(object sender, EventArgs e)
{
    OpenFileDialog ofd = new OpenFileDialog();
    ofd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
    ofd.CheckFileExists = true;
    ofd.CheckPathExists = true;
    if (ofd.ShowDialog() == DialogResult.OK)
    {
        //pbxShowImage.ImageLocation = ofd.FileName;
        bmp = new Bitmap(ofd.FileName);
        if (bmp==null)
        {
            MessageBox.Show(" Failed to load picture !", " Errors ");
            return;
        }
        pbxShowImage.Image = bmp;
        ofd.Dispose();
    }
}

Where bmp is an object of the class: private Bitmap bmp = null;
Before using the Bitmap and BitmapData classes, you need to use using System. Drawing. Imaging;

2. Save the image


private void btnSaveImage_Click(object sender, EventArgs e)
{
    if (bmp == null) return;
    SaveFileDialog sfd = new SaveFileDialog();
    sfd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
    if (sfd.ShowDialog() == DialogResult.OK)
    {
        pbxShowImage.Image.Save(sfd.FileName);
        MessageBox.Show(" Save successfully !"," Prompt ");
        sfd.Dispose();
    }
}

3. Access to Pixels

We can create an GrayBitmapData class to do related processing. The procedure for the whole class is as follows:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace ImageElf
{
    class GrayBitmapData
    {
        public byte[,] Data;// Save the Pixel Matrix
        public int Width;// Width of image
        public int Height;// Height of image
        public GrayBitmapData()
        {
            this.Width = 0;
            this.Height = 0;
            this.Data = null;
        }
        public GrayBitmapData(Bitmap bmp)
        {
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            this.Width = bmpData.Width;
            this.Height = bmpData.Height;
            Data = new byte[Height, Width];
            unsafe
            {
                byte* ptr = (byte*)bmpData.Scan0.ToPointer();
                for (int i = 0; i < Height; i++)
                {
                    for (int j = 0; j < Width; j++)
                    {
    // Will 24 Bitwise RGB Conversion of color image to gray image
                        int temp = (int)(0.114 * (*ptr++)) + (int)(0.587 * (*ptr++))+(int)(0.299 * (*ptr++));
                        Data[i, j] = (byte)temp;
                    }
                    ptr += bmpData.Stride - Width * 3;// Pointer plus filled blank space
                }
            }
            bmp.UnlockBits(bmpData);
        }
        public GrayBitmapData(string path)
            : this(new Bitmap(path))
        {
        }
        public Bitmap ToBitmap()
        {
            Bitmap bmp=new Bitmap(Width,Height,PixelFormat.Format24bppRgb);
            BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,Width,Height),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
            unsafe
            {
                byte* ptr=(byte*)bmpData.Scan0.ToPointer();
                for(int i=0;i<Height;i++)
                {
                    for(int j=0;j<Width;j++)
                    {
                        *(ptr++)=Data[i,j];
                        *(ptr++)=Data[i,j];
                        *(ptr++)=Data[i,j];
                    }
                    ptr+=bmpData.Stride-Width*3;
                }
            }
            bmp.UnlockBits(bmpData);
            return bmp;
        }
        public void ShowImage(PictureBox pbx)
        {
            Bitmap b = this.ToBitmap();
            pbx.Image = b;
            //b.Dispose();
        }
        public void SaveImage(string path)
        {
            Bitmap b=ToBitmap();
            b.Save(path);
            //b.Dispose();
        }
// Mean filtering
        public void AverageFilter(int windowSize)
        {
            if (windowSize % 2 == 0)
            {
                return;
            }
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    int sum = 0;
                    for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
                    {
                        for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
                        {
                            int a = i + g, b = j + k;
                            if (a < 0) a = 0;
                            if (a > Height - 1) a = Height - 1;
                            if (b < 0) b = 0;
                            if (b > Width - 1) b = Width - 1;
                            sum += Data[a, b];
                        }
                    }
                    Data[i,j]=(byte)(sum/(windowSize*windowSize));
                }
            }
        }
// Median filtering
        public void MidFilter(int windowSize)
        {
            if (windowSize % 2 == 0)
            {
                return;
            }
            int[] temp = new int[windowSize * windowSize];
            byte[,] newdata = new byte[Height, Width];
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    int n = 0;
                    for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
                    {
                        for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
                        {
                            int a = i + g, b = j + k;
                            if (a < 0) a = 0;
                            if (a > Height - 1) a = Height - 1;
                            if (b < 0) b = 0;
                            if (b > Width - 1) b = Width - 1;
                            temp[n++]= Data[a, b];
                        }
                    }
                    newdata[i, j] = GetMidValue(temp,windowSize*windowSize);
                }
            }
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    Data[i, j] = newdata[i, j];
                }
            }
        }
// Obtain 1 Median of vectors
        private byte GetMidValue(int[] t, int length)
        {
            int temp = 0;
            for (int i = 0; i < length - 2; i++)
            {
                for (int j = i + 1; j < length - 1; j++)
                {
                    if (t[i] > t[j])
                    {
                        temp = t[i];
                        t[i] = t[j];
                        t[j] = temp;
                    }
                }
            }
            return (byte)t[(length - 1) / 2];
        }
//1 A new filtering method is brighter and darker
        public void NewFilter(int windowSize)
        {
            if (windowSize % 2 == 0)
            {
                return;
            }
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    int sum = 0;
                    for (int g = -(windowSize - 1) / 2; g <= (windowSize - 1) / 2; g++)
                    {
                        for (int k = -(windowSize - 1) / 2; k <= (windowSize - 1) / 2; k++)
                        {
                            int a = i + g, b = j + k;
                            if (a < 0) a = 0;
                            if (a > Height - 1) a = Height - 1;
                            if (b < 0) b = 0;
                            if (b > Width - 1) b = Width - 1;
                            sum += Data[a, b];
                        }
                    }
                    double avg = (sum+0.0) / (windowSize * windowSize);
                    if (avg / 255 < 0.5)
                    {
                        Data[i, j] = (byte)(2 * avg / 255 * Data[i, j]);
                    }
                    else
                    {
                        Data[i,j]=(byte)((1-2*(1-avg/255.0)*(1-Data[i,j]/255.0))*255);
                    }
                }
            }
        }
// Histogram equalization
        public void HistEqual()
        {
            double[] num = new double[256] ;
            for(int i=0;i<256;i++) num[i]=0;
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    num[Data[i, j]]++;
                }
            }
            double[] newGray = new double[256];
            double n = 0;
            for (int i = 0; i < 256; i++)
            {
                n += num[i];
                newGray[i] = n * 255 / (Height * Width);
            }
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    Data[i,j]=(byte)newGray[Data[i,j]];
                }
            }
        }
}
}

In the GrayBitmapData class, as long as we perform a series of operations on a 2-dimensional array Data, it is the operation processing of pictures. On the window, we can use the
1 button to make various calls:


// Mean filtering
private void btnAvgFilter_Click(object sender, EventArgs e)
{
    if (bmp == null) return;
    GrayBitmapData gbmp = new GrayBitmapData(bmp);
    gbmp.AverageFilter(3);
    gbmp.ShowImage(pbxShowImage);
}
// Convert to gray image
private void btnToGray_Click(object sender, EventArgs e)
{
    if (bmp == null) return;
    GrayBitmapData gbmp = new GrayBitmapData(bmp);
    gbmp.ShowImage(pbxShowImage);
}

4. Summary

To process or access images in Visual c #, it is necessary to establish an Bitmap object first, then obtain an BitmapData object by its LockBits method, and then operate the pixel data of Bitmap object by obtaining the first address of its pixel data. Of course, a simple but slow approach is to use the GetPixel and SetPixel methods of the Bitmap class. Where the Stride attribute of the BitmapData class is the bytes occupied by each row of pixels.


Related articles: