{"id":38,"date":"2020-06-05T10:07:17","date_gmt":"2020-06-05T10:07:17","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=38"},"modified":"2020-06-05T10:07:17","modified_gmt":"2020-06-05T10:07:17","slug":"chisquaredimagecomparison-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/06\/05\/chisquaredimagecomparison-cs\/","title":{"rendered":"ChiSquaredImageComparison.cs"},"content":{"rendered":"\n<p>Chi Squared Image Comparison (Work In Progress)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Drawing;\nusing System.IO;\nusing System.Linq;\npublic class ChiSquaredImageComparison\n{\n    private readonly int[]                               _expectedHistogram  = new int[256];\n    private readonly ConcurrentDictionary&lt;string, float> _finalDistList      = new ConcurrentDictionary&lt;string, float>();\n    private          ConcurrentDictionary&lt;string, int[]> _observedHistograms = new ConcurrentDictionary&lt;string, int[]>();\n    private volatile float                               c, p, t, s1, s2;\n    private volatile int                                 ExpectedLength;\n    private volatile int                                 ExpectedMetric;\n    private volatile int                                 XYExpectedLength;\n    public void SetExpectedHistogram(string path)\n    {\n        try\n        {\n            using (var org = new Bitmap(path))\n            {\n                using (var img = new MemoryBitmap(org))\n                {\n                    XYExpectedLength = img.Height * img.Width;\n                    for (var y = 0; y &lt; img.Height; y++)\n                    for (var x = 0; x &lt; img.Width; x++)\n                    {\n                        var pixel = img.GetPixel(x, y);\n                        _expectedHistogram[(pixel.R + pixel.G + pixel.B) \/ 3]++;\n                    }\n                }\n            }\n        }\n        catch\n        {\n        }\n        ExpectedLength = _expectedHistogram.Sum(e => e);\n        ExpectedMetric = _expectedHistogram.Count(e => e > 0);\n    }\n    public void BuildHistograms(EnumBase.IEnumBase[] paths)\n    {\n        if (File.Exists(LocalSettings.ProgramDir + \"C_JPG_HISTOGRAM.bin\"))\n        {\n            var file = LoadFromFile(LocalSettings.ProgramDir + \"C_JPG_HISTOGRAM.bin\");\n            _observedHistograms = new ConcurrentDictionary&lt;string, int[]>(file);\n            var list1 = paths.Select(e => e.PathString).ToList();\n            var list2 = file.Select(e => e.Key).ToList();\n            var list3 = list1.Except(list2).ToArray();\n            foreach (var e in list3)\n                try\n                {\n                    using (var org = new Bitmap(e))\n                    {\n                        var observedHistogram = new int[256];\n                        using (var img = new MemoryBitmap(org))\n                        {\n                            c++;\n                            p = c \/ t * 100f;\n                            for (var y = 0; y &lt; img.Height; y++)\n                            for (var x = 0; x &lt; img.Width; x++)\n                            {\n                                var pixel = img.GetPixel(x, y);\n                                observedHistogram[(pixel.R + pixel.G + pixel.B) \/ 3]++;\n                            }\n                            if (!_observedHistograms.ContainsKey(e))\n                                _observedHistograms.TryAdd(e, observedHistogram);\n                        }\n                    }\n                }\n                catch\n                {\n                }\n        }\n        else\n        {\n            t = paths.Length;\n            paths.AsParallel().WithDegreeOfParallelism(8).ForAll(i =>\n            {\n                try\n                {\n                    using (var org = new Bitmap(i.PathString))\n                    {\n                        var observedHistogram = new int[256];\n                        using (var img = new MemoryBitmap(org))\n                        {\n                            c++;\n                            p = c \/ t * 100f;\n                            for (var y = 0; y &lt; img.Height; y++)\n                            for (var x = 0; x &lt; img.Width; x++)\n                            {\n                                var pixel = img.GetPixel(x, y);\n                                observedHistogram[(pixel.R + pixel.G + pixel.B) \/ 3]++;\n                            }\n                            _observedHistograms.TryAdd(i.PathString, observedHistogram);\n                        }\n                    }\n                }\n                catch\n                {\n                }\n            });\n        }\n        var kpa = _observedHistograms.ToArray();\n        SaveToFile(kpa, LocalSettings.ProgramDir + \"C_JPG_HISTOGRAM.bin\");\n    }\n    public void SaveToFile(KeyValuePair&lt;string, int[]>[] kpa, string path)\n    {\n        using (var wrtr = new Writer(path))\n        {\n            foreach (var i in kpa)\n            {\n                var k = i.Key;\n                var v = i.Value;\n                wrtr.WriteString(k);\n                wrtr.WriteInts(v);\n            }\n        }\n    }\n    public KeyValuePair&lt;string, int[]>[] LoadFromFile(string path)\n    {\n        var kpd = new Dictionary&lt;string, int[]>();\n        using (var reader = new Reader(path))\n        {\n            while (true)\n                try\n                {\n                    var k = reader.ReadString();\n                    var v = reader.ReadInts();\n                    kpd.Add(k, v);\n                }\n                catch\n                {\n                    return kpd.ToArray();\n                }\n        }\n        return kpd.ToArray();\n    }\n    public ConcurrentDictionary&lt;string, float> HistogramChiSquared(EnumBase.IEnumBase[] paths)\n    {\n        t = paths.Length;\n        paths.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>\n        {\n            try\n            {\n                using (var org = new Bitmap(i.PathString))\n                {\n                    var observedHistogram = new int[256];\n                    using (var img = new MemoryBitmap(org))\n                    {\n                        c++;\n                        p = c \/ t * 100f;\n                        var XYObservedLength = img.Height * img.Width;\n                        if (XYObservedLength != XYExpectedLength)\n                        {\n                            s1++;\n                            return;\n                        }\n                        for (var y = 0; y &lt; img.Height; y++)\n                        for (var x = 0; x &lt; img.Width; x++)\n                        {\n                            var pixel = img.GetPixel(x, y);\n                            observedHistogram[(pixel.R + pixel.G + pixel.B) \/ 3]++;\n                        }\n                        var observedLength = observedHistogram.Sum(e => e);\n                        if (observedLength > ExpectedLength)\n                        {\n                            s2++;\n                            return;\n                        }\n                        var ChiSqrd = 0.0f;\n                        for (var j = 0; j &lt; 256; j++)\n                            if (_expectedHistogram[j] + observedHistogram[j] != 0)\n                                ChiSqrd += (float) Math.Pow(_expectedHistogram[j] - observedHistogram[j], 2) \/ (_expectedHistogram[j] + observedHistogram[j]);\n                        var fp = Math.Abs(ChiSqrd \/ ExpectedLength * 100f);\n                        if (fp >= 0 &amp;&amp; fp &lt; 15)\n                            _finalDistList.TryAdd(i.PathString, fp);\n                    }\n                }\n            }\n            catch\n            {\n            }\n        });\n        return _finalDistList;\n    }\n    public ConcurrentDictionary&lt;string, float> LoadedHistogramChiSquared()\n    {\n        var file = LoadFromFile(LocalSettings.ProgramDir + \"C_JPG_HISTOGRAM.bin\");\n        t = file.Length;\n        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>\n        {\n            try\n            {\n                c++;\n                p = c \/ t * 100f;\n                var d = 0.0f;\n                for (var j = 0; j &lt; 256; j++)\n                {\n                    var e = _expectedHistogram[j];\n                    var o = i.Value[j];\n                    if (e + o != 0)\n                        d += (float) Math.Pow(e - o, 2) \/ (e + o);\n                }\n                var dd = d \/ 100;\n                if (dd >= 0 &amp;&amp; dd &lt; 500)\n                    _finalDistList.TryAdd(i.Key, dd);\n            }\n            catch\n            {\n            }\n        });\n        var srt = _finalDistList.OrderBy(x => x.Value);\n        return _finalDistList;\n    }\n    public ConcurrentDictionary&lt;string, float> LoadedHistogramIntersection()\n    {\n        var file = LoadFromFile(LocalSettings.ProgramDir + \"C_JPG_HISTOGRAM.bin\");\n        t = file.Length;\n        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>\n        {\n            try\n            {\n                c++;\n                p = c \/ t * 100f;\n                var d = 0.0f;\n                for (var j = 0; j &lt; 256; j++)\n                {\n                    var e = _expectedHistogram[j];\n                    var o = i.Value[j];\n                    d += e + o - Math.Abs(e - o);\n                }\n                var observedLength = i.Value.Sum(e => e);\n                var dd             = 0.5f * d \/ Math.Max(ExpectedLength, observedLength);\n                if (d >= 0 &amp;&amp; d &lt; 5)\n                    _finalDistList.TryAdd(i.Key, d);\n            }\n            catch\n            {\n            }\n        });\n        var srt = _finalDistList.OrderBy(x => x.Value);\n        return _finalDistList;\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Chi Squared Image Comparison (Work In Progress)<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/38"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=38"}],"version-history":[{"count":1,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":39,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/38\/revisions\/39"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}