Je travaille depuis un certain temps maintenant. J'écris un blog pour la première fois. Je ne sais pas comment l'écrire. Livrons-le. Veuillez me corriger si vous avez des mots incorrects.
Récemment, une fonction de compression d'image a été utilisée dans le travail. J'ai trouvé des outils, mais il n'y avait pas de bon choix. Enfin, j'ai choisi une personne du nom de Jdeli, mais l'efficacité est redevenue un problème. Je n'avais pas d'autre choix que d'étudier son code source, mais j'ai constaté que j'étais intéressé par l'un de ses algorithmes de quantification soustractifs. Cependant, j'étais gêné de ne pas comprendre ce qu'il écrivait du tout, j'ai donc eu l'idée de mettre en œuvre moi-même un algorithme de couleur quantitatif.
J'ai moi-même trouvé des informations et j'ai trouvé trois algorithmes de traitement de couleur plus couramment utilisés:
Algorithme de couleur populaire:
L'algorithme spécifique consiste à compter d'abord le nombre de fois que toutes les couleurs apparaissent dans une image, de sélectionner les 256 couleurs avec le plus d'occurrences comme la couleur de la palette de l'image, puis d'itérer à travers tous les pixels de l'image à nouveau, de trouver la couleur la plus proche de la palette pour chaque pixel (j'utilise la méthode de variance ici), et de l'écrire à l'image. La mise en œuvre de cet algorithme est relativement simple, mais la distorsion est relativement grave. Certaines images apparaissent à basse fréquence, mais l'effet visuel sur l'œil humain est assez évident. Les informations seront perdues. Par exemple, les taches de lubrification élevées dans l'image ne peuvent pas être sélectionnées par l'algorithme en raison du petit nombre d'occurrences et seront perdues.
Algorithme de découpage médian:
Je n'ai pas étudié cet algorithme. Ceux qui veulent savoir peuvent lire cet article, qui contient des présentations de trois algorithmes.
Octave
Cet algorithme est le dernier algorithme que j'ai choisi. Son idée principale est de convertir la valeur de couleur RVB de l'image en distribution binaire en Octree, par exemple: (173 234,144)
Pour se convertir en binaire est (10101101, 11101010, 10010000), retirez les premiers bits de r, g, b pour se former (111), et servir de nœuds enfants du nœud racine, où 111 est l'index du tableau des nœuds enfants racine, et ainsi de suite, jusqu'au dernier bit, puis stocker la valeur des composants de cette couleur et le nombre d'occurrences sur le nœud feuille. Voir l'image pour plus de détails.
L'une des choses dont je suis plus confus est la stratégie de fusion des nœuds de feuilles. La méthode la plus stupide que j'utilise ici est de trouver le nœud le plus profond, puis de fusionner. C'est un peu simple et brut. Il existe d'autres meilleures méthodes. S'il vous plaît laissez-moi un message. L'image est trop grande et ne peut pas être téléchargée, donc je télécharge simplement le code. Le code n'a pas été refactorisé, donc tout le monde peut le lire.
Package com.gys.pngquant.octree; import java.util.arraylist; importer java.util.hashmap; import java.util.list; importer java.util.map; / ** * * @classname Nom de la classe: node * @Description Fonction Description: * <p> Fonction de la classe des octètes * </p> * * * 2015-12-16 GuoYs Force Implémentation * * * * * 2015-12-16 GuoYs Fonction. * *************. PIEXLS = 0; carte privée <entier, liste <Node>> NIVEALMapping; // Stockez la relation entre la hiérarchie et le nœud public int getrgBValue () {int r = this.rnum / this.piexls; int g = this.gnum / this.piexls; int b = this.bnum / this.piexls; b);} public map <Integer, list <node>> getLevelMapping () {return niveaumapping;} public void atersetParam () {if (this.getparent () == null && this.depth == 0) {NIVLEAPPAPPE {NIVILEMAPPing.put (i, new ArrayList <Node> ());}}} public int getrnum () {return rnum;} public void setrnum (int rnum) {if (! Isleaf) {lancer un nouveau non soupportedOpperationException ();} setGnum (int gnum) {if (! isleaf) {lance un nouveau non soutenu par un usasperationxception ();} this.gnum = gnum;} public int getBnum () {return bnum;} public void setbnum (int bnum) {if (! isleaf) {lance une nouvelle intervention de l'Usportationxception ();} getPiexls () {return Piexls;} public void SetPiexls (int piexls) {if (! isleaf) {lance un nouveau non soutenu 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 (nœud child: this.children) {if (child == null) {continu; child.getGnum (); bnum + = child.getBnum (); pixel + = child.getpiexls (); i + = 1;} this.setrnum (rnum); this.setgnum (gnum); this.setbnum (bnum); this.setpiexls (pixel); this.childrers = null; renvoie i;} 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);}} retourne null;} // obtenir le numéro de NODES INTTR INTTR INTRICT getleafnum () {if (isLeaf) {return 1;} int i = 0; for (nœud child: this.children) {if (child! = null) {i + = child.getleafnum ();}} return i;} public void setdepth (int Depth) {this.depth = Defth;} public node GetPaRent () {webu public; setParent (nœud parent) {this.parent = parent;} nœud public [] getchildren () {return enfants;} noeud public getchild (int index) {return enfants [index];} public void SetChild (int index, nœud nœud) {enfants [index] = node;} public boolean isleaf () {return isleaf;} public void SetpIx (int r,) {return isleaf; 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. 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 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.levelming.get (child.getDepth (). child);} if (i == Speed) {child.setleaf (true);} if (child.isleaf ()) {child.setPixel (r, g, b); bris;} pronode = child;}} public static nœud build (inte [] [] matrix, int vitesse); pour (int [] row: matrix) {for (int cell: row) {root.add8bite2root (cellule, speed);}} return root;} public static byte [] MergeColors (nœud root, int maxcolors) {byte [] bytteRay = new Byte [maxColor * 3]; list <byte> résultat = newing = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = result = résultat> Résultat = Résultat = Résultat = résultat = root.getLeafNum (); try {while (Leafnum> maxcolors) {int megerleafNode = root.getDepestNode -). : result) {bytearray [i ++] = byte1;} return bytearray;} private static void fillarray (nœud 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 ())); result.add ((byte) (node.getbnum () / node.getpiexlS ())); else {for (node child: node.getchildren ()) {fillarray (enfant, résultat, offset);}}}}}Pauvre ma seule structure de données au collège. Le code implémente uniquement un OCTree. Il faut environ 450 ms pour quantifier une image 1920 * 1080, et si le niveau -2, il est d'environ 100 ms.
D'accord, c'est tout. Avant de l'écrire, je sentais que je voulais en dire beaucoup, mais je ne savais pas quoi dire quand je l'ai écrit. S'il te plaît, pardonne-moi.
Résumer
Ce qui précède est tout le contenu de cet article sur la simple implémentation de Java des exemples de code de traitement d'image OCTREE, j'espère que cela sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!