我在下面的源代码中结合了denfromufa和HouseCat提出的解决方案,并进行了一些总体清理,因此您可以看到代码的效果。由于我使用 / 编写了重构代码,因此您还将注意到可读性方面的一些改进。
尽管 denfromula 正确地指出了实现问题,并且 HouseCat 提到使用更多的cpu资源,但真正的收益取决于减少图像搜索算法期间执行的操作数量。
假设该MinMax()
功能遍历图像的所有像素以收集所有这些统计信息,但是您只对使用感兴趣maxValue[0]
。极好的微调是 当maxValue[0]
低于最小阈值时, 。显然,这就是您功能所需要的。切记: 。
似乎您正在尝试识别图像集中的任何图像是否与您输入的屏幕截图(tela
)相匹配。如果没有太多要匹配的图像,并且您一直在检查屏幕上是否有新的匹配项,则强烈建议预先加载所有这些图像匹配对象,并在函数调用之间重用它们。
以防万一您每秒要获取多个屏幕截图,然后尝试重用屏幕截图的缓冲区。 不断 。
这很难获得,并且取决于您要为此投资多少。 (图像匹配阶段,OCR阶段,鼠标位置绘画阶段,视频记录阶段等) 。这个想法是创建固定数量的容器并重用它们,避免它们的创建和破坏。容器的数量类似于管道系统的“缓冲区大小”。
最后的优化使用这些外部库确实很难实现,因为在大多数情况下,它们的API需要一些内部位图实例化,并且微调也会导致库与外部库之间的极端软件耦合。因此,您将不得不深入研究这些漂亮的库以了解它们的实际工作原理,并构建自己的自定义框架。我可以说这是一次很好的学习经历。
这些库在许多方面确实很棒。它们提供了通用API,以提高功能的可重用性。这也意味着它们在单个API调用中处理的内容远远超出您的实际需要。对于高性能算法,您应该始终重新考虑那些库中实现目标所需的基本功能是什么,如果它们是您的瓶颈,请自己解决。
我可以说,一个好的微调图像识别算法只需花费几毫秒即可完成您想要的操作。我经历过图像识别应用程序,该应用程序几乎可以瞬间完成较大的屏幕截图(例如Eggplant Functional)。
您的重构代码应如下所示。我没有包括我提到的所有那些经过微调的算法-您最好在SO中为它们提出单独的问题。
Image<Bgr, byte> source = new Image<Bgr, byte>(ofd.FileName);
// Preferably use Path.Combine here:
string dir = Path.Combine(Directory.GetCurrentDirectory(), "Images");
// Check whether directory exists:
if (!Directory.Exists(dir))
throw new Exception($"Directory was not found: '{dir}'");
// It looks like you just need filenames here...
// Simple parallel foreach suggested by HouseCat (in 2.):
Parallel.ForEach(Directory.GetFiles(dir), (fname) =>
{
Image<Gray, float> result = source.MatchTemplate(
new Image<Bgr, byte>(fname.FullName),
Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed);
// By using C# 7.0, we can do inline out declarations here:
result.MinMax(
out double[] minValues,
out double[] maxValues,
out Point[] minLocations,
out Point[] maxLocations);
if (maxValues[0] > 0.96)
{
// ...
var result = ...
return result; // <<< As suggested by: denfromufa
}
// ...
});
快乐调音;-)