ChiSquaredImageComparison.cs

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”

Leave a Reply

Your email address will not be published. Required fields are marked *