/// <summary> /// given a location of a pixel (x,y), returns the info about that pixel. /// </summary> /// <param name="i"></param> /// <param name="j"></param> /// <param name="imageDataArray"></param> /// <param name="injectedContext"></param> /// <returns></returns> public pixel getPixelInfo(int i, int j, byte[] imageDataArray, SeamCarvingContext injectedContext) { byte[] red = { 0, 0, 0, this.getPixel(imageDataArray, i, j, 0, injectedContext) }; byte[] green = { 0, 0, 0, this.getPixel(imageDataArray, i, j, 1, injectedContext) }; byte[] blue = { 0, 0, 0, this.getPixel(imageDataArray, i, j, 2, injectedContext) }; byte[] alpha = { 0, 0, 0, this.getPixel(imageDataArray, i, j, 3, injectedContext) }; if (BitConverter.IsLittleEndian) { Array.Reverse(red); Array.Reverse(green); Array.Reverse(blue); Array.Reverse(alpha); } int redInt = BitConverter.ToInt32(red, 0); int greenInt = BitConverter.ToInt32(green, 0); int blueInt = BitConverter.ToInt32(blue, 0); int alphaInt = BitConverter.ToInt32(alpha, 0); pixel toReturn = new pixel(); toReturn.red = redInt; toReturn.green = greenInt; toReturn.blue = blueInt; toReturn.alpha = alphaInt; return toReturn; }
/// <summary> /// takes a given bitmapImage and copies it into a new byte array and returns it. /// </summary> /// <param name="img"></param> /// <param name="injectedContext"></param> /// <returns></returns> public byte[] ImageToByte(BitmapImage toCopy, SeamCarvingContext injectedContext) { injectedContext.stride = toCopy.PixelWidth * 4; int size = toCopy.PixelHeight * injectedContext.stride; byte[] pixels = new byte[size]; toCopy.CopyPixels(pixels, injectedContext.stride, 0); return pixels; }
/// <summary> /// find the minimum index in the right most column of a two dimensional array represented as a one dimensional array /// </summary> /// <param name="arr"></param> /// <param name="injectedContext"></param> /// <returns></returns> public int findMinIndex(int[] arr, SeamCarvingContext injectedContext) { int lowest = Int32.MaxValue; int toReturn = 0; for (int i = 0; i < injectedContext.Height; i++) { int current = this.getIndex(arr, i, (int)injectedContext.Width - 2, injectedContext); if (current < lowest) { lowest = current; toReturn = i; } } return toReturn; }
/// <summary> /// /// </summary> /// <param name="injectedContext"></param> public void calculateSeam(SeamCarvingContext injectedContext) { injectedContext.dirtyArray = new int[injectedContext.energy.Length]; int j = this.seamUtilities.findMinIndex(injectedContext.energy, injectedContext); for (int i = (int)injectedContext.Width - 2; i >= 0; i--) { if (j == 0) { j += 1; } int up = this.seamUtilities.getIndex(injectedContext.energy, j + 1, i, injectedContext); int lat = this.seamUtilities.getIndex(injectedContext.energy, j, i, injectedContext); int down = this.seamUtilities.getIndex(injectedContext.energy, j - 1, i, injectedContext); if (up < lat && up < down) { seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 2, 0xff, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 1, 0x00, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 0, 0x00, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 3, 0xff, injectedContext); this.seamUtilities.setIndex(injectedContext.dirtyArray, j, i, 1, injectedContext); j = j + 1; } else if (lat < down && lat < up) { seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 2, 0xff, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 1, 0x00, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 3, 0xff, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 0, 0x00, injectedContext); this.seamUtilities.setIndex(injectedContext.dirtyArray, j, i, 1, injectedContext); } else { seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 2, 0xff, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 3, 0xff, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 1, 0x00, injectedContext); seamUtilities.setPixel(injectedContext.imageDataArray, j, i, 0, 0x00, injectedContext); this.seamUtilities.setIndex(injectedContext.dirtyArray, j, i, 1, injectedContext); j = j - 1; } } }
/// <summary> /// given a seam carving context, calculates the gradient of every pixel. /// </summary> /// <param name="injectedContext"></param> public void calculateGradient(SeamCarvingContext injectedContext) { injectedContext.gradientArray = new byte[injectedContext.imageDataArray.Length]; for (int i = 1; i < injectedContext.Height - 1; i++) { for (int j = 1; j < injectedContext.Width - 1; j++) { pixel last = seamUtilities.getPixelInfo(i, j - 1, injectedContext.imageDataArray, injectedContext); pixel current = seamUtilities.getPixelInfo(i, j, injectedContext.imageDataArray, injectedContext); pixel next = seamUtilities.getPixelInfo(i, j + 1, injectedContext.imageDataArray, injectedContext); byte gradient = calculateGradientOfPixel(last, current, next); seamUtilities.setPixel(injectedContext.gradientArray, i, j, 0, gradient, injectedContext); seamUtilities.setPixel(injectedContext.gradientArray, i, j, 1, gradient, injectedContext); seamUtilities.setPixel(injectedContext.gradientArray, i, j, 2, gradient, injectedContext); seamUtilities.setPixel(injectedContext.gradientArray, i, j, 3, 0xff, injectedContext); } } }
/// <summary> /// calculates the heatmap of the given seam carving context /// </summary> /// <param name="injectedContext"></param> public void calculateHeat(SeamCarvingContext injectedContext) { injectedContext.energyArray = injectedContext.gradientArray; injectedContext.energy = new int[injectedContext.gradientArray.Length / 4]; for (int i = 0; i < injectedContext.Height; i++) { byte current = this.seamUtilities.getPixel(injectedContext.gradientArray, i, 0, 0, injectedContext); this.seamUtilities.setIndex(injectedContext.energy, i, 0, (int)current, injectedContext); } for (int i = 1; i < injectedContext.Width - 1; i++) { for (int j = 0; j < injectedContext.Height; j++) { if (j == 0 || j == (injectedContext.Height - 1)) { this.seamUtilities.setIndex(injectedContext.energy, j, i, Int32.MaxValue, injectedContext); } else { int current = (int)this.seamUtilities.getPixel(injectedContext.gradientArray, j, i, 0, injectedContext); int neg = this.seamUtilities.getIndex(injectedContext.energy, j - 1, i - 1, injectedContext); int lat = this.seamUtilities.getIndex(injectedContext.energy, j, i - 1, injectedContext); int pos = this.seamUtilities.getIndex(injectedContext.energy, j + 1, i - 1, injectedContext); int least = (Math.Min(Math.Min(neg, lat), pos)); int toSet = current + least; int maxVal = 255 * (int)injectedContext.Width; this.seamUtilities.setIndex(injectedContext.energy, j, i, (current + least), injectedContext); double ratio = (((double)toSet) / ((double)maxVal)) * 128; byte pixelValue = (byte)(ratio * 256); this.seamUtilities.setPixel(injectedContext.energyArray, j, i, 0, pixelValue, injectedContext); this.seamUtilities.setPixel(injectedContext.energyArray, j, i, 1, pixelValue, injectedContext); this.seamUtilities.setPixel(injectedContext.energyArray, j, i, 2, pixelValue, injectedContext); } } } }
/// <summary> /// gets the pixel value from a given byte array at location (x,y) with the given color. /// </summary> /// <param name="arr"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> /// <returns></returns> public byte getPixel(byte[] arr, int x, int y, int color, SeamCarvingContext context) { int index = (int)context.Width * 4 * x + y * 4; return arr[index + color]; }
/// <summary> /// sets the pixel value in the given byte array at location (x,y) with the given color to the given value. /// </summary> /// <param name="arr"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="color"></param> /// <param name="toSet"></param> public void setPixel(byte[] arr, int x, int y, int color, byte toSet, SeamCarvingContext context) { int index = (int)context.Width * 4 * x + y * 4; arr[index + color] = toSet; }
/// <summary> /// get index form the given array. /// </summary> /// <param name="arr"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="injectedContext"></param> /// <returns></returns> public int getIndex(int[] arr, int x, int y, SeamCarvingContext injectedContext) { int index = x * (int)injectedContext.Width + y; return arr[index]; }
/// <summary> /// set index of pixel in array /// </summary> /// <param name="arr"></param> /// <param name="x"></param> /// <param name="y"></param> /// <param name="toSet"></param> /// <param name="injectedContext"></param> public void setIndex(int[] arr, int x, int y, int toSet, SeamCarvingContext injectedContext) { int index = x * (int)injectedContext.Width + y; arr[index] = toSet; }