C# 数字图像处理

高手!在C#中如何利用picturebox来显示图片?

 
 
我想利用visual studio 平台编写一个小程序,用c#来实现,但是遇到了困难,如何利用picturebox来显示?我想设置一个按钮,单击时让picturebox显示图片。要怎么办啊?高手求救一下!在输入图片路径时出错,要怎么解决呢?(要详细代码!)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void pictureBox1_Click(object sender, EventArgs e)
{


}

private void button1_Click(object sender, EventArgs e)
{

Image img = Image.FromFile(@"F:\picture\q.jpg");//双引号里是图片的路径

pictureBox1.Image = img;
}

}
}
 
在Win窗体放三个控件
"Button1" "picturebox1" 和对话框"openFileDialog1"
然后写"Button"的Onclick事件
DialogResult result = openFileDialog1.ShowDialog();//声明一个对话框
if (result == DialogResult.OK)//判断对话框是否被选中
{
pictureBox1.ImageLocation = openFileDialog1.FileName;//pictureBox显示被对话框选中的图片
}

可以设置openFileDialog1的Filer属性来设置选择图片的格式
希望你能满意
 
 
 
 
 
 
 
 
 
 
 

C#用picturebox来显示图片

 
 
第一种方法:



string ImgPath;

private void btn_show_Click(object sender, EventArgs e)

{


pBox_zj.Image = Image.FromFile(ImgPath);

}





private void btn_Choose_Click(object sender, EventArgs e)

{


openFileDialog1.Filter = "*jpg|*jpg|*bmp|*bmp";


if (openFileDialog1.ShowDialog() == DialogResult.OK)


{



FileInfo finfo = new FileInfo(openFileDialog1.FileName);



ImgPath = "BookImage\\"+finfo.Name;


}

}
第二种方法:

private void btn_show_Click(object sender, EventArgs e)

{


pBox_zj.Image = Image.FromFile("BookImage\\01.jpg");

}

现在问题是,为什么第一种方法不行,第二种放行?
"BookImage\\"+finfo.name其实就是"BookImage\01.jpg",
为什么第一种方法老是提示错误:BookImage\01.jpg.
谁能告诉我?十分感谢!
 
penFileDialog1.FileName本来就是全路径,在楼主程序里
openFileDialog1.FileName=="BookImage\01.jpg";ok?楼主还要把多其余操作,是不是画蛇添足呢?
直接ImgPath=openFileDialog1.FileName;
当然楼主这么写当然是想验证一下第一种方法的可行性,那我告诉楼主,第一种可行,本人做过实验,可以通过,不存在楼主所说的问题
楼主好好检查下代码
方法老是提示错误:BookImage\01.jpg. 这里的.是楼主加的还是提示就有呢,如果提示就有错误就在这里了

string strFileDir = System.IO.Path.GetDirectoryName(flg.FileName)
获取文件名用这个方法比较好,楼主的方法不好
第二:
ImgPath = "BookImage\\"+finfo.Name;这种方法可行,我验证过
第三:
我睡觉去了,很晚了
 
 

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

 

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# colorMatrix 对图片的处理 : 亮度调整 抓屏 翻转 随鼠标画矩形

 

1.图片亮度处理

 

        private void btn_Grap_Click(object sender, EventArgs e)

        {

            //亮度百分比

            int percent = 50;

            Single v = 0.006F * percent;    

            Single[][] matrix = {         

                new Single[] { 1, 0, 0, 0, 0 },         

                new Single[] { 0, 1, 0, 0, 0 },          

                new Single[] { 0, 0, 1, 0, 0 },         

                new Single[] { 0, 0, 0, 1, 0 },         

                new Single[] { v, v, v, 0, 1 }     

            };    

            System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix);

            System.Drawing.Imaging.ImageAttributes attr = new System.Drawing.Imaging.ImageAttributes();    

            attr.SetColorMatrix(cm);    

            //Image tmp 

            Image tmp = Image.FromFile("1.png");

 

            this.pictureBox_Src.Image = Image.FromFile("1.png");

 

            Graphics g = Graphics.FromImage(tmp);  

            try  

            {

                Rectangle destRect = new Rectangle(0, 0, tmp.Width, tmp.Height);        

                g.DrawImage(tmp, destRect, 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, attr);    

            }    

            finally    

            {        

                g.Dispose();    

            }

 

            this.pictureBox_Dest.Image = (Image)tmp.Clone();

        }

 

 

2.抓屏将生成的图片显示在pictureBox

 

        private void btn_Screen_Click(object sender, EventArgs e)

        {

            Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);

            Graphics g = Graphics.FromImage(myImage);

            g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height));

            //IntPtr dc1 = g.GetHdc();      //此处这两句多余,具体看最后GetHdc()定义

            //g.ReleaseHdc(dc1);           

            g.Dispose();

            this.pictureBox_Src.SizeMode = PictureBoxSizeMode.StretchImage;

            this.pictureBox_Src.Image = myImage;

            myImage.Save("Screen", ImageFormat.Png);

     }

 

3.翻转

 

        private void btn_RotateFlip_Click(object sender, EventArgs e)

        {

            this.pictureBox_Src.Image = Image.FromFile("1.png");

 

            Image tmp = Image.FromFile("1.png");

 

            tmp.RotateFlip(RotateFlipType.Rotate90FlipNone);

            this.pictureBox_Dest.Image = tmp;

        }

4.跟随鼠标在 pictureBox的图片上画矩形

        private int intStartX = 0;

        private int intStartY = 0;

        private bool isMouseDraw = false;

 

        private void pictureBox_Src_MouseDown(object sender, MouseEventArgs e)

        {

            isMouseDraw = true;

 

            intStartX = e.X;

            intStartY = e.Y;

        }

 

        private void pictureBox_Src_MouseMove(object sender, MouseEventArgs e)

        {

            if (isMouseDraw)

            {

                try

                {

                    //Image tmp = Image.FromFile("1.png");

                    Graphics g = this.pictureBox_Src.CreateGraphics();

                    //清空上次画下的痕迹

                    g.Clear(this.pictureBox_Src.BackColor);

                    Brush brush = new SolidBrush(Color.Red);

                    Pen pen = new Pen(brush, 1);

                    pen.DashStyle = DashStyle.Solid;

                    g.DrawRectangle(pen, new Rectangle(intStartX > e.X ? e.X : intStartX, intStartY > e.Y ? e.Y :intStartY, Math.Abs(e.X - intStartX), Math.Abs(e.Y - intStartY)));

                    g.Dispose();

                    //this.pictureBox_Src.Image = tmp;

                }

                catch (Exception ex)

                {

                    ex.ToString();

                }

            }

        }

 

        private void pictureBox_Src_MouseUp(object sender, MouseEventArgs e)

        {

            isMouseDraw = false;

 

            intStartX = 0;

            intStartY = 0;

        }

5.取灰度

 

        private void btn_GetGray_Click(object sender, EventArgs e)

        {

            this.pictureBox_Src.Image = Image.FromFile("1.png");

            Bitmap currentBitmap = new Bitmap(this.pictureBox_Src.Image);

            Graphics g = Graphics.FromImage(currentBitmap);

            ImageAttributes ia = new ImageAttributes();

            float[][] colorMatrix =   {    

                new   float[]   {0.299f,   0.299f,   0.299f,   0,   0},

                new   float[]   {0.587f,   0.587f,   0.587f,   0,   0},

                new   float[]   {0.114f,   0.114f,   0.114f,   0,   0},

                new   float[]   {0,   0,   0,   1,   0},

                new   float[]   {0,   0,   0,   0,   1}

            };

            ColorMatrix cm = new ColorMatrix(colorMatrix);

            ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            g.DrawImage(currentBitmap, new Rectangle(0, 0, currentBitmap.Width, currentBitmap.Height), 0, 0,currentBitmap.Width, currentBitmap.Height, GraphicsUnit.Pixel, ia);

            this.pictureBox_Dest.Image = (Image)(currentBitmap.Clone());

            g.Dispose();

        }

 

 

 

 

Graphics.GetHdc 方法

.NET Framework 4

 

获取与此 Graphics 关联的设备上下文的句柄。

命名空间:  System.Drawing
程序集:  System.Drawing(在 System.Drawing.dll 中)

语法

[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags =

SecurityPermissionFlag.UnmanagedCode)]

public IntPtr GetHdc()

返回值

类型:System.IntPtr
与此 Graphics 关联的设备上下文的句柄。

实现

IDeviceContext.GetHdc()

备注


设备上下文是一个基于 GDI 的 Windows 结构,它定义一组图形对象及其关联的特性,以及影响输出的图形模式。 此方法返回该设备上下文(字体除外)。由于未选择字体,使用 GetHdc 方法返回的句柄对 FromHdc 方法进行调用将会失败。

GetHdc 方法调用和 ReleaseHdc 方法调用必须成对出现。 在 GetHdc 和 ReleaseHdc 方法对的范围内,通常仅调用 GDI 函数。 在该范围内对 Graphics(它产生 hdc 参数)的 GDI+ 方法的调用因 ObjectBusy 错误而失败。 此外,GDI+ 忽略后续操作中对 hdc 参数的 Graphics 所做的所有状态更改。

示例


下面的代码示例设计为与 Windows 窗体一起使用,它需要 PaintEventArgse,即 Paint 事件处理程序的一个参数。 该示例演示如何调用 Windows GDI 函数以执行与 GDI+ Graphics 方法相同的任务。 代码执行下列操作:

  • 为 Windows DLL 文件 gdi32.dll 定义互操作性 DllImportAttribute 特性。 此 DLL 包含所需的 GDI 函数。
  • 将该 DLL 中的 Rectangle 函数定义为外部函数。
  • 创建一支红色钢笔。
  • 利用该钢笔,使用 GDI+ DrawRectangle 方法将矩形绘制到屏幕。
  • 定义内部指针类型变量 hdc 并将它的值设置为窗体的设备上下文句柄。
  • 使用 GDI Rectangle 函数将矩形绘制到屏幕。

释放由 hdc 参数表示的设备上下文。

 

public class GDI

{

    [System.Runtime.InteropServices.DllImport("gdi32.dll")]

    internal static extern bool Rectangle(

       IntPtr hdc,

       int ulCornerX, int ulCornerY,

       int lrCornerX, int lrCornerY);

}

 

[System.Security.Permissions.SecurityPermission(

System.Security.Permissions.SecurityAction.LinkDemand, Flags =

System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]           

private void GetHdcForGDI1(PaintEventArgs e)

{

    // Create pen.

    Pen redPen = new Pen(Color.Red, 1);

 

    // Draw rectangle with GDI+.

    e.Graphics.DrawRectangle(redPen, 10, 10, 100, 50);

 

    // Get handle to device context.

    IntPtr hdc = e.Graphics.GetHdc();

 

    // Draw rectangle with GDI using default pen.

    GDI.Rectangle(hdc, 10, 70, 110, 120);

 

    // Release handle to device context.

    e.Graphics.ReleaseHdc(hdc);

}

 

 

 

 

 

更多0
 
查看评论
14楼 yelaizuozuo 2013-12-06 15:56发表 [回复]
膜拜一个,有空学学
13楼 pachleng 2013-11-07 11:28发表 [回复]
改变大小的注释,似乎颠倒了source和destination
12楼 zhanwei103 2013-09-24 10:29发表 [回复]
丫的,楼主你好强!我也是C#开发的,交个朋友呗!!!QQ:244529012
11楼 孤独旅者 2013-08-01 00:39发表 [回复]
很强啊,果断转载!
10楼 锋行 2013-07-09 17:13发表 [回复]
学习了,谢谢博主
9楼 MrCoder 2013-05-22 00:32发表 [回复]
真的很不错!
8楼 xu_yu123 2013-04-18 14:06发表 [回复]
请问一下,如果是任意角度的旋转应该怎么做呢
Re: jiangxinyu 2013-04-19 10:31发表 [回复]
回复xu_yu123:任意角度旋转就需要自己计算出点的位置,通过三角函数,只不过90度,180度这种特殊的角度,旋转后点的位置口算就可以得出,所以直接用了,
Re: hh213___ 2013-04-27 20:58发表 [回复]
回复jiangxinyu:但是用了三角函数还是没反应呀
Re: jiangxinyu 2013-04-28 09:46发表 [回复]
回复hh213___:你可以这样测试一下:
Point[] destinationPoints = {
new Point(15, 100), // destination for upper-left point of original
new Point(100, 50),// destination for upper-right point of original
new Point(0, 0)}; // destination for lower-left point of original
把这里面的三个点的坐标值,随便改动一下,你看看有没有效果,如果有那可能是你代码什么地方有问题;
我测试,是有效果的。比如上面那些值是我随手改的,图片显示出来已经发生改变了
7楼 xuqiao5022339 2013-03-27 16:32发表 [回复]
很强啊,L主,如果图像雾化的那个效果在MATLAB里要怎么实现呢
6楼 sinuosnow 2013-03-01 12:01发表 [回复]
顶个~~~
5楼 Carecluse 2013-01-06 08:46发表 [回复]
很好,很强大!
4楼 nightwish_wuming 2012-12-12 15:19发表 [回复]
强顶。。。
3楼 smile06 2012-11-15 23:17发表 [回复]
很好~~
2楼 huntions0815 2012-04-01 21:28发表 [回复]
学习了
1楼 Mr_graceless 2011-12-14 17:19发表 [回复] [引用] [举报]
好文。。

C#图像处理

2009-11-01  来自:网上整理  字体大小:【  
  • 摘要:本文介绍C#图像处理用到的Bitmap类和BitmapData类的相关知识,并实现一个图像灰度处理的例子。

一.Bitmap

Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下:

1.       GetPixel方法和 SetPixel方法:获取和设置一个图像的指定像素的颜色.

2.       PixelFormat属性:返回图像的像素格式.

3.       Palette属性:获取和设置图像所使用的颜色调色板.

4.       Height Width属性:返回图像的高度和宽度.

5.       LockBits 方法和UnlockBits方法:分别锁定和解锁系统内存中的位图像素.在基于像素点的图像处理方法中使用LockBits UnlockBits是一个很好的方式,这两种方法可以使我们指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理,每调用LockBits 之后都应该调用一次UnlockBits.

 

二.BitmapData

BitmapData对象指定了位图的属性

1.       Height属性:被锁定位图的高度.

2.       Width属性:被锁定位图的高度.

3.       PixelFormat属性:数据的实际像素格式.

4.       Scan0属性:被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.

5.       Stride属性:步幅,也称为扫描宽度.

C图像处理――前奏(一) - miaole1986@126 - asp.net 学习笔记

 

如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为4的倍数.

 

三.Graphics

Graphics对象是GDI+的关键所在,许多对象都是由Graphics类表示的,该类定义了绘制和填充图形对象的方法和属性,一个应用程序只要需要进行绘制或着色,它就必须使用Graphics对象.

 

四.Image

  这个类提供了位图和元文件操作的函数.Image类被声明为abstract,也就是说Image类不能实例化对象,而只能做为一个基类.

1.FromFile方法:它根据输入的文件名产生一个Image对象,它有两种函数形式:

public static Image FromFile(string filename);

public static Image FromFile(string filename, bool useEmbeddedColorManagement);

2.FromHBitmap方法:它从一个windows句柄处创建一个bitmap对象它也包括两种函数形式:

public static bitmap fromhbitmap(intptr hbitmap);

public static bitmap fromhbitmap(intptr hbitmap, intptr hpalette);

3. FromStream方法:从一个数据流中创建一个image对象,它包含三种函数形式 :

public static image fromstream(stream stream);

public static image fromstream(stream stream, bool useembeddedcolormanagement);

fromstream(stream stream, bool useembeddedcolormanagement, bool validateimagedata);

 

 

有了上面的了解,我们便可以开始利用C#做图像处理,下面介绍几种方法:

一.   打开、保存、显示图像

         private Bitmap srcBitmap = null;

          private Bitmap showBitmap = null;

        //打开文件

        private void menuFileOpen_Click(object sender, EventArgs e)

        {

            OpenFileDialog openFileDialog = new OpenFileDialog();

            openFileDialog.Filter = @"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";

            openFileDialog.FilterIndex = 3;

            openFileDialog.RestoreDirectory = true;

            if (DialogResult.OK == openFileDialog.ShowDialog())

            {

                srcBitmap = (Bitmap)Bitmap.FromFile(openFileDialog.FileName, false);

                showBitmap = srcBitmap;

                this.AutoScroll = true;

                this.AutoScrollMinSize = new Size((int)(showBitmap.Width), (int)(showBitmap.Height));

                this.Invalidate();

                

               

            }

        }

        //保存图像文件

        private void menuFileSave_Click(object sender, EventArgs e)

        {

            if (showBitmap != null)

            {

                SaveFileDialog saveFileDialog = new SaveFileDialog();

                saveFileDialog.Filter = @"Bitmap文件(*.bmp)|*.bmp|Jpeg文件(*.jpg)|*.jpg|所有合适文件(*.bmp,*.jpg)|*.bmp;*.jpg";

                saveFileDialog.FilterIndex = 3;

                saveFileDialog.RestoreDirectory = true;

                if (DialogResult.OK == saveFileDialog.ShowDialog())

                {  

                    ImageFormat format = ImageFormat.Jpeg;

                    switch (Path.GetExtension(saveFileDialog.FileName).ToLower())

                    {

                        case ".jpg":

                            format = ImageFormat.Jpeg;

                            break;

                        case ".bmp":

                            format = ImageFormat.Bmp;

                            break;

                        default:

                            MessageBox.Show(this"Unsupported image format was specified""Error",

                                MessageBoxButtons.OK, MessageBoxIcon.Error);

                            return;

                    }

                    try

                    {

                        showBitmap.Save(saveFileDialog.FileName,format );

                    }

                    catch (Exception)

                    {

                        MessageBox.Show(this"Failed writing image file""Error",

                            MessageBoxButtons.OK, MessageBoxIcon.Error);

                    }

                }

            }

 

        }

    //窗口重绘,在窗体上显示图像,重载Paint

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

        {

            if (showBitmap != null)

            {

                Graphics g = e.Graphics;

                g.DrawImage(showBitmap, new Rectangle(this.AutoScrollPosition.X, this.AutoScrollPosition.Y ,

                (int)(showBitmap.Width), (int)(showBitmap.Height)));

            }

        }

         //灰度化

        private void menu2Gray_Click(object sender, EventArgs e)

        {

            if (showBitmap == nullreturn;

            showBitmap = RGB2Gray(showBitmap);//下面都以RGB2Gray为例

            this.Invalidate();

        }

二.   提取像素法

       这种方法简单易懂,但相当耗时,完全不可取.

public static Bitmap RGB2Gray(Bitmap srcBitmap)

        {

            Color srcColor;

            int wide = srcBitmap.Width;

            int height = srcBitmap.Height;

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

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

                {

                    //获取像素的RGB颜色值

                    srcColor = srcBitmap.GetPixel(x, y);

                    byte temp = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114);

                    //设置像素的RGB颜色值

                    srcBitmap.SetPixel(x, y, Color.FromArgb(temp, temp, temp));

                }

            return srcBitmap ;

 

        }//#

 

三.   内存法

这是比较常用的方法

public static Bitmap RGB2Gray(Bitmap srcBitmap)

        {

            int wide = srcBitmap.Width;

            int height = srcBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, wide, height);

            // Bitmap锁定到系统内存中获得BitmapData

            BitmapData srcBmData = srcBitmap.LockBits(rect,

                      ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            //创建Bitmap

             Bitmap dstBitmap = CreateGrayscaleImage(wide, height);//这个函数在后面有定义

            BitmapData dstBmData = dstBitmap.LockBits(rect,

                      ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

            // 位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行

            System.IntPtr srcPtr = srcBmData.Scan0;

            System.IntPtr dstPtr = dstBmData.Scan0;

            // Bitmap对象的信息存放到byte数组中

            int src_bytes = srcBmData.Stride * height;

            byte[] srcValues = new byte[src_bytes];

            int dst_bytes = dstBmData.Stride * height;

            byte[] dstValues = new byte[dst_bytes];

            //复制GRB信息到byte数组

            System.Runtime.InteropServices.Marshal.Copy(srcPtr, srcValues, 0, src_bytes);

            System.Runtime.InteropServices.Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);

            // 根据Y=0.299*R+0.114*G+0.587B,Y为亮度

            for (int i = 0; i < height; i++)

                for (int j = 0; j < wide; j++)

                {

                  //只处理每行中图像像素数据,舍弃未用空间

                  //注意位图结构中RGBBGR的顺序存储

                    int k = 3 * j;

                    byte temp = (byte)(srcValues[i * srcBmData.Stride + k + 2] * .299

                         + srcValues[i * srcBmData.Stride + k + 1] * .587 + srcValues[i * srcBmData.Stride + k] * .114);

                    dstValues[i * dstBmData.Stride + j] = temp;

                }

            //将更改过的byte[]拷贝到原位图

            System.Runtime.InteropServices.Marshal.Copy(dstValues, 0, dstPtr, dst_bytes);

           

            // 解锁位图

            srcBitmap.UnlockBits(srcBmData);

            dstBitmap.UnlockBits(dstBmData);

            return dstBitmap;

 

        }//#

 

   指针法

C/C++的习惯,不是C#的特点

public static Bitmap  RGB2Gray(Bitmap srcBitmap)

        {

            int wide = srcBitmap.Width;

            int height = srcBitmap.Height ;

            Rectangle rect = new Rectangle(0, 0, wide, height);

            BitmapData srcBmData = srcBitmap.LockBits(rect,

                      ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            Bitmap dstBitmap = CreateGrayscaleImage(wide, height);

            BitmapData dstBmData = dstBitmap.LockBits(rect,

                      ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

   

            System.IntPtr srcScan = srcBmData.Scan0;

            System.IntPtr dstScan = dstBmData.Scan0;

            Unsafe  //启动不安全代码

            {

                byte* srcP = (byte*)(void*) srcScan;

                byte* dstP = (byte*)(void*) dstScan;

                int srcOffset = srcBmData.Stride - wide  * 3;

                int dstOffset = dstBmData.Stride  - wide ;

                byte red, green, blue;

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

                {

                    for (int x = 0; x <wide ; x++, srcP += 3, dstP++)

                    {

                        blue = srcP [0];

                        green = srcP [1];

                        red = srcP [2];

                        * dstP = (byte)(.299 * red + .587 * green + .114 * blue);

                       

                    }

                    srcP += srcOffset;

                    dstP += dstOffset;

                }

            }

            srcBitmap.UnlockBits(srcBmData);

            dstBitmap.UnlockBits(dstBmData );

            return dstBitmap;

 

        }//#

五.   矩阵法

并不是什么新方法,只是将图像数据分做R,G,B三个矩阵(二维数组)存储,类似MATLAB的习惯.

       public static bool GetRGB(Bitmap Source, out int[,] R, out int[,] G, out int[,] B)

        {

            try

            {

                int iWidth = Source.Width;

                int iHeight = Source.Height;

 

                Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);

                System.Drawing.Imaging.BitmapData bmpData = Source.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, Source.PixelFormat);

                IntPtr iPtr = bmpData.Scan0;

 

                int iBytes = iWidth * iHeight * 3;

                byte[] PixelValues = new byte[iBytes];

                System.Runtime.InteropServices.Marshal.Copy(iPtr, PixelValues, 0, iBytes);

                Source.UnlockBits(bmpData);

 

                // 注意这个地方图像的两维方向与数组两维的方向是转置的关系

 

                R = new int[iHeight, iWidth];

                G = new int[iHeight, iWidth];

                B = new int[iHeight, iWidth];

 

                int iPoint = 0;

 

                for (int i = 0; i < iHeight; i++)

                {

                    for (int j = 0; j < iWidth; j++)

                    {

                        // 注意,Windows 中三基色的排列顺序是 BGR 而不是 RGB

                        B[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                        G[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                        R[i, j] = Convert.ToInt32(PixelValues[iPoint++]);

                    }

                }

 

                return true;

            }

            catch (Exception)

            {

                R = null;

                G = null;

                B = null;

 

                return false;

            }

        }//#

        public static Bitmap FromRGB(int[,] R, int[,] G, int[,] B)

        {

            int iWidth = G.GetLength(1);

            int iHeight = G.GetLength(0);

            Bitmap Result = new Bitmap(iWidth, iHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

 

            Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);

            System.Drawing.Imaging.BitmapData bmpData = Result.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            IntPtr iPtr = bmpData.Scan0;

            int iStride = bmpData.Stride;

 

            int iBytes = iWidth * iHeight * 3;

            byte[] PixelValues = new byte[iBytes];

 

            int iPoint = 0;

 

            for (int i = 0; i < iHeight; i++)

                for (int j = 0; j < iWidth; j++)

                {

                    int iG = G[i, j];

                    int iB = B[i, j];

                    int iR = R[i, j];

                    PixelValues[iPoint] = Convert.ToByte(iB);

                    PixelValues[iPoint + 1] = Convert.ToByte(iG);

                    PixelValues[iPoint + 2] = Convert.ToByte(iR);

                    iPoint += 3;

                }

 

            System.Runtime.InteropServices.Marshal.Copy(PixelValues, 0, iPtr, iBytes);

 

            Result.UnlockBits(bmpData);

 

            return Result;

        }//#

        public static bool  GetGray(Bitmap srcBitmap, out byte [,] gray)

        {

 

            Bitmap tempBitmap;

            if (srcBitmap.PixelFormat != PixelFormat.Format8bppIndexed)

                tempBitmap = ImageProcess.Image.Gray(srcBitmap);

            else

                tempBitmap = srcBitmap;

            int wide = tempBitmap.Width;

            int height = tempBitmap.Height;

            gray = new byte [height, wide];

            BitmapData gbmData = tempBitmap.LockBits(new Rectangle(0, 0, wide, height),

                  ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

            System.IntPtr ScanG = gbmData.Scan0;

            int gOffset = gbmData.Stride - wide;

            unsafe

            {

                byte* g = (byte*)(void*)ScanG;

                // for each pixel

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

                {

                    // for each pixel

                    for (int x = 0; x < wide; x++, g++)

                    {

                        gray[y ,x ] =*g;

                    }

                    g += gOffset;

                }

            }

 

            tempBitmap.UnlockBits(gbmData);

 

            return true ;

 

        }//#

        public static Bitmap FromGray(byte [,] Gray)

        {

            int iWidth = Gray.GetLength(1);

            int iHeight = Gray.GetLength(0);

            Bitmap dstBitmap = ImageProcess.Image.CreateGrayscaleImage(iWidth, iHeight);

            BitmapData gbmData = dstBitmap.LockBits(new Rectangle(0, 0, iWidth, iHeight),

                      ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);

            System.IntPtr ScanG = gbmData.Scan0;

            int gOffset = gbmData.Stride - iWidth;

            unsafe

            {

                byte* g = (byte*)(void*)ScanG;

 

                // 注意这个地方图像的两维方向与数组两维的方向是转置的关系

 

                for (int i = 0; i < iHeight; i++)

                {

                    for (int j = 0; j < iWidth; j++)

                    {

 

                        *g=(byte )Gray[i, j] ;

                        g++;

                    }

                    g += gOffset;

                }

            }

 

            dstBitmap.UnlockBits(gbmData);

 

            return dstBitmap;

        } //#

/*********************************补充******************************************/

 

         /// <summary>

         /// Create and initialize grayscale image

         /// </summary>

         public static Bitmap CreateGrayscaleImage( int width, int height )

         {

              // create new image

              Bitmap bmp = new Bitmap( width, height, PixelFormat.Format8bppIndexed );

              // set palette to grayscale

              SetGrayscalePalette( bmp );

              // return new image

              return bmp;

         }//#

 

         /// <summary>

         /// Set pallete of the image to grayscale

         /// </summary>

         public static void SetGrayscalePalette( Bitmap srcImg )

         {

              // check pixel format

              if ( srcImg.PixelFormat != PixelFormat.Format8bppIndexed )

                   throw new ArgumentException( );

 

              // get palette

              ColorPalette cp = srcImg.Palette;

              // init palette

              for ( int i = 0; i < 256; i++ )

              {

                   cp.Entries[i] = Color.FromArgb( i, i, i );

              }

              // set palette back

              srcImg.Palette = cp;

         }//#

/*********************************END********************************************/

 

 

posted @ 2013-12-20 17:40  苏苏zhao  阅读(405)  评论(0)    收藏  举报