public ColorTemplate(Bitmap image, Segmentation seg, PaletteData palette)
        {
            slots = seg; //TODO: need to copy the segmentation?
            originalPalette = new PaletteData(palette);

            int width = image.Width;
            int height = image.Height;

            template = new CIELAB[width, height];

            //initialize the template
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    template[i, j] = Util.RGBtoLAB(image.GetPixel(i, j));
                }
            }

            segToColor = new int[seg.numSegments];

            //map each segment to the closest palette color, based on its mean color
            //TODO: if two adjacent segments have the same mean color, we could merge them...
            for (int i = 0; i < seg.numSegments; i++)
            {
                CIELAB lab = seg.segToMeanColor[i];
                int bestColor = -1;
                double bestDist = Double.PositiveInfinity;
                for (int j = 0; j < palette.lab.Count(); j++)
                {
                    double dist = palette.lab[j].SqDist(lab);

                    if (dist < bestDist)
                    {
                        bestDist = dist;
                        bestColor = j;
                    }
                }
                segToColor[i] = bestColor;
            }

            //subtract the mean color from the template
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int coloridx = segToColor[slots.assignments[i, j]];
                    template[i, j] -= palette.lab[coloridx];
                    //template[i, j] /= palette.lab[coloridx];
                }
            }
        }
        CIELAB[,] template; //relative LAB difference (or change to RGB difference?)

        #endregion Fields

        #region Constructors

        public ColorTemplate(Bitmap image, PaletteData palette)
        {
            //create the segmentation based on the palette
            //TODO: There's a problem that sometimes a palette color won't appear in the image (perhaps due to color blending), and so the slot will have no pixels associated with it
            int width = image.Width;
            int height = image.Height;
            slots = new Segmentation(palette.colors.Count(), width, height);
            segToColor = new int[slots.numSegments];

            template = new CIELAB[width, height];

            CIELAB[,] recolored = ModeRecolor(Util.Map<Color, CIELAB>(Util.BitmapToArray(image), c => Util.RGBtoLAB(c)), palette);

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    template[i, j] = new CIELAB();
                    int bestIdx = -1;
                    CIELAB lab = recolored[i, j];
                    double bestDist = Double.PositiveInfinity;

                    for (int c = 0; c < palette.lab.Count(); c++)
                    {
                        double dist = palette.lab[c].SqDist(lab);
                        if (dist < bestDist)
                        {
                            bestDist = dist;
                            bestIdx = c;

                            if (dist < 0.00001)
                                break;

                        }
                    }

                    slots.assignments[i, j] = bestIdx;
                    slots.counts[bestIdx]++;
                    segToColor[bestIdx] = bestIdx;
                }
            }

            originalPalette = new PaletteData(palette);
        }
        //render an image of the original pattern, plus columns of patterns generated by different models (trained on diff styles)
        private void VisAllStyles()
        {
            Directory.CreateDirectory(outdir + "\\stylecolor\\");

            Directory.CreateDirectory(outdir + "\\styles\\");

            //read in the patterns and save out their layers
            List<PatternItem> patterns = PatternIO.GetPatterns(Path.Combine(imagedir,"../styles"));

            foreach (PatternItem p in patterns)
            {
                String basename = p.Name;

                //Read the style description if available
                String specs = Path.Combine(outdir, "styles", p.Directory, Util.ConvertFileName(basename, "", ".txt"));
                if (!File.Exists(specs))
                    continue;

                Bitmap image = new Bitmap(p.FullPath);

                if (!palettes.ContainsKey(basename))
                    continue;

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);

                int[] slotToColor = new int[template.NumSlots()];
                for (int i = 0; i < slotToColor.Count(); i++)
                    slotToColor[i] = i;

                List<List<String>> lines = File.ReadAllLines(specs).Select(line => line.Split(',').ToList<String>()).ToList<List<String>>();
                if (lines.Count() == 0)
                    continue;

                Dictionary<String, int> styleToRowIdx = new Dictionary<String, int>();
                String origStyle = "";

                foreach (List<String> line in lines)
                {
                    origStyle = line[0];
                    if (!styleToRowIdx.ContainsKey(line[1]))
                        styleToRowIdx.Add(line[1], 0);
                }

                //read the score and if it's the original or not
                double score = 0;
                int iwidth = 100;
                int iheight = 100;
                int padding = 15;
                int headerSpace = 30;
                int width = (styleToRowIdx.Keys.Count() + 1) * iwidth;
                int height = (lines.Count() / styleToRowIdx.Keys.Count()) * iheight + headerSpace;

                Font font = new Font("Arial", 10);

                Bitmap vis = new Bitmap(width, height);
                Graphics g = Graphics.FromImage(vis);

                //write out the headings, highlight the original style heading
                var headers = styleToRowIdx.Keys.ToList<String>();
                int ncol = headers.Count()+1;
                Color headerColor = Color.Black;
                g.DrawString("original", font, new SolidBrush(headerColor), 0, 0);
                for (int i=0; i<headers.Count(); i++)
                {
                    if (headers[i] == origStyle)
                        g.DrawString(headers[i], font, new SolidBrush(headerColor), (i+1)*iwidth, 0);
                    else
                        g.DrawString(headers[i], font, new SolidBrush(headerColor), (i+1)*iwidth, 0);
                }

                //draw the original
                Bitmap original = (renderFinal)? image: template.DebugQuantization();
                g.DrawImage(original, 0, headerSpace, iwidth-padding, iheight-padding);
                original.Dispose();

                PaletteData data = new PaletteData();
                Dictionary<int, int> groupToSlot = new Dictionary<int, int>();
                int ngroups = 0;
                for (int i = 0; i < slotToColor.Count(); i++)
                {
                    slotToColor[i] = i;
                    data.colors.Add(new Color());
                    data.lab.Add(new CIELAB());

                    if (template.PixelsInSlot(i) > 0)
                        groupToSlot.Add(ngroups++, i);
                }

                foreach (List<String> line in lines)
                {
                    //draw the colorized thumbnail in the right location
                    String style = line[1];

                    String[] colors = line[2].Split('^');

                    int colorIdx = 0;
                    foreach (String color in colors)
                    {
                        //rgb floats
                        int[] fields = color.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select<String, int>(s => ((int)(Math.Round(double.Parse(s) * 255)))).ToArray<int>();
                        Color c = Color.FromArgb(fields[0], fields[1], fields[2]);
                        data.colors[groupToSlot[colorIdx]] = c;
                        data.lab[groupToSlot[colorIdx]] = Util.RGBtoLAB(c);
                        colorIdx++;
                    }

                    int x = (headers.IndexOf(style)+1)*iwidth;
                    int y = styleToRowIdx[style]*iheight+headerSpace;
                    styleToRowIdx[style]++;

                    Bitmap result = (renderFinal)?GetFinalRendering(Util.ConvertFileName(basename, "",""), data):template.SolidColor(data, slotToColor);
                    //sometimes we can't get the nice image, so render the quantized image in this case
                    if (result == null)
                        result = template.SolidColor(data, slotToColor);
                    g.DrawImage(result, x, y, iwidth-padding, iheight-padding);
                    result.Dispose();

                }

                PatternIO.SavePattern(vis, p, Path.Combine(outdir, "stylecolor"));
                vis.Dispose();

            }
        }
示例#4
0
        private double PaletteDistanceHungarian(PaletteData a, PaletteData b, ref int[] matching, bool print, int thresh = 1000)
        {
            double score = 0;
            int maxDist = thresh;

            //Make a the smaller palette
            if (a.colors.Count() > b.colors.Count())
            {
                //swap
                PaletteData temp = a;
                a = b;
                b = temp;
            }

            //do the matching
            List<int> foundMatching = HungarianAlgorithmColors(a.lab, b.lab, maxDist, false, print);
            matching = foundMatching.ToArray<int>();

            Debug.Assert(foundMatching.Count() == a.colors.Count());

            //find the score
            for (int i = 0; i < foundMatching.Count(); i++)
            {
                int idx = foundMatching[i];
                if (idx < b.lab.Count())
                {

                    double dist = Math.Sqrt(a.lab[i].SqDist(b.lab[idx]));
                    score += dist;
                }
                else
                {
                    score += maxDist;
                    matching[i] = -1;
                }
            }

            int nullDistances = (b.colors.Count() - a.colors.Count()) * maxDist;

            //normalize between 0 and 1
            return ((score + nullDistances) / b.lab.Count()) / maxDist;
        }
        public double PaletteImageScore(PaletteData palette, String key, String saliencyPattern, bool debug = false)
        {
            double score = 0;

            //weights
            Dictionary<Features, double> weights = new Dictionary<Features, double>();
            weights = LoadWeights(weightsDir + "/weights-final-no.csv", weightsDir + "/featurenames-all.txt");

            SortedSet<Features> included = new SortedSet<Features>(weights.Keys);
            FeatureParams fparams = SetupFeatureParams(included, key, saliencyPattern, debug, 1);

            score = ScorePalette(weights, CalculateFeatures(palette, fparams));
            return score;
        }
 public PaletteData(PaletteData other)
 {
     colors = new List<Color>(other.colors);
     lab = new List<CIELAB>(other.lab);
     id = other.id;
 }
        private CIELAB[,] EdgeUnmixRecolor(CIELAB[,] image, PaletteData palette)
        {
            int width = image.GetLength(0);
            int height = image.GetLength(1);
            CIELAB[,] result = new CIELAB[width, height];

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    double[] scores = new double[palette.colors.Count()];

                    //check if the color is in the palette
                    CIELAB color = image[i, j];
                    if (palette.lab.Contains(color))
                    {
                        result[i, j] = color;
                        continue;
                    }

                    //otherwise, find the best color
                    //see if this is an edge
                    //if it is, assign the color to be one of the edge color candidates
                    HashSet<CIELAB> tbCandidates = new HashSet<CIELAB>();
                    HashSet<CIELAB> lrCandidates = new HashSet<CIELAB>();
                    List<HashSet<CIELAB>> unmixCandidates = new List<HashSet<CIELAB>> { tbCandidates, lrCandidates };

                    //check edge types
                    //horizontal and vertical
                    HashSet<CIELAB> oneSide = new HashSet<CIELAB>();
                    HashSet<CIELAB> otherSide = new HashSet<CIELAB>();
                    Point[] top = new Point[] { new Point(i - 1, j - 1), new Point(i, j - 1), new Point(i + 1, j - 1) };
                    Point[] bottom = new Point[] { new Point(i - 1, j + 1), new Point(i - 1, j), new Point(i - 1, j + 1) };
                    Point[] left = new Point[] { new Point(i - 1, j - 1), new Point(i - 1, j), new Point(i - 1, j + 1) };
                    Point[] right = new Point[] { new Point(i + 1, j - 1), new Point(i + 1, j), new Point(i + 1, j + 1) };

                    List<Point[]> oneCompare = new List<Point[]> { top, left };
                    List<Point[]> otherCompare = new List<Point[]> { bottom, right };

                    bool edge = false;
                    for (int c = 0; c < oneCompare.Count(); c++)
                    {
                        oneSide.Clear();
                        otherSide.Clear();

                        foreach (Point p in oneCompare[c])
                        {
                            if (Util.InBounds(p.X, p.Y, width, height))
                            {
                                CIELAB rc = ClosestColor(image[p.X, p.Y], palette.lab);
                                //check if in the set
                                if (oneSide.Contains(rc))
                                {
                                    //yes, we found a majority
                                    unmixCandidates[c].Add(image[p.X, p.Y]);
                                    break;
                                }
                                else
                                {
                                    oneSide.Add(rc);
                                }
                            }
                        }

                        foreach (Point p in otherCompare[c])
                        {

                            if (Util.InBounds(p.X, p.Y, width, height))
                            {
                                CIELAB rc = ClosestColor(image[p.X, p.Y], palette.lab);
                                //check if in the set
                                if (otherSide.Contains(rc))
                                {
                                    //yes, we found a majority
                                    unmixCandidates[c].Add(rc);
                                    break;
                                }
                                else
                                {
                                    otherSide.Add(rc);
                                }
                            }
                        }

                        //is it an edge?
                        if (unmixCandidates[c].Count() >= 2)
                        {
                            result[i, j] = ClosestColor(image[i, j], unmixCandidates[c].ToList<CIELAB>());
                            edge = true;
                            break;
                        }
                    }

                    //TODO:
                    //45 degrees

                    //45 degrees-flipped

                    if (!edge)
                    {
                        for (int dx = -1; dx <= 1; dx++)
                        {
                            for (int dy = -1; dy <= 1; dy++)
                            {
                                int x = i + dx;
                                int y = j + dy;
                                double weight = (dx == 0 && dy == 0) ? 4 : 1;
                                if (Util.InBounds(x, y, width, height))
                                {
                                    int bestc = ClosestColorIndex(image[x, y], palette.lab);
                                    scores[bestc] -= weight;
                                }
                            }
                        }

                        //pick the color with the min score
                        double minScore = Double.PositiveInfinity;
                        int bestIdx = 0;
                        for (int c = 0; c < palette.colors.Count(); c++)
                        {
                            if (scores[c] < minScore)
                            {
                                minScore = scores[c];
                                bestIdx = c;
                            }
                        }

                        result[i, j] = palette.lab[bestIdx];
                    }

                }
            }

            return result;
        }
示例#8
0
        /**
         * Randomly pick image swatches, and return the theme
         */
        private List<PaletteData> GenerateRandomPalettesNonBinned(int count, PaletteData swatches)
        {
            int k = 5;
            List<PaletteData> data = new List<PaletteData>();

            Random random = new Random();
            List<int> shuffled = new List<int>();
            for (int i = 0; i < swatches.lab.Count(); i++)
                shuffled.Add(i);

            for (int i = 0; i < count; i++)
            {

                PaletteData result = new PaletteData();
                result.id = -1;

                //pick k random colors. First shuffle the colors and pick the top k
                for (int j = shuffled.Count() - 1; j >= 0; j--)
                {
                    int idx = random.Next(j + 1);
                    int temp = shuffled[j];
                    shuffled[j] = shuffled[idx];
                    shuffled[idx] = temp;
                }

                for (int c = 0; c < k; c++)
                {
                    result.colors.Add(swatches.colors[shuffled[c]]);
                    result.lab.Add(swatches.lab[shuffled[c]]);
                }
                data.Add(result);
            }
            return data;
        }
示例#9
0
        /**
         * Draw the themes aligned to the swatches, assume themes are already sorted in the right order
         */
        private void DrawThemes(Graphics g, String name, List<PaletteData> themes, PaletteData swatches, int startX, int labelTop, int colorSize, int padding)
        {
            g.DrawString(name, new Font("Arial", 12.0f), new SolidBrush(Color.Black), startX+(colorSize*(themes.Count()-1)/2) - colorSize/2, labelTop/2);

            int x = startX;
            int y = labelTop;

            for (int i = 0; i < themes.Count(); i++)
            {
                int[] matching = new int[themes[i].colors.Count];
                PaletteDistanceHungarian(themes[i], swatches, ref matching, false);

                for (int c = 0; c < themes[i].colors.Count; c++)
                {
                    if (matching[c] < 0)
                    {
                        backgroundWorker.ReportProgress(-1, "Error: Some elements not matched");
                        continue;
                    }

                    y = labelTop + matching[c] * colorSize;
                    g.FillRectangle(new SolidBrush(themes[i].colors[c]), x, y, colorSize - padding, colorSize - padding);
                    g.DrawRectangle(new Pen(Color.Black), x, y, colorSize - padding, colorSize - padding);
                }
                x = startX + colorSize * (i+1);
            }
        }
示例#10
0
        private List<PaletteData> GenerateRandomPalettes(int count, List<PaletteData> palettes, PaletteData swatches)
        {
            PaletteScoreCache cache = new PaletteScoreCache(1000000);
            int k = 5;
            List<PaletteData> data = new List<PaletteData>();

            Random random = new Random();
            List<int> shuffled = new List<int>();
            for (int i = 0; i < swatches.lab.Count(); i++)
                shuffled.Add(i);

            //find the max scoring human palette
            double maxScore = Double.NegativeInfinity;

            foreach (PaletteData p in palettes)
            {
                double score = 1 - GetAvgDist(new List<PaletteData> { p }, palettes);
                maxScore = Math.Max(maxScore, score);
            }

            //generate random palettes to find the min score
            double minScore = Double.PositiveInfinity;
            for (int i = 0; i < 10000; i++)
            {

                PaletteData result = new PaletteData();
                result.id = -1;

                //pick k random colors. First shuffle the colors and pick the top k
                for (int j = shuffled.Count() - 1; j >= 0; j--)
                {
                    int idx = random.Next(j + 1);
                    int temp = shuffled[j];
                    shuffled[j] = shuffled[idx];
                    shuffled[idx] = temp;
                }

                for (int c = 0; c < k; c++)
                {
                    result.colors.Add(swatches.colors[shuffled[c]]);
                    result.lab.Add(swatches.lab[shuffled[c]]);
                }

                double score = 1 - GetAvgDist(new List<PaletteData>{result}, palettes);
                cache.SetScore(result.lab, score);

                minScore = Math.Min(minScore, score);
                maxScore = Math.Max(maxScore, score);
            }

            int numbins = 10;
            int[] counts = new int[numbins];
            int totalCount = 0;

            int thresh = count / numbins;
            int tries = 0;

            //generate random palettes, given swatches
            while (totalCount < count)
            {

                if (tries % 1000 == 0)
                {
                    String log = Path.Combine(trainOutDir, "randlog.txt");
                    Log(log, tries + "-" + totalCount + " binned ");
                    Log(log, " bins --- " + counts[0] + "," + counts[1] + "," + counts[2] + "," + counts[3] + "," + counts[4] + "," + counts[5] + "," + counts[6] + "," + counts[7] + "," + counts[8] + "," + counts[9]);

                    backgroundWorker.ReportProgress(-1,"bin counts " + String.Join(",",counts));
                }

                tries++;

                PaletteData result = new PaletteData();
                result.id = -1;

                //pick k random colors. First shuffle the colors and pick the top k
                for (int j = shuffled.Count() - 1; j >= 0; j--)
                {
                    int idx = random.Next(j + 1);
                    int temp = shuffled[j];
                    shuffled[j] = shuffled[idx];
                    shuffled[idx] = temp;
                }

                for (int c = 0; c < k; c++)
                {
                    result.colors.Add(swatches.colors[shuffled[c]]);
                    result.lab.Add(swatches.lab[shuffled[c]]);
                }

                double score = 0;
                if (cache.ContainsKey(result.lab))
                    score = cache.GetScore(result.lab);
                else
                {
                    score = 1 - GetAvgDist(new List<PaletteData> { result }, palettes);
                    cache.SetScore(result.lab, score);
                }

                score = (score - minScore) / (maxScore - minScore);

                int bin = (int)Math.Min(Math.Max(0, Math.Floor(score * numbins)), numbins - 1);

                if (counts[bin] >= thresh)
                    continue;
                totalCount++;
                counts[bin]++;

                data.Add(result);
            }
            return data;
        }
示例#11
0
        /**
         * Run c-means clustering on the given image file, and return the theme
         */
        private PaletteData CMeansPalette(String file, int k=5)
        {
            PaletteData result = new PaletteData();
            List<CIELAB> colors = Util.BitmapTo1DArray(Util.GetImage(file,debug)).Select(c => Util.RGBtoLAB(c)).ToList<CIELAB>();
            List<Cluster> final = null;
            double bestScore = Double.PositiveInfinity;

            int trials = 5;
            for (int t = 0; t < trials; t++)
            {
                List<Cluster> seeds = Clustering.InitializePictureSeeds(colors, k);
                double score = Clustering.CMeansPicture(colors, seeds);
                if (score < bestScore)
                {
                    final = seeds;
                    bestScore = score;
                }
            }

            foreach (Cluster c in final)
            {
                result.colors.Add(Util.LABtoRGB(c.lab));
                result.lab.Add(c.lab);
            }

            return result;
        }
示例#12
0
 /**
  * Return a theme with colors snapped to the given swatches
  */
 private PaletteData SnapColors(PaletteData data, PaletteData swatches)
 {
     PaletteData result = new PaletteData();
     List<CIELAB> matchedColors = new List<CIELAB>();
     //match each color to closest swatch color
     foreach (CIELAB kc in data.lab)
     {
         double bestDist = Double.PositiveInfinity;
         CIELAB best = new CIELAB();
         foreach (CIELAB s in swatches.lab)
         {
             double dist = s.SqDist(kc);
             if (dist < bestDist)
             {
                 bestDist = dist;
                 best = s;
             }
         }
         matchedColors.Add(best);
     }
     result.lab = matchedColors;
     foreach (CIELAB l in data.lab)
         result.colors.Add(Util.LABtoRGB(l));
     return result;
 }
示例#13
0
 private double PaletteOverlap(PaletteData a, PaletteData b, int[] matching)
 {
     //return number of colors in common over the number of colors in the larger palette
     int common = 0;
     foreach (int idx in matching)
         if (idx != -1)
             common++;
     return common / (double)(Math.Max(a.colors.Count(), b.colors.Count()));
 }
示例#14
0
        private Dictionary<String, List<PaletteData>> LoadFilePalettes(String file)
        {
            //load art palettes
            String[] lines = File.ReadAllLines(file);

            Dictionary<String, List<PaletteData>> plist = new Dictionary<String, List<PaletteData>>();

            for (int i = 1; i < lines.Count(); i++)
            {
                String line = lines[i];
                String[] fields = line.Replace("\"", "").Split('\t');
                PaletteData data = new PaletteData();
                data.id = Int32.Parse(fields[0]);
                data.workerNum = Int32.Parse(fields[1]);
                String key = fields[2];
                String[] colors = fields[3].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                foreach (String s in colors)
                {
                    String[] comp = s.Split(',');
                    Color c = Color.FromArgb(Int32.Parse(comp[0]), Int32.Parse(comp[1]), Int32.Parse(comp[2]));
                    CIELAB l = Util.RGBtoLAB(c);
                    data.colors.Add(c);
                    data.lab.Add(l);
                }
                if (!plist.ContainsKey(key))
                    plist.Add(key, new List<PaletteData>());
                plist[key].Add(data);
            }
            return plist;
        }
示例#15
0
        /**
         * Find the theme closest on average to a given set of themes (compare[key])
         */
        private PaletteData GetOracleTheme(String key, Dictionary<String, List<PaletteData>> compare)
        {
            //find the palette that has the lowest distance to all other palettes
            int trials = 20;

            PaletteExtractor extractor = new PaletteExtractor(evalDir, weightsDir, json);
            PaletteData swatches = extractor.GetPaletteSwatches(key);

            List<CIELAB> shuffled = new List<CIELAB>();
            foreach (CIELAB c in swatches.lab)
                shuffled.Add(c);

            Random random = new Random();

            PaletteData best = new PaletteData();
            double bestScore = Double.NegativeInfinity;

            Stopwatch watch = new Stopwatch();

            //Generate all the random starts first
            List<PaletteData> starts = new List<PaletteData>();
            PaletteData[] allOptions = new PaletteData[trials];
            double[] allScores = new double[trials];

            for (int t = 0; t < trials; t++)
            {
                //setup
                PaletteData option = new PaletteData();

                //pick k random colors. First shuffle the colors and pick the top k
                for (int j = shuffled.Count() - 1; j >= 0; j--)
                {
                    int idx = random.Next(j + 1);
                    CIELAB temp = shuffled[j];
                    shuffled[j] = shuffled[idx];
                    shuffled[idx] = temp;
                }

                for (int i = 0; i < 5; i++)
                {
                    option.lab.Add(shuffled[i]);
                    option.colors.Add(Util.LABtoRGB(shuffled[i]));
                }
                starts.Add(option);
                allOptions[t] = new PaletteData(option);
                double optionScore = 1 - GetAvgDist(new List<PaletteData> { option }, compare[key]);
                allScores[t] = optionScore;
            }

            watch.Restart();

            Parallel.For(0, trials, t =>
            {
                //setup
                PaletteData option = new PaletteData(starts[t]);

                double optionScore = allScores[t];

                //Now hill climb, for each swatch, consider replacing it with a better swatch
                //Pick the best replacement, and continue until we reach the top of a hill
                int changes = 1;
                int iters = 0;

                watch.Restart();
                while (changes > 0)
                {
                    changes = 0;

                    for (int i = 0; i < option.lab.Count(); i++)
                    {
                        //find the best swatch replacement for this color
                        double bestTempScore = optionScore;
                        CIELAB bestRep = option.lab[i];

                        double[] scores = new double[swatches.lab.Count()];

                        for (int s = 0; s < swatches.lab.Count(); s++)
                        {
                            CIELAB r = swatches.lab[s];

                            PaletteData temp = new PaletteData(option);
                            if (!temp.lab.Contains(r))
                            {

                                temp.lab[i] = r;
                                temp.colors[i] = swatches.colors[s];

                                double tempScore = 1 - GetAvgDist(new List<PaletteData> { temp }, compare[key]);
                                scores[s] = tempScore;
                            }
                            else
                            {
                                scores[s] = Double.NegativeInfinity;
                            }
                        }

                        //aggregate results
                        for (int s = 0; s < scores.Count(); s++)
                        {
                            if (scores[s] > bestTempScore)
                            {
                                bestTempScore = scores[s];
                                bestRep = swatches.lab[s];
                            }
                        }

                        if (!option.lab[i].Equals(bestRep))
                        {
                            option.lab[i] = bestRep;
                            optionScore = bestTempScore;
                            changes++;
                        }
                    }

                    iters++;
                }

                if (optionScore > allScores[t])
                {
                    allOptions[t] = option;
                    allScores[t] = optionScore;
                }
            });

            //aggregate scores
            for (int i = 0; i < allScores.Count(); i++)
            {
                if (allScores[i] > bestScore)
                {
                    bestScore = allScores[i];
                    best = allOptions[i];
                }
            }

            //convert best lab to rgb
            best.colors = new List<Color>();
            foreach (CIELAB l in best.lab)
                best.colors.Add(Util.LABtoRGB(l));

            return best;
        }
示例#16
0
        private void SavePaletteToImage(String dir, String key, String filename, PaletteData data)
        {
            int colorSize = 100;
            int numColors = data.colors.Count();
            int gridWidth = 10;
            int padding = 20;

            int imageSize = 500;

            Bitmap image = new Bitmap(Image.FromFile(dir + "\\" + key));

            int imageWidth = imageSize;
            int imageHeight = imageSize;

            if (image.Width > image.Height)
                imageHeight = (int)Math.Round(imageSize / (double)image.Width * image.Height);
            else
                imageWidth = (int)Math.Round(imageSize / (double)image.Height * image.Width);

            int width = Math.Max(colorSize * Math.Min(gridWidth, numColors), imageSize)+2*padding;
            int height = imageHeight + 3*padding + colorSize * (int)(Math.Ceiling(numColors / (double)gridWidth));

            Bitmap bitmap = new Bitmap(width, height);
            Graphics g = Graphics.FromImage(bitmap);

            //fill with black
            g.FillRectangle(new SolidBrush(Color.Black), 0, 0, bitmap.Width, bitmap.Height);

            //draw image
            g.DrawImage(image, padding, padding, imageWidth, imageHeight);

            //draw out the clusters
            for (int i = 0; i < numColors; i++)
            {
                int row = (int)Math.Floor(i / (double)gridWidth);
                int col = i - row * gridWidth;
                Pen pen = new Pen(data.colors[i]);
                g.FillRectangle(pen.Brush, col * colorSize+padding, imageHeight + 2*padding +  row * colorSize, colorSize - padding, colorSize - padding);

                double brightness = pen.Color.GetBrightness();
                Brush brush = new SolidBrush(Color.White);
                if (brightness > 0.5)
                    brush = new SolidBrush(Color.Black);

            }

            bitmap.Save(filename);
        }
 private Bitmap GetFinalRendering(String patternId, PaletteData palette)
 {
     String url = "http://www.colourlovers.com/patternPreview/";//41/CCCCCC/999999/666666/333333/000000.png
     String[] colorHexes;
     if (palette.colors.Count <= 5)
         colorHexes = new String[] { "CCCCCC", "999999", "666666", "333333", "000000" };
     else
         colorHexes = new String[palette.colors.Count];
     for (int i = 0; i < palette.colors.Count(); i++)
     {
         int slotIdx = i;
         String hex = ColorTranslator.ToHtml(palette.colors[i]).Replace("#","");
         colorHexes[slotIdx] = hex;
     }
     String finalUrl = url + patternToTemplate[patternId] + "/" + String.Join("/", colorHexes) + ".png";
     return Util.BitmapFromWeb(finalUrl);
 }
        public Bitmap SolidColor(PaletteData palette, int[] slotToColor)
        {
            int width = Width();
            int height = Height();
            Bitmap result = new Bitmap(width, height);

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    CIELAB lab = palette.lab[slotToColor[slots.assignments[i, j]]];
                    result.SetPixel(i, j, Util.LABtoRGB(lab));
                }
            }

            return result;
        }
        //Load PaletteData
        private Dictionary<String, PaletteData> LoadFilePalettes(String file)
        {
            FileInfo finfo = new FileInfo(file);

            Dictionary<String, PaletteData> plist = new Dictionary<String, PaletteData>();
            String[] lines = File.ReadAllLines(file);

            //extracted palettes file format
            if (finfo.Extension == ".tsv")
            {
                for (int i = 1; i < lines.Count(); i++)
                {
                    String line = lines[i];
                    String[] fields = line.Replace("\"", "").Split('\t');
                    PaletteData data = new PaletteData();
                    data.id = Int32.Parse(fields[0]);
                    data.workerNum = Int32.Parse(fields[1]);
                    String key = fields[2];
                    String[] colors = fields[3].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (String s in colors)
                    {
                        String[] comp = s.Split(',');
                        Color c = Color.FromArgb(Int32.Parse(comp[0]), Int32.Parse(comp[1]), Int32.Parse(comp[2]));
                        CIELAB l = Util.RGBtoLAB(c);
                        data.colors.Add(c);
                        data.lab.Add(l);
                    }
                    if (!plist.ContainsKey(key))
                        plist.Add(key, data);
                    else
                        throw new IOException("More than one palette per key");
                }
            }
            else //pattern template file format, populate the pattern id to template id field
            {
                for (int i = 0; i < lines.Count(); i++)
                {
                    String line = lines[i];
                    String[] fields = line.Replace("\"", "").Split(',');

                    PaletteData data = new PaletteData();
                    data.id = Int32.Parse(fields[1]);
                    data.workerName = fields[0];
                    String[] colors = fields[3].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                    colors = colors.Distinct<String>().ToArray<String>();
                    String key = fields[1]+".png";
                    foreach (String s in colors)
                    {
                        Color c = ColorTranslator.FromHtml("#"+s);
                        data.colors.Add(c);
                        data.lab.Add(Util.RGBtoLAB(c));

                    }

                    //ignore missing palette data
                    if (!plist.ContainsKey(key) && colors.Count()>0)
                        plist.Add(key, data);
                    else if (plist.ContainsKey(key))
                        throw new IOException("More than one palette per key");

                    String templateId = fields[4];
                    if (!patternToTemplate.ContainsKey(data.id.ToString()))
                        patternToTemplate.Add(data.id.ToString(), templateId);

                }
            }
            return plist;
        }
        private CIELAB[,] ModeRecolor(CIELAB[,] image, PaletteData palette)
        {
            int width = image.GetLength(0);
            int height = image.GetLength(1);
            CIELAB[,] result = new CIELAB[width, height];

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    double[] scores = new double[palette.colors.Count()];

                    //check if the color is in the palette
                    CIELAB color = image[i, j];
                    if (palette.lab.Contains(color))
                    {
                        result[i, j] = color;
                        continue;
                    }

                    //otherwise, find the best color by mode
                    for (int dx = -1; dx <= 1; dx++)
                    {
                        for (int dy = -1; dy <= 1; dy++)
                        {
                            int x = i + dx;
                            int y = j + dy;
                            double weight = (dx == 0 && dy == 0) ? 4 : 1;
                            if (Util.InBounds(x, y, width, height))
                            {
                                int bestc = ClosestColorIndex(image[x, y], palette.lab);
                                scores[bestc] -= weight;
                            }
                        }
                    }

                    //pick the color with the min score
                    double minScore = Double.PositiveInfinity;
                    int bestIdx = 0;
                    for (int c = 0; c < palette.colors.Count(); c++)
                    {
                        if (scores[c] < minScore)
                        {
                            minScore = scores[c];
                            bestIdx = c;
                        }
                    }

                    result[i, j] = palette.lab[bestIdx];

                }
            }

            return result;
        }
        private void Recolor()
        {
            String suboutdir = Path.Combine(outdir, "recolored");
            Directory.CreateDirectory(suboutdir);

            //read in the patterns and save out their layers
            List<PatternItem> patterns = PatternIO.GetPatterns(imagedir);

            foreach (PatternItem p in patterns)
            {
                String basename = p.Name;

                if (!palettes.ContainsKey(basename))
                    continue;

                PaletteData palette = palettes[basename];

                //Read the recoloring description if available
                String specs = Path.Combine(outdir, "specs", p.Directory, Util.ConvertFileName(basename, "", ".txt"));

                if (!File.Exists(specs))
                    continue;

                Bitmap image = new Bitmap(p.FullPath);

                //TODO: save and reload color templates functionality
                ColorTemplate template = new ColorTemplate(image, palette);

                PaletteData data = new PaletteData();

                String[] lines = File.ReadAllLines(specs);
                int[] slotToColor = new int[template.NumSlots()];
                Dictionary<int, int> groupToSlot = new Dictionary<int, int>();

                int ngroups = 0;
                for (int i = 0; i < slotToColor.Count(); i++)
                {
                    slotToColor[i] = i;
                    if (template.PixelsInSlot(i) > 0)
                        groupToSlot.Add(ngroups++, i);
                }

                //TODO: handle recoloring when # groups is less than number of original slots, because of quantization issues.
                //Right now, this is rather ugly..

                data.colors = new List<Color>();
                data.lab = new List<CIELAB>();
                for (int i = 0; i < slotToColor.Count(); i++)
                {
                    data.colors.Add(new Color());
                    data.lab.Add(new CIELAB());
                }

                int groupid = 0;
                foreach (String line in lines)
                {
                    //rgb floats
                    int[] fields = line.Split(new string[]{" "},StringSplitOptions.RemoveEmptyEntries).Select<String, int>(s=>((int)(Math.Round(double.Parse(s)*255)))).ToArray<int>();
                    Color color = Color.FromArgb(fields[0], fields[1], fields[2]);
                    data.colors[groupToSlot[groupid]] = color;
                    data.lab[groupToSlot[groupid]] = Util.RGBtoLAB(color);
                    groupid++;
                }

                Bitmap orig = (renderFinal)? image : template.DebugQuantization();
                PatternIO.SavePattern(orig, p, suboutdir, "_original");
                orig.Dispose();

                Bitmap result = (renderFinal)? GetFinalRendering(Util.ConvertFileName(basename, "",""), data): template.SolidColor(data, slotToColor);
                //sometimes we can't get the nice image, so render the quantized image in this case. TODO: or maybe skip rendering this visualization at all
                if (result == null)
                    result = template.SolidColor(data, slotToColor);
                PatternIO.SavePattern(result, p, suboutdir, "_recolored");
                result.Dispose();

            }
        }
        //Load or create the candidate swatches
        private PaletteData GetPaletteSwatches(string key, int maxIters=50)
        {
            PaletteData global = new PaletteData();

            //load all the candidate colors (the json file)
            String jsonFile = dir + "/swatches/" + Util.ConvertFileName(key,"",".json");

            //check if it exists, if not, create the swatches
            if (!File.Exists(jsonFile))
                GenerateCandidates(key, maxIters);

            String rawText = System.IO.File.ReadAllText(jsonFile);

            //Get the rgb strings
            String cleanedText = rawText.Replace("},{", "^");
            cleanedText = cleanedText.Replace("[{", "");
            cleanedText = cleanedText.Replace("}]", "");

            String[] rgbStrings = cleanedText.Split('^');
            foreach (String rgb in rgbStrings)
            {
                String[] fields = rgb.Split(',');

                //assume that the first three fields are r,g,b
                Color color = Color.FromArgb(Int32.Parse(fields[0].Split(':')[1]),
                                             Int32.Parse(fields[1].Split(':')[1]),
                                             Int32.Parse(fields[2].Split(':')[1]));
                CIELAB lab = Util.RGBtoLAB(color);
                global.lab.Add(lab);
                global.colors.Add(color);
            }
            return global;
        }
        private void RenderTurkFile(String filename, String turkDir)
        {
            String[] lines = File.ReadAllLines(filename);
            foreach (String line in lines)
            {
                String[] fields = line.Split('|');
                String pid = fields[0];
                String[] colors = fields[3].Split('^');

                //render the template
                Bitmap template = GetFinalRendering(pid, new PaletteData());
                if (template != null)
                {
                    template.Save(Path.Combine(turkDir, pid + "_t.png"));

                    //render the candidate pattern
                    String name = fields[1] + ".png";
                    PaletteData data = new PaletteData();
                    foreach (String color in colors)
                    {
                        int[] cfields = color.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select<String, int>(s => ((int)(Math.Round(double.Parse(s) * 255)))).ToArray<int>();
                        data.colors.Add(Color.FromArgb(cfields[0], cfields[1], cfields[2]));
                    }
                    Bitmap cand = GetFinalRendering(pid, data);
                    cand.Save(Path.Combine(turkDir, name));

                    cand.Dispose();
                    template.Dispose();
                }

            }
        }
        public PaletteData HillClimbPalette(String key, String saliencyPattern, bool debug = false)
        {
            //Now initialize a palette and start hill climbing
            int trials = 5;

            PaletteData swatches = GetPaletteSwatches(key);

            List<CIELAB> shuffled = new List<CIELAB>();
            foreach (CIELAB c in swatches.lab)
                shuffled.Add(c);

            Random random = new Random();

            //weights
            Dictionary<Features, double> weights = new Dictionary<Features, double>();

            weights = LoadWeights(weightsDir+"/weights-final-no.csv", weightsDir+"/featurenames-all.txt");

            PaletteData best = new PaletteData();
            double bestScore = Double.NegativeInfinity;

            SortedSet<Features> included = new SortedSet<Features>(weights.Keys);
            FeatureParams fparams = SetupFeatureParams(included, key, saliencyPattern, debug);

            Stopwatch watch = new Stopwatch();

            //Generate all the random starts first
            List<PaletteData> starts = new List<PaletteData>();
            PaletteData[] allOptions = new PaletteData[trials];
            double[] allScores = new double[trials];

            for (int t = 0; t < trials; t++)
            {
                //setup
                PaletteData option = new PaletteData();

                //pick k random colors. First shuffle the colors and pick the top k
                for (int j = shuffled.Count() - 1; j >= 0; j--)
                {
                    int idx = random.Next(j + 1);
                    CIELAB temp = shuffled[j];
                    shuffled[j] = shuffled[idx];
                    shuffled[idx] = temp;
                }

                for (int i = 0; i < 5; i++)
                {
                    option.lab.Add(shuffled[i]);
                    option.colors.Add(Util.LABtoRGB(shuffled[i]));
                }
                starts.Add(option);
                allOptions[t] = new PaletteData(option);
                double optionScore = ScorePalette(weights, CalculateFeatures(option, fparams));
                allScores[t] = optionScore;
            }

            watch.Restart();

            for (int t = 0; t < trials; t++)
            {
                //setup
                PaletteData option = new PaletteData(starts[t]);

                double optionScore = allScores[t];

                //Now hill climb, for each swatch, consider replacing it with a better swatch
                //Pick the best replacement, and continue until we reach the top of a hill
                int changes = 1;
                int iters = 0;

                watch.Restart();
                while (changes > 0)
                {
                    changes = 0;

                    for (int i = 0; i < option.lab.Count(); i++)
                    {
                        //find the best swatch replacement for this color
                        double bestTempScore = optionScore;
                        CIELAB bestRep = option.lab[i];

                        double[] scores = new double[swatches.lab.Count()];

                        for (int s = 0; s < swatches.lab.Count(); s++)
                        {
                            CIELAB r = swatches.lab[s];

                            PaletteData temp = new PaletteData(option);
                            if (!temp.lab.Contains(r))
                            {

                                temp.lab[i] = r;
                                temp.colors[i] = swatches.colors[s];

                                double tempScore = ScorePalette(weights, CalculateFeatures(temp, fparams));
                                scores[s] = tempScore;
                            }
                            else
                            {
                                scores[s] = Double.NegativeInfinity;
                            }
                        }

                        //aggregate results
                        for (int s = 0; s < scores.Count(); s++)
                        {
                            if (scores[s] > bestTempScore)
                            {
                                bestTempScore = scores[s];
                                bestRep = swatches.lab[s];
                            }
                        }

                        if (!option.lab[i].Equals(bestRep))
                        {
                            option.lab[i] = bestRep;
                            optionScore = bestTempScore;
                            changes++;
                        }
                    }

                    iters++;
                }

                if (optionScore > allScores[t])
                {
                    allOptions[t] = option;
                    allScores[t] = optionScore;
                }
                Log(dir + "/out/convergelog.txt", "Trial " + t + " Key " + key + " BestScore: " + allScores[t] + " Steps: " + iters + " Time: " + watch.ElapsedMilliseconds, true);

            }

            //aggregate scores
            for (int i = 0; i < allScores.Count(); i++)
            {
                if (allScores[i] > bestScore)
                {
                    bestScore = allScores[i];
                    best = allOptions[i];
                }
            }

            //convert best lab to rgb
            best.colors = new List<Color>();
            foreach (CIELAB l in best.lab)
                best.colors.Add(Util.LABtoRGB(l));

            return best;
        }
        private void Vis(bool figureQuality = false)
        {
            Directory.CreateDirectory(outdir + "\\viscolor\\");

            Directory.CreateDirectory(outdir + "\\vis\\");

            //read in the patterns and save out their layers
            List<PatternItem> patterns = PatternIO.GetPatterns(imagedir);

            foreach (PatternItem p in patterns)
            {
                String basename = p.Name;

                //Read the vis permutation description if available
                String specs = Path.Combine(outdir, "vis", p.Directory, Util.ConvertFileName(basename, "", ".txt"));
                if (!File.Exists(specs))
                    continue;

                Bitmap image = new Bitmap(p.FullPath);

                if (!palettes.ContainsKey(basename))
                    continue;

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);

                int[] slotToColor = new int[template.NumSlots()];
                for (int i = 0; i < slotToColor.Count(); i++)
                    slotToColor[i] = i;

                Dictionary<int, int> groupToSlot = new Dictionary<int, int>();
                PaletteData data = new PaletteData();

                int ngroups = 0;
                for (int i = 0; i < slotToColor.Count(); i++)
                {
                    slotToColor[i] = i;
                    data.colors.Add(new Color());
                    data.lab.Add(new CIELAB());

                    if (template.PixelsInSlot(i) > 0)
                        groupToSlot.Add(ngroups++, i);
                }

                Bitmap vis = null;
                Graphics g = null;

                String[] lines = File.ReadAllLines(specs);

                //read the score and if it's the original or not
                double score = 0;
                bool orig = false;

                int nresult = 0;
                int y = 0;
                int x = 0;
                int ncol = 8;
                int iwidth = 200;
                int iheight = 200;
                int padding = (figureQuality) ? 8 : 15 ;
                Font font = new Font("Arial", 8);
                int colorIdx = 0;

                foreach (String line in lines)
                {
                    if (line.StartsWith("Count"))
                    {
                        int count = Int32.Parse(line.Split(' ').Last());

                        //initialize the result image
                        int nrow = count / ncol + 1;
                        vis = new Bitmap(ncol*iwidth, nrow*iheight);
                        g = Graphics.FromImage(vis);

                    } else if (line.StartsWith("Score"))
                    {
                        //add the result to the visualization
                        x = (nresult % ncol)*iwidth;
                        y = (nresult / ncol)*iheight;

                        if (colorIdx > 0)
                        {
                            Bitmap result = (renderFinal) ? GetFinalRendering(Util.ConvertFileName(basename, "",""), data): template.SolidColor(data, slotToColor);
                            //sometimes we can't get the nice image, so render the quantized image in this case
                            if (result == null)
                                result = template.SolidColor(data, slotToColor);
                            g.DrawImage(result, x, y, iwidth-padding, iheight-padding);

                            String label = String.Format("{0:0.00}", score);
                            Color color = Color.Black;
                            if (orig)
                            {
                                label += ", ***";
                                color = Color.Red;
                            }
                            if(!figureQuality) g.DrawString(label, font, new SolidBrush(color), x, y + iheight-padding);

                            result.Dispose();

                            colorIdx = 0;
                            //data.colors.Clear();
                            //data.lab.Clear();

                            nresult++;
                        }
                        score = Double.Parse(line.Split(' ')[1]);
                        orig = Boolean.Parse(line.Split(' ')[2]);
                    }
                    else
                    {
                        //rgb floats
                        int[] fields = line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select<String, int>(s => ((int)(Math.Round(double.Parse(s) * 255)))).ToArray<int>();
                        Color color = Color.FromArgb(fields[0], fields[1], fields[2]);
                        data.colors[groupToSlot[colorIdx]] = color;
                        data.lab[groupToSlot[colorIdx]] = Util.RGBtoLAB(color);
                        colorIdx++;
                    }
                }

                //save the last image
                if (data.colors.Count() > 0)
                {
                    x = (nresult % ncol) * iwidth;
                    y = (nresult / ncol) * iheight;

                    Bitmap result = (renderFinal)? GetFinalRendering(Util.ConvertFileName(basename, "",""), data): template.SolidColor(data, slotToColor);
                    //sometimes we can't get the nice image, so render the quantized image in this case
                    if (result == null)
                        result = template.SolidColor(data, slotToColor);
                    g.DrawImage(result, x, y, iwidth - padding, iheight - padding);
                    Color color = Color.Black;

                    String label = String.Format("{0:0.00}", score);
                    if (orig)
                    {
                        label += ", ***";
                        color = Color.Red;
                    }

                    if (!figureQuality) g.DrawString(label, font, new SolidBrush(color), x, y + iheight - padding);

                    result.Dispose();

                    //data.colors.Clear();
                    //data.lab.Clear();
                    colorIdx = 0;

                    nresult++;
                }

                PatternIO.SavePattern(vis, p, Path.Combine(outdir, "viscolor"));
                vis.Dispose();

            }
        }
        private Dictionary<Features, double> CalculateFeatures(PaletteData data, FeatureParams options)
        {
            String log = dir + "/out/timelog.txt";
            Stopwatch watch = new Stopwatch();

            //unpack options
            SortedSet<Features> included = options.included;
            CIELAB[,] imageLAB = options.imageLAB;
            double[,] map = options.map;
            double[] colorToSaliency = options.colorToSaliency;
            int[] colorToCounts = options.colorToCounts;
            double totalSaliency = options.totalSaliency;
            ColorNames colorNames = options.colorNames;
            double factor = options.factor;
            double[] colorToCNSaliency = options.colorToCNSaliency;
            double minE = options.minE;
            double maxE = options.maxE;
            Dictionary<CIELAB, int> swatchIndexOf = options.swatchIndexOf;
            Dictionary<Tuple<int, int>, double> imageSwatchDist = options.imageSwatchDist;
            double afactor = options.afactor;
            double[] swatchToPurity = options.swatchToPurity;
            Dictionary<int, double> pToScore = options.pToScore;
            double maxN = options.maxN;
            double avgN = options.avgN;
            double avgE = options.avgE;
            double[] segToSaliency = options.segmentToSaliency;
            Segmentation seg = options.seg;
            int[] swatchIdxToBin = options.swatchIdxToBin;
            int[,] binAssignments = options.binAssignments;
            double totalCapturable = options.totalCapturableSaliency;
            double[,] pixelToDists = options.pixelToDists;
            double[,] pixelToCNDists = options.pixelToNDists;

            double[] segmentToSD = options.segmentToSD;
            double totalSD = options.totalSD;

            //calculate the palette features
            Dictionary<Features, double> features = new Dictionary<Features, double>();

            double sdmin2 = 1;
            double sdmax2 = 0;
            double sdavg2 = 0;

            int width = options.imageLAB.GetLength(0);
            int height = options.imageLAB.GetLength(1);

            int n = data.lab.Count();

            double[] elementToSaliency = new double[n];
            int[] elementToCount = new int[n];

            //Calculate the error of recoloring the image, each pixel weighted the same, and subtract from 1
            double error = 0;
            //Coverage weighted by saliency of pixel
            double errorWeighted = 0;

            //error of recoloring the image, distance is the names distance metric
            double nerror = 0;
            double nerrorWeighted = 0;

            double errorSeg = 0;
            double errorSegSal = 0;

            double colorsPSeg = 0;
            double colorsPSegW = 0;

            double withinVariance = 0;
            double betweenVariance = 0;

            double sqerror = 0;
            double sqerrorW = 0;
            double sqerrorSeg = 0;
            double sqerrorSegSal = 0;

            double nsqerrorSeg = 0;
            double nsqerrorSegSal = 0;

            double nerrorSeg = 0;
            double nerrorSegSal = 0;

            double nsqerror = 0;
            double nsqerrorW = 0;

            double softerror = 0;
            double softwerror = 0;
            double softerrorseg = 0;
            double softerrorwseg = 0;
            double nsofterror = 0;
            double nsoftwerror = 0;
            double nsofterrorseg = 0;
            double nsofterrorwseg = 0;

            double nmeansegerror = 0;
            double nmeansegwerror = 0;

            double softerrorsegsd = 0;
            double nsofterrorsegsd = 0;
            double errorsegsd = 0;
            double nerrorsegsd = 0;
            double nsqerrorsegsd = 0;
            double sqerrorsegsd = 0;
            double meansegsd = 0;
            double nmeansegsd = 0;

            watch.Start();

            int numPixels = width * height;

            //compute the memberships
            double[,] memberships = new double[numPixels, n];
            double[,] nmemberships = new double[numPixels, n];

            //LAB, and SAT coverage
            double[] Lbounds = new double[] { double.PositiveInfinity, double.NegativeInfinity };
            double[] Abounds = new double[] { double.PositiveInfinity, double.NegativeInfinity };
            double[] Bbounds = new double[] { double.PositiveInfinity, double.NegativeInfinity };
            double[] Satbounds = new double[] { double.PositiveInfinity, double.NegativeInfinity };

            for (int i = 0; i < n; i++)
            {
                CIELAB lab = data.lab[i];
                Color c = data.colors[i];
                double s = c.GetSaturation();

                Lbounds[0] = Math.Min(Lbounds[0], lab.L);
                Lbounds[1] = Math.Max(Lbounds[1], lab.L);

                Abounds[0] = Math.Min(Abounds[0], lab.A);
                Abounds[1] = Math.Max(Abounds[1], lab.A);

                Bbounds[0] = Math.Min(Bbounds[0], lab.B);
                Bbounds[1] = Math.Max(Bbounds[1], lab.B);

                Satbounds[0] = Math.Min(Satbounds[0], s);
                Satbounds[1] = Math.Max(Satbounds[1], s);

            }
            double Lspan = Lbounds[1] - Lbounds[0];
            double Aspan = Abounds[1] - Abounds[0];
            double Bspan = Bbounds[1] - Bbounds[0];
            double Satspan = Satbounds[1] - Satbounds[0];

            double Lcov = Math.Min(Lspan, options.Lspan) / Math.Max(Math.Max(Lspan, options.Lspan), 1);
            double Acov = Math.Min(Aspan, options.Aspan) / Math.Max(Math.Max(Aspan, options.Aspan), 1);
            double Bcov = Math.Min(Bspan, options.Bspan) / Math.Max(Math.Max(Bspan, options.Bspan), 1);
            double Scov = Math.Min(Satspan, options.Satspan) / Math.Max(Math.Max(Satspan, options.Satspan), 1);

            double meansegError = 0;
            double meansegErrorWeighted = 0;

            double[,] colorSegDist = new double[n, seg.numSegments];

            double[] segToDist = new double[seg.numSegments];

            for (int j = 0; j < seg.numSegments; j++)
            {
                //find the closest color for each segment
                double bestDist = Double.PositiveInfinity;
                for (int i = 0; i < n; i++)
                {
                    colorSegDist[i, j] = Math.Sqrt(data.lab[i].SqDist(seg.segToMeanColor[j]));
                    segToDist[j] += colorSegDist[i, j];

                    bestDist = Math.Min(colorSegDist[i, j], bestDist);
                }

                double nbestDist = Double.PositiveInfinity;
                for (int i = 0; i < n; i++)
                {
                    double ndist = GetCNDist(colorNames.GetBin(data.lab[i]), colorNames.GetBin(seg.segToMeanColor[j]));
                    nbestDist = Math.Min(ndist, nbestDist);

                }

                meansegError += bestDist;
                meansegErrorWeighted += bestDist * segToSaliency[j];

                nmeansegerror += nbestDist;
                nmeansegwerror += nbestDist * segToSaliency[j];

                meansegsd += bestDist * segmentToSD[j];
                nmeansegsd += nbestDist * segmentToSD[j];

            }

            meansegError /= seg.numSegments * factor;
            meansegErrorWeighted /= totalSaliency * factor;

            nmeansegerror /= seg.numSegments;
            nmeansegwerror /= totalSaliency;

            meansegsd /= totalSD * factor;
            nmeansegsd /= totalSD;

            //now calculate entropy per segment
            //probability is 1-(dist/totaldist)
            double[] segEntropy = new double[seg.numSegments];
            for (int i = 0; i < seg.numSegments; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double prob = 1 - colorSegDist[j, i] / segToDist[i];
                    segEntropy[i] += prob * Math.Log(prob);
                }
            }

            //average and/or weight by saliency of segment
            for (int i = 0; i < seg.numSegments; i++)
            {
                colorsPSeg += segEntropy[i];
                colorsPSegW += segEntropy[i] * segToSaliency[i];
            }

            colorsPSeg /= seg.numSegments;
            colorsPSegW /= totalSaliency;

            double[,] nsubs = new double[width, height];
            double[,] subs = new double[width, height];

            if (included.Overlaps(options.NameCovFeatures) ||
                included.Overlaps(options.CoverageFeatures) ||
                included.Overlaps(options.SaliencyDensFeatures))
            {

                double[,] errors = new double[width, height];
                int[,] assignment = new int[width, height]; //the pixel to the nearest palette color

                double[,] nerrors = new double[width, height];
                double[,] nerrorsWeighted = new double[width, height];

                double[] clusterSqError = new double[n];

                int[,] nassignment = new int[width, height];

                Parallel.For(0, width, i =>
               {
                   for (int j = 0; j < height; j++)
                   {
                       double bestDist = Double.PositiveInfinity;
                       int bestIdx = -1;
                       for (int s = 0; s < data.lab.Count(); s++)
                       {
                           double dist = data.lab[s].SqDist(options.imageLAB[i, j]);
                           if (dist < bestDist)
                               bestIdx = s;
                           bestDist = Math.Min(dist, bestDist);

                       }
                       assignment[i, j] = bestIdx;
                       double sqrtBestDist = Math.Sqrt(bestDist);
                       errors[i, j] = sqrtBestDist;
                       clusterSqError[bestIdx] += bestDist;
                   }

                   if (included.Overlaps(options.NameCovFeatures))
                   {
                       for (int j = 0; j < height; j++)
                       {
                           int bestIdx = -1;
                           double bestDist = Double.PositiveInfinity;
                           for (int s = 0; s < data.lab.Count(); s++)
                           {
                               int sIdx = swatchIndexOf[data.lab[s]];
                               double dist = GetCNDist(binAssignments[i, j], swatchIdxToBin[sIdx]);//imageSwatchDist[new Tuple<int, int>(binAssignments[i,j], swatchIdxToBin[sIdx])]; //imageSwatchDist[new Tuple<int, int>(colorNames.GetBin(imageLAB[i, j]), colorNames.GetBin(data.lab[s]))];

                               if (dist < bestDist)
                                   bestIdx = s;

                               bestDist = Math.Min(dist, bestDist);
                           }
                           double val = map[i, j];
                           nerrors[i, j] = bestDist;
                           nerrorsWeighted[i, j] = bestDist * val;
                           nassignment[i, j] = bestIdx;
                       }
                   }

                   double epsilon = 0.0001;

                   for (int j = 0; j < height; j++)
                   {
                       //calculate the memberships
                       double[] dists = new double[n];
                       double[] ndists = new double[n];

                       double subtotal = 0;
                       double nsubtotal = 0;

                       int idx = j * width + i;

                       for (int k = 0; k < n; k++)
                       {
                           int sidx = swatchIndexOf[data.lab[k]];

                           dists[k] = Math.Max(pixelToDists[idx, sidx], epsilon);
                           ndists[k] = Math.Max(pixelToCNDists[idx, sidx], epsilon);

                           subtotal += (1.0 / dists[k]);
                           nsubtotal += (1.0 / ndists[k]);
                       }
                       for (int k = 0; k < n; k++)
                       {
                           memberships[idx, k] = 1.0 / (dists[k] * subtotal);
                           nmemberships[idx, k] = 1.0 / (ndists[k] * nsubtotal);
                       }

                       for (int k = 0; k < n; k++)
                       {
                           int sidx = swatchIndexOf[data.lab[k]];

                           double u = memberships[idx, k];
                           subs[i, j] += u * u * Math.Max(pixelToDists[idx, sidx], epsilon);

                           double nu = nmemberships[idx, k];
                           nsubs[i, j] += nu * nu * Math.Max(pixelToCNDists[idx, sidx], epsilon);
                       }
                   }

               });

                //find J

                double[] segToJ = new double[seg.numSegments];
                double[] nsegToJ = new double[seg.numSegments];

                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        int idx = j * width + i;

                        double sub = subs[i, j];
                        double nsub = nsubs[i, j];

                        softerror += sub;
                        nsofterror += nsub;

                        softwerror += sub * map[i, j];
                        nsoftwerror += nsub * map[i, j];

                        int segIdx = seg.assignments[i, j];
                        segToJ[segIdx] += sub;
                        nsegToJ[segIdx] += nsub;
                    }
                }

                softerror /= numPixels * factor * factor;
                nsofterror /= numPixels;

                softwerror /= totalSaliency * factor * factor;
                nsoftwerror /= totalSaliency;

                for (int s = 0; s < seg.numSegments; s++)
                {
                    softerrorseg += segToJ[s] / seg.counts[s];
                    softerrorwseg += segToSaliency[s] * segToJ[s] / seg.counts[s];

                    nsofterrorseg += nsegToJ[s] / seg.counts[s];
                    nsofterrorwseg += segToSaliency[s] * nsegToJ[s] / seg.counts[s];

                    softerrorsegsd += segmentToSD[s] * segToJ[s] / seg.counts[s];
                    nsofterrorsegsd += segmentToSD[s] * nsegToJ[s] / seg.counts[s];

                }
                softerrorseg /= seg.numSegments * factor * factor;
                softerrorwseg /= totalSaliency * factor * factor;

                nsofterrorseg /= seg.numSegments;
                nsofterrorwseg /= totalSaliency;

                softerrorsegsd /= totalSD * factor * factor;
                nsofterrorsegsd /= totalSD;

                //calculate within and between palette cluster variance
                //between variance
                CIELAB betweenMean = new CIELAB();

                for (int j = 0; j < n; j++)
                {
                    betweenMean = betweenMean + data.lab[j];
                }
                betweenMean = betweenMean / (double)n;
                for (int j = 0; j < n; j++)
                {
                    betweenVariance += betweenMean.SqDist(data.lab[j]);
                }
                betweenVariance /= (double)n * factor * factor;

                double[] counts = new double[n];

                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        counts[assignment[i, j]]++;
                    }
                }

                for (int i = 0; i < n; i++)
                {
                    withinVariance += clusterSqError[i] / Math.Max(1, counts[i]);
                }
                withinVariance /= n * (factor * factor);

                double[] segmentToError = new double[segToSaliency.Count()];
                double[] segToSqError = new double[segToSaliency.Count()];
                Dictionary<int, SortedSet<int>> segToColors = new Dictionary<int, SortedSet<int>>();

                //now aggregate
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        double sqError = errors[i, j] * errors[i, j];
                        double val = map[i, j];
                        errorWeighted += val * errors[i, j];
                        sqerrorW += val * sqError;
                        error += errors[i, j];
                        sqerror += sqError;

                        int idx = assignment[i, j];
                        if (idx >= 0)
                        {
                            elementToSaliency[idx] += val;
                            elementToCount[idx]++;
                        }
                        int segIdx = seg.assignments[i, j];
                        segmentToError[segIdx] += errors[i, j] / seg.counts[segIdx];
                        segToSqError[segIdx] += sqError / seg.counts[segIdx];

                    }
                }

                for (int i = 0; i < seg.numSegments; i++)
                {

                    errorSeg += segmentToError[i];
                    errorSegSal += segmentToError[i] * segToSaliency[i];

                    sqerrorSeg += segToSqError[i];
                    sqerrorSegSal += segToSqError[i] * segToSaliency[i]; //TODO: this is weighted by segment percent salient density

                    errorsegsd += segmentToError[i] * segmentToSD[i];
                    sqerrorsegsd += segToSqError[i] * segmentToSD[i];

                }

                errorSeg /= seg.numSegments * factor;
                errorSegSal /= totalSaliency * factor;

                sqerrorSeg /= seg.numSegments * factor * factor;
                sqerrorSegSal /= totalSaliency * factor * factor;

                errorWeighted /= totalSaliency * factor;
                error /= width * height * factor;

                sqerrorW /= totalSaliency * factor * factor;
                sqerror /= width * height * factor * factor;

                errorsegsd /= totalSD * factor;
                sqerrorsegsd /= totalSD * factor * factor;

                //now sum it all up
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        nerrorWeighted += nerrorsWeighted[i, j];
                        nerror += nerrors[i, j];
                    }
                }

                nerrorWeighted /= totalSaliency;
                nerror /= width * height;

                double[] nsegmentToError = new double[segToSaliency.Count()];
                double[] nsegToSqError = new double[segToSaliency.Count()];

                //now aggregate
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        double sqError = nerrors[i, j] * nerrors[i, j];
                        double val = map[i, j];
                        nerrorWeighted += val * nerrors[i, j];
                        nsqerrorW += val * sqError;
                        nerror += nerrors[i, j];
                        nsqerror += sqError;

                        int idx = nassignment[i, j];
                        if (idx >= 0)
                        {
                            elementToSaliency[idx] += val;
                            elementToCount[idx]++;
                        }
                        int segIdx = seg.assignments[i, j];
                        nsegmentToError[segIdx] += nerrors[i, j] / seg.counts[segIdx];
                        nsegToSqError[segIdx] += sqError / seg.counts[segIdx];

                    }
                }

                for (int i = 0; i < seg.numSegments; i++)
                {

                    nerrorSeg += nsegmentToError[i];
                    nerrorSegSal += nsegmentToError[i] * segToSaliency[i];

                    nsqerrorSeg += nsegToSqError[i];
                    nsqerrorSegSal += nsegToSqError[i] * segToSaliency[i]; //TODO: this is weighted by segment percent salient density

                    nerrorsegsd += nsegmentToError[i] * segmentToSD[i];
                    nsqerrorsegsd += nsegToSqError[i] * segmentToSD[i];

                }

                nerrorSeg /= seg.numSegments;
                nerrorSegSal /= totalSaliency;

                nsqerrorSeg /= seg.numSegments;
                nsqerrorSegSal /= totalSaliency;

                nerrorWeighted /= totalSaliency;
                nerror /= width * height;

                nsqerrorW /= totalSaliency;
                nsqerror /= width * height;

                nerrorsegsd /= totalSD;
                nsqerrorsegsd /= totalSD;

            }
            Log(log, "Coverage and Name Coverage" + watch.ElapsedMilliseconds);
            watch.Restart();

            for (int i = 0; i < n; i++)
            {
                double dens = elementToSaliency[i] / Math.Max(1, elementToCount[i]);
                sdmin2 = Math.Min(dens, sdmin2);
                sdmax2 = Math.Max(dens, sdmax2);
                sdavg2 += dens;
            }
            sdavg2 /= data.lab.Count();

            Log(log, "SaliencyDensClust " + watch.ElapsedMilliseconds);
            watch.Restart();

            //total captured salience (salience sum/salience of the image)
            double stotal = 0;

            //average salience density of each swatch (and min/max)
            double sdmin = 1;
            double sdmax = 0;
            double sdavg = 0;

            foreach (CIELAB c in data.lab)
            {
                double val = colorToSaliency[swatchIndexOf[c]] / Math.Max(1, colorToCounts[swatchIndexOf[c]]);
                sdmin = Math.Min(val, sdmin);
                sdmax = Math.Max(val, sdavg);
                sdavg += val;
                stotal += colorToSaliency[swatchIndexOf[c]];
            }
            sdavg /= data.lab.Count();
            stotal /= totalCapturable;

            Log(log, "SaliencyDens " + watch.ElapsedMilliseconds);
            watch.Restart();

            double cnmin = 1;
            double cnmax = 0;
            double cnavg = 0;

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    double dist = 1 - colorNames.CosineDistance(data.lab[i], data.lab[j]);
                    cnavg += dist;
                    cnmin = Math.Min(cnmin, dist);
                    cnmax = Math.Max(cnmax, dist);
                }
            }
            cnavg /= n * (n - 1) / 2;

            Log(log, "NamesDiff " + watch.ElapsedMilliseconds);
            watch.Restart();

            //Calculate the color name diversity, avg color name distance to closest neighbor
            double cndiv = 0;

            for (int c = 0; c < n; c++)
            {
                double bestDist = 1;
                for (int i = 0; i < n; i++)
                {
                    if (c == i)
                        continue;
                    double curDist = 1 - colorNames.CosineDistance(data.lab[i], data.lab[c]);
                    if (curDist < bestDist)
                        bestDist = curDist;
                }

                cndiv += bestDist / n;
            }

            Log(log, "NamesClosestAvg " + watch.ElapsedMilliseconds);
            watch.Restart();

            //calculate color name salience (average, min, max)
            double csmin = 1;
            double csmax = 0;
            double csavg = 0;

            for (int i = 0; i < n; i++)
            {
                double salience = (colorToCNSaliency[swatchIndexOf[data.lab[i]]] - minE) / (maxE - minE);//colorNames.NormalizedSaliency(data.lab[i], minE, maxE);
                csavg += salience;
                csmin = Math.Min(csmin, salience);
                csmax = Math.Max(csmax, salience);
            }
            csavg /= n;

            Log(log, "NameSalience " + watch.ElapsedMilliseconds);
            watch.Restart();

            //Calculate the diversity, avg distance to closest neighbor
            double div = 0;
            double divr = 0;

            for (int c = 0; c < n; c++)
            {
                double bestDist = Double.PositiveInfinity;
                for (int i = 0; i < n; i++)
                {
                    if (c == i)
                        continue;
                    double curDist = data.lab[c].SqDist(data.lab[i]);
                    if (curDist < bestDist)
                        bestDist = curDist;
                }

                div += Math.Sqrt(bestDist); // (n * factor);
            }
            double temp = div;
            div = temp / (n * factor);
            divr = temp / (n * afactor);

            Log(log, "DiffClosestAvg " + watch.ElapsedMilliseconds);
            watch.Restart();

            //calculate average distance of one color to the rest of the colors
            double dmin = 1;
            double dmax = 0;
            double davg = 0;

            double dminr = 1;
            double dmaxr = 0;
            double davgr = 0;

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    double dist = Math.Sqrt(data.lab[i].SqDist(data.lab[j]));
                    davg += dist;
                    dmin = Math.Min(dmin, dist);
                    dmax = Math.Max(dmax, dist);
                }
            }

            double dtemp = dmin;
            dmin = dtemp / factor;
            dminr = dtemp / afactor;
            dtemp = dmax;
            dmax = dtemp / factor;
            dmaxr = dtemp / afactor;

            davg /= n * (n - 1) / 2;

            dtemp = davg;
            davg = dtemp / factor;
            davgr = dtemp / afactor;

            Log(log, "LABDiff " + watch.ElapsedMilliseconds);
            watch.Restart();

            double puritymin = double.PositiveInfinity;
            double puritymax = double.NegativeInfinity;
            double purityavg = 0;

            double purityminr = puritymin;
            double puritymaxr = puritymax;
            double purityavgr = 0;

            foreach (CIELAB c in data.lab)
            {
                double val = swatchToPurity[swatchIndexOf[c]];
                puritymin = Math.Min(puritymin, val);
                puritymax = Math.Max(puritymax, val);
                purityavg += val;
            }
            double ptemp = puritymin;
            puritymin = ptemp / factor;
            purityminr = ptemp / factor;

            ptemp = puritymax;
            puritymax = ptemp / factor;
            puritymaxr = ptemp / afactor;

            ptemp = purityavg / data.lab.Count();
            purityavg = ptemp / factor;
            purityavgr = ptemp / afactor;

            //Record all the features
            features.Add(Features.CovUnweighted, 1 - error);
            features.Add(Features.CovWeightedSaliency, 1 - errorWeighted);
            features.Add(Features.ErrorUnweighted, error);
            features.Add(Features.ErrorWeightedSaliency, errorWeighted);
            features.Add(Features.NCov, 1 - nerror);
            features.Add(Features.NCovWeightedSaliency, 1 - nerrorWeighted);
            features.Add(Features.NError, nerror);
            features.Add(Features.NErrorWeightedSaliency, nerrorWeighted);
            features.Add(Features.DAvg, davg);
            features.Add(Features.DClosestAvg, div);
            features.Add(Features.DMin, dmin);
            features.Add(Features.DMax, dmax);
            features.Add(Features.NClosestAvg, cndiv);
            features.Add(Features.NDiffAvg, cnavg / maxN);
            features.Add(Features.NDiffMin, cnmin / maxN);
            features.Add(Features.NDiffMax, cnmax / maxN);
            features.Add(Features.NSaliencyMin, csmin);
            features.Add(Features.NSaliencyMax, csmax);
            features.Add(Features.NSaliencyAvg, csavg);
            features.Add(Features.SaliencyDensMin, sdmin);
            features.Add(Features.SaliencyDensMax, sdmax);
            features.Add(Features.SaliencyDensAvg, sdavg);
            features.Add(Features.SaliencyTotal, stotal);
            features.Add(Features.SaliencyDensClustMin, sdmin2);
            features.Add(Features.SaliencyDensClustMax, sdmax2);
            features.Add(Features.SaliencyDensClustAvg, sdavg2);
            features.Add(Features.DMinR, dminr);
            features.Add(Features.DMaxR, dmaxr);
            features.Add(Features.DAvgR, davgr);
            features.Add(Features.DClosestAvgR, divr);
            features.Add(Features.PurityMin, puritymin);
            features.Add(Features.PurityMax, puritymax);
            features.Add(Features.PurityAvg, purityavg);
            features.Add(Features.PurityMinR, purityminr);
            features.Add(Features.PurityMaxR, puritymaxr);
            features.Add(Features.PurityAvgR, purityavgr);

            features.Add(Features.NDiffMinR, cnmin / avgN);
            features.Add(Features.NDiffMaxR, cnmax / avgN);
            features.Add(Features.NDiffAvgR, cnavg / avgN);
            features.Add(Features.NSaliencyAvgR, csavg / avgE);
            features.Add(Features.NSaliencyMaxR, csmax / avgE);
            features.Add(Features.NSaliencyMinR, csmin / avgE);
            features.Add(Features.NClosestAvgR, cndiv / avgE);

            features.Add(Features.ErrorWeightedSegment, errorSegSal);
            features.Add(Features.ErrorUnweightedSegment, errorSeg);

            features.Add(Features.ColorsPerSeg, colorsPSeg);
            features.Add(Features.ColorsPerSegWeighted, colorsPSegW);

            features.Add(Features.MeanSegError, meansegError);
            features.Add(Features.MeanSegErrorWeighted, meansegErrorWeighted);

            features.Add(Features.LCov, Lcov);
            features.Add(Features.ACov, Acov);
            features.Add(Features.BCov, Bcov);
            features.Add(Features.SatCov, Scov);

            features.Add(Features.BetweenVar, betweenVariance);
            features.Add(Features.WithinVar, withinVariance);
            features.Add(Features.SqErrorUnweighted, sqerror);
            features.Add(Features.SqErrorWeightedSaliency, sqerrorW);
            features.Add(Features.SqErrorWSeg, sqerrorSegSal);
            features.Add(Features.SqErrorSeg, sqerrorSeg);

            features.Add(Features.NSqError, nsqerror);
            features.Add(Features.NSqErrorW, nsqerrorW);
            features.Add(Features.NSqErrorSeg, nsqerrorSeg);
            features.Add(Features.NSqErrorWSeg, nsqerrorSegSal);
            features.Add(Features.NErrorSeg, nerrorSeg);
            features.Add(Features.NErrorWSeg, nerrorSegSal);

            features.Add(Features.SoftError, softerror);
            features.Add(Features.SoftWError, softwerror);
            features.Add(Features.SoftErrorSeg, softerrorseg);
            features.Add(Features.SoftErrorWSeg, softerrorwseg);

            features.Add(Features.NSoftError, nsofterror);
            features.Add(Features.NSoftWError, nsoftwerror);
            features.Add(Features.NSoftErrorSeg, nsofterrorseg);
            features.Add(Features.NSoftErrorWSeg, nsofterrorwseg);

            features.Add(Features.NMeanSegError, nmeansegerror);
            features.Add(Features.NMeanSegErrorW, nmeansegwerror);

            features.Add(Features.MeanSegErrorDensity, meansegsd);
            features.Add(Features.NMeanSegErrorDensity, nmeansegsd);

            features.Add(Features.ErrorSegSD, errorsegsd);
            features.Add(Features.NErrorSegSD, nerrorsegsd);
            features.Add(Features.SqErrorSegSD, sqerrorsegsd);
            features.Add(Features.NSqErrorSegSD, nsqerrorsegsd);
            features.Add(Features.SoftErrorSegSD, softerrorsegsd);
            features.Add(Features.NSoftErrorSegSD, nsofterrorsegsd);

            return features;
        }
示例#27
0
        private Dictionary<String, List<PaletteData>> LoadFilePalettes(String file)
        {
            //load art palettes
            var lines = File.ReadLines(file);

            Dictionary<String, List<PaletteData>> plist = new Dictionary<String, List<PaletteData>>();

            int count = 0;
            List<String> headers = new List<String>();

            foreach (String line in lines)
            {
                if (count == 0)
                {
                    count++;
                    headers = line.Replace("\"", "").Split('\t').ToList<String>();
                    continue;
                }

                String[] fields = line.Replace("\"", "").Split('\t');
                PaletteData data = new PaletteData();
                data.id = Int32.Parse(fields[headers.IndexOf("pid")]);
                data.workerNum = Int32.Parse(fields[headers.IndexOf("id")]);
                String key = fields[headers.IndexOf("image")];
                String[] colors = fields[headers.IndexOf("colors")].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
                if (headers.IndexOf("log") >= 0)
                    data.log = fields[headers.IndexOf("log")];

                foreach (String s in colors)
                {
                    String[] comp = s.Split(',');
                    Color c = Color.FromArgb(Int32.Parse(comp[0]), Int32.Parse(comp[1]), Int32.Parse(comp[2]));
                    CIELAB l = Util.RGBtoLAB(c);
                    data.colors.Add(c);
                    data.lab.Add(l);
                }
                if (!plist.ContainsKey(key))
                    plist.Add(key, new List<PaletteData>());
                plist[key].Add(data);
            }
            return plist;
        }