English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
작업이 오래되었네요. 첫 번째 블로그를 써보니 어떻게 써야 할지 모르겠습니다. 여러분이 견딜 수 있기를 바랍니다. 잘못된 부분이 있다면 여러분의 지적을 기다립니다.
최근 일工作中에서 이미지 압축 기능이 사용되었습니다. 몇 가지 도구를 찾았지만, 매우 좋은 선택이 없었습니다. 결국 jdeli라는 것을 선택했습니다. 그러나 효율성 문제가 생겼습니다. 제가 무력해져서 그의 소스 코드를 연구했지만, 그의 단색화 퀼라이제이션 알고리즘에 관심을 가지게 되었습니다. 그러나 실망스럽게도 그가 무엇을 썼는지 전혀 이해하지 못했습니다. 그래서 나 자신이 단색화 색상 알고리즘을 구현하는 생각을 머릿속에 떠올렸습니다.
최근 몇 년 동안 일하면서 일부 자료를 찾아서 세 가지 매우 일반적인 색상 처리 알고리즘을 찾았습니다:
인기 색상 알고리즘:
정확한 알고리즘은, 이미지의 모든 색상이 발생하는 횟수를 통계를 먼저 수집한 후, 발생 횟수가 가장 많은256색상을 이미지 팔레트의 색상으로 사용하고, 그 다음으로 이미지의 모든 픽셀을 다시 순회하며, 각 픽셀에 가장 가까운 팔레트 색상을 찾아 이미지에 다시 씁니다(여기서 저는 분산 방식을 사용합니다). 이 알고리즘의 구현은 매우 간단하지만, 전형이 매우 심합니다. 이미지에서 발생 횟수가 낮은 정보는 이미지에서 사라질 수 있습니다. 예를 들어, 이미지에 존재하는 고밝기 점은 발생 횟수가 적기 때문에 알고리즘에서 선택되지 않을 수 있으며, 사라질 수 있습니다.
중앙切开 알고리즘:
저는 이 알고리즘을 연구하지 않았습니다. 알고 싶은 분은 다음을 보세요이 기사, 그里面有 세 가지 알고리즘의 소개가 있습니다.
오크타트 트리
이 알고리즘은 저가 마지막으로 선택한 알고리즘입니다. 주요 아이디어는 이미지의 RGB 색상 값을 이진으로 변환하여 오ク타트 트리에 분포시키는 것입니다. 예를 들어:(173,234,144)
이진으로 변환하면 (10101101,11101010,10010000),R, G, B의 첫 번째 자리를 꺼내어 (111),root 노드의 자식 노드로서111root 자식 노드 배열의 인덱스로 사용되며, 마지막 인덱스까지 이어져 마지막 레이블 노드에 이 색의 부분 값과 발생 횟수를 저장합니다. 자세히 이미지를 보세요.
저는 매우 의문스러운 처리 중 하나는 레이블 노드의 병합 전략입니다. 저는 가장 기본적인 방법을 사용했습니다. 그것은 가장 깊은 수준의 노드를 찾아서 병합하는 것이며, 간단하고 무서운 방법입니다. 다른 더 나은 방법도 많이 있으니 여러분의 의견을 기다립니다. 이미지가 너무 크기 때문에 업로드할 수 없습니다. 그래서 코드를 직접 올려놓았습니다. 코드는 재구조화되지 않았기 때문에 여러분이 견딜 수 있기를 바랍니다.
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> * octree 구현 * </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){ 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; } // 返回节点原有的子节点数量 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; } // 获取最深层次的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); } } return null; } // leaf 노드의 수를 가져오기 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 _속도){ if(깊이 != 0 || 이루트 부모 != null){ throw new UnsupportedOperationException(); } int 속도 = 7 + 1 - _속도; int r = _taget >> 16 & 0xFF; int g = _taget >> 8 & 0xFF; int b = _taget & 0xFF; Node proNode = this; for (int i=7;i>=속도;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); } } } }
대학 시절 유일하게 불합격한 데이터 구조. 코드는 오각수만 구현되었으며, 한1920*1080 이미지 정량화, 소요 시간大概是450ms, 계층-2그렇다면大概是100ms 정도.
그래, 이것이 그렇습니다. 쓰기 전에 자신이 많이 말하고 싶다고 생각했지만, 쓰면서 어떻게 말할지 몰랐습니다. 용서해 주세요.
결론
이것이 이 문서에서 java의 간단한 오각수 이미지 처리 코드 예제에 대한 모든 내용입니다. 이를 통해 도움이 되었기를 바랍니다. 관심이 있는 분은 이 사이트의 다른 관련 주제를 참고하시고, 불충분한 부분이 있으면 댓글을 남겨 주시기 바랍니다. 친구들의 이 사이트에 대한 지지에 감사합니다!
선언: 이 문서의 내용은 인터넷에서 가져왔으며, 저작권은 원저자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용입니다. 이 사이트는 소유권을 가지지 않으며, 인공적인 편집을 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 침해가 의심되는 내용이 있으면, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com에 (이메일 보내기 시, #을 @으로 변경하십시오) 신고를 하시고 관련 증거를 제공하시면, 사실이 확인되면 이 사이트는 즉시 저작권 침해 내용을 삭제할 것입니다.