RunLengthEncoding与普通图像间的相互转换

有些大图像直接存储会很浪费磁盘空间,因此可以将普通图像转换成RunLengthEncoding编码,以压缩存储空间。将图像看成是一个二维数组,数组的每个元素代表图像的一个像素,其中存储了R(Red)、G(Green)、B(Blue)的具体值。RunLengthEncoding就是首先将图像的每行像素连接到一起,形成一个长的一维数组。然后将相邻的具有相同RGB值的像素合并到一块存储。例如下图是一个图像变成一维数组的样子(这里假设每个像素的RGB值相同):


将该图像采用RunLenthEncoding后变成下面的样子,其中前面的数字代表RGB的具体值,后边数字代表相同的像素个数:


这里RunLengthEncoding采用双向链表实现,遍历RunLenthEncoding采用iterator实现,我叫RunIterator,其中RunIterator只能采用RunLenthEncoding类中的Iterator方法实例化,只有Iterator方法能够调用RunIterator的构造方法,各个类的代码如下:

实例化RunIterator:

public RunIterator iterator() {
   
	  RunIterator iterator = new RunIterator(this);
	  return  iterator;
  }


双向链表类:

public class DlinkedRunNode {
	
	Run head;
	int length;
	
	public DlinkedRunNode(){
		head = new Run();
		length = 0;
	}
	public void addAfter(Run runNode){
		Run tail = this.head.getPrev();
		runNode.setNext(tail.getNext());
		tail.setNext(runNode);
		runNode.setPrev(tail);
		head.setPrev(runNode);
		length++;
	}
	public Run findFirst(){
		return head.getNext();
	}
	public Run getTail() {
		return head.getPrev();
	}
RunIterator类:

public class RunIterator implements Iterator {

  
  private RunLengthEncoding iterator;
  private Run index;

  RunIterator(RunLengthEncoding rLE) {
    iterator = rLE;
    index = iterator.getFirst();
  }


  public boolean hasNext() {
    // Replace the following line with your solution.
	  if(iterator.getEncoding().getNext(index) != iterator.getEncoding().findFirst()){
		  return true;
	  }
      return false;
  }

  public int[] next() {

	  int[] run = new int[4];
	  run[0] = index.getRunLength();
	  run[1] = index.getRed();
	  run[2] = index.getGreen();
	  run[3] = index.getBlue();
	  index = index.getNext();
      return run;
  }

 
  public void remove() {
    throw new UnsupportedOperationException();
  }
}


	public Run getNext(Run runNode) {
		return runNode.getNext();
	}
	

}



首先将普通图像转换成RunLengthEncoding,这里直接使用构造方法并将普通图像作为参数传入直接构造出RunLenthEncoding:

public RunLengthEncoding(PixImage image) {
	  int hIndex = 0;
	  int wIndex = 1;
	  width = image.getWidth();
	  height = image.getHeight();
	  encoding = new DlinkedRunNode();
	  Pixel firstPixel = image.getPixel(0, 0);
	  Run firstRun = new Run(firstPixel.getRed(), firstPixel.getGreen(), firstPixel.getBlue(), 1);
	  encoding.addAfter(firstRun);
	  while(hIndex < height){
		  while(wIndex < width){
			  Run tail = encoding.getTail();
			  Pixel pixel = image.getPixel(wIndex, hIndex);
			  if((tail.getRed() == pixel.getRed()) && 
				 (tail.getGreen() == pixel.getGreen()) && 
				 (tail.getBlue() == pixel.getBlue())){
				  int runLength = tail.getRunLength() + 1;
				  tail.setRunLength(runLength);
				  wIndex++;
			  }else{
				  Run newRun = new Run(pixel.getRed(), pixel.getGreen(), pixel.getBlue(), 1);
				  encoding.addAfter(newRun);
				  wIndex++;
			  }
		  }
		  wIndex = 0;
		  hIndex++;
	  }

  }


将RunLengthEncoding转换回普通图像,采用RunIterator遍历RunLenthEncoding,然后按照图像的长和宽构造图像,这里wIndex递增,采用%运送实现循环,当到每行最后一个元素后。hIndex加一:

 public PixImage toPixImage() {
  
	  int wIndex = 0;
	  int hIndex = 0;
	  int width = this.getWidth();
	  int height = this.getHeight();
	  PixImage image = new PixImage(width,height);
	  RunIterator iterator = this.iterator();
	  while(iterator.hasNext()){
		  int[] run = iterator.next();
		  for(int i = 0; i < run[0]; i++){
			  if((wIndex % width) == (width - 1)){
				  
				  if(hIndex < height){
					  toImage(wIndex, hIndex, width, image, run);
					  hIndex++;
				  }else{
					  break;
				  }
				  
			  }else{
				  toImage(wIndex, hIndex, width, image, run);
			  }
			  wIndex++;
		  }
	  }
    return image;
  }

private void toImage(int wIndex, int hIndex, int width, PixImage image,
		int[] run) {
	  short red = (short) run[1];
	  short green = (short) run[2];
	  short blue = (short) run[3];
	  image.setPixel(wIndex % width, hIndex, red, green, blue);
}




你可能感兴趣的:(java,算法)