【问题标题】:searching image in another image, only return a partial result在另一个图像中搜索图像,只返回部分结果
【发布时间】:2020-10-28 21:35:53
【问题描述】:

以下代码的错误是,它只能部分找到第一张图像本身。

让我更清楚一点,我截取了一张图片,将其裁剪并放在桌面上。然后我将实际的原始图像也以全尺寸(未裁剪)保存在桌面上。

当我运行代码时,它会正确检测到桌面上裁剪图像的所有坐标,但是,当我打开全尺寸图像并将其悬停时,它不会检测到任何东西并返回 null,而它应该是也能够检测全尺寸图像内的像素位置。

我将发布一个视频来说明我的意思,以便更清楚:

https://www.youtube.com/watch?v=Ha3eGxWcAF8

如您所见,它不会检测主图像上的像素。 那里有什么问题?

为什么它只检测加载的裁剪图像,而不是根据实际的全尺寸图像检测屏幕截图上的位置?

代码如下:

public static Point? Find(Bitmap first, Bitmap second)
{
    if (null == first || null == second)
    {
        return null;
    }

    if (first.Width < second.Width || first.Height < second.Height)
    {
        return null;
    }

    var firstArray = GetPixelArray(first);
    var secondArray = GetPixelArray(second);

    foreach (var firstLineMatchPoint in FindMatch(firstArray.Take(first.Height - second.Height), secondArray[0]))
    {
        if (IssecondPresentAtLocation(firstArray, secondArray, firstLineMatchPoint, 1))
        {
            return firstLineMatchPoint;
        }
    }

    return null;
}

private static int[][] GetPixelArray(Bitmap bitmap)
{
    var result = new int[bitmap.Height][];
    var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
        PixelFormat.Format32bppArgb);

    for (int y = 0; y < bitmap.Height; ++y)
    {
        result[y] = new int[bitmap.Width];
        Marshal.Copy(bitmapData.Scan0 + y * bitmapData.Stride, result[y], 0, result[y].Length);
    }

    bitmap.UnlockBits(bitmapData);

    return result;
}

private static IEnumerable<Point> FindMatch(IEnumerable<int[]> firstLines, int[] secondLine)
{
    var y = 0;
    foreach (var firstLine in firstLines)
    {
        for (int x = 0, n = firstLine.Length - secondLine.Length; x < n; ++x)
        {
            if (ContainSameElements(firstLine, x, secondLine, 0, secondLine.Length))
            {
                yield return new Point(x, y);
            }
        }
        y += 1;
    }
}

private static bool ContainSameElements(int[] first, int firstStart, int[] second, int secondStart, int length)
{
    for (int i = 0; i < length; ++i)
    {
        if (first[i + firstStart] != second[i + secondStart])
        {
            return false;
        }
    }
    return true;
}

private static bool IssecondPresentAtLocation(int[][] first, int[][] second, Point point, int alreadyVerified)
{
    //we already know that "alreadyVerified" lines already match, so skip them
    for (int y = alreadyVerified; y < second.Length; ++y)
    {
        if (!ContainSameElements(first[y + point.Y], point.X, second[y], 0, second.Length))
        {
            return false;
        }
    }
    return true;
}

static void Main(string[] args)
{
    int counter = 1;
    while (true)
    {
        Console.WriteLine("Executing pixel search");

        Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
        Graphics graphics = Graphics.FromImage(bitmap);
        graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
        Bitmap bitmap2 = (Bitmap)Image.FromFile(@"path_to_desktop\cropped.jpg", true);

        if (Find(bitmap, bitmap2) == null)
        {
            Console.WriteLine("Not found.");
        }
        else {
            Console.WriteLine($"{Find(bitmap, bitmap2)}.");
        }

        System.Threading.Thread.Sleep(500); // loop to detect new position
        counter++;
    }
}

【问题讨论】:

  • 您使用的是 .Net Framework 还是 .Net Core?这些图片可以分享吗?
  • .NET core,至于图片我还不太明白你的意思。它基本上在另一个图像中搜索图像/像素,所以任何都可以工作
  • 当您保存文件时,您是否使用正确的图像类型扩展名保存?
  • @jdweng 是的,否则它只会返回文件不存在打开它

标签: c# image-processing search pixel


【解决方案1】:

编辑 7.11.2020:我发布了一个示例项目和视频作为这个问题的结果:

示例:

https://github.com/DataJuggler/SubImageCreator

也可以称为 SubImageSearcher。

视频:

如何使用 C# 和 DataJuggler.PixelDatabase 搜索图像

https://youtu.be/JKc7QtdaxWY

使用 C# 在较大图像中搜索子图像。

Nuget 更新

DataJuggler.PixelDatabase .Net 核心 DataJuggler.PixelDatabase.Net .Net 框架

// Return a sub image after a PixelDatabase is loaded
Bitmap subImage = CreateSubImage(Point topLeft, Rectangle size);

// Search for a sub image inside a larger image
SearchResult result = PixelDatabase.SearchForSubImage(bitmap, searchDepth);

搜索结果包含左上角的一个点和一个分数。零分是完美匹配。

如果在大图像中找到子图像,示例项目会在左上角绘制一个黄色的小矩形。

-- 结束编辑

图片可以分享吗?如果不是示例图像,则可能会有所帮助。如果是,请告诉我您要查找的内容,也许我可以找到“您正在搜索的像素在哪里”。

需要注意的另一件事是,如果任一图像被拉伸,任何类似的差异都可能会扭曲准确的像素颜色和位置。

您使用的是 .Net Framework 还是 .Net Core?

我有一个 Nuget 包可以帮助你:

Nuget: DataJuggler.PixelDatabase .Net 核心 DataJuggler.PixelDatabase.Net .Net 框架

两个包昨天都更新了。

显示 .Net Core 示例

using DataJuggler.PixelDatabase;

// local
DataJuggler.PixelDatabase.PixelDatabase pixelDatabase = null;

// Load the pixelDatabase (you can also pass in a Bitmap or an Image also)
pixelDatabase = PixelDatabaseLoader.LoadPixelDatabase(FullImagePath, null);

// get information about a pixel at the coordinates given
PixelInformation pixel = PixelDatabase.GetPixel(x, y);

像素信息对象包含 Red Green 和 Blue 颜色,以及 X、Y 和许多只读属性,例如 Total、BlueRed、MinMaxDifference 等,这使得查询和更新位图非常简单。

您可以做的另一件事是,如果您知道您正在寻找的某种颜色:

// color
Color color = Color.FromArgb(128, 55, 92);                                    

// get the pixels that match a certain color
List<PixelInformation> pixels = PixelDatabase.GetPixels(color);

这可能有助于您定位图像中的某些像素组。

我的网站也使用了支持 Nuget 包的相同代码:

https://PixelDatabase.Net

该站点和 Nuget 包使用一种称为位图查询语言或简称 BQL 的语言。如果您已经了解的话,这与用于数据库的 SQL 非常相似。

有很多帮助和视频,但如果您进行任何 Pixel 查询,我想您会发现它物有所值。

完整的源代码在 Git Hub 上: https://github.com/DataJuggler/PixelDatabase.Net.Net 框架 https://github.com/DataJuggler/PixelDatabase.Net Core

帮助位于此处: https://pixeldatabase.net/Help

这里还有很多视频: https://www.youtube.com/playlist?list=PLKrW5tXCPiX2PxrLPszDzlcEZwQG-Qb8r

【讨论】:

  • 谢谢,您有时间通过​​聊天更深入地了解吗?这会有所帮助。
  • 至于示例图像,您可以使用这些:find this: i.imgur.com/w6DtyYF.jpg inside this: i.imgur.com/qvsnFqc.jpg
  • 我正好有这个开源项目和现场:blazorchat.com,我现在必须去跑步,否则太热了,但我会在一个半小时后回来,或者所以。
猜你喜欢
  • 1970-01-01
  • 2015-11-07
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多