//Конструктор дерева public BlockTree(Object.Block block, int blockSize) { mainBlock = block; mainBlock.X = block.X; mainBlock.Y = block.Y; mainBlock.SumR = block.SumR; mainBlock.SumG = block.SumG; mainBlock.SumB = block.SumB; mainBlock.BlockSize = blockSize; mainBlock.Depth = QuadTreeCompression.numLock; if (QuadTreeCompression.numLock == (-1)) { QuadTreeCompression.numLock = 2; } else { ++QuadTreeCompression.numLock; } //Для ранговых блоковы if (mainBlock.BlockSize > 2) { Object.Block tmpBlock = QuadTreeCompression.CreateBlockRange(block.X, block.Y, QuadTreeCompression.classImageColor, block.BlockSize / 2, QuadTreeCompression.brightnessImage); ul = new BlockTree(tmpBlock, tmpBlock.BlockSize); tmpBlock = QuadTreeCompression.CreateBlockRange(block.X + block.BlockSize / 2, block.Y, QuadTreeCompression.classImageColor, block.BlockSize / 2, QuadTreeCompression.brightnessImage); ur = new BlockTree(tmpBlock, tmpBlock.BlockSize); tmpBlock = QuadTreeCompression.CreateBlockRange(block.X, block.Y + block.BlockSize / 2, QuadTreeCompression.classImageColor, block.BlockSize / 2, QuadTreeCompression.brightnessImage); dl = new BlockTree(tmpBlock, tmpBlock.BlockSize); tmpBlock = QuadTreeCompression.CreateBlockRange(block.X + block.BlockSize / 2, block.Y + block.BlockSize / 2, QuadTreeCompression.classImageColor, block.BlockSize / 2, QuadTreeCompression.brightnessImage); dr = new BlockTree(tmpBlock, tmpBlock.BlockSize); } }
//Отразить блок по вертикали private static Color[,] ReverseColor(Color[,] imageColor, int block_size, Object.Block block) { Color[,] newImageColor = imageColor; Color[,] blockImageColor = new Color[block_size, block_size]; Color[,] tmp_BlockImageColor = new Color[block_size, block_size]; //Считывание нужного блока из всего изображения for (int i = 0; i < block_size; ++i) { for (int j = 0; j < block_size; ++j) { blockImageColor[i, j] = newImageColor[block.X + i, block.Y + j]; } } //Отражение for (int i = 0; i < block_size; ++i) { for (int j = 0; j < block_size; ++j) { tmp_BlockImageColor[i, j] = blockImageColor[block_size - i - 1, j]; } } blockImageColor = tmp_BlockImageColor; //Запись блока в изображение for (int i = 0; i < block_size; ++i) { for (int j = 0; j < block_size; ++j) { //NewImageColor[Block.X + i, Block.Y + j] = tmp_BlockImageColor[i, j]; newImageColor[block.X + i, block.Y + j] = blockImageColor[i, j]; } } return(newImageColor); }
//Определение угла между центрами масс двух блоков (используется для классификации) protected static double Angle(Object.Block RangeBlock, Object.Block DomainBlock) { double angle = 0; double vec1X = RangeBlock.Px; double vec1Y = RangeBlock.Py; double vec2X = DomainBlock.Px; double vec2Y = DomainBlock.Py; double sum1 = Math.Sqrt(vec1X * vec1X + vec1Y * vec1Y); double sum2 = Math.Sqrt(vec2X * vec2X + vec2Y * vec2Y); double scalar = vec1X * vec2X + vec1Y * vec2Y; angle = Math.Acos(scalar / (sum1 * sum2)); //Переводим из радин в градусы //return (angle * 57.2958); return(angle); }
public static bool CheckMonotoneBlock(Object.Block block) { int count = 0; Color currentColor = classImageColor[block.X, block.Y]; for (int i = 0; i < block.BlockSize - 1; ++i) { for (int j = 1; j < block.BlockSize - 1; ++j) { if (classImageColor[block.X + i, block.Y + j] != classImageColor[block.X + i + 1, block.Y + j + 1]) { ++count; } } } return(count < ((block.BlockSize))); }
static public double DistanceQuad(Color[,] classImageColor, Object.Block rangeBlock, Object.Block domainBlock, int range_block_size, double shift) { double distance = 0; double rangeValue = 0; double domainValue = 0; for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = classImageColor[rangeBlock.X + i, rangeBlock.Y + j].R; domainValue = classImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].R; distance += Metrics.Two(rangeValue, domainValue, shift); } } return(distance); }
//Определение сдвига по яркости между двумя блоками public static double Shift(Object.Block rangeBlock, Object.Block domainBlock, int range_block_size, int flag) { double shift = 0; if (flag == 0) { shift = ((rangeBlock.SumR) - (u * domainBlock.SumR)) / (range_block_size * range_block_size); } if (flag == 1) { shift = ((rangeBlock.SumG) - (u * domainBlock.SumG)) / (range_block_size * range_block_size); } if (flag == 2) { shift = ((rangeBlock.SumB) - (u * domainBlock.SumB)) / (range_block_size * range_block_size); } return(shift); }
//Создание доменного блока public static Object.Block CreateBlockDomain(int x, int y, Color[,] imageColor, int range_block_size, double[,] brightness) { Object.Block block = new Object.Block { X = x, Y = y, SumR = 0, SumG = 0, SumB = 0, Px = 0, Py = 0, Active = false }; double blockBrightness = 0; for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { block.SumR += imageColor[block.X + i * 2, block.Y + j * 2].R; block.SumG += imageColor[block.X + i * 2, block.Y + j * 2].G; block.SumB += imageColor[block.X + i * 2, block.Y + j * 2].B; block.SumR2 += (block.SumR * block.SumR); block.SumG2 += (block.SumG * block.SumG); block.SumB2 += (block.SumB * block.SumB); //Считаем общую яркость для блока blockBrightness += brightness[block.X + i * 2, block.Y + j * 2]; //Считаем координаты центра масс блока block.Px += i * brightness[block.X + i * 2, block.Y + j * 2]; block.Py += j * brightness[block.X + i * 2, block.Y + j * 2]; } } block.Px = (block.Px / blockBrightness) - ((range_block_size + 1) / 2); block.Py = (block.Py / blockBrightness) - ((range_block_size + 1) / 2); return(block); }
//Создание рангового блока public static Object.Block CreateBlockRange(int x, int y, Color[,] imageColor, int range_block_size, double[,] brightness) { Object.Block block = new Object.Block { X = x, Y = y, SumR = 0, SumG = 0, SumB = 0, Px = 0, Py = 0, BlockSize = range_block_size, Active = false }; double blockBrightness = 0; for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { block.SumR += imageColor[block.X + i, block.Y + j].R; block.SumG += imageColor[block.X + i, block.Y + j].G; block.SumB += imageColor[block.X + i, block.Y + j].B; block.SumR2 += (block.SumR * block.SumR); block.SumG2 += (block.SumG * block.SumG); block.SumB2 += (block.SumB * block.SumB); blockBrightness += brightness[block.X + i, block.Y + j]; block.Px += i * brightness[block.X + i, block.Y + j]; block.Py += j * brightness[block.X + i, block.Y + j]; } } block.Px = (block.Px / blockBrightness) - ((range_block_size + 1) / 2); block.Py = (block.Py / blockBrightness) - ((range_block_size + 1) / 2); return(block); }
//Поворот на 90 градусов блока во всём изображении private static Color[,] RotateColor(Color[,] imageColor, int block_size, Object.Block block) { Color[,] newImageColor = imageColor; Color[,] blockImageColor = new Color[block_size, block_size]; Color[,] tmp_BlockImageColor = new Color[block_size, block_size]; //Считывание нужного блока из всего изображения for (int i = 0; i < block_size; ++i) { for (int j = 0; j < block_size; ++j) { blockImageColor[i, j] = newImageColor[block.X + i, block.Y + j]; } } //Поворот блока на 90 градусов против часовой стрелки Color tmp; for (int i = 0; i < block_size / 2; i++) { for (int j = i; j < block_size - 1 - i; j++) { tmp = blockImageColor[i, j]; blockImageColor[i, j] = blockImageColor[block_size - j - 1, i]; blockImageColor[block_size - j - 1, i] = blockImageColor[block_size - i - 1, block_size - j - 1]; blockImageColor[block_size - i - 1, block_size - j - 1] = blockImageColor[j, block_size - i - 1]; blockImageColor[j, block_size - i - 1] = tmp; } } //Запись блока в изображение for (int i = 0; i < block_size; ++i) { for (int j = 0; j < block_size; ++j) { newImageColor[block.X + i, block.Y + j] = blockImageColor[i, j]; } } return(newImageColor); }
//Построить по дереву изображение public void DrawTree(BlockTree rangeTree, Object.BlockArray[] domainArray, Color[,] newImageColor) { if (rangeTree.mainBlock.Active == false) { DrawTree(rangeTree.ul, domainArray, newImageColor); DrawTree(rangeTree.ur, domainArray, newImageColor); DrawTree(rangeTree.dl, domainArray, newImageColor); DrawTree(rangeTree.dr, domainArray, newImageColor); } else { ++BlockCompression.numLock; int currentSize = 0; for (int i = 0; i < domainArray.Length; ++i) { if ((domainArray[i].BlockSize) == (rangeTree.mainBlock.BlockSize * 2)) { currentSize = i; } } Object.Block domainBlock = domainArray[currentSize].Blocks[rangeTree.mainBlock.Coeff.X, rangeTree.mainBlock.Coeff.Y]; for (int pix_x = 0; pix_x < rangeTree.mainBlock.BlockSize; ++pix_x) { for (int pix_y = 0; pix_y < rangeTree.mainBlock.BlockSize; ++pix_y) { Color color = newImageColor[domainBlock.X + (pix_x * 2), domainBlock.Y + (pix_y * 2)]; int r = (int)(0.75 * color.R + (rangeTree.mainBlock.Coeff.shiftR)); if (r < 0) { r = 0; } if (r > 255) { r = 255; } int g = (int)(0.75 * color.G + (rangeTree.mainBlock.Coeff.shiftG)); if (g < 0) { g = 0; } if (g > 255) { g = 255; } int b = (int)(0.75 * color.B + (rangeTree.mainBlock.Coeff.shiftB)); if (b < 0) { b = 0; } if (b > 255) { b = 255; } Color Newcolor = Color.FromArgb(r, g, b); newImageColor[rangeTree.mainBlock.X + pix_x, rangeTree.mainBlock.Y + pix_y] = Newcolor; } } } }
public static void ColorDecompression() { byte[] BytesFile = File.ReadAllBytes(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Compression"); int fileCount = 0; //Коэффициент масштабирования int scale = 1; Byte[] tmp = MyConverter.ReadByte(BytesFile, 0, 2); int Image_width = BitConverter.ToInt16(tmp, 0) * scale; fileCount += 2; tmp = MyConverter.ReadByte(BytesFile, 2, 4); int Image_height = BitConverter.ToInt16(tmp, 0) * scale; fileCount += 2; tmp = MyConverter.ReadByte(BytesFile, 4, 5); int range_block_size = tmp[0] * scale; fileCount += 1; Bitmap newImage = new Bitmap(Image_width, Image_height); int range_num_width = newImage.Width / range_block_size; int range_num_height = newImage.Height / range_block_size; compressCoeff = new Object.Coefficients[range_num_width, range_num_height, 1]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 1); compressCoeff[i, j, 0].X = tmp[0]; fileCount += 1; tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 1); compressCoeff[i, j, 0].Y = tmp[0]; fileCount += 1; tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2); compressCoeff[i, j, 0].shiftR = BitConverter.ToInt16(tmp, 0); fileCount += 2; tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2); compressCoeff[i, j, 0].shiftG = BitConverter.ToInt16(tmp, 0); fileCount += 2; tmp = MyConverter.ReadByte(BytesFile, fileCount, fileCount + 2); compressCoeff[i, j, 0].shiftB = BitConverter.ToInt16(tmp, 0); fileCount += 2; } } //Создаём ранговые блоки Object.Block[,] rangeArray = new Object.Block[range_num_width, range_num_height]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { rangeArray[i, j].X = i * range_block_size; rangeArray[i, j].Y = j * range_block_size; } } //Создаем доменные блоки int domain_num_width = range_num_width - 1; int domain_num_height = range_num_height - 1; int domain_block_size = range_block_size * 2; Object.Block[,] domainArray = new Object.Block[domain_num_width, domain_num_height]; for (int i = 0; i < domain_num_width; ++i) { for (int j = 0; j < domain_num_height; ++j) { domainArray[i, j].X = i * range_block_size; domainArray[i, j].Y = j * range_block_size; } } for (int it = 0; it < 10; ++it) { Color[,] newImageColor = new Color[newImage.Width, newImage.Height]; for (int i = 0; i < newImage.Width; ++i) { for (int j = 0; j < newImage.Height; ++j) { newImageColor[i, j] = newImage.GetPixel(i, j); } } Color[,] rotateNewImageR = newImageColor; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { Object.Block rangeBlock = rangeArray[i, j]; Object.Coefficients current_coefficentR = compressCoeff[i, j, 0]; Object.Block domainBlockR = domainArray[current_coefficentR.X, current_coefficentR.Y]; for (int pix_x = 0; pix_x < range_block_size; ++pix_x) { for (int pix_y = 0; pix_y < range_block_size; ++pix_y) { Color colorR1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)]; Color colorR = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)]; //int R = (int)(U * ((colorR.R + colorR1.R) / 2) + (Current_coefficentR.shiftR)); int r = (int)(u * colorR.R + (current_coefficentR.shiftR)); if (r < 0) { r = 0; } if (r > 255) { r = 255; } Color colorG1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)]; Color colorG = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)]; //int G = (int)(U * ((colorG.G + colorG1.G) / 2) + (Current_coefficentR.shiftG)); int g = (int)(u * colorG.G + (current_coefficentR.shiftG)); if (g < 0) { g = 0; } if (g > 255) { g = 255; } Color colorB1 = rotateNewImageR[domainBlockR.X + (pix_x), domainBlockR.Y + (pix_y)]; Color colorB = rotateNewImageR[domainBlockR.X + (pix_x * 2), domainBlockR.Y + (pix_y * 2)]; //int B = (int)(U * ((colorB.B + colorB1.B) / 2) + (Current_coefficentR.shiftB)); int b = (int)(u * colorB.B + (current_coefficentR.shiftB)); if (b < 0) { b = 0; } if (b > 255) { b = 255; } Color Newcolor = Color.FromArgb(r, g, b); newImage.SetPixel(rangeBlock.X + pix_x, rangeBlock.Y + pix_y, Newcolor); } } } } } newImage.Save(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Expanded file.bmp", System.Drawing.Imaging.ImageFormat.Bmp); }
//Сжатие с использование квадродеревьев public static void Compression(string filename, string quality) { if (!(File.Exists(filename))) { System.Console.WriteLine("Файла не существует"); return; } //Черно-белый файл или нет if (quality == "Black") { colorflag = 1; } else { if (quality == "Color") { colorflag = 3; } else { System.Console.WriteLine("Тип выбран не правильно"); return; } } Bitmap image = new Bitmap(filename); imageWidth = image.Width; imageHeigth = image.Height; classImageColor = new Color[image.Width, image.Height]; for (int i = 0; i < image.Width; ++i) { for (int j = 0; j < image.Height; ++j) { classImageColor[i, j] = image.GetPixel(i, j); } } brightnessImage = new double[image.Width, image.Height]; for (int i = 0; i < image.Width; ++i) { for (int j = 0; j < image.Height; ++j) { brightnessImage[i, j] = image.GetPixel(i, j).GetBrightness(); } } //Создаём ранговое дерево range_block_size = 64; range_num_width = image.Width / range_block_size; range_num_height = image.Height / range_block_size; rangeArray = new Object.Block[range_num_width, range_num_height]; //Изначально создаются ранговые блоки, на основе которых будут составляться деревья for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { rangeArray[i, j] = CreateBlockRange(i * range_block_size, j * range_block_size, classImageColor, range_block_size, brightnessImage); } } rangeTree = new BlockTree[range_num_width, range_num_height]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { numLock = 1; rangeTree[i, j] = new BlockTree(rangeArray[i, j], rangeArray[i, j].BlockSize); } } //Доменные блоки представлены не в виде деревьев, а в виде трехмерных массивов domain_num_width = range_num_width - 1; domain_num_height = range_num_height - 1; domain_block_size = range_block_size * 2; domainArray = new Object.Block[domain_num_width, domain_num_height]; //System.Console.WriteLine(DomainBlocks.Length); domainBlocks = new Object.BlockArray[PostProcessing.GetPow(domain_block_size)]; for (int i = 0; i < domainBlocks.Length; ++i) { if (i == 0) { domainBlocks[i].BlockSize = domain_block_size; } else { domainBlocks[i].BlockSize = domainBlocks[i - 1].BlockSize / 2; } domainBlocks[i].num_width = image.Width / domainBlocks[i].BlockSize; domainBlocks[i].num_height = image.Height / domainBlocks[i].BlockSize; domainBlocks[i].Blocks = new Object.Block[domainBlocks[i].num_width, domainBlocks[i].num_height]; for (int j = 0; j < domainBlocks[i].num_width; ++j) { for (int k = 0; k < domainBlocks[i].num_height; ++k) { domainBlocks[i].Blocks[j, k] = CreateBlockDomain(j * domainBlocks[i].BlockSize / 2, k * domainBlocks[i].BlockSize / 2, classImageColor, domainBlocks[i].BlockSize / 2, brightnessImage); } } } listCoeff = new List <Object.Coefficients>(); //Обход всех деревьев и нахождение для нужных коэффициентов преобразования, а так же выписывание их в файл for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { blockChecker = 0; rangeTree[i, j].RoundTree(rangeTree[i, j], domainBlocks, classImageColor, rangeTree[i, j].mainBlock.BlockSize); } } bw = new BinaryWriter(File.Open(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad Compression", FileMode.Create)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Width), 2)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Height), 2)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(range_block_size), 1)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(listCoeff.Count), 4)); //for (int i = 0; i < range_num_width; ++i) //{ // for (int j = 0; j < range_num_height; ++j) // { // rangeTree[i, j].PrintTree(rangeTree[i, j], 0); // } //} for (int i = 0; i < listCoeff.Count; ++i) { //Запись в файл всех нужные чисел, а так же глубину нахождения узла в дереве Byte[] D = BitConverter.GetBytes(listCoeff[i].Depth); Byte[] X = BitConverter.GetBytes(listCoeff[i].X); Byte[] Y = BitConverter.GetBytes(listCoeff[i].Y); Byte[] SR = BitConverter.GetBytes(listCoeff[i].shiftR); Byte[] SG = BitConverter.GetBytes(listCoeff[i].shiftG); Byte[] SB = BitConverter.GetBytes(listCoeff[i].shiftB); //System.Console.WriteLine(listCoeff[i].Depth + " -- " + D[0]); bw.Write(MyConverter.Convert(D, 1)); bw.Write(MyConverter.Convert(X, 1)); bw.Write(MyConverter.Convert(Y, 1)); bw.Write(MyConverter.Convert(SR, 2)); bw.Write(MyConverter.Convert(SG, 2)); bw.Write(MyConverter.Convert(SB, 2)); } bw.Close(); }
static public void Decompression() { System.Console.WriteLine("Decompression dont work"); return; byte[] bytesFile = File.ReadAllBytes(@"C:\Users\dbogdano\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad Compression"); int fileCount = 0; //Коэффициент масштабирования int scale = 1; Byte[] tmp = MyConverter.ReadByte(bytesFile, 0, 2); int image_width = BitConverter.ToInt16(tmp, 0) * scale; //+ fileCount += 2; tmp = MyConverter.ReadByte(bytesFile, 2, 4); int image_height = BitConverter.ToInt16(tmp, 0) * scale; //+ fileCount += 2; tmp = MyConverter.ReadByte(bytesFile, 4, 5); int range_block_size = tmp[0] * scale; //+ fileCount += 1; tmp = MyConverter.ReadByte(bytesFile, 5, 9); fileCount += 4; int listSize = BitConverter.ToInt32(tmp, 0); Bitmap newImage = new Bitmap(image_width, image_height); Color[,] newImageColor = new Color[newImage.Width, newImage.Height]; brightnessImage = new double[newImage.Width, newImage.Height]; for (int i = 0; i < newImage.Width; ++i) { for (int j = 0; j < newImage.Height; ++j) { brightnessImage[i, j] = newImage.GetPixel(i, j).GetBrightness(); } } int range_num_width = newImage.Width / range_block_size; int range_num_height = newImage.Height / range_block_size; Object.Block[,] newRangeArray = new Object.Block[range_num_width, range_num_height]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { newRangeArray[i, j].X = i * range_block_size; newRangeArray[i, j].Y = j * range_block_size; } } rangeTree = new BlockTree[range_num_width, range_num_height]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { numLock = 1; rangeTree[i, j] = new BlockTree(newRangeArray[i, j], newRangeArray[i, j].BlockSize); } } //Доменные блоки представлены не в виде деревьев, а в виде трехмерных массивов domain_num_width = range_num_width - 1; domain_num_height = range_num_height - 1; domain_block_size = range_block_size * 2; domainArray = new Object.Block[domain_num_width, domain_num_height]; //System.Console.WriteLine(DomainBlocks.Length); domainBlocks = new Object.BlockArray[PostProcessing.GetPow(domain_block_size)]; for (int i = 0; i < domainBlocks.Length; ++i) { if (i == 0) { domainBlocks[i].BlockSize = domain_block_size; } else { domainBlocks[i].BlockSize = domainBlocks[i - 1].BlockSize / 2; } domainBlocks[i].num_width = newImage.Width / domainBlocks[i].BlockSize; domainBlocks[i].num_height = newImage.Height / domainBlocks[i].BlockSize; domainBlocks[i].Blocks = new Object.Block[domainBlocks[i].num_width, domainBlocks[i].num_height]; for (int j = 0; j < domainBlocks[i].num_width; ++j) { for (int k = 0; k < domainBlocks[i].num_height; ++k) { domainBlocks[i].Blocks[j, k] = CreateBlockDomain(j * domainBlocks[i].BlockSize / 2, k * domainBlocks[i].BlockSize / 2, newImageColor, domainBlocks[i].BlockSize / 2, brightnessImage); } } } List <Object.Coefficients> listCoeff = new List <Object.Coefficients>(); Object.Coefficients coeff = new Object.Coefficients(); for (int i = 0; i < listSize; ++i) { tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1); coeff.Depth = tmp[0]; ++fileCount; tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1); coeff.X = tmp[0]; fileCount += 1; tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 1); coeff.Y = tmp[0]; fileCount += 1; tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2); coeff.shiftR = BitConverter.ToInt16(tmp, 0); fileCount += 2; tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2); coeff.shiftG = BitConverter.ToInt16(tmp, 0); fileCount += 2; tmp = MyConverter.ReadByte(bytesFile, fileCount, fileCount + 2); coeff.shiftB = BitConverter.ToInt16(tmp, 0); fileCount += 2; listCoeff.Add(coeff); } int blI = 0, blJ = -1; for (int i = 0; i < listCoeff.Count; ++i) { PrintCoefficients(listCoeff[i]); } for (int i = 0; i < listCoeff.Count; ++i) { if (listCoeff[i].Depth < 0) { ++blJ; if (blJ == range_num_height) { ++blI; blJ = 0; } } rangeTree[blI, blJ].AddCoeff(rangeTree[blI, blJ], listCoeff[i]); } //Построение изображения из деревьев for (int i = 0; i < 10; ++i) { for (int j = 0; j < range_num_width; ++j) { for (int k = 0; k < range_num_height; ++k) { rangeTree[j, k].DrawTree(rangeTree[j, k], domainBlocks, newImageColor); } } } for (int j = 0; j < newImage.Width; ++j) { for (int k = 0; k < newImage.Height; ++k) { newImage.SetPixel(j, k, newImageColor[j, k]); } } newImage.Save(@"C:\Users\dbogdano\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Quad file.bmp", System.Drawing.Imaging.ImageFormat.Bmp); }
public static void Compression(string filename, string quality) { if (!(File.Exists(filename))) { System.Console.WriteLine("Файла не существует"); return; } //Черно-белый файл или нет if (quality == "Black") { colorflag = 1; } else { if (quality == "Color") { colorflag = 3; } else { System.Console.WriteLine("Тип выбран не правильно"); return; } } Bitmap image = new Bitmap(filename); classImageColor = new Color[image.Width, image.Height]; for (int i = 0; i < image.Width; ++i) { for (int j = 0; j < image.Height; ++j) { classImageColor[i, j] = image.GetPixel(i, j); } } double[,] BrightnessImage = new double[image.Width, image.Height]; for (int i = 0; i < image.Width; ++i) { for (int j = 0; j < image.Height; ++j) { BrightnessImage[i, j] = image.GetPixel(i, j).GetBrightness(); } } //Основной параметр, отвечающий за размеры ранговых блоков range_block_size = 128; //Создаём ранговые блоки range_num_width = image.Width / range_block_size; range_num_height = image.Height / range_block_size; rangeArray = new Object.Block[range_num_width, range_num_height]; for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { rangeArray[i, j] = CreateBlockRange(i * range_block_size, j * range_block_size, classImageColor, range_block_size, BrightnessImage); } } //Создаем доменные блоки domain_num_width = range_num_width - 1; domain_num_height = range_num_height - 1; domain_block_size = range_block_size * 2; domainArray = new Object.Block[domain_num_width, domain_num_height]; for (int i = 0; i < domain_num_width; ++i) { for (int j = 0; j < domain_num_height; ++j) { domainArray[i, j] = CreateBlockDomain(i * range_block_size, j * range_block_size, classImageColor, range_block_size, BrightnessImage); } } //Алгоритм сжатия count = 1; //Общеее число преобразований block_all_num = colorflag * range_num_width * range_num_height; compressCoeff = new Object.Coefficients[range_num_width, range_num_height, 1]; BinaryWriter bw = new BinaryWriter(File.Open(@"C:\Users\Admin\Documents\GitHub\Fractal-Compression\NewFractalCompression\NewFractalCompression\Compression", FileMode.Create)); Parallel.For(0, range_num_width, FindCoefficients); //Выводим коэффиценты в файл bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Width), 2)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(image.Height), 2)); bw.Write(MyConverter.Convert(BitConverter.GetBytes(range_block_size), 1)); for (int k = 0; k < 1; ++k) { for (int i = 0; i < range_num_width; ++i) { for (int j = 0; j < range_num_height; ++j) { Byte[] X = BitConverter.GetBytes(compressCoeff[i, j, k].X); Byte[] Y = BitConverter.GetBytes(compressCoeff[i, j, k].Y); Byte[] SR = BitConverter.GetBytes(compressCoeff[i, j, k].shiftR); Byte[] SG = BitConverter.GetBytes(compressCoeff[i, j, k].shiftG); Byte[] SB = BitConverter.GetBytes(compressCoeff[i, j, k].shiftB); bw.Write(MyConverter.Convert(X, 1)); bw.Write(MyConverter.Convert(Y, 1)); bw.Write(MyConverter.Convert(SR, 2)); bw.Write(MyConverter.Convert(SG, 2)); bw.Write(MyConverter.Convert(SB, 2)); } } } bw.Close(); }
//Классический вариант метрики static public double DistanceClass(Color[,] rangeImageColor, Color[,] domainImageColor, Object.Block rangeBlock, Object.Block domainBlock, int range_block_size, double shift, int flag) { double distance = 0; double rangeValue = 0; double domainValue = 0; if (flag == 0) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].R; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].R; distance += Metrics.Two(rangeValue, domainValue, shift); } } return(distance); } if (flag == 1) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].G; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].G; distance += Metrics.Two(rangeValue, domainValue, shift); } } return(distance); } if (flag == 2) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].B; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].B; distance += Metrics.Two(rangeValue, domainValue, shift); } } return(distance); } return(distance); }
//Определение метрики между двумя блоками //Один из вариантов метрики, предложенный Шарабайко, который по его версии должен ускорить подсчёт static public double DistanceShar(Color[,] rangeImageColor, Color[,] domainImageColor, Object.Block rangeBlock, Object.Block domainBlock, int range_block_size, double shift, int flag) { double distance = 0; double rangeValue = 0; double domainValue = 0; double sum = 0; if (flag == 0) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].R; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].R; sum += rangeValue + domainValue; } } distance = (0.75 * 0.75) * domainBlock.SumR2 + (range_block_size * range_block_size) * (shift * shift) + domainBlock.SumR2 - (2 * 0.75) * sum + (2 * 0.75 * shift) * domainBlock.SumR - (2 * shift * rangeBlock.SumR); return(distance); } if (flag == 1) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].G; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].G; sum += rangeValue + domainValue; } } distance = (0.75 * 0.75) * domainBlock.SumG2 + (range_block_size * range_block_size) * (shift * shift) + domainBlock.SumG2 - (2 * 0.75) * sum + (2 * 0.75 * shift) * domainBlock.SumG - (2 * shift * rangeBlock.SumG); return(distance); } if (flag == 2) { for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].B; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].B; sum += rangeValue + domainValue; } } distance = (0.75 * 0.75) * domainBlock.SumB2 + (range_block_size * range_block_size) * (shift * shift) + domainBlock.SumB2 - (2 * 0.75) * sum + (2 * 0.75 * shift) * domainBlock.SumB - (2 * shift * rangeBlock.SumB); return(distance); } return(distance); }
static public double PSNR(Color[,] rangeImageColor, Color[,] domainImageColor, Object.Block rangeBlock, Object.Block domainBlock, int range_block_size, double shift, int flag) { double distance = 0; double rangeValue = 0; double domainValue = 0; for (int i = 0; i < range_block_size; ++i) { for (int j = 0; j < range_block_size; ++j) { rangeValue = rangeImageColor[rangeBlock.X + i, rangeBlock.Y + j].B; domainValue = domainImageColor[domainBlock.X + (i * 2), domainBlock.Y + (j * 2)].B; distance += Math.Pow((rangeValue - domainValue), 2); } } distance = Math.Sqrt(distance) / (range_block_size * range_block_size); distance = -20 * Math.Log(distance); return(distance); }