/// <summary>
        /// Сохранение видео как набора ключевых кадров
        /// </summary>
        /// <param name="video">Видео</param>
        /// <param name="pen">Кисть для отрисовки границ текстовых областей</param>
        /// <param name="fileName">Путь для сохранения</param>
        /// <param name="framesSubDir">Имя директории для сохранения ключевых кадров</param>
        /// <param name="frameExpansion">Расширение кадра</param>
        public Task<bool> SaveVideoAsync(GreyVideo video, System.Drawing.Pen pen, string fileName, string framesSubDir, string framesExpansion)
        {
            try
            {
                if (video == null)
                    throw new ArgumentNullException("Null video");
                if (fileName == null || fileName.Length == 0)
                    throw new ArgumentNullException("Null pathToSave");
                if (framesSubDir == null || framesSubDir.Length == 0)
                    throw new ArgumentNullException("Null framesSubDir");
                if (framesExpansion == null || framesExpansion.Length == 0)
                    throw new ArgumentNullException("Null framesExpansion");
                if (pen == null)
                    throw new ArgumentNullException("Null pen");

                return Task.Run(() =>
                {
                    SaveVideoFrames(video, pen, fileName, framesSubDir, framesExpansion);
                    return true;
                });
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }
        /// <summary>
        /// Запись инфориации о текстовых блоках видеопотока в XML - файл 
        /// </summary>
        /// <param name="video">Видео</param>
        /// <param name="fileName">Имя файла</param>
        /// <returns>true</returns>
        public static Task<bool> WriteTextBlocksInformation(GreyVideo video, string fileName)
        {
            if (video == null || video.Frames == null)
                throw new ArgumentNullException("Null video in WriteTextBlocksInformation");
            if (fileName == null || fileName.Length == 0)
                throw new ArgumentNullException("Null fileName in WriteTextBlocksInformation");
            try
            {
                return Task.Run(() =>
                {
                    XmlWriterSettings settings = new XmlWriterSettings();
                    settings.Indent = true;
                    settings.IndentChars = "\t";
                    System.Xml.XmlWriter xmlWriter = System.Xml.XmlWriter.Create(fileName, settings);
                    xmlWriter.WriteStartDocument();
                    xmlWriter.WriteStartElement("Video");

                    for (int i = 0; i < video.Frames.Count; i++)
                        XMLWriter.WriteTextBlocksInformation(video.Frames[i].Frame.TextRegions, xmlWriter, video.Frames[i].FrameNumber, fileName);

                    xmlWriter.WriteEndDocument();
                    xmlWriter.Flush();
                    xmlWriter.Close();
                    return true;
                });
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }
        /// <summary>
        /// Сохранение обработанных ключевых кадров видео
        /// </summary>
        /// <param name="video">Видео</param>
        /// <param name="pen">Кисть для выделения текстовых областей</param>
        /// <param name="fileName">Путь к сохранению</param>
        /// <param name="framesSubDir">Имя директории для сохранения ключевых кадров</param>
        /// <param name="frameExpansion">Расширение кадра</param>
        private void SaveVideoFrames(GreyVideo video, System.Drawing.Pen pen, string fileName, string framesSubDir, string frameExpansion)
        {
            try
            {
                if (video.Frames != null)
                {
                    int framesNumber = video.Frames.Count;
                    string framesDirName = Path.Combine(fileName, framesSubDir);
                    if (!Directory.Exists(framesDirName))
                        Directory.CreateDirectory(framesDirName);

                    for (int i = 0; i < framesNumber; i++)
                    {
                        string frameFileName = Path.Combine(framesDirName, i.ToString() + frameExpansion);
                        SaveVideoFrameAsync(video.Frames[i], pen, frameFileName);
                        if (i == framesNumber - 1)
                            videoFrameSavedEvent(i, true);
                        else
                            videoFrameSavedEvent(i, false);
                    }
                }
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }
        /// <summary>
        /// Выделение текста на кд\лючевых кадрах видеоролика
        /// </summary>
        /// <param name="video">Видеоролик</param>
        /// <returns>true</returns>
        public Task<bool> DetectText(GreyVideo video, int threadsNumber)
        {
            try
            {
                if (video == null)
                    throw new ArgumentNullException("Null video in DetectText");
                if (video.Frames == null)
                    throw new ArgumentNullException("Null video frames in DetectText");

                return Task.Run(() =>
                {
                    for (int i = 0; i < video.Frames.Count; i++)
                        if (video.Frames[i].NeedProcess)
                        {
                            EdgeDetectionFilter sobel = new SobelFilter();
                            SmoothingFilter gauss = new GaussFilter(this.GaussFilterSize, this.GaussFilterSigma);
                            GradientFilter gradientFiler = new SimpleGradientFilter();
                            CannyEdgeDetection canny = new CannyEdgeDetection(gauss, sobel, this.CannyLowTreshold, this.CannyHighTreshold);

                            SWTTextDetection SWTTextDetection = new SWTTextDetection(canny, null, gradientFiler, this.VarienceAverageSWRation,
                                this.AspectRatio, this.DiamiterSWRatio, this.BbPixelsNumberMinRatio, this.BbPixelsNumberMaxRatio, this.ImageRegionHeightRationMin,
                                this.ImageRegionWidthRatioMin, this.PairsHeightRatio, this.PairsIntensityRatio, this.PairsSWRatio,
                                this.PairsWidthDistanceSqrRatio, this.PairsOccupationRatio, this.MinLettersNumberInTextRegion, this.MergeByDirectionAndChainEnds);

                            SWTTextDetection.DetectText(video.Frames[i].Frame, threadsNumber);
                        }
                   return true;
                });
            }
            catch (Exception exception)
            {
                throw exception;
            }
        }
        /// <summary>
        /// Загрузка видео
        /// </summary>
        private async void LoadVideoFileFunction()
        {
            try
            {
                this.video = new GreyVideo();

                progressWindow = ProgressWindow.InitializeProgressWindow();
                OkButtonWindow okButtonWindow = OkButtonWindow.InitializeOkButtonWindow();

                OpenFileDialog dialog = new OpenFileDialog();
                dialog.Filter = "MP4 Image (.mp4)|*.mp4|3gp (.3gp)|*.3gp|Avi (.avi)|*.avi";
                dialog.ShowDialog();

                FrameSizeWindow frameSizeWindow = FrameSizeWindow.InitializeFrameSizeWindow();
                frameSizeWindow.capitalText.Text = PARAMETERS_SETTING_STRING;
                frameSizeWindow.ShowDialog();

                FrameSizeViewModel frameSizeViewModel = (FrameSizeViewModel)frameSizeWindow.DataContext;

                progressWindow.capitalText.Text = LOAD_VIDEO_STRING;
                progressWindow.textInformation.Text = VIDEO_INITIALIZATION_STRING;
                progressWindow.Show();

                string videoFilePath = System.IO.Path.GetDirectoryName(dialog.FileName);
                string videoFileName = System.IO.Path.GetFileNameWithoutExtension(dialog.FileName);
                string keyFramesInormatyionFilePath = System.IO.Path.Combine(videoFilePath, videoFileName + ".txt");

                IOData ioData = new IOData() { FileName = dialog.FileName, FrameHeight = frameSizeViewModel.FrameHeight, FrameWidth = frameSizeViewModel.FrameWidth };

                VideoLoader videoLoader = new VideoLoader();
                int framesNumber = await videoLoader.CountFramesNumberAsync(ioData);            
                progressWindow.pbStatus.SmallChange = (double)progressWindow.pbStatus.Maximum / (double)framesNumber;

                /// Если существует файл с информацией о ключевых кадрах
                if (System.IO.File.Exists(keyFramesInormatyionFilePath))
                {
                    FileReader fileReader = new FileReader();
                    FileReader.ExceptionOccuredEvent += this.ExceptionOccuredEventHandler;
                    keyFrameIOInformation = await fileReader.ReadKeyFramesInformationAsync(keyFramesInormatyionFilePath, frameSizeViewModel.FrameWidth, frameSizeViewModel.FrameHeight);
                    ioData.KeyFrameIOInformation = keyFrameIOInformation;                    

                   // EdgeBasedKeyFrameExtractor.keyFrameExtractedEvent += this.KeyFramesExtractionProcessing;
                   // EdgeBasedKeyFrameExtractor edgeBasedKeyFrameExtractor = new EdgeBasedKeyFrameExtractor();
                  //  this.video.Frames = await edgeBasedKeyFrameExtractor.ExtractKeyFramesByListNumberAsync(ioData);
                }
                else   /// Если нет, то выделяем кадры алгоритмически
                {
                    EdgeBasedKeyFrameExtractor.keyFrameExtractedEvent += this.KeyFramesExtractionProcessing;
                    EdgeBasedKeyFrameExtractor.framesDifferenceEvent += this.FramesDifferenceCalculateProcessing;
                    EdgeBasedKeyFrameExtractor edgeBasedKeyFrameExtractor = new EdgeBasedKeyFrameExtractor();
                    this.video.Frames = await edgeBasedKeyFrameExtractor.ExtractKeyFramesTwoPassAsync(ioData);
                }
                okButtonWindow = OkButtonWindow.InitializeOkButtonWindow();
                okButtonWindow.capitalText.Text = LOAD_VIDEO_STRING;
                okButtonWindow.textInformation.Text = LOAD_VIDEO_SUCCESS_STRING;
                okButtonWindow.ShowDialog();

                progressWindow.Close();                
                this.VideoFileName = new Uri(dialog.FileName);
                this.videoFileNameString = dialog.FileName;
                this.MediaPlayerNavigationVisibility = Visibility.Visible;
                this.VideoWasNotLoaded = Visibility.Hidden;

                this.IsVideoFrameTabSelected = false;
                this.IsProcessedVideoFramesTabSelected = false;
                this.IsProcessedVideoFrameTabSelected = false;
                this.IsVideoTabSelected = true;
            }
            catch (Exception exception)
            {
                progressWindow.Hide();
                ShowExceptionMessage(exception.Message);             
            }
        }