Пример #1
0
        /// <summary>
        /// 得到图像的散列
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="hashEnum"></param>
        /// <returns></returns>
        private static string GetImageHashes(Bitmap bitmap, HashEnum hashEnum)
        {
            // 获取hash类型
            Func <Bitmap, string> hashMethod = null;

            switch (hashEnum)
            {
            case HashEnum.Mean:
                hashMethod = (imageName) =>
                             GetMeanHash(bitmap);
                break;

            case HashEnum.Difference:
                hashMethod = (imageName) =>
                             GetDifferenceHash(bitmap);
                break;

            case HashEnum.Perceptual:
                hashMethod = (imageName) =>
                             GetPerceptualHash(bitmap);
                break;

            default: break;
            }

            // 获取hash值

            string hash = hashMethod(bitmap);

            return(hash);
        }
Пример #2
0
        public static List <Tuple <string, string, double> > GetSimilarity(
            string folderPath, out int validImageCount, int precision,
            InterpolationMode interpolationMode, HashEnum hashEnum, double threshold)
        {
            Stopwatch watch = new Stopwatch();

            if (threshold < 0 || threshold >= 1)
            {
                throw new ArgumentOutOfRangeException("Threshold should be [0,1);");
            }
            if (!Directory.Exists(folderPath))
            {
                throw new DirectoryNotFoundException("Directory not found.");
            }
            Debug.WriteLine($"Hash Algorithm: {hashEnum}\nPrecision: {precision}\n" +
                            $"Interpolation Mode: {interpolationMode}\nThreshold: {threshold}");

            watch.Restart();

            // Set config
            currentPrecision         = precision;
            currentInterpolationMode = interpolationMode;

            // Get hashes
            var imageHashPairs = GetImageHashes(folderPath, hashEnum).ToArray();

            validImageCount = imageHashPairs.Length;
            if (validImageCount < 2)
            {
                return(null);
            }
            watch.Stop();
            long hashTime = watch.ElapsedMilliseconds;

            watch.Restart();
            var tuples = new List <Tuple <string, string, double> >();

            for (int i = 0; i < imageHashPairs.Length; i++)
            {
                for (int j = imageHashPairs.Length - 1; j > i; j--)
                {
                    double hammingDistance = GetHammingDistancePercent(
                        imageHashPairs[i].Value, imageHashPairs[j].Value);
                    if (hammingDistance > threshold)
                    {
                        var tuple = Tuple.Create(imageHashPairs[i].Key,
                                                 imageHashPairs[j].Key, hammingDistance);
                        tuples.Add(tuple);
                    }
                }
            }
            ;
            watch.Stop();
            long compareTime = watch.ElapsedMilliseconds;

            Debug.WriteLine($"GetHash: {hashTime}ms; CompareHash: {compareTime}ms");

            // Sort by similarity
            return(tuples.OrderByDescending(u => u.Item3).ToList());
        }
Пример #3
0
        /// <summary>
        /// 获取图片对比数据
        /// </summary>
        /// <param name="folderPath"></param>
        /// <param name="validImageCount"></param>
        /// <param name="precision"></param>
        /// <param name="interpolationMode"></param>
        /// <param name="hashEnum"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static double GetSimilarity(Bitmap bitmap, Bitmap bitmap2, HashEnum hashEnum)
        {
            // Get hashes
            var imageHashPairs  = GetImageHashes(bitmap, hashEnum);
            var imageHashPairs2 = GetImageHashes(bitmap2, hashEnum);

            //获取明汉差异并返回
            double HammingDistance = GetHammingDistancePercent(imageHashPairs, imageHashPairs2);

            return(HammingDistance);
        }
        private static KeyValuePair <string, string>[] GetImageHashes(string folderPath, HashEnum hashEnum)
        {
            // Get images
            DirectoryInfo di         = new DirectoryInfo(folderPath);
            var           imageNames = from imageName
                                       in Directory.EnumerateFiles(folderPath, "*.*", SearchOption.AllDirectories)
                                       where imageExtensions.Any(imageName.ToLower().EndsWith)
                                       select imageName;

            Debug.WriteLine($"Directory: {folderPath}\nImageCount: {imageNames.Count()}");
            if (imageNames.Count() < 2)
            {
                return(null);
            }

            // Get hash algorithm
            Func <string, string> hashMethod = null;

            switch (hashEnum)
            {
            case HashEnum.Difference:
                hashMethod = (imageName) => GetDifferenceHash(imageName);
                break;

            case HashEnum.Mean:
                hashMethod = (imageName) => GetMeanHash(imageName);
                break;

            case HashEnum.Perceptual:
                hashMethod = (imageName) => GetPerceptualHash(imageName);
                break;

            default: break;
            }

            // Get hashes
            var imageHashPairs = new ConcurrentDictionary <string, string>();

            Parallel.ForEach(imageNames,
                             // TODO: Add performance limitation option
                             //new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.5) * 1.0)) },
                             imageName =>
            {
                string hash = hashMethod(imageName);
                if (!string.IsNullOrEmpty(hash))
                {
                    imageHashPairs.AddOrUpdate(imageName, hash, (k, v) => v = hash);
                }
            });

            Debug.WriteLine($"ImageCount(Valid): {imageHashPairs.Count}");
            return(imageHashPairs.ToArray());
        }
Пример #5
0
        private static ConcurrentDictionary <string, string> GetImageHashes(string folderPath, HashEnum hashEnum)
        {
            // Get images
            DirectoryInfo di         = new DirectoryInfo(folderPath);
            var           imageNames = from file in di.GetFiles()
                                       where imageExtensions.Contains(file.Extension)
                                       select file.Name;

            Debug.WriteLine($"Directory: {folderPath}\nImage count: {imageNames.Count()}");

            // Get hash algorithm
            Func <string, string> hashMethod = null;

            switch (hashEnum)
            {
            case HashEnum.Mean:
                hashMethod = (imageName) =>
                             GetMeanHash(Path.Combine(folderPath, imageName));
                break;

            case HashEnum.Difference:
                hashMethod = (imageName) =>
                             GetDifferenceHash(Path.Combine(folderPath, imageName));
                break;

            case HashEnum.Perceptual:
                hashMethod = (imageName) =>
                             GetPerceptualHash(Path.Combine(folderPath, imageName));
                break;

            default: break;
            }

            // Get hashes
            var         imageHashPair = new ConcurrentDictionary <string, string>();
            List <Task> taskList      = new List <Task>();

            foreach (string imageName in imageNames)
            {
                taskList.Add(Task.Run(() =>
                {
                    string hash = hashMethod(imageName);
                    if (!string.IsNullOrEmpty(hash))
                    {
                        imageHashPair.AddOrUpdate(imageName, hash, (k, v) => v = hash);
                    }
                }));
            }
            Task.WaitAll(taskList.ToArray());

            Debug.WriteLine($"Valid count: {imageHashPair.Count}");
            return(imageHashPair);
        }
Пример #6
0
        /// <summary>
        /// Generates a hash for the given plain text value and returns a
        /// base64-encoded result. Before the hash is computed, a random salt
        /// is generated and appended to the plain text. This salt is stored at
        /// the end of the hash value, so it can be used later for hash
        /// verification.
        /// </summary>
        /// <param name="plainText">
        /// Plaintext value to be hashed. The function does not check whether
        /// this parameter is null.
        /// </param>
        /// <param name="hashAlgorithm">
        /// Name of the hash algorithm. Allowed values are: "MD5", "SHA1",
        /// "SHA256", "SHA384", and "SHA512" (if any other value is specified
        /// MD5 hashing algorithm will be used). This value is case-insensitive.
        /// </param>
        /// <param name="saltBytes">
        /// Salt bytes. This parameter can be null, in which case a random salt
        /// value will be generated.
        /// </param>
        /// <returns>
        /// Hash value formatted as a base64-encoded string.
        /// </returns>
        public static string ComputeHash(string plainText,
                                         HashEnum hashAlgorithm,
                                         byte[] saltBytes)
        {
            // If salt is not specified, generate it on the fly.
            if (saltBytes == null)
            {
                // Define min and max salt sizes.
                int minSaltSize = 4;
                int maxSaltSize = 8;

                // Generate a random number for the size of the salt.
                Random random = new Random();
                int saltSize = random.Next(minSaltSize, maxSaltSize);

                // Allocate a byte array, which will hold the salt.
                saltBytes = new byte[saltSize];

                // Initialize a random number generator.
                RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

                // Fill the salt with cryptographically strong byte values.
                rng.GetNonZeroBytes(saltBytes);
            }

            // Convert plain text into a byte array.
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // Allocate array, which will hold plain text and salt.
            byte[] plainTextWithSaltBytes =
                    new byte[plainTextBytes.Length + saltBytes.Length];

            // Copy plain text bytes into resulting array.
            for (int i = 0; i < plainTextBytes.Length; i++)
                plainTextWithSaltBytes[i] = plainTextBytes[i];

            // Append salt bytes to the resulting array.
            for (int i = 0; i < saltBytes.Length; i++)
                plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

            // Because we support multiple hashing algorithms, we must define
            // hash object as a common (abstract) base class. We will specify the
            // actual hashing algorithm class later during object creation.
            HashAlgorithm hash = GetHashType(hashAlgorithm);


            // Compute hash value of our plain text with appended salt.
            byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

            // Create array which will hold hash and original salt bytes.
            byte[] hashWithSaltBytes = new byte[hashBytes.Length +
                                                saltBytes.Length];

            // Copy hash bytes into resulting array.
            for (int i = 0; i < hashBytes.Length; i++)
                hashWithSaltBytes[i] = hashBytes[i];

            // Append salt bytes to the result.
            for (int i = 0; i < saltBytes.Length; i++)
                hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

            // Convert result into a base64-encoded string.
            string hashValue = Convert.ToBase64String(hashWithSaltBytes);

            // Return the result.
            return hashValue;
        }
Пример #7
0
        /// <summary>
        /// Compares a hash of the specified plain text value to a given hash
        /// value. Plain text is hashed with the same salt value as the original
        /// hash.
        /// </summary>
        /// <param name="plainText">
        /// Plain text to be verified against the specified hash. The function
        /// does not check whether this parameter is null.
        /// </param>
        /// <param name="hashAlgorithm">
        /// Name of the hash algorithm. Allowed values are: "MD5", "SHA1", 
        /// "SHA256", "SHA384", and "SHA512" (if any other value is specified,
        /// MD5 hashing algorithm will be used). This value is case-insensitive.
        /// </param>
        /// <param name="hashValue">
        /// Base64-encoded hash value produced by ComputeHash function. This value
        /// includes the original salt appended to it.
        /// </param>
        /// <returns>
        /// If computed hash mathes the specified hash the function the return
        /// value is true; otherwise, the function returns false.
        /// </returns>
        public static bool VerifyHash(string plainText,
                                      HashEnum hashAlgorithm,
                                      string hashValue)
        {
            // Convert base64-encoded hash value into a byte array.
            byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue);

            // We must know size of hash (without salt).
            int hashSizeInBits, hashSizeInBytes;

            hashSizeInBits = GetHashBits(hashAlgorithm);

            // Convert size of hash from bits to bytes.
            hashSizeInBytes = hashSizeInBits / 8;

            // Make sure that the specified hash value is long enough.
            if (hashWithSaltBytes.Length < hashSizeInBytes)
                return false;

            // Allocate array to hold original salt bytes retrieved from hash.
            byte[] saltBytes = new byte[hashWithSaltBytes.Length -
                                        hashSizeInBytes];

            // Copy salt from the end of the hash to the new array.
            for (int i = 0; i < saltBytes.Length; i++)
                saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i];

            // Compute a new hash string.
            string expectedHashString =
                        ComputeHash(plainText, hashAlgorithm, saltBytes);

            System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
            _salt = enc.GetString(saltBytes);

            // If the computed hash matches the specified hash,
            // the plain text value must be correct.
            return (hashValue == expectedHashString);
        }
Пример #8
0
        private static int GetHashBits(HashEnum hashEnum)
        {
            // Because we support multiple hashing algorithms, we must define
            // hash object as a common (abstract) base class. We will specify the
            // actual hashing algorithm class later during object creation.
            int hashBits = 0;

            // Initialize appropriate hashing algorithm class.
            if (hashEnum == HashEnum.SHA1)
            {
                hashBits = 160;
            }
            else if (hashEnum == HashEnum.MD5)
            {
                hashBits = 128;
            }
            else if (hashEnum == HashEnum.SHA256)
            {
                hashBits = 256;
            }
            else if (hashEnum == HashEnum.SHA384)
            {
                hashBits = 384;
            }
            else if (hashEnum == HashEnum.SHA512)
            {
                hashBits = 512;
            }

            return hashBits;
        }
Пример #9
0
        private static HashAlgorithm GetHashType(HashEnum hashEnum)
        {
            // Because we support multiple hashing algorithms, we must define
            // hash object as a common (abstract) base class. We will specify the
            // actual hashing algorithm class later during object creation.
            HashAlgorithm hash = null;

            // Initialize appropriate hashing algorithm class.
            if (hashEnum == HashEnum.SHA1)
            {
                hash = new SHA1Managed();
            }
            else if (hashEnum == HashEnum.MD5)
            {
                hash = new MD5CryptoServiceProvider();
            }
            else if (hashEnum == HashEnum.SHA256)
            {
                hash = new SHA256Managed();
            }
            else if (hashEnum == HashEnum.SHA384)
            {
                hash = new SHA384Managed();
            }
            else if (hashEnum == HashEnum.SHA512)
            {
                hash = new SHA512Managed();
            }

            return hash;
        }