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

Exemplo de código de processamento de imagem octree simples em Java

一晃工作有段时间了,第一次写博客,有点不知道怎么写,大家将就着看吧,说的有什么不正确的也请大家指正。

最近工作中用到了一个图像压缩的功能。找了一些工具,没有太好的选择。最后选了一个叫jdeli的,奈何效率又成了问题。我迫于无奈就只能研究了下它的源码,却发现自己对它的一个减色量化算法起了兴趣,可是尴尬的自己完全不明白它写的什么,就起了一个自己实现一个量化颜色算法的念头。

自己找了一些资料,找到三个比较常用的颜色处理算法:

流行色算法:

具体的算法就是,先对一个图像的所有颜色出现的次数进行统计,选举出出现次数最多的256种颜色作为图片的调色板的颜色,然后再次遍历图片的所有像素,对每个像素找出调色板中最接近的颜色(这里我用的是方差的方式),写回到图片中。这个算法的实现比较简单,但是失真比较严重,图像中一些出现频率较低,但对人眼的视觉效挺明显的信息将丢失。比如,图像中存在的高亮度斑点,由于出现的次数少,很可能不能被算法选中,将被丢失。

中位切分算法:

这个算法我没有研究,想要了解的同学,可以看下这篇文章,里面有三种算法的介绍。

八叉树

这个算法就是我最后选用的算法,它的主要思想就是把图像的RGB颜色值转换成二进制分布到八叉树中,例如:(173,234,144)

转换成二进制就是(10101101,11101010,10010000),取R,G,B的第一位组成(111),como subnó do nó root,其中111Como índice do array de subnós root, e assim por diante, até o último, e armazenar na nó folha o valor da componente de cor e a ocorrência dessa cor. Veja a imagem para mais detalhes.

Um dos processos que me deixou mais intrigado é a estratégia de combinação de nós folhas, aqui usei o método mais tosco,那就是找到层次最深的节点,然后合并,有点简单粗暴,还有其他更好的方法,也请大家给我留言。图片太大上传不了了,直接上代码了,代码没有重构,大家凑合看吧。

package com.gys.pngquant.octree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 
 *
 * @ClassName Nome da classe: Node
 * @Description Descrição da função: 
 * <p>
 *   Implementação de árvore octal
 * </p>
 * 
 *  2015-12-16  guoys cria essa classe funcional.
 *
 **********************************************************
 * </p>
 */
public class Node{
	private int depth = 0;
	// Quando for zero, é o nó raiz
	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;
	// Armazenar a relação entre a camada e o 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;
	}
	// retornar o número original de subnós da nó
	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.filhos) {
			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;
	}
	// obter o node de nível mais profundo
	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;
	}
	// Obter o número de nós folha
	public int getLeafNum(){
		if(ehFolha){
			return 1;
		}
		int i = 0;
		for (Node child : this.filhos) {
			if(child != null){
				i += child.getLeafNum();
			}
		}
		return i;
	}
	public void setarProfundidade(int profundidade) {
		this.profundidade = profundidade;
	}
	public Node getPai() {
		return pai;
	}
	public void setarPai(Node pai) {
		this.pai = pai;
	}
	public Node[] getFilhos() {
		return filhos;
	}
	public Node getFilho(int index){
		return filhos[index];
	}
	public void setarFilho(int index, Node nó){
		filhos[index] = nó;
	}
	public Boolean ehFolha() {
		return ehFolha;
	}
	public void setarPixel(int r, int g, int b){
		this.rNum += r;
		this.gNum += g;
		this.bNum += b;
		this.piexls += 1;
	}
	public void setarFolha(Boolean ehFolha) {
		this.ehFolha = ehFolha;
	}
	public void adicionar8Bite2Raiz(int _taget, int _velocidade){
		if(profundidade != 0 || this.pai != null){
			throw new UnsupportedOperationException();
		}
		int velocidade = 7 + 1 - _velocidade;
		int r = _taget >> 16 & 0xFF;
		int g = _taget >> 8 & 0xFF;
		int b = _taget & 0xFF;
		Node proNode = this;
		for (int i=7;i>=velocidade;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()));
		}
			for (Node child : node.getChildren()) {
				fillArray(child, result, offset);
			}
		}
	}
}

Infelizmente, os dois únicos cursos que falhei na universidade foram ESTRUTURAS DE DADOS. O código implementado é apenas uma árvore octal, para um1920*108Quantificação de 0 imagens, demorando aproximadamente45Aproximadamente 0ms, se o nível-2Seria aproximadamente10Aproximadamente 0ms.

Bem, isso é tudo. Antes de escrever, sentia que tinha muito a dizer, mas quando comecei a escrever, não sabia o que dizer. Por favor, entenda.

Resumo

Isso é tudo sobre o exemplo de código de implementação simples de árvore octal de imagem em Java discutido neste artigo. Espero que ajude. Quem estiver interessado pode continuar a ler outros tópicos relacionados neste site. Se houver点什么不足之处,por favor, deixe um comentário. Agradecemos o apoio dos amigos para este site!

Declaração: O conteúdo deste artigo é extraído da Internet, pertence ao respectivo detentor dos direitos autorais, fornecido pelos usuários da Internet de forma voluntária e auto-publicado. Este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidades legais relacionadas. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar e forneça provas relevantes. Em caso de verificação, o site deletará imediatamente o conteúdo suspeito de violação de direitos autorais.)

Você também pode gostar