Exemplo n.º 1
0
        private bool isBlackWhite(Color[,] image, CIELAB[,] imageLAB)
        {
            double nonGray = 0;
            double thresh  = 0.001;
            CIELAB white   = new CIELAB(100, 0, 0);
            CIELAB black   = new CIELAB(0, 0, 0);

            int width  = image.GetLength(0);
            int height = image.GetLength(1);

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    Color  color = image[i, j];
                    CIELAB lab   = imageLAB[i, j];//Util.RGBtoLAB(color);
                    bool   gray  = color.GetSaturation() <= 0.2 || lab.SqDist(white) <= 5 || lab.SqDist(black) <= 5;

                    if (!gray)
                    {
                        nonGray++;
                    }
                }
            }
            return(nonGray / (width * height) < thresh);
        }
Exemplo n.º 2
0
 public double NormalizedSaliency(CIELAB a, double minE = -4.5, double maxE = 0)
 {
     //hardcoded to XKCD
     //double minE = -4.5;
     //double maxE = 0;
     return((Saliency(a) - minE) / (maxE - minE));
 }
Exemplo n.º 3
0
 public Cluster()
 {
     lab    = new CIELAB();
     sumlab = new CIELAB();
     count  = 0;
     id     = -1;
 }
Exemplo n.º 4
0
 public void AddColor(CIELAB color, double weight = 1)
 {
     sumlab.L += color.L * weight;
     sumlab.A += color.A * weight;
     sumlab.B += color.B * weight;
     count    += weight;
 }
Exemplo n.º 5
0
        public Bitmap Render()
        {
            //render the template (assuming possible values are between -200 and 200)
            //must clamp to be valid RGB values
            int    width  = template.GetLength(0);
            int    height = template.GetLength(1);
            Bitmap result = new Bitmap(width, height);

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    CIELAB lab = template[i, j];

                    //add gray to the lab value
                    CIELAB gray = new CIELAB(53.5850, 0, 0);

                    //convert (first clamp to reasonable LAB values?)
                    Color rgb = Util.LABtoRGB(lab + gray);
                    //Color rgb = Util.LABtoRGB(lab * gray);

                    result.SetPixel(i, j, rgb);
                }
            }

            return(result);
        }
Exemplo n.º 6
0
        private int GetBinId(CIELAB color)
        {
            int Lbin = GetBin(color.L, minL, maxL, Lbins);
            int Abin = GetBin(color.A, minA, maxA, Abins);
            int Bbin = GetBin(color.B, minB, maxB, Bbins);

            return((int)(Abins * Bbins * Lbin + Abins * Bbin + Abin));
        }
Exemplo n.º 7
0
        private CIELAB[,] AverageRecolor(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
                    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))
                            {
                                for (int c = 0; c < palette.colors.Count(); c++)
                                {
                                    scores[c] += weight * image[x, y].SqDist(palette.lab[c]);
                                }
                            }
                        }
                    }

                    //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);
        }
Exemplo n.º 8
0
        public PixelCluster()
        {
            id    = -1;
            lab   = new CIELAB();
            count = 1;

            neighbors = new SortedSet <int>();
            parentId  = -1;
            children  = new int[] { };
        }
Exemplo n.º 9
0
        public PixelCluster(int i, CIELAB color)
        {
            id    = i;
            lab   = color;
            count = 1;

            neighbors = new SortedSet <int>();
            parentId  = i;
            children  = new int[] { };
        }
Exemplo n.º 10
0
        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];
                }
            }
        }
Exemplo n.º 11
0
        public double GetCNDist(CIELAB a, CIELAB b)
        {
            int i = colorNames.GetBin(a);
            int j = colorNames.GetBin(b);

            if (CNcache[i, j] < 0)
            {
                double dist = 1 - colorNames.CosineDistance(i, j);
                CNcache[i, j] = dist;
                CNcache[j, i] = dist;
            }
            return(CNcache[i, j]);
        }
Exemplo n.º 12
0
        public static ColorMood LABtoColorMood(CIELAB lab)
        {
            //hue angle
            double h        = Math.Atan2(lab.B, lab.A);// +Math.PI;
            double radians1 = 100 * (Math.PI / 180.0);
            double radians2 = 50 * (Math.PI / 180.0);
            double chroma   = Math.Sqrt(lab.A * lab.A + lab.B * lab.B);

            double activity = -2.1 + 0.06 * Math.Sqrt(Math.Pow(lab.L - 50, 2) + Math.Pow(lab.A - 3, 2) + Math.Pow((lab.B - 17) / 1.4, 2));
            double weight   = -1.8 + 0.04 * (100 - lab.L) + 0.45 * Math.Cos(h - radians1);
            double heat     = -0.5 + 0.02 * Math.Pow(chroma, 1.07) * Math.Cos(h - radians2);

            return(new ColorMood(activity, weight, heat));
        }
Exemplo n.º 13
0
        private CIELAB ClosestColor(CIELAB color, List <CIELAB> palette)
        {
            int    bestc    = 0;
            Double bestDist = Double.PositiveInfinity;

            for (int c = 0; c < palette.Count(); c++)
            {
                double dist = color.SqDist(palette[c]);
                if (dist < bestDist)
                {
                    bestDist = dist;
                    bestc    = c;
                }
            }
            return(palette[bestc]);
        }
Exemplo n.º 14
0
        public double Saliency(CIELAB a)
        {
            double H = 0;
            int    W = terms.Count();
            int    i = GetBin(a);

            for (int w = 0; w < W; w++)
            {
                double p = T[i * W + w];
                p /= ccount[i];
                if (p > 0)
                {
                    H += p * Math.Log(p) / Math.Log(2);
                }
            }
            return(H);
        }
Exemplo n.º 15
0
        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);
        }
Exemplo n.º 16
0
        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);
        }
Exemplo n.º 17
0
        public static Color LABtoRGB(CIELAB lab)
        {
            double gamma = 2.2;
            double e     = 216 / 24389.0;
            double k     = 24389 / 27.0;

            double XR = 0.95047;
            double YR = 1.00000;
            double ZR = 1.08883;

            double fy = (lab.L + 16) / 116.0;
            double fx = lab.A / 500.0 + fy;
            double fz = fy - lab.B / 200.0;

            double[,] xyzTorgbMatrix = new double[3, 3] {
                { 3.2404542, -1.5371385, -0.4985314 },
                { -0.9692660, 1.8760108, 0.0415560 },
                { 0.0556434, -0.2040259, 1.0572252 }
            };
            double xR = Math.Pow(fx, 3.0);
            double zR = Math.Pow(fz, 3.0);

            xR = (xR > e) ? xR : (116 * fx - 16) / k;
            double yR = (lab.L > k * e) ? Math.Pow((lab.L + 16) / 116.0, 3.0) : lab.L / k;

            zR = (zR > e) ? zR : (116 * fz - 16) / k;

            double x = xR * XR;
            double y = yR * YR;
            double z = zR * ZR;

            //xyz to rgb
            double r = xyzTorgbMatrix[0, 0] * x + xyzTorgbMatrix[0, 1] * y + xyzTorgbMatrix[0, 2] * z;
            double g = xyzTorgbMatrix[1, 0] * x + xyzTorgbMatrix[1, 1] * y + xyzTorgbMatrix[1, 2] * z;
            double b = xyzTorgbMatrix[2, 0] * x + xyzTorgbMatrix[2, 1] * y + xyzTorgbMatrix[2, 2] * z;

            int red   = (int)Math.Round(255 * (Math.Pow(clamp(r), 1.0 / gamma)));
            int green = (int)Math.Round(255 * (Math.Pow(clamp(g), 1.0 / gamma)));
            int blue  = (int)Math.Round(255 * (Math.Pow(clamp(b), 1.0 / gamma)));

            return(Color.FromArgb(red, green, blue));
        }
Exemplo n.º 18
0
        public int GetBin(CIELAB x)
        {
            int    L = (int)(5 * Math.Round(x.L / 5));
            int    A = (int)(5 * Math.Round(x.A / 5));
            int    B = (int)(5 * Math.Round(x.B / 5));
            String s = L + "," + A + "," + B;

            if (map.ContainsKey(s))
            {
                return(map[s]);
            }
            else
            {
                //look at nearby bins
                CIELAB[] neighbors = new CIELAB[] { new CIELAB(L, A, B + 5), new CIELAB(L, A, B - 5), new CIELAB(L, A + 5, B), new CIELAB(L, A - 5, B), new CIELAB(L - 5, A, B), new CIELAB(L + 5, A, B) };
                double   bestDist  = Double.PositiveInfinity;
                String   best      = "";

                for (int i = 0; i < neighbors.Count(); i++)
                {
                    String key  = neighbors[i].L + "," + neighbors[i].A + "," + neighbors[i].B;
                    double dist = neighbors[i].SqDist(x);
                    if (dist < bestDist && map.ContainsKey(key))
                    {
                        bestDist = dist;
                        best     = key;
                    }
                }
                if (best != "")
                {
                    //return the best
                    return(map[best]);
                }
                else
                {
                    //give up
                    return(-1);
                }
            }
        }
Exemplo n.º 19
0
        public double CosineDistance(CIELAB a, CIELAB b)
        {
            int i = GetBin(a);
            int j = GetBin(b);
            int C = colors.Count();
            int W = terms.Count();

            double sa = 0, sb = 0, sc = 0;
            int    ta;
            int    tb;

            for (var w = 0; w < W; w++)
            {
                ta  = T[i * W + w];
                tb  = T[j * W + w];
                sa += ta * ta;
                sb += tb * tb;
                sc += ta * tb;
            }

            return(sc / Math.Max((Math.Sqrt(sa * sb)), 1));
        }
Exemplo n.º 20
0
        public static List <Cluster> InitializePictureSeeds(List <CIELAB> colors, int k)
        {
            //initialize k seeds, randomly choose colors in LAB space
            //find extents
            List <Cluster> seeds  = new List <Cluster>();
            Random         random = new Random();

            //sample colors in LAB bounding box
            double Lmin = double.PositiveInfinity;
            double Lmax = double.NegativeInfinity;
            double Amin = double.PositiveInfinity;
            double Amax = double.NegativeInfinity;
            double Bmin = double.PositiveInfinity;
            double Bmax = double.NegativeInfinity;

            for (int i = 0; i < colors.Count(); i++)
            {
                CIELAB lab = colors[i];
                Lmin = Math.Min(Lmin, lab.L);
                Lmax = Math.Max(Lmax, lab.L);
                Amin = Math.Min(Amin, lab.A);
                Amax = Math.Max(Amax, lab.A);
                Bmin = Math.Min(Bmin, lab.B);
                Bmax = Math.Max(Bmax, lab.B);
            }



            //initialize the seeds (stratified) randomly
            //within the bounding box
            if (k <= 10)
            {
                for (int i = 0; i < k; i++)
                {
                    double  L       = random.NextDouble() * (Lmax - Lmin) + Lmin;
                    double  A       = random.NextDouble() * (Amax - Amin) + Amin;
                    double  B       = random.NextDouble() * (Bmax - Bmin) + Bmin;
                    CIELAB  seed    = new CIELAB(L, A, B);
                    Cluster cluster = new Cluster();
                    cluster.id  = i;
                    cluster.lab = seed;
                    seeds.Add(cluster);
                }
            }
            else
            {
                //stratified
                //find closest floor perfect square.
                //TODO: need to generalize this better, doesn't work for non-perfect squares
                int sideLength = 2;

                int numSamples = (int)Math.Floor(k / (double)(sideLength * sideLength * sideLength));
                int i          = 0;

                for (int l = 0; l < sideLength; l++)
                {
                    double dLmax = (Lmax - Lmin) / sideLength * (l + 1) + Lmin;
                    double dLmin = (Lmax - Lmin) / sideLength * l + Lmin;

                    for (int a = 0; a < sideLength; a++)
                    {
                        double dAmax = (Amax - Amin) / sideLength * (a + 1) + Amin;
                        double dAmin = (Amax - Amin) / sideLength * a + Amin;

                        for (int b = 0; b < sideLength; b++)
                        {
                            double dBmax = (Bmax - Bmin) / sideLength * (b + 1) + Bmin;
                            double dBmin = (Bmax - Bmin) / sideLength * b + Bmin;

                            int dSamples = numSamples;

                            if (b == sideLength - 1 && a == sideLength - 1 && l == sideLength - 1)
                            {
                                //figure out leftovers
                                dSamples = k - numSamples * (sideLength * sideLength * sideLength - 1);
                            }
                            for (int s = 0; s < dSamples; s++)
                            {
                                double  L       = random.NextDouble() * (dLmax - dLmin) + dLmin;
                                double  A       = random.NextDouble() * (dAmax - dAmin) + dAmin;
                                double  B       = random.NextDouble() * (dBmax - dBmin) + dBmin;
                                CIELAB  seed    = new CIELAB(L, A, B);
                                Cluster cluster = new Cluster();
                                cluster.id  = i;
                                cluster.lab = seed;
                                seeds.Add(cluster);
                                i++;
                            }
                        }
                    }
                }
            }


            return(seeds);
        }
Exemplo n.º 21
0
 public void Reset()
 {
     lab    = MeanColor();
     count  = 0;
     sumlab = new CIELAB(0, 0, 0);
 }
Exemplo n.º 22
0
        /**
         * Compute histograms for the given category, both clipart and regular
         **/
        private void ComputeHistograms(Category category, bool loadIfPossible = true)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();

            Parallel.For(0, category.members.Count(), m =>
            {
                String member = category.members[m];

                //Get the relevant images
                String[] queryLabels = { "", "_clipart" };

                foreach (String label in queryLabels)
                {
                    String baseName  = Encode(member) + label;
                    String outFile   = Path.Combine(cacheDir, baseName + ".txt");
                    String memberDir = Path.Combine(imageDir, baseName);

                    if (File.Exists(outFile) && loadIfPossible)
                    {
                        Console.WriteLine("Reusing histogram for " + baseName);
                        continue;
                    }

                    double[, ,] histogram = new double[Lbins, Abins, Bbins];
                    String[] files        = Directory.GetFiles(memberDir);

                    foreach (String f in files)
                    {
                        //TODO: maybe process the image here, or filter it out
                        try
                        {
                            Bitmap image = ResizeImage(f);

                            Color[,] imageRGB  = Util.BitmapToArray(image);
                            CIELAB[,] imageLAB = Util.Map <Color, CIELAB>(imageRGB, Util.RGBtoLAB);

                            //Process the image
                            bool valid = ProcessImage(imageRGB, imageLAB);
                            if (!valid)
                            {
                                continue;
                            }

                            double pixelCount = 0;
                            for (int i = 0; i < image.Width; i++)
                            {
                                for (int j = 0; j < image.Height; j++)
                                {
                                    if (imageRGB[i, j].A >= 1)
                                    {
                                        pixelCount++;
                                    }
                                }
                            }

                            if (pixelCount > 0)
                            {
                                for (int i = 0; i < image.Width; i++)
                                {
                                    for (int j = 0; j < image.Height; j++)
                                    {
                                        if (imageRGB[i, j].A <= 1)
                                        {
                                            continue;
                                        }

                                        CIELAB lab = imageLAB[i, j];//Util.RGBtoLAB(imageRGB[i,j]);

                                        //update histogram
                                        int L = (int)Math.Floor((lab.L / (double)binSize) + 0.5);
                                        int A = (int)Math.Floor(((100 + lab.A) / (double)binSize) + 0.5);
                                        int B = (int)Math.Floor(((100 + lab.B) / (double)binSize) + 0.5);

                                        L = clamp(L, 0, Lbins - 1);
                                        A = clamp(A, 0, Abins - 1);
                                        B = clamp(B, 0, Bbins - 1);

                                        histogram[L, A, B] += 1.0 / pixelCount;
                                    }
                                }
                            }

                            //cleanup
                            image.Dispose();
                        }
                        catch (Exception)
                        {
                            Console.WriteLine("Could not process image " + f);
                        }
                    }

                    //save the histogram to a file
                    List <String> lines = new List <String>();

                    for (int i = 0; i < Lbins; i++)
                    {
                        for (int j = 0; j < Abins; j++)
                        {
                            for (int k = 0; k < Bbins; k++)
                            {
                                lines.Add(histogram[i, j, k].ToString());
                            }
                        }
                    }
                    File.WriteAllLines(outFile, lines.ToArray <String>());
                }
            });
            watch.Stop();
            Console.WriteLine("Done with histograms Time: " + watch.ElapsedMilliseconds / 1000.0);
        }
Exemplo n.º 23
0
        private double[] GetProbabilities(String query, Func <CIELAB, CIELAB, double> distFunc, Kernel kernel, double whiteThresh = 20)
        {
            CIELAB white = new CIELAB(100, 0, 0);

            //load the histogram
            double[, ,] hist = new double[Lbins, Abins, Bbins];
            String histFile = Path.Combine(cacheDir, query) + ".txt";

            String[] hlines = File.ReadAllLines(histFile);
            for (int i = 0; i < hlines.Count(); i++)
            {
                int L     = i / (Abins * Bbins);
                int plane = (i % (Abins * Bbins));
                int A     = plane / Bbins;
                int B     = plane % Bbins;

                hist[L, A, B] = Double.Parse(hlines[i]);
            }

            int ncolors = paletteLAB.Count();

            double[] freq = new double[20];

            Parallel.For(0, ncolors, l =>
            {
                double count = 0;

                for (int i = 0; i < Lbins; i++)
                {
                    for (int j = 0; j < Abins; j++)
                    {
                        for (int k = 0; k < Bbins; k++)
                        {
                            double val = hist[i, j, k];

                            System.Diagnostics.Debug.Assert(!double.IsNaN(val));

                            CIELAB lab = new CIELAB(i * binSize, j * binSize - 100, k * binSize - 100);

                            if (white.SqDist(lab) < whiteThresh * whiteThresh)
                            {
                                continue;
                            }
                            if (val <= 0)
                            {
                                continue;
                            }

                            count += val;


                            freq[l] += val * kernel.Eval(distFunc(paletteLAB[l], lab));
                        }
                    }
                }
                if (count > 0)
                {
                    freq[l] /= count;
                }
            });

            //now renormalize
            double totalFreq = 0;

            for (int i = 0; i < freq.Count(); i++)
            {
                totalFreq += freq[i];
            }

            //this should only happen if the histogram is empty or has no valid bins
            if (totalFreq == 0)
            {
                totalFreq = 1;
            }

            for (int i = 0; i < freq.Count(); i++)
            {
                freq[i] /= totalFreq;
            }

            return(freq);
        }
Exemplo n.º 24
0
        public static double CMeansPicture(List <CIELAB> colors, List <Cluster> seeds, int m = 2)
        {
            //cluster colors given seeds
            //return score
            List <double> weights = new List <double>();

            double[,] memberships = new double[colors.Count(), seeds.Count()]; //pixel to cluster
            int numSeeds  = seeds.Count();
            int numColors = colors.Count();

            int    maxIters = 50;//100;
            double epsilon  = 0.0001;

            double J = Double.PositiveInfinity;

            int changes = 0;

            for (int t = 0; t < maxIters; t++)
            {
                changes = 0;
                for (int i = 0; i < colors.Count(); i++)
                {
                    //calculate the memberships
                    double[] dists  = new double[numSeeds];
                    double   factor = 0;
                    for (int k = 0; k < numSeeds; k++)
                    {
                        dists[k] = Math.Max(epsilon, Math.Pow(Math.Sqrt(colors[i].SqDist(seeds[k].lab)), 2.0 / (m - 1)));
                        factor  += (1.0 / dists[k]);
                    }
                    for (int k = 0; k < numSeeds; k++)
                    {
                        double oldval = memberships[i, k];
                        memberships[i, k] = 1.0 / (dists[k] * factor);
                        if (oldval != memberships[i, k])
                        {
                            changes++;
                        }
                    }
                }

                //update the centers
                for (int k = 0; k < numSeeds; k++)
                {
                    CIELAB center = new CIELAB();
                    double total  = 0;
                    for (int i = 0; i < numColors; i++)
                    {
                        double u = Math.Pow(memberships[i, k], m);
                        center += colors[i] * u;
                        total  += u;
                    }
                    center       = center / total;
                    seeds[k].lab = center;
                }

                //find J
                double thisJ = 0;
                for (int i = 0; i < numColors; i++)
                {
                    for (int k = 0; k < numSeeds; k++)
                    {
                        double u = memberships[i, k];
                        thisJ += Math.Pow(u, m) * Math.Max(epsilon, seeds[k].lab.SqDist(colors[i]));
                    }
                }

                if (thisJ >= J)
                {
                    break;
                }

                J = thisJ;

                if (changes == 0)
                {
                    break;
                }
            }



            return(J);
        }
Exemplo n.º 25
0
        private void RemoveBackground(Color[,] image, CIELAB[,] imageLAB)
        {
            //check perimeter to see if it's mostly black or white

            //RGB to LAB
            CIELAB black = new CIELAB(0, 0, 0);
            CIELAB white = new CIELAB(100, 0, 0);

            int width  = image.GetLength(0);
            int height = image.GetLength(1);

            CIELAB[,] labs = imageLAB;//Util.Map<Color, CIELAB>(image, (c) => Util.RGBtoLAB(c));

            int          numBlack       = 0;
            int          numWhite       = 0;
            int          thresh         = 3 * 3;
            List <Point> perimeterIdx   = new List <Point>();
            double       totalPerimeter = 4 * width + 4 * height;
            double       bgThresh       = totalPerimeter * 0.75;

            for (int i = 0; i < width; i++)
            {
                //top
                for (int j = 0; j < 2; j++)
                {
                    if (black.SqDist(labs[i, j]) < thresh)
                    {
                        numBlack++;
                    }
                    if (white.SqDist(labs[i, j]) < thresh)
                    {
                        numWhite++;
                    }
                    perimeterIdx.Add(new Point(i, j));
                }

                //bottom
                for (int j = height - 2; j < height; j++)
                {
                    perimeterIdx.Add(new Point(i, j));
                    if (black.SqDist(labs[i, j]) < thresh)
                    {
                        numBlack++;
                    }
                    if (white.SqDist(labs[i, j]) < thresh)
                    {
                        numWhite++;
                    }
                }
            }

            for (int j = 0; j < height; j++)
            {
                //left
                for (int i = 0; i < 2; i++)
                {
                    perimeterIdx.Add(new Point(i, j));
                    if (black.SqDist(labs[i, j]) < thresh)
                    {
                        numBlack++;
                    }
                    if (white.SqDist(labs[i, j]) < thresh)
                    {
                        numWhite++;
                    }
                }

                //right
                for (int i = width - 2; i < width; i++)
                {
                    perimeterIdx.Add(new Point(i, j));
                    if (black.SqDist(labs[i, j]) < thresh)
                    {
                        numBlack++;
                    }
                    if (white.SqDist(labs[i, j]) < thresh)
                    {
                        numWhite++;
                    }
                }
            }

            if (numBlack >= bgThresh || numWhite >= bgThresh)
            {
                //connected components
                UnionFind <CIELAB> uf = new UnionFind <CIELAB>((a, b) => a.SqDist(b) < thresh);
                int[,] cc = uf.ConnectedComponents(labs);

                SortedSet <int> ids = new SortedSet <int>();

                //go around the perimeter to collect the right ids
                foreach (Point p in perimeterIdx)
                {
                    if (numWhite > numBlack)
                    {
                        if (labs[p.X, p.Y].SqDist(white) < thresh)
                        {
                            ids.Add(cc[p.X, p.Y]);
                        }
                    }
                    else
                    {
                        if (labs[p.X, p.Y].SqDist(black) < thresh)
                        {
                            ids.Add(cc[p.X, p.Y]);
                        }
                    }
                }

                //fill the bitmap with transparency
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        if (ids.Contains(cc[i, j]))
                        {
                            image[i, j] = Color.FromArgb(0, 0, 0, 0);
                        }
                    }
                }
            }
        }
Exemplo n.º 26
0
        private double[,] ComputeAffinities(Category category, double clipartPrior = 0.7, double saturationThresh = 0.1, double sigma = 0.2, double whiteThresh = 20)
        {
            //get the color probabilities for regular and clipart queries
            double[,] pcw_regular = new double[paletteHex.Count(), category.members.Count()];
            double[,] pcw_clipart = new double[paletteHex.Count(), category.members.Count()];
            double[,] pcw         = new double[paletteHex.Count(), category.members.Count()];


            Parallel.For(0, category.members.Count(), w =>
            {
                String query        = Encode(category.members[w]);
                double[] pc_regular = GetProbabilities(query, GetCNDist, new GaussianKernel(sigma), whiteThresh);
                double[] pc_clipart = GetProbabilities(query + "_clipart", GetCNDist, new GaussianKernel(sigma), whiteThresh);

                for (int c = 0; c < paletteLAB.Count(); c++)
                {
                    pcw_regular[c, w] = pc_regular[c];
                    pcw_clipart[c, w] = pc_clipart[c];
                }
            });

            Console.WriteLine("Done computing probabilities");

            //compute combined probability
            for (int w = 0; w < category.members.Count(); w++)
            {
                double rentropy = 0;
                double centropy = 0;

                for (int c = 0; c < paletteHex.Count(); c++)
                {
                    if (pcw_clipart[c, w] > 0)
                    {
                        centropy += pcw_clipart[c, w] * Math.Log(pcw_clipart[c, w]);
                    }
                    if (pcw_regular[c, w] > 0)
                    {
                        rentropy += pcw_regular[c, w] * Math.Log(pcw_regular[c, w]);
                    }
                }

                centropy *= -1;
                rentropy *= -1;

                //avoid divide by zero
                centropy = Math.Max(centropy, epsilon);
                rentropy = Math.Max(rentropy, epsilon);

                double cw = clipartPrior / centropy;
                double rw = (1 - clipartPrior) / rentropy;

                for (int c = 0; c < paletteHex.Count(); c++)
                {
                    CIELAB lab        = paletteLAB[c];
                    double chroma     = Math.Sqrt(lab.A * lab.A + lab.B * lab.B);
                    double saturation = chroma / Math.Max(Math.Sqrt(chroma * chroma + lab.L * lab.L), epsilon);

                    pcw[c, w] = Math.Max(saturation, saturationThresh) * (cw * pcw_clipart[c, w] + rw * pcw_regular[c, w]);
                }
            }

            //renormalize
            double[] memberSums = new double[category.members.Count()];
            for (int c = 0; c < paletteHex.Count(); c++)
            {
                for (int w = 0; w < category.members.Count(); w++)
                {
                    memberSums[w] += pcw[c, w];
                }
            }
            for (int c = 0; c < paletteHex.Count(); c++)
            {
                for (int w = 0; w < category.members.Count(); w++)
                {
                    pcw[c, w] /= memberSums[w];
                }
            }


            //now compute affinities from the combined probabilities
            double[,] affinities = new double[paletteHex.Count(), category.members.Count()];


            double[,] pwc = new double[category.members.Count(), paletteHex.Count()];

            //compute p(w|c)
            //p(w|c) = p(c|w)*p(w)/p(c)
            double colorZ = 0;

            double[] colorSums = new double[paletteHex.Count()];
            for (int c = 0; c < paletteHex.Count(); c++)
            {
                for (int w = 0; w < category.members.Count(); w++)
                {
                    colorSums[c] += pcw[c, w];
                    colorZ       += pcw[c, w];
                }
            }

            for (int c = 0; c < paletteHex.Count(); c++)
            {
                for (int w = 0; w < category.members.Count(); w++)
                {
                    pwc[w, c] = pcw[c, w] * (1.0 / category.members.Count()) / (Math.Max(colorSums[c], epsilon) / colorZ);
                }
            }

            double minScore = Double.PositiveInfinity;
            double maxScore = Double.NegativeInfinity;

            //balance with entropy H(w|c)
            for (int c = 0; c < paletteHex.Count(); c++)
            {
                double Hwc = 0;
                for (int w = 0; w < category.members.Count(); w++)
                {
                    if (pwc[w, c] > 0)
                    {
                        Hwc += pwc[w, c] * Math.Log(pwc[w, c]);
                    }
                }
                Hwc *= -1;
                System.Diagnostics.Debug.Assert(!double.IsNaN(Hwc));

                for (int w = 0; w < category.members.Count(); w++)
                {
                    affinities[c, w] = pcw[c, w] / Math.Max(Hwc, epsilon);
                    minScore         = Math.Min(minScore, affinities[c, w]);
                    maxScore         = Math.Max(maxScore, affinities[c, w]);
                }
            }
            System.Diagnostics.Debug.Assert(maxScore != minScore);

            //scale the affinities between 0 and 1s (easier to visualize)
            for (int c = 0; c < paletteHex.Count(); c++)
            {
                for (int w = 0; w < category.members.Count(); w++)
                {
                    affinities[c, w] = (affinities[c, w] - minScore) / (maxScore - minScore);
                    if (Double.IsNaN(affinities[c, w]))
                    {
                        throw new FormatException("Affinity is NaN! Affinity " + category.members[w] + " " + paletteHex[c]);
                    }
                }
            }

            Console.WriteLine("Done computing affinities");
            return(affinities);
        }
Exemplo n.º 27
0
        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);
        }