/// <summary> /// Uncompress image using 10 iterations. /// </summary> /// <param name="compressionResult">Compressed image result.</param> /// <param name="decodingImage">Image used for decoding.</param> /// <returns>Custom Image.</returns> public CustomImage CompleteUncompress(FractalCompressionResult compressionResult, CustomImage decodingImage) { using (new CustomTimer("Complete decompression")) { for (int i = 0; i < 10; i++) { decodingImage = Uncompress(compressionResult, decodingImage); } } //if (_options.SmoothImage) // return new CustomImage(SmoothImage(decodingImage.ImageData, _options.RSquareSize)); //else return(decodingImage); }
public CustomImage Uncompress(FractalCompressionResult compressionResult, CustomImage decodingImage) { const int dimensions = 3; int rXCount = compressionResult.RCountX; int rYCount = compressionResult.Transformations.GetLength(0) / compressionResult.RCountX; int imgSizeX = rXCount * _options.RSquareSize; int imgSizeY = rYCount * _options.RSquareSize; //if (decodingImage.Width != imgSizeX || decodingImage.Height != imgSizeY) // throw new ArgumentException("Decoding image must be the same size that the compressed image!"); Pixel[,] pixels = new Pixel[imgSizeX, imgSizeY]; double drRatio = (double)_options.RSquareSize / (double)_options.DSquareSize; int drInverseRatio = _options.DSquareSize / _options.RSquareSize; int dSizeXAdapted = decodingImage.Width / (rXCount / drInverseRatio); int dSizeYAdapted = decodingImage.Height / (rYCount / drInverseRatio); double drRatioAdapted = (double)_options.RSquareSize / dSizeXAdapted; int drInverseRatioAdapted = dSizeXAdapted / _options.RSquareSize; int maxDxPos = imgSizeX - _options.DSquareSize + 1; int maxDyPos = imgSizeY - _options.DSquareSize + 1; int dSize = _options.DSquareSize; int rSize = _options.RSquareSize; double[, ][][,] tempDi = new double[maxDxPos, maxDyPos][][, ]; double[,,] imgData = new double[imgSizeX, imgSizeY, dimensions]; var rawImgData = decodingImage.ImageData; double pixelAverageSquareSize = (double)drInverseRatioAdapted * (double)drInverseRatioAdapted; var translateMatrixes = GetTranslateMatrixes(_options.RSquareSize); //Fill imgData Y, I and Q Parallel.For(0, imgSizeX, dx => { for (int dy = 0; dy < imgSizeY; dy++) { imgData[dx, dy, 0] = rawImgData[dx, dy].YNormalized; imgData[dx, dy, 1] = rawImgData[dx, dy].IDownSampledAndNormalized; imgData[dx, dy, 2] = rawImgData[dx, dy].QDownSampledAndNormalized; } }); //Subsample image to fit image to get Dis Parallel.For(0, maxDxPos, dx => { int x, y, j, k, indexX = 0, indexY = 0; 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++) { tempDi[dx, dy] = new double[dimensions][, ]; for (x = 0; x < dSize; x += drInverseRatioAdapted) //Increment of inverse ratio to get only parts of Di { for (y = 0; y < dSize; y += drInverseRatioAdapted) { //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 < drInverseRatioAdapted; j++) { for (k = 0; k < drInverseRatioAdapted; k++) { tempSumY += imgData[dx + x + j, dy + y + k, 0]; tempSumI += imgData[dx + x + j, dy + y + k, 1]; tempSumQ += imgData[dx + x + j, dy + y + k, 2]; } } //Calculating average Pixel Components tempAveragePixelY = tempSumY > 0 ? tempSumY / pixelAverageSquareSize : 0d; tempAveragePixelI = tempSumI > 0 ? tempSumI / pixelAverageSquareSize : 0d; tempAveragePixelQ = tempSumQ > 0 ? tempSumQ / pixelAverageSquareSize : 0d; indexX = (int)(y * drRatio); indexY = (int)(x * drRatio); ////Store pixel components for transformed Di (Fi) tempPixelY1[indexX, indexY] = tempAveragePixelY; tempPixelI1[indexX, indexY] = tempAveragePixelI; tempPixelQ1[indexX, indexY] = tempAveragePixelQ; ////Store pixels of Di tempDi[dx, dy][0] = tempPixelY1; tempDi[dx, dy][1] = tempPixelI1; tempDi[dx, dy][2] = tempPixelQ1; } } } }); //Uncompress image Parallel.For(0, rXCount, rx => { int dimIndex, indexX, indexY, newX, newY; double[,] tempTransform; double[] tempTranslate; byte[,,] tempComponents = new byte[rSize, rSize, dimensions]; FractalCompressionResult.FractalTransformation transformation; for (int ry = 0; ry < rYCount; ry++) { //Get transformed Di (Ri) for (indexX = 0; indexX < rSize; indexX++) { for (indexY = 0; indexY < rSize; indexY++) { for (dimIndex = 0; dimIndex < dimensions; dimIndex++) { transformation = compressionResult.Transformations[ry * rXCount + rx, dimIndex]; tempTransform = _transformMatrixes[transformation.TransformationType]; tempTranslate = translateMatrixes[transformation.TransformationType]; newX = (byte)(tempTransform[0, 0] * indexX + tempTransform[0, 1] * indexY + tempTranslate[0]); newY = (byte)(tempTransform[1, 0] * indexX + tempTransform[1, 1] * indexY + tempTranslate[1]); tempComponents[newX, newY, dimIndex] = (byte)(tempDi[transformation.DiX, transformation.DiY][dimIndex][indexX, indexY] * transformation.ContrastTransformation + transformation.BrightnessTransformation); } } } //Populate pixels from Ri calculated for (indexX = 0; indexX < rSize; indexX++) { for (indexY = 0; indexY < rSize; indexY++) { pixels[rx * rSize + indexX, ry * rSize + indexY] = Pixel.FromYIQDownSampled(tempComponents[indexX, indexY, 0], tempComponents[indexX, indexY, 1], tempComponents[indexX, indexY, 2]); } } } }); return(new CustomImage(pixels)); }
/// <summary> /// Uncompress image compressed using fractal compression (single iteration of decompression). /// </summary> /// <param name="compressionResult">Compressed image result.</param> /// <param name="decodingImage">Image used for decoding.</param> /// <returns>Uncompressed image.</returns> public CustomImage Uncompress(FractalCompressionResult compressionResult, CustomImage decodingImage) { int rXCount = compressionResult.RCountX; int rYCount = compressionResult.Transformations.GetLength(0) / compressionResult.RCountX; int imgSizeX = rXCount * _options.RSquareSize; int imgSizeY = rYCount * _options.RSquareSize; Pixel[,] pixels = new Pixel[imgSizeX, imgSizeY]; int rSize = _options.RSquareSize; const int dimensions = 3; byte dSquareSize = Convert.ToByte(_options.RSquareSize * _options.DSquareRatio); double drRatio = (double)_options.RSquareSize / (double)dSquareSize; int drInverseRatio = _options.DSquareRatio; int maxDxPos = imgSizeX - dSquareSize + 1; int maxDyPos = imgSizeY - dSquareSize + 1; int dSize = dSquareSize; var imgData = decodingImage.ImageData; int pixelAverageSquareSize = drInverseRatio * drInverseRatio; var translateMatrixes = GetTranslateMatrixes(Convert.ToSByte(dSize)); Parallel.For(0, rXCount, rx => { int dimIndex, indexX, indexY, newX, newY, i, j, y; sbyte[,] tempTransform; sbyte[] tempTranslate; double[,,] tempComponents = new double[dSize, dSize, dimensions]; double s, o; FractalCompressionResult.FractalTransformation transformation; double componentSumY; double componentSumI; double componentSumQ; for (int ry = 0; ry < rYCount; ry++) { //Get transformed Di (Ri) for (indexX = 0; indexX < dSize; indexX++) { for (indexY = 0; indexY < dSize; indexY++) { for (dimIndex = 0; dimIndex < dimensions; dimIndex++) { transformation = compressionResult.Transformations[ry * rXCount + rx, dimIndex]; tempTransform = _transformMatrixes[transformation.TransformationType]; tempTranslate = translateMatrixes[transformation.TransformationType]; newX = Convert.ToInt32(tempTransform[0, 0] * indexX + tempTransform[0, 1] * indexY + tempTranslate[0]); newY = Convert.ToInt32(tempTransform[1, 0] * indexX + tempTransform[1, 1] * indexY + tempTranslate[1]); s = transformation.ContrastTransformation / (double)(S_BITS_VALUE) * (2d * S_MAX) - S_MAX; if (dimIndex == 0) { o = (transformation.BrightnessTransformation / (double)(O_BITS_VALUE - 1) * ((1d + Math.Abs(s)) * Y_LEVELS)); if (s > 0d) { o -= s * Y_LEVELS; } tempComponents[newX, newY, dimIndex] = imgData[transformation.DiX + indexX, transformation.DiY + indexY].Y * s + o; } else if (dimIndex == 1) { o = (transformation.BrightnessTransformation / (double)(O_BITS_VALUE - 1) * ((1d + Math.Abs(s)) * I_LEVELS)); if (s > 0d) { o -= s * I_LEVELS; } tempComponents[newX, newY, dimIndex] = imgData[transformation.DiX + indexX, transformation.DiY + indexY].I * s + o; } else { o = (transformation.BrightnessTransformation / (double)(O_BITS_VALUE - 1) * ((1d + Math.Abs(s)) * Q_LEVELS)); if (s > 0d) { o -= s * Q_LEVELS; } tempComponents[newX, newY, dimIndex] = imgData[transformation.DiX + indexX, transformation.DiY + indexY].Q * s + o; } } } } //Populate pixels from Ri calculated for (indexX = 0; indexX < dSize; indexX += drInverseRatio) { for (indexY = 0; indexY < dSize; indexY += drInverseRatio) { componentSumY = 0; componentSumI = 0; componentSumQ = 0; for (i = 0; i < drInverseRatio; i++) { for (j = 0; j < drInverseRatio; j++) { componentSumY += tempComponents[indexX + i, indexY + j, 0]; componentSumI += tempComponents[indexX + i, indexY + j, 1]; componentSumQ += tempComponents[indexX + i, indexY + j, 2]; } } pixels[rx * rSize + indexX / drInverseRatio, ry * rSize + indexY / drInverseRatio] = Pixel.FromYIQ( Convert.ToByte(Math.Max(Math.Min(componentSumY / (drInverseRatio * drInverseRatio), 255), 0)), Convert.ToInt16(Math.Max(Math.Min(componentSumI / (drInverseRatio * drInverseRatio), 151), -151)), Convert.ToInt16(Math.Max(Math.Min(componentSumQ / (drInverseRatio * drInverseRatio), 133), -133))); } } } }); if (_options.SmoothImage) { pixels = SmoothImage(pixels, rSize); } return(new CustomImage(pixels)); }