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”