English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Ein kurzer Arbeitsschritt ist vergangen, das erste Mal, ein Blog zu schreiben, ich weiß nicht, wie ich es schreiben soll, also bitte um Verständnis, und bitte alle, mir zu korrigieren, wenn etwas Falsches gesagt wird.
In meiner jüngsten Arbeit wurde eine Funktion zur Bildkompression verwendet. Ich habe einige Werkzeuge gefunden, aber keine guten Auswahlmöglichkeiten. Am Ende habe ich mich für einen namens jdeli entschieden, aber die Effizienz war wieder ein Problem. Aus Not habe ich die Quelldatei untersucht und habe festgestellt, dass ich an einem Reduktion Quantisierungsalgorithmus interessiert war, aber der schämliche selbst habe ich nicht verstanden, was er geschrieben hat, also habe ich mir vorgenommen, einen eigenen Quantisierungsalgorithmus für Farben zu implementieren.
Ich habe einige Quellen durchsucht und drei ziemlich häufig verwendete Farbenverarbeitungsalgorithmen gefunden:
Popular Color Algorithmus:
Der spezifische Algorithmus besteht darin, zunächst die Häufigkeiten aller Farben in einem Bild zu zählen und die häufigste auszuwählen256Farben als Farbenpalette des Bildes auswählen und das Bild erneut durch alle Pixel durchgehen, um für jeden Pixel die nächstgelegene Farbe in der Palette zu finden (hier verwende ich die Varianzmethode) und zurückzuschreiben. Die Implementierung dieses Algorithmus ist relativ einfach, aber die Verzerrung ist relativ schwerwiegend, einige Informationen, die in Bildern auftreten und deren Häufigkeit gering ist, aber für das menschliche Auge visuell auffällig sind, werden verloren gehen. Zum Beispiel könnten helle Flecken im Bild, die nicht oft auftreten, möglicherweise nicht von dem Algorithmus ausgewählt und verloren gehen.
Median Splitting Algorithmus:
Dieser Algorithmus habe ich nicht erforscht, wenn jemand mehr darüber erfahren möchte, kann dies nachlesenDieser Artikel, darin sind drei Algorithmen vorgestellt.
Octree
Dieser Algorithmus ist der von mir letztendlich gewählte Algorithmus, sein Hauptgedanke ist es, die RGB-Farbwerte des Bildes in einen binären Verteilungsbereich des Octrees umzuwandeln, zum Beispiel: (173,234,144)
In binärer Form ist das (10101101,11101010,10010000), nimmt die ersten Stellen von R, G, B zusammen um (111) Als Unterknoten des Root-Knotens, darin111Als Index des Arrays der Root-Unterknoten, bis zum letzten, und speichert die Wertanteile und Häufigkeiten dieser Farben auf den Blattknoten. Siehe bitte das Diagramm.
Eine der Fragen, die mich besonders verwirrt haben, ist die Strategie zur Zusammenführung von Blattknoten. Der dämlichste Ansatz, den ich hier verwendet habe, besteht darin, den tiefsten Knoten zu finden und zu vereinen, was etwas einfach und brutal ist. Es gibt sicherlich bessere Methoden, und ich bitte alle, mir Feedback zu hinterlassen. Das Bild ist zu groß, um hochzuladen, also habe ich direkt den Code gepostet. Der Code wurde nicht neu strukturiert, also schaut ihn einfach durch.
package com.gys.pngquant.octree; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * * * @ClassName Klassenname: Node * @Description Funktionsbeschreibung: * <p> * Octree-Implementierung * </p> * * 2015-12-16 guoys erstellt diese Klasse mit der Funktion. * ********************************************************** * </p> */ public class Node{ private int depth = 0; // Wenn 0, ist es der Root-Knoten 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; // Speicherung der Beziehung zwischen Ebene und 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; } // rückgeben Sie die Anzahl der ursprünglichen Unter nodes des Knotens 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; } // erhalten Sie das Node der tiefsten Ebene 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=7i >= 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())); / 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); } } } }
arm ich, dass ich die Datenstruktur in der Universität nur zwei Mal durchfallen ließ. Der Code implementiert nur den Octree, aber für einen1920*1080 Bildquantifizierung, dauert etwa45ca. 0ms, wenn die Ebene-2könnte vielleicht sein10ca. 0ms.
Na gut, das ist's dann. Ich dachte, ich hätte viel zu sagen, aber beim Schreiben wusste ich nicht, wie ich anfangen sollte. Ich bitte um Verständnis.
Zusammenfassung
Das ist das gesamte Inhaltsverzeichnis dieses Artikels über die einfache Implementierung von Octree-Bildverarbeitungscode in Java. Ich hoffe, es hilft Ihnen weiter. Freunde, die daran interessiert sind, können andere verwandte Themen auf dieser Website weiter lesen. Jegliche Unzulänglichkeiten sind willkommen, um Kommentare zu hinterlassen. Vielen Dank für die Unterstützung der Freunde dieser Website!
Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem Urheber. Der Inhalt wurde von Internetnutzern selbstständig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie übernimmt auch keine rechtlichen Verantwortlichkeiten. Wenn Sie verdächtige urheberrechtliche Inhalte entdecken, sind Sie herzlich eingeladen, eine E-Mail an notice#w zu senden.3codebox.com (Bitte ersetzen Sie # durch @, wenn Sie eine Meldung senden, und fügen Sie relevante Beweise bei. Bei nachgewiesener Urheberrechtsverletzung wird diese Website den fraglichen Inhalt sofort löschen.)