看了网上的方法,如何将24位真彩图转化为8位灰度图像,核心问题就是重置颜色灰阶,但是用下面两种方法保存的图片为嘛会出现不一样?急求助 private void convert_Click(object sender, EventArgs e)
{
if (curBitmap != null)
{
//新的我要的8位图像容器
Bitmap bit = new Bitmap(curBitmap.Width, curBitmap.Height, PixelFormat.Format8bppIndexed);
//可读写的方式锁定全部原图像
BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, curBitmap.Width, curBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
//得到首地址
IntPtr ptr1 = data.Scan0;
//可读写的方式锁定全部容器
BitmapData data2 = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
//得到首地址
IntPtr ptr2 = data2.Scan0;
//计算24位图像的字节数
int bytes = curBitmap.Width * curBitmap.Height * 3;
//定义位图数组
byte[] grayValues = new byte[bytes];
//复制被锁定的图像到该数组
System.Runtime.InteropServices.Marshal.Copy(ptr1, grayValues, 0, bytes);
//同上
int byte8 = curBitmap.Width * curBitmap.Height;
byte[] gray8Values = new byte[byte8];
System.Runtime.InteropServices.Marshal.Copy(ptr2, gray8Values, 0, byte8); for (int i = 0, n = 0; i < bytes; i += 3, n++)
{
//灰度变换
double colorTemp = grayValues[i + 2] * 0.299 + grayValues[i + 1] * 0.589 + grayValues[i] * 0.114;
//将灰度值赋值给容器 这是新图8位
gray8Values[n] = (byte)colorTemp;
}
//送回数组
System.Runtime.InteropServices.Marshal.Copy(gray8Values, 0, ptr2, byte8);
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr1, bytes);
//解锁
curBitmap.UnlockBits(data);
bit.UnlockBits(data2);
//调色板
ColorPalette palette = bit.Palette;
//调色板结构体数组 填充
for (int i = 0; i != palette.Entries.Length; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
bit.Palette = palette; Bitmap b = bit.Clone(new Rectangle(0, 0, bit.Width, bit.Height), PixelFormat.Format8bppIndexed);
保存方法一、
b.Save(@"F:\C#\1.bmp", ImageFormat.Bmp);
Image image = (Bitmap)System.Drawing.Image.FromHbitmap(b.GetHbitmap());
pictureBox2.Image = image;
b.Dispose();
bit.Dispose();
Invalidate(); }
}
保存方法二、
private void save_Click(object sender, EventArgs e)
{
//如果没有创建图像,则退出
if (pictureBox2.Image == null)
{
return;
}
//调用SaveFileDialog
SaveFileDialog saveDlg = new SaveFileDialog();
//设置对话框标题
saveDlg.Title = "保存为";
//读写已存在文件时提示用户
saveDlg.OverwritePrompt = true;
//为图像选择一个筛选器
saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" +
"JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";
//启用“帮助”按钮
saveDlg.ShowHelp = true;
//如果选择了格式,则保存图像
if (saveDlg.ShowDialog() == DialogResult.OK)
{
//获取用户选择的文件名
string fileName = saveDlg.FileName;
//保存文件
Bitmap a = new Bitmap(pictureBox2.Image);
a.Save(fileName,ImageFormat.Bmp);
}
}
{
if (curBitmap != null)
{
//新的我要的8位图像容器
Bitmap bit = new Bitmap(curBitmap.Width, curBitmap.Height, PixelFormat.Format8bppIndexed);
//可读写的方式锁定全部原图像
BitmapData data = curBitmap.LockBits(new Rectangle(0, 0, curBitmap.Width, curBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
//得到首地址
IntPtr ptr1 = data.Scan0;
//可读写的方式锁定全部容器
BitmapData data2 = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
//得到首地址
IntPtr ptr2 = data2.Scan0;
//计算24位图像的字节数
int bytes = curBitmap.Width * curBitmap.Height * 3;
//定义位图数组
byte[] grayValues = new byte[bytes];
//复制被锁定的图像到该数组
System.Runtime.InteropServices.Marshal.Copy(ptr1, grayValues, 0, bytes);
//同上
int byte8 = curBitmap.Width * curBitmap.Height;
byte[] gray8Values = new byte[byte8];
System.Runtime.InteropServices.Marshal.Copy(ptr2, gray8Values, 0, byte8); for (int i = 0, n = 0; i < bytes; i += 3, n++)
{
//灰度变换
double colorTemp = grayValues[i + 2] * 0.299 + grayValues[i + 1] * 0.589 + grayValues[i] * 0.114;
//将灰度值赋值给容器 这是新图8位
gray8Values[n] = (byte)colorTemp;
}
//送回数组
System.Runtime.InteropServices.Marshal.Copy(gray8Values, 0, ptr2, byte8);
System.Runtime.InteropServices.Marshal.Copy(grayValues, 0, ptr1, bytes);
//解锁
curBitmap.UnlockBits(data);
bit.UnlockBits(data2);
//调色板
ColorPalette palette = bit.Palette;
//调色板结构体数组 填充
for (int i = 0; i != palette.Entries.Length; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
bit.Palette = palette; Bitmap b = bit.Clone(new Rectangle(0, 0, bit.Width, bit.Height), PixelFormat.Format8bppIndexed);
保存方法一、
b.Save(@"F:\C#\1.bmp", ImageFormat.Bmp);
Image image = (Bitmap)System.Drawing.Image.FromHbitmap(b.GetHbitmap());
pictureBox2.Image = image;
b.Dispose();
bit.Dispose();
Invalidate(); }
}
保存方法二、
private void save_Click(object sender, EventArgs e)
{
//如果没有创建图像,则退出
if (pictureBox2.Image == null)
{
return;
}
//调用SaveFileDialog
SaveFileDialog saveDlg = new SaveFileDialog();
//设置对话框标题
saveDlg.Title = "保存为";
//读写已存在文件时提示用户
saveDlg.OverwritePrompt = true;
//为图像选择一个筛选器
saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" +
"JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";
//启用“帮助”按钮
saveDlg.ShowHelp = true;
//如果选择了格式,则保存图像
if (saveDlg.ShowDialog() == DialogResult.OK)
{
//获取用户选择的文件名
string fileName = saveDlg.FileName;
//保存文件
Bitmap a = new Bitmap(pictureBox2.Image);
a.Save(fileName,ImageFormat.Bmp);
}
}
解决方案 »
- asp.net页面显示问题
- 画面中有一个控件,想连接到多个控件上单独操作,怎么写事件委托
- 两台服务器之间拷贝文件如何实现?
- 用C# 生成word文档 并设置样式 同时还要输出一副图片的问题
- 关于自定义控件的焦点
- HELP!怎样让WPF的XAML支持中文?
- [急]请问如何才能得到DataGrid中单击一个按钮得到此按钮的值,在线等,谢谢。
- 基于组件开发的优点在哪 ?
- webform中的treeview问题
- 在线等待:在SQLSERVER中相当于原FOX中备注字段类型的是哪个类型呀,就是我现在想存贮上万字的文字,但不知道把该字段的数据类型设为哪种
- |ZYCWPF| 关于WCF开发视频会议功能中,对视频传输的方法的问题:我现在是本地取得视频像头的一帧后转成Byte传给服务器,WCF通过双工回调发送给所有用户
- c#怎么解析json?
{
int X,Y;
int SrcStride,DestStride,Width,Height;
byte * SrcData,DestData;
BitmapData SrcBmpData = SrcImg.LockBits(new Rectangle(0, 0, SrcImg.Width, SrcImg.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
DestImg = new Bitmap(SrcImg.Width, SrcImg.Height, PixelFormat.Format8bppIndexed);
ColorPalette Pal = DestImg.Palette;
for (Y=0;Y<Pal.Entries.Length;Y++) // 设置灰度图像的调色板
Pal.Entries[Y]=Color.FromArgb(255,Y,Y,Y);
DestImg.Palette = Pal;
/* LockBits 在第一个参数和图像一样大,以及读取格式和原始一样的情况
* 下,调用函数的时间为0,且每次调用后BitmapData的Scan0都相同,而在
* 其他的大部分情况下同样参数调用该函数返回的Scan0都不同,这就说明在
* 在程序内部,GDI+为在创建图像时还是分配了和对应位图一样大小内存空间,
* 这样我们就可以再加载时调用一次该函数,并记住Scan0的值,然后直接用
* 指针操作这一片区域,就相当于操作了图像。而不用每次都LOCK和UNLOCK了
* 从这个层次上说,该函数和GetDibits类似。
*/ BitmapData DestBmpData = DestImg.LockBits(new Rectangle(0, 0, DestImg.Width, DestImg.Height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
Width =SrcBmpData.Width ;Height =SrcBmpData.Height ;
SrcStride =SrcBmpData.Stride;DestStride =DestBmpData.Stride ; // 这个值并不一定就等于width*height*色深/8
for (Y=0;Y<Height;Y++)
{
SrcData = (byte*)SrcBmpData.Scan0 + Y * SrcStride; // 必须在某个地方开启unsafe功能,其实C#中的unsafe很safe,搞的好吓人。
DestData= (byte *) DestBmpData.Scan0 + Y*DestStride;
for (X=0;X<Width;X++)
{
* DestData =(byte)((*SrcData*299 + *(SrcData+1)*587+*(SrcData+2)*114)/1000); //优化算法是通过移位实现的。
SrcData+=3;
DestData++;
}
}
SrcImg.UnlockBits(SrcBmpData);
DestImg.UnlockBits(DestBmpData);
}调用: private void button1_Click(object sender, EventArgs e)
{
Bitmap DestImg =null;
GetGrayModeImage ((Bitmap)pictureBox1.Image, ref DestImg);
pictureBox2.Image = DestImg;
pictureBox2.Refresh();
}
http://dongtingyueh.blog.163.com/blog/static/461945320114865323592/
{
//如果没有创建图像,则退出
if (pictureBox2.Image == null)
{
return;
}
//调用SaveFileDialog
SaveFileDialog saveDlg = new SaveFileDialog();
//设置对话框标题
saveDlg.Title = "保存为";
//读写已存在文件时提示用户
saveDlg.OverwritePrompt = true;
//为图像选择一个筛选器
saveDlg.Filter = "BMP文件(*.bmp)|*.bmp|" + "Gif文件(*.gif)|*.gif|" +
"JPEG文件(*.jpg)|*.jpg|" + "PNG文件(*.png)|*.png";
//启用“帮助”按钮
saveDlg.ShowHelp = true;
//如果选择了格式,则保存图像
if (saveDlg.ShowDialog() == DialogResult.OK)
{
//获取用户选择的文件名
string fileName = saveDlg.FileName;
//保存文件
Bitmap a = new Bitmap(pictureBox2.Image);
a.Save(fileName,ImageFormat.Bmp);
}
}
这样对整体有影响吗?
Bitmap a = new Bitmap(pictureBox2.Image);
说明.NET的这个构造函数确实会不管原始图像时申明色深,统一都创建为32位的。你要创建一个完全一样的,可以这样用
Bitmap a =(Bitmap) pictureBox1.Image.Clone();
Bitmap a = new Bitmap(pictureBox2.Image);
这句代码,如果 pictureBox2.Image是灰度图,创建的a却是32位的,两者不一致,当然保存后的就不一样了啊。
通过这条语句测试Bitmap a =(Bitmap) pictureBox1.Image.Clone();
a可以输出的是pictureBox1中的24位图像,也就是原始图像,所以不存在a创建的本身就是32位这一说