按图像跟踪球的位置

时间:2013-06-22 21:37:11

标签: c# vb.net winforms bitmap pixels

让我说我有这个形象:
http://srv2.jpg.co.il/9/51c614f7c280e.png
我想获得白球位置(x,y),
这是一张verey大图像,然后我按矩形切割图像
(因为当图像较小时,一切都更快),
结果:
http://srv2.jpg.co.il/1/51c616787a3fa.png
现在我想通过他的颜色跟踪白球位置(白色= rbg(255,255,255)),
我的代码:

Public Function GetBallPosition(ByRef HaxScreenOnly As Bitmap) As Point
    For y = 0 To HaxScreenOnly.Height - 1
        For x = 0 To HaxScreenOnly.Width - 1
            If HaxScreenOnly.GetPixel(x, y) = Color.FromArgb(0, 0, 0) Then
                If HaxScreenOnly.GetPixel(x + 8, y) = Color.FromArgb(0, 0, 0) And HaxScreenOnly.GetPixel(x + 8, y + 3) = Color.FromArgb(255, 255, 255) Then
                    Return New Point(x, y)

                End If
            End If
        Next
    Next
    Return New Point(0, 0)
End Function


如果当前像素的颜色为黑色且当前像素的颜色(x + 8,y + 3)为白色,那么这就是球
它正在工作......但它的速度很慢,比如200毫秒来跟踪球的位置 这还不够快。
有更快的方法来跟踪白球( C#或VB.net )?

1 个答案:

答案 0 :(得分:2)

最后,我为您提供了解决方案。调用GetPixel是一个代价高昂的过程,但您使用Bitmap.LockBits并操纵/访问指针中的图像数据。我从 this article

获取了LockBitmap课程

我检查了我之前获得的表现,就像你提到的那样,大约200ms~。

以下是使用LockBitmap的结果图片,使用优化的代码连续重新扫描图像! Here's a picture

static void Main(string[] args)
{
    byte[] data = new WebClient().DownloadData("http://srv2.jpg.co.il/1/51c616787a3fa.png");
    Image image = Image.FromStream(new MemoryStream(data));

    LockBitmap bitmap = new LockBitmap(new Bitmap(image));
    // this essentially copies the data into memory and copies from a pointer to an array
    bitmap.LockBits();

    Color black = Color.FromArgb(0, 0, 0);
    Color white = Color.FromArgb(255, 255, 255);

    Stopwatch stopwatch = Stopwatch.StartNew();

    for (int y = 0; y < bitmap.Height; y++)
    {
        for (int x = 0; x < bitmap.Width; x++)
        {
            // GetPixel is a nice abstraction the author in the Article created so we don't have to do any of the gritty stuff.
            if (bitmap.GetPixel(x, y) == black)
            {
                if (bitmap.GetPixel(x + 8, y) == black && bitmap.GetPixel(x + 8, y + 3) == white)
                {
                    Console.WriteLine("White Ball Found in {0}", stopwatch.Elapsed.ToString());
                    break;
                }
            }
        }
    }

    bitmap.UnlockBits(); // copies the data from the array back to the original pointer

    Console.Read();
}

希望这有帮助,对我来说这当然是一个有趣的读物。

更新

正如King所说,我能够根据算法的改进进一步缩短你的时间。所以我们已经从O(n)变为O(n log)时间复杂度(我认为)。

Algorithm improvement

for (int y = 0; y < bitmap.Height; y += 3) // As we know the radius of the ball
{
    for (int x = 0; x < bitmap.Width; x += 3) // We can increase this
    {
        if (bitmap.GetPixel(x, y) == black && bitmap.GetPixel(x, y + 3) == white)
        {
            Console.WriteLine("White Ball Found ({0},{1}) in {2}", x, y, stopwatch.Elapsed.ToString());
            break;
        }
    }
}