C#图像处理

 

(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)

 

 

 

一、各种旋转、改变大小

 

注意:先要添加画图相关的using引用。

 

//向右旋转图像90°代码如下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");//加载图像

g.FillRectangle(Brushes.White, this.ClientRectangle);//填充窗体背景为白色

Point[] destinationPoints = {

new Point(100, 0), // destination for upper-left point of original

new Point(100, 100),// destination for upper-right point of original

new Point(0, 0)}; // destination for lower-left point of original

g.DrawImage(bmp, destinationPoints);

 

}

 

 

//旋转图像180°代码如下:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");

g.FillRectangle(Brushes.White, this.ClientRectangle);

Point[] destinationPoints = {

new Point(0, 100), // destination for upper-left point of original

new Point(100, 100),// destination for upper-right point of original

new Point(0, 0)}; // destination for lower-left point of original

g.DrawImage(bmp, destinationPoints);

 

}

 

 

//图像切变代码:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");

g.FillRectangle(Brushes.White, this.ClientRectangle);

Point[] destinationPoints = {

new Point(0, 0), // destination for upper-left point of original

new Point(100, 0), // destination for upper-right point of original

new Point(50, 100)};// destination for lower-left point of original

g.DrawImage(bmp, destinationPoints);

 

}

 

 

//图像截取:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");

g.FillRectangle(Brushes.White, this.ClientRectangle);

Rectangle sr = new Rectangle(80, 60, 400, 400);//要截取的矩形区域

Rectangle dr = new Rectangle(0, 0, 200, 200);//要显示到Form的矩形区域

g.DrawImage(bmp, dr, sr, GraphicsUnit.Pixel);

 

}

 

 

//改变图像大小:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");

g.FillRectangle(Brushes.White, this.ClientRectangle);

int width = bmp.Width;

int height = bmp.Height;

// 改变图像大小使用低质量的模式

g.InterpolationMode = InterpolationMode.NearestNeighbor;

g.DrawImage(bmp, new Rectangle(10, 10, 120, 120), // source rectangle

 

new Rectangle(0, 0, width, height), // destination rectangle

GraphicsUnit.Pixel);

// 使用高质量模式

//g.CompositingQuality = CompositingQuality.HighSpeed;

g.InterpolationMode = InterpolationMode.HighQualityBicubic;

g.DrawImage(

bmp,

new Rectangle(130, 10, 120, 120), 

new Rectangle(0, 0, width, height),

GraphicsUnit.Pixel);

 

}

 

 

//设置图像的分辩率:

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Bitmap bmp = new Bitmap("rama.jpg");

g.FillRectangle(Brushes.White, this.ClientRectangle);

bmp.SetResolution(300f, 300f);

g.DrawImage(bmp, 0, 0);

bmp.SetResolution(1200f, 1200f);

g.DrawImage(bmp, 180, 0);

 

}

 

 

//用GDI+画图

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics gForm = e.Graphics;

gForm.FillRectangle(Brushes.White, this.ClientRectangle);

for (int i = 1; i <= 7; ++i)

{

 

//在窗体上面画出橙色的矩形

 

Rectangle r = new Rectangle(i*40-15, 0, 15,

this.ClientRectangle.Height);

gForm.FillRectangle(Brushes.Orange, r);

 

}

 

//在内存中创建一个Bitmap并设置CompositingMode

Bitmap bmp = new Bitmap(260, 260,

 

System.Drawing.Imaging.PixelFormat.Format32bppArgb);

Graphics gBmp = Graphics.FromImage(bmp);

gBmp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;

// 创建一个带有Alpha的红色区域

// 并将其画在内存的位图里面

Color red = Color.FromArgb(0x60, 0xff, 0, 0);

Brush redBrush = new SolidBrush(red);

gBmp.FillEllipse(redBrush, 70, 70, 160, 160);

// 创建一个带有Alpha的绿色区域

Color green = Color.FromArgb(0x40, 0, 0xff, 0);

Brush greenBrush = new SolidBrush(green);

gBmp.FillRectangle(greenBrush, 10, 10, 140, 140);

//在窗体上面画出位图 now draw the bitmap on our window

gForm.DrawImage(bmp, 20, 20, bmp.Width, bmp.Height);

// 清理资源

bmp.Dispose();

gBmp.Dispose();

redBrush.Dispose();

greenBrush.Dispose();

 

}

 

 

//在窗体上面绘图并显示图像

private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)

{

 

Graphics g = e.Graphics;

Pen blackPen = new Pen(Color.Black, 1);

 

if (ClientRectangle.Height / 10 > 0)

 

{

 

for (int y = 0; y < ClientRectangle.Height; y += ClientRectangle.Height / 10)

 

{

 

g.DrawLine(blackPen, new Point(0, 0), new Point(ClientRectangle.Width, y));

 

}

 

}

 

blackPen.Dispose();

 

}

 

 

 

C# 使用Bitmap类进行图片裁剪 

 

 

 

 在Mapwin(手机游戏地图编辑器)生成的地图txt文件中添加自己需要处理的数据后转换成可在手机(Ophone)开发环境中使用的字节流地图文件的小工具,其中就涉及到图片的裁剪和生成了。有以下几种方式。

 

 

 

方法一:拷贝像素。

 

 

 

当然这种方法是最笨的,效率也就低了些。

 

在Bitmap类中我们可以看到这样两个方法:GetPixel(int x, int y)和SetPixel(int x, int y, Color color)方法。从字面的含以上就知道前者是获取图像某点像素值,是用Color对象返回的;后者是将已知像素描画到制定的位置。

 

下面就来做个实例检验下:

 

1.首先创建一个Windows Form窗体程序,往该窗体上拖放7个PictureBox控件,第一个用于放置并显示原始的大图片,其后6个用于放置并显示裁剪后新生成的6个小图;

 

2.放置原始大图的PictureBox控件name属性命名为pictureBoxBmpRes,其后pictureBox1到pictureBox6依次命名,并放置在合适的位置;

 

3.双击Form窗体,然后在Form1_Load事件中加入下面的代码即可。

 

//导入图像资源

 

            Bitmap bmpRes = null;

 

            String strPath = Application.ExecutablePath;

 

            try{

 

                int nEndIndex = strPath.LastIndexOf('//');

 

                strPath = strPath.Substring(0,nEndIndex) + "//Bmp//BmpResMM.bmp";

 

                bmpRes = new Bitmap(strPath);

 

 

 

                //窗体上显示加载图片

 

                pictureBoxBmpRes.Width = bmpRes.Width;

 

                pictureBoxBmpRes.Height = bmpRes.Height;

 

                pictureBoxBmpRes.Image = bmpRes;

 

            }

 

            catch(Exception ex)

 

            {

 

               System.Windows.Forms.MessageBox.Show("图片资源加载失败!/r/n" + ex.ToString());

 

            }

 

 

 

            //裁剪图片(裁成2行3列的6张图片)

 

            int nYClipNum = 2, nXClipNum = 3;

 

            Bitmap[] bmpaClipBmpArr = new Bitmap[nYClipNum * nXClipNum];            

 

            for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++) 

 

            {

 

                for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++) 

 

                {

 

                    int nClipWidth = bmpRes.Width / nXClipNum;

 

                    int nClipHight = bmpRes.Height / nYClipNum;

 

                    int nBmpIndex = nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);

 

                    bmpaClipBmpArr[nBmpIndex] = new Bitmap(nClipWidth, nClipHight);

 

 

 

                    for(int nY = 0; nY < nClipHight; nY++)

 

                    {

 

                        for(int nX = 0; nX < nClipWidth; nX++)

 

                        {

 

                            int nClipX = nX + nClipWidth * nXClipNumIndex;

 

                            int nClipY = nY + nClipHight * nYClipNumIndex;

 

                            Color cClipPixel = bmpRes.GetPixel(nClipX, nClipY);

 

                            bmpaClipBmpArr[nBmpIndex].SetPixel(nX, nY, cClipPixel);

 

                        }

 

                    }                    

 

                }

 

            }

 

            PictureBox[] picbShow = new PictureBox[nYClipNum * nXClipNum];

 

            picbShow[0] = pictureBox1;

 

            picbShow[1] = pictureBox2;

 

            picbShow[2] = pictureBox3;

 

            picbShow[3] = pictureBox4;

 

            picbShow[4] = pictureBox5;

 

            picbShow[5] = pictureBox6;

 

            for (int nLoop = 0; nLoop < nYClipNum * nXClipNum; nLoop++) 

 

            {

 

                picbShow[nLoop].Width = bmpRes.Width / nXClipNum;

 

                picbShow[nLoop].Height = bmpRes.Height / nYClipNum;

 

                picbShow[nLoop].Image = bmpaClipBmpArr[nLoop];                

 

            }

 

 现在看看那些地方需要注意的了。其中

 

int nBmpIndex = 

 

nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0?1:0);

 

 这句定义了存储裁剪图片对象在数组中的索引,需要注意的就是后面的(nYClipNumIndex > 0?1:0)——因为只有当裁剪的对象处于第一行以外的行时需要将索引加1;

 

另外,因为这种方法的效率不高,程序运行起来还是顿了下。如果有兴趣的话,可以将以上的代码放到一个按钮Click事件函数中,当单击该按钮时就可以感觉到了。

 

 

 

 方法二:运用Clone函数局部复制。

 

 

 

同样在Bitmap中可以找到Clone()方法,该方法有三个重载方法。Clone(),Clone(Rectangle, PixelFormat)和Clone(RectangleF, PixelFormat)。第一个方法将创建并返回一个精确的实例对象,后两个就是我们这里需要用的局部裁剪了(其实后两个方法本人觉得用法上差不多)。

 

将上面的程序稍稍改进下——将裁剪的处理放到一个按钮事件函数中,然后再托一个按钮好窗体上,最后将下面的代码复制到该按钮的事件函数中。

 

for (int nYClipNumIndex = 0; nYClipNumIndex < nYClipNum; nYClipNumIndex++)

 

{

 

       for (int nXClipNumIndex = 0; nXClipNumIndex < nXClipNum; nXClipNumIndex++)

 

         {

 

              int nClipWidth = bmpRes.Width / nXClipNum;

 

                      int nClipHight = bmpRes.Height / nYClipNum;

 

                int nBmpIndex = 

 

nXClipNumIndex + nYClipNumIndex * nYClipNum + (nYClipNumIndex > 0 ? 1 : 0);

 

              

 

        Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,

 

                                                            nClipHight * nYClipNumIndex,

 

                                                            nClipWidth, 

 

                                                            nClipHight);

 

              

 

                bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);

 

            }

 

}

 

 

 

 运行程序,单击按钮检验下,发现速度明显快可很多。

 

其实这种方法较第一中方法不同的地方仅只是变换了for循环中的拷贝部分的处理,

 

Rectangle rClipRect = new Rectangle(nClipWidth * nXClipNumIndex,

 

                                                            nClipHight * nYClipNumIndex,

 

                                                            nClipWidth, 

 

                                                            nClipHight);

 

 

 

bmpaClipBmpArr[nBmpIndex] = bmpRes.Clone(rClipRect, bmpRes.PixelFormat);

 

 

 

 

 

 

 

 

 

一. 底片效果

原理: GetPixel方法获得每一点像素的值, 然后再使用SetPixel方法将取反后的颜色值设置到对应的点.

效果图: 

 

 

 

 

代码实现:

 

          private void button1_Click(object sender, EventArgs e)

        {

            //以底片效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap newbitmap = new Bitmap(Width, Height);

                Bitmap oldbitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel;

                for (int x = 1; x < Width; x++)

                {

                    for (int y = 1; y < Height; y++)

                    {

                        int r, g, b;

                        pixel = oldbitmap.GetPixel(x, y);

                        r = 255 - pixel.R;

                        g = 255 - pixel.G;

                        b = 255 - pixel.B;

                        newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b));

                    }

                }

                this.pictureBox1.Image = newbitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

            }

        }

 

二. 浮雕效果

 

原理: 对图像像素点的像素值分别与相邻像素点的像素值相减后加上128, 然后将其作为新的像素点的值.

 

效果图:

 

 

 

 

 

 

 

 

 

 

 

 

 

代码实现:

 

 

       private void button1_Click(object sender, EventArgs e)

        {

            //以浮雕效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap newBitmap = new Bitmap(Width, Height);

                Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel1, pixel2;

                for (int x = 0; x < Width - 1; x++)

                {

                    for (int y = 0; y < Height - 1; y++)

                    {

                        int r = 0, g = 0, b = 0;

                        pixel1 = oldBitmap.GetPixel(x, y);

                        pixel2 = oldBitmap.GetPixel(x + 1, y + 1);

                        r = Math.Abs(pixel1.R - pixel2.R + 128);

                        g = Math.Abs(pixel1.G - pixel2.G + 128);

                        b = Math.Abs(pixel1.B - pixel2.B + 128);

                        if (r > 255)

                            r = 255;

                        if (r < 0)

                            r = 0;

                        if (g > 255)

                            g = 255;

                        if (g < 0)

                            g = 0;

                        if (b > 255)

                            b = 255;

                        if (b < 0)

                            b = 0;

                        newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));

                    }

                }

                this.pictureBox1.Image = newBitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

            }

        }

 

三. 黑白效果

 

原理: 彩色图像处理成黑白效果通常有3种算法;

 

(1).最大值法: 使每个像素点的 R, G, B 值等于原像素点的 RGB (颜色值) 中最大的一个;

 

(2).平均值法: 使用每个像素点的 R,G,B值等于原像素点的RGB值的平均值;

 

(3).加权平均值法: 对每个像素点的 R, G, B值进行加权

 

      ---自认为第三种方法做出来的黑白效果图像最 "真实".

 

效果图:

 

 

 

 

 

 

 

 

 

 

 

代码实现:

 

 

        private void button1_Click(object sender, EventArgs e)

        {

            //以黑白效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap newBitmap = new Bitmap(Width, Height);

                Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel;

                for (int x = 0; x < Width; x++)

                    for (int y = 0; y < Height; y++)

                    {

                        pixel = oldBitmap.GetPixel(x, y);

                        int r, g, b, Result = 0;

                        r = pixel.R;

                        g = pixel.G;

                        b = pixel.B;

                        //实例程序以加权平均值法产生黑白图像

                        int iType =2;

                        switch (iType)

                        {

                            case 0://平均值法

                                Result = ((r + g + b) / 3);

                                break;

                            case 1://最大值法

                                Result = r > g ? r : g;

                                Result = Result > b ? Result : b;

                                break;

                            case 2://加权平均值法

                                Result = ((int)(0.7 * r) + (int)(0.2 * g) + (int)(0.1 * b));

                                break;

                        }

                        newBitmap.SetPixel(x, y, Color.FromArgb(Result, Result, Result));

                    }

                this.pictureBox1.Image = newBitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示");

            }

        }

 

 

 

四. 柔化效果

 

原理: 当前像素点与周围像素点的颜色差距较大时取其平均值.

 

效果图:

 

 

 

 

 

 

 

 

 

 

 

代码实现:

 

 

        private void button1_Click(object sender, EventArgs e)

        {

            //以柔化效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap bitmap = new Bitmap(Width, Height);

                Bitmap MyBitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel;

                //高斯模板

                int[] Gauss ={ 1, 2, 1, 2, 4, 2, 1, 2, 1 };

                for (int x = 1; x < Width - 1; x++)

                    for (int y = 1; y < Height - 1; y++)

                    {

                        int r = 0, g = 0, b = 0;

                        int Index = 0;

                        for (int col = -1; col <= 1; col++)

                            for (int row = -1; row <= 1; row++)

                            {

                                pixel = MyBitmap.GetPixel(x + row, y + col);

                                r += pixel.R * Gauss[Index];

                                g += pixel.G * Gauss[Index];

                                b += pixel.B * Gauss[Index];

                                Index++;

                            }

                        r /= 16;

                        g /= 16;

                        b /= 16;

                        //处理颜色值溢出

                        r = r > 255 ? 255 : r;

                        r = r < 0 ? 0 : r;

                        g = g > 255 ? 255 : g;

                        g = g < 0 ? 0 : g;

                        b = b > 255 ? 255 : b;

                        b = b < 0 ? 0 : b;

                        bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));

                    }

                this.pictureBox1.Image = bitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示");

            }

        }

 

五.锐化效果

 

原理:突出显示颜色值大(即形成形体边缘)的像素点.

 

效果图:

 

 

 

 

 

 

 

 

 

 

 

实现代码:

 

 

       private void button1_Click(object sender, EventArgs e)

        {

            //以锐化效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap newBitmap = new Bitmap(Width, Height);

                Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel;

                //拉普拉斯模板

                int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 };

                for (int x = 1; x < Width - 1; x++)

                    for (int y = 1; y < Height - 1; y++)

                    {

                        int r = 0, g = 0, b = 0;

                        int Index = 0;

                        for (int col = -1; col <= 1; col++)

                            for (int row = -1; row <= 1; row++)

                            {

                                pixel = oldBitmap.GetPixel(x + row, y + col); r += pixel.R * Laplacian[Index];

                                g += pixel.G * Laplacian[Index];

                                b += pixel.B * Laplacian[Index];

                                Index++;

                            }

                        //处理颜色值溢出

                        r = r > 255 ? 255 : r;

                        r = r < 0 ? 0 : r;

                        g = g > 255 ? 255 : g;

                        g = g < 0 ? 0 : g;

                        b = b > 255 ? 255 : b;

                        b = b < 0 ? 0 : b;

                        newBitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));

                    }

                this.pictureBox1.Image = newBitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示");

            }

        }

 

六. 雾化效果

 

原理: 在图像中引入一定的随机值, 打乱图像中的像素值

 

效果图:

 

 

 

 

 

 

 

 

 

 

实现代码:

 

 

       private void button1_Click(object sender, EventArgs e)

        {

            //以雾化效果显示图像

            try

            {

                int Height = this.pictureBox1.Image.Height;

                int Width = this.pictureBox1.Image.Width;

                Bitmap newBitmap = new Bitmap(Width, Height);

                Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;

                Color pixel;

                for (int x = 1; x < Width - 1; x++)

                    for (int y = 1; y < Height - 1; y++)

                    {

                        System.Random MyRandom = new Random();

                        int k = MyRandom.Next(123456);

                        //像素块大小

                        int dx = x + k % 19;

                        int dy = y + k % 19;

                        if (dx >= Width)

                            dx = Width - 1;

                        if (dy >= Height)

                            dy = Height - 1;

                        pixel = oldBitmap.GetPixel(dx, dy);

                        newBitmap.SetPixel(x, y, pixel);

                    }

                this.pictureBox1.Image = newBitmap;

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message, "信息提示");

            }

        }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

浅谈Visual C#进行图像处理

 

 

 

作者:彭军 http://pengjun.org.cn

 

这里之所以说“浅谈”是因为我这里只是简单的介绍如何使用Visual C#进行图像的读入、保存以及对像素的访问。而不涉及太多的算法。

 

一、读入图像

 

在Visual C#中我们可以使用一个Picture Box控件来显示图片,如下:

        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("加载图片失败!", "错误");

                    return;

                }

                pbxShowImage.Image = bmp;

                ofd.Dispose();

            }

        }

其中bmp为类的一个对象:private Bitmap bmp=null;

在使用Bitmap类和BitmapData类之前,需要使用using System.Drawing.Imaging;

二、保存图像

        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("保存成功!","提示");

                sfd.Dispose();

            }

        }

三、对像素的访问

我们可以来建立一个GrayBitmapData类来做相关的处理。整个类的程序如下:

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;//保存像素矩阵

        public int Width;//图像的宽度

        public int Height;//图像的高度

 

        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++)

                    {

    //将24位的RGB彩色图转换为灰度图

                        int temp = (int)(0.114 * (*ptr++)) + (int)(0.587 * (*ptr++))+(int)(0.299 * (*ptr++));

                        Data[i, j] = (byte)temp;

                    }

                    ptr += bmpData.Stride - Width * 3;//指针加上填充的空白空间

                }

            }

            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();

        }

//均值滤波

        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));

                }

            }

        }

//中值滤波

        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];

                }

            }

        }

//获得一个向量的中值

        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];

        }

//一种新的滤波方法,是亮的更亮、暗的更暗

        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);

                    }

                }

            }

        }

//直方图均衡

        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]];

                }

            }

        }

 

}

}

在GrayBitmapData类中,只要我们对一个二维数组Data进行一系列的操作就是对图片的操作处理。在窗口上,我们可以使用

一个按钮来做各种调用:

//均值滤波

        private void btnAvgFilter_Click(object sender, EventArgs e)

        {

            if (bmp == null) return;

            GrayBitmapData gbmp = new GrayBitmapData(bmp);

            gbmp.AverageFilter(3);

            gbmp.ShowImage(pbxShowImage);

        }

//转换为灰度图

        private void btnToGray_Click(object sender, EventArgs e)

        {

            if (bmp == null) return;

            GrayBitmapData gbmp = new GrayBitmapData(bmp);

            gbmp.ShowImage(pbxShowImage);

        }

 

 

 

四、总结

 

在Visual c#中对图像进行处理或访问,需要先建立一个Bitmap对象,然后通过其LockBits方法来获得一个BitmapData类的对象,然后通过获得其像素数据的首地址来对Bitmap对象的像素数据进行操作。当然,一种简单但是速度慢的方法是用Bitmap类的GetPixel和SetPixel方法。其中BitmapData类的Stride属性为每行像素所占的字节。

 

 

C# (GDI+相关) 图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)的更多相关文章

  1. 黄聪:C#图像处理(各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果) (转)

    一.各种旋转.改变大小 注意:先要添加画图相关的using引用. //向右旋转图像90°代码如下:private void Form1_Paint(object sender, System.Wind ...

  2. C# 使用 GDI+ 实现添加中心旋转(任意角度)的文字

    这篇文章是 GDI+ 总结系列的第三篇,如果对 GDI+ 的基础使用不熟悉的朋友可以先看第一篇文章<C# 使用 GDI+ 画图>. 需求 需求是要实现给图片添加任意角度旋转的文字,文字的旋 ...

  3. JS实现漂亮的窗口拖拽效果(可改变大小、最大化、最小化、关闭)

    转自<JS实现漂亮的窗口拖拽效果(可改变大小.最大化.最小化.关闭)>:http://www.jb51.net/article/73157.htm   这篇文章主要介绍了JS实现漂亮的窗口 ...

  4. GDI+简单现实文字旋转

    原文 http://www.cnblogs.com/kaixiangbb/p/3301272.html 题记 入职新公司已快有两月了,试用期已快结束,项目却迟迟还未正式启动.安排给我的多是些琐事,一直 ...

  5. 【转】C# 控件的自定义拖动、改变大小方法

    在用VS的窗体设计器时,我们可以发现控件都是可以拖动的,并且还可以调整大小.怎么在自己的程序中可以使用上述功能呢? 下面的方法值得借鉴! using System; using System.Wind ...

  6. Qt 无边框窗体改变大小 完美实现(全部自己实现)

    近期,做项目用到无边框窗体,令人蛋疼的是无边框窗体大小的改变要像右边框那样,上下左右四周,而且要流畅. 网上也找了些代码,发现居然还要连接到windows事件,这显然不合常理,后来自己新建了demo, ...

  7. Qt:无标题栏无边框程序的拖动和改变大小

    From: http://blog.csdn.net/kfbyj/article/details/9284923 最近做项目遇到的问题,总结下. 有时候我们觉得系统的标题栏和按钮太丑太呆板,想做自己的 ...

  8. WPF 窗体中的 Canvas 限定范围拖动 鼠标滚轴改变大小

    xaml代码: <Canvas Name="movBg"> <Canvas.Background> <LinearGradientBrush EndP ...

  9. windows 编程 —— 消息与参数(定时器、初始化消息、改变大小)

    目录: 定时器 WM_TIMER 初始化消息 WM_CREATE 改变大小 WM_SIZE 定时器: 接收消息:WM_TIMER 参数wParam:wParam参数等于定时器的ID值(上述情形为1). ...

随机推荐

  1. Shell_Shell调用SQLPlus简介(案例)

    2014-06-20  Created By BaoXinjian

  2. GL_GL系列 - 预算管理分析(案例)

    2014-07-09 Created By BaoXinjian

  3. poj 1011 Sticks

    Sticks Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 126238   Accepted: 29477 Descrip ...

  4. nyoj 284 坦克大战 (优先队列)

    题目链接:http://acm.nyist.net/JudgeOnline/status.php?pid=284 特殊数据: 5 5 BBEEY EEERB SSERB SSERB SSETB 7 非 ...

  5. 庭审精彩语录整理 z

    公诉人:用百度搜索淫秽关键字+快播,搜索结果得出超过4200万结果,可见快播在传播淫秽视频方面的巨大影响.王欣:这个没有任何意义,您可以用百度搜索淫秽关键字+QQ看有多少结果. 新浪科技讯 1月8日下 ...

  6. dede文章页调用当前栏目链接方法

    DedeCMS内容页调用当前栏目其实用下来是调用不出来的,{dede:field.typename/}是有效的,可是 {dede:field.typeurl/}却调不出文档当前栏目所在目录链接URL. ...

  7. Java中的Property类

    Property是JAVA中的属性操作类,该类在java.util包中,它是HashTable的子类. 常用函数列表: l  Properties() n  构造函数 l  setProperty(S ...

  8. Innosetup中将bat文件压缩到压缩包中

      有时候在安装的过程中需要调用某些文件(bat或者exe等文件),但是只需要使用一次,然后就可以删掉该文件, 在Innosetup中应该这样操作: 1.在.iss脚本的[Files]章节写下: So ...

  9. 第二章 I - The 3n + 1 problem(2.4.2)

    这是一道很坑爹的题,一定注意输入的两个数的大小,并且不能简单的交换,因为在最后的输出的时候还需要将原来的数按照原来的顺序和大小,这就是为什么还得开辟两个值得原因 Description Problem ...

  10. [转]dispatcher、redirect和chain三种result type的使用区别

    http://blog.163.com/zhangfei_jiayou/blog/static/562441782009826045248/ dispatcher:用于页面转发,页面跳转过程一直是同一 ...