【问题标题】:Fastest way to Iterate through a List<Byte[]> of 1000 elements迭代 1000 个元素的 List<Byte[]> 的最快方法
【发布时间】:2017-08-19 10:33:33
【问题描述】:

我有一千个指纹存储在我的数据库中的 Byte[] 数组中,我正在尝试对指纹进行 1 对 N 验证,这意味着我需要比较传感器给出的指纹和数组中的。

但是这个过程花费的时间太长,我正在使用 forEach 循环遍历数组中的所有指纹并调用验证方法来比较 2 个数组以找到匹配项。

有什么方法可以让我更快地找到匹配项?在最坏的情况下,匹配项是数组中的最后一项。或靠近底部。

指纹列表

List<Huellas> ListaHuellas = new List<Huellas>();
public class Huellas 
{
    public int idUsuario;
    public Byte[] Huella;
}

搜索匹配项

foreach (Huellas h in ListaHuellas) {
    // Por cada huella... la almacenamos en un MemoryStream como arreglo de bytes.
     MemoryStream fingerprintData = new MemoryStream(h.Huella);
     // Creamos una plantilla a partir de esos bytes...
     DPFP.Template templateIterando = new DPFP.Template(fingerprintData);
     // Extraemos las caracteristicas de la plantilla
     DPFP.FeatureSet features = ExtractFeatures(Sample, DPFP.Processing.DataPurpose.Verification);
     // Verificamos que las caracteristicas sean buenas
     if (features != null) {
        // Compare the feature set with our template
         DPFP.Verification.Verification.Result result = new DPFP.Verification.Verification.Result();
         Verificator.Verify(features, templateIterando, ref result);
         // Y vemos si el resultado es valido o no, (verified)
         // Si es verified, significa que el dedo escaneado ya existia en la base de datos.
         if (result.Verified) {
             MessageBox.Show(new Form { TopMost = true }, "Usuario encontrado: ID " + h.idUsuario);
             // Por ultimo se cierra el programa.
             this.Invoke(new MethodInvoker(delegate { this.Close(); })); 
         }
     }
 }

对不起,西班牙 cmets。

【问题讨论】:

  • 我建议查看Parallel.ForEach
  • 您存储的是原始指纹数据,而不是特征提取的结果? IIRC(很长一段时间,可能是不同的产品)您将从指纹中提取特征并获得哈希结果,您可以通过哈希搜索数据库。您可能需要查看指纹软件的文档以获取存储指纹数据以进行识别的示例。或者,如果他们是这样做的,那就买一个不同的开发工具包。
  • 如果您使用的List 已排序,您可以使用某种形式的二分搜索算法来减少搜索期间的迭代次数。一般来说,迭代列表的最有效方法是使用 forforeach 语句(来源:stackoverflow.com/questions/15204/…
  • @Will 我将字节数组的 ba​​se64 字符串存储在数据库中,但解码回字节数组进行验证,因为 SDK 提供的方法将其作为参数接收
  • 你有没有分析过这段代码,看看哪个步骤一直在走,并研究了如何减少它?实际的循环将非常非常快。但是循环调用了很多其他方法。例如,如果ExtractFeatures 函数需要很长时间,这可能是限制步骤,您可以寻找改进它的选项。这是您要匹配的指纹吗?如果是这样,您是否需要在每次循环时在同一个 Sample 上运行此 ExtractFeatures?不能移到循环外吗?

标签: c# list optimization foreach fingerprint


【解决方案1】:

您可以使用“字典>”:

对于每个指纹,您从合适的哈希函数计算一个“长”值,并将指纹存储在与哈希值关联的列表中(如果您不能保证已知指纹之间不会发生冲突,则需要一个列表)。

当您想要搜索指纹时,您可以计算哈希值,从字典中检索相关列表,然后您可以按顺序搜索(或使用 parallel.foreach)。

如果你使用一个像样的哈希函数,那么冲突就会很少,并且列表将主要包含一个或最多几个元素,因此顺序搜索不会花费很长时间。

注意:即使未知指纹的(哈希)列表仅包含一个结果,您仍然需要验证实际的字节数组(或提取的特征):指纹实际上总是有可能是新的指纹恰好产生与数据库中的指纹之一相同的哈希值。

【讨论】:

  • 您可以使用Lookup&lt;long, Huellas&gt; 而不是Dictionary&lt;long, List&lt; Huellas&gt;&gt;,只需执行var lookup = ListaHuellas.ToLookup(element =&gt; &lt;something to help distinguish elements like a hash&gt;)
  • 查找无疑是一个明智的选择!有关差异,请参阅stackoverflow.com/questions/13362490/…
【解决方案2】:

通过删除永远不会匹配的项目来减少您必须搜索的项目数量。有很多方法可以做到这一点,但一个例子可能是:

  1. 对目标字节数组(您要查找的那个)上的每个字节进行交互。
  2. 在每次迭代时,从源列表中删除项数组中相同索引上的字节与您正在迭代的字节不匹配的所有条目。
  3. 执行此操作,直到您拥有一件物品。

这样,您无需搜索整个数组,而是从一次搜索一个字节开始,并减少搜索的项目数。

如果你想进一步减少这个时间,首先对列表中的字节数组进行排序,然后通过字典搜索它们。也就是说,只与中间的项目进行比较,然后将列表除以一半,只取你认为匹配的一半。这样做,直到你只有一个项目的一半。这与您尝试在物理词典中搜索单词时所做的相同。首先,您尝试打开字典中要查找的单词的第一个字母;当您找到以该字母开头的单词时,您会尝试仅查找与您单词的第二个字母匹配的单词,依此类推。为此,您需要首先对列表进行排序(开头为 {0, 0, 0, ...} 的字节数组,最后为 {255, 255, 255, ...} 的字节数组) ;

例如,无论数组的长度如何,该算法只需要将列表中最多 16 个字节与 65536 个项目进行比较。这会非常快。

这只是一个没有任何代码的谈话示例,但我想你明白了。一个简单的方法是创建一个名为 FingerPrint 的类来表示字节数组,覆盖它的 GetHashCode() 和 Equals() 方法,只使用 HashTable 执行搜索的实例。

【讨论】:

  • 感谢您的回答,以后如果我想提高系统中指纹数量的限制,我会尝试一下。
【解决方案3】:

我的问题是,我在 forEach 循环的每次迭代中都提取了传感器给出的 Sample 指纹的特征。感谢 ainwood 的评论,我将特征提取移到了循环的外部,因为我只需要提取样本的特征一次,并与列表中的指纹进行比较,这将最坏的情况从 15 秒减少到 2。

【讨论】:

    猜你喜欢
    • 2023-04-11
    • 1970-01-01
    • 2023-03-14
    • 2011-02-10
    • 2013-12-04
    • 2022-06-13
    • 2019-04-08
    • 1970-01-01
    • 2021-10-10
    相关资源
    最近更新 更多