diff options
author | matthewsotoudeh <matthewsot@outlook.com> | 2016-04-16 23:30:58 -0700 |
---|---|---|
committer | matthewsotoudeh <matthewsot@outlook.com> | 2016-04-16 23:30:58 -0700 |
commit | ca085c7bd59ea6ef9ebaa2c082e4150bf6896bd2 (patch) | |
tree | b6c6a41721a1a4333034ea4d0b2c6e86451ba5c7 | |
parent | f75c35a62ddaf5a0fd3f1226e3b6631a991a311d (diff) |
added a CompressionOptions class
-rw-r--r-- | NImg/NImg/CompressionOptions.cs | 23 | ||||
-rw-r--r-- | NImg/NImg/Compressor.cs | 159 | ||||
-rw-r--r-- | NImg/NImg/Loader.cs | 47 | ||||
-rw-r--r-- | NImg/NImg/NImg.csproj | 1 |
4 files changed, 77 insertions, 153 deletions
diff --git a/NImg/NImg/CompressionOptions.cs b/NImg/NImg/CompressionOptions.cs new file mode 100644 index 0000000..733bc46 --- /dev/null +++ b/NImg/NImg/CompressionOptions.cs @@ -0,0 +1,23 @@ +namespace NImg +{ + public class CompressionOptions + { + public object this[string property] + { + set + { + this.GetType().GetProperty(property, System.Reflection.BindingFlags.IgnoreCase)?.SetValue(this, value, null); + } + } + + public int ColorIndexBytes { get; set; } + public int ColorIndexTolerance { get; set; } + public int InnerLayers { get; set; } + public int InputPixels { get; set; } + public int MaxTrainingSets { get; set; } + public int NeuronsPerLayer { get; set; } + public int TrainingRounds { get; set; } + public int TrainingSetRandomization { get; set; } + public int WriteTolerance { get; set; } + } +} diff --git a/NImg/NImg/Compressor.cs b/NImg/NImg/Compressor.cs index c611cb4..246b7e8 100644 --- a/NImg/NImg/Compressor.cs +++ b/NImg/NImg/Compressor.cs @@ -15,85 +15,34 @@ namespace NImg Directory.CreateDirectory("Output"); var files = new string[] { file }; - var inputPixels = 3; - var innerLayers = 2; - var neuronsPerLayer = 5; - var colorIndexBytes = 2; // Currently only supporting 0-2 here - var writeTolerance = 10; - var colorIndexTolerance = 5; - var trainingRounds = 5; - var maxTrainingSets = -1; - var trainingSetRandomization = 0; + var options = Loader.LoadOptions(); - if (File.Exists("nimg.config")) - { - using (var reader = new StreamReader("nimg.config")) - { - while (reader.Peek() > -1) - { - var line = reader.ReadLine(); - var parts = line.Split(' '); - switch (parts[0]) - { - case "inputPixels": - inputPixels = int.Parse(parts[1]); - break; - case "innerLayers": - innerLayers = int.Parse(parts[1]); - break; - case "neuronsPerLayer": - neuronsPerLayer = int.Parse(parts[1]); - break; - case "colorIndexBytes": - colorIndexBytes = int.Parse(parts[1]); - break; - case "writeTolerance": - writeTolerance = int.Parse(parts[1]); - break; - case "colorIndexTolerance": - colorIndexTolerance = int.Parse(parts[1]); - break; - case "trainingRounds": - trainingRounds = int.Parse(parts[1]); - break; - case "maxTrainingSets": - maxTrainingSets = int.Parse(parts[1]); - break; - case "trainingSetRandomization": - trainingSetRandomization = int.Parse(parts[1]); - break; - } - } - } - } - - var trainingSets = Loader.LoadTrainingSets(files, inputPixels, maxTrainingSets, trainingSetRandomization); + var trainingSets = Loader.LoadTrainingSets(files, options); - Network network = new Network(inputPixels * 3, innerLayers, neuronsPerLayer, 3); + Network network = new Network(options.InputPixels * 3, options.InnerLayers, options.NeuronsPerLayer, 3); var biasNeurons = 1; network.AddBiasNeuron(0); - Optimizer.Optimize(network, inputPixels, trainingSets, trainingRounds); + Optimizer.Optimize(network, options.InputPixels, trainingSets, options.TrainingRounds); - Writer.WriteWeights(network, inputPixels, innerLayers, neuronsPerLayer, biasNeurons); + Writer.WriteWeights(network, options.InputPixels, options.InnerLayers, options.NeuronsPerLayer, biasNeurons); using (var originalImage = new Bitmap(file)) - { - using (var writer = new BinaryWriter(new FileStream(@"Output\image.data", FileMode.Create))) + { + using (var imageWriter = new BinaryWriter(new FileStream(@"Output\image.data", FileMode.Create))) { + imageWriter.WriteImageMetadata(originalImage.Width, originalImage.Height, options.ColorIndexBytes); + using (var colorsWriter = new BinaryWriter(new FileStream(@"Output\colors.list", FileMode.Create))) { var colors = new List<int[]>(); - writer.Write(originalImage.Width); - writer.Write(originalImage.Height); - writer.Write(Convert.ToByte(colorIndexBytes)); var hits = 0; var misses = 0; for (var yPixel = 0; yPixel < originalImage.Height; yPixel++) { - var input = new double[inputPixels * 3]; + var input = new double[options.InputPixels * 3]; var inARow = 0; for (var xPixel = 0; xPixel < originalImage.Width; xPixel++) { @@ -109,7 +58,7 @@ namespace NImg var good = true; for (var i = 0; i < 3; i++) { - if (Math.Abs(actualColors[i] - output[i]) < writeTolerance) + if (Math.Abs(actualColors[i] - output[i]) < options.WriteTolerance) { hits++; toUse[i] = output[i]; @@ -129,99 +78,19 @@ namespace NImg } else if (good && (inARow == 15 || xPixel == originalImage.Width - 1)) { - //NOTE: 11110000 -> inARow = 1, not 0, increase by 1 inARow++; - Console.WriteLine(inARow); - // "Use AI" bytes start are in the form 1111 + (number of pixels) - writer.Write(Convert.ToByte("1111" + Convert.ToString(inARow - 1, 2).PadLeft(4, '0'), 2)); + imageWriter.WriteAIByte(inARow); inARow = 0; } else { if (inARow > 0) { - //NOTE: 11110000 -> inARow = 1, not 0, increase by 1 - Console.WriteLine(inARow); - // "Use AI" bytes start are in the form 1111 + (number of pixels) - writer.Write(Convert.ToByte("1111" + Convert.ToString(inARow - 1, 2).PadLeft(8, '0').Substring(4), 2)); + imageWriter.WriteAIByte(inARow); inARow = 0; } - if (colorIndexBytes > 0) - { - // find the color - var existing = colors.FirstOrDefault(color => - Math.Abs(roundedToUse[0] - color[0]) < colorIndexTolerance && - Math.Abs(roundedToUse[1] - color[1]) < colorIndexTolerance && - Math.Abs(roundedToUse[2] - color[2]) < colorIndexTolerance); - - var maxColorIndex = (colorIndexBytes == 1 ? 239 : 61440); - - if (existing != null) - { - var index = colors.IndexOf(existing); - switch (colorIndexBytes) - { - case 1: - writer.Write(Convert.ToByte(index)); - break; - case 2: - var bytesStr = Convert.ToString(index, 2).PadLeft(16, '0'); - writer.Write(Convert.ToByte(bytesStr.Substring(0, 8), 2)); - writer.Write(Convert.ToByte(bytesStr.Substring(8), 2)); - break; - } - } - else if (colors.Count >= maxColorIndex) //Over 239/61440 the byte starts with "1111", which is interpreted as a "Use AI" byte - { - Console.WriteLine("Hit max colors"); - switch (colorIndexBytes) - { - case 1: - writer.Write(Convert.ToByte(maxColorIndex - 1)); - break; - case 2: - var bytesStr = Convert.ToString(maxColorIndex - 1, 2); - writer.Write(Convert.ToByte(bytesStr.Substring(0, 8), 2)); - writer.Write(Convert.ToByte(bytesStr.Substring(8), 2)); - break; - } - } - else - { - colors.Add(roundedToUse); - colorsWriter.Write(Convert.ToByte(roundedToUse[0])); - colorsWriter.Write(Convert.ToByte(roundedToUse[1])); - colorsWriter.Write(Convert.ToByte(roundedToUse[2])); - - switch (colorIndexBytes) - { - case 1: - writer.Write(Convert.ToByte(colors.Count() - 1)); - break; - case 2: - var byteStr = Convert.ToString(colors.Count() - 1, 2).PadLeft(16, '0'); - writer.Write(Convert.ToByte(byteStr.Substring(0, 8), 2)); - writer.Write(Convert.ToByte(byteStr.Substring(8), 2)); - break; - } - } - } - else - { - var RStr = Convert.ToString(roundedToUse[0], 2); - var GStr = Convert.ToString(roundedToUse[1], 2); - var BStr = Convert.ToString(roundedToUse[2], 2); - - //TODO: handle 11111111 - if (RStr.StartsWith("1111")) RStr = RStr.Replace("1111", "1110"); - if (GStr.StartsWith("1111")) GStr = GStr.Replace("1111", "1110"); - if (BStr.StartsWith("1111")) BStr = BStr.Replace("1111", "1110"); - - writer.Write(Convert.ToByte(RStr, 2)); - writer.Write(Convert.ToByte(GStr, 2)); - writer.Write(Convert.ToByte(BStr, 2)); - } + imageWriter.WriteColor(options.ColorIndexBytes, colors, roundedToUse, colorsWriter, options.ColorIndexTolerance); } for (var i = 0; i < input.Length - 3; i++) diff --git a/NImg/NImg/Loader.cs b/NImg/NImg/Loader.cs index f78d59d..f7f2b57 100644 --- a/NImg/NImg/Loader.cs +++ b/NImg/NImg/Loader.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.IO; using Zoltar; namespace NImg { static class Loader { - public static TrainingSet[] LoadTrainingSets(string[] paths, int inputPixels = 3, int maxTrainingSets = -1, int trainingSetRandomization = 1) + public static TrainingSet[] LoadTrainingSets(string[] paths, CompressionOptions options) { var trainingSets = new List<TrainingSet>(); foreach (var path in paths) @@ -16,9 +17,9 @@ namespace NImg using (var image = new Bitmap(path)) { var sets = 0; - if (maxTrainingSets != -1 && trainingSetRandomization == 1) + if (options.MaxTrainingSets != -1 && options.TrainingSetRandomization == 1) { - for (var i = 0; i < maxTrainingSets; i++) + for (var i = 0; i < options.MaxTrainingSets; i++) { var xPixel = BruteOptimizer.Random.Next(0, image.Width); var yPixel = BruteOptimizer.Random.Next(0, image.Height); @@ -26,9 +27,9 @@ namespace NImg var output = new double[] { (double)pixel.R / 255, (double)pixel.G / 255, (double)pixel.B / 255 }; - var input = new double[inputPixels * 3]; + var input = new double[options.InputPixels * 3]; - for (var x = (xPixel - 1); x >= Math.Max(0, xPixel - inputPixels); x--) + for (var x = (xPixel - 1); x >= Math.Max(0, xPixel - options.InputPixels); x--) { var thisPixel = image.GetPixel(x, yPixel); var inputOffsetPixels = (xPixel - 1) - x; @@ -44,7 +45,7 @@ namespace NImg for (var yPixel = 0; yPixel < image.Height; yPixel++) { - var input = new double[inputPixels * 3]; + var input = new double[options.InputPixels * 3]; for (var xPixel = 0; xPixel < image.Width; xPixel++) { var pixel = image.GetPixel(xPixel, yPixel); @@ -61,12 +62,12 @@ namespace NImg input[input.Length - 1] = (double)pixel.B / 255; sets++; - if (maxTrainingSets > 0 && sets >= maxTrainingSets) + if (options.MaxTrainingSets > 0 && sets >= options.MaxTrainingSets) { break; } } - if (maxTrainingSets > 0 && sets >= maxTrainingSets) + if (options.MaxTrainingSets > 0 && sets >= options.MaxTrainingSets) { break; } @@ -75,5 +76,35 @@ namespace NImg } return trainingSets.ToArray(); } + public static CompressionOptions LoadOptions() + { + var options = new CompressionOptions() + { + InputPixels = 3, + InnerLayers = 2, + NeuronsPerLayer = 5, + ColorIndexBytes = 2, // Currently only supporting 0-2 here + WriteTolerance = 10, + ColorIndexTolerance = 5, + TrainingRounds = 5, + MaxTrainingSets = -1, + TrainingSetRandomization = 0 + }; + + if (File.Exists("nimg.config")) + { + using (var reader = new StreamReader("nimg.config")) + { + while (reader.Peek() > -1) + { + var line = reader.ReadLine(); + var parts = line.Split(' '); + options[parts[0]] = int.Parse(parts[1]); + } + } + } + + return options; + } } } diff --git a/NImg/NImg/NImg.csproj b/NImg/NImg/NImg.csproj index 986defc..a121af2 100644 --- a/NImg/NImg/NImg.csproj +++ b/NImg/NImg/NImg.csproj @@ -64,6 +64,7 @@ <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> + <Compile Include="CompressionOptions.cs" /> <Compile Include="Compressor.cs" /> <Compile Include="Loader.cs" /> <Compile Include="Optimizer.cs" /> |