Chi Squared Image Comparison (Work In Progress)
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; public class ChiSquaredImageComparison { private readonly int[] _expectedHistogram = new int[256]; private readonly ConcurrentDictionary<string, float> _finalDistList = new ConcurrentDictionary<string, float>(); private ConcurrentDictionary<string, int[]> _observedHistograms = new ConcurrentDictionary<string, int[]>(); private volatile float c, p, t, s1, s2; private volatile int ExpectedLength; private volatile int ExpectedMetric; private volatile int XYExpectedLength; public void SetExpectedHistogram(string path) { try { using (var org = new Bitmap(path)) { using (var img = new MemoryBitmap(org)) { XYExpectedLength = img.Height * img.Width; for (var y = 0; y < img.Height; y++) for (var x = 0; x < img.Width; x++) { var pixel = img.GetPixel(x, y); _expectedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++; } } } } catch { } ExpectedLength = _expectedHistogram.Sum(e => e); ExpectedMetric = _expectedHistogram.Count(e => e > 0); } public void BuildHistograms(EnumBase.IEnumBase[] paths) { if (File.Exists(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin")) { var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"); _observedHistograms = new ConcurrentDictionary<string, int[]>(file); var list1 = paths.Select(e => e.PathString).ToList(); var list2 = file.Select(e => e.Key).ToList(); var list3 = list1.Except(list2).ToArray(); foreach (var e in list3) try { using (var org = new Bitmap(e)) { var observedHistogram = new int[256]; using (var img = new MemoryBitmap(org)) { c++; p = c / t * 100f; for (var y = 0; y < img.Height; y++) for (var x = 0; x < img.Width; x++) { var pixel = img.GetPixel(x, y); observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++; } if (!_observedHistograms.ContainsKey(e)) _observedHistograms.TryAdd(e, observedHistogram); } } } catch { } } else { t = paths.Length; paths.AsParallel().WithDegreeOfParallelism(8).ForAll(i => { try { using (var org = new Bitmap(i.PathString)) { var observedHistogram = new int[256]; using (var img = new MemoryBitmap(org)) { c++; p = c / t * 100f; for (var y = 0; y < img.Height; y++) for (var x = 0; x < img.Width; x++) { var pixel = img.GetPixel(x, y); observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++; } _observedHistograms.TryAdd(i.PathString, observedHistogram); } } } catch { } }); } var kpa = _observedHistograms.ToArray(); SaveToFile(kpa, LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"); } public void SaveToFile(KeyValuePair<string, int[]>[] kpa, string path) { using (var wrtr = new Writer(path)) { foreach (var i in kpa) { var k = i.Key; var v = i.Value; wrtr.WriteString(k); wrtr.WriteInts(v); } } } public KeyValuePair<string, int[]>[] LoadFromFile(string path) { var kpd = new Dictionary<string, int[]>(); using (var reader = new Reader(path)) { while (true) try { var k = reader.ReadString(); var v = reader.ReadInts(); kpd.Add(k, v); } catch { return kpd.ToArray(); } } return kpd.ToArray(); } public ConcurrentDictionary<string, float> HistogramChiSquared(EnumBase.IEnumBase[] paths) { t = paths.Length; paths.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i => { try { using (var org = new Bitmap(i.PathString)) { var observedHistogram = new int[256]; using (var img = new MemoryBitmap(org)) { c++; p = c / t * 100f; var XYObservedLength = img.Height * img.Width; if (XYObservedLength != XYExpectedLength) { s1++; return; } for (var y = 0; y < img.Height; y++) for (var x = 0; x < img.Width; x++) { var pixel = img.GetPixel(x, y); observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++; } var observedLength = observedHistogram.Sum(e => e); if (observedLength > ExpectedLength) { s2++; return; } var ChiSqrd = 0.0f; for (var j = 0; j < 256; j++) if (_expectedHistogram[j] + observedHistogram[j] != 0) ChiSqrd += (float) Math.Pow(_expectedHistogram[j] - observedHistogram[j], 2) / (_expectedHistogram[j] + observedHistogram[j]); var fp = Math.Abs(ChiSqrd / ExpectedLength * 100f); if (fp >= 0 && fp < 15) _finalDistList.TryAdd(i.PathString, fp); } } } catch { } }); return _finalDistList; } public ConcurrentDictionary<string, float> LoadedHistogramChiSquared() { var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"); t = file.Length; file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i => { try { c++; p = c / t * 100f; var d = 0.0f; for (var j = 0; j < 256; j++) { var e = _expectedHistogram[j]; var o = i.Value[j]; if (e + o != 0) d += (float) Math.Pow(e - o, 2) / (e + o); } var dd = d / 100; if (dd >= 0 && dd < 500) _finalDistList.TryAdd(i.Key, dd); } catch { } }); var srt = _finalDistList.OrderBy(x => x.Value); return _finalDistList; } public ConcurrentDictionary<string, float> LoadedHistogramIntersection() { var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"); t = file.Length; file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i => { try { c++; p = c / t * 100f; var d = 0.0f; for (var j = 0; j < 256; j++) { var e = _expectedHistogram[j]; var o = i.Value[j]; d += e + o - Math.Abs(e - o); } var observedLength = i.Value.Sum(e => e); var dd = 0.5f * d / Math.Max(ExpectedLength, observedLength); if (d >= 0 && d < 5) _finalDistList.TryAdd(i.Key, d); } catch { } }); var srt = _finalDistList.OrderBy(x => x.Value); return _finalDistList; } }
2 thoughts on “ChiSquaredImageComparison.cs”