public void CompareHashes_Size64() { var hash1 = _imgHashes.CalculateMedianHash64("testPattern1.png"); var hash2 = _imgHashes.CalculateMedianHash64("testPattern2.png"); var differrence = ImageHashes.CompareHashes(hash1, hash2); Assert.InRange(differrence, 0.49, 0.51); }
public void IsSimilarTo(List <DImage> images) { foreach (DImage image in images.Where(image => ImageHashes.CompareHashes(ImageHash, image.ImageHash) == 1.0f)) { if (image != this) { SimilarTo.Add(image); } } }
public void CompareHashes_notEqualLength() { var hash1 = new ulong[1]; var hash2 = new ulong[2]; var exception = Record.Exception(() => ImageHashes.CompareHashes(hash1, hash2)); Assert.NotNull(exception); Assert.IsType <ArgumentException>(exception); }
public void CompareHashes_identicalHashesSize64() { var hash1 = new ulong[1]; var hash2 = new ulong[1]; hash1[0] = 0x0fff0000ffff0000; hash2[0] = 0x0fff0000ffff0000; var result = ImageHashes.CompareHashes(hash1, hash2); Assert.Equal(1.0f, result, 4); }
public void CompareHashes_halfIdenticalHashes() { var hash1 = new ulong[1]; var hash2 = new ulong[1]; hash1[0] = 0x00000000ffffffff; hash2[0] = ulong.MaxValue; var result = ImageHashes.CompareHashes(hash1, hash2); Assert.Equal(0.5f, result, 4); }
public void CompareHashes_nonIdenticalHashes() { ulong[] hash1 = new ulong[1]; ulong[] hash2 = new ulong[1]; hash1[0] = 0L; hash2[0] = ulong.MaxValue; float result = ImageHashes.CompareHashes(hash1, hash2); Assert.Equal(0.0f, result, 4); }
public static IDictionary <Tuple <string, string>, float> CreateDiffMapFromDCTCache(int MaxCount, int startIdx) { if (_diffHashCache.Count == 0) { return(new Dictionary <Tuple <string, string>, float>()); } bool skippedWith = false; long permutations = GetPermutationCount(); int skipAgainst = startIdx / _diffHashCache.Count; int skipWith = startIdx % _diffHashCache.Count; var result = new ConcurrentDictionary <Tuple <string, string>, float>(); long maxAgainst = permutations / MaxCount; if (permutations < MaxCount) { maxAgainst = permutations; } foreach (string fileAgainst in _diffHashCache.Skip(skipAgainst).Select((kvp) => kvp.Key).Take((int)maxAgainst)) { ulong[] hashAgainst = _diffHashCache[fileAgainst]; int skipCount = 0; if (!skippedWith) { skipCount = skipWith; skippedWith = true; } ParallelOptions opts = new ParallelOptions(); opts.MaxDegreeOfParallelism = (Environment.ProcessorCount - 1); Parallel.ForEach(_diffHashCache.Skip(skipCount + skipAgainst).Select((kvp) => kvp.Key), opts, (fileWith) => { if (fileAgainst == fileWith) { return; } ulong[] hashWith = _diffHashCache[fileWith]; float diff = ImageHashes.CompareHashes(hashAgainst, hashWith); result.TryAdd(new Tuple <string, string>(fileAgainst, fileWith), diff); }); } return(result); }
/// <summary> /// Finds the closest hash of a card and returns the GUID of the closest card. /// </summary> /// <param name="incomingHash"></param> /// <returns></returns> // TODO: Fix ids after removing ".jpg" from dictionary // TODO: Make work with double-sided public string FindMatch(ulong incomingHash) { float LeastHammingDistance = 0; ulong closestHash = 0; foreach (ulong key in imageHashDictionary.Keys) { float hammingDistance = ImageHashes.CompareHashes(incomingHash, key); if (hammingDistance >= LeastHammingDistance) { LeastHammingDistance = hammingDistance; closestHash = key; } } ; string idOfCard = imageHashDictionary[closestHash]; return(idOfCard.Substring(0, idOfCard.Length - 4)); }
public void CompareHashes_identicalHashesSize256() { ulong[] hash1 = new ulong[4]; ulong[] hash2 = new ulong[4]; hash1[0] = 0x0fff0000ffff0000; hash1[1] = 0x0fff0000ffff0000; hash1[2] = 0x0fff0000ffff0000; hash1[3] = 0x0fff0000ffff0000; hash2[0] = 0x0fff0000ffff0000; hash2[1] = 0x0fff0000ffff0000; hash2[2] = 0x0fff0000ffff0000; hash2[3] = 0x0fff0000ffff0000; float result = ImageHashes.CompareHashes(hash1, hash2); Assert.Equal(1.0f, result, 4); }
public void CompareHashes_Size64() => Assert.InRange( ImageHashes.CompareHashes(_imgHashes.CalculateMedianHash64("testPattern1.png"), _imgHashes.CalculateMedianHash64("testPattern2.png")), 0.49, 0.51);
/// <summary> Handles the process if no CLI parse errors.</summary> /// <param name="opts">The opts.</param> /// <returns></returns> private static int RunOptionsAndReturnExitCode(Options opts) { Console.WriteLine("Searching for image perceptual similarities..."); var defaultColor = Console.ForegroundColor; try { var files = Directory.EnumerateFiles(opts.SourceFolder, "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".jpg") || s.EndsWith(".jpeg") || s.EndsWith(".png") || s.EndsWith(".bmp") || s.EndsWith(".gif") || s.EndsWith(".tif") || s.EndsWith(".tiff")); var imageHasher = new ImageHashes(new ImageMagickTransformer()); foreach (var file in files) { var currentImage = new MagickImage(file); var currentSize = currentImage.Width * currentImage.Height; Console.WriteLine("{0} ({1}x{2})", file, currentImage.Width, currentImage.Height); var currentHash = imageHasher.CalculateDifferenceHash64(file); var sim = 0f; foreach (var hash in _hashList) { sim = ImageHashes.CompareHashes(hash.Key, currentHash); if (sim >= opts.Threshold) { var existingImage = new MagickImage(hash.Value); var existingSize = existingImage.Width * existingImage.Height; if (currentImage > existingImage) { Console.ForegroundColor = ConsoleColor.Magenta; Console.WriteLine("\t=> Found ! (sim = {0}) {1} ({2}x{3})", sim, hash.Value, existingImage.Width, existingImage.Height); Console.ForegroundColor = defaultColor; File.Move(file, opts.DestinationFolder.TrimEnd('\\') + "\\" + Path.GetFileName(file)); } else if (currentImage == existingImage) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("\t=> Found ! (sim = {0}) {1} ({2}x{3})", sim, hash.Value, existingImage.Width, existingImage.Height); Console.ForegroundColor = defaultColor; File.Move(file, opts.DestinationFolder.TrimEnd('\\') + "\\" + Path.GetFileName(file)); } else { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("\t=> Found ! (sim = {0}) {1} ({2}x{3})", sim, hash.Value, existingImage.Width, existingImage.Height); Console.ForegroundColor = defaultColor; File.Move(hash.Value, opts.DestinationFolder.TrimEnd('\\') + "\\" + Path.GetFileName(hash.Value)); } break; } } if (sim != 1) { _hashList.Add(currentHash, file); } } } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error : " + ex.Message); Console.ForegroundColor = defaultColor; return(1); } return(0); }
public void CompareHashes_ulongVersion(ulong hash1, ulong hash2, float similarity) { var result = ImageHashes.CompareHashes(hash1, hash2); Assert.Equal(similarity, result, 4); }
static void Main(string[] args) { var filters = new String[] { "jpg", "jpeg", "png", "gif", "tiff", "bmp", "svg" }; if (args.Count() > 0) { foreach (var filter in filters) { images.AddRange(Directory.GetFiles(args[0], $"*.{filter}")); } threshold = float.Parse(args[1]); } else { string reading = "0"; do { WriteMessage($"What is the Threshold? default = {threshold}", ConsoleColor.Yellow); reading = Console.ReadLine(); reading = (reading == "" ? reading = "0" : reading); } while (float.Parse(reading) > 1); if (reading != "0") { threshold = float.Parse(reading); } } var i = 0; if (!File.Exists(Path.Combine(args[0], "ImageArray.json"))) { List <Thread> tasks = new List <Thread>(); foreach (var img in images) { WriteMessage($"Loading Thread {i}", ConsoleColor.White); var tsk = new Thread(r => { ProcessImage(imageArray, imageHasher1, img); WriteMessage("Thread Completed " + Thread.CurrentThread.Name, ConsoleColor.Green); }); tsk.Name = $"MyThread {i}"; tasks.Add(tsk); i++; } // Start the Threads foreach (var t in tasks) { WriteMessage($"Starting Thread {t.Name}", ConsoleColor.Green); Console.Title = t.Name; debugTimer = new Stopwatch(); debugTimer.Start(); t.Start(); while (t.IsAlive) { if (debugTimer.ElapsedMilliseconds > 1000) { Console.Write("."); debugTimer.Restart(); } } } File.WriteAllText(Path.Combine(args[0], "ImageArray.json"), System.Text.Json.JsonSerializer.Serialize(imageArray.ToArray())); } else { imageArray = System.Text.Json.JsonSerializer.Deserialize <Dictionary <string, ulong> >(File.ReadAllText(Path.Combine(args[0], "ImageArray.json"))); } i = 0; var sb = new StringBuilder(); sb.Append(@" <html> <head> <style> .myBody { background-image: linear-gradient(#061212, #a6a6a6); } #myData{ color:white; position:fixed; top: 0px; right: 0px; display:none; } .card-img-top { height: 300px; object-fit: cover; } .top-row{ margin-bottom:20px; padding-left:30%; } .actionButton{ margin: 2px; } .hilight{ color:red } .grayScale{ filter: gray; /* IE6-9 */ -webkit-filter: grayscale(1); /* Google Chrome, Safari 6+ & Opera 15+ */ filter: grayscale(1); /* Microsoft Edge and Firefox 35+ */ } .grayScale .msg::after{ content:''; position: absolute; top: 102px; width: 80%; height: 40px; left: 10%; background: RED; color: white; font-size: 20px; margin :20px; text-align: center; transform: rotate(20deg); } .grayScale .msg::before{ content:'DELETE'; position: absolute; top: 102px; width: 80%; height: 40px; left: 10%; background: RED; color: white; z-index:200; font-size: 20px; margin :20px; text-align: center; transform: rotate(-20deg); } </style> <script src = 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js'></script> <script src = 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.bundle.js'></script > <link href = 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css' rel = 'stylesheet'> <script> var array = []; function updateHTML(item,index){ document.getElementById('myData').innerHTML += item+'<br>'; } function isDuplicate(path,val){ document.querySelectorAll('#img_' + val).forEach( img => { if(img.className.indexOf('grayScale')>-1) { array.splice( array.indexOf({id:val,cmd:'del /f ' + path.split('/').join('\\')}), 1); img.className = img.className.replace('grayScale',''); } else { array.push({id:val,cmd:'del /f ' + path.split('/').join('\\')}); img.className += ' grayScale'; } document.getElementById('myData').innerHTML =''; }); array.forEach(updateHTML); } function resetArray(){ var removeArray = []; /* Make sure we only get a distinct List*/ const map = new Map(); for (const item of array) { if(!map.has(item.id)){ map.set(item.id, true); // set any value to Map removeArray.push({ id: item.id, cmd: item.cmd }); } } /* now go and remove the grayscale class*/ removeArray.forEach( x=>{ var fn = x.cmd.replace('del /f ','').split('\\').join('/'); var id = x.id; console.log(fn); isDuplicate(fn,id); }); } </script> </head> <body class='myBody'> <div class='container'> <div id='actionButtons' class = 'row top-row'> <div class='btn btn-primary actionButton' id ='actionButton'>BACK</div> <div class='btn btn-primary actionButton' id ='actionButton'>DELETE</div> <div class='btn btn-primary actionButton' id ='actionButton'>IDENTIFY</div> <div class='btn btn-primary actionButton' id ='actionButton' onclick = 'resetArray()'>RESET</div> </div> <div id ='myData'>No Items Selected</div> <div id='parent-list'> "); processed = new Dictionary <string, ulong>(); foreach (var img in imageArray) { foreach (var comp in imageArray.Where(x => !processed.Select(p => p.Key).Contains(x.Key))) { var similarity = ImageHashes.CompareHashes(img.Value, comp.Value); if (similarity > threshold && !comp.Key.Equals(img.Key)) { var fimg = new FileInfo(img.Key); var fcomp = new FileInfo(comp.Key); var pimg = Image.FromFile(img.Key); var pcomp = Image.FromFile(comp.Key); sb.Append(@$ " <div class='row text-center'>