//Test the quantization, connected components on different color layers, and output the descriptor
        private void OutputPatterns_Click(object sender, RoutedEventArgs e)
        {
            //Create output directories
            Directory.CreateDirectory(outdir + "\\cc\\");
            Directory.CreateDirectory(outdir + "\\quantized\\");
            Directory.CreateDirectory(outdir + "\\mesh\\");

            //read in the patterns and save out their layers
            String[]           files    = System.IO.Directory.GetFiles(System.IO.Path.Combine(imagedir));
            List <PatternItem> patterns = PatternIO.GetPatterns(imagedir);

            foreach (PatternItem p in patterns)
            {
                Bitmap image    = new Bitmap(p.FullPath);
                String basename = p.Name;

                //TODO: sometimes keys are not found in patterns.csv...will need to look into recovering missing info. For now, just ignore those patterns
                if (!palettes.ContainsKey(basename))
                {
                    continue;
                }

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);

                //output the template descriptor
                SegmentMesh mesh = new SegmentMesh(template);
                PatternIO.SaveMesh(mesh, p, Path.Combine(outdir, "mesh"));

                if (outputDebugImages)
                {
                    Bitmap result = template.DebugQuantization();
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_quantized");
                    PatternIO.SavePattern(result, p, Path.Combine(outdir, "quantized"), "_original");

                    //save the connected components
                    UnionFind <Color> uf = new UnionFind <Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
                    Color[,] resultArray = Util.BitmapToArray(result);
                    int[,] cc            = uf.ConnectedComponentsNoiseRemoval(resultArray);

                    int numColors = palette.colors.Count();
                    for (int i = 0; i < numColors; i++)
                    {
                        Bitmap debug = uf.RenderComponents(cc, resultArray, palette.colors[i]);
                        PatternIO.SavePattern(debug, p, Path.Combine(outdir, "cc"), "_" + i);
                        debug.Dispose();
                    }
                    result.Dispose();
                }
                image.Dispose();
            }
        }
Beispiel #2
0
    void get_color()
    {
        selected_color = color_template;

        switch (color_template)
        {
        case ColorTemplate.red:
            r = 255; g = 0; b = 0; a = 0;
            break;

        case ColorTemplate.green:
            r = 3; g = 250; b = 8; a = 0;
            break;

        case ColorTemplate.blue:
            r = 0; g = 182; b = 241; a = 0;
            break;

        case ColorTemplate.yellow:
            r = 240; g = 255; b = 0; a = 0;
            break;

        case ColorTemplate.rosa:
            r = 206; g = 4; b = 219; a = 0;
            break;

        case ColorTemplate.white:
            r = 245; g = 245; b = 245; a = 0;
            break;

        case ColorTemplate.black:
            r = 39; g = 39; b = 39; a = 0;
            break;

        case ColorTemplate.orange:
            r = 255; g = 115; b = 0; a = 0;
            break;

        case ColorTemplate.brown:
            r = 102; g = 51; b = 45; a = 0;
            break;

        default:
            break;
        }
    }
Beispiel #3
0
        private void ExtractTemplate_Click(object sender, EventArgs e)
        {
            //extract templates from images in a directory
            String[] files  = Directory.GetFiles(dir, "*.png");
            String   infile = dir + "\\palettes.tsv";
            Dictionary <String, List <PaletteData> > palettes = LoadFilePalettes(infile);

            Directory.CreateDirectory(dir + "\\templates\\");
            Directory.CreateDirectory(dir + "\\recolor\\");

            Random random = new Random();

            foreach (String f in files)
            {
                Bitmap       image    = new Bitmap(Image.FromFile(f));
                Segmentation seg      = new Segmentation();
                String       basename = f.Replace(dir + "\\", "");
                String       segFile  = dir + "/segments/" + basename;
                seg.LoadFromFile(f, segFile);

                ColorTemplate template = new ColorTemplate(image, seg, palettes[basename].First());
                Bitmap        render   = template.Render();
                render.Save(dir + "\\templates\\" + basename);

                //testing random color assignments
                int numSeg = template.NumSlots();

                int[] segToColor = new int[numSeg];
                for (int t = 0; t < 3; t++)
                {
                    for (int i = 0; i < numSeg; i++)
                    {
                        segToColor[i] = random.Next(palettes[basename].First().colors.Count());
                    }

                    Bitmap recolor = template.ColorWith(palettes[basename].First(), segToColor);
                    recolor.Save(dir + "\\recolor\\" + Util.ConvertFileName(basename, "_" + t));

                    Bitmap solidcolor = template.SolidColor(palettes[basename].First(), segToColor);
                    solidcolor.Save(dir + "\\recolor\\" + Util.ConvertFileName(basename, "_" + t + "_solid"));
                }
            }
        }
Beispiel #4
0
 void GetARandomTemplate()
 {
     ColorTemplate[] colorTemplates = FindObjectsOfType <ColorTemplate>();
     colorTemplate = colorTemplates[Random.Range(0, colorTemplates.Length)];
 }
        public SegmentMesh(ColorTemplate template)
        {
            int numGroups = template.NumSlots();

            imageWidth  = template.Width();
            imageHeight = template.Height();

            groups   = new List <SegmentGroup>();
            segments = new List <Segment>();

            //now populate the segments and segment groups
            //filter out groups that have no members (due to quantization)
            Dictionary <int, int> slotToGroup = new Dictionary <int, int>();

            for (int i = 0; i < numGroups; i++)
            {
                if (template.PixelsInSlot(i) > 0)
                {
                    slotToGroup.Add(i, groups.Count());
                    groups.Add(new SegmentGroup(template.OriginalSlotColor(i)));
                }
            }

            UnionFind <Color> uf    = new UnionFind <Color>((a, b) => (a.GetHashCode() == b.GetHashCode()));
            Bitmap            image = template.DebugQuantization();

            assignments = uf.ConnectedComponentsNoiseRemoval(Util.BitmapToArray(image));


            Dictionary <int, Segment> idToSegment            = new Dictionary <int, Segment>();
            int totalAdjacencyPerimeter                      = 0;
            Dictionary <int, HashSet <Point> > idToPerimeter = new Dictionary <int, HashSet <Point> >();

            //populate segments
            int width  = image.Width;
            int height = image.Height;

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    int id = assignments[i, j];
                    if (!idToSegment.ContainsKey(id))
                    {
                        idToSegment.Add(id, new Segment(id));
                        idToPerimeter.Add(id, new HashSet <Point>());
                    }

                    idToSegment[id].points.Add(new Point(i, j));
                    idToSegment[id].groupId = slotToGroup[template.GetSlotId(i, j)];

                    //look for 8-neighbor adjacencies, 2 pixels away
                    //TODO: measure adjacency strength and filter?
                    for (int dx = -2; dx <= 2; dx++)
                    {
                        for (int dy = -2; dy <= 2; dy++)
                        {
                            int x = i + dx;
                            int y = j + dy;
                            if (x >= 0 && x < width && y >= 0 && y < height)
                            {
                                int nid = assignments[x, y];
                                if (nid != id)
                                {
                                    idToSegment[id].adjacencies.Add(nid);

                                    //keep track of the total perimeter, and individual segment perimeters
                                    //don't double count the same point for each segment
                                    if (!idToPerimeter[id].Contains(new Point(x, y)))
                                    {
                                        idToPerimeter[id].Add(new Point(x, y));
                                        totalAdjacencyPerimeter++;

                                        //keep track of the adjacecy strength per segment
                                        if (!idToSegment[id].adjacencyStrength.ContainsKey(nid))
                                        {
                                            idToSegment[id].adjacencyStrength.Add(nid, 0);
                                        }
                                        idToSegment[id].adjacencyStrength[nid]++;
                                    }
                                    else
                                    {
                                        Console.WriteLine("Point already counted");
                                    }
                                }
                            }
                            else
                            {
                                //might as well be consistent here, and take into account the borders of the image when determining
                                //enclosure. We don't need to do this for the totalAdjacencyPerimeter, because that is just a normalization
                                //for the adjacency strengths of segments within the image
                                if (!idToPerimeter[id].Contains(new Point(x, y)))
                                {
                                    idToPerimeter[id].Add(new Point(x, y));
                                }
                            }
                        }
                    }
                }
            }

            //finalize segment list and adjacency list
            Dictionary <int, int> idToIdx = new Dictionary <int, int>();

            foreach (int id in idToSegment.Keys)
            {
                segments.Add(idToSegment[id]);
                idToIdx.Add(id, segments.Count() - 1);
            }

            //finalize adjacencies
            for (int i = 0; i < segments.Count(); i++)
            {
                SortedSet <int> renamedAdj = new SortedSet <int>();
                foreach (int a in segments[i].adjacencies)
                {
                    renamedAdj.Add(idToIdx[a]);
                }
                segments[i].adjacencies = renamedAdj;

                //finalize adjacency strengths
                int sid = assignments[segments[i].points.First().X, segments[i].points.First().Y];

                Dictionary <int, double> renamedAdjStrength = new Dictionary <int, double>();
                foreach (int nid in segments[i].adjacencyStrength.Keys)
                {
                    double pixelsAdj = segments[i].adjacencyStrength[nid];
                    renamedAdjStrength.Add(idToIdx[nid], pixelsAdj / totalAdjacencyPerimeter);
                    segments[i].enclosureStrength.Add(idToIdx[nid], new Tuple <double, double>(pixelsAdj / idToPerimeter[sid].Count(), pixelsAdj / idToPerimeter[nid].Count()));
                }
                segments[i].adjacencyStrength = renamedAdjStrength;
            }

            //finalize groups
            for (int i = 0; i < segments.Count(); i++)
            {
                int groupId = segments[i].groupId;
                groups[groupId].members.Add(i);
            }

            //finalize segment list

            ClassifySegments();

            foreach (Segment s in segments)
            {
                ComputeFeatures(s);
            }

            foreach (SegmentGroup g in groups)
            {
                ComputeFeatures(g);
            }
        }
        private void RenderPreviews()
        {
            //render the segment previews for the visualization
            Directory.CreateDirectory(Path.Combine(outdir, "\\previews\\"));

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

            int hpadding = 30;

            foreach (PatternItem p in patterns)
            {
                Bitmap image    = new Bitmap(p.FullPath);
                String basename = p.Name;

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

                PaletteData palette = palettes[basename];

                ColorTemplate template = new ColorTemplate(image, palette);
                SegmentMesh   mesh     = new SegmentMesh(template);

                //create a pattern directory (Not using PatternIO here, since each pattern has its own directory anyways)
                String patternDir = Path.Combine(outdir, "previews", Util.ConvertFileName(basename, "", ""));
                Directory.CreateDirectory(patternDir);

                //for each segment, pair of adjacent segments, and group, output a preview image
                List <Segment>      segs   = mesh.getSegments();
                List <SegmentGroup> groups = mesh.getGroups();

                Bitmap original = (renderFinal)? image : template.DebugQuantization();

                Bitmap previewBase = new Bitmap(original.Width * 2 + hpadding, original.Height);
                //draw the original image on the right
                Graphics g = Graphics.FromImage(previewBase);
                g.DrawImage(original, original.Width + hpadding, 0);

                //draw a grayscaled image on the left
                for (int i = 0; i < original.Width; i++)
                {
                    for (int j = 0; j < original.Height; j++)
                    {
                        int gray = (int)Math.Round(255 * original.GetPixel(i, j).GetBrightness());
                        previewBase.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
                    }
                }

                //color in orange and blue

                for (int i = 0; i < segs.Count(); i++)
                {
                    Bitmap unary = new Bitmap(previewBase);
                    foreach (var point in segs[i].points)
                    {
                        unary.SetPixel(point.X, point.Y, Color.Orange);
                    }
                    unary.Save(Path.Combine(patternDir, "s" + i + ".png"));

                    foreach (int j in segs[i].adjacencies)
                    {
                        if (j > i)
                        {
                            Bitmap binary = new Bitmap(unary);

                            Segment neighbor = segs[j];
                            foreach (var point in neighbor.points)
                            {
                                binary.SetPixel(point.X, point.Y, Color.ForestGreen);
                            }

                            binary.Save(Path.Combine(patternDir, "s" + i + "-s" + j + ".png"));
                            binary.Dispose();
                        }
                    }
                    unary.Dispose();
                }

                for (int i = 0; i < groups.Count(); i++)
                {
                    Bitmap group = new Bitmap(previewBase);
                    foreach (int j in groups[i].members)
                    {
                        Segment member = segs[j];

                        //color in the points
                        foreach (var point in member.points)
                        {
                            group.SetPixel(point.X, point.Y, Color.Orange);
                        }
                    }
                    group.Save(Path.Combine(patternDir, "g" + i + ".png"));
                    group.Dispose();
                }


                original.Dispose();
                previewBase.Dispose();
            }
        }
        //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();
            }
        }
        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 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();
            }
        }