private void FilterWithCorrection(FastBitmapArray /*bitmap*/ array, int x, int y) { double red = array.GetRed(x, y); double green = array.GetGreen(x, y); double blue = array.GetBlue(x, y); double redNew = FilterRed(red, green, blue); double greenNew = FilterGreen(red, green, blue); double blueNew = FilterBlue(red, green, blue); if (redNew < 0) { redNew = 0; } else if (redNew > 1) { redNew = 1; } if (greenNew < 0) { greenNew = 0; } else if (greenNew > 1) { greenNew = 1; } if (blueNew < 0) { blueNew = 0; } else if (blueNew > 1) { blueNew = 1; } array.SetPixelBatch(x, y, redNew, greenNew, blueNew); }
public FastBitmapArray Process(FastBitmapArray array, ErrorDiffusionKernelName kernelName, int levelsCount) { if (levelsCount < 2) { throw new ArgumentException("at least 2 levels are needed"); } var processed = new FastBitmapArray(array.Width, array.Height); int levelsCountLess = levelsCount - 1; double[] levels = new double[levelsCount]; // upper bounds for all levels (except for the last level, cos this one is always 1.0) double[] levelsBounds = new double[levelsCountLess]; for (int i = 0; i < levelsCount; ++i) { levels[i] = ((double)i) / levelsCountLess; if (i > 0) { levelsBounds[i - 1] = (levels[i - 1] + levels[i]) / 2; } } var matrix = Matrices[kernelName]; var matrixSum = MatricesSums[kernelName]; var matrixWidth = matrix[0].Length; var matrixHeight = matrix.Length; var currentPixelX = (matrixWidth - 1) / 2; for (int y = 0; y < array.Height; ++y) { for (int x = 0; x < array.Width; ++x) { // get color value double red = array.GetRed(x, y); double green = array.GetGreen(x, y); double blue = array.GetBlue(x, y); // add error accumulated from previous pixels red += processed.GetRed(x, y); green += processed.GetGreen(x, y); blue += processed.GetBlue(x, y); // approximate double redApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (red < levelsBounds[i]) { redApprox = levels[i]; break; } } double greenApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (green < levelsBounds[i]) { greenApprox = levels[i]; break; } } double blueApprox = levels[levelsCountLess]; for (int i = 0; i < levelsCountLess; ++i) { if (blue < levelsBounds[i]) { blueApprox = levels[i]; break; } } // calculate error double redError = red - redApprox; double greenError = green - greenApprox; double blueError = blue - blueApprox; // set current pixel value processed.SetRedBatch(x, y, redApprox); processed.SetGreenBatch(x, y, greenApprox); processed.SetBlueBatch(x, y, blueApprox); // diffuse the arror accross other pixels for (int xx = 0; xx < matrixWidth; ++xx) { for (int yy = 0; yy < matrixHeight; ++yy) { if (yy == 0 && xx <= currentPixelX) { continue; } int xxx = x + xx - currentPixelX; int yyy = y + yy; if (xxx < 0 || xxx >= array.Width || yyy >= array.Height) { continue; } double level = ((double)matrix[yy][xx]) / matrixSum; processed.SetRedBatch(xxx, yyy, processed.GetRed(xxx, yyy) + redError * level); processed.SetGreenBatch(xxx, yyy, processed.GetGreen(xxx, yyy) + greenError * level); processed.SetBlueBatch(xxx, yyy, processed.GetBlue(xxx, yyy) + blueError * level); } } } } processed.SetBatchArea(); return(processed); }
/// <summary> /// Processes the input array. /// </summary> /// <param name="array"></param> /// <param name="matrixSize"></param> /// <returns></returns> public FastBitmapArray Process(FastBitmapArray array, int matrixSize, int levelsCount) { #region old approach //var processed = new FastBitmapArray(array.Width * matrixSize, array.Height * matrixSize); //int procXmin = 0; //int procXmax = 0; //int procYmin = 0; //int procYmax = 0; //var matrix = Matrices[matrixSize]; //var matrixCoef = matrixSize * matrixSize + 1; //for (int x = 0; x < array.Width; ++x) //{ // procXmin = x * matrixSize; // procXmax = procXmin + matrixSize; // for (int y = 0; y < array.Height; ++y) // { // double red = array.GetRed(x, y); // double green = array.GetGreen(x, y); // double blue = array.GetBlue(x, y); // procYmin = y * matrixSize; // procYmax = procYmin + matrixSize; // for (int xx = procXmin, xxx = 0; xx < procXmax; ++xx, ++xxx) // for (int yy = procYmin, yyy = 0; yy < procYmax; ++yy, ++yyy) // { // double matrixValue = ((double)matrix[xxx][yyy]) / matrixCoef; // processed.SetRed(xx, yy, red > matrixValue ? 1 : 0); // processed.SetGreen(xx, yy, green > matrixValue ? 1 : 0); // processed.SetBlue(xx, yy, blue > matrixValue ? 1 : 0); // } // } //} #endregion // new approach: var processed = new FastBitmapArray(array.Width, array.Height); int levelsCountLess = levelsCount - 1; var matrix = Matrices[matrixSize]; var matrixCoef = matrixSize * matrixSize + 1; double matrixLevel = 1.0 / levelsCountLess; double[] levels = new double[levelsCount]; // upper bounds for all levels (except for the last level, cos this one is always 1.0) double[] levelsBounds = new double[levelsCountLess]; for (int i = 0; i < levelsCount; ++i) { levels[i] = ((double)i) / levelsCountLess; if (i > 0) { levelsBounds[i - 1] = (levels[i - 1] + levels[i]) / 2; } if (i > 0 && i < levelsCount - 1) { levels[i] += 0.5 / (levelsCountLess * (matrixCoef - 1) + 1); } } int matrixX = 0; int matrixY = 0; for (int x = 0; x < array.Width; ++x) { for (int y = 0; y < array.Height; ++y) { double matrixValue = matrixLevel * ((double)matrix[matrixY][matrixX]) / matrixCoef; double red = array.GetRed(x, y); double green = array.GetGreen(x, y); double blue = array.GetBlue(x, y); // approximation double redApprox = processOnePixel(red, levels, levelsBounds, levelsCountLess, matrixValue); double greenApprox = processOnePixel(green, levels, levelsBounds, levelsCountLess, matrixValue); double blueApprox = processOnePixel(blue, levels, levelsBounds, levelsCountLess, matrixValue); processed.SetRedBatch(x, y, redApprox); processed.SetGreenBatch(x, y, greenApprox); processed.SetBlueBatch(x, y, blueApprox); ++matrixY; if (matrixY == matrixSize) { matrixY = 0; } } ++matrixX; if (matrixX == matrixSize) { matrixX = 0; } } processed.SetBatchArea(); return(processed); }