java簡單實現(xiàn)八叉樹圖像處理代碼示例
一晃工作有段時間了,第一次寫博客,有點不知道怎么寫,大家將就著看吧,說的有什么不正確的也請大家指正。
最近工作中用到了一個圖像壓縮的功能。找了一些工具,沒有太好的選擇。最后選了一個叫jdeli的,奈何效率又成了問題。我迫于無奈就只能研究了下它的源碼,卻發(fā)現(xiàn)自己對它的一個減色量化算法起了興趣,可是尷尬的自己完全不明白它寫的什么,就起了一個自己實現(xiàn)一個量化顏色算法的念頭。
自己找了一些資料,找到三個比較常用的顏色處理算法:
流行色算法:
具體的算法就是,先對一個圖像的所有顏色出現(xiàn)的次數(shù)進行統(tǒng)計,選舉出出現(xiàn)次數(shù)最多的256個顏色作為圖片的調(diào)色板的顏色,然后再次遍歷圖片的所有像素,對每個像素找出調(diào)色板中的最接近的顏色(這里我用的是方差的方式),寫回到圖片中。這個算法的實現(xiàn)比較簡單,但是失真比較嚴重,圖像中一些出現(xiàn)頻率較低,但對人眼的視覺效挺明顯的信息將丟失。比如,圖像中存在的高亮度斑點,由于出現(xiàn)的次數(shù)少,很可能不能被算法選中,將被丟失。
中位切分算法:
這個算法我沒有研究,想要了解的同學(xué),可以看下這篇文章,里面有三種算法的介紹。
八叉樹
這個算法就是我最后選用的算法,它的主要思想就是把圖像的RGB顏色值轉(zhuǎn)成二進制分布到八叉樹中,例如:(173,234,144)
轉(zhuǎn)成二進制就是(10101101,11101010,10010000),將R,G,B的第一位取出來組成(111),作為root節(jié)點的子節(jié)點,其中111作為root子節(jié)點數(shù)組的索引,以此類推,一直到最后一位,然后在葉子節(jié)點上存放這個顏色的分量值以及其出現(xiàn)的次數(shù)。具體看圖。

其中我比較疑惑的有一個處理就是葉子節(jié)點的合并策略,這兒我用的最笨的一個方法,就是找到層次最深的節(jié)點,然后合并,有點簡單粗暴,有別的比較好的方法,也請大家給我留言。圖片太大上傳不了了,直接上代碼了,代碼沒有重構(gòu),大家湊合看吧。
package com.gys.pngquant.octree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @ClassName 類名:Node
* @Description 功能說明:
* <p>
* 八叉樹實現(xiàn)
* </p>
*
* 2015-12-16 guoys 創(chuàng)建該類功能。
*
**********************************************************
* </p>
*/
public class Node{
private int depth = 0;
// 為0時為root節(jié)點
private Node parent;
private Node[] children = new Node[8];
private Boolean isLeaf = false;
private int rNum = 0;
private int gNum = 0;
private int bNum = 0;
private int piexls = 0;
private Map<Integer, List<Node>> levelMapping;
// 存放層次和node的關(guān)系
public int getRGBValue(){
int r = this.rNum / this.piexls;
int g = this.gNum / this.piexls;
int b = this.bNum / this.piexls;
return (r << 16 | g << 8 | b);
}
public Map<Integer, List<Node>> getLevelMapping() {
return levelMapping;
}
public void afterSetParam(){
if(this.getParent() == null && this.depth == 0){
levelMapping = new HashMap<Integer, List<Node>>();
for (int i = 1; i <= 8; i++) {
levelMapping.put(i, new ArrayList<Node>());
}
}
}
public int getrNum() {
return rNum;
}
public void setrNum(int rNum) {
if(!isLeaf){
throw new UnsupportedOperationException();
}
this.rNum = rNum;
}
public int getgNum() {
return gNum;
}
public void setgNum(int gNum) {
if(!isLeaf){
throw new UnsupportedOperationException();
}
this.gNum = gNum;
}
public int getbNum() {
return bNum;
}
public void setbNum(int bNum) {
if(!isLeaf){
throw new UnsupportedOperationException();
}
this.bNum = bNum;
}
public int getPiexls() {
return piexls;
}
public void setPiexls(int piexls) {
if(!isLeaf){
throw new UnsupportedOperationException();
}
this.piexls = piexls;
}
public int getDepth() {
return depth;
}
// 返回節(jié)點原有的子節(jié)點數(shù)量
public int mergerLeafNode(){
if(this.isLeaf){
return 1;
}
this.setLeaf(true);
int rNum = 0;
int gNum = 0;
int bNum = 0;
int pixel = 0;
int i = 0;
for (Node child : this.children) {
if(child == null){
continue;
}
rNum += child.getrNum();
gNum += child.getgNum();
bNum += child.getbNum();
pixel += child.getPiexls();
i += 1;
}
this.setrNum(rNum);
this.setgNum(gNum);
this.setbNum(bNum);
this.setPiexls(pixel);
this.children = null;
return i;
}
// 獲取最深層次的node
public Node getDepestNode(){
for (int i = 7; i > 0; i--) {
List<Node> levelList = this.levelMapping.get(i);
if(!levelList.isEmpty()){
return levelList.remove(levelList.size() - 1);
}
}
return null;
}
// 獲取葉子節(jié)點的數(shù)量
public int getLeafNum(){
if(isLeaf){
return 1;
}
int i = 0;
for (Node child : this.children) {
if(child != null){
i += child.getLeafNum();
}
}
return i;
}
public void setDepth(int depth) {
this.depth = depth;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public Node[] getChildren() {
return children;
}
public Node getChild(int index){
return children[index];
}
public void setChild(int index, Node node){
children[index] = node;
}
public Boolean isLeaf() {
return isLeaf;
}
public void setPixel(int r, int g, int b){
this.rNum += r;
this.gNum += g;
this.bNum += b;
this.piexls += 1;
}
public void setLeaf(Boolean isLeaf) {
this.isLeaf = isLeaf;
}
public void add8Bite2Root(int _taget, int _speed){
if(depth != 0 || this.parent != null){
throw new UnsupportedOperationException();
}
int speed = 7 + 1 - _speed;
int r = _taget >> 16 & 0xFF;
int g = _taget >> 8 & 0xFF;
int b = _taget & 0xFF;
Node proNode = this;
for (int i=7;i>=speed;i--){
int item = ((r >> i & 1) << 2) + ((g >> i & 1) << 1) + (b >> i & 1);
Node child = proNode.getChild(item);
if(child == null){
child = new Node();
child.setDepth(8-i);
child.setParent(proNode);
child.afterSetParam();
this.levelMapping.get(child.getDepth()).add(child);
proNode.setChild(item, child);
}
if(i == speed){
child.setLeaf(true);
}
if(child.isLeaf()){
child.setPixel(r, g, b);
break;
}
proNode = child;
}
}
public static Node build(int[][] matrix, int speed){
Node root = new Node();
root.afterSetParam();
for (int[] row : matrix) {
for (int cell : row) {
root.add8Bite2Root(cell, speed);
}
}
return root;
}
public static byte[] mergeColors(Node root, int maxColors){
byte[] byteArray = new byte[maxColors * 3];
List<byte> result = new ArrayList<byte>();
int leafNum = root.getLeafNum();
try{
while(leafNum > maxColors){
int mergerLeafNode = root.getDepestNode().mergerLeafNode();
leafNum -= (mergerLeafNode - 1);
}
}
catch(Exception e){
e.printStackTrace();
}
fillArray(root, result, 0);
int i = 0;
for (byte byte1 : result) {
byteArray[i++] = byte1;
}
return byteArray;
}
private static void fillArray(Node node, List<byte> result, int offset){
if(node == null){
return;
}
if(node.isLeaf()){
result.add((byte) (node.getrNum() / node.getPiexls()));
result.add((byte) (node.getgNum() / node.getPiexls()));
result.add((byte) (node.getbNum() / node.getPiexls()));
} else{
for (Node child : node.getChildren()) {
fillArray(child, result, offset);
}
}
}
}
可憐我大學(xué)唯二掛的數(shù)據(jù)結(jié)構(gòu)。代碼實現(xiàn)的只是八叉樹,對一個1920*1080圖片量化,耗時大概是450ms,如果層次-2的話大概是100ms左右。
好吧,這篇就這樣吧,本來寫之前,感覺自己想說的挺多的,結(jié)果寫的時候就不知道怎么說了,大家見諒。
總結(jié)
以上就是本文關(guān)于java簡單實現(xiàn)八叉樹圖像處理代碼示例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
Selenium Webdriver實現(xiàn)截圖功能的示例
今天小編就為大家分享一篇Selenium Webdriver實現(xiàn)截圖功能的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05
java中form以post、get方式提交數(shù)據(jù)中文亂碼問題總結(jié)
這篇文章主要介紹了java中form以post、get方式提交數(shù)據(jù)中文亂碼問題總結(jié),需要的朋友可以參考下2014-10-10

