文档章节

一个简单的统计图像主颜色的算法(C#源代码)

abcijkxyz
 abcijkxyz
发布于 2016/11/22 16:38
字数 956
阅读 10
收藏 0

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

      界面截图如下:

      

      算法的原理很简单,就是统计出图像中各种颜色的分布情况,然后取前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 = 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  转载请保留本行信息*************************

本文转载自:http://www.cnblogs.com/Imageshop/p/3183932.html

共有 人打赏支持
abcijkxyz
粉丝 64
博文 6196
码字总数 1876
作品 0
深圳
项目经理
Win8 Metro(C#)数字图像处理--2.35图像肤色检测算法

原文:Win8 Metro(C#)数字图像处理--2.35图像肤色检测算法  [函数名称] 肤色检测函数SkinDetectProcess(WriteableBitmap src) [算法说明] 这个算法是一篇学术论文算法的实现,论文名字为“...

杰克.陈
03/13
0
0
C# WinForm开发系列 - GDI+

UI(User Interface)编程在整个项目开发过程中是个颇为重要的环节,任何好的解决方案若没有良好的用户界面呈现给最终用户,那么就算包含了最先进的技术也不能算是好程序。UI编程体现在两个方...

长征2号
2017/11/14
0
0
[Beautifulzzzz的博客目录] 快速索引点这儿O(∩_∩)O~~,红色标记的是不错的(⊙o⊙)哦~

3D相关开发 [direct-X] 1、direct-X最小框架 [OpenGL] 1、环境搭建及最小系统 [OpenGL] 2、企业版VC6.0自带的Win32-OpenGL工程浅析 51单片机 [51单片机] 1602液晶显示控制代码 [51单片机] 1...

史迪奇2号
2017/08/01
0
0
.NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍

.NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍 阅读目录 Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来。因为AForge.NET更注重与一些底层和广度,而A...

老朱第八
2017/11/11
0
0
【OpenCV】扫描图像、查找表、计时

扫描图像   扫描图像有四种方法:C指针访问方法、迭代器方法、即时地址计算方法、LUT函数。实现方法及用时比较可参考下方代码。 参考链接:https://docs.opencv.org/master/db/da5/tutoria...

u013165921
2017/10/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

一个可能的NEO链上安全随机数解决方案

0x00 困境 链上安全随机数生成应该算是一个比较蛋疼的问题,哪怕你的系统再牛逼,合约程序困在小小的虚拟机里,哪怕天大的本事也施展不开。 更悲催的是,交易执行的时候,是在每一个节点都执...

暖冰
今天
1
0
【大福利】极客时间专栏返现二维码大汇总

我已经购买了如下专栏,大家通过我的二维码你可以获得一定额度的返现! 然后,再给大家来个福利,只要你通过我的二维码购买,并且关注了【飞鱼说编程】公众号,可以加我微信或者私聊我,我再...

飞鱼说编程
今天
1
0
Spring5对比Spring3.2源码之容器的基本实现

最近看了《Spring源码深度解析》,该书是基于Spring3.2版本的,其中关于第二章容器的基本实现部分,目前spring5的实现方式已有较大改变。 Spring3.2的实现: public void testSimpleLoad(){...

Ilike_Java
今天
1
0
【王阳明心学语录】-001

1.“破山中贼易,破心中贼难。” 2.“夫万事万物之理不外于吾心。” 3.“心即理也。”“心外无理,心外无物,心外无事。” 4.“人心之得其正者即道心;道心之失其正者即人心。” 5.“无...

卯金刀GG
今天
2
0
OSChina 周三乱弹 —— 我们无法成为野兽

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ _刚刚好: 霸王洗发水这波很骚 手机党少年们想听歌,请使劲儿戳(这里) hahahahahahh @嘻酱:居然忘了喝水。 让你喝可乐的话, 你准忘不了...

小小编辑
今天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部