private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
Bitmap bmp = new Bitmap("rama.jpg");//加载图像
//填充窗体背景为白色
new Point(100, 0), // destination for upper-left point of original
new Point(0, 0)}; // destination for lower-left point of original
//旋转图像180°代码如下:
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, this.ClientRectangle);
new Point(0, 100), // destination for upper-left point of original
new Point(0, 0)}; // destination for lower-left point of original
//图像切变代码:
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, this.ClientRectangle);
new Point(0, 0), // destination for upper-left point of original
new Point(50, 100)};// destination for lower-left point of original
//图像截取:
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, this.ClientRectangle);
//要截取的矩形区域
//要显示到Form的矩形区域
//改变图像大小:
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.White, this.ClientRectangle);
int height = bmp.Height;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
GraphicsUnit.Pixel);
//g.CompositingQuality = CompositingQuality.HighSpeed;
g.DrawImage(
new Rectangle(130, 10, 120, 120),
GraphicsUnit.Pixel);
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
Bitmap bmp = new Bitmap("rama.jpg");
bmp.SetResolution(300f, 300f);
bmp.SetResolution(1200f, 1200f);
//用GDI+画图
{
Graphics gForm = e.Graphics;
for (int i = 1; i <= 7; ++i)
this.ClientRectangle.Height);
Bitmap bmp = new Bitmap(260, 260,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
gBmp.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// 并将其画在内存的位图里面
Brush redBrush = new SolidBrush(red);
// 创建一个带有Alpha的绿色区域
Brush greenBrush = new SolidBrush(green);
//在窗体上面画出位图 now draw the bitmap on our window
// 清理资源
gBmp.Dispose();
greenBrush.Dispose();
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
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);
一. 底片效果
效果图:
{
try
int Height = this.pictureBox1.Image.Height;
Bitmap newbitmap = new Bitmap(Width, Height);
Color pixel;
{
{
pixel = oldbitmap.GetPixel(x, y);
g = 255 - pixel.G;
newbitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
{
}
private void button1_Click(object sender, EventArgs e)
//以浮雕效果显示图像
{
int Width = this.pictureBox1.Image.Width;
Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
for (int x = 0; x < Width - 1; x++)
for (int y = 0; y < Height - 1; y++)
int r = 0, g = 0, b = 0;
pixel2 = oldBitmap.GetPixel(x + 1, y + 1);
g = Math.Abs(pixel1.G - pixel2.G + 128);
if (r > 255)
if (r < 0)
if (g > 255)
if (g < 0)
if (b > 255)
if (b < 0)
newBitmap.SetPixel(x, y, Color.FromArgb(r, g, b));
}
}
{
}
private void button1_Click(object sender, EventArgs e)
//以黑白效果显示图像
{
int Width = this.pictureBox1.Image.Width;
Bitmap oldBitmap = (Bitmap)this.pictureBox1.Image;
for (int x = 0; x < Width; x++)
{
int r, g, b, Result = 0;
g = pixel.G;
//实例程序以加权平均值法产生黑白图像
switch (iType)
case 0://平均值法
break;
Result = r > g ? r : g;
break;
Result = ((int)(0.7 * r) + (int)(0.2 * g) + (int)(0.1 * b));
}
}
}
{
}
private void button1_Click(object sender, EventArgs e)
//以柔化效果显示图像
{
int Width = this.pictureBox1.Image.Width;
Bitmap MyBitmap = (Bitmap)this.pictureBox1.Image;
//高斯模板
for (int x = 1; x < Width - 1; x++)
{
int Index = 0;
for (int row = -1; row <= 1; row++)
pixel = MyBitmap.GetPixel(x + row, y + col);
g += pixel.G * Gauss[Index];
Index++;
r /= 16;
b /= 16;
r = r > 255 ? 255 : r;
g = g > 255 ? 255 : g;
b = b > 255 ? 255 : b;
bitmap.SetPixel(x - 1, y - 1, Color.FromArgb(r, g, b));
this.pictureBox1.Image = bitmap;
catch (Exception ex)
MessageBox.Show(ex.Message, "信息提示");
}
五.锐化效果
原理:突出显示颜色值大(即形成形体边缘)的像素点.
效果图:
实现代码:
{
try
int Height = this.pictureBox1.Image.Height;
Bitmap newBitmap = new Bitmap(Width, Height);
Color pixel;
int[] Laplacian ={ -1, -1, -1, -1, 9, -1, -1, -1, -1 };
for (int y = 1; y < Height - 1; y++)
int r = 0, g = 0, b = 0;
for (int col = -1; col <= 1; col++)
{
g += pixel.G * Laplacian[Index];
Index++;
//处理颜色值溢出
r = r < 0 ? 0 : r;
g = g < 0 ? 0 : g;
b = b < 0 ? 0 : b;
}
}
{
}
实现代码:
{
try
int Height = this.pictureBox1.Image.Height;
Bitmap newBitmap = new Bitmap(Width, Height);
Color pixel;
for (int y = 1; y < Height - 1; y++)
System.Random MyRandom = new Random();
//像素块大小
int dy = y + k % 19;
dx = Width - 1;
dy = Height - 1;
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控件来显示图片,如下:
{
ofd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
ofd.CheckPathExists = true;
{
bmp = new Bitmap(ofd.FileName);
{
return;
pbxShowImage.Image = bmp;
}
其中bmp为类的一个对象:private Bitmap bmp=null;
二、保存图像
{
sfd.Filter = "BMP Files(*.bmp)|*.bmp|JPG Files(*.jpg;*.jpeg)|*.jpg;*.jpeg|All Files(*.*)|*.*";
{
MessageBox.Show("保存成功!","提示");
}
三、对像素的访问
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
namespace ImageElf
class GrayBitmapData
public byte[,] Data;//保存像素矩阵
//图像的宽度
//图像的高度
public GrayBitmapData()
this.Width = 0;
this.Data = null;
{
this.Width = bmpData.Width;
Data = new byte[Height, Width];
{
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
//将24位的RGB彩色图转换为灰度图
Data[i, j] = (byte)temp;
ptr += bmpData.Stride - Width * 3;//指针加上填充的空白空间
}
}
public GrayBitmapData(string path)
{
{
BitmapData bmpData=bmp.LockBits(new Rectangle(0,0,Width,Height),ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
{
for(int i=0;i<Height;i++)
for(int j=0;j<Width;j++)
*(ptr++)=Data[i,j];
*(ptr++)=Data[i,j];
ptr+=bmpData.Stride-Width*3;
}
return bmp;
{
pbx.Image = b;
}
public void SaveImage(string path)
Bitmap b=ToBitmap();
//b.Dispose();
//均值滤波
{
{
}
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
int sum = 0;
{
{
if (a < 0) a = 0;
if (b < 0) b = 0;
sum += Data[a, b];
}
}
}
public void MidFilter(int windowSize)
if (windowSize % 2 == 0)
return;
byte[,] newdata = new byte[Height, Width];
{
{
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 > Height - 1) a = Height - 1;
if (b > Width - 1) b = Width - 1;
}
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];
}
//获得一个向量的中值
{
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[j] = temp;
}
}
public void NewFilter(int windowSize)
if (windowSize % 2 == 0)
return;
{
{
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 > Height - 1) a = Height - 1;
if (b > Width - 1) b = Width - 1;
}
double avg = (sum+0.0) / (windowSize * windowSize);
{
}
{
}
}
//直方图均衡
{
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];
for (int i = 0; i < 256; i++)
n += num[i];
}
for (int i = 0; i < Height; i++)
for (int j = 0; j < Width; j++)
Data[i,j]=(byte)newGray[Data[i,j]];
}
}
一个按钮来做各种调用:
private void btnAvgFilter_Click(object sender, EventArgs e)
if (bmp == null) return;
gbmp.AverageFilter(3);
}
private void btnToGray_Click(object sender, EventArgs e)
if (bmp == null) return;
gbmp.ShowImage(pbxShowImage);