public Double CalculateMeanError(ImageBuffer target, Int32 parallelTaskCount = 4) { // checks parameters Guard.CheckNull(target, "target"); // initializes the error Int64 totalError = 0; // prepares the function TransformPixelFunction calculateMeanError = (sourcePixel, targetPixel) => { Color sourceColor = GetColorFromPixel(sourcePixel); Color targetColor = GetColorFromPixel(targetPixel); totalError += ColorModelHelper.GetColorEuclideanDistance(ColorModel.RedGreenBlue, sourceColor, targetColor); return(false); }; // performs the image scan, using a chosen method IList <Point> standardPath = new StandardPathProvider().GetPointPath(Width, Height); TransformPerPixel(target, standardPath, calculateMeanError, parallelTaskCount); // returns the calculates RMSD return(Math.Sqrt(totalError / (3.0 * Width * Height))); }
public void ChangeFormat(ImageBuffer target, IColorQuantizer quantizer, Int32 parallelTaskCount = 4) { // checks parameters Guard.CheckNull(target, "target"); Guard.CheckNull(quantizer, "quantizer"); // gathers some information about the target format Boolean hasSourceAlpha = PixelFormat.HasAlpha(); Boolean hasTargetAlpha = target.PixelFormat.HasAlpha(); Boolean isTargetIndexed = target.PixelFormat.IsIndexed(); Boolean isSourceDeepColor = PixelFormat.IsDeepColor(); Boolean isTargetDeepColor = target.PixelFormat.IsDeepColor(); // prepares the palette if needed if (isTargetIndexed) { // synthetises palette using provided quantizer List <Color> targetPalette = SynthetizePalette(quantizer, target.PixelFormat.GetColorCount(), parallelTaskCount); // updates the bitmap palette target.bitmap.SetPalette(targetPalette); target.UpdatePalette(true); } // prepares the quantization function TransformPixelFunction changeFormat = (passIndex, sourcePixel, targetPixel) => { // if both source and target formats are deep color formats, copies a value directly if (isSourceDeepColor && isTargetDeepColor) { //UInt64 value = sourcePixel.Value; //targetPixel.SetValue(value); } else { // retrieves a source image color Color color = sourcePixel.GetColor(); // if alpha is not present in the source image, but is present in the target, make one up if (!hasSourceAlpha && hasTargetAlpha) { Int32 argb = 255 << 24 | color.R << 16 | color.G << 8 | color.B; color = Color.FromArgb(argb); } // sets the color to a target pixel targetPixel.SetColor(color, quantizer); } // allows to write (obviously) the transformed pixel return(true); }; // generates the target image IList <Point> standardPath = new StandardPathProvider().GetPointPath(Width, Height); TransformPerPixelBase(target, standardPath, parallelTaskCount, changeFormat); }
public void TransformPerPixel(ImageBuffer target, IList<Point> path, TransformPixelFunction transformPixelFunction, Int32 parallelTaskCount = 4) { TransformPerPixelBase(target, path, transformPixelFunction, parallelTaskCount); }
public void Quantize(ImageBuffer target, IColorQuantizer quantizer, IColorDitherer ditherer, Int32 colorCount, Int32 parallelTaskCount = 4) { // checks parameters Guard.CheckNull(target, "target"); Guard.CheckNull(quantizer, "quantizer"); // initializes quantization parameters Boolean isTargetIndexed = target.PixelFormat.IsIndexed(); // step 1 - prepares the palettes List <Color> targetPalette = isTargetIndexed ? SynthetizePalette(quantizer, colorCount, parallelTaskCount) : null; // step 2 - updates the bitmap palette target.bitmap.SetPalette(targetPalette); target.UpdatePalette(true); // step 3 - prepares ditherer (optional) if (ditherer != null) { ditherer.Prepare(quantizer, colorCount, this, target); } // step 4 - prepares the quantization function TransformPixelFunction quantize = (sourcePixel, targetPixel) => { // reads the pixel color Color color = GetColorFromPixel(sourcePixel); // converts alpha to solid color color = QuantizationHelper.ConvertAlpha(color); // quantizes the pixel SetColorToPixel(targetPixel, color, quantizer); // marks pixel as processed by default Boolean result = true; // preforms inplace dithering (optional) if (ditherer != null && ditherer.IsInplace) { result = ditherer.ProcessPixel(sourcePixel, targetPixel); } // returns the result return(result); }; // step 5 - generates the target image IList <Point> path = quantizer.GetPointPath(Width, Height); TransformPerPixel(target, path, quantize, parallelTaskCount); // step 6 - preforms non-inplace dithering (optional) if (ditherer != null && !ditherer.IsInplace) { Dither(target, ditherer, quantizer, colorCount, 1); } // step 7 - finishes the dithering (optional) if (ditherer != null) { ditherer.Finish(); } // step 8 - clean-up quantizer.Finish(); }
public void TransformPerPixel(ImageBuffer target, IList <Point> path, TransformPixelFunction transformPixelFunction, Int32 parallelTaskCount = 4) { TransformPerPixelBase(target, path, transformPixelFunction, parallelTaskCount); }
private void TransformPerPixelBase(ImageBuffer target, IList <Point> path, Delegate transformAction, Int32 parallelTaskCount = 4) { // checks parameters Guard.CheckNull(path, "path"); Guard.CheckNull(target, "target"); Guard.CheckNull(transformAction, "transformAction"); // updates the palette UpdatePalette(); target.UpdatePalette(); // checks the dimensions if (Width != target.Width || Height != target.Height) { const String message = "Both images have to have the same dimensions."; throw new ArgumentOutOfRangeException(message); } // determines mode Boolean isAdvanced = transformAction is TransformPixelAdvancedFunction; // process the image in a parallel manner Action <LineTask> transformPerPixel = lineTask => { // creates individual pixel structures per task Pixel sourcePixel = new Pixel(this); Pixel targetPixel = new Pixel(target); // enumerates the pixels row by row for (Int32 pathOffset = lineTask.StartOffset; pathOffset < lineTask.EndOffset; pathOffset++) { Point point = path[pathOffset]; Boolean allowWrite; // enumerates the pixel, and returns the control to the outside sourcePixel.Update(point.X, point.Y); targetPixel.Update(point.X, point.Y); // when read is allowed, retrieves current value (in bytes) if (CanRead) { ReadPixel(sourcePixel); } if (target.CanRead) { target.ReadPixel(targetPixel); } // process the pixel by custom user operation if (isAdvanced) { TransformPixelAdvancedFunction transformAdvancedFunction = (TransformPixelAdvancedFunction)transformAction; allowWrite = transformAdvancedFunction(sourcePixel, targetPixel, this, target); } else // use simplified version with pixel parameters only { TransformPixelFunction transformFunction = (TransformPixelFunction)transformAction; allowWrite = transformFunction(sourcePixel, targetPixel); } // when write is allowed, copies the value back to the row buffer if (target.CanWrite && allowWrite) { target.WritePixel(targetPixel); } } }; // transforms image per pixel ProcessInParallel(path, transformPerPixel, parallelTaskCount); }
private void TransformPerPixelBase(ImageBuffer target, IList <Point> path = null, Int32 parallelTaskCount = 4, params Delegate[] passes) { // checks parameters Guard.CheckNull(target, "target"); Guard.CheckNull(passes, "passes"); // creates internal quantizer if needed UpdatePalette(); target.UpdatePalette(); // checks the dimensions if (Width != target.Width || Height != target.Height) { const String message = "Both images have to have the same dimensions."; throw new ArgumentOutOfRangeException(message); } // determines mode Boolean isAdvanced = passes.Length > 0 && passes[0] is TransformPixelAdvancedFunction; // creates default path, if none is available if (path == null) { path = StandardPathProvider.CreatePath(Width, Height); } // process the image in a parallel manner Action <LineTask> transformPerPixel = lineTask => { // creates individual pixel structures per task Pixel sourcePixel = CreatePixel(); Pixel targetPixel = target.CreatePixel(); Delegate pass = passes[lineTask.PassIndex]; // enumerates the pixels row by row for (Int32 pathOffset = lineTask.StartOffset; pathOffset < lineTask.EndOffset; pathOffset++) { Point point = path[pathOffset]; Boolean allowWrite; // enumerates the pixel, and returns the control to the outside sourcePixel.Update(point.X, point.Y); targetPixel.Update(point.X, point.Y); // when read is allowed, retrieves current value (in bytes) if (CanRead) { ReadPixel(sourcePixel); } if (target.CanRead) { target.ReadPixel(targetPixel); } // process the pixel by custom user operation if (isAdvanced) { TransformPixelAdvancedFunction transformAdvancedFunction = (TransformPixelAdvancedFunction)pass; allowWrite = transformAdvancedFunction(lineTask.PassIndex, sourcePixel, targetPixel, this, target); } else // use simplified version with pixel parameters only { TransformPixelFunction transformFunction = (TransformPixelFunction)pass; allowWrite = transformFunction(lineTask.PassIndex, sourcePixel, targetPixel); } // when write is allowed, copies the value back to the row buffer if (target.CanWrite && allowWrite) { target.WritePixel(targetPixel); } } }; // transforms image per pixel for (Int32 passIndex = 0; passIndex < passes.Length; passIndex++) { ProcessInParallel(passIndex, transformPerPixel, path, parallelTaskCount); } }