前段日子来意中人咨询了下分析图像主颜色的算法,我对这无异于块吧不曾什么深刻的钻,参考了有小代码,然后自己写了一个生粗略的有些器,现共享于大家。

微博剩余字数统计新浪官方算法的C#兑现,要的冤家请求保存。

      界面截图如下:

参数text是本文内容。

      图片 1

isOutOfRange用来判断文字是否溢起,以之来控制发送按钮的可用状态。

     
算法的原理非常粗略,就是统计出图像被各种颜色的布情况,然后取前N个颜色作为主成分。

 1 public static string GetContentLengthString(string text, out bool isOutOfRange)
 2 {
 3     text = text.Trim();
 4     text = Regex.Replace(text, "\r\n", "\n");
 5     int textLength = 0;
 6     if (text.Length > 0)
 7     {
 8         int min = 41, max = 140, urlLen = 20;
 9         var n = text;
10         var r = Regex.Matches(text, @"http://[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_$.+!*()/\\\,:;@&=?~#%]*)*");
11         var total = 0;
12         for (int m = 0, p = r.Count; m < p; m++)
13         {
14             var url = r[m].Value;
15             var byteLen = url.Length + Regex.Matches(url, @"[^\x00-\x80]").Count;
16             if (Regex.IsMatch(url, @"^(http://t.cn)"))
17             {
18                 continue;
19             }
20             else if (Regex.IsMatch(url, @"^(http:\/\/)+(weibo.com|weibo.cn)"))
21             {
22                 total += byteLen <= min ? byteLen : (byteLen <= max ? urlLen : (byteLen - max + urlLen));
23             }
24             else
25             {
26                 total += byteLen <= max ? urlLen : (byteLen - max + urlLen);
27             }
28             n = n.Replace(url, "");
29         }
30         textLength = (int)Math.Ceiling((total + n.Length + Regex.Matches(n, @"[^\x00-\x80]").Count) / 2.00d);
31     }
32 
33     int textRemainLength = 140 - textLength;
34     string template = string.Empty;
35     if (textRemainLength >= 0)
36     {
37         template = "还可以输入{0:N0}个字";
38         isOutOfRange = false;
39     }
40     else
41     {
42         template = "已经超过了{0:N0}个字";
43 
44         isOutOfRange = true;
45     }
46     return string.Format(template, Math.Abs(textRemainLength));
47 }

     
当然,实际上只要直白指向图像的每通道256个色阶进行统计,得到的结果或者是绝非意思之,所以一般还亟需先管256独色阶线性的隐射到重少之色阶范围。

履行效力

      主要的代码如下:

图片 2

    static unsafe class Statistics
    {

      
 //’*****************************************************************************************
      //’** 开发日期 : 2013-6-21
      //’** 作 者 : laviewpbt
      //’** 联系方式: 33184777
      //’** 修改日期 : 2013-6-21
      //’** 版 本 : Version 1.1.1
      //’** 转载请不要去上述信息
      //’****************************************************************************************

        [StructLayout(LayoutKind.Sequential)]
        public struct MajorColor : IComparable<MajorColor>
        {
            internal int Color;
            internal int Amount;
            public MajorColor(int Color, int Amount)
            {
                this.Color = Color;
                this.Amount = Amount;
            }
            public int CompareTo(MajorColor obj)
            {
                return this.Amount.CompareTo(obj.Amount);
            }
        }

        // http://www.coolphptools.com/color_extract
        // http://www.wookmark.com/image/268753/30-inspiring-examples-of-levitation-photography-inspirationfeed-com
        public static List<MajorColor> PrincipalColorAnalysis(Bitmap Bmp, int PCAAmount, int Delta = 24)
        {
            List<MajorColor> MC = new List<MajorColor>();

            int X, Y, Width, Height, Stride, Index, TotalColorAmount = 0;
            int HalfDelta;
            byte* Pointer, Scan0;
            BitmapData BmpData = Bmp.LockBits(new Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            Height = Bmp.Height; Width = Bmp.Width; Stride = BmpData.Stride; Scan0 = (byte*)BmpData.Scan0;

            int[] Table = new int[256 * 256 * 256];
            int[] NonZero = new int[Width * Height];
            int[] Map = new int[256];

            if (Delta > 2)
                HalfDelta = Delta / 2 - 1;
            else
                HalfDelta = 0;

            for (Y = 0; Y < 256; Y++)
            {
                Map[Y] = ((Y + HalfDelta) / Delta) * Delta;
                if (Map[Y] > 255) Map[Y] = 255;
            }
            for (Y = 0; Y < Height; Y++)
            {
                Pointer = Scan0 + Stride * Y;
                for (X = 0; X < Width; X++)
                {
                    Index = (Map[*Pointer] << 16) + (Map[*(Pointer + 1)] << 8) + Map[*(Pointer + 2)];
                    if (Table[Index] == 0)                  //      还没有出现过该颜色
                    {
                        NonZero[TotalColorAmount] = Index;  //      记录下有颜色的位置,同时也记录下了该颜色
                        TotalColorAmount++;                 //      颜色总数+1
                    }
                    Table[Index]++;                         //      对应的颜色数加1
                    Pointer += 3;                          //      移动到下一个像素
                }
            }
            MajorColor[] Result = new MajorColor[TotalColorAmount];
            for (Y = 0; Y < TotalColorAmount; Y++)
            {
                Result[Y].Amount = Table[NonZero[Y]];
                Result[Y].Color = NonZero[Y];
            }   
            Array.Sort(Result);                             // 系统自带的这个排序算法比一般自己写的都要快
            Array.Reverse(Result);  

            for (Y = 0; Y < PCAAmount; Y++)
                MC.Add(new MajorColor(Result[Y].Color, Result[Y].Amount));
            Bmp.UnlockBits(BmpData);
            GC.Collect();                                   // 立即释放掉分配的64MB的内存
            return MC;
        }
    }

   
 统计颜色就同片,其实自己一直以找相同种不畏不用占好挺内存,速度又快之算法,但是一直从未想到好方式。
上面的代码中凡是分配了64MB的内存来索引计数的,虽然于老粗之图像也需要这么老的内存占用量,但是本人透过对比发现,比用Dictionary之类的根据字典的统计方式还是使快多之。

   
 关于排序,我直接觉得好会写来比较系统再度快之算法,但是最后自或者选择了以上代码中的地利方法。在对Amount进行排序的以,Color的价值吗就随动了。

   
 在这种占用比较特别内存的代码中,我以为应该马上调用GC.Collect()释放掉内存。

   
 关于Delta的取值,似乎不绝好确定,这个只能说试验确定吧,一般拿走16-32里面比较合理。

   
 两个参考链接处也有一对比较好之算法的,不过其中的代码是PHP的,改写成C#的应该说还是发生必然的难度之,有趣味的恋人可以团结参考着上下吧。

   
 从个人的知来拘禁,我看这种颜色主成分分析 还得采取
类似于彩色转索引时
找最佳索引表时用底八叉树算法;也得用FCM或者KMEANS之类的聚类算法来促成。待时间充裕时自回来实际验证下。

     源代码下载地址:
http://files.cnblogs.com/Imageshop/ColorStatistics.rar

 

***************************作者:
laviewpbt   时间: 2013.4.07    联系QQ:  33184777
 转载请保留本行信息*************************