Как добиться минимального выделения для поиска растрового изображения? - PullRequest
0 голосов
/ 11 февраля 2020

Во-первых, моя проблема, найти новые способы для быстрого и эффективного поиска изображений, пытаясь опередить время .65 ~ .80 мс.

До сих пор я сделал значительные улучшения поиск с использованием параллельного небезопасного анализа растровых изображений, секвенирование частей после начальной индексации, множество других сокращений. Но тот, который ускользает от меня, - это метод, который не использует посредника для хранения и сравнения данных. Бонус также включает минимальный разбор искомого растрового изображения (ie при синтаксическом поиске цели).

Итак, учитывая этот алгоритм, что мы могли бы сделать, чтобы улучшить его?

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public unsafe static Point InMemSearch(Bitmap Haystack, Bitmap NeedleStack)
    {
        if (NeedleStack == null)
            throw new System.ArgumentNullException(nameof(NeedleStack));

        if (Haystack == null)
        {
            return default;
        }

        BitmapData Stack = Haystack.LockBits(new Rectangle(0, 0, Haystack.Width, Haystack.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
        BitmapData Needle = NeedleStack.LockBits(new Rectangle(0, 0, NeedleStack.Width, NeedleStack.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
        Point p = default;
        byte* PtrStackPixel = (byte*)Stack.Scan0;
        byte* PtrNeedlePixel = (byte*)Needle.Scan0;
        Dictionary<int, IEnumerable<byte>> NeedleLookup = new Dictionary<int, IEnumerable<byte>>();
        Dictionary<int, IEnumerable<byte>> StackLookup = new Dictionary<int, IEnumerable<byte>>();
        IEnumerable<byte> GetNeedleLine(int needleY)
        {
            if(NeedleLookup.ContainsKey(needleY))
            {
                return NeedleLookup[needleY];
            }
            var NeedleLine = new byte[Needle.Width];
            for (int x = 0; x < Needle.Width; x++)
            {
                byte np = *(PtrNeedlePixel + (needleY * Needle.Stride) + (x >> 3));
                np &= (byte)(0x80 >> (x & 0x7));
                NeedleLine[x] = np;
            }
            NeedleLookup.Add(needleY, NeedleLine);
            return NeedleLine;
        }
        IEnumerable<byte> GetStackLine(int stackY)
        {
            if(StackLookup.ContainsKey(stackY))
            {
                return StackLookup[stackY];
            }
            var StackLine = new byte[Stack.Width];
            for (var x = 0; x < Stack.Width; x++)
            {
                byte sp = *(PtrStackPixel + (stackY * Stack.Stride) + (x >> 3));
                sp &= (byte)(0x80 >> (x & 0x7));
                StackLine[x] = sp;
            }
            StackLookup[stackY] = StackLine;
            return StackLine;
        }
        int Bad = 0;
        while(!GetNeedleLine(0 + Bad).Any(b => b > 0))
        {
            Bad++;
        }
        int BadStackLines = 0;
        int GoodIndex = 0;
        while (GoodIndex <= 0)
        {
            GoodIndex = SubListIndex(GetStackLine(Stack.Height - BadStackLines), 0, GetNeedleLine(0 + Bad));
            if (GoodIndex == -1)
            {
                BadStackLines++;
            }
            else
            {
                if (GetStackLine(Stack.Height - BadStackLines - 1).Skip(GoodIndex).Take(Needle.Width).SequenceEqual(GetNeedleLine(0 + Bad - 1)))
                {
                    p = new Point(GoodIndex, Stack.Height - BadStackLines);
                }
                else
                {
                    GoodIndex = 0;
                }
            }
        }
        Haystack.UnlockBits(Stack);
        NeedleStack.UnlockBits(Needle);
        return p;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int SubListIndex<T>(IEnumerable<T> list, int start, IEnumerable<T> sublist)
    {
        int Index = 0;
        var LoopResult = Parallel.For(start, list.Count() - sublist.Count() + 1, (listIndex, loopState) =>
          {
              int count = 0;
              while (count < sublist.Count() && sublist.ElementAt(count).Equals(list.ElementAt(listIndex + count)))
              {
                  count++;
              }
              if (count == sublist.Count())
              {
                  Index = listIndex;
                  loopState.Break();
              }
          });
        if (LoopResult.IsCompleted)
        {
            return -1;
        }
        else
        {
            return Index;
        }
    }

В нем все еще есть структуры данных, с которыми нужно сравниваться, и требуется улучшение, но он реализует одну часть идеи.

...