• 全部
...

C# bmp图像取像素问题

hzhsky1985 2008-05-21 02:29:42
小弟近日开发一套程序,其中一个功能需要对图像取像素。我用的是.GetPixel方法,但发觉这个方法太慢了(已把扫描的范围尽量缩到最小啦),达不到客户的要求,请问高手有其他更快的方法吗?
...全文
给本帖投票
912 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
huang_8228 2008-05-23
  • 打赏
  • 举报
回复
p += n就是p = p+n
王集鹄 2008-05-21
  • 打赏
  • 举报
回复
n = 3 ....

对于24位色的位图,一个像素需要24个bit表示--即:3个byte(24 / 8)
这里的n就表示访问下一个像素需要偏移几个字节。。。
BitmapData.Scan0属性表示第一个像素(注意第一个像素是在左下角)存放的内存地址。。。
hzhsky1985 2008-05-21
  • 打赏
  • 举报
回复
自己顶一下,上面的写错了,我意思是
nt n = 3;
int w = pictureBox1.Image.Width;
int h = pictureBox1.Image.Height ;
Color c;
Graphics f = pictureBox1.CreateGraphics();
// bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
// pictureBox1.Image = bmp;
bmp = new Bitmap(pictureBox1.Image);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h),ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
unsafe
{
// 将原始图片变成灰度二位数组
byte* p = (byte*)data.Scan0;
byte[,] vSource = new byte[w, h];
int offset = data.Stride - w * n;

for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
vSource[x, y] = (byte)(((int)p[0] + (int)p[1] + (int)p[2]) / 3);
p += n;
}
p += offset;
}

bmp.UnlockBits(data);
// 将灰度二位数组变成二值图像
bmpDest = new Bitmap(w, h, PixelFormat.Format24bppRgb);
BitmapData dataDest = bmpDest.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);

p = (byte*)dataDest.Scan0;
offset = dataDest.Stride - w * n;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
p[0] = p[1] = p[2] = (int)GetAverageColor(vSource, x, y, w, h) > 120 ? (byte)255 : (byte)0;
p += n;
}
p += offset;
}

bmpDest.UnlockBits(dataDest);
pictureBox1.Image = bmpDest;

}
这是一个变为二值化的代码,我想问其中的p += n这句是什么意思
hzhsky1985 2008-05-21
  • 打赏
  • 举报
回复
还有一个地方不理解的。
p[0] = p[1] = p[2] = 255;
p += n;
p+=n这句是什么意思。
hzhsky1985 2008-05-21
  • 打赏
  • 举报
回复
谢谢楼上各位,具体的方法我已想到,但可不可行就要靠我慢慢调试了,这里再问一下,用Bitmap.LockBits()取边缘,可行吗?
王集鹄 2008-05-21
  • 打赏
  • 举报
回复
通过Bitmap.LockBits()方法直接扫描位图的内存

如下代码是取图像透明区域的,供参考:
using System.Runtime.InteropServices;

[DllImport("gdi32.dll")]
public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount,
ref byte lpRgnData);

public static int RGN_AND = 1;
public static int RGN_OR = 2;
public static int RGN_XOR = 3;
public static int RGN_DIFF = 4;
public static int RGN_COPY = 5;
public static int RGN_MIN = RGN_AND;
public static int RGN_MAX = RGN_COPY;

[DllImport("gdi32.dll")]
public static extern int CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2,
int fnCombineMode);

[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

public Region ImageToRegion(Image AImage, Color ATransparent)
{
//转贴请注明出处ZswangY37(wjhu111#21cn.com) 时间2007-05-25
if (AImage == null) return null;
Bitmap vBitmap = new Bitmap(AImage);
BitmapData vBitmapData = vBitmap.LockBits(
new Rectangle(0, 0, vBitmap.Width, vBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
int vAddress = (int)vBitmapData.Scan0;
int vOffset = vBitmapData.Stride - vBitmap.Width * 4; // 每行多出的字节数
int h = vBitmap.Height, w = vBitmap.Width;
int vTransparent = ColorTranslator.ToWin32(ATransparent); // 透明色
int vAllocRect = (0x1000 - sizeof(uint) * 8) / sizeof(int); // 预分配的矩形数
if (h * w < vAllocRect) vAllocRect = h * w;
Byte[] vBuffer = new byte[sizeof(uint) * 8 + sizeof(int) * 4 * vAllocRect];
//头信息dwSize\iType\nCount\nRegSize
uint vCount = 0;
vBuffer[0] = sizeof(uint) * 8; //dwSize//头信息大小
vBuffer[4] = 1; //iType//int RDH_RECTANGLES = 1;//数据类型
IntPtr vResult = IntPtr.Zero;

uint vPointer = sizeof(uint) * 8;

bool vWriteRect = false;
bool vWriteAlways = false;

for (int y = 0; y < h; y++)
{
int vBlockStart = 0;
bool vLastMaskBit = false;

for (int x = 0; x < w; x++)
{
int i = Marshal.ReadInt32((IntPtr)vAddress) & 0x00FFFFFF;
if (vTransparent == i) // 透明色
{
if (vLastMaskBit)
vWriteRect = true;
}
else
{
if (!vLastMaskBit)
{
vBlockStart = x;
vLastMaskBit = true;
}
}
if (x == w - 1)
{
if (y == h - 1)
{
vWriteRect = true;
vWriteAlways = true;
}
else if (vLastMaskBit)
{
vWriteRect = true;
}
x++;
}
if (vWriteRect)
{
if (vLastMaskBit)
{
vCount++;
WriteRect(vBuffer, ref vPointer,
new Rectangle(vBlockStart, y, x - vBlockStart, 1));
}
if (vCount == vAllocRect || vWriteAlways)
{

vBuffer[8] = (byte)vCount;
vBuffer[9] = (byte)(vCount >> 8);
vBuffer[10] = (byte)(vCount >> 16);
vBuffer[11] = (byte)(vCount >> 24);
IntPtr hTemp = ExtCreateRegion(IntPtr.Zero,
sizeof(uint) * 8 + sizeof(int) * 4 * vCount,
ref vBuffer[0]);
if (vResult == IntPtr.Zero)
vResult = hTemp;
else
{
CombineRgn(vResult, vResult, hTemp, RGN_OR);
DeleteObject(hTemp);
}
vCount = 0;
vPointer = sizeof(uint) * 4;
vWriteAlways = false;
}
vWriteRect = false;
vLastMaskBit = false;
}
vAddress += 4;
}
vAddress += vOffset;
}

vBitmap.UnlockBits(vBitmapData);
return Region.FromHrgn(vResult);
}

private void WriteRect(byte[] ARGNData, ref uint ptr, Rectangle r)
{
ARGNData[ptr] = (byte)r.X;
ARGNData[ptr + 1] = (byte)(r.X >> 8);
ARGNData[ptr + 2] = (byte)(r.X >> 16);
ARGNData[ptr + 3] = (byte)(r.X >> 24);
ARGNData[ptr + 4] = (byte)r.Y;
ARGNData[ptr + 5] = (byte)(r.Y >> 8);
ARGNData[ptr + 6] = (byte)(r.Y >> 16);
ARGNData[ptr + 7] = (byte)(r.Y >> 24);
ARGNData[ptr + 8] = (byte)r.Right;
ARGNData[ptr + 9] = (byte)(r.Right >> 8);
ARGNData[ptr + 10] = (byte)(r.Right >> 16);
ARGNData[ptr + 11] = (byte)(r.Right >> 24);
ARGNData[ptr + 12] = (byte)r.Bottom;
ARGNData[ptr + 13] = (byte)(r.Bottom >> 8);
ARGNData[ptr + 14] = (byte)(r.Bottom >> 16);
ARGNData[ptr + 15] = (byte)(r.Bottom >> 24);
ptr += 16;
}

private void button1_Click(object sender, EventArgs e)
{
Region = ImageToRegion(pictureBox1.Image, Color.FromArgb(216, 233, 236));
}

wood87654321 2008-05-21
  • 打赏
  • 举报
回复
很遗憾,没有更快或更直接的办法,你必须自己编程去对应点与数据字节的关系,Bitmap的像素数据结构与BMP文件数据一样并不复杂
hzhsky1985 2008-05-21
  • 打赏
  • 举报
回复
我也知道可以用这个方法,也正在研究中,但问题是我还要根据图像和某些条件得到相应点的坐标,如果用Bitmap.LockBits恐怕有点难实现,请教有具体的方法吗
wood87654321 2008-05-21
  • 打赏
  • 举报
回复
当然,仔细研究一下Bitmap.LockBits

111,092

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧

手机看
关注公众号

关注公众号

客服 返回
顶部