任务链接: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();
}
}