清理算法

本文关键字:算法 | 更新日期: 2023-09-27 18:10:05

我做了一个c#应用程序,它连接到我的网络摄像头,并以网络摄像头提供的速度读取图像。我正在解析流,以一种每秒有几个jpeg的方式。

我不想把所有的摄像头数据写入磁盘,我想把图像存储在内存中。此外,应用程序将作为一个web服务器,我可以在查询字符串中提供日期时间。web服务器必须提供内存中最接近该时间的图像。

在我的代码中,我有这个:

Dictionary<DateTime, byte[]> cameraImages;
其中DateTime为接收图像的时间戳,bytearray为jpeg。所有这些都有效;同时处理webrequest工作。基本上,我想通过根据图像的年龄来清理这个字典。

现在我需要一个算法,因为它清理旧的图像。

我真的不能想出一个算法,一个原因是日期时间并不是在一个特定的时刻,我不能确定一个图像总是到达。(有时图像流中断几分钟)。但是我想做的是:

  • 第一分钟保留所有图片
  • 前半小时保持每秒2张图片。
  • 如果超过30分钟,只保留每秒一张图像。
  • 如果超过2小时,每30秒只保留一张图片。
  • 如果超过12小时,每分钟只保留一张图片。
  • 拍摄时间超过24小时,每小时只保留一张图片。
  • 如果超过两天,每天只保留一张图片。
  • 删除所有超过1周的图片。

以上间隔只是一个例子。

有什么建议吗?

清理算法

我认为@Kevin Holditch的方法是完全合理的,而且它的优点是很容易得到正确的代码。

如果有大量的图像,或者你想要考虑如何"有效"地做到这一点,我会提出如下的思考过程:

创建7个队列,代表您的7个类别。我们注意保持这个队列中的图像按时间顺序排序。队列数据结构能够有效地在它的前面插入和从后面删除。. net的队列将是完美的。

每个队列(称为Qi)都有一个"入队列"和一个"出队列"。队列0的传入集合是来自相机的图像,对于任何其他集合,它等于队列i-1的传出集合

每个队列在其输入和输出端都有规则,这些规则决定队列是否从其传入集合中接收新项目,以及是否应从其返回集合中弹出项目。作为一个具体的例子,如果Q3是队列"如果超过2小时,每30秒只保留一个图像",那么Q3迭代它的传入集合(这是Q2的输出集合),并且只允许项目i的时间戳距离Q3 30秒或更长。first()(为了正确工作,项目需要从最高到最低的时间戳进行处理)。在输出端,我们从Q3的尾部弹出任何超过12小时的对象,这成为Q4的输入集。

同样,@Kevin Holditch的方法具有简单的优点,可能是你应该做的。我只是觉得你可能会觉得上面的内容值得思考。

您可以很容易地做到这一点(尽管使用Linq可能不是最有效的方法)。

var firstMinImages = cameraImages.Where(
    c => c.Key >= DateTime.Now.AddMinutes(-1));

然后对每个时间间隔执行一个等价的查询。将它们合并成一个图像存储并覆盖现有的存储(假设您不想保留它们)。这将适用于您当前的标准,因为所需的图像会随着时间的推移而逐渐减少。

我的策略是将元素分组到您计划清除的桶中,然后从列表中选择1个元素保留…我已经做了一个例子,如何做到这一点,使用日期时间和int的列表,但图片将完全相同的方式工作。

My Class用于存储每个Pic

    class Pic
    {
        public DateTime when {get;set;}
        public int val {get;set;}
    }

和清单中一些项目的样品…

        List<Pic> intTime = new List<Pic>();
        intTime.Add(new Pic() { when = DateTime.Now, val = 0 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-1), val = 1 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-1.01), val = 2 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-1.02), val = 3 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-2), val = 4 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-2.1), val = 5 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-2.2), val = 6 });
        intTime.Add(new Pic() { when = DateTime.Now.AddDays(-3), val = 7 });

现在我创建一个帮助函数来bucket和remove…

    private static void KeepOnlyOneFor(List<Pic> intTime, Func<Pic, int> Grouping, DateTime ApplyBefore)
    {
        var groups = intTime.Where(a => a.when < ApplyBefore).OrderBy(a=>a.when).GroupBy(Grouping);
       foreach (var r in groups)
       {
           var s = r.Where(a=> a != r.LastOrDefault());
           intTime.RemoveAll(a => s.Contains(a));
       }
    }

允许您指定如何对对象进行分组并设置分组的年龄阈值。现在最后使用…

这将删除任何超过2天的图片,每天只删除一张:

        KeepOnlyOneFor(intTime, a => a.when.Day, DateTime.Now.AddDays(-2));

这将在1天后每小时删除除1张以外的所有图片:

        KeepOnlyOneFor(intTime, a => a.when.Hour, DateTime.Now.AddDays(-1));

如果你是在。net 4上,你可以使用MemoryCache为每个间隔与CachItemPolicy对象过期,当你想要他们过期和UpdateCallbacks移动一些到下一个间隔