diff options
Diffstat (limited to 'Algorithms/Part-II/2-SeamCarving')
| -rw-r--r-- | Algorithms/Part-II/2-SeamCarving/Makefile | 27 | ||||
| -rw-r--r-- | Algorithms/Part-II/2-SeamCarving/SeamCarver.java | 372 | 
2 files changed, 379 insertions, 20 deletions
| diff --git a/Algorithms/Part-II/2-SeamCarving/Makefile b/Algorithms/Part-II/2-SeamCarving/Makefile index 8a7d1c1..8e826fe 100644 --- a/Algorithms/Part-II/2-SeamCarving/Makefile +++ b/Algorithms/Part-II/2-SeamCarving/Makefile @@ -4,7 +4,7 @@ ALGS4	= $(HOME)/algs4  BIN	= SeamCarver  SRCS	= SeamCarver.java  CLASSES	= PrintEnergy.class PrintSeams.class ResizeDemo.class SCUtility.class ShowEnergy.class ShowSeams.class -CLASSPATH	= -classpath .:$(ALGS4)/algs4.jar:$(ALGS4)/stdlib.jar +CLASSPATH	= -classpath '.:$(ALGS4)/algs4.jar:$(ALGS4)/stdlib.jar'  .SUFFIXES:  .SUFFIXES: .java .class @@ -16,13 +16,28 @@ CLASSPATH	= -classpath .:$(ALGS4)/algs4.jar:$(ALGS4)/stdlib.jar  $(BIN): $(BIN).class -run: $(BIN) $(CLASSES) -	java $(CLASSPATH) PrintEnergy ./data/6x5.png -	java $(CLASSPATH) PrintSeams ./data/6x5.png +check.sh: +	echo -e "#! /bin/bash\nF=./data/\$${1}\njava $(CLASSPATH) PrintSeams \$${F}.png > \$${F}.txt && diff -B \$${F}.txt \$${F}.printseams.txt && rm \$${F}.txt" > check.sh +	chmod +x check.sh + +check: $(BIN) $(CLASSES) check.sh +	./check.sh 3x7 +	./check.sh 4x6 +	./check.sh 5x6 +	./check.sh 6x5 +	./check.sh 7x3 +	./check.sh 10x12 +	./check.sh 12x10 +	./check.sh HJocean +	./check.sh HJoceanTransposed + +test: $(BIN) $(CLASSES) +	java $(CLASSPATH) ResizeDemo ./data/HJocean.png 200 100  zip: $(BIN)  	$(ALGS4)/bin/findbugs $(BIN).class -	zip $(BIN).zip $(SRCS) +	rm -f *.zip +	zip seamCarving.zip $(SRCS)  clean: -	rm -f *.class *.zip $(BIN) +	rm -f *.class *.zip check.sh $(BIN) diff --git a/Algorithms/Part-II/2-SeamCarving/SeamCarver.java b/Algorithms/Part-II/2-SeamCarving/SeamCarver.java index 48e7f6e..70df587 100644 --- a/Algorithms/Part-II/2-SeamCarving/SeamCarver.java +++ b/Algorithms/Part-II/2-SeamCarving/SeamCarver.java @@ -1,54 +1,398 @@  /* vim: set expandtab tabstop=4 shiftwidth=4 : */ +import java.awt.Color; +  public class SeamCarver  { +    private static int MAX_ENERGY = 195075; + +    private static boolean DEBUG = false; + +    private int width; +    private int height; +    private int[][] pixels; +    private int[][] energies; +    private int[][] edgeTo; +    private int[][] distTo; +    private boolean verticalE; +    private boolean verticalP; +    private Stopwatch st; +      public SeamCarver(Picture picture)      { +        width = picture.width(); +        height = picture.height(); + +        copyPixels(picture); +        initEnergies(); +        initPaths(); +    } + +    private void copyPixels(Picture picture) +    { +        verticalP = true; +        pixels = new int[height][width]; +        for (int y = 0; y < height; y++) { +            for (int x = 0; x < width; x++) +                pixels[y][x] = picture.get(x, y).getRGB(); +        }      }      public Picture picture()      { -        // current picture -        return null; +        Picture p = new Picture(width, height); + +        if (!verticalP) { +            pixels = getRotatedMatrix(pixels, height, width); +            verticalP = true; +        } +        for (int y = 0; y < height; y++) { +            for (int x = 0; x < width; x++) { +                p.set(x, y, new Color(pixels[y][x])); +            } +        } + +        return p;      }      public int width()      { -        // width  of current picture -        return 0; +        return width;      }      public int height()      { -        // height of current picture -        return 0; +        return height; +    } + +    private void initEnergies() +    { +        verticalE = true; +        energies = new int[height][width]; +        for (int i = 0; i < width; i++) +            energies[0][i] = MAX_ENERGY; + +        for (int i = 0; i < width; i++) +            energies[height - 1][i] = MAX_ENERGY; + +        for (int i = 0; i < height; i++) +            energies[i][0] = MAX_ENERGY; + +        for (int i = 0; i < height; i++) +            energies[i][width - 1] = MAX_ENERGY; + +        for (int h = 1; h < (height - 1); h++) +            for (int w = 1; w < (width - 1); w++) +                energies[h][w] = energyPriv(h, w); +    } + +    private int[][] getRotatedMatrix(int[][] matrix, int y, int x) +    { +        if (DEBUG) { +            if (matrix == energies) System.out.println("rotate energies"); +            else System.out.println("rotate pixels"); +            System.out.println(" new ["+y+";"+x+"]"); +        } + +        int[][] m = new int[y][x]; +        for (int i = 0; i < y; i++) { +            for (int j = 0; j < x; j++) { +                m[i][j] = matrix[j][i]; +            } +        } + +        return m; +    } + +    private int getRed(int rgb)     { return (rgb >> 16) & 0x0ff; } +    private int getGreen(int rgb)   { return (rgb >> 8) & 0x0ff; } +    private int getBlue(int rgb)    { return (rgb) & 0x0ff; } + +    private int energyPriv(int y, int x) +    { +        int left = pixels[y][x - 1]; +        int right = pixels[y][x + 1]; +        int up = pixels[y - 1][x]; +        int down = pixels[y + 1][x]; + +        int rx = getRed(left) - getRed(right); +        int gx = getGreen(left) - getGreen(right); +        int bx = getBlue(left) - getBlue(right); +        int ry = getRed(up) - getRed(down); +        int gy = getGreen(up) - getGreen(down); +        int by = getBlue(up) - getBlue(down); + +        return (rx * rx) + (gx * gx) + (bx * bx) + (ry * ry) + (gy * gy) + (by * by); +    } + +    private void initPaths() +    { +        int sz = Math.max(height, width); +        edgeTo = new int[sz][sz]; +        distTo = new int[sz][sz]; +    } + +    private void clearPaths(int Y, int X) +    { +        for (int x = 0; x < X; x++) { +            // edgeTo[0][x] = -1; +            distTo[0][x] = MAX_ENERGY; +        } + +        for (int y = 1; y < Y; y++) { +            for (int x = 0; x < X; x++) { +                distTo[y][x] = 0; +            } +        }      }      public double energy(int x, int y)      { -        // energy of pixel at column x and row y in current picture -        return 0; +        int w = (width - 1); +        int h = (height - 1); + +        if ((x < 0) || (x > w) || (y < 0) || (y > h)) { +            String err = "["+x+";"+y+"] out of ["+w+";"+h+"]"; +            throw new java.lang.IndexOutOfBoundsException(err); +        } + +        if ((x == 0) || (x == w) || (y == 0) || (y == h)) +            return MAX_ENERGY; + +        if (verticalE) +            return energies[y][x]; +        else +            return energies[x][y]; +    } + +    private void relax(int e, int p, int cy, int cx) +    { +        int d = distTo[cy][cx]; +        int v = e +  energies[cy][cx]; +        if ((d == 0) || (d > v)) { +            edgeTo[cy][cx] = p; +            distTo[cy][cx] = v; +        } +    } + +    private int[] findMinPath(int Y, int X) +    { +        if (DEBUG) st = new Stopwatch(); + +        clearPaths((Y + 1), (X + 1)); + +        int e, c, d, v; +        // from 0 to before last +        for (int y = 0, cy = 1; y < Y; y++, cy++) { +            // first element +            e = distTo[y][0]; +            // relax center child +            relax(e, 0, cy, 0); +            // relax right child +            relax(e, 0, cy, 1); +            // inner elements +            for (int x = 1; x < X; x++) { +                e = distTo[y][x]; +                // relax left child +                relax(e, x, cy, (x - 1)); +                // relax center child +                relax(e, x, cy, x); +                // relax right child +                relax(e, x, cy, (x + 1)); +            } +            // last element +            e = distTo[y][X]; +            // relax left child +            relax(e, X, cy, X - 1); +            // relax center child +            relax(e, X, cy, X); +        } + +        // find first min bottom element +        int best = 0; +        v = Integer.MAX_VALUE; +        for (int x = 0, y = Y; x < X; x++) { +            d = distTo[y][x]; +            if ((d != 0) && (d < v)) { +                best = x; +                v = d; +            } +        } + +        // build path +        int[] path = new int[Y + 1]; +        int x = edgeTo[Y][best]; +        path[Y] = best; +        for (int y = (Y - 1); y > 0; y--) { +            path[y] = x; +            x = edgeTo[y][x]; +        } +        path[0] = x; + +        if (DEBUG) System.out.println("seam found in "+st.elapsedTime()); + +        return path;      }      public int[] findHorizontalSeam()      { -        // sequence of indices for horizontal seam in current picture -        return null; +        if (verticalE) { +            energies = getRotatedMatrix(energies, width, height); +            verticalE = false; +        } + +        return findMinPath((width - 1), (height - 1));      }      public int[] findVerticalSeam()      { -        // sequence of indices for vertical   seam in current picture -        return null; +        if (!verticalE) { +            energies = getRotatedMatrix(energies, height, width); +            verticalE = true; +        } + +        return findMinPath((height - 1), (width - 1)); +    } + +    private void validateSeam(int[] a, int X, int Y) +    { +        if (a.length > X) { +            String err = "seam length "+a.length+" > "+X; +            throw new java.lang.IllegalArgumentException(err); +        } +        int prev = a[0]; +        for (int i = 0; i < X; i++) { +            int v = a[i]; +            if ((v >= Y) || (v < 0)) { +                String err = v+" is out of bounds [0;"+Y+"["; +                throw new java.lang.IllegalArgumentException(err); +            } +            if (Math.abs(prev - v) > 1) { +                String err = "wrong move: "+prev+" -> "+v; +                throw new java.lang.IllegalArgumentException(err); +            } +            prev = v; +        } +    } + +    private void removeItem(int[] a, int index) +    { +        for (int i = index; i < a.length - 1; i++) { +            a[i] = a[i+1]; +        } +    } + +    private void removeSeam(int[] a, int J, int[][] e, int[][] p) +    { +        for (int i = 0; i < a.length; i++) +            removeItem(p[i], a[i]); + +        for (int i = 1; i < (a.length - 1); i++) { +            int v = a[i]; +            if (v == 0) { +                e[i][0] = MAX_ENERGY; +                removeItem(e[i], 1); +            } else if (v == 1) { +                e[i][1] = energyPriv(i, 1); +                removeItem(e[i], 2); +            } else { +                e[i][v - 1] = energyPriv(i, (v - 1)); +                if (v < (J - 1)) { +                    e[i][v] = energyPriv(i, v); +                    removeItem(e[i], v+1); +                } else { +                    e[i][v] = MAX_ENERGY; +                } +            } +        } + +        if (!DEBUG) return; + +        String err; +        for (int j = 0; j < J; j++) { +            int i = 0; +            if (e[i][j] != MAX_ENERGY) { +                err = "["+a.length+" ; "+J+"] : "+i+" ; "+j+" != MAX"; +                throw new java.lang.IndexOutOfBoundsException(err); +            } +            i = a.length - 1; +            if (e[i][j] != MAX_ENERGY) { +                err = "["+a.length+" ; "+J+"] : "+i+" ; "+j+" != MAX"; +                throw new java.lang.IndexOutOfBoundsException(err); +            } +        } +        for (int i = 0; i < a.length; i++) { +            int j = 0; +            if (e[i][j] != MAX_ENERGY) { +                err = "["+a.length+" ; "+J+"] : "+i+" ; "+j+" != MAX"; +                throw new java.lang.IndexOutOfBoundsException(err); +            } +            j = J - 1; +            if (e[i][j] != MAX_ENERGY) { +                err = "["+a.length+" ; "+J+"] : "+i+" ; "+j+" != MAX"; +                throw new java.lang.IndexOutOfBoundsException(err); +            } +        } +        for (int i = 1; i < (a.length - 1); i++) { +            int[] ei = e[i]; +            for (int j = 1; j < (J - 1); j++) { +                int v = ei[j]; +                int eij = energyPriv(i, j); +                if (v != eij) { +                    err = "["+a.length+" ; "+J+"] : "+i+" ; "+j+" != "+eij; +                    throw new java.lang.IllegalArgumentException(err); +                } +            } +        }      }      public void removeHorizontalSeam(int[] a)      { -        // remove horizontal seam from current picture +        if (width <= 1) +            throw new java.lang.IllegalArgumentException("image is to small"); + +        if (DEBUG) st = new Stopwatch(); + +        validateSeam(a, width, height); + +        if (verticalE) { +            energies = getRotatedMatrix(energies, width, height); +            verticalE = false; +        } + +        if (verticalP) { +            pixels = getRotatedMatrix(pixels, width, height); +            verticalP = false; +        } + +        height -= 1; +        removeSeam(a, height, energies, pixels); + +        if (DEBUG) System.out.println("["+width+" "+height+"] in "+st.elapsedTime());      }      public void removeVerticalSeam(int[] a)      { -        // remove vertical   seam from current picture +        if (height <= 1) +            throw new java.lang.IllegalArgumentException("image is to small"); + +        if (DEBUG) st = new Stopwatch(); + +        validateSeam(a, height, width); + +        if (!verticalE) { +            energies = getRotatedMatrix(energies, height, width); +            verticalE = true; +        } + +        if (!verticalP) { +            pixels = getRotatedMatrix(pixels, height, width); +            verticalP = true; +        } + +        width -= 1; +        removeSeam(a, width, energies, pixels); + +        if (DEBUG) System.out.println("["+width+" "+height+"] in "+st.elapsedTime());      }  } | 
