c#图像处理入门

一.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)

时间: 2024-10-13 09:50:34

c#图像处理入门的相关文章

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

c#图像处理入门 -bitmap类和图像像素值获取方法 一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetPixel方法和SetPixel方法:获取和设置一个图像的指定像素的颜色. 2. PixelFormat属性:返回图像的像素格式. 3. Palette属性:获取和设置图像所使用的颜色调色板. 4. Height Width属性:返回图像的高度和

图像处理入门教程

最近有人问我图像处理怎么研究,怎么入门,怎么应用,我竟一时语塞.仔细想想,自己也搞了两年图像方面的研究,做个两个创新项目,发过两篇论文,也算是有点心得,于是总结总结和大家分享,希望能对大家有所帮助.在写这篇教程之前我本想多弄点插图,让文章看起来花哨一点,后来我觉得没必要这样做,大家花时间沉下心来读读文字没什么不好,况且学术和技术本身也不是多么花哨的东西. 一.图像处理的应用 这个其实没什么好说的,一种技术的应用价值不是靠嘴上说,而是要看有多少人去搞,很简单的道理.其实我觉得判断一项技术有没有价值

实用图像处理入门 - 合集

实用图像处理入门 - 1 - opencv VS2012 环境搭建 实用图像处理入门 - 2 - Windows平台下编译openCV 实用图像处理入门 - 3 - 训练自己的识别器 实用图像处理入门 - 合集

对比《Keras图像深度学习实战》PDF+《深度学习技术图像处理入门》PDF代码分析

将深度学习技术应用于图像处理,推荐阅读<深度学习技术图像处理入门>,基于理论讲解,由浅入深地引出若干个经典案例,讲解当前深度神经网络在图像处理领域的应用.提供了基于云GPU容器(Docker)的完整在线开发环境,方便初学者直接学习核心代码. <深度学习技术图像处理入门>以通俗易懂的语言简要讲解机器学习的核心概念,通过比较传统机器学习和深度神经网络的区别,引入深度神经网络的应用领域,将一个完整的深度神经网络的复杂结构拆成输入处理.模型元件以及模型优化三个子块,并详细说明如何将深度神经

入门实战《深度学习技术图像处理入门》+《视觉SLAM十四讲从理论到实践》

学习图像识别处理,想在数据分析竞赛中取得较高的排名,看了<深度学习技术图像处理入门>电子书,一边看电子书一边做标记,对配套的代码也做了测试,收获颇多. 从机器学习.图像处理的基本概念入手,逐步阐述深度学习图像处理技术的基本原理以及简单的实现. 学习理论后做实验,使用卷积神经网络进行端到端学习,构建深度卷积神经网络,使用循环神经网络改进模型,评估模型,测试模型.最关键的是可以将模型运用于实战之中,将深度学习模型导入到工程中,数据类型转换函数,实施CAM可视化,这是我最需要的. 视觉和图形学真是一

【转载】大话图像处理之入门篇

原文链接:http://c.biancheng.net/cpp/html/3077.html 本文由@陈俊岭编辑. 最近有人问我图像处理怎么研究,怎么入门,怎么应用,我竟一时语塞.仔细想想,自己也搞了两年图像方面的研究,做个两个创新项目,发过两篇论文,也算是有点心得,于是总结总结和大家分享,希望能对大家有所帮助. 在写这篇教程之前我本想多弄点插图,让文章看起来花哨一点,后来我觉得没必要这样做,大家花时间沉下心来读读文字没什么不好,况且学术和技术本身也不是多么花哨的东西. 一.图像处理的应用 这个

Python_Imaging_Library中文手册、PIL中文手册、python图像处理

Python Imaging Library 中文手册 这是PIL的官方手册,2005年5月6日发布.这个版本涵盖 PIL 1.1.5的全部内容.本中文手册来自Woodpecker.org.cn 啄木鸟社区 你可以在PythonWare library找到改文档其它格式的版本以及先前的版本. 原版出处:http://www.pythonware.com/library/pil/handbook/ 目录 Python Imaging Library 中文手册 第一部分:介绍 概览 介绍 图像归档处

总会有一个是你需要的

http://www.shouce.ren/post/d/id/112300 黑客攻防实战入门与提高.pdfhttp://www.shouce.ren/post/d/id/112299 黑客入门新手特训.pdfhttp://www.shouce.ren/post/d/id/112298 黑客与设计-剖析设计之美的秘密(彩印).pdfhttp://www.shouce.ren/post/d/id/112297 鸟哥的LINUX私房菜:服务器架设篇 (第二版).pdfhttp://www.shouc

python PIL学习

http://www.pythonware.com/products/pil/index.htm 文档 例子:http://www.cnblogs.com/way_testlife/archive/2011/04/17/2019013.html    http://onlypython.group.iteye.com/group/wiki/1371-python-graphics-library-pil-python-image-library-introduction http://wenku