summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatthewsotoudeh <matthewsot@outlook.com>2016-04-16 23:30:58 -0700
committermatthewsotoudeh <matthewsot@outlook.com>2016-04-16 23:30:58 -0700
commitca085c7bd59ea6ef9ebaa2c082e4150bf6896bd2 (patch)
treeb6c6a41721a1a4333034ea4d0b2c6e86451ba5c7
parentf75c35a62ddaf5a0fd3f1226e3b6631a991a311d (diff)
added a CompressionOptions class
-rw-r--r--NImg/NImg/CompressionOptions.cs23
-rw-r--r--NImg/NImg/Compressor.cs159
-rw-r--r--NImg/NImg/Loader.cs47
-rw-r--r--NImg/NImg/NImg.csproj1
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" />
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback