在另一张图片中查找图像

10

我正在尝试构建一个应用程序来解决一个谜题(尝试开发图形算法),我不想一直手动输入示例输入。

编辑: 我不是在尝试构建一个游戏。我正在尝试构建一个代理程序来玩游戏“SpellSeeker”

假设我有一个屏幕上的图像(见附件)其中有数字,我知道盒子的位置,并且我有这些数字的确切图像。我想要做的就是告诉哪个图像(数字)在相应的盒子中。

Numbers

所以我想我需要实现

bool isImageInsideImage(Bitmap numberImage,Bitmap Portion_Of_ScreenCap)或类似的东西。

我尝试过的是(使用AForge库)

public static bool Contains(this Bitmap template, Bitmap bmp)
{
    const Int32 divisor = 4;
    const Int32 epsilon = 10;

    ExhaustiveTemplateMatching etm = new ExhaustiveTemplateMatching(0.9f);

    TemplateMatch[] tm = etm.ProcessImage(
        new ResizeNearestNeighbor(template.Width / divisor, template.Height / divisor).Apply(template),
        new ResizeNearestNeighbor(bmp.Width / divisor, bmp.Height / divisor).Apply(bmp)
        );

    if (tm.Length == 1)
    {
        Rectangle tempRect = tm[0].Rectangle;

        if (Math.Abs(bmp.Width / divisor - tempRect.Width) < epsilon
            &&
            Math.Abs(bmp.Height / divisor - tempRect.Height) < epsilon)
        {
            return true;
        }
    }

    return false;
}

但是在搜索这张图片中的黑点时,它会返回false。

我应该如何实现它?


一些数独或井字棋游戏吗? - bonCodigo
你有看到其他关于类似主题的问题吗? - bonCodigo
这是一个名为“拼写搜寻者”的游戏。但重要的不是游戏本身,我只是想构建解决这类问题的算法。实际上,我在其他问题中找到了这个解决方案,但它们并没有帮助我。请原谅我的懒惰,但我真的认为应该有一种更简单的方法来解决这个问题 :) - marvin
对于这个有趣的问题点个赞。 :-) 假设您锁定了原始拼图。因此,您知道每个块在哪里 - 就像整个网格的点一样。当用户单击某个内容时,您不必查找图像,而是相应的点。并且您可以基于该点移动(复制/粘贴)子图像块。只是一个想法。 - bonCodigo
嗨,bonCodigo,我不知道我是否正确理解了你的评论,但我只想从图像中获取数字,而不是相反。这样我就可以初始化我的图形节点了。 - marvin
2个回答

5

因为我找到了解决方案,所以我来回答我的问题:

这个 对我有用:

System.Drawing.Bitmap sourceImage = (Bitmap)Bitmap.FromFile(@"C:\SavedBMPs\1.jpg");
            System.Drawing.Bitmap template = (Bitmap)Bitmap.FromFile(@"C:\SavedBMPs\2.jpg");
            // create template matching algorithm's instance
            // (set similarity threshold to 92.5%)

           ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f);
                // find all matchings with specified above similarity

                TemplateMatch[] matchings = tm.ProcessImage(sourceImage, template);
                // highlight found matchings

           BitmapData data = sourceImage.LockBits(
                new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
                ImageLockMode.ReadWrite, sourceImage.PixelFormat);
            foreach (TemplateMatch m in matchings)
            {

                    Drawing.Rectangle(data, m.Rectangle, Color.White);

                MessageBox.Show(m.Rectangle.Location.ToString());
                // do something else with matching
            }
            sourceImage.UnlockBits(data);

唯一的问题是它找到了所有(58个)该游戏的盒子。但将值0.921f更改为0.98使其完美,即仅找到指定数量的图像(模板)。

编辑:实际上我必须为不同的图片输入不同的相似度阈值。我通过尝试找到了优化的值,最终我有一个类似于以下的函数:

float getSimilarityThreshold(int number)

1
更好的方法是构建一个自定义类,它包含了您需要的所有信息,而不是依赖于图像本身。
例如:
public class MyTile
{
    public Bitmap TileBitmap;
    public Location CurrentPosition;
    public int Value;
}

这样,您可以“移动”瓷砖类并从Value字段中读取值,而无需分析图像。您只需将类所持有的任何图像绘制到其当前位置。

您的瓷砖可以存储在数组中,例如:

private list<MyTile> MyTiles = new list<MyTile>();

根据需要扩展类(并记得在不再需要时处置这些图像)。

如果您真的想查看图像中是否有图像,您可以查看我为另一篇帖子编写的此扩展名(尽管是VB代码):
Vb.Net Check If Image Existing In Another Image


谢谢你的回答。我已经有一个类似于这个的类了。我有一个带有值(在文本框中)的节点类,以及一个具有节点数组的Tile类。但是初始化所有节点的问题仍然存在。我可以将它们输入到文本框中,但这仍然意味着我必须手动输入大约60个数字,而运行时间只有2秒。因此,我正在寻找一种使用打印屏幕图像来初始化它们的方法。 - marvin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接