题意理解
给定一张图片,将它任意缩放尺寸,能保持图片中主要的图像区域保持不变,避免过分拉伸或拍扁。ps里的线裁剪技术。
问题分析
使用图最短路径算法。把图像中每个像素点作为图的顶点,点和邻接点的连线的作为边来构成有向无环图。具体边的构造策略看是自上而下,还是自左至右。如果是上下的线裁剪,那么图的边是上面的像素点和下面相邻的三个像素点连接成边。点的权重由上下和左右像素点的rgb三色差值的平方根决定。实现的效果就是越接近的颜色权重越小,也就是最短路径了。图片中两个物体交接的地方颜色较接近。
计算的时候,首先转换成单源点最短路径问题,以第一行像素点为源点,计算每个源点到最下面一行像素点的最短距离,找到所有源点中最小的那个最短路径。
因为这题可以直接找到邻接点,所以不用费心构造全图。仅用数组保存每个点的权重即可。因为权重放在点上,所以和传统的方法有一点变化。但是都会运用disTo和pathTo来保存计算过程,用relax松弛算法来优化最短路径。
挺难的。
其他
https://www.cnblogs.com/lxc1910/p/8320736.html
链接
/* *****************************************************************************
* Name:
* Date:
* Description:
**************************************************************************** */
import edu.princeton.cs.algs4.Picture;
public class SeamCarver {
private Picture picture;
private int width;
private int height;
private double[][] energy;
// create a seam carver object based on the given picture
public SeamCarver(Picture mypicture) {
if (mypicture == null) {
throw new IllegalArgumentException();
}
picture = mypicture;
width = mypicture.width();
height = mypicture.height();
energy = new double[width][height];
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
energy[x][y] = energy(x, y);
}
}
}
// current picture
public Picture picture() {
Picture tmppicture = new Picture(width, height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
tmppicture.set(x, y, picture.get(x, y));
}
}
return tmppicture;
}
// width of current picture
public int width() {
return width;
}
// height of current picture
public int height() {
return height;
}
// energy of pixel at column x and row y
public double energy(int x, int y) {
if (x < 0 || x >= width || y < 0 || y >= height) {
throw new IllegalArgumentException();
}
//top,bottom,left,right
if (x == 0 || x == picture.width()-1 || y == 0 || y == picture.height()-1) {
return 1000;
}
//left-right
double xdifferencered = picture.get(x-1,y).getRed() - picture.get(x+1,y).getRed();
double xdifferencegreen = picture.get(x-1,y).getGreen() - picture.get(x+1,y).getGreen();
double xdifferenceblue = picture.get(x-1,y).getBlue() - picture.get(x+1,y).getBlue();
//up-down
double ydifferencered = picture.get(x,y-1).getRed() - picture.get(x,y+1).getRed();
double ydifferencegreen = picture.get(x,y-1).getGreen() - picture.get(x,y+1).getGreen();
double ydifferenceblue = picture.get(x,y-1).getBlue() - picture.get(x,y+1).getBlue();
double total = xdifferencered * xdifferencered + xdifferencegreen * xdifferencegreen +
xdifferenceblue * xdifferenceblue + ydifferencered * ydifferencered +
ydifferencegreen * ydifferencegreen + ydifferenceblue * ydifferenceblue;
return Math.sqrt(total);
}
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 tmpwidth = height;
int tmpheight = width;
double[][] tmpenergy = new double[tmpwidth][tmpheight];
Picture tmppicture = new Picture(tmpwidth, tmpheight);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
tmpenergy[y][x] = energy[x][y];
tmppicture.set(y, x, picture.get(x, y));
}
}
width = tmpwidth;
height = tmpheight;
energy = tmpenergy;
picture = tmppicture;
}
// sequence of indices for horizontal seam
public int[] findHorizontalSeam() {
transpose();
int[] seam = findVerticalSeam();
transpose();
return seam;
}
// sequence of indices for vertical seam
public int[] findVerticalSeam() {
int[] seam = new int[height];
double[][] disto = new double[width][height];
int[][] edgeto = new int[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (y == 0) {
disto[x][y] = energy[x][y];
}
else {
disto[x][y] = Double.POSITIVE_INFINITY;
}
}
}
for (int y = 0; y < height - 1; y++) {
for (int x = 0; x < width; x++) {
relaxvertical(disto, edgeto, x, y);
}
}
double min = Double.MAX_VALUE;
int minindex = 0;
for (int x = 0; x < width; x++) {
if (disto[x][height-1] < min) {
min = disto[x][height-1];
minindex = x;
}
}
seam[height-1] = minindex;
for (int j = height-2; j >= 0; j--) {
seam[j] = edgeto[seam[j+1]][j+1];
}
return seam;
}
private void checksum(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();
}
}
}
// remove horizontal seam from current picture
public void removeHorizontalSeam(int[] seam) {
checksum(seam);
int min = Integer.MAX_VALUE;
int max = 0;
for (int x = 0; x < width; x++) {
if (seam[x] > max) max = seam[x];
if (seam[x] < min) min = seam[x];
for (int y = seam[x]; y < height-1; y++) {
picture.set(x, y, picture.get(x, y+1));
}
}
Picture tmppicture = new Picture(picture);
height--;
if (min > 0) min--;
if (max > height-1) max = height-1;
for(int x=0; x < width; x++) {
for (int y=min; y <= max; y++) {
energy[x][y] = energy(x, y);
}
for (int y = max+1; y < height-1; y++) {
energy[x][y] = energy[x][y+1];
}
}
}
// remove vertical seam from current picture
public void removeVerticalSeam(int[] seam) {
transpose();
removeHorizontalSeam(seam);
transpose();
}
public static void main(String[] args) {
}
}