public FractalCompressionResult Compress(CustomImage image) { //Validate the image and the params if (image.Width % _options.RSquareSize > 0 || image.Height % _options.RSquareSize > 0 || _options.DSquareSize % _options.RSquareSize > 0) { throw new InvalidOperationException("The compression options specified can't compress this image as the R squares size is not a divisor of height and width. Ri Sizes must be divisor of Di sizes too."); } object finalResultLock = new object(); int rXCount = image.Width / _options.RSquareSize; //Number of R Squares in X int rYCount = image.Height / _options.RSquareSize; //Number of R Squares in Y int totalRCount = rXCount * rYCount; int maxDxPos = image.Width - _options.DSquareSize + 1; // POP: Ici, le coin supérieur droit du carré ne se rend pas au coin supérieur droit de l'image int maxDyPos = image.Height - _options.DSquareSize + 1; // POP: même commentaire mais avec le coin inférieur gauche byte dSize = _options.DSquareSize; byte rSize = _options.RSquareSize; int n = _options.RSquareSize * _options.RSquareSize; double drRatio = (double)_options.RSquareSize / (double)_options.DSquareSize; int drInverseRatio = _options.DSquareSize / _options.RSquareSize; double pixelAverageSquareSize = (double)drInverseRatio * (double)drInverseRatio; var translateMatrixes = GetTranslateMatrixes(_options.RSquareSize); int transformationsCount = _transformMatrixes.Length; var transformations = new FractalCompressionResult.FractalTransformation[totalRCount, 3]; //Transformations (2 dimension to keep transformations for each ri in each color component) int rx; double finalRmsY = Double.MaxValue, finalRmsI = Double.MaxValue, finalRmsQ = Double.MaxValue, bestBrightnessY = 0d, bestContrastY = 0d, bestBrightnessI = 0d, bestContrastI = 0d, bestBrightnessQ = 0d, bestContrastQ = 0d; var rawImgData = image.ImageData; var imgDataY = new double[image.Width, image.Height]; var imgDataI = new double[image.Width, image.Height]; var imgDataQ = new double[image.Width, image.Height]; double[, ][][,] tempDiY = new double[maxDxPos, maxDyPos][][, ]; double[, ][][,] tempDiI = new double[maxDxPos, maxDyPos][][, ]; double[, ][][,] tempDiQ = new double[maxDxPos, maxDyPos][][, ]; double[,] sumsOfAY = new double[maxDxPos, maxDyPos]; double[,] sumsOfAYSquared = new double[maxDxPos, maxDyPos]; double[,] sumsOfAI = new double[maxDxPos, maxDyPos]; double[,] sumsOfAISquared = new double[maxDxPos, maxDyPos]; double[,] sumsOfAQ = new double[maxDxPos, maxDyPos]; double[,] sumsOfAQSquared = new double[maxDxPos, maxDyPos]; //Fill imgData Y, I and Q Parallel.For(0, image.Width, dx => { for (int dy = 0; dy < image.Height; dy++) { imgDataY[dx, dy] = rawImgData[dx, dy].YNormalized; imgDataI[dx, dy] = rawImgData[dx, dy].IDownSampledAndNormalized; imgDataQ[dx, dy] = rawImgData[dx, dy].QDownSampledAndNormalized; } }); //Average pixels of each Di to size of Ri Parallel.For(0, maxDxPos, dx => { int i, x, y, j, k, newX, newY, indexX = 0, indexY = 0; double[,] tempTransformMatrix; double[] tempTranslateMatrix; double[,] tempPixelY1 = null; double[,] tempPixelI1 = null; double[,] tempPixelQ1 = null; double tempSumY = 0d, tempSumI = 0d, tempSumQ = 0d, tempAveragePixelY = 0d, tempAveragePixelI = 0d, tempAveragePixelQ = 0d; for (int dy = 0; dy < maxDyPos; dy++) { tempDiY[dx, dy] = new double[transformationsCount][, ]; tempDiI[dx, dy] = new double[transformationsCount][, ]; tempDiQ[dx, dy] = new double[transformationsCount][, ]; for (i = 0; i < transformationsCount; i++) { for (x = 0; x < dSize; x += drInverseRatio) //Increment of inverse ratio to get only parts of Di { for (y = 0; y < dSize; y += drInverseRatio) { //Get transformation tempTransformMatrix = _transformMatrixes[i]; tempTranslateMatrix = translateMatrixes[i]; //Average pixels on first transform if (i == 0) { //Reset temp variables tempSumY = 0; tempSumI = 0; tempSumQ = 0; tempPixelY1 = new double[rSize, rSize]; tempPixelI1 = new double[rSize, rSize]; tempPixelQ1 = new double[rSize, rSize]; //Average pixels for (j = 0; j < drInverseRatio; j++) { for (k = 0; k < drInverseRatio; k++) { tempSumY += imgDataY[dx + x + j, dy + y + k]; tempSumI += imgDataI[dx + x + j, dy + y + k]; tempSumQ += imgDataQ[dx + x + j, dy + y + k]; } } //Calculating average Pixel Components tempAveragePixelY = tempSumY > 0 ? tempSumY / pixelAverageSquareSize : 0d; tempAveragePixelI = tempSumI > 0 ? tempSumI / pixelAverageSquareSize : 0d; tempAveragePixelQ = tempSumQ > 0 ? tempSumQ / pixelAverageSquareSize : 0d; //Sum of "a" and "a^2" for future RMS calculation sumsOfAY[dx, dy] += tempAveragePixelY; sumsOfAI[dx, dy] += tempAveragePixelI; sumsOfAQ[dx, dy] += tempAveragePixelQ; sumsOfAYSquared[dx, dy] += tempAveragePixelY * tempAveragePixelY; sumsOfAISquared[dx, dy] += tempAveragePixelI * tempAveragePixelI; sumsOfAQSquared[dx, dy] += tempAveragePixelQ * tempAveragePixelQ; } newX = (byte)(tempTransformMatrix[0, 0] * (x / drInverseRatio) + tempTransformMatrix[0, 1] * (y / drInverseRatio) + tempTranslateMatrix[0]); newY = (byte)(tempTransformMatrix[1, 0] * (x / drInverseRatio) + tempTransformMatrix[1, 1] * (y / drInverseRatio) + tempTranslateMatrix[1]); indexX = (int)(newX * drRatio); indexY = (int)(newY * drRatio); //Store pixel components for transformed Di (Fi) tempPixelY1[indexX, indexY] = tempAveragePixelY; tempPixelI1[indexX, indexY] = tempAveragePixelI; tempPixelQ1[indexX, indexY] = tempAveragePixelQ; //Store pixels of Di tempDiY[dx, dy][i] = tempPixelY1; tempDiI[dx, dy][i] = tempPixelI1; tempDiQ[dx, dy][i] = tempPixelQ1; } } } } }); //Find the Transformations to do... //For each Ri for (rx = 0; rx < rXCount; rx++) { //Parallel execution of for loop, so it runs faster. Parallel.For(0, rYCount, ry => { //Calculate the sums of components in Ri for future RMS metric calculation double sumOfBY = 0d; double sumOfBYSquared = 0d; double sumOfBI = 0d; double sumOfBISquared = 0d; double sumOfBQ = 0d; double sumOfBQSquared = 0d; double sumOfAAndBY; double sumOfAAndBI; double sumOfAAndBQ; int x, y, indexX, indexY, dx, dy, i, bestRmsYIndexX = -1, bestRmsYIndexY = -1, bestRmsYTransformationIndex = -1, bestRmsIIndexX = -1, bestRmsIIndexY = -1, bestRmsITransformationIndex = -1, bestRmsQIndexX = -1, bestRmsQIndexY = -1, bestRmsQTransformationIndex = -1; double[,] tempPixelY = null; double[,] tempPixelI = null; double[,] tempPixelQ = null; double tempContrastY, tempBrightnessY, tempContrastI, tempBrightnessI, tempContrastQ, tempBrightnessQ, tempRmsY, tempRmsI, tempRmsQ; for (x = 0; x < rSize; x++) { for (y = 0; y < rSize; y++) { //Sum of "b" and of "b^2" indexX = rx * rSize + x; indexY = ry * rSize + y; sumOfBY += imgDataY[indexX, indexY]; sumOfBI += imgDataI[indexX, indexY]; sumOfBQ += imgDataQ[indexX, indexY]; sumOfBYSquared += imgDataY[indexX, indexY] * imgDataY[indexX, indexY]; sumOfBISquared += imgDataI[indexX, indexY] * imgDataI[indexX, indexY]; sumOfBQSquared += imgDataQ[indexX, indexY] * imgDataQ[indexX, indexY]; } } //For Each Di using (var timer = new CustomTimer("Transformation")) for (dx = 0; dx < maxDxPos; dx++) { for (dy = 0; dy < maxDyPos; dy++) { //For Each possible transformations for (i = 0; i < transformationsCount; i++) { sumOfAAndBY = 0d; sumOfAAndBI = 0d; sumOfAAndBQ = 0d; tempPixelY = tempDiY[dx, dy][i]; tempPixelI = tempDiI[dx, dy][i]; tempPixelQ = tempDiQ[dx, dy][i]; //Compute sums necessary for calculating RMS metric for (x = 0; x < rSize; x++) { for (y = 0; y < rSize; y++) { //Calculate indexX and indexY indexX = dx + x; indexY = dy + y; //Sum of "a*b" sumOfAAndBY += tempPixelY[x, y] * imgDataY[indexX, indexY]; sumOfAAndBI += tempPixelI[x, y] * imgDataI[indexX, indexY]; sumOfAAndBQ += tempPixelQ[x, y] * imgDataQ[indexX, indexY]; } } //Compute contrast, brightness and RMS metric tempContrastY = (n * sumOfAAndBY - sumsOfAY[dx, dy] * sumOfBY) / (n * sumsOfAYSquared[dx, dy] - Math.Pow(sumsOfAY[dx, dy], 2)); tempContrastI = (n * sumOfAAndBI - sumsOfAI[dx, dy] * sumOfBI) / (n * sumsOfAISquared[dx, dy] - Math.Pow(sumsOfAI[dx, dy], 2)); tempContrastQ = (n * sumOfAAndBQ - sumsOfAQ[dx, dy] * sumOfBQ) / (n * sumsOfAQSquared[dx, dy] - Math.Pow(sumsOfAQ[dx, dy], 2)); tempBrightnessY = (1d / n) * (sumOfBY - tempContrastY * sumsOfAY[dx, dy]); tempBrightnessI = (1d / n) * (sumOfBI - tempContrastI * sumsOfAI[dx, dy]); tempBrightnessQ = (1d / n) * (sumOfBQ - tempContrastQ * sumsOfAQ[dx, dy]); tempRmsY = (1d / n) * (sumOfBYSquared + tempContrastY * (tempContrastY * sumsOfAYSquared[dx, dy] - 2 * sumOfAAndBY + 2 * tempBrightnessY * sumsOfAY[dx, dy]) + tempBrightnessY * (n * tempBrightnessY - 2 * sumOfBY)); tempRmsI = (1d / n) * (sumOfBISquared + tempContrastI * (tempContrastI * sumsOfAISquared[dx, dy] - 2 * sumOfAAndBI + 2 * tempBrightnessI * sumsOfAI[dx, dy]) + tempBrightnessI * (n * tempBrightnessI - 2 * sumOfBI)); tempRmsQ = (1d / n) * (sumOfBQSquared + tempContrastQ * (tempContrastQ * sumsOfAQSquared[dx, dy] - 2 * sumOfAAndBQ + 2 * tempBrightnessQ * sumsOfAQ[dx, dy]) + tempBrightnessQ * (n * tempBrightnessQ - 2 * sumOfBQ)); lock (finalResultLock) { //For each component, keep best transformation if (finalRmsY > tempRmsY) { finalRmsY = tempRmsY; bestRmsYIndexX = dx; bestRmsYIndexY = dy; bestRmsYTransformationIndex = i; bestContrastY = tempContrastY; bestBrightnessY = tempBrightnessY; } if (finalRmsI > tempRmsI) { finalRmsI = tempRmsI; bestRmsIIndexX = dx; bestRmsIIndexY = dy; bestRmsITransformationIndex = i; bestContrastI = tempContrastI; bestBrightnessI = tempBrightnessI; } if (finalRmsQ > tempRmsQ) { finalRmsQ = tempRmsQ; bestRmsQIndexX = dx; bestRmsQIndexY = dy; bestRmsQTransformationIndex = i; bestContrastQ = tempContrastQ; bestBrightnessQ = tempBrightnessQ; } } } } } //Save Di retained for Ri lock (finalResultLock) { transformations[ry * rXCount + rx, 0] = new FractalCompressionResult.FractalTransformation(bestRmsYIndexX, bestRmsYIndexY, (byte)bestBrightnessY, (byte)bestContrastY, (byte)bestRmsYTransformationIndex); transformations[ry * rXCount + rx, 1] = new FractalCompressionResult.FractalTransformation(bestRmsIIndexX, bestRmsIIndexY, (byte)bestBrightnessI, (byte)bestContrastI, (byte)bestRmsITransformationIndex); transformations[ry * rXCount + rx, 2] = new FractalCompressionResult.FractalTransformation(bestRmsQIndexX, bestRmsQIndexY, (byte)bestBrightnessQ, (byte)bestContrastQ, (byte)bestRmsQTransformationIndex); } }); } return(new FractalCompressionResult(transformations, (byte)Math.Ceiling(Math.Log(Math.Max(maxDxPos, maxDyPos), 2)), (short)rXCount)); }
/// <summary> /// Compress image. /// </summary> /// <param name="image">Image to compress.</param> /// <returns>Result of the compression.</returns> public FractalCompressionResult Compress(CustomImage image) { //Validate the image and the params if (image.Width % _options.RSquareSize > 0 || image.Height % _options.RSquareSize > 0 || _options.DSquareRatio <= 1) { throw new InvalidOperationException("The compression options specified can't compress this image as the R squares size is not a divisor of height and width. Ri Sizes must be divisor of Di sizes too."); } object finalResultLock = new object(); int rXCount = image.Width / _options.RSquareSize; //Number of R Squares in X int rYCount = image.Height / _options.RSquareSize; //Number of R Squares in Y int totalRCount = rXCount * rYCount; byte dSquareSize = Convert.ToByte(_options.RSquareSize * _options.DSquareRatio); int maxDxPos = image.Width - dSquareSize + 1; int maxDyPos = image.Height - dSquareSize + 1; byte dSize = dSquareSize; byte rSize = _options.RSquareSize; int n = _options.RSquareSize * _options.RSquareSize; double drRatio = (double)_options.RSquareSize / (double)dSquareSize; int drInverseRatio = dSquareSize / _options.RSquareSize; double pixelAverageSquareSize = (double)drInverseRatio * (double)drInverseRatio; var translateMatrixes = GetTranslateMatrixes(Convert.ToSByte(rSize)); int transformationsCount = _transformMatrixes.Length; var transformations = new FractalCompressionResult.FractalTransformation[totalRCount, 3]; //Transformations (2 dimension to keep transformations for each ri in each color component) int rx; var rawImgData = image.ImageData; var imgDataY = new byte[image.Width, image.Height]; var imgDataI = new short[image.Width, image.Height]; var imgDataQ = new short[image.Width, image.Height]; byte[, ][][,] tempDiY = new byte[maxDxPos, maxDyPos][][, ]; short[, ][][,] tempDiI = new short[maxDxPos, maxDyPos][][, ]; short[, ][][,] tempDiQ = new short[maxDxPos, maxDyPos][][, ]; int[,] sumsOfDY = new int[maxDxPos, maxDyPos]; int[,] sumsOfDYSquared = new int[maxDxPos, maxDyPos]; int[,] sumsOfDI = new int[maxDxPos, maxDyPos]; int[,] sumsOfDISquared = new int[maxDxPos, maxDyPos]; int[,] sumsOfDQ = new int[maxDxPos, maxDyPos]; int[,] sumsOfDQSquared = new int[maxDxPos, maxDyPos]; //Fill imgData Y, I and Q Parallel.For(0, image.Width, dx => { for (int dy = 0; dy < image.Height; dy++) { imgDataY[dx, dy] = rawImgData[dx, dy].Y; imgDataI[dx, dy] = rawImgData[dx, dy].I; imgDataQ[dx, dy] = rawImgData[dx, dy].Q; } }); //Average pixels of each Di to size of Ri Parallel.For(0, maxDxPos, dx => { int i, x, y, j, k, newX, newY, indexX = 0, indexY = 0; sbyte[,] tempTransformMatrix; sbyte[] tempTranslateMatrix; byte[,] tempPixelY = null; short[,] tempPixelI = null; short[,] tempPixelQ = null; int tempSumY = 0, tempSumI = 0, tempSumQ = 0; byte tempAveragePixelY = 0; short tempAveragePixelI = 0, tempAveragePixelQ = 0; byte[,] tempDY = new byte[rSize, rSize]; short[,] tempDI = new short[rSize, rSize]; short[,] tempDQ = new short[rSize, rSize]; for (int dy = 0; dy < maxDyPos; dy++) { tempDiY[dx, dy] = new byte[transformationsCount][, ]; tempDiI[dx, dy] = new short[transformationsCount][, ]; tempDiQ[dx, dy] = new short[transformationsCount][, ]; for (i = 0; i < transformationsCount; i++) { tempPixelY = new byte[rSize, rSize]; tempPixelI = new short[rSize, rSize]; tempPixelQ = new short[rSize, rSize]; for (x = 0; x < dSize; x += drInverseRatio) //Increment of inverse ratio to get only parts of Di { for (y = 0; y < dSize; y += drInverseRatio) { //Get transformation tempTransformMatrix = _transformMatrixes[i]; tempTranslateMatrix = translateMatrixes[i]; //Average pixels on first transform if (i == 0) { //Reset temp variables tempSumY = 0; tempSumI = 0; tempSumQ = 0; //Average pixels for (j = 0; j < drInverseRatio; j++) { for (k = 0; k < drInverseRatio; k++) { tempSumY += imgDataY[dx + x + j, dy + y + k]; tempSumI += imgDataI[dx + x + j, dy + y + k]; tempSumQ += imgDataQ[dx + x + j, dy + y + k]; } } //Calculating average Pixel Components tempAveragePixelY = Convert.ToByte(tempSumY / pixelAverageSquareSize); tempAveragePixelI = Convert.ToInt16(tempSumI / pixelAverageSquareSize); tempAveragePixelQ = Convert.ToInt16(tempSumQ / pixelAverageSquareSize); //Keep reference to subsampled Di. tempDY[x / drInverseRatio, y / drInverseRatio] = tempAveragePixelY; tempDI[x / drInverseRatio, y / drInverseRatio] = tempAveragePixelI; tempDQ[x / drInverseRatio, y / drInverseRatio] = tempAveragePixelQ; //Sum of "a" and "a^2" for future RMS calculation sumsOfDY[dx, dy] += tempAveragePixelY; sumsOfDI[dx, dy] += tempAveragePixelI; sumsOfDQ[dx, dy] += tempAveragePixelQ; sumsOfDYSquared[dx, dy] += tempAveragePixelY * tempAveragePixelY; sumsOfDISquared[dx, dy] += tempAveragePixelI * tempAveragePixelI; sumsOfDQSquared[dx, dy] += tempAveragePixelQ * tempAveragePixelQ; } newX = tempTransformMatrix[0, 0] * (x / drInverseRatio) + tempTransformMatrix[0, 1] * (y / drInverseRatio) + tempTranslateMatrix[0]; newY = tempTransformMatrix[1, 0] * (x / drInverseRatio) + tempTransformMatrix[1, 1] * (y / drInverseRatio) + tempTranslateMatrix[1]; indexX = x / drInverseRatio; indexY = y / drInverseRatio; //Store pixel components for transformed Di (Fi) tempPixelY[newX, newY] = tempDY[indexX, indexY]; tempPixelI[newX, newY] = tempDI[indexX, indexY]; tempPixelQ[newX, newY] = tempDQ[indexX, indexY]; } } //Store pixels of Di tempDiY[dx, dy][i] = tempPixelY; tempDiI[dx, dy][i] = tempPixelI; tempDiQ[dx, dy][i] = tempPixelQ; } } }); //Find the Transformations to do... //For each Ri for (rx = 0; rx < rXCount; rx++) { //Parallel execution of for loop, so it runs faster. Parallel.For(0, rYCount, ry => { //Calculate the sums of components in Ri for future RMS metric calculation int sumOfRY = 0; int sumOfRYSquared = 0; int sumOfRI = 0; int sumOfRISquared = 0; int sumOfRQ = 0; int sumOfRQSquared = 0; int sumOfDAndRY; int sumOfDAndRI; int sumOfDAndRQ; int x, y, indexX, indexY, dx, dy, i, sYInt, oYInt, sIInt, oIInt, sQInt, oQInt, bestRmsYIndexX = -1, bestRmsYIndexY = -1, bestRmsYTransformationIndex = -1, bestRmsIIndexX = -1, bestRmsIIndexY = -1, bestRmsITransformationIndex = -1, bestRmsQIndexX = -1, bestRmsQIndexY = -1, bestRmsQTransformationIndex = -1, bestOY = 0, bestSY = 0, bestOI = 0, bestSI = 0, bestOQ = 0, bestSQ = 0; byte[,] tempPixelY = null; short[,] tempPixelI = null; short[,] tempPixelQ = null; double sY, oY, sI, oI, sQ, oQ, tempRmsY, tempRmsI, tempRmsQ, tempSYDenominator, tempSIDenominator, tempSQDenominator, finalRmsY = Double.MaxValue, finalRmsI = Double.MaxValue, finalRmsQ = Double.MaxValue; for (x = 0; x < rSize; x++) { for (y = 0; y < rSize; y++) { //Sum of "b" and of "b^2" indexX = rx * rSize + x; indexY = ry * rSize + y; sumOfRY += imgDataY[indexX, indexY]; sumOfRI += imgDataI[indexX, indexY]; sumOfRQ += imgDataQ[indexX, indexY]; sumOfRYSquared += imgDataY[indexX, indexY] * imgDataY[indexX, indexY]; sumOfRISquared += imgDataI[indexX, indexY] * imgDataI[indexX, indexY]; sumOfRQSquared += imgDataQ[indexX, indexY] * imgDataQ[indexX, indexY]; } } //For Each Di for (dx = 0; dx < maxDxPos; dx++) { for (dy = 0; dy < maxDyPos; dy++) { tempSYDenominator = n * sumsOfDYSquared[dx, dy] - sumsOfDY[dx, dy] * sumsOfDY[dx, dy]; tempSIDenominator = n * sumsOfDISquared[dx, dy] - sumsOfDI[dx, dy] * sumsOfDI[dx, dy]; tempSQDenominator = n * sumsOfDQSquared[dx, dy] - sumsOfDQ[dx, dy] * sumsOfDQ[dx, dy]; //For Each possible transformations for (i = 0; i < transformationsCount; i++) { sumOfDAndRY = 0; sumOfDAndRI = 0; sumOfDAndRQ = 0; tempPixelY = tempDiY[dx, dy][i]; tempPixelI = tempDiI[dx, dy][i]; tempPixelQ = tempDiQ[dx, dy][i]; //Compute sums necessary for calculating RMS metric for (x = 0; x < rSize; x++) { indexX = rx * rSize + x; for (y = 0; y < rSize; y++) { //Calculate indexX and indexY indexY = ry * rSize + y; //Sum of "ri*di" sumOfDAndRY += tempPixelY[x, y] * imgDataY[indexX, indexY]; sumOfDAndRI += tempPixelI[x, y] * imgDataI[indexX, indexY]; sumOfDAndRQ += tempPixelQ[x, y] * imgDataQ[indexX, indexY]; } } //Compute contrast, brightness and RMS metric sY = CalculateS(tempSYDenominator, n, sumOfDAndRY, sumsOfDY[dx, dy], sumOfRY, out sYInt); sI = CalculateS(tempSIDenominator, n, sumOfDAndRI, sumsOfDI[dx, dy], sumOfRI, out sIInt); sQ = CalculateS(tempSQDenominator, n, sumOfDAndRQ, sumsOfDQ[dx, dy], sumOfRQ, out sQInt); oY = CalculateO(n, sY, sumOfRY, sumsOfDY[dx, dy], Y_LEVELS, out oYInt); oI = CalculateO(n, sI, sumOfRI, sumsOfDI[dx, dy], I_LEVELS, out oIInt); oQ = CalculateO(n, sQ, sumOfRQ, sumsOfDQ[dx, dy], Q_LEVELS, out oQInt); tempRmsY = Math.Sqrt((sumOfRYSquared + sY * (sY * sumsOfDYSquared[dx, dy] - 2 * sumOfDAndRY + 2 * oY * sumsOfDY[dx, dy]) + oY * (n * oY - 2 * sumOfRY)) / n); tempRmsI = Math.Sqrt((sumOfRISquared + sI * (sI * sumsOfDISquared[dx, dy] - 2 * sumOfDAndRI + 2 * oI * sumsOfDI[dx, dy]) + oI * (n * oI - 2 * sumOfRI)) / n); tempRmsQ = Math.Sqrt((sumOfRQSquared + sQ * (sQ * sumsOfDQSquared[dx, dy] - 2 * sumOfDAndRQ + 2 * oQ * sumsOfDQ[dx, dy]) + oQ * (n * oQ - 2 * sumOfRQ)) / n); if (Double.IsNaN(tempRmsY)) { throw new Exception("SQRT IS NAN!"); } if (Double.IsNaN(tempRmsI)) { throw new Exception("SQRT IS NAN!"); } if (Double.IsNaN(tempRmsQ)) { throw new Exception("SQRT IS NAN!"); } //For each component, keep best transformation if (!Double.IsNaN(tempRmsY) && finalRmsY > tempRmsY) { finalRmsY = tempRmsY; bestRmsYIndexX = dx; bestRmsYIndexY = dy; bestRmsYTransformationIndex = i; bestSY = sYInt; bestOY = oYInt; } if (!Double.IsNaN(tempRmsI) && finalRmsI > tempRmsI) { finalRmsI = tempRmsI; bestRmsIIndexX = dx; bestRmsIIndexY = dy; bestRmsITransformationIndex = i; bestSI = sIInt; bestOI = oIInt; } if (!Double.IsNaN(tempRmsQ) && finalRmsQ > tempRmsQ) { finalRmsQ = tempRmsQ; bestRmsQIndexX = dx; bestRmsQIndexY = dy; bestRmsQTransformationIndex = i; bestSQ = sQInt; bestOQ = oQInt; } } } } //Save Di retained for Ri transformations[ry * rXCount + rx, 0] = new FractalCompressionResult.FractalTransformation(bestRmsYIndexX, bestRmsYIndexY, Convert.ToByte(bestOY), Convert.ToByte(bestSY), Convert.ToByte(bestRmsYTransformationIndex)); transformations[ry * rXCount + rx, 1] = new FractalCompressionResult.FractalTransformation(bestRmsIIndexX, bestRmsIIndexY, Convert.ToByte(bestOI), Convert.ToByte(bestSI), Convert.ToByte(bestRmsITransformationIndex)); transformations[ry * rXCount + rx, 2] = new FractalCompressionResult.FractalTransformation(bestRmsQIndexX, bestRmsQIndexY, Convert.ToByte(bestOQ), Convert.ToByte(bestSQ), Convert.ToByte(bestRmsQTransformationIndex)); }); } return(new FractalCompressionResult(transformations, Convert.ToByte(Math.Ceiling(Math.Log(Math.Max(maxDxPos, maxDyPos), 2))), Convert.ToInt16(rXCount))); }