博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个简单的统计图像主颜色的算法(C#源代码)
阅读量:6835 次
发布时间:2019-06-26

本文共 4225 字,大约阅读时间需要 14 分钟。

      前段日子有朋友咨询了下分析图像主颜色的算法,我对这一块也没有什么深入的研究,参考了一些小代码,然后自己写了一个很简单的小工具,现共享给大家。

      界面截图如下:

      

      算法的原理很简单,就是统计出图像中各种颜色的分布情况,然后取前N个颜色作为主成分。

      当然,实际上如果直接对图像的各通道256个色阶进行统计,得到的结果可能是没有意义的,所以一般都需要先把256个色阶线性的隐射到更少的色阶范围。

      主要的代码如下:

static unsafe class Statistics    {

        //'*****************************************************************************************

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

[StructLayout(LayoutKind.Sequential)]        public struct MajorColor : IComparable
{ 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
PrincipalColorAnalysis(Bitmap Bmp, int PCAAmount, int Delta = 24) { List
MC = new List
(); 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之类的聚类算法来实现。待时间充足时我回去实际验证下。

     源代码下载地址:

 

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

转载于:https://www.cnblogs.com/Imageshop/p/3183932.html

你可能感兴趣的文章
《SQL Server性能调优实战》知识点汇总
查看>>
JS 中文乱码
查看>>
原生JS实现音乐播放器!
查看>>
hive-安装MySQL(centos6.4)
查看>>
UVa 12100 Printer Queue (习题 5-7)
查看>>
windows下安装apache zookeeper
查看>>
第三周作业
查看>>
git pull --rebase
查看>>
linux下mysql的root密码忘记解决方
查看>>
protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用
查看>>
0-1背包问题
查看>>
系统的Drawable(二)-Selector
查看>>
CAS 界面根据不同的域名显示不同的界面
查看>>
Node js 嵌入式模板引擎 ejs 的使用
查看>>
vue 事件修饰符
查看>>
自定义的一个JDBC工具类
查看>>
数据类型(列类型)
查看>>
hihocoder [Offer收割]编程练习赛14
查看>>
mongodb_服务端安装及连接
查看>>
将baidu地图中的baidu logo去掉
查看>>