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

Exemple de code d'implémentation simple d'un arbre octal en Java

Je travaille depuis un certain temps, c'est ma première fois d'écrire un blog, je ne sais pas comment écrire, vous devrez vous contenter de cela, et si quelque chose ne va pas, je vous prie de bien vouloir me le faire savoir.

Récemment, j'ai utilisé une fonction de compression d'image dans mon travail. J'ai cherché quelques outils, sans trouver de bon choix. En fin de compte, j'ai choisi un nommé jdeli, mais malheureusement, l'efficacité est devenue un problème. sous la contrainte, je n'ai eu d'autre choix que d'étudier son code source, mais je me suis rendu compte que je ne comprenais pas ce qu'il avait écrit, donc j'ai eu l'idée de réaliser moi-même un algorithme de quantification des couleurs.

J'ai trouvé quelques documents, trouvant trois algorithmes de traitement des couleurs couramment utilisés :

Algorithme de couleur populaire :

L'algorithme spécifique consiste à effectuer d'abord un compte des occurrences de toutes les couleurs d'une image, à élire la plus fréquente256de couleurs en tant que couleurs du panneau de l'image, puis à nouveau parcourir tous les pixels de l'image, trouver la couleur la plus proche dans le panneau de couleurs pour chaque pixel (ici j'utilise la variance), et l'écrire dans l'image. L'implémentation de cet algorithme est assez simple, mais la déformation est assez sévère, certaines informations apparaissant fréquemment mais évidentes pour l'œil humain peuvent être perdues. Par exemple, les taches de haute luminosité dans l'image, en raison de leur faible fréquence d'apparition, peuvent ne pas être sélectionnées par l'algorithme et être perdues.

Algorithme de coupure médiane :

Je n'ai pas étudié cet algorithme, ceux qui veulent en savoir plus peuvent le consulterCet article,y compris une introduction à trois algorithmes.

Arbre octal

Cet algorithme est celui que j'ai finalement sélectionné, son idée principale consiste à convertir les valeurs de couleur RGB de l'image en une distribution binaire et à les distribuer dans un arbre octal, par exemple : (173,234,144)

En le convertissant en binaire, cela donne (10101101,11101010,10010000),en prenant la première position de R, G, B pour former (111),en tant que sous-nœud du nœud root, où111En tant qu'index du tableau de sous-nœuds de root, et ainsi de suite, jusqu'au dernier, puis stocker cette valeur de composante de couleur et son nombre d'apparitions sur les nœuds feuilles. Voir l'image pour plus de détails.

L'un des aspects que je trouve le plus mystérieux est la stratégie de fusion des nœuds feuilles, ici j'ai utilisé la méthode la plus primaire, à savoir trouver le nœud le plus profond et le fusionner, ce qui est assez brutal et simpliste. Il y a d'autres méthodes meilleures, je vous invite également à me laisser des commentaires. L'image est trop grande pour être téléchargée, je vais directement montrer le code, le code n'a pas été refondu, vous devrez vous contenter de cela.

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>
 *   八叉树实现
 * </p>
 * 
 *  2015-12-16  guoys 创建该类功能。
 *
 **********************************************************
 * </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){
			lancer une nouvelle UnsupportedOperationException();
		}
		this.rNum = rNum;
	}
	public int getgNum() {
		return gNum;
	}
	public void setgNum(int gNum) {
		if(!isLeaf){
			lancer une nouvelle UnsupportedOperationException();
		}
		this.gNum = gNum;
	}
	public int getbNum() {
		return bNum;
	}
	public void setbNum(int bNum) {
		if(!isLeaf){
			lancer une nouvelle UnsupportedOperationException();
		}
		this.bNum = bNum;
	}
	public int getPiexls() {
		return piexls;
	}
	public void setPiexls(int piexls) {
		if(!isLeaf){
			lancer une nouvelle UnsupportedOperationException();
		}
		this.piexls = piexls;
	}
	public int getDepth() {
		return depth;
	}
	// 返回节点原有的子节点数量
	public int mergerLeafNode(){
		if(this.isLeaf){
			retourner 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;
		retourner 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);
			}
		}
		retourner null;
	}
	// obtenir le nombre de nœuds feuilles
	public int getLeafNum(){
		if(isLeaf){
			retourner 1;
		}
		int i = 0;
		for (Node child : this.children) {
			if(child != null){
				i += child.getLeafNum();
			}
		}
		retourner i;
	}
	public void setDepth(int profondeur) {
		this.depth = profondeur;
	}
	public Node getParent() {
		retourner parent;
	}
	public void setParent(Node parent) {
		this.parent = parent;
	}
	public Node[] getChildren() {
		retourner children;
	}
	public Node getChild(int index){
		retourner children[index];
	}
	public void setChild(int index, Node node){
		children[index] = node;
	}
	public Boolean isLeaf() {
		retourner 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 ajouter8Bite2Root(int _taget, int _vitesse){
		if (profondeur != 0 || this.parent != null){
			lancer une nouvelle UnsupportedOperationException();
		}
		int vitesse = 7 + 1 - vitesse;
		int r = _taget >> 16 & 0xFF;
		int g = _taget >> 8 & 0xFF;
		int b = _taget & 0xFF;
		Node proNode = this;
		for (int i=;7i>=vitesse;--}
			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;
		}
		
			 / node.getPiexls()));
			 / node.getPiexls()));
			result.add((byte) (node.getbNum() / node.getPiexls()));
		}
			for (Node child : node.getChildren()) {
				fillArray(child, result, offset);
			}
		}
	}
}

Malheureusement, les deux seuls cours que j'ai ratés à l'université sont les structures de données. Le code implémente uniquement un arbre octal, pour un1920*1080 quantification d'image, le temps d'exécution est environ450 ms, si l'ordre des niveaux-2En parlant de10Environ 0 ms.

Bon, c'est tout pour cet article. Avant de l'écrire, je me sentais comme si j'avais beaucoup à dire, mais en réalité, je ne savais pas comment le dire. Veuillez m'excuser.

Résumé

Voici tous les contenus de cet article sur l'implémentation simple d'un arbre octal pour le traitement des images en Java, j'espère que cela vous sera utile. Si vous êtes intéressé, vous pouvez continuer à consulter d'autres sujets pertinents sur ce site. Si vous trouvez des insuffisances, n'hésitez pas à laisser un message. Merci de votre soutien à ce site !

Déclaration : le contenu de cet article est extrait du réseau, et les droits d'auteur appartiennent à leurs propriétaires respectifs. Le contenu est apporté par les utilisateurs d'Internet et téléversé par eux-mêmes. Le site Web ne possède pas de propriété, n'a pas été édité par l'homme et n'assume aucune responsabilité juridique. Si vous trouvez du contenu susceptible de violer les droits d'auteur, veuillez envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation et fournir des preuves. Une fois vérifié, le site supprimera immédiatement le contenu suspect de violation de droits d'auteur.)

Vous pourriez aussi aimer