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

  • Post author:
  • Post category:其他





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 窗体一起使用,它需要

PaintEventArgs


e

,即

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


}