Beispiel #1
0
 /// <summary>
 /// 2й по важности метод класса. Разбивает массив точек на контура, в зависимости от того, с какими областями\объектами они граничат. В связке с <see cref="ImagePrData"/> фактически полностью векторизирует изображение.
 /// </summary>
 /// <param name="arr">Массив для выделения контуров</param>
 private VPointEx[][] SortPointArray(VPointEx[] arr)
 {
     VPointEx[][] result = new VPointEx[0][];
     while (arr.Length > 0)
     {
         var a  = arr[0].BordWith;
         var tm = new VPointEx[0];
         Helper.InsertToArray(ref tm, arr[0]);
         Helper.DeleteFromArray(1, ref arr);
         var needtodelete = new int[0];
         for (int i = 0; i <= arr.Length - 1; i++)
         {
             if (arr[i].BordWith == a)
             {
                 Helper.InsertToArray(ref tm, arr[i]);
                 Helper.InsertToArray(ref needtodelete, i + 1);
             }
         }
         if (arr.Length != 0)
         {
             if (needtodelete != null)
             {
                 Array.Sort(needtodelete);
                 for (int ii = needtodelete.Length - 1; ii >= 0; ii--)
                 {
                     Helper.DeleteFromArray(needtodelete[ii], ref arr);
                 }
             }
         }
         Helper.InsertToArray(ref result, tm);
     }
     return(result);
 }
Beispiel #2
0
        /// <summary>
        /// Сортировка контуров так, чтобы расстояние между ними было минимальное, и перо совершало найменшее количество перемещений.
        /// </summary>
        /// <param name="Arr"></param>
        private void CSort(ref VPointEx[][] Arr)
        {
            var res           = new VPointEx[0][];
            var checked_      = new VPointEx[0];
            var first         = Arr[0]; checked_ = first;
            var uncheckedmask = new bool[Arr.Length];

            for (int ii = 0; ii <= Arr.Length; ii++)
            {
                var mostshort = 99999.9;
                int num       = 0;
                for (int i = 0; i <= Arr.Length - 1; i++)
                {
                    if (!uncheckedmask[i])
                    {
                        var dist = Distance(checked_[checked_.Length - 1].BasePoint, Arr[i][0].BasePoint);
                        if (dist < mostshort)
                        {
                            mostshort = dist; num = i;
                        }
                    }
                }
                checked_           = Arr[num];
                uncheckedmask[num] = true;
                Helper.InsertToArray(ref res, checked_);
            }
            Arr = res;
        }
Beispiel #3
0
        /// <summary>
        /// Загружает вектор формата .PCV.
        /// </summary>
        /// <param name="filename">Имя файла для загрузки</param>
        private void LoadVectPCV(string filename)
        {
            VPointEx[][] contours = new VPointEx[0][];
            string       s        = new string(GetBytesAndRemoveHeader(filename).Select(pp => (char)pp).ToArray());

            //TODO: Это по прежнему не совместимо с PCV старого образца, с VectArch.
            //Нид сделать что-то по типу удаления того "хедера" и читать его.

            var data    = s.Split(';');
            var head    = new VectHeader();
            var header_ = data[0].Split(',');

            head.Width  = float.Parse(header_[1], CultureInfo.InvariantCulture);
            head.Height = float.Parse(header_[2], CultureInfo.InvariantCulture);
            switch (header_[3].ToLower().Trim())
            {
            case ("rastr"):
                head.VectType = VectType.Rastr;
                break;

            case ("func"):
                head.VectType = VectType.Func;
                break;

            case ("curve"):
                head.VectType = VectType.Curve;
                break;

            case ("svgvector"):
                head.VectType = VectType.SvgVector;
                break;

            default: throw new ArgumentException("Указан неверный тип вектора");
            }
            //try { head.CountOfCont = int.Parse(header_[4]); } catch { throw new ArgumentException("Указано неверное число контуров вектора"); }
            var p = data[1].Split('?');

            head.CountOfCont = p.Length;
            contours         = new VPointEx[p.Length][];
            for (int i = 0; i <= p.Length - 1; i++)
            {
                var data1         = p[i];
                var data2         = data1.Split(':');
                var countofpoints = data2.Length;
                contours[i] = new VPointEx[countofpoints - 1];
                for (int ii = 0; ii <= data2.Length - 2; ii++)
                {
                    var Coordinates = data2[ii].Split(',');
                    var xs          = Coordinates[0];
                    var ys          = Coordinates[1];
                    contours[i][ii] = new VPointEx(float.Parse(xs, CultureInfo.InvariantCulture), float.Parse(ys, CultureInfo.InvariantCulture), 0, Color.Black);
                }
            }
            Helper.DeleteFromArray(contours.Length, ref contours);
            Header  = head;
            RawData = contours;
        }
Beispiel #4
0
        /// <summary>
        /// Находит разницу двух точек и возвращает результаты типа <see cref="Int16"/>, как массив 4х байтов.
        /// </summary>
        /// <param name="pn1">Первая точка.</param>
        /// <param name="pn2">Вторая точка.</param>
        private byte[] DeltaPoints(VPointEx p1, VPointEx p2)
        {
            var dx    = BitConverter.GetBytes((Int16)(-p1.BasePoint.X + p2.BasePoint.X));
            var dy    = BitConverter.GetBytes((Int16)(-p1.BasePoint.Y + p2.BasePoint.Y));
            var bytes = new byte[4];

            Buffer.BlockCopy(dx, 0, bytes, 0, 2);
            Buffer.BlockCopy(dy, 0, bytes, 2, 2);
            return(bytes);
        }
Beispiel #5
0
        /// <summary>
        /// Загружает вектор формата .PRRES.
        /// </summary>
        /// <param name="FileName">Имя файла для загрузки.</param>
        private void LoadVectPrres(string FileName)
        {
            VPointEx[][] contours;// = new VPointEx[0][];
            var          s       = File.ReadAllText(FileName);
            var          main    = s.Split('$');
            var          header  = main[0].Split(';');
            VectHeader   headerr = new VectHeader();

            if (header[0] == "prres")
            {
                headerr.Width       = int.Parse(header[1]);
                headerr.Height      = int.Parse(header[2]);
                headerr.CountOfCont = int.Parse(header[6]);
                headerr.VectType    = VectType.Rastr; //TODO sdelat` normalnoe opredelenie tipa vectora
                contours            = new VPointEx[headerr.CountOfCont][];
                for (int i = 0; i <= headerr.CountOfCont - 1; i++)
                {
                    var data1         = main[i + 1].Split('?');
                    var countofpoints = data1[0];
                    contours[i] = new VPointEx[int.Parse(countofpoints)];
                    var data2 = data1[1].Split(';');
                    for (int j = 0; j <= data2.Length - 2; j++)
                    {
                        var coordinates = data2[j].Split(',');
                        var xs          = coordinates[0];
                        Helper.Delete(ref xs, 1, 1);
                        var ys = coordinates[1];
                        Helper.Delete(ref ys, ys.Length, 1);
                        contours[i][j] = new VPointEx(int.Parse(xs), int.Parse(ys), 0, Color.Black);
                    }
                }
            }
            else
            {
                return;
            }
            Header  = headerr;
            RawData = contours;
        }
Beispiel #6
0
        /// <summary>
        /// Основной метод класса. Выделяет те самые массивы точек, которые методом <see cref="SortPointArray(VPointEx[])"/> бьются на контура. Сортирует их и чистит от хлама. Возвращает и берет данные с соответсвущих словарей. Многопоточная операция.
        /// </summary>
        private void ImagePrData()
        {
            // == ШАГ 1: ОБЪЯВЛЕНИЕ ЛОКАЛЬНЫХ ПЕРЕМЕННЫХ ==


            //Основной счетчик. Обозначает уникальный номер области или объекта.
            int AreaMark = 0;
            //Результирующий массив контуров.
            var Contours = new VPointEx[0][];
            //Изначальное биннарное представление изображения. Если пиксель равен (0,0,0), то digMap на этом индексе будет равен 1.
            var digMap = new int[0][];
            //Само изображение данного потока.
            var ProceedImage = _imgMap[Thread.CurrentThread.ManagedThreadId];
            //Массив, с обозначенными на нем областями.
            var WhiteMap = new int[0][];

            //Массив цветов изображения.
            Color[][] BufferImage = new Color[0][];


            // == ШАГ 2: ПОДГОТОВКА ==


            //Вывод информации о выполении новой операции.
            if (_outputDebugInfo)
            {
                Console.WriteLine(string.Format(_initSay, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.ThreadState, Thread.CurrentThread.Priority, (Milliseconds / 1000)));
                Console.WriteLine(string.Format(_stateSay, Thread.CurrentThread.ManagedThreadId, "Init", (Milliseconds / 1000)));
            }
            _proList[Thread.CurrentThread.ManagedThreadId]++;

            //Задаем размер BufferImage.
            Helper.ResizeArray(ref BufferImage, ProceedImage.Height, ProceedImage.Width);
            //Задаем размер digMap.
            Helper.ResizeArray(ref digMap, BufferImage.Length, BufferImage[0].Length);

            //Заполняем BufferImage цветами из ProceedImage.
            for (int i = 0; i <= ProceedImage.Width - 1; i++)
            {
                for (int ii = 0; ii <= ProceedImage.Height - 1; ii++)
                {
                    BufferImage[ii][i] = ProceedImage.GetPixel(i, ii);
                }
            }

            //Заполняем digMap по вышеуказанному правилу.
            for (int i = 0; i <= BufferImage.Length - 2; i++)
            {
                for (int ii = 0; ii <= BufferImage[0].Length - 2; ii++)
                {
                    if (BufferImage[i][ii].R == 0 && BufferImage[i][ii].G == 0 && BufferImage[i][ii].B == 0)
                    {
                        digMap[i][ii] = 1;
                    }
                }
            }

            //Добавляем digMap по 2 пустых ячейки с каждой стороны.
            Surround(ref digMap);
            Surround(ref digMap);

            //Создаем копию digMap.
            WhiteMap = digMap;


            // == ШАГ 3: ПОИСК ОБЛАСТЕЙ ==


            //Вывод информации о выполении новой операции.
            if (_outputDebugInfo)
            {
                Console.WriteLine(string.Format(_stateSay, Thread.CurrentThread.ManagedThreadId, "Searching For Areas", (Milliseconds / 1000)));
            }
            _proList[Thread.CurrentThread.ManagedThreadId]++;

            //Присваиваем 3, потому что 0,1 и 2 зарезервированы.
            AreaMark = 3;

            //Для каждого пикселя выполняем.
            for (int i = 1; i <= BufferImage.Length - 2; i++)
            {
                for (int ii = 1; ii <= BufferImage[0].Length - 2; ii++)
                {
                    //Если, проверяеммый пиксель пустой (что есть условием существования области)
                    if (WhiteMap[i][ii] == 0)
                    {
                        //Обозначиваем этот пиксель уникальным для области номером.
                        WhiteMap[i][ii] = AreaMark;

                        //Следующая операция выполняется для присваивания всем пикселям данной области, одного и того же номера.
                        //Некий аналог рекурсивного метода поиска объектов.
                        while (true)
                        {
                            //Указывает на то, были ли произведены какие-либо изменения.
                            bool changedSomething = false;

                            //Для каждого пикселя выполняем.
                            for (int i2 = 1; i2 <= BufferImage.Length - 2; i2++)
                            {
                                for (int ii2 = 1; ii2 <= BufferImage[0].Length - 2; ii2++)
                                {
                                    //Если есть пиксель, рядом с пикселем, помеченным нашим текущем AreaMark, то...
                                    if (WhiteMap[i2][ii2] == 0 && NearK(WhiteMap, i2, ii2, AreaMark))
                                    {
                                        //...и этот пиксель помечаем, как AreaMark.
                                        WhiteMap[i2][ii2] = AreaMark;
                                        //Помечаем, что изменили что-то.
                                        changedSomething = true;
                                    }
                                }
                            }
                            if (!changedSomething)
                            {
                                break;
                            }
                        }
                        AreaMark++;
                    }
                }
            }


            // == ШАГ 4: ПОИСК ОБЪЕКТОВ ==

            //Вывод информации о выполении новой операции.
            if (_outputDebugInfo)
            {
                Console.WriteLine(string.Format(_stateSay, Thread.CurrentThread.ManagedThreadId, "Searching For Objects", (Milliseconds / 1000)));
            }
            _proList[Thread.CurrentThread.ManagedThreadId]++;


            //Создаем копию digMap.
            var MaskArray = digMap;

            //Для отделения областей от объектов, добавляем к счетчику еще 2.
            var ObjectMark = AreaMark + 2;

            //Для каждого пикселя выполняем.
            for (int i = 1; i <= BufferImage.Length - 2; i++)
            {
                for (int ii = 1; ii <= BufferImage[0].Length - 2; ii++)
                {
                    //Если, проверяеммый пиксель не пустой (что есть условием существования объекта)
                    if (MaskArray[i][ii] == 1)
                    {
                        //tempPointArray - временный массив несортированых точек.
                        VPointEx[] tempPointArray = new VPointEx[0];

                        //Обозначиваем этот пиксель уникальным для объетка номером.
                        MaskArray[i][ii] = ObjectMark;

                        //Если, этот пиксель граничит с каким-то пикселем из области (т.е. его значение <= AreaMark)...
                        for (int d = 3; d <= AreaMark - 1; d++)
                        {
                            if (NearK(WhiteMap, i, ii, d))
                            {
                                //..., то добавляем его в наш массив.
                                Helper.InsertToArray(ref tempPointArray, new VPointEx(i, ii, d, Color.Empty));
                            }
                        }

                        //Далее выполняется аналог предыдущей операции, с некоторым изменениям.
                        while (true)
                        {
                            //Указывает на то, были ли произведены какие-либо изменения.
                            bool changedSomething = false;

                            //Для каждого пикселя выполняем.
                            for (int i2 = 1; i2 <= BufferImage.Length - 2; i2++)
                            {
                                for (int ii2 = 1; ii2 <= BufferImage[0].Length - 2; ii2++)
                                {
                                    //Если есть пиксель, рядом с пикселем, помеченным нашим текущем ObjectMark, то...
                                    if (MaskArray[i2][ii2] == 1 && NearK(MaskArray, i2, ii2, ObjectMark))
                                    {
                                        //...и этот пиксель помечаем, как ObjectMark.
                                        MaskArray[i2][ii2] = ObjectMark;
                                        //Помечаем, что изменили что-то.
                                        changedSomething = true;

                                        //В этом случаем, мы выполняем то же, что и с первым пекселем.
                                        //Если, этот пиксель граничит с каким-то пикселем из области (т.е. его значение <= AreaMark)...
                                        for (int d = 3; d <= AreaMark - 1; d++)
                                        {
                                            if (NearK(WhiteMap, i2, ii2, d))
                                            {
                                                //..., то добавляем его в наш массив.
                                                Helper.InsertToArray(ref tempPointArray, new VPointEx(i2, ii2, d, Color.Empty));
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if (!changedSomething)
                            {
                                break;
                            }
                        }
                        ObjectMark++;

                        //Далее сортируем наш массив.
                        var tmp = SortPointArray(tempPointArray);
                        //Сливаем его с нашим Contours.
                        Helper.ConcatArrays(ref Contours, ref tmp);
                        tmp            = null;
                        tempPointArray = null;
                    }
                }
            }


            // == ШАГ 5: ОБРАБОТКА РЕЗУЛЬТАТОВ ==


            // ШАГ 5.1: Сортировка точек.

            //Вывод информации о выполении новой операции.
            if (_outputDebugInfo)
            {
                Console.WriteLine(string.Format(_stateSay, Thread.CurrentThread.ManagedThreadId, "Sorting Points", (Milliseconds / 1000)));
            }
            _proList[Thread.CurrentThread.ManagedThreadId]++;

            //Для каждого контура...
            for (int ii = 0; ii <= Contours.Length - 1; ii++)
            {
                VPoint[] sortedArray = new VPoint[0];
                //Добавляем в новый массив необходимые точки.
                //Это необходимо из-за различия типов VPoint и VPointEx.
                for (int i = 0; i <= Contours[ii].Length - 1; i++)
                {
                    Helper.InsertToArray(ref sortedArray, Contours[ii][i].BasePoint);
                }

                //Сортируем наш массив.
                PointSort(ref sortedArray);

                //Выполняем обратную операцию пресваивания.
                for (int i = 0; i <= Contours[ii].Length - 1; i++)
                {
                    Contours[ii][i].BasePoint = sortedArray[i];
                }
                sortedArray = null;
            }

            // ШАГ 5.2: Сортировка контуров и сохранения результата.

            //Вывод информации о выполении новой операции.
            if (_outputDebugInfo)
            {
                Console.WriteLine(string.Format(_stateSay, Thread.CurrentThread.ManagedThreadId, "Sorting Contours", (Milliseconds / 1000)));
            }
            _proList[Thread.CurrentThread.ManagedThreadId]++;

            //Сортировка всех контуров.
            CSort(ref Contours);

            //Сохраняем результат.
            _imgVect.Add(ProceedImage, Contours);

            //Отмечаем что процесс завершенн.
            _endList[Thread.CurrentThread.ManagedThreadId] = true;

            //Вывод информации о завершении процесса.
            if (_outputDebugInfo)
            {
                Console.WriteLine("Stream Ended. ID: " + Thread.CurrentThread.ManagedThreadId);
            }
        }