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

Ejemplo de código de procesamiento de imágenes octree implementado en Java

Después de un tiempo de trabajo, es la primera vez que escribo un blog, no sé cómo escribir, espero que todos lo vean como una aproximación, también espero que todos me corrijan si algo está mal.

Recientemente utilicé una función de compresión de imágenes en el trabajo. Busqué algunas herramientas, no tuve muchas opciones. Finalmente, elegí una llamada jdeli, pero la eficiencia volvió a ser un problema. Me vi obligado a investigar su código fuente, pero descubrí que no entendía nada de lo que había escrito, así que tuve la idea de implementar un algoritmo de cuantificación de colores por mi cuenta.

He encontrado algunos materiales, encontré tres algoritmos de procesamiento de color bastante comunes:

Algoritmo de color popular:

El algoritmo específico es, primero hacer un recuento de la frecuencia de aparición de todos los colores de una imagen, elegir el256Colores como colores del paleta de la imagen, luego nuevamente recorrer todos los píxeles de la imagen, para cada píxel encontrar el color más cercano en la paleta (aquí utilizo el método de varianza), escribirlo de vuelta en la imagen. La implementación de este algoritmo es bastante simple, pero la distorsión es bastante grave, algunas información que aparece con baja frecuencia en la imagen, pero que es bastante visible para el ojo humano, se perderá. Por ejemplo, los puntos de alta intensidad en la imagen, debido a que la frecuencia de aparición es baja, es posible que no puedan ser seleccionados por el algoritmo y se perderán.

Algoritmo de división mediana:

Este algoritmo no lo he investigado, los estudiantes que deseen saber más pueden verloEste artículo,hay una introducción a tres algoritmos.

Árbol octagonal

Este algoritmo es el que elegí finalmente, su idea principal es convertir los valores de color RGB de la imagen en una distribución binaria y distribuirla en un octree, por ejemplo:(173,234,144)

Convertido a binario es (10101101,11101010,10010000),tomar el primer bit de R, G, B para formar (111),como subnodo de root, entre111Como índice del array de subnodos de root, etc., hasta el último, y luego almacenar en los nodos hoja el valor de la componente de color y su frecuencia de aparición. Consulte la imagen específica.

Una de las cuestiones que me causó más confusión es la estrategia de fusión de nodos hoja, aquí utilicé el método más simple, es decir, encontrar el nodo más profundo en la jerarquía y fusionarlo, algo simple y brusco, también espero que otros me dejen comentarios. La imagen es demasiado grande para subir, así que subiré el código directamente, el código no ha sido重构, espero que todos lo vean como una aproximación.

package com.gys.pngquant.octree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 
 *
 * @ClassName Nombre de la clase:
 * @Description Descripción de la función: 
 * <p>
 *   Implementación de el octree
 * </p>
 * 
 *  2015-12-16  guoys crea esta clase de funcionalidad.
 *
 **********************************************************
 * </p>
 */
public class Node{
	private int depth = 0;
	// Cuando es 0, es el nodo raíz
	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;
	// Almacena la relación entre el nivel y el 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;
	}
	// devolver la cantidad original de subnodos del nodo
	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.hijos) {
			if(hijo == 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;
	}
	// obtener el nodo más profundo de la capa
	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;
	}
	// obtener el número de nodos hoja
	public int getLeafNum(){
		if(esHoja){
			return 1;
		}
		int i = 0;
		for (Node child : this.hijos) {
			if(child != null){
				i += child.getLeafNum();
			}
		}
		return i;
	}
	public void setDepth(int profundidad) {
		this.profundidad = profundidad;
	}
	public Node getParent() {
		return padre;
	}
	public void setParent(Node padre) {
		this.padre = padre;
	}
	public Node[] getChildren() {
		return hijos;
	}
	public Node getChild(int index){
		return hijos[index];
	}
	public void setChild(int index, Node nodo){
		hijos[index] = nodo;
	}
	public Boolean isLeaf() {
		return esHoja;
	}
	public void setPixel(int r, int g, int b){
		this.rNum = += r;
		this.gNum = += g;
		this.bNum = += b;
		this.puntos; += 1;
	}
	public void setLeaf(Boolean esHoja) {
		this.esHoja = esHoja;
	}
	public void add8Bite2Root(int _taget, int _velocidad){
		if(profundidad != 0 || this.padre != null){
			throw new UnsupportedOperationException();
		}
		int velocidad = 7 + 1 - _velocidad;
		int r = _taget >> 16 & 0xFF;
		int g = _taget >> 8 & 0xFF;
		int b = _taget & 0xFF;
		Node proNode = this;
		for (int i=7;i>=velocidad;i--}
			int item = ((r >> i & 1) << 2) + ((g >> i & 1) << 1) + (b >> i & 1);
			Node hijo = proNodo.getChild(item);
			if(hijo == null){
				hijo = new Node();
				hijo.setDepth(8-i);
				hijo.setParent(proNodo);
				hijo.afterSetParam();
				this.levelMapping.get(hijo.getDepth()).add(hijo);
				proNodo.setChild(item, hijo);
			}
			if(i == speed){
				hijo.setLeaf(true);
			}
			if(hijo.isLeaf()){
				hijo.setPixel(r, g, b);
				break;
			}
			proNodo = hijo;
		}
	}
	public static Node construir(int[][] matrix, int speed){
		Node root = new Node();
		root.afterSetParam();
		for (int[] row : matrix) {
			for (int cell : row) {
				root.agregar8Bite2Root(cell, speed);
			}
		}
		return root;
	}
	public static byte[] combinarColores(Node root, int maxColores){
		byte[] byteArray = new byte[maxColores * 3];
		List<byte> resultado = new ArrayList<byte>();
		int numeroHojas = root.getLeafNum();
		try{
			while(numeroHojas > maxColores){
				int combinarNodoHoja = root.getDepestNode().combinarNodoHoja();
				numeroHojas -= (combinarNodoHoja - 1);
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		llenarArreglo(root, resultado, 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())); / result.add((byte) (node.getPiexls()));
			result.add((byte) (node.getgNum())); / result.add((byte) (node.getPiexls()));
			result.add((byte) (node.getbNum())); / result.add((byte) (node.getPiexls()));
		}
			for (Node child : node.getChildren()) {
				fillArray(child, result, offset);
			}
		}
	}
}

Lástima que las dos únicas asignaturas falladas de mi universidad sean Estructuras de Datos.1920*1080 imágenes cuantitativas, el tiempo consumido sería aproximadamente45Aproximadamente 0ms, si el nivel-2Sería más o menos10Aproximadamente 0ms.

Bueno, así es este artículo, sentí que tenía mucho que decir antes de escribirlo, pero no sabía cómo decirlo, por favor disculpen.

Resumen

Esto es todo el contenido del ejemplo de código de implementación simple de octree para el procesamiento de imágenes en Java en este artículo. Espero que sea útil para todos. Los amigos interesados pueden continuar leyendo otros temas relacionados en este sitio, y bienvenidos a dejar comentarios si hay algo que no funcione bien. Agradecemos el apoyo de los amigos a este sitio!

Declaración: El contenido de este artículo se ha obtenido de la red, es propiedad del autor original, el contenido ha sido contribuido y subido por usuarios de Internet de manera autónoma, este sitio no posee los derechos de propiedad, no ha sido editado artificialmente y no asume responsabilidad por las responsabilidades legales relacionadas. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @ para denunciar, y proporcione evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción de derechos de autor.).

Te gustará