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

界面截图如下:

算法的原理很简单,就是统计出图像中各种颜色的分布情况,然后取前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<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 = )
{
List<MajorColor> MC = new List<MajorColor>(); int X, Y, Width, Height, Stride, Index, TotalColorAmount = ;
int HalfDelta;
byte* Pointer, Scan0;
BitmapData BmpData = Bmp.LockBits(new Rectangle(, , 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[ * * ];
int[] NonZero = new int[Width * Height];
int[] Map = new int[]; if (Delta > )
HalfDelta = Delta / - ;
else
HalfDelta = ; for (Y = ; Y < ; Y++)
{
Map[Y] = ((Y + HalfDelta) / Delta) * Delta;
if (Map[Y] > ) Map[Y] = ;
}
for (Y = ; Y < Height; Y++)
{
Pointer = Scan0 + Stride * Y;
for (X = ; X < Width; X++)
{
Index = (Map[*Pointer] << ) + (Map[*(Pointer + )] << ) + Map[*(Pointer + )];
if (Table[Index] == ) // 还没有出现过该颜色
{
NonZero[TotalColorAmount] = Index; // 记录下有颜色的位置,同时也记录下了该颜色
TotalColorAmount++; // 颜色总数+1
}
Table[Index]++; // 对应的颜色数加1
Pointer += ; // 移动到下一个像素
}
}
MajorColor[] Result = new MajorColor[TotalColorAmount];
for (Y = ; Y < TotalColorAmount; Y++)
{
Result[Y].Amount = Table[NonZero[Y]];
Result[Y].Color = NonZero[Y];
}
Array.Sort(Result); // 系统自带的这个排序算法比一般自己写的都要快
Array.Reverse(Result); for (Y = ; 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  转载请保留本行信息*************************

一个简单的统计图像主颜色的算法(C#源代码)的更多相关文章

  1. 【opencv学习笔记五】一个简单程序:图像读取与显示

    今天我们来学习一个最简单的程序,即从文件读取图像并且创建窗口显示该图像. 目录 [imread]图像读取 [namedWindow]创建window窗口 [imshow]图像显示 [imwrite]图 ...

  2. 一个简单的统计问题(解决方案:Trie树)

    题目如图   输入几个不重复的单词和几个前缀,分别统计出单词中包含前缀的个数. Trie树   这个题目用到了 Trie 树.它在百度百科中的定义如下:在计算机科学中,Trie,又称字典树.单词查找树 ...

  3. 《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK THREE ...

  4. 关于apriori算法的一个简单的例子

    apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...

  5. 《Linux内核分析》第三周笔记 构造一个简单的Linux系统MenuOS

    构造一个简单的Linux系统MenuOS 一.linux内核源代码简介 三大法宝(存储程序计算机.函数调用堆栈.中断)和两把宝剑(中断上下文的切换:保存现场和恢复现场.进程上下文的切换) 1.在lin ...

  6. 《Linux内核分析》第三周学习小结 构造一个简单的Linux系统OS

    郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 第三周 构造一个简单的Linux系统Me ...

  7. WPF 一个简单的颜色选择器

    原文:WPF 一个简单的颜色选择器 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/details/8340999 ...

  8. CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能

    CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能 效果图 这是红宝书里的例子,在这个例子中,下述功能全部登场,因此这个例子可作为使用Compute Shader的典型 ...

  9. 从一个简单的寻路问题深入Q-learning

    这第一篇随笔实际上在我的科学网博客上是首发,我重新拿到博客园再发一次是希望以此作为我学习Q-learning的一个新的开始.以后这边主技术,科学网博客主理论.我也会将科学网那边技术类的文章转过来的.希 ...

随机推荐

  1. cron表达式详解[转]

    Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: Seconds Minutes Hours DayofMonth Month ...

  2. EC笔记,第二部分:10.让=返回指向*this的引用

    Effective C++ 学习笔记 10 让=返回指向*this的引用 Table of Contents 1. 原因 2. 建议:在没有充分理由标新立异前,最好的做法是遵从传统. –by SkyF ...

  3. Linux Cmd Tool 系列之—history & search command history

    History cmd is for list Bash's log of the historical cmd you typed 1. List last n commands history n ...

  4. C++构造函数中不能调用虚函数

    在构造函数中调用虚函数,并不会产生多态的效果,就跟普通函数一样. c++ primer 第四版中497页15.4.5构造函数和析构中的虚函数讲到,如果在构造函数或析构函数中调用虚函数,则运行的是为构造 ...

  5. MySQL中进行模糊搜索的一些问题

    在搜索数据库中的数据时,SQL 通配符可以替代一个或多个字符.SQL 通配符必须与 LIKE 运算符一起使用.在 SQL 中,可使用以下通配符:通配符 描述       % 替代一个或多个字符     ...

  6. arcgis for flex展示GIS基本功能

    1.地图框选搜索: 这是空间查询,在地图上框选一定的范围,然后搜索出在这个范围之内的所有信息,搜索到的详细信息在列表框显示出来 2.属性查询: 3.数据库展示: 4.绘制图形: 地图上绘制各种不同形状 ...

  7. 更改Visual Studio 2015 默认的语言设置

    Vs支持多种语言,但有可能创建项目时,默认的开发语言不是你需要的,比如:默认是Visual C++ 你可以通过"工具"----选项----导入和导出设置来修改. 引用: https ...

  8. C# 多線程&BackgroundWorker概念入門教程

    感謝以下各位作者的貢獻~ 百度經驗舉了個例子,很好理解BackgroundWorker的用途(主要是用來啟動後台線程,而不阻塞調用程式的運行),收藏一下  http://jingyan.baidu.c ...

  9. Android项目实战(二十五):Android studio 混淆+打包+验证是否成功

    前言: 单挑Android项目,最近即时通讯用到环信,集成sdk的时候 官方有一句 在 ProGuard 文件中加入以下 keep. -keep class com.hyphenate.** {*;} ...

  10. [转]Android应用程序框架思路整理

    一.一般Android应用程序架构(Book,购彩,Market). 普通的应用程序由于只需要用到Android的联网与显示的功能,所以应用程序大体上是呈现为UI(Activities)与网络(Net ...