private static IEnumerable<string> TryDeduceMatchingCandidateSnapshot(
            ImageWrapper transformedOriginalSnapshot,
            IEnumerable<string> candidateSnapshots,
            Func<ImageWrapper, Maybe<ImageWrapper>> candidateTranform
            )
        {
            var candidateResultList = new ConcurrentBag<Tuple<string, int>>();
            using (var originaImageAsLockbit = new LockBitImage(transformedOriginalSnapshot.Image))
            {
                Parallel.ForEach(candidateSnapshots, candidateSnapshot =>
                {
                    var candidateComparisonResult = from loadedCandidateSnapshot in TryLoadImage(candidateSnapshot)
                                                    from transformedCandidate in candidateTranform.Invoke(loadedCandidateSnapshot)
                                                    let candidateLockbitImage = new LockBitImage(transformedCandidate.Image)
                                                    let similarityIndex = SimilarityCalculator.CalculateSimilarityIndex(
                                                        originaImageAsLockbit,
                                                        candidateLockbitImage
                                                    )
                                                    select CommonFunctions.ExecThenDispose(
                                                        () => Tuple.Create<string, int>(candidateSnapshot, similarityIndex),
                                                        loadedCandidateSnapshot,
                                                        transformedCandidate,
                                                        candidateLockbitImage
                                                    );
                    candidateComparisonResult.Apply(i => candidateResultList.Add(i));
                });
            }

            return from candidateTuple in candidateResultList
                   where candidateTuple.Item2 >= 69
                   select candidateTuple.Item1;
        }
        /// <summary>
        /// Calculate the similarity between two images
        /// </summary>
        /// <remarks>
        /// Images that are not the same size will always return a result of 0, as they cannot 
        /// be the same.
        /// </remarks>
        /// <param name="original">The original image to compare against</param>
        /// <param name="candidate">The candidate image to compare with the original</param>
        /// <returns>An integer, from 0-100 indicating how similar the two images are</returns>
        public static int CalculateSimilarityIndex(LockBitImage original, LockBitImage candidate)
        {
            // Images that are not the same size are immediately discounted
            if (original.Width != candidate.Width || original.Height != candidate.Height)
            {
                return 0;
            }

            return (int)(SSIMCalculator.Compute(original, candidate) * 100);
        }
 public GaussianBlurTransformation(Image sourceImage, int radius)
 {
     _disposed = false;
     _sourceImage = new LockBitImage(sourceImage);
     _radius = radius;
 }