Exemple #1
0
        //Конструктор дерева
        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);
        }
Exemple #10
0
        //Построить по дереву изображение
        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);
        }