private void CalculateDistance(ImageBuffer image) { var maxDist = (image.Height + image.Width) > 255 ? 255 : (image.Height + image.Width); var buffer = image.GetBuffer(); // O(n^2) solution to find the Manhattan distance to "on" pixels in a two dimension array // traverse from top left to bottom right for (int y = 0; y < image.Height; y++) { var yOffset = image.GetBufferOffsetY(y); for (int x = 0; x < image.Width; x++) { if (buffer[yOffset + x] == 0) { // first pass and pixel was off, it remains a zero } else { // pixel was on // It is at most the sum of the lengths of the array // away from a pixel that is off buffer[yOffset + x] = (byte)maxDist; // or one more than the pixel to the north if (x > 0) { var value = Math.Min(buffer[yOffset + x], buffer[yOffset + x - 1] + 1); buffer[yOffset + x] = (byte)value; } // or one more than the pixel to the west if (y > 0) { var value = Math.Min(buffer[yOffset + x], buffer[yOffset - image.Width + x] + 1); buffer[yOffset + x] = (byte)value; } } } } // traverse from bottom right to top left for (int y = image.Height - 1; y >= 0; y--) { var yOffset = image.GetBufferOffsetY(y); for (int x = image.Width - 1; x >= 0; x--) { // either what we had on the first pass // or one more than the pixel to the south if (x + 1 < image.Width) { var value = Math.Min(buffer[yOffset + x], buffer[yOffset + x + 1] + 1); buffer[yOffset + x] = (byte)value; } // or one more than the pixel to the east if (y + 1 < image.Height) { var value = Math.Min(buffer[yOffset + x], buffer[yOffset + image.Width + x] + 1); buffer[yOffset + x] = (byte)value; } } } }
public void CopyColorBufferToImage(ImageBuffer destImage, RectangleInt viewport) { if (destImage.BitDepth != 32) { throw new Exception("We can only render to 32 bit dest at the moment."); } Byte[] destBuffer = destImage.GetBuffer(); viewport.Bottom = Math.Max(0, Math.Min(destImage.Height, viewport.Bottom)); viewport.Top = Math.Max(0, Math.Min(destImage.Height, viewport.Top)); #if MULTI_THREAD System.Threading.Tasks.Parallel.For(viewport.Bottom, viewport.Height, y => // #else for (int y = viewport.Bottom; y < viewport.Height; y++) #endif { for (int x = viewport.Left; x < viewport.Right; x++) { int bufferOffset = destImage.GetBufferOffsetY(y); // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + x * 4; destBuffer[totalOffset++] = (byte)colorBuffer[x][y].Blue0To255; destBuffer[totalOffset++] = (byte)colorBuffer[x][y].Green0To255; destBuffer[totalOffset++] = (byte)colorBuffer[x][y].Red0To255; destBuffer[totalOffset] = (byte)colorBuffer[x][y].Alpha0To255; } }
public static ImageBuffer Multiply(this ImageBuffer sourceImage, RGBA_Bytes color) { var outputImage = new ImageBuffer(sourceImage); switch (outputImage.BitDepth) { case 32: int height = outputImage.Height; int width = outputImage.Width; byte[] imageABuffer = outputImage.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = outputImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { imageABuffer[offsetA + 0] = (byte)((imageABuffer[offsetA + 0] * color.blue) / 255); imageABuffer[offsetA + 1] = (byte)((imageABuffer[offsetA + 1] * color.green) / 255); imageABuffer[offsetA + 2] = (byte)((imageABuffer[offsetA + 2] * color.red) / 255); imageABuffer[offsetA + 3] = (byte)((imageABuffer[offsetA + 3] * color.alpha) / 255); offsetA += 4; } } break; default: throw new NotImplementedException(); } return(outputImage); }
public MarchingSquaresByte(ImageBuffer imageToMarch, PositiveArea0to1 thresholdFunction, int debugColor) { thersholdPerPixel = new double[imageToMarch.Width * imageToMarch.Height]; { byte[] buffer = imageToMarch.GetBuffer(); int strideInBytes = imageToMarch.StrideInBytes(); for (int y = 0; y < imageToMarch.Height; y++) { int imageBufferOffset = imageToMarch.GetBufferOffsetY(y); int thresholdBufferOffset = y * imageToMarch.Width; for (int x = 0; x < imageToMarch.Width; x++) { int imageBufferOffsetWithX = imageBufferOffset + x * 4; thersholdPerPixel[thresholdBufferOffset + x] = thresholdFunction(GetRGBA(buffer, imageBufferOffsetWithX)); } } } this.thresholdFunction = thresholdFunction; this.imageToMarch = imageToMarch; this.debugColor = debugColor; CreateLineSegments(); }
public void CopyNoramlBufferToImage(ImageBuffer destImage, RectangleInt viewport) { if (destImage.BitDepth != 32) { throw new Exception("We can only render to 32 bit dest at the moment."); } byte[] destBuffer = destImage.GetBuffer(); viewport.Bottom = Math.Max(0, Math.Min(destImage.Height, viewport.Bottom)); viewport.Top = Math.Max(0, Math.Min(destImage.Height, viewport.Top)); for (int y = viewport.Bottom; y < viewport.Height; y++) { for (int x = viewport.Left; x < viewport.Right; x++) { int bufferOffset = destImage.GetBufferOffsetY(y); // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + x * 4; destBuffer[totalOffset++] = (byte)((NormalBuffer[x][y].X + 1) * 128); destBuffer[totalOffset++] = (byte)((NormalBuffer[x][y].Y + 1) * 128); destBuffer[totalOffset++] = (byte)((NormalBuffer[x][y].Z + 1) * 128); destBuffer[totalOffset] = 255; } } destImage.MarkImageChanged(); }
internal static void DoXBlur(ImageBuffer sourceDest) { if (sourceDest.BitDepth != 8) { throw new NotImplementedException("We only work with 8 bit at the moment."); } int height = sourceDest.Height; int width = sourceDest.Width; byte[] buffer = sourceDest.GetBuffer(); byte[] cache = new byte[width]; for (int y = 0; y < height; y++) { int offset = sourceDest.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { cache[x] = buffer[offset + x]; } for (int x = 1; x < width - 1; x++) { int newValue = (cache[x - 1] + cache[x] * 2 + cache[x + 1] + 2) / 4; // the + 2 is so that we will round correctly buffer[offset + x] = (byte)newValue; } } }
public void BuildHistogramFromImage(ImageBuffer image, ImageToPathObject3D_2.AnalysisTypes analysisType) { // build the histogram cache var height = (int)(100 * GuiWidget.DeviceScale); _histogramRawCache = new ImageBuffer(256, height); var counts = new int[_histogramRawCache.Width]; IThresholdFunction function = new MapOnMaxIntensity(0, 1); var bottom = 0; if (analysisType == ImageToPathObject3D_2.AnalysisTypes.Colors) { function = new QuickHue(); bottom = (int)(10 * GuiWidget.DeviceScale); } byte[] buffer = image.GetBuffer(); for (int y = 0; y < image.Height; y++) { int imageBufferOffset = image.GetBufferOffsetY(y); for (int x = 0; x < image.Width; x++) { int imageBufferOffsetWithX = imageBufferOffset + x * 4; var color = GetRGBA(buffer, imageBufferOffsetWithX); counts[(int)(function.Transform(color) * (_histogramRawCache.Width - 1))]++; } } double max = counts.Select((value, index) => new { value, index }) .OrderByDescending(vi => vi.value) .First().value; var graphics = _histogramRawCache.NewGraphics2D(); var theme = ApplicationController.Instance.Theme; graphics.Clear(theme.SlightShade); var graphShape = new VertexStorage(); var graphHeight = height - bottom; graphShape.MoveTo(0, bottom); for (int i = 0; i < 256; i++) { graphShape.LineTo(i, bottom + Easing.Exponential.Out(counts[i] / max) * graphHeight); // graphShape.LineTo(i, bottom + Easing.Cubic.Out(counts[i] / max) * graphHeight); // graphShape.LineTo(i, bottom + Easing.Exponential.Out(counts[i] / max) * graphHeight); // graphShape.LineTo(i, bottom + counts[i] / max * graphHeight); } graphShape.LineTo(256, bottom); graphShape.LineTo(0, bottom); graphics.Render(graphShape, 0, 0, theme.TextColor); for (int i = 0; i < 256; i++) { var hue = ColorF.FromHSL(i / 255.0, 1, .49).ToColor(); graphics.Line(i, 0, i, bottom, hue); } }
public static ImageBuffer AnyAlphaToColor(this ImageBuffer sourceImage, Color color, Color transparency) { var outputImage = new ImageBuffer(sourceImage); switch (outputImage.BitDepth) { case 32: { int height = outputImage.Height; int width = outputImage.Width; byte[] imageABuffer = outputImage.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = outputImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { int alpha = imageABuffer[offsetA + 3]; if (alpha > 0) { // Set semi-transparent colors imageABuffer[offsetA + 0] = color.blue; imageABuffer[offsetA + 1] = color.green; imageABuffer[offsetA + 2] = color.red; //imageABuffer[offsetA + 3] = (byte) (alpha == 255 ? 255 : 255 - alpha); imageABuffer[offsetA + 3] = (byte)alpha; } else { // Set transparent colors imageABuffer[offsetA + 0] = transparency.blue; imageABuffer[offsetA + 1] = transparency.green; imageABuffer[offsetA + 2] = transparency.red; imageABuffer[offsetA + 3] = transparency.alpha; } offsetA += 4; } } //outputImage.SetRecieveBlender(new BlenderPreMultBGRA()); } break; default: throw new NotImplementedException(); } return(outputImage); }
public static void DoAllWhite(ImageBuffer result, ImageBuffer imageA) { if (imageA.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (imageA.Width != result.Width || imageA.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (imageA.BitDepth) { case 32: { int height = imageA.Height; int width = imageA.Width; byte[] resultBuffer = result.GetBuffer(); byte[] imageABuffer = imageA.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = imageA.GetBufferOffsetY(y); int offsetResult = result.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { int alpha = imageABuffer[offsetA + 3]; if (alpha > 0) { resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)alpha; offsetA++; } else { resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; } } } result.SetRecieveBlender(new BlenderPreMultBGRA()); } break; default: throw new NotImplementedException(); } }
private void CopyColorXSpan(ImageBuffer destImage, RectangleInt viewport, int y, byte[] destBuffer) { for (int x = viewport.Left; x < viewport.Right; x++) { int bufferOffset = destImage.GetBufferOffsetY(y); // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + x * 4; destBuffer[totalOffset++] = (byte)ColorBuffer[x][y].Blue0To255; destBuffer[totalOffset++] = (byte)ColorBuffer[x][y].Green0To255; destBuffer[totalOffset++] = (byte)ColorBuffer[x][y].Red0To255; destBuffer[totalOffset] = (byte)ColorBuffer[x][y].Alpha0To255; } }
public static void DoSubtract(ImageBuffer result, ImageBuffer imageToSubtractFrom, ImageBuffer imageToSubtract) { if (lookupSubtractAndClamp == null) { CreateLookup(); } if (imageToSubtractFrom.BitDepth != imageToSubtract.BitDepth || imageToSubtract.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (imageToSubtractFrom.Width != imageToSubtract.Width || imageToSubtractFrom.Height != imageToSubtract.Height || imageToSubtractFrom.Width != result.Width || imageToSubtractFrom.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (imageToSubtractFrom.BitDepth) { case 32: { int height = imageToSubtractFrom.Height; int width = imageToSubtractFrom.Width; byte[] resultBuffer = result.GetBuffer(); byte[] imageABuffer = imageToSubtractFrom.GetBuffer(); byte[] imageBBuffer = imageToSubtract.GetBuffer(); for (int y = 0; y < height; y++) { int offset = imageToSubtractFrom.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { resultBuffer[offset] = (byte)lookupSubtractAndClamp[imageABuffer[offset] - imageBBuffer[offset] + 255]; // add 255 to make sure not < 0 offset++; resultBuffer[offset] = (byte)lookupSubtractAndClamp[imageABuffer[offset] - imageBBuffer[offset] + 255]; offset++; resultBuffer[offset] = (byte)lookupSubtractAndClamp[imageABuffer[offset] - imageBBuffer[offset] + 255]; offset++; resultBuffer[offset] = 255; offset++; } } } break; default: throw new NotImplementedException(); } }
public static void DoSetGrayToColor(ImageBuffer result, ImageBuffer imageA, Color color) { if (imageA.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (imageA.Width != result.Width || imageA.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (imageA.BitDepth) { case 32: { int height = imageA.Height; int width = imageA.Width; byte[] resultBuffer = result.GetBuffer(); byte[] imageABuffer = imageA.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = imageA.GetBufferOffsetY(y); int offsetResult = result.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { imageA.GetPixel(x, y).ToColorF().GetHSL(out double _, out double s, out double _); if (s < .01) { resultBuffer[offsetResult++] = (byte)(color.blue); offsetA++; resultBuffer[offsetResult++] = (byte)(color.green); offsetA++; resultBuffer[offsetResult++] = (byte)(color.red); offsetA++; resultBuffer[offsetResult++] = imageABuffer[offsetA++]; } else { offsetResult += 4; offsetA += 4; } } } } break; default: throw new NotImplementedException(); } }
public static void DoThreshold(ImageBuffer result, ImageBuffer sourceImage, int threshold, TestThreshold testFunction) { if (sourceImage.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (sourceImage.Width != result.Width || sourceImage.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (sourceImage.BitDepth) { case 32: { int height = sourceImage.Height; int width = sourceImage.Width; byte[] resultBuffer = result.GetBuffer(); byte[] sourceBuffer = sourceImage.GetBuffer(); for (int y = 0; y < height; y++) { int offset = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { if (testFunction(sourceBuffer, offset, threshold)) { resultBuffer[offset + 0] = (byte)255; resultBuffer[offset + 1] = (byte)255; resultBuffer[offset + 2] = (byte)255; resultBuffer[offset + 3] = (byte)255; } else { resultBuffer[offset + 0] = (byte)0; resultBuffer[offset + 1] = (byte)0; resultBuffer[offset + 2] = (byte)0; resultBuffer[offset + 3] = (byte)0; } offset += 4; } } } break; default: throw new NotImplementedException(); } }
public static ImageBuffer ReplaceColor(this ImageBuffer sourceImage, Color existingColor, Color newColor, bool keepExistingAlpha = true) { var outputImage = new ImageBuffer(sourceImage); switch (outputImage.BitDepth) { case 32: { int height = outputImage.Height; int width = outputImage.Width; byte[] imageABuffer = outputImage.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = outputImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { if (imageABuffer[offsetA + 0] == existingColor.blue && imageABuffer[offsetA + 1] == existingColor.green && imageABuffer[offsetA + 2] == existingColor.red && imageABuffer[offsetA + 3] == existingColor.alpha) { // Set transparent colors imageABuffer[offsetA + 0] = newColor.blue; imageABuffer[offsetA + 1] = newColor.green; imageABuffer[offsetA + 2] = newColor.red; if (!keepExistingAlpha) { imageABuffer[offsetA + 3] = newColor.alpha; } } offsetA += 4; } } outputImage.SetRecieveBlender(new BlenderPreMultBGRA()); } break; default: throw new NotImplementedException(); } return(outputImage); }
public static ImageBuffer AllWhite(this ImageBuffer sourceImage) { var destImage = new ImageBuffer(sourceImage); switch (destImage.BitDepth) { case 32: { int height = destImage.Height; int width = destImage.Width; byte[] resultBuffer = sourceImage.GetBuffer(); byte[] imageABuffer = destImage.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = destImage.GetBufferOffsetY(y); int offsetResult = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { int alpha = imageABuffer[offsetA + 3]; if (alpha > 0) { resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)255; offsetA++; resultBuffer[offsetResult++] = (byte)alpha; offsetA++; } else { resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; resultBuffer[offsetResult++] = (byte)0; offsetA++; } } } destImage.SetRecieveBlender(new BlenderPreMultBGRA()); } break; default: throw new NotImplementedException(); } return(destImage); }
private void CopyDepthXSpan(ImageBuffer destImage, RectangleInt viewport, int y, byte[] destBuffer, double minZ, double divisor) { for (int x = viewport.Left; x < viewport.Right; x++) { int bufferOffset = destImage.GetBufferOffsetY(y); // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + x * 4; double depthXY = DepthBuffer[x][y]; double rangedDepth = (depthXY - minZ) / divisor; double clampedDepth = Math.Max(0, Math.Min(255, rangedDepth * 255)); byte depthColor = (byte)clampedDepth; destBuffer[totalOffset++] = depthColor; destBuffer[totalOffset++] = depthColor; destBuffer[totalOffset++] = depthColor; destBuffer[totalOffset] = 255; } }
private bool ColorDetected(ImageBuffer sourceImage, out double hueDetected) { byte[] sourceBuffer = sourceImage.GetBuffer(); var min = new Vector3(double.MaxValue, double.MaxValue, double.MaxValue); var max = new Vector3(double.MinValue, double.MinValue, double.MinValue); var hueCount = new int[10]; var colorPixels = 0; for (int y = 0; y < sourceImage.Height; y++) { int imageOffset = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < sourceImage.Width; x++) { int offset = imageOffset + x * 4; var b = sourceBuffer[offset + 0]; var g = sourceBuffer[offset + 1]; var r = sourceBuffer[offset + 2]; var color = new ColorF(r / 255.0, g / 255.0, b / 255.0); color.GetHSL(out double hue, out double saturation, out double lightness); min = Vector3.ComponentMin(min, new Vector3(hue, saturation, lightness)); max = Vector3.ComponentMax(max, new Vector3(hue, saturation, lightness)); if (saturation > .4 && lightness > .1 && lightness < .9) { hueCount[(int)(hue * 9)]++; colorPixels++; } } } if (colorPixels / (double)(sourceImage.Width * sourceImage.Height) > .1) { var indexAtMax = hueCount.ToList().IndexOf(hueCount.Max()); hueDetected = indexAtMax / 10.0; return(true); } hueDetected = 0; return(false); }
private void RebuildColorToAlphaImage(ImageBuffer sourceImage, ImageBuffer alphaImage, ImageBuffer displayImage) { if (sourceImage == null) { return; } // build the alpha image if (alphaImage == null) { alphaImage = new ImageBuffer(sourceImage.Width, sourceImage.Height); } else if (alphaImage.Width != sourceImage.Width || alphaImage.Height != sourceImage.Height) { alphaImage.Allocate(sourceImage.Width, sourceImage.Height, sourceImage.BitDepth, sourceImage.GetRecieveBlender()); } byte[] sourceBuffer = sourceImage.GetBuffer(); byte[] destBuffer = alphaImage.GetBuffer(); Parallel.For(0, sourceImage.Height, (y) => //for(int y = 0; y < sourceImage.Height; y++) { int imageOffset = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < sourceImage.Width; x++) { int imageBufferOffsetWithX = imageOffset + x * 4; var b = sourceBuffer[imageBufferOffsetWithX + 0]; var g = sourceBuffer[imageBufferOffsetWithX + 1]; var r = sourceBuffer[imageBufferOffsetWithX + 2]; destBuffer[imageBufferOffsetWithX + 0] = b; destBuffer[imageBufferOffsetWithX + 1] = g; destBuffer[imageBufferOffsetWithX + 2] = r; destBuffer[imageBufferOffsetWithX + 3] = GetAlphaFromHue(r, g, b, RangeStart, RangeEnd); } //} }); alphaImage.MarkImageChanged(); displayImage.CopyFrom(alphaImage); }
public static void DoInvertLightness(ImageBuffer result, ImageBuffer sourceImage) { if (sourceImage.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (sourceImage.Width != result.Width || sourceImage.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (sourceImage.BitDepth) { case 32: { int height = sourceImage.Height; int width = sourceImage.Width; byte[] resultBuffer = result.GetBuffer(); byte[] sourceBuffer = sourceImage.GetBuffer(); for (int y = 0; y < height; y++) { int offset = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { RGBA_Bytes color = new RGBA_Bytes(resultBuffer[offset + 2], resultBuffer[offset + 1], resultBuffer[offset + 0], resultBuffer[offset + 3]); RGBA_Bytes invertedColor = InvertColor(color); resultBuffer[offset + 0] = invertedColor.blue; resultBuffer[offset + 1] = invertedColor.green; resultBuffer[offset + 2] = invertedColor.blue; resultBuffer[offset + 3] = invertedColor.alpha; offset += 4; } } } break; default: throw new NotImplementedException(); } }
public static void DoMultiply(ImageBuffer result, ImageBuffer imageA, ImageBuffer imageB) { if (imageA.BitDepth != imageB.BitDepth || imageB.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (imageA.Width != imageB.Width || imageA.Height != imageB.Height || imageA.Width != result.Width || imageA.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (imageA.BitDepth) { case 32: { int height = imageA.Height; int width = imageA.Width; byte[] resultBuffer = result.GetBuffer(); byte[] imageABuffer = imageA.GetBuffer(); byte[] imageBBuffer = imageB.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = imageA.GetBufferOffsetY(y); int offsetB = imageB.GetBufferOffsetY(y); int offsetResult = result.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { resultBuffer[offsetResult++] = (byte)((imageABuffer[offsetA++] * imageBBuffer[offsetB++]) / 255); resultBuffer[offsetResult++] = (byte)((imageABuffer[offsetA++] * imageBBuffer[offsetB++]) / 255); resultBuffer[offsetResult++] = (byte)((imageABuffer[offsetA++] * imageBBuffer[offsetB++]) / 255); resultBuffer[offsetResult++] = 255; offsetA++; offsetB++; } } } break; default: throw new NotImplementedException(); } }
public static void DoWhiteToColor(ImageBuffer result, ImageBuffer imageA, RGBA_Bytes color) { if (imageA.BitDepth != result.BitDepth) { throw new NotImplementedException("All the images have to be the same bit depth."); } if (imageA.Width != result.Width || imageA.Height != result.Height) { throw new Exception("All images must be the same size."); } switch (imageA.BitDepth) { case 32: { int height = imageA.Height; int width = imageA.Width; byte[] resultBuffer = result.GetBuffer(); byte[] imageABuffer = imageA.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = imageA.GetBufferOffsetY(y); int offsetResult = result.GetBufferOffsetY(y); byte amoutOfWhite = imageABuffer[offsetA]; for (int x = 0; x < width; x++) { resultBuffer[offsetResult++] = (byte)(color.blue * amoutOfWhite / 255); offsetA++; resultBuffer[offsetResult++] = (byte)(color.green * amoutOfWhite / 255); offsetA++; resultBuffer[offsetResult++] = (byte)(color.red * amoutOfWhite / 255); offsetA++; resultBuffer[offsetResult++] = imageABuffer[offsetA++]; } } } break; default: throw new NotImplementedException(); } }
public static ImageBuffer AjustAlpha(this ImageBuffer sourceImage, double factor) { var outputImage = new ImageBuffer(sourceImage); switch (outputImage.BitDepth) { case 32: { int height = outputImage.Height; int width = outputImage.Width; byte[] imageABuffer = outputImage.GetBuffer(); for (int y = 0; y < height; y++) { int offsetA = outputImage.GetBufferOffsetY(y); for (int x = 0; x < width; x++) { var alpha = imageABuffer[offsetA + 3]; if (alpha > 0) { imageABuffer[offsetA + 3] = (byte)(alpha * factor); } offsetA += 4; } } outputImage.SetRecieveBlender(new BlenderPreMultBGRA()); } break; default: throw new NotImplementedException(); } return(outputImage); }
private void Paint(ImageBuffer dest, ImageBuffer source, int level) { int height = source.Height; int width = source.Width; int sourceStrideInBytes = source.StrideInBytes(); int destStrideInBytes = dest.StrideInBytes(); byte[] sourceBuffer = source.GetBuffer(); byte[] destBuffer = dest.GetBuffer(); for (int y = 1; y < height - 1; y++) { int offset = source.GetBufferOffsetY(y); for (int x = 1; x < width - 1; x++) { if (destBuffer[offset] == 255 && // the dest is white sourceBuffer[offset] == 0) // the dest is cleared { destBuffer[offset] = (byte)level; } offset++; } } }
public MarchingSquaresByte(ImageBuffer sourceImage, Color edgeColor, Func <Color, double> thresholdFunction, int debugColor) { // expand the image so we have a border around it (in case it goes to the edge) var imageToMarch = new ImageBuffer(sourceImage.Width + 2, sourceImage.Height + 2); imageToMarch.SetRecieveBlender(new BlenderBGRAExactCopy()); var graphics2D = imageToMarch.NewGraphics2D(); graphics2D.Clear(edgeColor); graphics2D.Render(sourceImage, 1, 1); thersholdPerPixel = new double[imageToMarch.Width * imageToMarch.Height]; { byte[] buffer = imageToMarch.GetBuffer(); int strideInBytes = imageToMarch.StrideInBytes(); for (int y = 0; y < imageToMarch.Height; y++) { int imageBufferOffset = imageToMarch.GetBufferOffsetY(y); int thresholdBufferOffset = y * imageToMarch.Width; for (int x = 0; x < imageToMarch.Width; x++) { int imageBufferOffsetWithX = imageBufferOffset + x * 4; var color = GetRGBA(buffer, imageBufferOffsetWithX); var thresholdValue = thresholdFunction(color); thersholdPerPixel[thresholdBufferOffset + x] = thresholdValue; } } } this.ThresholdFunction = thresholdFunction; this.imageToMarch = imageToMarch; this.debugColor = debugColor; CreateLineSegments(); }
private static void Copy8BitDataToImage(ImageBuffer destImage, Bitmap bitmap) { destImage.Allocate(bitmap.Width, bitmap.Height, bitmap.Width * 4, 32); if (destImage.GetRecieveBlender() == null) { destImage.SetRecieveBlender(new BlenderBGRA()); } BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat); int sourceIndex = 0; int destIndex = 0; unsafe { byte[] destBuffer = destImage.GetBuffer(out int offset); byte * pSourceBuffer = (byte *)bitmapData.Scan0; System.Drawing.Color[] colors = bitmap.Palette.Entries; for (int y = 0; y < destImage.Height; y++) { sourceIndex = y * bitmapData.Stride; destIndex = destImage.GetBufferOffsetY(destImage.Height - 1 - y); for (int x = 0; x < destImage.Width; x++) { System.Drawing.Color color = colors[pSourceBuffer[sourceIndex++]]; destBuffer[destIndex++] = color.B; destBuffer[destIndex++] = color.G; destBuffer[destIndex++] = color.R; destBuffer[destIndex++] = color.A; } } } bitmap.UnlockBits(bitmapData); }
private void RebuildIntensityToAlphaImage(ImageBuffer sourceImage, ImageBuffer alphaImage, ImageBuffer displayImage) { if (sourceImage == null) { return; } // build the alpha image if (alphaImage.Width != sourceImage.Width || alphaImage.Height != sourceImage.Height) { alphaImage.Allocate(sourceImage.Width, sourceImage.Height, sourceImage.BitDepth, sourceImage.GetRecieveBlender()); displayImage.Allocate(sourceImage.Width, sourceImage.Height, sourceImage.BitDepth, sourceImage.GetRecieveBlender()); } var startInt = (int)(RangeStart * 255); var endInt = (int)(RangeEnd * 255); var rangeInt = (int)Math.Max(1, (RangeEnd - RangeStart) * 255); byte GetAlphaFromIntensity(byte r, byte g, byte b) { // return (color.Red0To1 * 0.2989) + (color.Green0To1 * 0.1140) + (color.Blue0To1 * 0.5870); var alpha = (r * 76 + g * 29 + b * 150) / 255; if (alpha < startInt) { return(0); } else if (alpha > endInt) { return(0); } else { if (rangeInt > 64) { var s1 = 255 - Math.Min(255, ((alpha - startInt) * 255 / rangeInt)); return((byte)s1); } return(255); } } byte[] sourceBuffer = sourceImage.GetBuffer(); byte[] destBuffer = alphaImage.GetBuffer(); Parallel.For(0, sourceImage.Height, (y) => { int imageOffset = sourceImage.GetBufferOffsetY(y); for (int x = 0; x < sourceImage.Width; x++) { int imageBufferOffsetWithX = imageOffset + x * 4; var b = sourceBuffer[imageBufferOffsetWithX + 0]; var g = sourceBuffer[imageBufferOffsetWithX + 1]; var r = sourceBuffer[imageBufferOffsetWithX + 2]; var a = sourceBuffer[imageBufferOffsetWithX + 3]; destBuffer[imageBufferOffsetWithX + 0] = b; destBuffer[imageBufferOffsetWithX + 1] = g; destBuffer[imageBufferOffsetWithX + 2] = r; destBuffer[imageBufferOffsetWithX + 3] = (byte)(GetAlphaFromIntensity(r, g, b) * a / 255); } }); alphaImage.MarkImageChanged(); byte[] displayBuffer = displayImage.GetBuffer(); Parallel.For(0, sourceImage.Height, (y) => { int imageOffset = displayImage.GetBufferOffsetY(y); for (int x = 0; x < displayImage.Width; x++) { int imageBufferOffsetWithX = imageOffset + x * 4; displayBuffer[imageBufferOffsetWithX + 0] = destBuffer[imageBufferOffsetWithX + 0]; displayBuffer[imageBufferOffsetWithX + 1] = destBuffer[imageBufferOffsetWithX + 1]; displayBuffer[imageBufferOffsetWithX + 2] = destBuffer[imageBufferOffsetWithX + 2]; if (destBuffer[imageBufferOffsetWithX + 3] > 1) { displayBuffer[imageBufferOffsetWithX + 3] = 255; } else { displayBuffer[imageBufferOffsetWithX + 3] = 0; } } }); displayImage.MarkImageChanged(); }
void FindSubPixelPositions(ImageBuffer imageBuffer) { // find the subpixel center int imageWidth = imageBuffer.Width; int imageHeight = imageBuffer.Height; byte[] buffer = imageBuffer.GetBuffer(); foreach (ValidResponseData validResponse in validResponsesBotomToTopList) { Vector2 position = validResponse.position; int centerXInt = (int)(position.x + .5); int centerYInt = (int)(position.y + .5); int min = int.MaxValue; int max = int.MinValue; { for (int y = centerYInt - 5; y <= centerYInt + 5; y++) { int byteOffset = imageBuffer.GetBufferOffsetY(y); ValidResponseData[] totalResponseRow = allResponsesGrid.GetRow(y); for (int x = centerXInt - 5; x <= centerXInt + 5; x++) { int intensity = buffer[byteOffset + x]; if (intensity < min) { min = intensity; } if (intensity > max) { max = intensity; } } } } double center = (max - min) / 2 + min; double maxRange = (max - min) / 4; { double weight = 0; Vector2 accumulatedPosition = Vector2.Zero; for (int y = centerYInt - 5; y <= centerYInt + 5; y++) { int byteOffset = imageBuffer.GetBufferOffsetY(y); ValidResponseData[] totalResponseRow = allResponsesGrid.GetRow(y); for (int x = centerXInt - 5; x <= centerXInt + 5; x++) { int value = buffer[byteOffset + x]; double absDeltaFromCenter = Math.Abs(value - center); double contribution = 1 - (absDeltaFromCenter / maxRange); contribution = Math.Max(0, Math.Min(1, contribution)); double distScalling = Math.Min(1, Math.Max(0, 1 - ((new Vector2(x, y) - position).Length - 3) / 2)); contribution *= distScalling; weight += contribution; accumulatedPosition += new Vector2(x, y) * contribution; #if SHOW_SUB_PIXEL_LOGIC if (i == 4) { buffer[byteOffset + x] = (byte)(contribution * 255); } #endif } } validResponse.position = accumulatedPosition / weight; } } }
public static void DoErode3x3Binary(ImageBuffer source, ImageBuffer dest, int threshold) { if (source.Width != dest.Width || source.Height != dest.Height || source.StrideInBytes() != dest.StrideInBytes()) { throw new NotImplementedException("Source and Dest have to be the same size"); } switch (source.BitDepth) { case 8: { int height = source.Height; int width = source.Width; int strideInBytes = source.StrideInBytes(); byte[] sourceBuffer = source.GetBuffer(); byte[] destBuffer = dest.GetBuffer(); System.Threading.Tasks.Parallel.For(1, height, y => //for (int y = 1; y < height - 1; y++) { int rowOffset = source.GetBufferOffsetY(y); for (int x = 1; x < width - 1; x++) { int bufferOffset = rowOffset + x; // make sure it is set to 1 if we don't change it to 0 destBuffer[bufferOffset] = 255; // do the upper left int checkOffset = bufferOffset - strideInBytes - 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the upper center checkOffset = bufferOffset - strideInBytes + 0; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the upper right checkOffset = bufferOffset - strideInBytes + 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the center left checkOffset = bufferOffset + strideInBytes - 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the center center checkOffset = bufferOffset + strideInBytes + 0; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the lower right checkOffset = bufferOffset + strideInBytes + 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the lower left checkOffset = bufferOffset + strideInBytes - 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the lower center checkOffset = bufferOffset + strideInBytes + 0; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } // do the lower right checkOffset = bufferOffset + strideInBytes + 1; if (sourceBuffer[checkOffset] < threshold) { destBuffer[bufferOffset] = 0; continue; } } }); } break; case 32: { int height = source.Height; int width = source.Width; int sourceStrideInBytes = source.StrideInBytes(); int destStrideInBytes = dest.StrideInBytes(); byte[] sourceBuffer = source.GetBuffer(); byte[] destBuffer = dest.GetBuffer(); for (int destY = 1; destY < height - 1; destY++) { for (int destX = 1; destX < width - 1; destX++) { for (int sourceY = -1; sourceY <= 1; sourceY++) { for (int sourceX = -1; sourceX <= 1; sourceX++) { int sourceOffset = source.GetBufferOffsetXY(destX + sourceX, destY + sourceY); if (sourceBuffer[sourceOffset] < threshold) { int destOffset = dest.GetBufferOffsetXY(destX, destY); destBuffer[destOffset++] = 0; destBuffer[destOffset++] = 0; destBuffer[destOffset++] = 0; destBuffer[destOffset++] = 255; } } } } } } break; default: throw new NotImplementedException(); } }
public void RayTraceScene(ImageBuffer destImage, RectangleInt viewport, Scene scene) { int maxsamples = (int)AntiAliasing; //graphics2D.FillRectangle(viewport, RGBA_Floats.Black); if (imageBufferAsDoubles == null || imageBufferAsDoubles.Length < viewport.Width || imageBufferAsDoubles[0].Length < viewport.Height) { imageBufferAsDoubles = new RGBA_Floats[viewport.Width][]; for (int i = 0; i < viewport.Width; i++) { imageBufferAsDoubles[i] = new RGBA_Floats[viewport.Height]; } } if (destImage.BitDepth != 32) { throw new Exception("We can only render to 32 bit dest at the moment."); } Byte[] destBuffer = destImage.GetBuffer(); viewport.Bottom = Math.Max(0, Math.Min(destImage.Height, viewport.Bottom)); viewport.Top = Math.Max(0, Math.Min(destImage.Height, viewport.Top)); #if MULTI_THREAD System.Threading.Tasks.Parallel.For(viewport.Bottom, viewport.Height, y => // #else for (int y = viewport.Bottom; y < viewport.Height; y++) #endif { for (int x = viewport.Left; x < viewport.Right; x++) { if (traceWithRayBundles) { int width = Math.Min(8, viewport.Right - x); int height = Math.Min(8, viewport.Top - y); FrustumRayBundle rayBundle = new FrustumRayBundle(width * height); IntersectInfo[] intersectionsForBundle = new IntersectInfo[width * height]; for (int rayY = 0; rayY < height; rayY++) { for (int rayX = 0; rayX < width; rayX++) { rayBundle.rayArray[rayX + rayY * width] = scene.camera.GetRay(x + rayX, y + rayY); intersectionsForBundle[rayX + rayY * width] = new IntersectInfo(); } } rayBundle.CalculateFrustum(width, height, scene.camera.Origin); FullyTraceRayBundle(rayBundle, intersectionsForBundle, scene); for (int rayY = 0; rayY < height; rayY++) { int bufferOffset = destImage.GetBufferOffsetY(y + rayY); for (int rayX = 0; rayX < width; rayX++) { imageBufferAsDoubles[x + rayX][y + rayY] = intersectionsForBundle[rayX + rayY * width].totalColor; if (AntiAliasing == AntiAliasing.None) { // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + (x + rayX) * 4; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x + rayX][y + rayY].Blue0To255; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x + rayX][y + rayY].Green0To255; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x + rayX][y + rayY].Red0To255; destBuffer[totalOffset] = 255; } } } x += width - 1; // skip all the pixels we bundled y += height - 1; // skip all the pixels we bundled } else { int bufferOffset = destImage.GetBufferOffsetY(y); Ray ray = scene.camera.GetRay(x, y); imageBufferAsDoubles[x][y] = FullyTraceRay(ray, scene); // we don't need to set this if we are anti-aliased int totalOffset = bufferOffset + x * 4; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x][y].Blue0To255; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x][y].Green0To255; destBuffer[totalOffset++] = (byte)imageBufferAsDoubles[x][y].Red0To255; destBuffer[totalOffset] = 255; } } }