Coursera普林斯顿大学算法下Week2:Seam Carving

10 篇文章 0 订阅
9 篇文章 0 订阅

任务链接:http://coursera.cs.princeton.edu/algs4/assignments/seam.html

本周任务没做出来,只求出了能量。

本周任务难度的话,主要是数组、像素下标问题,感觉用起来不是很舒服。再一个就是求最小能量路径问题。本文在求最小能量路径的时候对于有些图可以准确的求出,有些就出错,找了半天也没找到原因,把有问题的代码贴出来,后续有时间再接着做。也找了篇正确的,贴出来。

我的有问题的代码。


import edu.princeton.cs.algs4.Picture;

public class SeamCarver {
	private int height; // 高度
	private int width; // 宽度
	private int[][] pictureColor; // 用于存放像素点的颜色
	private double[][] energy;  // 像素节点能量
	
	// 基于给定图片创建SealCavor对象
	public SeamCarver(Picture picture)      
	{
		if (picture == null) 
			throw new java.lang.IllegalArgumentException("the picture is null");
		
		height = picture.height();
		width = picture.width();
		
		pictureColor = new int[width][height];
		energy = new double[width][height];
		
		// 像素 
		for (int i = 0; i < width; i++)  // 行
			for (int j = 0; j < height; j++)  // 列
				pictureColor[i][j] = picture.get(i, j).getRGB();
		// 能量
		renewEnergy();
	
	}
	
	// 计算列X和行Y像素的能量
	private double calculattionEnery(int x, int y) 
	{
		// 下标超出范围
		if (x < 0 || x >= width() || y < 0 || y >= height())
			throw new java.lang.IllegalArgumentException("the row or col is beyond index");
		
		// 四周的像素能量值为1000.0
		if (x == 0 || x == width() - 1 || y == 0 || y == height() - 1)
			return 1000.0;
		
		// 计算内部像素值
		int upRGB = pictureColor[x][y -1];      // 上
		int downRGB = pictureColor[x][y + 1];   // 下
		int leftRGB = pictureColor[x - 1][y];   // 左
		int rightRGB = pictureColor[x + 1][y];  // 右
		
		int rx = Math.abs(((rightRGB >> 16) & 0xFF) - ((leftRGB >> 16) & 0xFF));
		int gx = Math.abs(((rightRGB >> 8) & 0xFF) - ((leftRGB >> 8) & 0xFF));
		int bx = Math.abs(((rightRGB >> 0) & 0xFF) - ((leftRGB >> 0) & 0xFF));
		
		int ry = Math.abs(((downRGB >> 16) & 0xFF) - ((upRGB >> 16) & 0xFF));
		int gy = Math.abs(((downRGB >> 8) & 0xFF) - ((upRGB >> 8) & 0xFF));
		int by = Math.abs(((downRGB >> 0) & 0xFF) - ((upRGB >> 0) & 0xFF));
		
		double ener = Math.sqrt(rx * rx + gx * gx + bx * bx + ry * ry + gy * gy + by * by);
		//System.out.println(ener);
		return ener;
		
	}
	
	// 当前图片
	public Picture picture()
	{
		Picture picture = new Picture(width(), height()); // 创建当前处理图片
		
		for (int i = 0; i < width(); i++) 
			for (int j = 0; j < height(); j++) 
				picture.setRGB(i, j, pictureColor[i][j]);  // 设置像素
		
		return picture;
	}
	
	// 当前图片宽度
	public int width()                            
	{
		return width;
	}
	
	// 当前图片高度
	public int height()                           
	{
		return height;
	}
	
	// 返回列X和行Y像素的能量
	public double energy(int x, int y)               
	{
		// 下标超出范围
		if (x < 0 || x >= width() || y < 0 || y >= height())
			throw new java.lang.IllegalArgumentException("the row or col is beyond index");
		return energy[x][y];
	}
	
	// 更新能量
	private void renewEnergy()
	{
		energy = new double[width][height];
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++) {
				energy[i][j] = calculattionEnery(i, j);
			}
		}
	}
	
	// 水平缝索引序列
	public int[] findVerticalSeam()               
	{
		renewEnergy();
		//changeEnery();
		int []seam = findSeam(energy);
		return seam;
	}
	// 垂直缝索引序列,转置按照水平方式求
	public int[] findHorizontalSeam()                 
	{
		pictureColor = transpose(pictureColor); 
		int []seam = findVerticalSeam();
		pictureColor = transpose(pictureColor);
		return seam;
	}
	
	/*
	private void changeEnery()
	{
		this.height = 6;
		this.width = 4;
		energy = new double[4][6];
		
		energy[0][0] = 1000.0;
		energy[0][1] = 1000.0;
		energy[0][2] = 1000.0;
		energy[0][3] = 1000.0;
		energy[0][4] = 1000.0;
		energy[0][5] = 1000.0;
		
		energy[1][0] = 1000.0;
		energy[1][1] = 275.66;
		energy[1][2] = 173.21;
		energy[1][3] = 171.80;
		energy[1][4] = 270.93;
		energy[1][5] = 1000.0;
		
		energy[2][0] = 1000.0;
		energy[2][1] = 173.21;
		energy[2][2] = 321.01;
		energy[2][3] = 195.63;
		energy[2][4] = 188.15;
		energy[2][5] = 1000.0;
		
		energy[3][0] = 1000.0;
		energy[3][1] = 1000.0;
		energy[3][2] = 1000.0;
		energy[3][3] = 1000.0;
		energy[3][4] = 1000.0;
		energy[3][5] = 1000.0;
	}
	*/
	// 计算索引序列
	private int[] findSeam(double[][] enery)
	{
		//changeEnery();
		//System.out.println(width());
		int[][] beforeIndex = new int[width()][height()]; 
		double[][] energyTotal = new double[width()][height()];
		
		// beforeIndex[i][j] 表示到达[i][j]的最短线的上一层的下标(i-1,i或i+1)
		for (int i = 0; i < width(); i++) // 0层默认为i
			beforeIndex[i][0] = i;
		
		// energyTotal[i][j]表示从第0层的线经过(i, j)线的能量之和
		for (int i = 0; i < width; i++) // 到达0层 
			energyTotal[i][0] = enery[i][0];
		
		for (int j = 1; j < height(); j++) {  // j层
			for (int i = 0; i < width(); i++) {  // i列
				//int beforeIndex = nextTo[i][j - 1];  // 从(i,0)出发的线,在j-1层的横坐标(列)
				
				// 默认中间
				double minEnergy = energyTotal[i][j-1];  
				int indexNextI = i;
				
				// 左
				if (i-1 >= 0 && minEnergy > energyTotal[i - 1][j-1]) {
					minEnergy = energyTotal[i - 1][j-1];
					indexNextI = i - 1; 
				}
				
				// 右
				if (i+1 <= width() -1 && minEnergy > energyTotal[i + 1][j-1]) {
					minEnergy = energyTotal[i + 1][j-1];
					indexNextI = i + 1; 
				}
				
				// 更新本层信息
				energyTotal[i][j] = enery[i][j] + minEnergy;
				beforeIndex[i][j] = indexNextI;
				//System.out.println("minenery"+minEnergy);
				//System.out.println(enery[i][j] + "  "+indexNextI);
			}
		}
		
		// 找能量最小的线
		double minEnergyTotal = energyTotal[0][height-1];
		int index = 0;
		for (int i = 1; i < energyTotal.length; i++) {
			if (minEnergyTotal > energyTotal[i][height-1]) {
				minEnergyTotal = energyTotal[i][height-1];
				index = i;
			}
		}
		
		
		// 求最小线的横坐标 befor w h
		int[] scem = new int[height];
		scem[height-1] = index;
		for (int i = height-2; i >= 0; i--) {
		
			scem[i] = beforeIndex[index+1][i];
		}
		
		for (int i = 0; i < scem.length; i++) {
			System.out.println(scem[i]);
		}
		
		return scem;
	}

	// 转置图片
	private int[][] transpose(int[][] origin) 
	{
        if (origin == null) throw new NullPointerException();
        if (origin.length < 1) throw new IllegalArgumentException();
        int[][] result = new int[height][width];
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                result[j][i] = origin[i][j];
            }
        }
        int temp = width;
        width = height;
        height = temp;
        return result;
}
	
	// 从当前图片中删除水平缝
	public void removeHorizontalSeam(int[] seam)   
	{
		pictureColor = transpose(pictureColor); 
		removeVerticalSeam(seam);
		pictureColor = transpose(pictureColor);
		
	}
	
	// 从当前图片中删除垂直接缝
	public void removeVerticalSeam(int[] seam)     
	{
		if (seam == null || seam.length != height())
			throw new java.lang.IllegalArgumentException("seam is not ture");
		
		int[][] newColor = new int[width-1][height];
		
		for (int i = 0; i < seam.length; i++) { //层
			if (seam[i] < 0 || seam[i] >= width()) 
				throw new java.lang.IllegalArgumentException("the index is false");
			
			 if (seam[i] == 0) 
			 {
				 System.arraycopy(pictureColor[i], seam[i] + 1, newColor[i], 0, height() - 1);
	         } 
			 else if (seam[i] == height() - 1) 
			 {
				 System.arraycopy(pictureColor[i], 0, newColor[i], 0, height() - 1);
	         } 
			 else 
			 {
				 System.arraycopy(pictureColor[i], 0, newColor[i], 0, seam[i]);
	             System.arraycopy(pictureColor[i], seam[i] + 1, newColor[i], seam[i], height() - seam[i] - 1);
	         }
		}
		width = width-1;
		
	}
	
	public static void main(String[] args)
	{
		int [][]rgb = new int[4][6];
		rgb[0][0] = (213 << 16) + (96 << 8) + (166 << 0);
		rgb[0][1] = (212 << 16) + (96 << 8) + (166 << 0);
		rgb[0][2] = (255 << 16) + (101 << 8) + (51 << 0);
		rgb[0][3] = (255 << 16) + (103 << 8) + (153 << 0);
		rgb[0][4] = (255 << 16) + (101 << 8) + (255 << 0);
		rgb[0][5] = (210 << 16) + (90 << 8) + (200 << 0);
		
		rgb[1][0] = (200 << 16) + (170 << 8) + (180 << 0);
		rgb[1][1] = (98 << 16) + (196 << 8) + (196 << 0);
		rgb[1][2] = (255 << 16) + (153 << 8) + (51 << 0);
		rgb[1][3] = (255 << 16) + (153 << 8) + (153 << 0);
		rgb[1][4] = (255 << 16) + (153 << 8) + (255 << 0);
		rgb[1][5] = (250 << 16) + (150 << 8) + (200 << 0);
	
		rgb[2][0] = (36 << 16) + (99 << 8) + (199 << 0);
		rgb[2][1] = (38 << 16) + (101 << 8) + (180 << 0);
		rgb[2][2] = (255 << 16) + (203 << 8) + (51 << 0);
		rgb[2][3] = (255 << 16) + (204 << 8) + (153 << 0);
		rgb[2][4] = (255 << 16) + (205 << 8) + (255 << 0);
		rgb[2][5] = (177 << 16) + (205 << 8) + (197 << 0);
		
		rgb[3][0] = (38 << 16) + (99 << 8) + (100 << 0);
		rgb[3][1] = (40 << 16) + (90 << 8) + (90 << 0);
		rgb[3][2] = (255 << 16) + (255 << 8) + (51 << 0);
		rgb[3][3] = (255 << 16) + (255 << 8) + (153 << 0);
		rgb[3][4] = (255 << 16) + (255 << 8) + (255 << 0);
		rgb[3][5] = (166 << 16) + (250 << 8) + (170 << 0);
		
		Picture picture = new Picture(4,6);
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 6; j++) {
				picture.setRGB(i, j, rgb[i][j]);
				
			}
		}
		SeamCarver sCarver = new SeamCarver(picture);
		for (int i = 0; i < sCarver.height(); i++) {
			for (int j = 0; j < sCarver.width(); j++) {
				System.out.println(sCarver.energy(j, i));
			}
		}
		
		int []a = sCarver.findVerticalSeam();
		for (int i = 0; i < a.length; i++) {
			System.out.println(a[i]);
		}
		
	}
}

 

 

 

这个正确的是:https://www.cnblogs.com/lxc1910/p/8320736.html 这篇博客里的

import edu.princeton.cs.algs4.Picture;

public class SeamCarver {
  private int[][] picture;
  private double[][] energy;
  private int width;
  private int height;
  
  public SeamCarver(Picture picture)                // create a seam carver object based on the given picture
  {
      if (picture == null)
          throw new IllegalArgumentException();
      width = picture.width();
      height = picture.height();
      energy = new double[width][height];
      this.picture = new int[width][height];
      
      for (int i = 0; i < width(); i++)
      {
          for (int j = 0; j < height(); j++)
              this.picture[i][j] = picture.getRGB(i, j);
      }
      
      for (int i = 0; i < width(); i++)
      {
          for (int j = 0; j < height(); j++)
              energy[i][j] = computeEnergy(i, j);
      }
  }
  
  private double computeEnergy(int x, int y)
  {
      if (x == 0 || x == width() - 1 || y == 0 || y == height() - 1)
          return 1000.0;
      
      int rgbUp = picture[x][y - 1];
      int rgbDown = picture[x][y + 1];
      int rgbLeft = picture[x - 1][y];
      int rgbRight = picture[x + 1][y];
      double rx = Math.pow(((rgbLeft >> 16) & 0xFF) - ((rgbRight >> 16) & 0xFF), 2);
      double gx = Math.pow(((rgbLeft >> 8) & 0xFF) - ((rgbRight >> 8) & 0xFF), 2);
      double bx = Math.pow(((rgbLeft >> 0) & 0xFF) - ((rgbRight >> 0) & 0xFF), 2);
                  
      double ry = Math.pow(((rgbUp >> 16) & 0xFF) - ((rgbDown >> 16) & 0xFF), 2);
      double gy = Math.pow(((rgbUp >> 8) & 0xFF) - ((rgbDown >> 8) & 0xFF), 2);
      double by = Math.pow(((rgbUp >> 0) & 0xFF) - ((rgbDown >> 0) & 0xFF), 2);
      
      return Math.sqrt(rx + gx + bx + ry + gy + by);
  }
  
  public Picture picture()                          // current picture
  {
      Picture pic = new Picture(width, height);
      for (int i = 0; i < width; i++)
          for (int j = 0; j < height; j++)
              pic.setRGB(i, j, picture[i][j]);
          
      return pic;
  }
  
  public int width()                            // width of current picture
  {
      return width;
  }
  
  public     int height()                           // height of current picture
  {
      return height;
  }
  
  public  double energy(int x, int y)               // energy of pixel at column x and row y
  {
      if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
          throw new IllegalArgumentException();
      return energy[x][y];
  }
  
  private void relaxvertical(double[][] distTo, int[][] edgeTo, int x, int y)
  {
      if (distTo[x][y + 1] > distTo[x][y] + energy[x][y + 1])
      {
          distTo[x][y + 1] = distTo[x][y] + energy[x][y + 1];
          edgeTo[x][y + 1] = x;
      }
      if (x > 0 && distTo[x - 1][y + 1] > distTo[x][y] + energy[x - 1][y + 1])
      {
          distTo[x - 1][y + 1] = distTo[x][y] + energy[x - 1][y + 1];
          edgeTo[x - 1][y + 1] = x;
      }
      if (x < width() - 1 && distTo[x + 1][y + 1] > distTo[x][y] + energy[x + 1][y + 1])
      {
          distTo[x + 1][y + 1] = distTo[x][y] + energy[x + 1][y + 1];
          edgeTo[x + 1][y + 1] = x;
      }
  }
  
  private void transpose() 
  {
      int temp = width;
      width = height;
      height = temp;
      
      double[][] energy2 = new double[width][height];
      int[][] picture2 = new int[width][height];
      
      for (int i = 0; i < width; i++)
      {
          for (int j = 0; j < height; j++)
          {
              energy2[i][j] = energy[j][i];
              picture2[i][j] = picture[j][i];
          }
      }
      
      energy = energy2;
      picture = picture2;
  }
  
  public int[] findHorizontalSeam()               // sequence of indices for horizontal seam
  {
      transpose();
      int[] array = findVerticalSeam();
      transpose();
      return array;
  }
  
  public int[] findVerticalSeam()                 // sequence of indices for vertical seam
  {
      int[] seam = new int[height];
      double[][] distTo = new double[width][height];
      int[][] edgeTo = new int[width][height];
      
      for (int i = 0; i < width; i++)
      {
          for (int j = 0; j < height; j++)
          {
              if (j == 0) distTo[i][j] = energy[i][j];
              else distTo[i][j] = Double.POSITIVE_INFINITY;
          }
      }
      for (int j = 0; j < height - 1; j++)
      {
          for (int i = 0; i < width; i++)
          {
              relaxvertical(distTo, edgeTo, i, j);
          }
      }
      
      double min = Double.MAX_VALUE;
      int minIndex = 0;
      for (int i = 0; i < width; i++)
      {
          if (distTo[i][height - 1] < min)
          {
              min = distTo[i][height - 1];
              minIndex = i;
          }
      }
      
      seam[height - 1] = minIndex;
      for (int j = height - 2; j >= 0; j--)
      {
          seam[j] = edgeTo[seam[j + 1]][j + 1];
      }
      
      return seam;
  }
  
  public void removeHorizontalSeam(int[] seam)   // remove horizontal seam from current picture
  {
      checkSeam(seam);
      
      int min = Integer.MAX_VALUE;
      int max = 0;
      
      for (int i = 0; i < width; i++)
      {
          if (seam[i] > max) max = seam[i];
          if (seam[i] < min) min = seam[i];
          
          for (int j = seam[i]; j < height - 1; j++)
          {
              picture[i][j] = picture[i][j + 1];
          }
      }
      
      height--;
      if (min > 0) min--;
      if (max > height - 1) max = height - 1;
      
      for (int i = 0; i < width; i++)
      {
          for (int j = min; j <= max; j++)
              energy[i][j] = computeEnergy(i, j);
          for (int j = max + 1; j < height - 1; j++)
              energy[i][j] = energy[i][j + 1];
      }

  }
  
  private void checkSeam(int[] seam)
  {
      if (height <= 1 || seam == null || seam.length != width)
          throw new IllegalArgumentException();
      for (int i = 0; i < width; i++) 
      {
          if (seam[i] < 0 || seam[i] > height - 1)
              throw new IllegalArgumentException();
          if (i > 0 && Math.abs(seam[i] - seam[i - 1]) > 1)
              throw new IllegalArgumentException();
      }
  }
  public void removeVerticalSeam(int[] seam)     // remove vertical seam from current picture
  {
      transpose();
      removeHorizontalSeam(seam);
      transpose();
  }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值