算法课程2-线裁剪-作业

题意理解

给定一张图片,将它任意缩放尺寸,能保持图片中主要的图像区域保持不变,避免过分拉伸或拍扁。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) {

    }
}

 

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