English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

java简单实现八叉树图像处理代码示例

Passato un po' di tempo al lavoro, è la prima volta che scrivo un blog, non so proprio come scrivere, sperate di accontentarvi, se c'è qualcosa di non corretto, per favore correggetemi.

Di recente, nel lavoro, ho utilizzato una funzione di compressione delle immagini. Ho trovato alcuni strumenti, non ci sono molte scelte. Alla fine, ho scelto uno chiamato jdeli, ma l'efficienza è diventata un problema. Di fronte a questa situazione, non ho avuto altra scelta se non studiare il codice sorgente, ma ho scoperto che ho completamente perso la comprensione di un suo algoritmo di quantizzazione dei colori, quindi ho avuto l'idea di implementare un algoritmo di quantizzazione dei colori personalizzato.

Ho trovato alcune risorse, trovato tre algoritmi di gestione dei colori più comuni:

Algoritmo di colore popolare:

L'algoritmo specifico è, prima di tutto, contare le frequenze di apparizione di tutti i colori di un'immagine,选举出出现次数最多的256个颜色作为图片的调色板的颜色, poi esplorare nuovamente tutti i pixel dell'immagine, per ogni pixel trovare il colore più vicino nella tavolozza (qui uso il metodo della varianza), scrivere indietro nella immagine. La realizzazione di questo algoritmo è abbastanza semplice, ma la distorsione è molto grave, alcune informazioni di frequenza bassa, ma molto evidenti per l'occhio umano, perderanno informazioni. Ad esempio, i punti ad alta luminosità nell'immagine, a causa della bassa frequenza di apparizione, potrebbero non essere selezionati dall'algoritmo e persi.

Algoritmo di tagliamento mediano:

Questo algoritmo non l'ho studiato, chi desidera saperne di più può guardareQuesto articolo, ci sono tre descrizioni di algoritmi.

Albero esagonale

Questo algoritmo è quello che ho scelto alla fine, la sua idea principale è convertire i valori di colore RGB dell'immagine in una distribuzione binaria e distribuirli nell'albero esagonale, ad esempio: (173, 234, 144)

Convertito in binario diventa (10101101, 11101010, 10010000), prendiamo il primo bit di R, G, B e formiamo (111) come figlio del nodo radice, 111 come indice dell'array dei figli del nodo radice, ecc., fino all'ultimo bit, poi nella foglia del nodo si memorizza il valore della componente di colore e la frequenza di apparizione. Vedi la figura.

Tra le cose che mi hanno fatto dubitare c'è una gestione, ovvero la strategia di fusione dei nodi foglia, qui ho usato un metodo molto ingegnoso, ovvero trovare il nodo più profondo e poi unire, un po' semplice e violento, ci sono altri metodi migliori, anche per favore lasciate un messaggio. L'immagine è troppo grande per caricarla, metto direttamente il codice, il codice non è stato ristrutturato, spero che possiate farcela.

package com.gys.pngquant.octree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 
 *
 * @ClassName Nome della classe: Node
 * @Description Descrizione della funzione: 
 * <p>
 *   Implementazione dell'albero esagonale.
 * </p>
 * 
 *  16-12-2015 guoys ha creato questa funzione.
 *
 **********************************************************
 * </p>
 */
public class Node{
	private int depth = 0;
	// 为0时为root节点
	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的关系
	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;
	}
	// 返回节点原有的子节点数量
	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;
	}
	// 获取叶子节点的数量
	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);
			}
		}
	}
}

Povero me, solo due corsi universitari falliti di struttura dati. Il codice implementato è solo un albero di otto, quantificazione di un'immagine 1920*1080, il tempo di esecuzione è circa 450ms, se il livello è -2, circa 100ms.

Beh, questo è tutto, prima di scrivere, mi sembrava di avere molte cose da dire, ma quando l'ho fatto, non sapevo come esprimermi, vi prego di scusarmi.

Sommario

Questo è tutto il contenuto dell'esempio di implementazione semplice dell'albero di otto in Java per la gestione delle immagini, spero sia utile a tutti. Gli amici interessati possono continuare a consultare altre sezioni correlate di questo sito, e se c'è qualcosa di insufficiente, è sempre il benvenuto un commento. Grazie per il supporto degli amici a questo sito!

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, di proprietà del rispettivo autore. Il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato modificato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, ti preghiamo di inviare una email a notice#oldtoolbag.com (al momento dell'invio dell'email, sostituisci # con @) per segnalare e fornire prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.