2018-11-15 18:28:01 u012671435 阅读数 133
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    17306 人正在学习 去看看 张建飞
  1. 图像处理常用类

         Bitmap只要用于处理由像素数据定义的图像的对象,主要方法和属性如下: GetPixel方法和SetPixel方法,获取和设置一个图像的指定像素的颜色。

        PixelFormat属性,返回图像的像素格式。

         Palette属性,获取或折纸图像所使用的颜色调色板。

         Height属性和Width属性,返回图像的高度和宽度。

         LockBits方法和UnlockBits方法,分别锁定和解锁系统内存中的位图像素。

       BitmapData对象指定了位图的属性:

         Height属性,被锁定位图的高度。

         Width属性,被锁定位图的宽度。

         PixelFormat属性,数据的实际像素格式。

        Scan0属性,被锁定数组的首字节地址。

       Stride属性,步幅,也称扫描宽度。

       Graphics类提供了对象绘制到现实设备的方法。

         创建Graphics对象的方法如下:

         // Create image.
         Image imageFile = Image.FromFile("SampImag.jpg");

        // Create graphics object for alteration.
         Graphics newGraphics = Graphics.FromImage(imageFile);

         Graphics常用方法:

        Clear(Color)   清除整个绘图面并以指定背景色填充。

        Dispose()      释放此 Graphics 使用的所有资源。

        DrawIcon(Icon, Int32, Int32)    在指定坐标处绘制由指定的 Icon 表示的图像。

        DrawIcon(Icon, Rectangle)    在 Icon 结构指定的区域内绘制指定的 Rectangle 表示的图像。

        DrawImage(Image, Int32, Int32)    在由坐标对指定的位置,使用图像的原始物理大小绘制指定的图像。

        Graphics属性:

         DpiX属性, 获取Graphics的水平分辨率。

         DpiY属性,获取Graphics的垂直分辨率。

         Transform属性,获取或设置此Graphics的几何世界转换的副本。

         TextContrast属性,获取或设置文本的灰度校正值。

        详细请见:https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.graphics?view=netframework-4.7.2

  2.  彩色图像灰度化

      24位彩色图像每个像素用3个字节表示,每个字节对应着R、G、B分量的亮度(红、绿、蓝)。当3个分量不想同时表现为       灰度图像。转化方式:

    平均法:将同一像素位置3个通道RGB的值进行平均

     Gray(i,j)=[R(i,j)+G(i,j)+B(i,j)]/3

     Gray(i,j)为转换后的灰度图像在(i,j)点出的灰度值。由于人眼对颜色的感应不同,有了以下的转化为方式:

    Gray(i,j)=0.299*R(i,j)+0.587*G(i,j)+0.114*B(i,j)

   Gray(i,j)=G(i,j)

    图像处理的3种方法为:

       使用Bitmap.GetPixel()和Bitmap.SetPixel()

  • 提取像素法
         /// 图像灰度化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            Image imageFile = (Bitmap)Image.FromFile(@"C:\Users\Administrator.USER-20151012WY\Desktop\WaterMarkTool\xiaowanzi.jpg");
            Bitmap newbitmap = imageFile as Bitmap;
            Graphics g = Graphics.FromImage(newbitmap);
            Color pixel;
            int ret = 0;
            for (int x = 0; x < newbitmap.Width; x++)
            {
                for (int y = 0; y < newbitmap.Height; y++)
                {
                    pixel = newbitmap.GetPixel(x, y);
                    //ret = (int)(pixel.R * 0.299 + pixel.G * 0.587 + pixel.B * 0.114);
                    ret = (pixel.R + pixel.G + pixel.B) / 3;
                    newbitmap.SetPixel(x, y, Color.FromArgb(ret, ret, ret));
                }
            }
            g.DrawImage(newbitmap, 0, 0);
            this.pictureBox2.Image = newbitmap;
            g.Dispose();

        }

 

  • 指针法

   通过LockBits方法来获取位图的首地址, 该方法简单,直接用指针进行位图操作。所以对内存的操作需要unsafe下进行操作。

   为了保持类型安全,在默认情况下,C#是不支持指针运算的,因为使用指针会带来相关的风险。所以C#只允许在特别标记的代码块中使用指针。通过使用unsafe关键字,可以定义可使用指针的不安全上下文。

  • 内存法

 该方法就是指图像数据直接复制到内存中,这样就使程序的运行速度大大提高。 

 

3. 转化为灰度方法

浮点算法:Gray=R*0.3+G*0.59+B*0.11

整数算法:Gray=(R*30+G*59+B*11)/100

移位算法:Gray=(R*28+G*151+B*77)>>8

平均值法:Gray=(R+G+B)/3

仅取绿色:Gray=G

灰度是指黑白图像中点的颜色深度,范围一般从0到255,白色为255,黑色为0,因此黑白图片也称为灰度图像。

 

 

 

 

 

      

2016-08-12 15:12:59 scimence 阅读数 3797
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    17306 人正在学习 去看看 张建飞

示例:

Image screen = getScreen();                       // 截取屏幕
saveImage(screen, screen.Size, @"d:\截屏.jpg");   // 保存截屏

# region 图像处理功能函数

/// <summary>
/// 按指定尺寸对图像pic进行非拉伸缩放
/// </summary>
public static Bitmap shrinkTo(Image pic, Size S, Boolean cutting)
{
    //创建图像
    Bitmap tmp = new Bitmap(S.Width, S.Height);     //按指定大小创建位图

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

    Boolean mode = (float)pic.Width / S.Width > (float)pic.Height / S.Height;   //zoom缩放
    if (cutting) mode = !mode;                      //裁切缩放

    //计算Zoom绘制区域             
    if (mode)
        S.Height = (int)((float)pic.Height * S.Width / pic.Width);
    else
        S.Width = (int)((float)pic.Width * S.Height / pic.Height);
    Point P = new Point((tmp.Width - S.Width) / 2, (tmp.Height - S.Height) / 2);

    g.DrawImage(pic, new Rectangle(P, S));

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


//保存图像pic到文件fileName中,指定图像保存格式
public static void SaveToFile(Image pic, string fileName, bool replace, ImageFormat format)    //ImageFormat.Jpeg
{
    //若图像已存在,则删除
    if (System.IO.File.Exists(fileName) && replace)
        System.IO.File.Delete(fileName);

    //若不存在则创建
    if (!System.IO.File.Exists(fileName))
    {
        if (format == null) format = getFormat(fileName);   //根据拓展名获取图像的对应存储类型

        if (format == ImageFormat.MemoryBmp) pic.Save(fileName);
        else pic.Save(fileName, format);                    //按给定格式保存图像
    }
}

//根据文件拓展名,获取对应的存储类型
public static ImageFormat getFormat(string filePath)
{
    ImageFormat format = ImageFormat.MemoryBmp;
    String Ext = System.IO.Path.GetExtension(filePath).ToLower();

    if (Ext.Equals(".png")) format = ImageFormat.Png;
    else if (Ext.Equals(".jpg") || Ext.Equals(".jpeg")) format = ImageFormat.Jpeg;
    else if (Ext.Equals(".bmp")) format = ImageFormat.Bmp;
    else if (Ext.Equals(".gif")) format = ImageFormat.Gif;
    else if (Ext.Equals(".ico")) format = ImageFormat.Icon;
    else if (Ext.Equals(".emf")) format = ImageFormat.Emf;
    else if (Ext.Equals(".exif")) format = ImageFormat.Exif;
    else if (Ext.Equals(".tiff")) format = ImageFormat.Tiff;
    else if (Ext.Equals(".wmf")) format = ImageFormat.Wmf;
    else if (Ext.Equals(".memorybmp")) format = ImageFormat.MemoryBmp;

    return format;
}

[DllImport("user32.dll")]
static extern bool GetCursorInfo(out CURSORINFO pci);

private const Int32 CURSOR_SHOWING = 0x00000001;
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
    public Int32 x;
    public Int32 y;
}

[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
    public Int32 cbSize;
    public Int32 flags;
    public IntPtr hCursor;
    public POINT ptScreenPos;
}

/// <summary>
/// 截取屏幕指定区域为Image,保存到路径savePath下,haveCursor是否包含鼠标
/// </summary>
public static Image getScreen(int x = 0, int y = 0, int width = -1, int height = -1, String savePath = "", bool haveCursor = true)
{
    if (width == -1) width = SystemInformation.VirtualScreen.Width;
    if (height == -1) height = SystemInformation.VirtualScreen.Height;

    Bitmap tmp = new Bitmap(width, height);                 //按指定大小创建位图
    Graphics g = Graphics.FromImage(tmp);                   //从位图创建Graphics对象
    g.CopyFromScreen(x, y, 0, 0, new Size(width, height));  //绘制

    // 绘制鼠标
    if (haveCursor)
    {
        try
        {
            CURSORINFO pci;
            pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
            GetCursorInfo(out pci);
            System.Windows.Forms.Cursor cur = new System.Windows.Forms.Cursor(pci.hCursor);
            cur.Draw(g, new Rectangle(pci.ptScreenPos.x, pci.ptScreenPos.y, cur.Size.Width, cur.Size.Height));
        }
        catch (Exception ex) { }    // 若获取鼠标异常则不显示
    }

    //Size halfSize = new Size((int)(tmp.Size.Width * 0.8), (int)(tmp.Size.Height * 0.8));  // 按一半尺寸存储图像
    if (!savePath.Equals("")) saveImage(tmp, tmp.Size, savePath);       // 保存到指定的路径下

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

/// <summary>
/// 缩放icon为指定的尺寸,并保存到路径PathName
/// </summary>
public static void saveImage(Image image, Size size, String PathName)
{
    Image tmp = shrinkTo(image, size, false);
    SaveToFile(tmp, PathName, true, null);
}

# endregion



2014-03-12 21:12:43 Chriswu9010 阅读数 2066
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    17306 人正在学习 去看看 张建飞

c#图像处理入门

-bitmap类和图像像素值获取方法

 

一.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属性:步幅,也称为扫描宽度.

 

 

如上图所示,数组的长度并不一定等于图像像素数组的长度,还有一部分未用区域,这涉及到位图的数据结构,系统要保证每行的字节数必须为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#做图像处理,下面介绍几种方法:

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

        privateBitmap srcBitmap = null;

          privateBitmap showBitmap = null;

        //打开文件

        privatevoid menuFileOpen_Click(object sender, EventArgs e)

        {

            OpenFileDialog openFileDialog = newOpenFileDialog();

            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 =

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

                this.Invalidate();

             }

        }

        //保存图像文件

        privatevoid menuFileSave_Click(object sender, EventArgs e)

        {

            if (showBitmap != null)

            {

                SaveFileDialog saveFileDialog = newSaveFileDialog();

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

                    }

                }

            }

        }

 

c#中将bitmap或者image保存为清晰的gif

在c#中默认可以讲bitmap保存为gif等格式,但是这种保存方法保存的gif会严重失真,正常情况下的代码:

1 System.Drawing.Bitmap b = new System.Drawing.Bitmap(“c://original_image.gif“); 
2   System.Drawing.Image thmbnail = b.GetThumbnailImage(100,75,null,new IntPtr()); 

3   thmbnail.Save(“c://thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif); 

一个批量处理图片的软件,包括各种处理方式,处理效果,但是在保存为gif的时候出现了问题,在网上查了很久也没有发现一个可用的改善gif图片质量的方法,找到了一个解决办法,保存出来的gif容量大减,但是效果基本符合常规这中方法就是就是“Octree“ 算法。

“Octree“ 算法允许我们插入自己的算法来量子化我们的图像。

 

一个好的“颜色量子化”算法应该考虑在两个像素颗粒之间填充与这两个像素颜色相近的过渡颜色,提供更多可视颜色空间。

 

Morgan Skinner提供了很好的“Octree“ 算法代码,大家可以下载参考使用。

 

  使用OctreeQuantizer很方便:

 System.Drawing.Bitmap b = new System.Drawing.Bitmap(“c://original_image.gif“);

 System.Drawing.Image thmbnail = b.GetThumbnailImage(100,75,null,new IntPtr());

 OctreeQuantizer quantizer = new OctreeQuantizer ( 255 , 8 ) ;

 using ( Bitmap quantized = quantizer.Quantize ( thmbnail ) )

 {

   quantized.Save(“c://thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif);

 }

 OctreeQuantizer grayquantizer = new GrayscaleQuantizer ( ) ;

 using ( Bitmap quantized = grayquantizer.Quantize ( thmbnail ) )

 {

   quantized.Save(“c://thumnail.gif“, System.Drawing.Imaging.ImageFormat.Gif);

}

你可以点击这里下载类的文件(项目文件),根据我的试用,只需要两个类文件(OctreeQuantizer.cs,Quantizer.cs)即可运行,将这两个类文件的namespace改成你项目的名称就行,还有,需要在不安全编译的方式下编译,右击项目名称,在生成选项卡里选择"允许不安全代码"即可

 

 

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

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

        {

            if (showBitmap != null)

            {

                Graphics g = e.Graphics;

                g.DrawImage(showBitmap, newRectangle(this.AutoScrollPosition.X, this.AutoScrollPosition.Y ,

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

            }

        }

         //灰度化

        privatevoid menu2Gray_Click(object sender, EventArgs e)

        {

            if (showBitmap == null) return;

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

            this.Invalidate();

        }

二.   提取像素法

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

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

        }

三.   内存法

这是比较常用的方法

publicstaticBitmap RGB2Gray(Bitmap srcBitmap)

        {

            int wide = srcBitmap.Width;

            int height = srcBitmap.Height;

            Rectangle rect = newRectangle(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 = newbyte[src_bytes];

            int dst_bytes = dstBmData.Stride * height;

            byte[] dstValues = newbyte[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++)

                {

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

                  //注意位图结构中RGB按BGR的顺序存储

                    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;

                }

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

            //解锁位图

            srcBitmap.UnlockBits(srcBmData);

            dstBitmap.UnlockBits(dstBmData);

            return dstBitmap; 

        } 

四  指针法

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

publicstaticBitmap RGB2Gray(Bitmap srcBitmap)

        {

            int wide = srcBitmap.Width;

            int height = srcBitmap.Height ;

            Rectangle rect = newRectangle(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的习惯.

       publicstaticbool GetRGB(Bitmap Source, outint[,] R, outint[,] G, outint[,] B)

        {

            try

            {

                int iWidth = Source.Width;

                int iHeight = Source.Height; 

                Rectangle rect = newRectangle(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 = newint[iHeight, iWidth];

                G = newint[iHeight, iWidth];

                B = newint[iHeight, iWidth]; 

                int iPoint = 0; 

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

                {

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

                    {

                        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; 

                returnfalse;

            }

        }

        publicstaticBitmap FromRGB(int[,] R, int[,] G, int[,] B)

        {

            int iWidth = G.GetLength(1);

            int iHeight = G.GetLength(0);

            Bitmap Result = newBitmap(iWidth, iHeight,

System.Drawing.Imaging.PixelFormat.Format24bppRgb); 

            Rectangle rect = newRectangle(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 = newbyte[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;

        }

        publicstaticbool GetGray(Bitmap srcBitmap, outbyte [,] 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 = newbyte [height, wide];

            BitmapData gbmData = tempBitmap.LockBits(newRectangle(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 (int y = 0; y < height; y++)

                {

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

                    {

                        gray[y ,x ] =*g;

                    }

                    g += gOffset;

                }

            }

             tempBitmap.UnlockBits(gbmData);

            returntrue ;

         }

        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(newRectangle(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>

         publicstaticBitmap CreateGrayscaleImage( int width, int height )

         {

              // create new image

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

              // set palette to grayscale

              SetGrayscalePalette( bmp );

              // return new image

              return bmp;

         }//#

         ///<summary>

         /// Set pallete of the image to grayscale

         ///</summary>

         publicstaticvoid SetGrayscalePalette( Bitmap srcImg )

         {

              // check pixel format

              if ( srcImg.PixelFormat != PixelFormat.Format8bppIndexed )

                   thrownewArgumentException( );

              // get palette

              ColorPalette cp = srcImg.Palette;

              // init palette

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

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

              }

              srcImg.Palette = cp;

         }

 

C#数字图像处理的3种典型方法(精简版)

 

C#数字图像处理有3种典型方法:提取像素法、内存法、指针法。其中提取像素法使用的是GDI+中的Bitmap.GetPixel和Bitmap.SetPixel方法;内存法是通过LockBits方法来获取位图的首地址,从而把图像数据直接复制到内存中进行处理;指针法与内存法相似,但该方法直接应用指针对位图进行操作,由于在默认情况下,C#不支持指针运算,所以该方法只能在unsafe关键字所标记的代码块中使用。以一幅真彩色图像的灰度化为例,下面代码分别展现了这3种方法的使用,方便大家学习图像处理的基本技巧。

(1) 像素提取法

if (curBitmap != null)

{

      Color curColor;

      int gray;

      for (int i = 0; i < curBitmap.Width; i++)

      {

             for (int j = 0; j < curBitmap.Height; j++)

             {

                    curColor = curBitmap.GetPixel(i, j);

                    gray = (int)(0.3 * curColor.R + 0.59 * curColor.G * 0.11 * curColor.B);

                    curBitmap.SetPixel(i, j, curColor);

             }

      }

}

(2) 内存法

if (curBitmap != null)

{

      int width = curBitmap.Width;

      int height = curBitmap.Height;

      int length = height * 3 * width;

      RGB = new byte[length];

     BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

      System.IntPtr Scan0 = data.Scan0;

      System.Runtime.InteropServices.Marshal.Copy(Scan0, RGB, 0, length);

      double gray = 0;

      for (int i = 0; i < RGB.Length; i=i+3)

      {

             gray = RGB[i + 2] * 0.3 + RGB[i + 1] * 0.59 + RGB[i] * 0.11;

             RGB[i + 2] = RGB[i + 1] = RGB[i] = (byte)gray;

      }

      System.Runtime.InteropServices.Marshal.Copy(RGB, 0, Scan0, length);

      curBitmap.UnlockBits(data);

}

(3) 指针法

if (curBitmap != null)

{

      int width = curBitmap.Width;

      int height = curBitmap.Height;

     BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

      System.IntPtr Scan0 = data.Scan0;

      int stride = data.Stride;

      System.Runtime.InteropServices.Marshal.Copy(Scan0, RGB, 0, length);

      unsafe

      {

             byte* p = (byte*)Scan0;

             int offset = stride - width * 3;

             double gray = 0;

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

             {

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

                    {

                           gray = 0.3 * p[2] + 0.59 * p[1] + 0.11 * p[0];

                           p[2] = p[1] = p[0] = (byte)gray;

                           p += 3;

                    }

                    p += offset;

             }

      }

      curBitmap.UnlockBits(data);

         }

在以上3种方法中,提取像素法能直观的展示图像处理过程,可读性很好,但效率最低,并不适合做图像处理方面的工程应用;内存法把图像直接复制到内存中,直接对内存中的数据进行处理,速度明显提高,程序难度也不大;指针法直接应用指针来对图像进行处理,所以速度最快。

 

 

简单图片处理函数代码(C#

 

一、生成图片并实现颜色渐变效果 
    Response.Clear(); 
    Bitmap imgOutput = new Bitmap(100, 50); 
    Graphics gic = Graphics.FromImage(imgOutput);

gic.Clear(Color.BlueViolet); 
    gic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; 
    gic.DrawString("渐变图形", new Font("黑体",16,FontStyle.Italic),

new SolidBrush(Color.White),new PointF(2,2)); 
    gic.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(new Point(0,0),

new Point(100,50), Color.FromArgb(0,0,0,0),

Color.FromArgb(255,255,255,255)),0,0,100,50);

    imgOutput.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg); 
    gic.Dispose(); 
    imgOutput.Dispose(); 
    Response.End(); 

二、对图片进行反转 
    System.Drawing.Image drawimage = System.Drawing.Image.FromFile(photopath);//photopath表示图片的物理地址 
    drawimage.RotateFlip(RotateFlipType.Rotate270FlipNone); 
    if(File.Exists(photopath)) 
    { 
         File.SetAttributes(photopath,FileAttributes.Normal); 
         File.Delete(photopath); 
    } 
    drawimage.Save(photopath,System.Drawing.Imaging.ImageFormat.Jpeg); 
    drawimage.Dispose(); 

三、对图片进行缩放 
    System.Drawing.Image drawimage = System.Drawing.Image.FromFile(photopath); 
    Bitmap imgOutput = new Bitmap(drawimage,60,30); 
    imgOutput.Save(newphotppath, System.Drawing.Imaging.ImageFormat.Jpeg); 
    imgOutput.Dispose();   
    Response.End(); 

其他还有一些画线、画矩形、画圆等的函数和方法都可以在System.Drawing中找到;

本文的实例是一个数字图像处理的应用程序,它完成的功能包括对图像颜色的翻转、对图像进行灰度处理和对图像进行增亮处理。该程序对图像进行处理部分的代码包含在一个专门的Filters类里面,通过调用该类里的静态成员函数,我们就可以实现相应的图像处理功能了。为实现图像处理,我们要对图像进行逐个象素处理。我们知道图像是由一个个的象素点组成的,对一幅图像的每个象素进行了相应的处理,最后整个图像也就处理好了。在这个过程中,我们只需对每个象素点进行相应的处理,在处理过程中却不需要考虑周围象素点对其的影响,所以相对来说程序的实现就变得简单多了。

  由于GDI+中的BitmapData类不提供对图像内部数据的直接访问的方法,我们唯一的办法就是使用指针来获得图像的内部数据,这时我们就得运用unsafe这个关键字来指明函数中访问图像内部数据的代码块了。在程序中,我还运用了打开文件和保存文件等选项,以使我们的辛勤劳动不付之东流。

  二.程序的实现:

  

Invert()、Gray()、Brightness()等三个函数均包含在Filters类里面,

Invert()函数的算法如下:

public static bool Invert(Bitmap b)

 {

 BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),

    ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

 int stride = bmData.Stride;

 System.IntPtr Scan0 = bmData.Scan0;

 unsafe

 {

  byte * p = (byte *)(void *)Scan0;

  int nOffset = stride - b.Width*3;

  int nWidth = b.Width * 3;

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

  {

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

   {

    p[0] = (byte)(255-p[0]);

    ++p;

   }

   p += nOffset;

  }

 }

 b.UnlockBits(bmData);

 return true;

 }

该函数以及后面的函数的参数都是Bitmap类型的,它们传值的对象就是程序中所打开的图像文件了。该函数中的BitmapData类型的bmData包含了图像文件的内部信息,bmData的Stride属性指明了一条线的宽度,而它的Scan0属性则是指向图像内部信息的指针。本函数完成的功能是图像颜色的翻转,实现的方法即用255减去图像中的每个象素点的值,并将所得值设置为原象素点处的值,对每个象素点进行如此的操作,只到整幅图像都处理完毕。函数中的unsafe代码块是整个函数的主体部分,首先我们取得图像内部数据的指针,然后设置好偏移量,同时设置nWidth为b.Width*3,因为每个象素点包含了三种颜色成分,对每个象素点进行处理时便要进行三次处理。接下来运用两个嵌套的for循环完成对每个象素点的处理,处理的核心便是一句:p[0] = (byte)(255-p[0]);。在unsafe代码块后,便可运用b.UnlockBits(bmData)进行图像资源的释放。函数执行成功,最后返回true值。注:由于是要编译不安全代码,所以得将项目属性页中的"允许不安全代码块"属性设置为true,

 

Gray()函数的算法如下:

public static bool Gray(Bitmap b)

 {

        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height),

                  ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

 int stride = bmData.Stride;

 System.IntPtr Scan0 = bmData.Scan0;

 unsafe

 {

  byte * p = (byte *)(void *)Scan0;

  int nOffset = stride - b.Width*3;

  byte red, green, blue;

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

 {

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

  {

   blue = p[0];

   green = p[1];

   red = p[2];

   p[0] = p[1] = p[2] = (byte)(.299 * red + .587 * green + .114 * blue);

   p += 3;

  }

  p += nOffset;

 }

 }

 b.UnlockBits(bmData);

 return true;

 }

  本函数完成的功能是对图像进行灰度处理,我们的基本想法可是将每个象素点的三种颜色成分的值取平均值。然而由于人眼的敏感性,这样完全取平均值的做法的效果并不好,所以在程序中我取了三个效果最好的参数:.299,.587,.114。不过在这里要向读者指明的是,在GDI+中图像存储的格式是BGR而非RGB,即其顺序为:Blue、Green、Red。所以在for循环内部一定要设置好red、green、blue等变量的值,切不可颠倒。函数执行成功后,同样返回true值。

 

Brightness()函数的算法如下:

public static bool Brightness(Bitmap b, int nBrightness)

 {

  if (nBrightness < -255 || nBrightness > 255)

   return false;

  BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width,

                                    b.Height), ImageLockMode.ReadWrite,

                                    PixelFormat.Format24bppRgb);

  int stride = bmData.Stride;

  System.IntPtr Scan0 = bmData.Scan0;

  int nVal = 0;

  unsafe

  {

   byte * p = (byte *)(void *)Scan0;

   int nOffset = stride - b.Width*3;

   int nWidth = b.Width * 3;

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

   {

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

       {

    nVal = (int) (p[0] + nBrightness);

    if (nVal < 0) nVal = 0;

    if (nVal > 255) nVal = 255;

    p[0] = (byte)nVal;

    ++p;

        }

       p += nOffset;

   }

  }

  b.UnlockBits(bmData);

  return true;

 }

  本函数完成的功能是对图像进行增亮处理,它比上面两个函数多了一个增亮参数-nBrightness,该参数由用户输入,范围为-255~255。在取得了增亮参数后,函数的unsafe代码部分对每个象素点的不同颜色成分进行逐个处理,即在原来值的基础上加上一个增亮参数以获得新的值。同时代码中还有一个防止成分值越界的操作,因为RGB成分值的范围为0~255,一旦超过了这个范围就要重新设置。函数最后执行成功后,同样得返回true值。

  该函数实现的程序效果如下:

 

  首先,我们把图像增亮的参数设置为100(其范围为-255~255),然后执行效果如下,读者也可尝试其他的参数值。

 

  三.小结:

  本文通过一个简单的实例向大家展现了用Visual C#以及GDI+完成数字图像处理的基本方法,通过实例,我们不难发现合理运用新技术不仅可以大大简化我们的编程工作,还可以提高编程的效率。不过我们在运用新技术的同时也得明白掌握基本的编程思想才是最主要的,不同的语言、不同的机制只是实现的具体方式不同而已,其内在的思想还是相通的。对于上面的例子,掌握了编写图像处理函数的算法,用其他的方式实现也应该是可行的。同时,在上面的基础上,读者不妨试着举一反三,编写出更多的图像处理的函数来,以充实并完善这个简单的实例。

image与byte数组的转换

image to byte[]

  MemoryStream ms=new MemoryStream();
   byte[] imagedata=null;
   pictureBox1.Image.Save(ms,System.Drawing.Imaging.ImageFormat.Gif );
   imagedata=ms.GetBuffer ();

byte[] to image

  ms = New IO.MemoryStream(by)
  img = Drawing.Image.FromStream(ms)

 

2007-05-05 05:36:00 sswwee 阅读数 1135
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    17306 人正在学习 去看看 张建飞
2017-02-09 21:21:01 qwezhaohaihong 阅读数 3433
  • C#急速入门

    Unity开发,C#绝对是基础中的基础,课程针对纯小白而设计,各种语言细节在课程里均有涉猎,从原理到实战,从底层到算法,你想了解的C#,这里应有尽有,除了讲解,还有练习,你说棒不棒,哈哈,当然如果你是有其他语言基础的同学,课程依然会让你收货满满。来吧,我们进入正题。

    17306 人正在学习 去看看 张建飞
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

//出现图像的不完全处理的原因是我们打开的24为bmp图像而不是书上说的8为bmp图像
//因此图像的像素点是height*width*3

namespace Transfer
{
    public partial class Form1 : Form
    {
        private string curFileName;
        private System.Drawing.Bitmap curBitmap;
        public Form1()
        {
            InitializeComponent();
        }

        private void open_Click(object sender, EventArgs e)
        {
            OpenFileDialog opnDlg = new OpenFileDialog();
            //为图像选择一个筛选器
            opnDlg.Filter = "所有图像文件|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico;*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf|" +
                "位图(*.bmp;*.jpg;*.png;...)|*.bmp;*.pcx;*.png;*.jpg;*.gif;*.tif;*.ico|" +
                "矢量图(*.wmf;*.eps;*.emf;...)|*.dxf;*.cgm;*.cdr;*.wmf;*.eps;*.emf";
            //设置对话框标题
            opnDlg.Title = "打开图像文件";
            //启用“帮助”功能
            opnDlg.ShowHelp = true;
            //如果结果为“打开”,选定文件
            if (opnDlg.ShowDialog() == DialogResult.OK)
            {
                //读取当前选中的文件名
                curFileName = opnDlg.FileName;
                //使用Image.FromFile创建图像对象
                try
                {
                    curBitmap = (Bitmap)Image.FromFile(curFileName);
                }
                catch (Exception exp)
                {
                    //抛出异常
                    MessageBox.Show(exp.Message);
                }
            }
            //对窗体进行重新绘制,这将强制执行paint事件处理程序
            Invalidate();
        }

        private void close_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void close_Paint(object sender, PaintEventArgs e)
        {

        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            if (curBitmap != null)
            {
                //使用DrawImage方法绘制图像
                //160,20显示在主窗体内,图像左上角的坐标
                g.DrawImage(curBitmap, 160, 20, curBitmap.Width, curBitmap.Height);
            }
        }

        private void translation_Click(object sender, EventArgs e)
        {
            if(curBitmap!= null)
            {
                translation traForm = new translation();
                if(traForm.ShowDialog()==DialogResult.OK)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect,
                        System.Drawing.Imaging.ImageLockMode.ReadWrite,
                        curBitmap.PixelFormat);
                    //得到首地址
                    IntPtr ptr = bmpData.Scan0;
                    //24为bmp位图字节数
                    int bytes = curBitmap.Width * curBitmap.Height * 3;
                    //定义位图数组
                    byte[] grayValues = new byte[bytes];
                    //复制被锁定的位图像素值到该数组内
                    System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
                    //得到两个方向的图像平移量
                    int x = Convert.ToInt32(traForm.GetXOffset);
                    int y = Convert.ToInt32(traForm.GetYOffset);
                    byte[] tempArray = new byte[bytes];
                    //临时数组初始化为白色255像素
                    for(int i=0;i<bytes;i++)
                    {
                        tempArray[i] = 255;
                    }
                    //平移运算
                    for(int i=0;i<curBitmap.Height;i++)
                    {
                        //保证纵向平移不出界限
                        if((i+y)<(curBitmap.Height)&&(i+y)>0)
                        {
                            for(int j=0;j<(curBitmap.Width*3);j++)
                            {
                                //保证横向平移不出界
                                if((j+x)< (curBitmap.Width*3)&& (j+x)>0)
                                {
                                    tempArray[(j + x) + (i + y) * curBitmap.Width*3] = grayValues[j + i * curBitmap.Width*3];
                                }
                            }
                        }
                    }
                    grayValues = (byte[])tempArray.Clone();
                    System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
                    curBitmap.UnlockBits(bmpData);
                }
                Invalidate();
            }
        }

        private void mirror_Click(object sender, EventArgs e)
        {
            if(curBitmap!=null)
            {
                //实例化窗体mirror
                mirror mirForm = new mirror();
                if(mirForm.ShowDialog()==DialogResult.OK)
                {
                    //位图矩形
                    Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
                    //以可读写的方式锁定全部位图像素
                    System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect,
                        System.Drawing.Imaging.ImageLockMode.ReadWrite,
                        curBitmap.PixelFormat);
                    //得到首地址
                    IntPtr ptr = bmpData.Scan0;
                    //24为bmp位图字节数
                    int bytes = curBitmap.Width * curBitmap.Height * 3;
                    //定义位图数组
                    byte[] grayValues = new byte[bytes];
                    //复制被锁定的位图像素值到该数组内
                    System.Runtime.InteropServices.Marshal.Copy(ptr, grayValues, 0, bytes);
                    //水平中轴
                    int halfWidth = (curBitmap.Width*3) / 2;
                    //垂直中轴
                    int halfHeight = (curBitmap.Height) / 2;
                    byte temp;
                    if(mirForm.GetMirror)
                    {
                        //水平镜像处理
                        for(int i=0;i<curBitmap.Height;i++)
                        {
                            for(int j=0;j<halfWidth;j++)
                            {
                                //以水平中轴线为对称轴,两边像素值交换
                                temp = grayValues[i * curBitmap.Width*3 + j];
                                grayValues[i * curBitmap.Width*3 + j] = grayValues[(i + 1) * curBitmap.Width*3 - 1 - j];
                                grayValues[(i + 1)*curBitmap.Width*3 - 1 - j] = temp;

                            }
                        }
                    }
                    else
                    {
                        //垂直镜像处理
                        for(int i=0;i<curBitmap.Width*3;i++)
                        {
                            for(int j=0;j<halfHeight;j++)
                            {
                                //以垂直中轴线为对称轴。两边像素值互换
                                temp = grayValues[j * curBitmap.Width*3 + i];
                                grayValues[j * curBitmap.Width*3 + i] = grayValues[(curBitmap.Height - j - 1) * curBitmap.Width*3 + i];
                                grayValues[(curBitmap.Height - j - 1) * curBitmap.Width*3 + i] = temp;
                            }
                        }
                    }
                    System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr, bytes);
                    curBitmap.UnlockBits(bmpData);
                }
                Invalidate();
            }
        }
    }
}
//要注意24位灰度图像是1440万色,但是我们书上给的算法是对8为进行处理,但是我们可以采用分割的思想将24位拆开成
//3个8位,由这三个8为所保存的数据组合为24位,在处理的时候就将他们分开处理但是要整体观看
//其中的 curBit.Height*3这个处理是关键 

//以上只是主窗体里面的代码和自己的思考,方便以后复习,写的不是很好

使用C#进行图像处理

阅读数 15349

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