/** * Extract a palette by hill climbing on the given image * key - image name in the base directory (directory) * saliencyPattern - the label appended to the image name, to find the saliency map filename (i.e. "_Judd" for "[imagename]_Judd.[imagename extension]") * debug - if images should be resized smaller * paletteSize - the size of the palette to be extracted */ public PaletteData HillClimbPalette(String key, String saliencyPattern, bool debug = false, int paletteSize=5) { //Now initialize a palette and start hill climbing int trials = 5; PaletteScoreCache cache = new PaletteScoreCache(1000000); 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(Path.Combine(weightsDir,"weights.csv"), Path.Combine(weightsDir,"featurenames.txt")); PaletteData best = new PaletteData(); double bestScore = Double.NegativeInfinity; SortedSet<Features> included = new SortedSet<Features>(weights.Keys); Stopwatch watch = new Stopwatch(); watch.Start(); FeatureParams fparams = SetupFeatureParams(included, key, saliencyPattern, debug); Log(Path.Combine(dir, "out", "convergelog.txt"), "Setup feature params " + watch.ElapsedMilliseconds); //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 < paletteSize; 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; cache.SetScore(option.lab, 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; int reuse = 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]; Color bestRGB = option.colors[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]; if (!cache.ContainsKey(temp.lab)) { double tempScore = ScorePalette(weights, CalculateFeatures(temp, fparams)); scores[s] = tempScore; cache.SetScore(temp.lab, tempScore); } else { scores[s] = cache.GetScore(temp.lab); reuse++; } } 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]; bestRGB = swatches.colors[s]; } } if (!option.lab[i].Equals(bestRep)) { option.lab[i] = bestRep; option.colors[i] = bestRGB; optionScore = bestTempScore; changes++; } } iters++; } if (optionScore > allScores[t]) { allOptions[t] = option; allScores[t] = optionScore; } Log(Path.Combine(dir, "out", "convergelog.txt"), "Trial " + t + " Key " + key + " BestScore: " + allScores[t] + " Steps: " + iters + " Time: " + watch.ElapsedMilliseconds); Log(Path.Combine(dir, "out", "convergelog.txt"), "Reused " + reuse); } //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 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; }