按颜色返回点定位像素
本文关键字:定位 像素 返回 颜色 | 更新日期: 2023-09-27 18:24:07
我需要找到具有指定颜色的第一个像素的点/坐标(x,y)。我已经使用了GetPixel()方法,但它有点太慢,并且正在研究LockBits。我怎么会搞不清楚这是否真的能解决我的问题。我可以使用LockBits返回找到的像素的点吗?
这是我当前的代码:
public Point FindPixel(Image Screen, Color ColorToFind)
{
Bitmap bit = new Bitmap(Screen);
BitmapData bmpData = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppPArgb);
unsafe
{
byte* ptrSrc = (byte*)bmpData.Scan0;
for (int y = 0; y < bmpData.Height; y++)
{
for (int x = 0; x < bmpData.Width; x++)
{
Color c = bit.GetPixel(x, y);
if (c == ColorToFind)
return new Point(x, y);
}
}
}
bit.UnlockBits(bmpData);
return new Point(0, 0);
}
您没有停止使用GetPixel(),所以您没有领先。改为这样写:
int IntToFind = ColorToFind.ToArgb();
int height = bmpData.Height; // These properties are slow so read them only once
int width = bmpData.Width;
unsafe
{
for (int y = 0; y < height; y++)
{
int* pline = (int*)bmpData.Scan0 + y * bmpData.Stride/4;
for (int x = 0; x < width; x++)
{
if (pline[x] == IntToFind)
return new Point(x, bit.Height - y - 1);
}
}
}
奇怪的Point构造函数是必要的,因为行是倒置存储在位图中的。失败时不要返回新的点(0,0),这是一个有效的像素。
您的代码有一些错误:
- 你使用的是PixelFormat.Format32ppPArgb-你应该使用图像的像素格式,如果它们不匹配,所有像素都会被复制到引擎盖下
- 您仍在使用
GetPixel
,所以所有这些麻烦都不会给您带来任何优势
为了有效地使用LockBits
,您基本上需要锁定图像,然后使用不安全的指针来获取像素值。不同像素格式的代码会有所不同,假设你真的有32bpp格式,蓝色在LSB上,你的代码可能看起来像这样:
for (int y = 0; y < bmpData.Height; ++y)
{
byte* ptrSrc = (byte*)(bmpData.Scan0 + y * bmpData.Stride);
int* pixelPtr = (int*)ptrSrc;
for (int x = 0; x < bmpData.Width; ++x)
{
Color col = Color.FromArgb(*pixelPtr);
if (col == ColorToFind) return new Point(x, y);
++pixelPtr; //Increate ptr by 4 bytes, because it is int
}
}
少数备注:
- 对于每一行,使用Scan0+步幅值计算新的ptrSrc。这是因为如果是
Stride != bpp * width
,那么仅仅增加指针可能会失败 - 我假设蓝色像素表示为LSB,alpha表示为MSB,但我认为事实并非如此,因为那些GDI像素格式是。。奇怪;),只要确保在使用
FromArgb()
方法之前检查它(如果是相反的话)反向字节 - 如果你的像素格式是24bpp,那就有点棘手了,因为你不能使用int指针并将其增加1(4字节),原因很明显