pj1弄了整整一周 test终于19分的时候眼泪都要出来了 心里蹦出了四个大字母f*** 这个作业动不动就是一个bug卡半天 读题读半天 十分打击自信心 不过还好最终是做出来了 非常感谢小伙伴们的帮助 先上码
import java.util.Arrays; /* PixImage.java */ /** * The PixImage class represents an image, which is a rectangular grid of * color pixels. Each pixel has red, green, and blue intensities in the range * 0...255. Descriptions of the methods you must implement appear below. * They include a constructor of the form * * public PixImage(int width, int height); * * that creates a black (zero intensity) image of the specified width and * height. Pixels are numbered in the range (0...width - 1, 0...height - 1). * * All methods in this class must be implemented to complete Part I. * See the README file accompanying this project for additional details. */ public class PixImage { /** * Define any variables associated with a PixImage object here. These * variables MUST be private. */ private int height; private int width; private short[][][] pixel; /** * PixImage() constructs an empty PixImage with a specified width and height. * Every pixel has red, green, and blue intensities of zero (solid black). * * @param width the width of the image. * @param height the height of the image. */ public PixImage(int width, int height) { this.width=width; this.height=height; pixel=new short[width][height][3]; for(int i=0;i<width;i++){ for(int j=0;j<height;j++){ setPixel(i, j, (short)0, (short)0, (short)0); } } } /** * getWidth() returns the width of the image. * * @return the width of the image. */ public int getWidth() { // Replace the following line with your solution. return width; } /** * getHeight() returns the height of the image. * * @return the height of the image. */ public int getHeight() { // Replace the following line with your solution. return height; } /** * getRed() returns the red intensity of the pixel at coordinate (x, y). * * @param x the x-coordinate of the pixel. * @param y the y-coordinate of the pixel. * @return the red intensity of the pixel at coordinate (x, y). */ public short getRed(int x, int y) { // Replace the following line with your solution. return pixel[x][y][0]; } /** * getGreen() returns the green intensity of the pixel at coordinate (x, y). * * @param x the x-coordinate of the pixel. * @param y the y-coordinate of the pixel. * @return the green intensity of the pixel at coordinate (x, y). */ public short getGreen(int x, int y) { // Replace the following line with your solution. return pixel[x][y][1]; } /** * getBlue() returns the blue intensity of the pixel at coordinate (x, y). * * @param x the x-coordinate of the pixel. * @param y the y-coordinate of the pixel. * @return the blue intensity of the pixel at coordinate (x, y). */ public short getBlue(int x, int y) { // Replace the following line with your solution. return pixel[x][y][2]; } /** * setPixel() sets the pixel at coordinate (x, y) to specified red, green, * and blue intensities. * * If any of the three color intensities is NOT in the range 0...255, then * this method does NOT change any of the pixel intensities. * * @param x the x-coordinate of the pixel. * @param y the y-coordinate of the pixel. * @param red the new red intensity for the pixel at coordinate (x, y). * @param green the new green intensity for the pixel at coordinate (x, y). * @param blue the new blue intensity for the pixel at coordinate (x, y). */ public void setPixel(int x, int y, short red, short green, short blue) { if(pixel[x][y][0]>255||pixel[x][y][0]<0||pixel[x][y][1]>255|| pixel[x][y][1]<0||pixel[x][y][2]>255||pixel[x][y][2]<0){ }else { pixel[x][y][0]=red; pixel[x][y][1]=green; pixel[x][y][2]=blue; } // Your solution here. } /** * toString() returns a String representation of this PixImage. * * This method isn't required, but it should be very useful to you when * you're debugging your code. It's up to you how you represent a PixImage * as a String. * * @return a String representation of this PixImage. */ public String toString() { // Replace the following line with your solution. String message; message="["; for(int i=0;i<getWidth();i++){ for(int j=0;j<getHeight();j++) message=message+ " {"+(getRed(i,j)+" "+getGreen(i,j)+" "+getBlue(i,j))+"} ";// Replace the following line with your solution. }message=message+"]"; return message; } /** * boxBlur() returns a blurred version of "this" PixImage. * * If numIterations == 1, each pixel in the output PixImage is assigned * a value equal to the average of its neighboring pixels in "this" PixImage, * INCLUDING the pixel itself. * * A pixel not on the image boundary has nine neighbors--the pixel itself and * the eight pixels surrounding it. A pixel on the boundary has six * neighbors if it is not a corner pixel; only four neighbors if it is * a corner pixel. The average of the neighbors is the sum of all the * neighbor pixel values (including the pixel itself) divided by the number * of neighbors, with non-integer quotients rounded toward zero (as Java does * naturally when you divide two integers). * * Each color (red, green, blue) is blurred separately. The red input should * have NO effect on the green or blue outputs, etc. * * The parameter numIterations specifies a number of repeated iterations of * box blurring to perform. If numIterations is zero or negative, "this" * PixImage is returned (not a copy). If numIterations is positive, the * return value is a newly constructed PixImage. * * IMPORTANT: DO NOT CHANGE "this" PixImage!!! All blurring/changes should * appear in the new, output PixImage only. * * @param numIterations the number of iterations of box blurring. * @return a blurred version of "this" PixImage. */ public PixImage boxBlur(int numIterations) { if(numIterations==0) return this; else{ PixImage blured=new PixImage(getWidth(),getHeight()); for(int i=1;i<getWidth()-1;i++){ for(int j=1;j<getHeight()-1;j++){ blured.setPixel(i,j,(short) ((getRed(i-1,j-1)+getRed(i-1,j)+getRed(i-1,j+1)+getRed(i,j-1)+ getRed(i,j)+getRed(i,j+1)+getRed(i+1,j-1)+getRed(i+1,j)+getRed(i+1,j+1))/9), (short) ((getGreen(i-1,j-1)+getGreen(i-1,j)+getGreen(i-1,j+1)+getGreen(i,j-1)+ getGreen(i,j)+getGreen(i,j+1)+getGreen(i+1,j-1)+getGreen(i+1,j)+getGreen(i+1,j+1))/9), (short) ((getBlue(i-1,j-1)+getBlue(i-1,j)+getBlue(i-1,j+1)+getBlue(i,j-1)+ getBlue(i,j)+getBlue(i,j+1)+getBlue(i+1,j-1)+getBlue(i+1,j)+getBlue(i+1,j+1))/9)); } } blured.setPixel(0,0,(short)((getRed(1,0)+getRed(1,1)+getRed(0,1)+getRed(0,0))/4), (short)((getGreen(1,0)+getGreen(1,1)+getGreen(0,1)+getGreen(0,0))/4), (short)((getBlue(1,0)+getBlue(1,1)+getBlue(0,1)+getBlue(0,0))/4)); //up left coner blured.setPixel(0, getHeight()-1,(short)((getRed(0,getHeight()-2)+getRed(0,getHeight()-1)+ getRed(1,getHeight()-2)+getRed(1,getHeight()-1))/4), (short)((getGreen(0,getHeight()-2)+getGreen(0,getHeight()-1)+ getGreen(1,getHeight()-2)+getGreen(1,getHeight()-1))/4), (short)((getBlue(0,getHeight()-2)+getBlue(0,getHeight()-1)+ getBlue(1,getHeight()-2)+getBlue(1,getHeight()-1))/4)); //bottom left coner blured.setPixel(getWidth()-1,0,(short)((getRed(getWidth()-2,0)+getRed(getWidth()-2,1)+ getRed(getWidth()-1,0)+getRed(getWidth()-1,1))/4),(short)((getGreen(getWidth()-2,0)+getGreen(getWidth()-2,1)+ getGreen(getWidth()-1,0)+getGreen(getWidth()-1,1))/4),(short)((getBlue(getWidth()-2,0)+getBlue(getWidth()-2,1)+ getBlue(getWidth()-1,0)+getBlue(getWidth()-1,1))/4)); // up right coner blured.setPixel(getWidth()-1, getHeight()-1, (short)((getRed(getWidth()-2,getHeight()-2)+getRed(getWidth()-2,getHeight()-1)+ getRed(getWidth()-1,getHeight()-2)+getRed(getWidth()-1,getHeight()-1))/4), (short)((getGreen(getWidth()-2,getHeight()-2)+getGreen(getWidth()-2,getHeight()-1)+ getGreen(getWidth()-1,getHeight()-2)+getGreen(getWidth()-1,getHeight()-1))/4), (short)((getBlue(getWidth()-2,getHeight()-2)+getBlue(getWidth()-2,getHeight()-1)+ getBlue(getWidth()-1,getHeight()-2)+getBlue(getWidth()-1,getHeight()-1))/4)); //bottom right coner for(int i=1;i<getWidth()-1;i++){ blured.setPixel(i, 0, (short) ((getRed(i-1,0)+getRed(i-1,1)+ getRed(i,0)+getRed(i,1)+getRed(i+1,0)+getRed(i+1,1))/6), (short) ((getGreen(i-1,0)+getGreen(i-1,1)+getGreen(i,0)+ getGreen(i,1)+getGreen(i+1,0)+getGreen(i+1,1))/6), (short)((getBlue(i-1,0)+getBlue(i-1,1)+ getBlue(i,0)+getBlue(i,1)+getBlue(i+1,0)+getBlue(i+1,1))/6)); blured.setPixel(i, getHeight()-1, (short) ((getRed(i-1,getHeight()-1)+getRed(i-1,getHeight()-2)+ getRed(i,getHeight()-1)+getRed(i,getHeight()-2)+getRed(i+1,getHeight()-1)+getRed(i+1,getHeight()-2))/6), (short) ((getGreen(i-1, getHeight()-1)+getGreen(i-1, getHeight()-2)+getGreen(i, getHeight()-1)+ getGreen(i, getHeight()-2)+getGreen(i+1, getHeight()-1)+getGreen(i+1, getHeight()-2))/6), (short)((getBlue(i-1, getHeight()-1)+getBlue(i-1, getHeight()-2)+ getBlue(i, getHeight()-1)+getBlue(i, getHeight()-2)+getBlue(i+1, getHeight()-1)+getBlue(i+1, getHeight()-2))/6)); }//the up and bottom boundary for(int j=1;j<getHeight()-1;j++){ blured.setPixel(0,j,(short) ((getRed(0,j-1)+getRed(0,j)+ getRed(0,j+1)+getRed(1,j-1)+getRed(1,j)+getRed(1,j+1))/6), (short) ((getGreen(0,j-1)+getGreen(0,j)+ getGreen(0,j+1)+getGreen(1,j-1)+getGreen(1,j)+getGreen(1,j+1))/6), (short) ((getBlue(0,j-1)+getBlue(0,j)+ getBlue(0,j+1)+getBlue(1,j-1)+getBlue(1,j)+getBlue(1,j+1))/6)); blured.setPixel(getWidth()-1,j, (short) ((getRed(getWidth()-1,j-1)+getRed(getWidth()-1,j)+ getRed(getWidth()-1,j+1)+getRed(getWidth()-2,j-1)+getRed(getWidth()-2,j)+getRed(getWidth()-2,j+1))/6), (short) ((getGreen(getWidth()-1,j-1)+getGreen(getWidth()-1,j)+ getGreen(getWidth()-1,j+1)+getGreen(getWidth()-2,j-1)+getGreen(getWidth()-2,j)+getGreen(getWidth()-2,j+1))/6), (short) ((getBlue(getWidth()-1,j-1)+getBlue(getWidth()-1,j)+ getBlue(getWidth()-1,j+1)+getBlue(getWidth()-2,j-1)+getBlue(getWidth()-2,j)+getBlue(getWidth()-2,j+1))/6)); }// the left and right boundary if(numIterations==1) return blured; else return blured.boxBlur(numIterations-1); } } /** * mag2gray() maps an energy (squared vector magnitude) in the range * 0...24,969,600 to a grayscale intensity in the range 0...255. The map * is logarithmic, but shifted so that values of 5,080 and below map to zero. * * DO NOT CHANGE THIS METHOD. If you do, you will not be able to get the * correct images and pass the autograder. * * @param mag the energy (squared vector magnitude) of the pixel whose * intensity we want to compute. * @return the intensity of the output pixel. */ private static short mag2gray(long mag) { short intensity = (short) (30.0 * Math.log(1.0 + (double) mag) - 256.0); // Make sure the returned intensity is in the range 0...255, regardless of // the input value. if (intensity < 0) { intensity = 0; } else if (intensity > 255) { intensity = 255; } return intensity; } /** * sobelEdges() applies the Sobel operator, identifying edges in "this" * image. The Sobel operator computes a magnitude that represents how * strong the edge is. We compute separate gradients for the red, blue, and * green components at each pixel, then sum the squares of the three * gradients at each pixel. We convert the squared magnitude at each pixel * into a grayscale pixel intensity in the range 0...255 with the logarithmic * mapping encoded in mag2gray(). The output is a grayscale PixImage whose * pixel intensities reflect the strength of the edges. * * See http://en.wikipedia.org/wiki/Sobel_operator#Formulation for details. * * @return a grayscale PixImage representing the edges of the input image. * Whiter pixels represent stronger edges. */ public PixImage sobelEdges() { PixImage reflected=doReflection(); long vector[][][][] = new long[getWidth()][getHeight()][3][2]; long energy[][] = new long[getWidth()][getHeight()]; PixImage sobeled=new PixImage(getWidth(),getHeight()); for(int i=0;i<getWidth();i++){ for(int j=0;j<getHeight();j++){ vector[i][j][0][0]=1*reflected.getRed(i,j)+0*reflected.getRed(i+1,j)+(-1)*reflected.getRed(i+2,j)+2*reflected.getRed(i,j+1)+0*reflected.getRed(i+1,j+1) +(-2)*reflected.getRed(i+2,j+1)+1*reflected.getRed(i,j+2)+0*reflected.getRed(i+1,j+2)+(-1)*reflected.getRed(i+2,j+2); vector[i][j][0][1]=1*reflected.getRed(i,j)+2*reflected.getRed(i+1,j)+1*reflected.getRed(i+2,j)+0*reflected.getRed(i,j+1)+0*reflected.getRed(i+1,j+1) +0*reflected.getRed(i+2,j+1)+(-1)*reflected.getRed(i,j+2)+(-2)*reflected.getRed(i+1,j+2)+(-1)*reflected.getRed(i+2,j+2); //Red's gx&gy vector[i][j][1][0]=1*reflected.getGreen(i,j)+0*reflected.getGreen(i+1,j)+(-1)*reflected.getGreen(i+2,j)+2*reflected.getGreen(i,j+1)+0*reflected.getGreen(i+1,j+1) +(-2)*reflected.getGreen(i+2,j+1)+1*reflected.getGreen(i,j+2)+0*reflected.getGreen(i+1,j+2)+(-1)*reflected.getGreen(i+2,j+2); vector[i][j][1][1]=1*reflected.getGreen(i,j)+2*reflected.getGreen(i+1,j)+1*reflected.getGreen(i+2,j)+0*reflected.getGreen(i,j+1)+0*reflected.getGreen(i+1,j+1) +0*reflected.getGreen(i+2,j+1)+(-1)*reflected.getGreen(i,j+2)+(-2)*reflected.getGreen(i+1,j+2)+(-1)*reflected.getGreen(i+2,j+2); //Green's gx&gy vector[i][j][2][0]=1*reflected.getBlue(i,j)+0*reflected.getBlue(i+1,j)+(-1)*reflected.getBlue(i+2,j)+2*reflected.getBlue(i,j+1)+0*reflected.getBlue(i+1,j+1) +(-2)*reflected.getBlue(i+2,j+1)+1*reflected.getBlue(i,j+2)+0*reflected.getBlue(i+1,j+2)+(-1)*reflected.getBlue(i+2,j+2); vector[i][j][2][1]=1*reflected.getBlue(i,j)+2*reflected.getBlue(i+1,j)+1*reflected.getBlue(i+2,j)+0*reflected.getBlue(i,j+1)+0*reflected.getBlue(i+1,j+1) +0*reflected.getBlue(i+2,j+1)+(-1)*reflected.getBlue(i,j+2)+(-2)*reflected.getBlue(i+1,j+2)+(-1)*reflected.getBlue(i+2,j+2); //Blue's gx&gy energy[i][j]=vector[i][j][0][0]*vector[i][j][0][0]+vector[i][j][0][1]*vector[i][j][0][1]+vector[i][j][1][0]*vector[i][j][1][0] +vector[i][j][1][1]*vector[i][j][1][1]+vector[i][j][2][0]*vector[i][j][2][0]+vector[i][j][2][1]*vector[i][j][2][1]; sobeled.setPixel(i,j,mag2gray(energy[i][j]),mag2gray(energy[i][j]),mag2gray(energy[i][j])); } } return sobeled; } private PixImage doReflection(){ //将原数列向外围扩大一圈 PixImage reflect=new PixImage(getWidth()+2,getHeight()+2); for(int j=0;j<getHeight();j++) reflect.setPixel(0,j+1,getRed(0,j),getGreen(0,j),getBlue(0,j)); //left boundary for(int j=0;j<getHeight();j++) reflect.setPixel(reflect.getWidth()-1,j+1,getRed(getWidth()-1,j),getGreen(getWidth()-1,j),getBlue(getWidth()-1,j)); //right boundary for(int j=0;j<getWidth();j++) reflect.setPixel(j+1,0,getRed(j,0),getGreen(j,0),getBlue(j,0)); //up boundary for(int j=0;j<getWidth();j++) reflect.setPixel(j+1,reflect.getHeight()-1,getRed(j,getHeight()-1),getGreen(j,getHeight()-1),getBlue(j,getHeight()-1)); //bottom boundary reflect.setPixel(0, 0, getRed(0,0), getGreen(0,0), getBlue(0,0)); reflect.setPixel(reflect.getWidth()-1, 0, getRed(getWidth()-1,0), getGreen(getWidth()-1,0), getBlue(getWidth()-1,0)); reflect.setPixel(0, reflect.getHeight()-1, getRed(0,getHeight()-1), getGreen(0,getHeight()-1), getBlue(0,getHeight()-1)); reflect.setPixel(reflect.getWidth()-1,reflect.getHeight()-1,getRed(getWidth()-1,getHeight()-1), getGreen(getWidth()-1,getHeight()-1), getBlue(getWidth()-1,getHeight()-1)); //4个特殊点 for(int i=1;i<reflect.getWidth()-1;i++){ for(int j=1;j<reflect.getHeight()-1;j++){ reflect.setPixel(i, j, getRed(i-1,j-1), getGreen(i-1,j-1), getBlue(i-1,j-1)); } } //复制中央位置 return reflect; } /** * TEST CODE: YOU DO NOT NEED TO FILL IN ANY METHODS BELOW THIS POINT. * You are welcome to add tests, though. Methods below this point will not * be tested. This is not the autograder, which will be provided separately. */ /** * doTest() checks whether the condition is true and prints the given error * message if it is not. * * @param b the condition to check. * @param msg the error message to print if the condition is false. */ private static void doTest(boolean b, String msg) { if (b) { System.out.println("Good."); } else { System.err.println(msg); } } /** * array2PixImage() converts a 2D array of grayscale intensities to * a grayscale PixImage. * * @param pixels a 2D array of grayscale intensities in the range 0...255. * @return a new PixImage whose red, green, and blue values are equal to * the input grayscale intensities. */ private static PixImage array2PixImage(int[][] pixels) { int width = pixels.length; int height = pixels[0].length; PixImage image = new PixImage(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setPixel(x, y, (short) pixels[x][y], (short) pixels[x][y], (short) pixels[x][y]); } } return image; } /** * equals() checks whether two images are the same, i.e. have the same * dimensions and pixels. * * @param image a PixImage to compare with "this" PixImage. * @return true if the specified PixImage is identical to "this" PixImage. */ public boolean equals(PixImage image) { int width = getWidth(); int height = getHeight(); if (image == null || width != image.getWidth() || height != image.getHeight()) { return false; } for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (! (getRed(x, y) == image.getRed(x, y) && getGreen(x, y) == image.getGreen(x, y) && getBlue(x, y) == image.getBlue(x, y))) { return false; } } } return true; } /** * main() runs a series of tests to ensure that the convolutions (box blur * and Sobel) are correct. */ public static void main(String[] args) { // Be forwarned that when you write arrays directly in Java as below, // each "row" of text is a column of your image--the numbers get // transposed. PixImage image1 = array2PixImage(new int[][] { { 0, 10, 240 }, { 30, 120, 250 }, { 80, 250, 255 } }); System.out.println("Testing getWidth/getHeight on a 3x3 image. " + "Input image:"); System.out.print(image1); System.out.println(image1.getWidth()); doTest(image1.getWidth() == 3 && image1.getHeight() == 3, "Incorrect image width and height."); System.out.println("Testing blurring on a 3x3 image."); doTest(image1.boxBlur(1).equals( array2PixImage(new int[][] { { 40, 108, 155 }, { 81, 137, 187 }, { 120, 164, 218 } })), "Incorrect box blur (1 rep): " + image1.boxBlur(1)); doTest(image1.boxBlur(2).equals( array2PixImage(new int[][] { { 91, 118, 146 }, { 108, 134, 161 }, { 125, 151, 176 } })), "Incorrect box blur (2 rep): " + image1.boxBlur(2)); doTest(image1.boxBlur(2).equals(image1.boxBlur(1).boxBlur(1)), "Incorrect box blur (1 rep + 1 rep): " + image1.boxBlur(2) + image1.boxBlur(1).boxBlur(1)); System.out.println("Testing edge detection on a 3x3 image."); doTest(image1.sobelEdges().equals( array2PixImage(new int[][] { { 104, 189, 180 }, { 160, 193, 157 }, { 166, 178, 96 } })), "Incorrect Sobel: " + image1.sobelEdges()); PixImage image2 = array2PixImage(new int[][] { { 0, 100, 100 }, { 0, 0, 100 } }); System.out.println("Testing getWidth/getHeight on a 2x3 image. " + "Input image:"); System.out.println(image2); System.out.println(image2.doReflection()); doTest(image2.getWidth() == 2 && image2.getHeight() == 3, "Incorrect image width and height."); System.out.println("Testing blurring on a 2x3 image."); doTest(image2.boxBlur(1).equals( array2PixImage(new int[][] { { 25, 50, 75 }, { 25, 50, 75 } })), "Incorrect box blur (1 rep): " + image2.boxBlur(1)); System.out.println("Testing edge detection on a 2x3 image."); doTest(image2.sobelEdges().equals( array2PixImage(new int[][] { { 122, 143, 74 }, { 74, 143, 122 } })), "Incorrect Sobel: " + image2.sobelEdges()); } }
/* RunLengthEncoding.java */ /** * The RunLengthEncoding class defines an object that run-length encodes * a PixImage object. Descriptions of the methods you must implement appear * below. They include constructors of the form * * public RunLengthEncoding(int width, int height); * public RunLengthEncoding(int width, int height, int[] red, int[] green, * int[] blue, int[] runLengths) { * public RunLengthEncoding(PixImage image) { * * that create a run-length encoding of a PixImage having the specified width * and height. * * The first constructor creates a run-length encoding of a PixImage in which * every pixel is black. The second constructor creates a run-length encoding * for which the runs are provided as parameters. The third constructor * converts a PixImage object into a run-length encoding of that image. * * See the README file accompanying this project for additional details. */ import java.util.Iterator; public class RunLengthEncoding implements Iterable { /** * Define any variables associated with a RunLengthEncoding object here. * These variables MUST be private. */ private DListNode1 head; private DListNode1 tail; private int size; private int width; private int height; private int k; /** * The following methods are required for Part II. */ /** * RunLengthEncoding() (with two parameters) constructs a run-length * encoding of a black PixImage of the specified width and height, in which * every pixel has red, green, and blue intensities of zero. * * @param width the width of the image. * @param height the height of the image. */ public RunLengthEncoding(int width, int height) { this.width=width; this.height=height; head=new DListNode1(0,width*height); tail=head; tail.prev=null; head.next=null; size=1;// Your solution here. } /** * RunLengthEncoding() (with six parameters) constructs a run-length * encoding of a PixImage of the specified width and height. The runs of * the run-length encoding are taken from four input arrays of equal length. * Run i has length runLengths[i] and RGB intensities red[i], green[i], and * blue[i]. * * @param width the width of the image. * @param height the height of the image. * @param red is an array that specifies the red intensity of each run. * @param green is an array that specifies the green intensity of each run. * @param blue is an array that specifies the blue intensity of each run. * @param runLengths is an array that specifies the length of each run. * * NOTE: All four input arrays should have the same length (not zero). * All pixel intensities in the first three arrays should be in the range * 0...255. The sum of all the elements of the runLengths array should be * width * height. (Feel free to quit with an error message if any of these * conditions are not met--though we won't be testing that.) */ public RunLengthEncoding(int width, int height, int[] red, int[] green, int[] blue, int[] runLengths) { this.width=width; this.height=height; head=new DListNode1(red[0],green[0],blue[0],runLengths[0]); tail=head; tail.prev=null; head.next=null; size=1; int k=runLengths.length; for(int i=1;i<k;i++){ DListNode1 theNext = new DListNode1(red[i],green[i],blue[i],runLengths[i]); tail.next=theNext; theNext.prev=tail; tail=theNext; size++;} // Your solution here. } /** * getWidth() returns the width of the image that this run-length encoding * represents. * * @return the width of the image that this run-length encoding represents. */ public int getWidth() { // Replace the following line with your solution. return width; } /** * getHeight() returns the height of the image that this run-length encoding * represents. * * @return the height of the image that this run-length encoding represents. */ public int getHeight() { // Replace the following line with your solution. return height; } /** * iterator() returns a newly created RunIterator that can iterate through * the runs of this RunLengthEncoding. * * @return a newly created RunIterator object set to the first run of this * RunLengthEncoding. */ public RunIterator iterator() { RunIterator run=new RunIterator(head); return run; // Replace the following line with your solution. // You'll want to construct a new RunIterator, but first you'll need to // write a constructor in the RunIterator class. } /** * toPixImage() converts a run-length encoding of an image into a PixImage * object. * * @return the PixImage that this RunLengthEncoding encodes. */ public PixImage toPixImage() { PixImage converted=new PixImage(width,height); RunIterator k=iterator(); int n0,m0,n1,m1,sumOfruns; int[] next; sumOfruns=0; m0=0; n0=0; while(k.hasNext()){ next=k.next(); sumOfruns=sumOfruns+next[0]; m1=sumOfruns%width; n1=sumOfruns/width; if (m1==0){m1=width; n1=n1-1; } if(n1>n0){ for(int i=m0;i<width;i++){ converted.setPixel(i,n0,(short)next[1],(short)next[2],(short)next[3]); } for(int j=n0+1;j<n1;j++){ for(int i=0;i<width;i++){ converted.setPixel(i,j,(short)next[1],(short)next[2],(short)next[3]); } } for(int i=0;i<m1;i++){ converted.setPixel(i,n1,(short)next[1],(short)next[2],(short)next[3]); } } else{ for(int i=m0;i<m1;i++){ converted.setPixel(i,n1,(short)next[1],(short)next[2],(short)next[3]); } } m0=m1; n0=n1; } // Replace the following line with your solution. return converted; } /** * toString() returns a String representation of this RunLengthEncoding. * * This method isn't required, but it should be very useful to you when * you're debugging your code. It's up to you how you represent * a RunLengthEncoding as a String. * * @return a String representation of this RunLengthEncoding. */ public String toString() { String h=new String(); DListNode1 current=head; h="["; while (current != null){ h=h+"{"+current.red+current.green+current.blue+"|"+current.num+"}"; current=current.next; } h=h+"]";// Replace the following line with your solution. return h; } /** * The following methods are required for Part III. */ /** * RunLengthEncoding() (with one parameter) is a constructor that creates * a run-length encoding of a specified PixImage. * * Note that you must encode the image in row-major format, i.e., the second * pixel should be (1, 0) and not (0, 1). * * @param image is the PixImage to run-length encode. */ public RunLengthEncoding(PixImage image) { int[] red=new int[image.getWidth()*image.getHeight()]; int[] green=new int[image.getWidth()*image.getHeight()]; int[] blue=new int[image.getWidth()*image.getHeight()]; int[] num=new int[image.getWidth()*image.getHeight()]; k=0; red[0]=image.getRed(0,0); green[0]=image.getGreen(0,0); blue[0]=image.getBlue(0,0); num[0]=1; for(int j=0;j<image.getHeight();j++){ for(int i=0;i<image.getWidth();i++){ if(i==image.getWidth()-1&&j==image.getHeight()-1){ break;} else if(i==image.getWidth()-1&&j!=image.getHeight()-1){ if(image.getRed(i,j)==image.getRed(0,j+1)&&image.getGreen(i,j)==image.getGreen(0,j+1) &&image.getBlue(i,j)==image.getBlue(0,j+1)){ num[k]++;} else{ k=k+1; num[k]=1; red[k]=image.getRed(0,j+1); green[k]=image.getGreen(0,j+1); blue[k]=image.getBlue(0,j+1); } }else if(image.getRed(i,j)==image.getRed(i+1,j) &&image.getGreen(i,j)==image.getGreen(i+1,j)&&image.getBlue(i,j)==image.getBlue(i+1,j)){ num[k]++;} else { k=k+1; num[k]=1; red[k]=image.getRed(i+1,j); green[k]=image.getGreen(i+1,j); blue[k]=image.getBlue(i+1,j); } } } // Your solution here, but you should probably leave the following line // at the end. this.width=image.getWidth(); this.height=image.getHeight(); for(int i=0;i<=k;i++){ DListNode1 theNext = new DListNode1(red[i],green[i],blue[i],num[i]); if(i==0) {head=theNext; tail=head; tail.prev=null; head.next=null; size++;} else {tail.next=theNext; theNext.prev=tail; theNext.next=null; tail=theNext; size++; } } check(); } /** * check() walks through the run-length encoding and prints an error message * if two consecutive runs have the same RGB intensities, or if the sum of * all run lengths does not equal the number of pixels in the image. */ public void check() { int sumLength=0; DListNode1 current; current=head; while(current.next!=null){ int r0=current.red; int g0=current.green; int b0=current.blue; int r1=current.next.red; int g1=current.next.green; int b1=current.next.blue; if(r0==r1&&g0==g1&&b0==b1){ System.out.println("ERROR:consecutive same runs"); } if(current.num<1||tail.num<1){ System.out.println("ERROR:runlength less than 1"); } sumLength=sumLength+current.num; current=current.next; } sumLength=sumLength+tail.num; if(sumLength!=width*height){ System.out.println("ERROR:unequal sum with pixels "); } } /** * The following method is required for Part IV. */ /** * setPixel() modifies this run-length encoding so that the specified color * is stored at the given (x, y) coordinates. The old pixel value at that * coordinate should be overwritten and all others should remain the same. * The updated run-length encoding should be compressed as much as possible; * there should not be two consecutive runs with exactly the same RGB color. * * @param x the x-coordinate of the pixel to modify. * @param y the y-coordinate of the pixel to modify. * @param red the new red intensity to store at coordinate (x, y). * @param green the new green intensity to store at coordinate (x, y). * @param blue the new blue intensity to store at coordinate (x, y). */ public void setPixel(int x, int y, short red, short green, short blue) { int location,totalLength,nth; location=x+y*width+1; DListNode1 current; current=head; totalLength=current.num; if(totalLength>=location){ nth=location; } else{ while(totalLength<location){ current=current.next; totalLength=totalLength+current.num;} nth=current.num-(totalLength-location);} if(current.red==red&¤t.green==green&¤t.blue==blue){ } else{ if(current.num==1){ current.red=red; current.green=green; current.blue=blue; if(current!=head&¤t!=tail){ if(red==current.prev.red&&green==current.prev.green &&blue==current.prev.blue&&red==current.next.red&&green==current.next.green &&blue==current.next.blue){ current.prev.num=current.prev.num+1+current.next.num; if(current.next==tail){ current.prev.next=null; current.prev=tail; } else{ current.prev.next=current.next.next; current.next.next.prev=current.prev; } } else if(red==current.next.red&&green==current.next.green &&blue==current.next.blue){ current.next.num=current.next.num+1;; current.prev.next=current.next; current.next.prev=current.prev; } else if(red==current.prev.red&&green==current.prev.green &&blue==current.prev.blue){ current.prev.num=current.prev.num+1; current.prev.next=current.next; current.next.prev=current.prev; } } if(current==head){ if(red==current.next.red&&green==current.next.green &&blue==current.next.blue){ current.next.num=current.next.num+current.num; current.next.prev=null; head=current.next; } } if(current==tail){ if(current.red==current.prev.red&¤t.green==current.prev.green &¤t.blue==current.prev.blue){ current.prev.num=current.prev.num+current.num; current.prev.next=null; tail=current.prev; } } } if(current.num>1){ if(current!=head&¤t!=tail){ if(nth==1){ if(current.prev.red==red&¤t.prev.green==green&¤t.prev.blue==blue){ current.prev.num++; current.num--; }else { DListNode1 changed=new DListNode1(red,green,blue,1); insertBefore(current,changed); } } if(nth==current.num){ if(current.next.red==red&¤t.next.green==green&¤t.next.blue==blue){ current.next.num++; current.num--; }else{ DListNode1 changed=new DListNode1(red,green,blue,1); insertAfter(current,changed); } } if (nth>1&&nth<current.num){ DListNode1 theFront=new DListNode1(current.red,current.green,current.blue,nth-1); insertBefore(current,theFront); DListNode1 changed=new DListNode1(red,green,blue,1); insertBefore(current,changed); current.num=current.num-nth+2; } } if(current==head){ if(nth==1){ DListNode1 changed=new DListNode1(red,green,blue,1); insertAsHead(current,changed); } else if(nth==current.num){ if(current.next.red==red&¤t.next.green==green&¤t.next.blue==blue){ current.next.num++; current.num--; }else{ DListNode1 changed=new DListNode1(red,green,blue,1); insertAfter(current,changed); } }else if(nth>1&&nth<current.num){ DListNode1 theAfter=new DListNode1(current.red,current.green,current.blue,current.num-nth); insertAfter(current,theAfter); DListNode1 changed=new DListNode1(red,green,blue,1); insertAfter(current,changed); current.num=nth-1; } } if(current==tail){ if(nth==current.num){ DListNode1 changed=new DListNode1(red,green,blue,1); insertAsTail(current,changed); } else if(nth==1){ if(current.prev.red==red&¤t.prev.green==green&¤t.prev.blue==blue){ current.prev.num++; current.num--; }else{ DListNode1 changed=new DListNode1(red,green,blue,1); insertBefore(current,changed); } }else if(nth>1&&nth<current.num){ DListNode1 theFront=new DListNode1(current.red,current.green,current.blue,nth-1); insertBefore(current,theFront); DListNode1 changed=new DListNode1(red,green,blue,1); insertBefore(current,changed); current.num=current.num-nth+2; } } } } // Your solution here, but you should probably leave the following line // at the end. check(); } private void insertAsHead(DListNode1 cur,DListNode1 inserted){ inserted.next=cur; inserted.prev=null; cur.prev=inserted; head=inserted; cur.num--; } private void insertAsTail(DListNode1 cur,DListNode1 inserted){ inserted.prev=cur; inserted.next=null; cur.next=inserted; tail=inserted; cur.num--; } private void insertBefore(DListNode1 cur,DListNode1 inserted){ cur.prev.next=inserted; inserted.prev=cur.prev; inserted.next=cur; cur.prev=inserted; cur.num--; } private void insertAfter(DListNode1 cur,DListNode1 inserted){ cur.next.prev=inserted; inserted.prev=cur; inserted.next=cur.next; cur.next=inserted; cur.num--; } /** * TEST CODE: YOU DO NOT NEED TO FILL IN ANY METHODS BELOW THIS POINT. * You are welcome to add tests, though. Methods below this point will not * be tested. This is not the autograder, which will be provided separately. */ /** * doTest() checks whether the condition is true and prints the given error * message if it is not. * * @param b the condition to check. * @param msg the error message to print if the condition is false. */ private static void doTest(boolean b, String msg) { if (b) { System.out.println("Good."); } else { System.err.println(msg); } } /** * array2PixImage() converts a 2D array of grayscale intensities to * a grayscale PixImage. * * @param pixels a 2D array of grayscale intensities in the range 0...255. * @return a new PixImage whose red, green, and blue values are equal to * the input grayscale intensities. */ private static PixImage array2PixImage(int[][] pixels) { int width = pixels.length; int height = pixels[0].length; PixImage image = new PixImage(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setPixel(x, y, (short) pixels[x][y], (short) pixels[x][y], (short) pixels[x][y]); } } return image; } /** * setAndCheckRLE() sets the given coordinate in the given run-length * encoding to the given value and then checks whether the resulting * run-length encoding is correct. * * @param rle the run-length encoding to modify. * @param x the x-coordinate to set. * @param y the y-coordinate to set. * @param intensity the grayscale intensity to assign to pixel (x, y). */ private static void setAndCheckRLE(RunLengthEncoding rle, int x, int y, int intensity) { rle.setPixel(x, y, (short) intensity, (short) intensity, (short) intensity); rle.check(); } /** * main() runs a series of tests of the run-length encoding code. */ public static void main(String[] args) { // Be forwarned that when you write arrays directly in Java as below, // each "row" of text is a column of your image--the numbers get // transposed. PixImage image1 = array2PixImage(new int[][] { { 0, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 } }); System.out.println("Testing one-parameter RunLengthEncoding constuctor " + "on a 3x3 image. Input image:"); System.out.print(image1); RunLengthEncoding rle1 = new RunLengthEncoding(image1); rle1.check(); System.out.println("Testing getWidth/getHeight on a 3x3 encoding."); doTest(rle1.getWidth() == 3 && rle1.getHeight() == 3, "RLE1 has wrong dimensions"); System.out.println("Testing toPixImage() on a 3x3 encoding."); doTest(image1.equals(rle1.toPixImage()), "image1 -> RLE1 -> image does not reconstruct the original image"); System.out.println(rle1.toPixImage()); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 0, 0, 42); image1.setPixel(0, 0, (short) 42, (short) 42, (short) 42); doTest(rle1.toPixImage().equals(image1), /* array2PixImage(new int[][] { { 42, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 } })), */ "Setting RLE1[0][0] = 42 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 1, 0, 42); image1.setPixel(1, 0, (short) 42, (short) 42, (short) 42); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[1][0] = 42 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 0, 1, 2); image1.setPixel(0, 1, (short) 2, (short) 2, (short) 2); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[0][1] = 2 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 0, 0, 0); image1.setPixel(0, 0, (short) 0, (short) 0, (short) 0); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[0][0] = 0 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 2, 2, 7); image1.setPixel(2, 2, (short) 7, (short) 7, (short) 7); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[2][2] = 7 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 2, 2, 42); image1.setPixel(2, 2, (short) 42, (short) 42, (short) 42); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[2][2] = 42 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle1, 1, 2, 42); image1.setPixel(1, 2, (short) 42, (short) 42, (short) 42); doTest(rle1.toPixImage().equals(image1), "Setting RLE1[1][2] = 42 fails."); PixImage image2 = array2PixImage(new int[][] { { 2, 3, 5 }, { 2, 4, 5 }, { 3, 4, 6 } }); System.out.println("Testing one-parameter RunLengthEncoding constuctor " + "on another 3x3 image. Input image:"); System.out.print(image2); RunLengthEncoding rle2 = new RunLengthEncoding(image2); rle2.check(); System.out.println("Testing getWidth/getHeight on a 3x3 encoding."); doTest(rle2.getWidth() == 3 && rle2.getHeight() == 3, "RLE2 has wrong dimensions"); System.out.println("Testing toPixImage() on a 3x3 encoding."); doTest(rle2.toPixImage().equals(image2), "image2 -> RLE2 -> image does not reconstruct the original image"); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle2, 0, 1, 2); image2.setPixel(0, 1, (short) 2, (short) 2, (short) 2); doTest(rle2.toPixImage().equals(image2), "Setting RLE2[0][1] = 2 fails."); System.out.println("Testing setPixel() on a 3x3 encoding."); setAndCheckRLE(rle2, 2, 0, 2); image2.setPixel(2, 0, (short) 2, (short) 2, (short) 2); doTest(rle2.toPixImage().equals(image2), "Setting RLE2[2][0] = 2 fails."); PixImage image3 = array2PixImage(new int[][] { { 0, 5 }, { 1, 6 }, { 2, 7 }, { 3, 8 }, { 4, 9 } }); System.out.println("Testing one-parameter RunLengthEncoding constuctor " + "on a 5x2 image. Input image:"); System.out.print(image3); RunLengthEncoding rle3 = new RunLengthEncoding(image3); rle3.check(); System.out.println("Testing getWidth/getHeight on a 5x2 encoding."); doTest(rle3.getWidth() == 5 && rle3.getHeight() == 2, "RLE3 has wrong dimensions"); System.out.println("Testing toPixImage() on a 5x2 encoding."); doTest(rle3.toPixImage().equals(image3), "image3 -> RLE3 -> image does not reconstruct the original image"); System.out.println("Testing setPixel() on a 5x2 encoding."); setAndCheckRLE(rle3, 4, 0, 6); image3.setPixel(4, 0, (short) 6, (short) 6, (short) 6); doTest(rle3.toPixImage().equals(image3), "Setting RLE3[4][0] = 6 fails."); System.out.println("Testing setPixel() on a 5x2 encoding."); setAndCheckRLE(rle3, 0, 1, 6); image3.setPixel(0, 1, (short) 6, (short) 6, (short) 6); doTest(rle3.toPixImage().equals(image3), "Setting RLE3[0][1] = 6 fails."); System.out.println("Testing setPixel() on a 5x2 encoding."); setAndCheckRLE(rle3, 0, 0, 1); image3.setPixel(0, 0, (short) 1, (short) 1, (short) 1); doTest(rle3.toPixImage().equals(image3), "Setting RLE3[0][0] = 1 fails."); PixImage image4 = array2PixImage(new int[][] { { 0, 3 }, { 1, 4 }, { 2, 5 } }); System.out.println("Testing one-parameter RunLengthEncoding constuctor " + "on a 3x2 image. Input image:"); System.out.print(image4); RunLengthEncoding rle4 = new RunLengthEncoding(image4); rle4.check(); System.out.println("Testing getWidth/getHeight on a 3x2 encoding."); doTest(rle4.getWidth() == 3 && rle4.getHeight() == 2, "RLE4 has wrong dimensions"); System.out.println("Testing toPixImage() on a 3x2 encoding."); doTest(rle4.toPixImage().equals(image4), "image4 -> RLE4 -> image does not reconstruct the original image"); System.out.println("Testing setPixel() on a 3x2 encoding."); setAndCheckRLE(rle4, 2, 0, 0); image4.setPixel(2, 0, (short) 0, (short) 0, (short) 0); doTest(rle4.toPixImage().equals(image4), "Setting RLE4[2][0] = 0 fails."); System.out.println("Testing setPixel() on a 3x2 encoding."); setAndCheckRLE(rle4, 1, 0, 0); image4.setPixel(1, 0, (short) 0, (short) 0, (short) 0); doTest(rle4.toPixImage().equals(image4), "Setting RLE4[1][0] = 0 fails."); System.out.println("Testing setPixel() on a 3x2 encoding."); setAndCheckRLE(rle4, 1, 0, 1); image4.setPixel(1, 0, (short) 1, (short) 1, (short) 1); doTest(rle4.toPixImage().equals(image4), "Setting RLE4[1][0] = 1 fails."); } }
/* RunIterator.java */ /** * The RunIterator class iterates over a RunLengthEncoding and allows other * classes to inspect the runs in a run-length encoding, one run at a time. * A newly constructed RunIterator "points" to the first run in the encoding * used to construct it. Each time next() is invoked, it returns a run * (represented as an array of four ints); a sequence of calls to next() * returns run in consecutive order until every run has been returned. * * Client classes should never call the RunIterator constructor directly; * instead they should invoke the iterator() method on a RunLengthEncoding * object, which will construct a properly initialized RunIterator for the * client. * * Calls to hasNext() determine whether another run is available, or whether * the iterator has reached the end of the run-length encoding. When * a RunIterator reaches the end of an encoding, it is no longer useful, and * the next() method may throw an exception; thus it is recommended to check * hasNext() before each call to next(). To iterate through the encoding * again, construct a new RunIterator by invoking iterator() on the * RunLengthEncoding and throw the old RunIterator away. * * A RunIterator is not guaranteed to work if the underlying RunLengthEncoding * is modified after the RunIterator is constructed. (Especially if it is * modified by setPixel().) */ import java.util.Iterator; import java.util.NoSuchElementException; @SuppressWarnings("rawtypes") public class RunIterator implements Iterator { /** * Define any variables associated with a RunIterator object here. * These variables MUST be private. */ private DListNode1 current; /** * RunIterator() constructs a new iterator starting with a specified run. * * @param node the run where this iterator starts. */ // Unlike all the other methods we have asked you to write, the RunIterator() // constructor does not have a predefined signature, because no outside // class should ever call this constructor except the iterator() method in // the RunLengthEncoding class. The correct way for outside classes to // get access to a RunIterator is to call the iterator() method on a // RunLengthEncoding object. You are welcome to add any parameters to the // constructor that you want so that your RunLengthEncoding.iterator() // implementation can construct a RunIterator that points to the first run of // the encoding. RunIterator(DListNode1 itr) { current=itr; // Your solution here. You may add parameters to the method signature. } /** * hasNext() returns true if this iterator has more runs. If it returns * false, then the next call to next() may throw an exception. * * @return true if the iterator has more elements. */ public boolean hasNext() { if (current==null) return false; else return true;// Replace the following line with your solution. } /** * next() returns an array of 4 ints that specifies the current run in the * sequence. It also advances the iterator to the next run, so that the * next call to next() will return the following run. * * If "this" RunIterator has returned every run, it cannot be expected to * behave well. (Technically, it is supposed to throw a * NoSuchElementException, but we haven't learned about exceptions yet.) * * @return an array of 4 ints that specify the current run in the sequence. * The pixel count is in index [0]; the red value is in index [1]; the green * value is in index [2]; and the blue value is in index [3]. * @throws NoSuchElementException if the iteration has no more elements. * (We strongly recommend calling hasNext() to check whether there are any * more runs before calling next().) * * The returned four-int array is constructed in next(), and can be * discarded by the calling method after use. The array should not be part * of your RunLengthEncoding data structure! It must be freshly constructed * for the sole purpose of returning four ints. */ public int[] next() { int[] k= new int[4]; if(hasNext()){ k[0]=current.num; k[1]=current.red; k[2]=current.green; k[3]=current.blue; current=current.next;} return k; // Construct a new array of 4 ints, fill in its values, and return it. // Don't forget to advance the RunIterator's pointer so that the next // call to next() will return the subsequent run. // Replace the following line with your solution. } /** * remove() would remove from the underlying run-length encoding the run * identified by this iterator, but we are NOT implementing it. * * DO NOT CHANGE THIS METHOD. */ public void remove() { throw new UnsupportedOperationException(); } }
/* DListNode1.java */ /** * A DListNode1 is a node in a DList1 (doubly-linked list). */ public class DListNode1 { /** * item references the item stored in the current node. * prev references the previous node in the DList. * next references the next node in the DList. * * DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS. */ public int red; public int green; public int blue; public int num; int item; public DListNode1 prev; public DListNode1 next; /** * DListNode1() constructor. */ DListNode1() { red = 0; green=0; blue=0; num=0; prev = null; next = null; } DListNode1(int intensity,int num) { red = intensity; green=intensity; blue=intensity; this.num=num; prev = null; next = null; } DListNode1(int red,int green,int blue,int num){ this.red=red; this.green=green; this.blue=blue; this.num=num; prev = null; next = null; } }