2015-04-02 10:03:56 scimence 阅读数 2429
        //=======================================================
        //图像剪裁、缩放,转化为鼠标光标
        //=======================================================
        /// <summary>
        /// 从图像pic中截取区域Rect构建新的图像
        /// </summary>
        public Bitmap GetRect(Image pic, Rectangle Rect)
        {
            //创建图像
            Rectangle drawRect = new Rectangle(0, 0, Rect.Width, Rect.Height);  //绘制整块区域
            Bitmap tmp = new Bitmap(drawRect.Width, drawRect.Height);           //按指定大小创建位图

            //绘制
            Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));                    //清空
            g.DrawImage(pic, drawRect, Rect, GraphicsUnit.Pixel);   //从pic的给定区域进行绘制

            return tmp;     //返回构建的新图像
        }

        /// <summary>
        /// 从图像pic中截取区域Rect构建为drawRect大小的图像
        /// </summary>
        public Bitmap GetRectTo(Image pic, Rectangle Rect, Rectangle drawRect)
        {
            //创建图像
            Bitmap tmp = new Bitmap(drawRect.Width, drawRect.Height);           //按指定大小创建位图

            //绘制
            Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));                    //清空
            g.DrawImage(pic, drawRect, Rect, GraphicsUnit.Pixel);   //从pic的给定区域进行绘制

            return tmp;     //返回构建的新图像
        }

        /// <summary>
        /// 对图像pic进行缩放,缩放比例reSize
        /// </summary>
        public Bitmap shrinkTo(Image pic, float reSize)
        {
            Size S = new Size((int)(pic.Width * reSize), (int)(pic.Height * reSize));
            Rectangle Rect = new Rectangle(new Point(0, 0), S);

            return shrinkTo(pic, Rect);
        }
        /// <summary>
        /// 对图像pic进行缩放处理,缩放为Rect大小的新图像
        /// </summary>
        public Bitmap shrinkTo(Image pic, Rectangle Rect)
        {
            //创建图像
            Bitmap tmp = new Bitmap(Rect.Width, Rect.Height);                   //按指定大小创建位图
            Rectangle drawRect = new Rectangle(0, 0, Rect.Width, Rect.Height);  //绘制整块区域
            Rectangle srcRect = new Rectangle(0, 0, pic.Width, pic.Height);     //pic的整个区域

            //绘制
            Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));                    //清空
            g.DrawImage(pic, drawRect, srcRect, GraphicsUnit.Pixel);//从pic的给定区域进行绘制

            return tmp;     //返回构建的新图像
        }

        /// <summary>
        /// 对图像进行任意角度的旋转
        /// </summary>
        public Bitmap Rotate(Bitmap bmp, float angle)
        {
            return Rotate(bmp, angle, Color.Transparent);
        }
        /// <summary>
        /// 任意角度旋转,此函数非原创
        /// </summary>
        public Bitmap Rotate(Bitmap bmp, float angle, Color bkColor)
        {
            int w = bmp.Width + 2;
            int h = bmp.Height + 2;

            PixelFormat pf;

            if (bkColor == Color.Transparent)
            {
                pf = PixelFormat.Format32bppArgb;
            }
            else
            {
                pf = bmp.PixelFormat;
            }

            Bitmap tmp = new Bitmap(w, h, pf);
            Graphics g = Graphics.FromImage(tmp);
            g.Clear(bkColor);
            g.DrawImageUnscaled(bmp, 1, 1);
            g.Dispose();

            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(new RectangleF(0f, 0f, w, h));
            Matrix mtrx = new Matrix();
            mtrx.Rotate(angle);
            RectangleF rct = path.GetBounds(mtrx);

            Bitmap dst = new Bitmap((int)rct.Width, (int)rct.Height, pf);
            g = Graphics.FromImage(dst);
            g.Clear(bkColor);
            g.TranslateTransform(-rct.X, -rct.Y);
            g.RotateTransform(angle);
            g.InterpolationMode = InterpolationMode.HighQualityBilinear;
            g.DrawImageUnscaled(tmp, 0, 0);
            g.Dispose();

            tmp.Dispose();

            return dst;
        }

        //获取图像pic旋转angle角度后的图像
        public Bitmap Rotate2(Image pic, float angle)
        {
            //创建图像
            int size = pic.Width > pic.Height ? pic.Width * 3 : pic.Height * 3;

            Bitmap tmp = new Bitmap(size, size);                           //按指定大小创建位图
            Rectangle Rect = new Rectangle(0, 0, pic.Width, pic.Height);   //pic的整个区域

            //绘制
            Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));                    //清空

            g.TranslateTransform(Rect.Width / 2, Rect.Height / 2);  //设置为绕中心处旋转
            g.RotateTransform(angle);                               //控制旋转角度

            Point pos = new Point((int)((size - pic.Width) / 2), (int)((size - pic.Height) / 2));  //中心对齐
            g.DrawImage(pic, pos);                                  //绘制图像

            g.TranslateTransform(-Rect.Width / 2, -Rect.Height / 2);//还原锚点为左上角

            return tmp;     //返回构建的新图像
        }

        /// <summary>
        /// 图像沿Y轴翻转
        /// </summary>
        public Bitmap FlipY(Bitmap pic)
        {
            pic.RotateFlip(RotateFlipType.RotateNoneFlipY);
            return pic;
        }

        /// <summary>
        /// 图像沿X轴翻转
        /// </summary>
        public Bitmap FlipX(Bitmap pic)
        {
            pic.RotateFlip(RotateFlipType.RotateNoneFlipX);
            return pic;
        }

        /// <summary>
        /// 从给定的图像创建鼠标光标
        /// </summary>
        public Cursor GetCursor(Bitmap pic)
        {
            try { return new Cursor(pic.GetHicon()); }         //从位图创建鼠标图标
            catch (Exception e) { return Cursors.Default; }
        }

        /// <summary>
        /// 获取用图像pic,按指定大小width创建鼠标光标
        /// </summary>
        public Cursor GetCursor(Image pic, int width)
        {
            Bitmap icon = new Bitmap(width, width);             //按指定大小创建位图
            Graphics g = Graphics.FromImage(icon);              //从位图创建Graphics对象
            g.Clear(Color.FromArgb(0, 0, 0, 0));
            g.DrawImage(pic, 0, 0, icon.Width, icon.Height);    //绘制Image到位图

            //Bitmap icon = new Bitmap(tiles[toolsPostion.Y - 1]);

            try { return new Cursor(icon.GetHicon()); }         //从位图创建鼠标图标
            catch (Exception e) { return Cursors.Default; }
        }

2016-09-20 10:45:16 clb929 阅读数 2583

Image 类

命名空间:   System.Drawing
一个抽象基类,提供了用于功能 Bitmap 和 Metafile 继承的类。
常用属性
Width 图片的宽度
Height 图片的高度
Size 图片的大小(宽度和高度)
RawFormat 图片的格式
常用的方法
FromFile(String) 静态方法,从指定文件创建图片
FromStream(Stream) 静态方法,从指定的数据流创建图片
Save(Stream, ImageFormat) 将图片以指定的格式保存到指定的数据流中
Save(String, ImageFormat) 将图片以指定的格式保存到指定的文件中
Dispose() 释放此 Image 使用的所有资源

Bitmap 类

命名空间:   System.Drawing
主要用于创建和保存图像文件(jpg、bmp、png、gif等),以及简单的图像处理:缩放、旋转、翻转、透明
常用构造函数
Bitmap(Image) 从已有image对象创建
Bitmap(Int32, Int32) 创建指定大小的空白对象
Bitmap(Stream) 从数据流创建
Bitmap(String) 从文件创建
常用属性
WidthHeightSize 宽、高、大小
常用方法
GetPixel(Int32, Int32) 获得指定像素点的颜色值
SetPixel(Int32, Int32, Color) 设置指定像素点的颜色值
MakeTransparent(Color) 将指定的颜色透明化,常用在去背景色
RotateFlip(RotateFlipType) 旋转或翻转对象
Save(Stream, ImageFormat) 以指定的图像格式保存到数据流
Save(String, ImageFormat) 以指定的图像格式保存到文件中

Graphics 类

命名空间:   System.Drawing
主要用于将对象绘制到显示设备,可以绘制图像、绘制图形(椭圆、矩形、多边形、直线、弧线等)、绘制文字、填充封闭图形、测量文字
获得Graphics 对象主要有3种方法:
1、通过所有继承于System.Windows.Forms.Control 的控件的CreateGraphics 方法创建Graphics 对象
2、在控件的Paint事件中,获得PaintEventArgs 的Graphics 对象
3、使用Graphics 类的静态方法FromImage(Image) 从任何继承于Image 的对象创建Graphics 对象(Bitmap类是继承于Image类的),此方法在您需要更改已存在的图像时十分有用。
常用方法
Clear(Color) 清除整个绘图面并以指定背景色填充
CopyFromScreen(Point, Point, Size) 将屏幕指定区域的图像拷贝到Graphics
DrawImage(Image, Int32, Int32) 将图像绘制到Graphics 对象的指定位置
DrawImage(Image, Rectangle) 将图像绘制到Graphics 对象的指定位置,并按指定大小拉伸
DrawImage(Image, Int32, Int32, Rectangle, GraphicsUnit) 在指定的位置绘制图像的一部分
DrawImage(Image, Rectangle, Rectangle, GraphicsUnit) 在指定位置并且按指定大小绘制指定的 Image 的指定部分
DrawString(String, Font, Brush, PointF) 使用指定的字体、画笔将文字绘制到指定位置
DrawString(String, Font, Brush, RectangleF) 使用指定的字体、画笔将文字绘制到指定的矩形内,如果文字内容超出该矩形则截断
IsVisible(Int32, Int32) 检查Graphics 对象中的指定点是否可见(显示在屏幕上,不可见的存在于内存但是不显示在屏幕上)
IsVisible(Rectangle) 检查Graphics 对象中的指定矩形是否可见(显示在屏幕上,不可见的存在于内存但是不显示在屏幕上)


附上一个简单综合练习程序链接:http://pan.baidu.com/s/1hsPpiAC
2017-06-16 15:11:14 liang890319 阅读数 3049

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


c#图像处理入门(-bitmap类和图像像素值获取方法)


C#全屏截图

用C#实现屏幕截屏功能




脚本之家C#图像操作大全


2018-11-18 11:29:52 weixin_35811044 阅读数 823
  • 图像旋转需要一个圆心,通常以图像的中心點为圆心,图像旋转经过三个步骤:

  1. 从图像坐标系转换为以圆心为原点的直角坐标系。

  2. 通过旋转算法,将坐标旋转。

  3. 再将旋转后图像从直角坐标系转换回图像坐标系。

如图:

     

 

  • 旋转算法:

  1. 坐标系变换:

    1. 由图象坐标系换成直角坐标系:。(x , y 为直角坐标)
    2. 由直角坐标系换成图象坐标系:。(x , y 为图象坐标)
  2. 坐标旋转:

    1. Pixel到原点的距离为r与原点的夹角为  ,则Pixel坐标可以表示为:
    2. 当图象顺时针旋转\theta度,则Pixel坐标为:    , 如图:。           

                  即:

 

  • 旋转算法最终公式:

    1. 顺时针旋转:图像坐标 --> 直角坐标 -->  图像旋转  -->  图像坐标 。
    2. 逆运算:用于反向映射。
  • 两种旋转方式:

    1. 正向失真映射:当图像旋转时,原图Pixel的坐标经过旋转公式得到的新Pixel坐标通常不会是整数,而图像的Pixel坐标都是以整数记录的。所以,我们会采用四舍六入五凑偶的方式。但是,如果采用近似,那么就会出现多个Pixel旋转后都对应到新图中的同一个整数坐标,而新图中有些整数坐标点却没有pixel对应,这样就会出现空洞(失真)。另外,对于多点对一点,在新图中采用按先后顺序覆盖的方式。
    2. 反向映射:为了避免出现空洞(失真),我们采用反向映射(其中正向映射也能采用相同方法避免空洞)。原理是对旋转后的图片,其整数坐标进行逆变换,可得到对应在原图中的坐标。通常得到的原图坐标也不会是整数,但是我们可以采用下面两种方法取得Pixel然后赋值给旋转后的图片。
    3. 如图:

       

      1. 最邻近插值:直接对原图中映射的非整数坐标进行四舍五入,得到的整数坐标,取Pixel值赋值给旋转图像中对应的点。
      2. 双线性插值:先说说线性插值。如下图:已知 (x0, y0) 、(x1, y1)、x,求 y。根据斜率相同:即可得:

                                                                                    

现在來看看什么是双线性插值法,说白了就是进行两次线性插值。如下图:(x,y) 为映射到原图的pixel点,是位于(0,0)、(1,0)、(0,1)、(1,1)中的点。f(0,0)、f(1,0)、f(0,1)、f(1,1)为各点的Pixel值,求 (x,y)的pixel值 f(x,y) 。根据线性插值,先进行x方向线性插值:

                          在(0,0)、(1,0)之间:f(x,0) = f(0,0)*(1-x)/1 + f(1,0)*(x-0) /1 ;

                          在(0,1)、(1,1)之间:f(x,1) = f(0,1)*(1-x)/1 + f(1,1)*(x-0) /1

                         得到  f(x,0)f(x,1) 后再进行 y 方向上的线性插值:f(x,y)  = f(x,0)*(1-y)/1 + f(x,1)*(y-0)/1

                         f(x,y)即按比例权重求得的Pixel值赋值回旋转图像中对应的点。

                                                            双线性插值

 

 

  • C#实现正向失真和反向双线性:        

C#存在Cos、Sin精度问题,即 Cos(Pi/2)、Sin(Pi) 等,不会等于0之类。目前没有想到很好的解决办法,有人知道的话请指教。 

 //正向失真旋转
public Bitmap rotateImageDis(Bitmap Image, double degree)
        {
            int Wo = Image.Width;
            int Lo = Image.Height;
            //采用向上取整,求旋转后图像大小。
            //double Wt = Math.Ceiling(Math.Abs(Wo * Math.Cos(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Sin(Math.PI * (degree / 180)))-0.00001);
            //double Lt = Math.Ceiling(Math.Abs(Wo * Math.Sin(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Cos(Math.PI * (degree / 180)))-0.00001);
            //采用四舍五入,求旋转后图像大小。
            double Wt = (int)(Math.Abs(Wo * Math.Cos(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Sin(Math.PI * (degree / 180))) + 0.5);
            double Lt = (int)(Math.Abs(Wo * Math.Sin(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Cos(Math.PI * (degree / 180))) + 0.5);
            Bitmap rotateImageData = new Bitmap((int)Wt, (int)Lt, PixelFormat.Format24bppRgb);

            //x、y即原图坐标,x1、y1即旋转后坐标。
            for (int y = 0; y < Lo; y++)
            {
                for (int x = 0; x < Wo; x++)
                {
                    int x1 = (int)Math.Round(x * Math.Cos(Math.PI * (degree / 180)) - y * Math.Sin(Math.PI * (degree / 180)) - (Wo - 1) / 2.0 * Math.Cos(Math.PI * (degree / 180)) + (Lo - 1) / 2.0 * Math.Sin(Math.PI * (degree / 180)) + (Wt - 1) / 2.0);
                    int y1 = (int)Math.Round(x * Math.Sin(Math.PI * (degree / 180)) + y * Math.Cos(Math.PI * (degree / 180)) - (Wo - 1) / 2.0 * Math.Sin(Math.PI * (degree / 180)) - (Lo - 1) / 2.0 * Math.Cos(Math.PI * (degree / 180)) + (Lt - 1) / 2.0);
                    rotateImageData.SetPixel(x1, y1, Image.GetPixel(x, y));
                }
            }
            return rotateImageData;
        }
        //反向双线性插值法
        public Bitmap rotareImageOri(Bitmap Image, double degree)
        {
            int Wo = Image.Width;
            int Lo = Image.Height;
            //采用向上取整,求旋转后图像大小。
            //double Wt = Math.Ceiling(Math.Abs(Wo * Math.Cos(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Sin(Math.PI * (degree / 180))) - 0.0001);
            //double Lt = Math.Ceiling(Math.Abs(Wo * Math.Sin(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Cos(Math.PI * (degree / 180))) - 0.0001);
            //采用四舍五入,求旋转后图像大小。
            double Wt = (int)(Math.Abs(Wo * Math.Cos(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Sin(Math.PI * (degree / 180))) + 0.5);
            double Lt = (int)(Math.Abs(Wo * Math.Sin(Math.PI * (degree / 180))) + Math.Abs(Lo * Math.Cos(Math.PI * (degree / 180))) + 0.5);
            Bitmap rotateImageData = new Bitmap((int)Wt, (int)Lt, PixelFormat.Format24bppRgb);

            //x1、y旋转后图像坐标,x、y原图坐标。
            for (int y1 = 0; y1 < Lt; y1++)
            {
                for (int x1 = 0; x1 < Wt; x1++)
                {
                    double x = x1 * Math.Cos(Math.PI * (degree / 180)) + y1 * Math.Sin(Math.PI * (degree / 180)) - (Wt - 1) / 2.0 * Math.Cos(Math.PI * (degree / 180)) - (Lt - 1) / 2.0 * Math.Sin(Math.PI * (degree / 180)) + (Wo - 1) / 2.0;
                    double y = -x1 * Math.Sin(Math.PI * (degree / 180)) + y1 * Math.Cos(Math.PI * (degree / 180)) + (Wt - 1) / 2.0 * Math.Sin(Math.PI * (degree / 180)) - (Lt - 1) / 2.0 * Math.Cos(Math.PI * (degree / 180)) + (Lo - 1) / 2.0;
                    if (-0.001 <= x & x <= (Wo - 1) & -0.001 <= y & y <= (Lo - 1))
                    {
                        Color RGB = new Color();

                        int a1 = (int)x;
                        int b1 = (int)y;
                        int a2 = (int)Math.Ceiling(x);
                        int b2 = (int)y;
                        int a3 = (int)x;
                        int b3 = (int)Math.Ceiling(y);
                        int a4 = (int)Math.Ceiling(x);
                        int b4 = (int)Math.Ceiling(y);

                        double xa13 = x - a1;
                        double xa24 = a2 - x;
                        double yb12 = y - b1;
                        double yb34 = b3 - y;

                        if (xa13 != 0 & xa24 != 0 & yb12 != 0 & yb34 != 0)
                        {//对应回原图是非整数坐标,双线性插值。
                            byte R1 = Image.GetPixel(a1, b1).R;
                            byte G1 = Image.GetPixel(a1, b1).G;
                            byte B1 = Image.GetPixel(a1, b1).B;
                            byte R2 = Image.GetPixel(a2, b2).R;
                            byte G2 = Image.GetPixel(a2, b2).G;
                            byte B2 = Image.GetPixel(a2, b2).B;
                            byte R3 = Image.GetPixel(a3, b3).R;
                            byte G3 = Image.GetPixel(a3, b3).G;
                            byte B3 = Image.GetPixel(a3, b3).B;
                            byte R4 = Image.GetPixel(a4, b4).R;
                            byte G4 = Image.GetPixel(a4, b4).G;
                            byte B4 = Image.GetPixel(a4, b4).B;

                            byte R = (byte)((R1 * xa24 + R2 * xa13) * yb34 + (R3 * xa24 + R4 * xa13) * yb12);
                            byte G = (byte)((G1 * xa24 + G2 * xa13) * yb34 + (G3 * xa24 + G4 * xa13) * yb12);
                            byte B = (byte)((B1 * xa24 + B2 * xa13) * yb34 + (B3 * xa24 + B4 * xa13) * yb12);

                            RGB = Color.FromArgb(R, G, B);
                        }
                        else
                        {//对应回原图是整数坐标,直接取Pixel。
                            RGB = Image.GetPixel(a1, b1);
                        }
                        rotateImageData.SetPixel(x1, y1, RGB);
                    }
                }
            }
            return rotateImageData;
        }

                                                                                                                                

 

仅为个人理解,如有不足,请指教。  https://blog.csdn.net/weixin_35811044

 

 

 

2013-07-02 10:14:00 weixin_33860553 阅读数 65
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);
}
 
 

 

C#.NET图像处理

阅读数 3729

没有更多推荐了,返回首页