//this helper function returns a new PixImage with pixels on the edges reflected across the axis //so that each pixel in the original image has 9 neighbors (including itself) private PixImage GetReflection() { var newMatrix = new PixImage(Width + 2, Height + 2); for (int x = 1; x < newMatrix.Width - 1; x++) { for (int y = 1; y < newMatrix.Height - 1; y++) { newMatrix.setPixel(x, y, this.getRed(x - 1, y - 1), this.getGreen(x - 1, y - 1), this.getBlue(x - 1, y - 1)); } } for (int x = 0; x < newMatrix.Width; x++) { for (int y = 0; y < newMatrix.Height; y++) { int a = x; int b = y; short red = 0; if (x == 0) { a = 1; } if (y == 0) { b = 1; } if (x == newMatrix.Width - 1) { a = newMatrix.Width - 2; } if (y == newMatrix.Height - 1) { b = newMatrix.Height - 2; } red = (short)newMatrix.getRed(a, b); //Console.WriteLine("getting a: {0}, b: {1}, for x: {2}, y: {3} which is: {4}", a, b, x, y, red); newMatrix.setPixel(x, y, red, red, red); } } //Console.WriteLine(newMatrix); return(newMatrix); }
private PixImage GetSubImage(int x, int y, int width, int height) { PixImage newImage = new PixImage(width, height); for (int i = x; i < x + width; i++) { for (int j = y; j < y + height; j++) { newImage.setPixel(i - x, j - y, this.getRed(i, j), this.getGreen(i, j), this.getBlue(i, j)); } } return(newImage); }
/// <summary> /// array2PixImage() converts a 2D array of grayscale intensities to /// a grayscale PixImage. /// </summary> /// <param name="pixels"> a 2D array of grayscale intensities in the range 0...255. </param> /// <returns> a new PixImage whose red, green, and blue values are equal to /// the input grayscale intensities. </returns> 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); }
/// <summary> /// 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. /// </summary> /// <returns> a grayscale PixImage representing the edges of the input image. /// Whiter pixels represent stronger edges. </returns> public virtual PixImage SobelEdges() { var newImage = new PixImage(this.Width, this.Height); //constant, Sobel operator int[,] xSobelOperator = { { 1, 0, -1 }, { 2, 0, -2 }, { 1, 0, -1 } }; //constant, Sobel operator int[,] ySobelOperator = { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }; int[] gx, gy; long[,] energy = new long[Width, Height]; //get reflection so every pixel within the original image has 9 neighbors (incl itself) var newImageWithReflection = this.GetReflection(); //traverse each pixel within original image and calculate dot product for (int i = 0; i < Width; i++) { for (int j = 0; j < Height; j++) { //get subimage for each pixel (from newImageWithReflection) var image = newImageWithReflection.GetSubImage(i, j, 3, 3); //calculate dot product with x and y sobel operators gx = image.DotProduct(xSobelOperator); gy = image.DotProduct(ySobelOperator); //calculate energy values energy[i, j] = (gx[0] * gx[0]) + (gy[0] * gy[0]) + (gx[1] * gx[1]) + (gy[1] * gy[1]) + (gx[2] * gx[2]) + (gy[2] * gy[2]); newImage.setPixel(i, j, mag2gray(energy[i, j]), mag2gray(energy[i, j]), mag2gray(energy[i, j])); } } return(newImage); }
/// <summary> /// 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 C# 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. /// </summary> /// <param name="numIterations"> the number of iterations of box blurring. </param> /// <returns> a blurred version of "this" PixImage. </returns> public virtual PixImage BoxBlur(int numIterations) { if (numIterations > 0) { //make a new image var newImage = new PixImage(this.Width, this.Height); for (int i = 0; i < this.Width; i++) { for (int j = 0; j < this.Height; j++) { Pixel newPixel = this.GetBlurredPixel(i, j); newImage.setPixel(i, j, newPixel.Red, newPixel.Green, newPixel.Blue); // Console.WriteLine("At pixel {0},{1}: {2}, {3}, {4}. Counter: {5}", i, j, red, green, blue, counter); } } for (int n = 0; n < numIterations; n++) { newImage = newImage.BoxBlur(n); } return(newImage); } return(this); }