Во-первых, моя проблема, найти новые способы для быстрого и эффективного поиска изображений, пытаясь опередить время .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;
}
}
В нем все еще есть структуры данных, с которыми нужно сравниваться, и требуется улучшение, но он реализует одну часть идеи.