Coursera 算法二 week2 Seam Carving

这周作业设计到的算法是有向无环图的最短路径算法,只需要按照顶点的拓扑顺序去放松顶点即可。而在这个题目中拓扑顺序就是按照行的顺序或列的顺序。

用到的数据结构为一个二维数组picture同来存储每个像素的颜色,一个二维数组energy用来存储每个像素的能量。开始我是用一个Picture类的对象来存储图像,但是在讨论区里发现用二维数组存储图像,可以占用更小的存储,且计算能量、removeseam时更快更方便。

在检验各像素能量时发现计算结果不正确,后来发现是运算符优先级的问题,((rgbLeft >> 16) & 0xFF) - ((rgbRight >> 16) & 0xFF),即‘ - ’的优先级大于‘ & ’的优先级,因此需要加括号。

在Checklist的Possible Progress Steps中发现计算seam以及removeseam时可以只写Horizontal和Vertical中的一个,然后另一个用矩阵转置的方法来完成。

第一次提交时memory没有通过,原因是把二维数组distTo和二维数组edgeTo放到了成员变量里,后来把这两个数组放到局部变量,就通过了memory测试。

  1 import edu.princeton.cs.algs4.Picture;
  2 
  3 public class SeamCarver {
  4   private int[][] picture;
  5   private double[][] energy;
  6   private int width;
  7   private int height;
  8   
  9   public SeamCarver(Picture picture)                // create a seam carver object based on the given picture
 10   {
 11       if (picture == null)
 12           throw new IllegalArgumentException();
 13       width = picture.width();
 14       height = picture.height();
 15       energy = new double[width][height];
 16       this.picture = new int[width][height];
 17       
 18       for (int i = 0; i < width(); i++)
 19       {
 20           for (int j = 0; j < height(); j++)
 21               this.picture[i][j] = picture.getRGB(i, j);
 22       }
 23       
 24       for (int i = 0; i < width(); i++)
 25       {
 26           for (int j = 0; j < height(); j++)
 27               energy[i][j] = computeEnergy(i, j);
 28       }
 29   }
 30   
 31   private double computeEnergy(int x, int y)
 32   {
 33       if (x == 0 || x == width() - 1 || y == 0 || y == height() - 1)
 34           return 1000.0;
 35       
 36       int rgbUp = picture[x][y - 1];
 37       int rgbDown = picture[x][y + 1];
 38       int rgbLeft = picture[x - 1][y];
 39       int rgbRight = picture[x + 1][y];
 40       double rx = Math.pow(((rgbLeft >> 16) & 0xFF) - ((rgbRight >> 16) & 0xFF), 2);
 41       double gx = Math.pow(((rgbLeft >> 8) & 0xFF) - ((rgbRight >> 8) & 0xFF), 2);
 42       double bx = Math.pow(((rgbLeft >> 0) & 0xFF) - ((rgbRight >> 0) & 0xFF), 2);
 43                   
 44       double ry = Math.pow(((rgbUp >> 16) & 0xFF) - ((rgbDown >> 16) & 0xFF), 2);
 45       double gy = Math.pow(((rgbUp >> 8) & 0xFF) - ((rgbDown >> 8) & 0xFF), 2);
 46       double by = Math.pow(((rgbUp >> 0) & 0xFF) - ((rgbDown >> 0) & 0xFF), 2);
 47       
 48       return Math.sqrt(rx + gx + bx + ry + gy + by);
 49   }
 50   
 51   public Picture picture()                          // current picture
 52   {
 53       Picture pic = new Picture(width, height);
 54       for (int i = 0; i < width; i++)
 55           for (int j = 0; j < height; j++)
 56               pic.setRGB(i, j, picture[i][j]);
 57           
 58       return pic;
 59   }
 60   
 61   public int width()                            // width of current picture
 62   {
 63       return width;
 64   }
 65   
 66   public     int height()                           // height of current picture
 67   {
 68       return height;
 69   }
 70   
 71   public  double energy(int x, int y)               // energy of pixel at column x and row y
 72   {
 73       if (x < 0 || x > width - 1 || y < 0 || y > height - 1)
 74           throw new IllegalArgumentException();
 75       return energy[x][y];
 76   }
 77   
 78   private void relaxvertical(double[][] distTo, int[][] edgeTo, int x, int y)
 79   {
 80       if (distTo[x][y + 1] > distTo[x][y] + energy[x][y + 1])
 81       {
 82           distTo[x][y + 1] = distTo[x][y] + energy[x][y + 1];
 83           edgeTo[x][y + 1] = x;
 84       }
 85       if (x > 0 && distTo[x - 1][y + 1] > distTo[x][y] + energy[x - 1][y + 1])
 86       {
 87           distTo[x - 1][y + 1] = distTo[x][y] + energy[x - 1][y + 1];
 88           edgeTo[x - 1][y + 1] = x;
 89       }
 90       if (x < width() - 1 && distTo[x + 1][y + 1] > distTo[x][y] + energy[x + 1][y + 1])
 91       {
 92           distTo[x + 1][y + 1] = distTo[x][y] + energy[x + 1][y + 1];
 93           edgeTo[x + 1][y + 1] = x;
 94       }
 95   }
 96   
 97   private void transpose() 
 98   {
 99       int temp = width;
100       width = height;
101       height = temp;
102       
103       double[][] energy2 = new double[width][height];
104       int[][] picture2 = new int[width][height];
105       
106       for (int i = 0; i < width; i++)
107       {
108           for (int j = 0; j < height; j++)
109           {
110               energy2[i][j] = energy[j][i];
111               picture2[i][j] = picture[j][i];
112           }
113       }
114       
115       energy = energy2;
116       picture = picture2;
117   }
118   
119   public int[] findHorizontalSeam()               // sequence of indices for horizontal seam
120   {
121       transpose();
122       int[] array = findVerticalSeam();
123       transpose();
124       return array;
125   }
126   
127   public int[] findVerticalSeam()                 // sequence of indices for vertical seam
128   {
129       int[] seam = new int[height];
130       double[][] distTo = new double[width][height];
131       int[][] edgeTo = new int[width][height];
132       
133       for (int i = 0; i < width; i++)
134       {
135           for (int j = 0; j < height; j++)
136           {
137               if (j == 0) distTo[i][j] = energy[i][j];
138               else distTo[i][j] = Double.POSITIVE_INFINITY;
139           }
140       }
141       for (int j = 0; j < height - 1; j++)
142       {
143           for (int i = 0; i < width; i++)
144           {
145               relaxvertical(distTo, edgeTo, i, j);
146           }
147       }
148       
149       double min = Double.MAX_VALUE;
150       int minIndex = 0;
151       for (int i = 0; i < width; i++)
152       {
153           if (distTo[i][height - 1] < min)
154           {
155               min = distTo[i][height - 1];
156               minIndex = i;
157           }
158       }
159       
160       seam[height - 1] = minIndex;
161       for (int j = height - 2; j >= 0; j--)
162       {
163           seam[j] = edgeTo[seam[j + 1]][j + 1];
164       }
165       
166       return seam;
167   }
168   
169   public void removeHorizontalSeam(int[] seam)   // remove horizontal seam from current picture
170   {
171       checkSeam(seam);
172       
173       int min = Integer.MAX_VALUE;
174       int max = 0;
175       
176       for (int i = 0; i < width; i++)
177       {
178           if (seam[i] > max) max = seam[i];
179           if (seam[i] < min) min = seam[i];
180           
181           for (int j = seam[i]; j < height - 1; j++)
182           {
183               picture[i][j] = picture[i][j + 1];
184           }
185       }
186       
187       height--;
188       if (min > 0) min--;
189       if (max > height - 1) max = height - 1;
190       
191       for (int i = 0; i < width; i++)
192       {
193           for (int j = min; j <= max; j++)
194               energy[i][j] = computeEnergy(i, j);
195           for (int j = max + 1; j < height - 1; j++)
196               energy[i][j] = energy[i][j + 1];
197       }
198 
199   }
200   
201   private void checkSeam(int[] seam)
202   {
203       if (height <= 1 || seam == null || seam.length != width)
204           throw new IllegalArgumentException();
205       for (int i = 0; i < width; i++) 
206       {
207           if (seam[i] < 0 || seam[i] > height - 1)
208               throw new IllegalArgumentException();
209           if (i > 0 && Math.abs(seam[i] - seam[i - 1]) > 1)
210               throw new IllegalArgumentException();
211       }
212   }
213   public void removeVerticalSeam(int[] seam)     // remove vertical seam from current picture
214   {
215       transpose();
216       removeHorizontalSeam(seam);
217       transpose();
218   }
219 }
View Code
原文地址:https://www.cnblogs.com/lxc1910/p/8320736.html