YUN
学习工作赚钱对象是正事
学习编程技术

C#获取图片主色调算法(聚类提取)

1.调用方法

  ColorThief colorThief = new ColorThief();
  var thiefColors = colorThief.GetColors(path, ignoreWhite: false);
  var thiefColor = colorThief.GetAveColor(thiefColors);

2.帮助类代码块

 public partial class ColorThief
 {
     public const int DefaultColorCount = 5;
     public const int DefaultQuality = 10;
     public const bool DefaultIgnoreWhite = true;
     public const int ColorDepth = 4;

     /// <summary>
     ///     Use the median cut algorithm to cluster similar colors.
     /// </summary>
     /// <param name="pixelArray">Pixel array.</param>
     /// <param name="colorCount">The color count.</param>
     /// <returns></returns>
     private CMap GetColorMap(byte[][] pixelArray, int colorCount)
     {
         // Send array to quantize function which clusters values using median
         // cut algorithm

         if (colorCount > 0)
         {
             --colorCount;
         }

         var cmap = Mmcq.Quantize(pixelArray, colorCount);
         return cmap;
     }

     private byte[][] ConvertPixels(byte[] pixels, int pixelCount, int quality, bool ignoreWhite)
     {
         var expectedDataLength = pixelCount * ColorDepth;
         if (expectedDataLength != pixels.Length)
         {
             throw new ArgumentException("(expectedDataLength = "
                                         + expectedDataLength + ") != (pixels.length = "
                                         + pixels.Length + ")");
         }

         // Store the RGB values in an array format suitable for quantize
         // function

         // numRegardedPixels must be rounded up to avoid an
         // ArrayIndexOutOfBoundsException if all pixels are good.

         var numRegardedPixels = (pixelCount + quality - 1) / quality;

         var numUsedPixels = 0;
         var pixelArray = new byte[numRegardedPixels][];

         for (var i = 0; i < pixelCount; i += quality)
         {
             var offset = i * ColorDepth;
             var b = pixels[offset];
             var g = pixels[offset + 1];
             var r = pixels[offset + 2];
             var a = pixels[offset + 3];

             // If pixel is mostly opaque and not white
             if (a >= 125 && !(ignoreWhite && r > 250 && g > 250 && b > 250))
             {
                 pixelArray[numUsedPixels] = new[] { r, g, b };
                 numUsedPixels++;
             }
         }

         // Remove unused pixels from the array
         var copy = new byte[numUsedPixels][];
         Array.Copy(pixelArray, copy, numUsedPixels);
         return copy;
     }
 }


 public partial class ColorThief
 {
     /// <summary>
     ///     Use the median cut algorithm to cluster similar colors and return the base color from the largest cluster.
     /// </summary>
     /// <param name="sourceImage">The source image.</param>
     /// <param name="quality">
     ///     1 is the highest quality settings. 10 is the default. There is
     ///     a trade-off between quality and speed. The bigger the number,
     ///     the faster a color will be returned but the greater the
     ///     likelihood that it will not be the visually most dominant color.
     /// </param>
     /// <param name="ignoreWhite">if set to <c>true</c> [ignore white].</param>
     /// <returns></returns>
     public QuantizedColor GetColor(string filePath, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite)
     {
         var palette = GetColors(filePath, quality, ignoreWhite);
         return GetAveColor(palette);
     }
     public QuantizedColor GetAveColor(List<QuantizedColor> colors)
     {
         var dominantColor = new QuantizedColor(new Color
         {
             A = Convert.ToByte(colors.Average(a => a.Color.A)),
             R = Convert.ToByte(colors.Average(a => a.Color.R)),
             G = Convert.ToByte(colors.Average(a => a.Color.G)),
             B = Convert.ToByte(colors.Average(a => a.Color.B))
         }, Convert.ToInt32(colors.Average(a => a.Population)));
         return dominantColor;
     }
     public List<QuantizedColor> GetColors(string filePath, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite)
     {
         //filePath= filePath.EncodePath();
         using Bitmap sourceImage = new Bitmap(filePath);
         var palette = GetPalette(sourceImage, 3, quality, ignoreWhite);
         return palette;
     }




     /// <summary>
     ///     Use the median cut algorithm to cluster similar colors.
     /// </summary>
     /// <param name="sourceImage">The source image.</param>
     /// <param name="colorCount">The color count. Value must be between 2 and 256</param>
     /// <param name="quality">
     ///     1 is the highest quality settings. 10 is the default. There is
     ///     a trade-off between quality and speed. The bigger the number,
     ///     the faster a color will be returned but the greater the
     ///     likelihood that it will not be the visually most dominant color.
     /// </param>
     /// <param name="ignoreWhite">if set to <c>true</c> [ignore white].</param>
     /// <returns></returns>
     /// <code>true</code>
     public List<QuantizedColor> GetPalette(Bitmap sourceImage, int colorCount = DefaultColorCount, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite)
     {
         var pixelArray = GetPixelsFast(sourceImage, quality, ignoreWhite);
         var cmap = GetColorMap(pixelArray, colorCount);
         if (cmap != null)
         {
             var colors = cmap.GeneratePalette();
             return colors;
         }
         return new List<QuantizedColor>();
     }

     public byte[] GetPixelValue(Bitmap bmp)
     {
         // Lock the bitmap's bits.  
         Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
         //System.Drawing.Imaging.BitmapData bmpData =bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,bmp.PixelFormat);

         System.Drawing.Imaging.BitmapData bmpData =
          bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
          System.Drawing.Imaging.PixelFormat.Format32bppArgb);

         // Get the address of the first line.
         IntPtr ptr = bmpData.Scan0;

         int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
         byte[] rgbValues = new byte[bytes];
         // Copy the RGB values into the array.
         System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
         System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);

         // Unlock the bits.
         bmp.UnlockBits(bmpData);
         return rgbValues;
     }


     private byte[] GetIntFromPixel(Bitmap bmp)
     {
         var intArray = GetPixelValue(bmp);
         return intArray;
     }

     private byte[][] GetPixelsFast(Bitmap sourceImage, int quality, bool ignoreWhite)
     {
         if (quality < 1)
         {
             quality = DefaultQuality;
         }

         var pixels = GetIntFromPixel(sourceImage);
         var pixelCount = sourceImage.Width * sourceImage.Height;
         return ConvertPixels(pixels, pixelCount, quality, ignoreWhite);
     }
 }

 internal static class Mmcq
 {
     public const int Sigbits = 5;
     public const int Rshift = 8 - Sigbits;
     public const int Mult = 1 << Rshift;
     public const int Histosize = 1 << (3 * Sigbits);
     public const int VboxLength = 1 << Sigbits;
     public const double FractByPopulation = 0.75;
     public const int MaxIterations = 1000;
     public const double WeightSaturation = 3d;
     public const double WeightLuma = 6d;
     public const double WeightPopulation = 1d;
     private static readonly VBoxComparer ComparatorProduct = new VBoxComparer();
     private static readonly VBoxCountComparer ComparatorCount = new VBoxCountComparer();

     public static int GetColorIndex(int r, int g, int b)
     {
         return (r << (2 * Sigbits)) + (g << Sigbits) + b;
     }

     /// <summary>
     ///     Gets the histo.
     /// </summary>
     /// <param name="pixels">The pixels.</param>
     /// <returns>Histo (1-d array, giving the number of pixels in each quantized region of color space), or null on error.</returns>
     private static int[] GetHisto(IEnumerable<byte[]> pixels)
     {
         var histo = new int[Histosize];

         foreach (var pixel in pixels)
         {
             var rval = pixel[0] >> Rshift;
             var gval = pixel[1] >> Rshift;
             var bval = pixel[2] >> Rshift;
             var index = GetColorIndex(rval, gval, bval);
             histo[index]++;
         }
         return histo;
     }

     private static VBox VboxFromPixels(IList<byte[]> pixels, int[] histo)
     {
         int rmin = 1000000, rmax = 0;
         int gmin = 1000000, gmax = 0;
         int bmin = 1000000, bmax = 0;

         // find min/max
         var numPixels = pixels.Count;
         for (var i = 0; i < numPixels; i++)
         {
             var pixel = pixels[i];
             var rval = pixel[0] >> Rshift;
             var gval = pixel[1] >> Rshift;
             var bval = pixel[2] >> Rshift;

             if (rval < rmin)
             {
                 rmin = rval;
             }
             else if (rval > rmax)
             {
                 rmax = rval;
             }

             if (gval < gmin)
             {
                 gmin = gval;
             }
             else if (gval > gmax)
             {
                 gmax = gval;
             }

             if (bval < bmin)
             {
                 bmin = bval;
             }
             else if (bval > bmax)
             {
                 bmax = bval;
             }
         }

         return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, histo);
     }

     private static VBox[] DoCut(char color, VBox vbox, IList<int> partialsum, IList<int> lookaheadsum, int total)
     {
         int vboxDim1;
         int vboxDim2;

         switch (color)
         {
             case 'r':
                 vboxDim1 = vbox.R1;
                 vboxDim2 = vbox.R2;
                 break;
             case 'g':
                 vboxDim1 = vbox.G1;
                 vboxDim2 = vbox.G2;
                 break;
             default:
                 vboxDim1 = vbox.B1;
                 vboxDim2 = vbox.B2;
                 break;
         }

         for (var i = vboxDim1; i <= vboxDim2; i++)
         {
             if (partialsum[i] > total / 2)
             {
                 var vbox1 = vbox.Clone();
                 var vbox2 = vbox.Clone();

                 var left = i - vboxDim1;
                 var right = vboxDim2 - i;

                 var d2 = left <= right
                     ? Math.Min(vboxDim2 - 1, Math.Abs(i + right / 2))
                     : Math.Max(vboxDim1, Math.Abs(Convert.ToInt32(i - 1 - left / 2.0)));

                 // avoid 0-count boxes
                 while (d2 < 0 || partialsum[d2] <= 0)
                 {
                     d2++;
                 }
                 var count2 = lookaheadsum[d2];
                 while (count2 == 0 && d2 > 0 && partialsum[d2 - 1] > 0)
                 {
                     count2 = lookaheadsum[--d2];
                 }

                 // set dimensions
                 switch (color)
                 {
                     case 'r':
                         vbox1.R2 = d2;
                         vbox2.R1 = d2 + 1;
                         break;
                     case 'g':
                         vbox1.G2 = d2;
                         vbox2.G1 = d2 + 1;
                         break;
                     default:
                         vbox1.B2 = d2;
                         vbox2.B1 = d2 + 1;
                         break;
                 }

                 return new[] { vbox1, vbox2 };
             }
         }

         throw new Exception("VBox can't be cut");
     }

     private static VBox[] MedianCutApply(IList<int> histo, VBox vbox)
     {
         if (vbox.Count(false) == 0)
         {
             return null;
         }
         if (vbox.Count(false) == 1)
         {
             return new[] { vbox.Clone(), null };
         }

         // only one pixel, no split

         var rw = vbox.R2 - vbox.R1 + 1;
         var gw = vbox.G2 - vbox.G1 + 1;
         var bw = vbox.B2 - vbox.B1 + 1;
         var maxw = Math.Max(Math.Max(rw, gw), bw);

         // Find the partial sum arrays along the selected axis.
         var total = 0;
         var partialsum = new int[VboxLength];
         // -1 = not set / 0 = 0
         for (var l = 0; l < partialsum.Length; l++)
         {
             partialsum[l] = -1;
         }

         // -1 = not set / 0 = 0
         var lookaheadsum = new int[VboxLength];
         for (var l = 0; l < lookaheadsum.Length; l++)
         {
             lookaheadsum[l] = -1;
         }

         int i, j, k, sum, index;

         if (maxw == rw)
         {
             for (i = vbox.R1; i <= vbox.R2; i++)
             {
                 sum = 0;
                 for (j = vbox.G1; j <= vbox.G2; j++)
                 {
                     for (k = vbox.B1; k <= vbox.B2; k++)
                     {
                         index = GetColorIndex(i, j, k);
                         sum += histo[index];
                     }
                 }
                 total += sum;
                 partialsum[i] = total;
             }
         }
         else if (maxw == gw)
         {
             for (i = vbox.G1; i <= vbox.G2; i++)
             {
                 sum = 0;
                 for (j = vbox.R1; j <= vbox.R2; j++)
                 {
                     for (k = vbox.B1; k <= vbox.B2; k++)
                     {
                         index = GetColorIndex(j, i, k);
                         sum += histo[index];
                     }
                 }
                 total += sum;
                 partialsum[i] = total;
             }
         }
         else /* maxw == bw */
         {
             for (i = vbox.B1; i <= vbox.B2; i++)
             {
                 sum = 0;
                 for (j = vbox.R1; j <= vbox.R2; j++)
                 {
                     for (k = vbox.G1; k <= vbox.G2; k++)
                     {
                         index = GetColorIndex(j, k, i);
                         sum += histo[index];
                     }
                 }
                 total += sum;
                 partialsum[i] = total;
             }
         }

         for (i = 0; i < VboxLength; i++)
         {
             if (partialsum[i] != -1)
             {
                 lookaheadsum[i] = total - partialsum[i];
             }
         }

         // determine the cut planes
         return maxw == rw ? DoCut('r', vbox, partialsum, lookaheadsum, total) : maxw == gw
                 ? DoCut('g', vbox, partialsum, lookaheadsum, total) : DoCut('b', vbox, partialsum, lookaheadsum, total);
     }

     /// <summary>
     ///     Inner function to do the iteration.
     /// </summary>
     /// <param name="lh">The lh.</param>
     /// <param name="comparator">The comparator.</param>
     /// <param name="target">The target.</param>
     /// <param name="histo">The histo.</param>
     /// <exception cref="System.Exception">vbox1 not defined; shouldn't happen!</exception>
     private static void Iter(List<VBox> lh, IComparer<VBox> comparator, int target, IList<int> histo)
     {
         var ncolors = 1;
         var niters = 0;

         while (niters < MaxIterations)
         {
             var vbox = lh[lh.Count - 1];
             if (vbox.Count(false) == 0)
             {
                 lh.Sort(comparator);
                 niters++;
                 continue;
             }

             lh.RemoveAt(lh.Count - 1);

             // do the cut
             var vboxes = MedianCutApply(histo, vbox);
             var vbox1 = vboxes[0];
             var vbox2 = vboxes[1];

             if (vbox1 == null)
             {
                 throw new Exception(
                     "vbox1 not defined; shouldn't happen!");
             }

             lh.Add(vbox1);
             if (vbox2 != null)
             {
                 lh.Add(vbox2);
                 ncolors++;
             }
             lh.Sort(comparator);

             if (ncolors >= target)
             {
                 return;
             }
             if (niters++ > MaxIterations)
             {
                 return;
             }
         }
     }

     public static CMap Quantize(byte[][] pixels, int maxcolors)
     {
         // short-circuit
         if (pixels.Length == 0 || maxcolors < 2 || maxcolors > 256)
         {
             return null;
         }

         var histo = GetHisto(pixels);

         // get the beginning vbox from the colors
         var vbox = VboxFromPixels(pixels, histo);
         var pq = new List<VBox> { vbox };

         // Round up to have the same behaviour as in JavaScript
         var target = (int)Math.Ceiling(FractByPopulation * maxcolors);

         // first set of colors, sorted by population
         Iter(pq, ComparatorCount, target, histo);

         // Re-sort by the product of pixel occupancy times the size in color
         // space.
         pq.Sort(ComparatorProduct);

         // next set - generate the median cuts using the (npix * vol) sorting.
         Iter(pq, ComparatorProduct, maxcolors - pq.Count, histo);

         // Reverse to put the highest elements first into the color map
         pq.Reverse();

         // calculate the actual colors
         var cmap = new CMap();
         foreach (var vb in pq)
         {
             cmap.Push(vb);
         }

         return cmap;
     }

     public static double CreateComparisonValue(double saturation, double targetSaturation, double luma, double targetLuma, int population, int highestPopulation)
     {
         return WeightedMean(InvertDiff(saturation, targetSaturation), WeightSaturation,
             InvertDiff(luma, targetLuma), WeightLuma,
             population / (double)highestPopulation, WeightPopulation);
     }

     private static double WeightedMean(params double[] values)
     {
         double sum = 0;
         double sumWeight = 0;

         for (var i = 0; i < values.Length; i += 2)
         {
             var value = values[i];
             var weight = values[i + 1];

             sum += value * weight;
             sumWeight += weight;
         }

         return sum / sumWeight;
     }

     private static double InvertDiff(double value, double targetValue)
     {
         return 1 - Math.Abs(value - targetValue);
     }
 }

 internal class CMap
 {
     private readonly List<VBox> vboxes = new List<VBox>();
     private List<QuantizedColor> palette;

     public void Push(VBox box)
     {
         palette = null;
         vboxes.Add(box);
     }

     public List<QuantizedColor> GeneratePalette()
     {
         if (palette == null)
         {
             palette = (from vBox in vboxes
                        let rgb = vBox.Avg(false)
                        let color = FromRgb(rgb[0], rgb[1], rgb[2])
                        select new QuantizedColor(color, vBox.Count(false))).ToList();
         }
         return palette;
     }

     public int Size()
     {
         return vboxes.Count;
     }

     public int[] Map(int[] color)
     {
         foreach (var vbox in vboxes.Where(vbox => vbox.Contains(color)))
         {
             return vbox.Avg(false);
         }
         return Nearest(color);
     }

     public int[] Nearest(int[] color)
     {
         var d1 = double.MaxValue;
         int[] pColor = null;

         foreach (var t in vboxes)
         {
             var vbColor = t.Avg(false);
             var d2 = Math.Sqrt(Math.Pow(color[0] - vbColor[0], 2)
                                + Math.Pow(color[1] - vbColor[1], 2)
                                + Math.Pow(color[2] - vbColor[2], 2));
             if (d2 < d1)
             {
                 d1 = d2;
                 pColor = vbColor;
             }
         }
         return pColor;
     }

     public VBox FindColor(double targetLuma, double minLuma, double maxLuma, double targetSaturation, double minSaturation, double maxSaturation)
     {
         VBox max = null;
         double maxValue = 0;
         var highestPopulation = vboxes.Select(p => p.Count(false)).Max();

         foreach (var swatch in vboxes)
         {
             var avg = swatch.Avg(false);
             var hsl = FromRgb(avg[0], avg[1], avg[2]).ToHsl();
             var sat = hsl.S;
             var luma = hsl.L;

             if (sat >= minSaturation && sat <= maxSaturation &&
                luma >= minLuma && luma <= maxLuma)
             {
                 var thisValue = Mmcq.CreateComparisonValue(sat, targetSaturation, luma, targetLuma,
                     swatch.Count(false), highestPopulation);

                 if (max == null || thisValue > maxValue)
                 {
                     max = swatch;
                     maxValue = thisValue;
                 }
             }
         }

         return max;
     }

     public Color FromRgb(int red, int green, int blue)
     {
         var color = new Color
         {
             A = 255,
             R = (byte)red,
             G = (byte)green,
             B = (byte)blue
         };

         return color;
     }
 }


 public class QuantizedColor
 {
     public QuantizedColor(Color color, int population)
     {
         Color = color;
         Population = population;
         IsDark = CalculateYiqLuma(color) < 128;
         //IsDark = CalculateYiqLuma(color) < 100;
     }

     public Color Color { get; private set; }
     public int Population { get; private set; }
     public bool IsDark { get; private set; }

     public int CalculateYiqLuma(Color color)
     {
         var val = Convert.ToInt32(Math.Round((299 * color.R + 587 * color.G + 114 * color.B) / 1000f));
         return val;
     }

     public HSV ToHSV()
     {
         return RGB.ToHSV(Color.R, Color.G, Color.B);
     }

 }

 public struct Color
 {
     /// <summary>
     ///     Get or Set the Alpha component value for sRGB.
     /// </summary>
     public byte A;

     /// <summary>
     ///     Get or Set the Blue component value for sRGB.
     /// </summary>
     public byte B;

     /// <summary>
     ///     Get or Set the Green component value for sRGB.
     /// </summary>
     public byte G;

     /// <summary>
     ///     Get or Set the Red component value for sRGB.
     /// </summary>
     public byte R;

     /// <summary>
     ///     Get HSL color.
     /// </summary>
     /// <returns></returns>
     public HslColor ToHsl()
     {
         const double toDouble = 1.0 / 255;
         var r = toDouble * R;
         var g = toDouble * G;
         var b = toDouble * B;
         var max = Math.Max(Math.Max(r, g), b);
         var min = Math.Min(Math.Min(r, g), b);
         var chroma = max - min;
         double h1;

         // ReSharper disable CompareOfFloatsByEqualityOperator
         if (chroma == 0)
         {
             h1 = 0;
         }
         else if (max == r)
         {
             h1 = (g - b) / chroma % 6;
         }
         else if (max == g)
         {
             h1 = 2 + (b - r) / chroma;
         }
         else //if (max == b)
         {
             h1 = 4 + (r - g) / chroma;
         }

         var lightness = 0.5 * (max - min);
         var saturation = chroma == 0 ? 0 : chroma / (1 - Math.Abs(2 * lightness - 1));
         HslColor ret;
         ret.H = 60 * h1;
         ret.S = saturation;
         ret.L = lightness;
         ret.A = toDouble * A;
         return ret;
         // ReSharper restore CompareOfFloatsByEqualityOperator
     }

     public string ToHexString()
     {
         return "#" + R.ToString("X2") + G.ToString("X2") + B.ToString("X2");
     }

     public string ToHexAlphaString()
     {
         return "#" + A.ToString("X2") + R.ToString("X2") + G.ToString("X2") + B.ToString("X2");
     }

     public override string ToString()
     {
         if (A == 255)
         {
             return ToHexString();
         }

         return ToHexAlphaString();
     }
 }


 public struct HslColor
 {
     /// <summary>
     ///     The Alpha/opacity in 0..1 range.
     /// </summary>
     public double A;

     /// <summary>
     ///     The Hue in 0..360 range.
     /// </summary>
     public double H;

     /// <summary>
     ///     The Lightness in 0..1 range.
     /// </summary>
     public double L;

     /// <summary>
     ///     The Saturation in 0..1 range.
     /// </summary>
     public double S;
 }


 internal class VBox
 {
     private readonly int[] histo;
     private int[] avg;
     public int B1;
     public int B2;
     private int? count;
     public int G1;
     public int G2;
     public int R1;
     public int R2;
     private int? volume;

     public VBox(int r1, int r2, int g1, int g2, int b1, int b2, int[] histo)
     {
         R1 = r1;
         R2 = r2;
         G1 = g1;
         G2 = g2;
         B1 = b1;
         B2 = b2;

         this.histo = histo;
     }

     public int Volume(bool force)
     {
         if (volume == null || force)
         {
             volume = (R2 - R1 + 1) * (G2 - G1 + 1) * (B2 - B1 + 1);
         }

         return volume.Value;
     }

     public int Count(bool force)
     {
         if (count == null || force)
         {
             var npix = 0;
             int i;

             for (i = R1; i <= R2; i++)
             {
                 int j;
                 for (j = G1; j <= G2; j++)
                 {
                     int k;
                     for (k = B1; k <= B2; k++)
                     {
                         var index = Mmcq.GetColorIndex(i, j, k);
                         npix += histo[index];
                     }
                 }
             }

             count = npix;
         }

         return count.Value;
     }

     public VBox Clone()
     {
         return new VBox(R1, R2, G1, G2, B1, B2, histo);
     }

     public int[] Avg(bool force)
     {
         if (avg == null || force)
         {
             var ntot = 0;

             var rsum = 0;
             var gsum = 0;
             var bsum = 0;

             int i;

             for (i = R1; i <= R2; i++)
             {
                 int j;
                 for (j = G1; j <= G2; j++)
                 {
                     int k;
                     for (k = B1; k <= B2; k++)
                     {
                         var histoindex = Mmcq.GetColorIndex(i, j, k);
                         var hval = histo[histoindex];
                         ntot += hval;
                         rsum += Convert.ToInt32((hval * (i + 0.5) * Mmcq.Mult));
                         gsum += Convert.ToInt32((hval * (j + 0.5) * Mmcq.Mult));
                         bsum += Convert.ToInt32((hval * (k + 0.5) * Mmcq.Mult));
                     }
                 }
             }

             if (ntot > 0)
             {
                 avg = new[]
                 {
                     Math.Abs(rsum / ntot), Math.Abs(gsum / ntot),
                     Math.Abs(bsum / ntot)
                 };
             }
             else
             {
                 avg = new[]
                 {
                     Math.Abs(Mmcq.Mult * (R1 + R2 + 1) / 2),
                     Math.Abs(Mmcq.Mult * (G1 + G2 + 1) / 2),
                     Math.Abs(Mmcq.Mult * (B1 + B2 + 1) / 2)
                 };
             }
         }

         return avg;
     }

     public bool Contains(int[] pixel)
     {
         var rval = pixel[0] >> Mmcq.Rshift;
         var gval = pixel[1] >> Mmcq.Rshift;
         var bval = pixel[2] >> Mmcq.Rshift;

         return rval >= R1 && rval <= R2 && gval >= G1 && gval <= G2 && bval >= B1 && bval <= B2;
     }
 }

 internal class VBoxCountComparer : IComparer<VBox>
 {
     public int Compare(VBox x, VBox y)
     {
         var a = x.Count(false);
         var b = y.Count(false);
         return a < b ? -1 : (a > b ? 1 : 0);
     }
 }

 internal class VBoxComparer : IComparer<VBox>
 {
     public int Compare(VBox x, VBox y)
     {
         var aCount = x.Count(false);
         var bCount = y.Count(false);
         var aVolume = x.Volume(false);
         var bVolume = y.Volume(false);

         // Otherwise sort by products
         var a = aCount * aVolume;
         var b = bCount * bVolume;
         return a < b ? -1 : (a > b ? 1 : 0);
     }
 }

发表回复

textsms
account_circle
email

学习编程技术

C#获取图片主色调算法(聚类提取)
1.调用方法 ColorThief colorThief = new ColorThief(); var thiefColors = colorThief.GetColors(path, ignoreWhite: false); var thiefColor = colorThief.GetAveColor(thiefCol…
扫描二维码继续阅读
2024-11-20