QuickImage – Rev 1
?pathlinks?
using QuickImage.Database;
using Shipwreck.Phash;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace QuickImage.ImageListViewSorters
{
public class PerceptionImageListViewItemSorter : IComparer, IComparer<ListViewItem>
{
private readonly Dictionary<string, double> _score;
private readonly Dictionary<string, Digest> _digest;
private readonly QuickImageDatabase _quickImageDatabase;
private readonly CancellationToken _cancellationToken;
private readonly IReadOnlyList<ListViewItem> _listViewItems;
private readonly TaskCompletionSource<object> _initializedTaskCompletionSource;
private PerceptionImageListViewItemSorter()
{
_score = new Dictionary<string, double>(StringComparer.Ordinal);
_digest = new Dictionary<string, Digest>();
_initializedTaskCompletionSource = new TaskCompletionSource<object>();
}
public PerceptionImageListViewItemSorter(IReadOnlyList<ListViewItem> items, QuickImageDatabase quickImageDatabase, CancellationToken cancellationToken) : this()
{
_listViewItems = items;
_quickImageDatabase = quickImageDatabase;
_cancellationToken = cancellationToken;
Task.Run(RetrieveDigests)
.ContinueWith(ComputeScores)
.ContinueWith(task => _initializedTaskCompletionSource.TrySetResult(new { }));
}
private async void RetrieveDigests()
{
await foreach (var item in _quickImageDatabase.GetAll(_cancellationToken).WithCancellation(_cancellationToken))
{
_digest.Add(item.File, item.Hash);
}
}
private void ComputeScores(Task _)
{
var collection = new List<(ListViewItem A, ListViewItem B, double Score)>();
foreach (var a in _listViewItems)
{
foreach (var b in _listViewItems)
{
if (a.Name == b.Name)
{
continue;
}
if (!_digest.TryGetValue(a.Name, out var p) || !(p is { }) ||
!_digest.TryGetValue(b.Name, out var q) || !(q is { }))
{
continue;
}
var score = ImagePhash.GetCrossCorrelation(p, q);
collection.Add((a, b, score));
}
}
collection.Sort((a, b) => b.Score.CompareTo(a.Score));
var visit = new HashSet<string>(collection.Count);
foreach (var (a, b, score) in collection)
{
foreach (var imageListViewItem in new[] { a, b })
{
if (visit.Contains(imageListViewItem.Name))
{
continue;
}
visit.Add(imageListViewItem.Name);
_score.Add(imageListViewItem.Name, score);
}
}
}
public int Compare(ListViewItem x, ListViewItem y)
{
_initializedTaskCompletionSource.Task.Wait(_cancellationToken);
if (!_score.TryGetValue(x.Name, out var scoreA) || !_score.TryGetValue(y.Name, out var scoreB))
{
return 0;
}
return scoreB.CompareTo(scoreA);
}
public int Compare(object x, object y)
{
return Compare(x as ListViewItem, y as ListViewItem);
}
}
}