一晃工作有段时间了,第一次写博客,有点不知道怎么写,大家将就着看吧,说的有什么不正确的也请大家指正。
最近工作中用到了一个图像压缩的功能。找了一些工具,没有太好的选择。最后选了一个叫jdeli的,奈何效率又成了问题。我迫于无奈就只能研究了下它的源码,却发现自己对它的一个减色量化算法起了兴趣,可是尴尬的自己完全不明白它写的什么,就起了一个自己实现一个量化颜色算法的念头。
自己找了一些资料,找到三个比较常用的颜色处理算法:
流行色算法:
具体的算法就是,先对一个图像的所有颜色出现的次数进行统计,选举出出现次数最多的256个颜色作为图片的调色板的颜色,然后再次遍历图片的所有像素,对每个像素找出调色板中的最接近的颜色(这里我用的是方差的方式),写回到图片中。这个算法的实现比较简单,但是失真比较严重,图像中一些出现频率较低,但对人眼的视觉效挺明显的信息将丢失。比如,图像中存在的高亮度斑点,由于出现的次数少,很可能不能被算法选中,将被丢失。
中位切分算法:
这个算法我没有研究,想要了解的同学,可以看下这篇文章,里面有三种算法的介绍。
八叉树
这个算法就是我最后选用的算法,它的主要思想就是把图像的RGB颜色值转成二进制分布到八叉树中,例如:(173234144)
转成二进制就是(10101101、10101101和10101101),将R, G, B的第一位取出来组成(111),作为根节点的子节点,其111年中作为根子节点数组的索引,以此类推,一直到最后一位,然后在叶子节点上存放这个颜色的分量值以及其出现的次数。具体看图。
其中我比较疑惑的有一个处理就是叶子节点的合并策略,这儿我用的最笨的一个方法,就是找到层次最深的节点,然后合,并有点简单粗暴,有别的比较好的方法,也请大家给我留的言。图片太大上传不了的了,直接上代码了,代码没有重构,大家凑合看吧。
包com.gys.pngquant.octree; 进口java.util.ArrayList; 进口java.util.HashMap; 进口并不知道; 进口java.util.Map;/* * * * * @ClassName类名:节点 * @Description功能说明: * & lt; p> *八叉树实现 * & lt;/p> * * 2015-12-16 guoys创建该类功能。 * ********************************************************** * & lt;/p> */公共类节点{ 私人int深度=0;//为0时为根节点 私人父节点; 私人节点[]儿童=新节点[8]; 私人布尔isLeaf=false; 私人int rNum=0; 私人int gNum=0; 私人int bNum=0; 私人int piexls=0; 私人Map<整数,List比;levelMapping;//存放层次和节点的关系 公共int getRGBValue () { int r=Num/this.piexls; int g=Num/this.piexls; int b=Num/this.piexls; 返回(r & lt; & lt;16 | g & lt; & lt;8 | b); } 公共Map<整数,List 比;getLevelMapping () { 返回levelMapping; } 公共空间afterSetParam () { 如果(this.getParent()==零,,this.depth==0) { levelMapping=new HashMap<整数,List 在(); for (int i=1;我& lt;=8;我+ +){ levelMapping。把(我,新的ArrayList ()); } } } 公共int getrNum () { 返回rNum; } 公共空间setrNum (int rNum) { 如果(! isLeaf) { 抛出UnsupportedOperationException()方式; } 这一点。rNum=rNum; } 公共int getgNum () { 返回gNum; } 公共空间setgNum (int gNum) { 如果(! isLeaf) { 抛出UnsupportedOperationException()方式; } 这一点。gNum=gNum; } 公共int getbNum () { 返回bNum; } 公共空间setbNum (int bNum) { 如果(! isLeaf) { 抛出UnsupportedOperationException()方式; } 这一点。bNum=bNum; } 公共int getPiexls () { 返回piexls; } 公共空间setPiexls (int piexls) { 如果(! isLeaf) { 抛出UnsupportedOperationException()方式; } 这一点。piexls=piexls; } 公共int getDepth () { 返回深度; }//返回节点原有的子节点数量 公共int mergerLeafNode () { 如果(this.isLeaf) { 返回1; } this.setLeaf(真正的); int rNum=0; int gNum=0; int bNum=0; int像素=0; int i=0; (节点的孩子:this.children) { 如果孩子==null) { 继续; } rNum +=child.getrNum (); gNum +=child.getgNum (); bNum +=child.getbNum (); 像素+=child.getPiexls (); 我+=1; } this.setrNum (rNum); this.setgNum (gNum); this.setbNum (bNum); this.setPiexls(像素); 这一点。孩子=零; 返回我; }//获取最深层次的节点 公共节点getDepestNode () { for (int i=7;我在;0;我(){ List java简单实现八叉树图像处理代码示例