Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Отчет по практике1.docx
Скачиваний:
12
Добавлен:
15.08.2019
Размер:
4.24 Mб
Скачать

Приложение

Тексты классов TextLineDetector и LineDetector, выполяющих основные процедуры распознавания и LineList, являющийся коллекцией для хранения выделенных строк

static class TextLineDetector

public static BitmapSource GetTestLine(LineList WidePaires, BitmapSource Picture)

{

CroppedBitmap crop = new CroppedBitmap(Picture, new Int32Rect(0, WidePaires[0].X, Picture.PixelWidth, WidePaires[0].Y - WidePaires[0].X));

return crop;

}

/// <summary>

/// ищет угол перебором (применимо только для совсем маленьких углов)

/// </summary>

/// <param name="LineBitmap"></param>

/// <param name="avarage"></param>

/// <returns></returns>

public static LineInfo AngleSearch(BitmapSource LineBitmap, double avarage)

{

int minHigth = int.MaxValue;

double ResultAngle = 0;

Point MinLine = new Point();

for (double CurrentAngle = -1; CurrentAngle <= 1.005; CurrentAngle += 0.05)

{

Image img = new Image();

img.Source = LineBitmap;

img.RenderTransform = new RotateTransform(CurrentAngle);

Canvas container = new Canvas();

container.Children.Add(img);

container.Arrange(new Rect(0, 0, LineBitmap.PixelWidth, LineBitmap.PixelHeight));

RenderTargetBitmap target = new RenderTargetBitmap(LineBitmap.PixelWidth, LineBitmap.PixelHeight, LineBitmap.DpiX, LineBitmap.DpiY, PixelFormats.Default);

target.Render(container);

float[,] LineArray = target.ToArray();

Point CurrentLine = LineSearch(LineArray, avarage);

int currentHight = CurrentLine.Y - CurrentLine.X;

if (currentHight < minHigth)

{

minHigth = currentHight;

ResultAngle = CurrentAngle;

MinLine = CurrentLine;

}

}

LineInfo Result = new LineInfo() { Angle = ResultAngle, Bounaries = MinLine };

return Result;

}

/// <summary>

/// ищет одну строку

/// </summary>

/// <param name="LineArray"></param>

/// <param name="average"></param>

/// <returns></returns>

public static Point LineSearch(float[,] LineArray, double average)

{

bool EndLineFind = false;

int ScanSize = 3;

double[] CurrentSum = CountHistogram(LineArray);

int j = 0;

Point pair = new Point();

for (int i = 0; i < CurrentSum.Length - ScanSize + 1; i++)

{

if (CurrentSum.PartialSum(i, i + ScanSize) / ScanSize > average)

{

pair.X = i;

for (j = i; j < CurrentSum.Length - ScanSize + 1; j++)

if (CurrentSum.PartialSum(j, j + ScanSize) / ScanSize < average)

{

pair.Y = j;

EndLineFind = true;

break;

}

if (!EndLineFind)

{

j = CurrentSum.Length - 1;

}

return new Point(i, j);

}

}

return new Point();

}

#region Pairs Search for Histogramm

public static LineList GetSimplePairs2(double[] sum)

{

int ScanSize = 3;

double average = sum.Average();

LineList pairs = new LineList();

for (int i = 0; i < sum.Length - ScanSize + 1; i++)

{

Point pair = new Point();

if (sum.PartialSum(i, i + ScanSize) / ScanSize > average / 3)

{

pair.X = i;

for (int j = i; j < sum.Length - ScanSize + 1; j++)

if (sum.PartialSum(j, j + ScanSize) / ScanSize < average / 3)

{

pair.Y = j;

pairs.Add(pair);

i = j;

break;

}

}

}

int _int = pairs.AvStringInterval;

return pairs;

}

public static LineList GetPairs2(LineList SimplePairs)

{

LineList Result = SimplePairs;

int ThreSholdInterval;

double Coef = 1;

//если много сторок - отбрасываем 20% чтобы исчезли выбросы

if (Result.Count < 5)

ThreSholdInterval = (int)(Result.AvStringInterval*Coef);

else

ThreSholdInterval = (int)(Result.MyAvStringIntervel(Result.Count/5)*Coef);

for (int i = 0; i < Result.Count - 1; i++)

{

if (Result[i + 1].X - Result[i].Y < ThreSholdInterval)

{

Point JointPair = new Point(Result[i].X, Result[i + 1].Y);

Result.RemoveAt(i + 1); Result.RemoveAt(i);

Result.Insert(i, JointPair);

i--;

}

}

return Result;

}

/// <summary>

/// функция для проверки пересекли ли мы строку

/// </summary>

/// <param name="ScannLine"></param>

/// <returns></returns>

public static bool IsCrossed(double[] ScannLine)

{

double[] sum = TextLineDetector.CumulativeVariationForOneLine(ScannLine);

double[] derivative = TextLineDetector.NumericalDerivative(sum);

int ScanSize = 3;

for (int j = 0; j < derivative.Length - ScanSize + 1; j++)

if (derivative.PartialSum(j, j + ScanSize) / ScanSize < derivative.Average() / 3)

{

//нашли пересечение

return true;

}

return false;

}

/// <summary>

/// функция для проверки, пересекает ли линия строки (используется для того чтобы найти вертикальные или горизонтальные границы страницы)

/// </summary>

/// <returns></returns>

public static bool IsLineCrossed(double[] ScannLine)

{

double[] sum = TextLineDetector.CumulativeVariationForOneLine(ScannLine);

double[] derivative = TextLineDetector.NumericalDerivative(sum);

double average = derivative.Average();

int ScanSize = 3;

for (int i = 0; i < derivative.Length - ScanSize + 1; i++)

{

if (derivative.PartialSum(i, i + ScanSize) / ScanSize > average)

{

for (int j = i; j < derivative.Length - ScanSize + 1; j++)

if (derivative.PartialSum(j, j + ScanSize) / ScanSize < average)

{

if (j - i > 7)

return true;

i = j;

break;

}

}

}

return false;

}

#endregion

#region Pairs Search for Picture

public static LineList GetSimplePairs(float[,] document)

{

double[] sum = TextLineDetector.CountHistogram(document);

int ScanSize = 3;

double average = sum.Average();

LineList pairs = new LineList();

pairs.VerticalSize = (uint?)document.GetLength(0);

for (int i = 0; i < sum.Length - ScanSize + 1; i++)

{

Point pair = new Point();

if (sum.PartialSum(i, i + ScanSize) / ScanSize > average)

{

pair.X = i;

for (int j = i; j < sum.Length - ScanSize + 1; j++)

if (sum.PartialSum(j, j + ScanSize) / ScanSize < average)

{

pair.Y = j;

if (j - i > 7)

pairs.Add(pair);

i = j;

break;

}

}

}

return pairs;

}

public static LineList GetWidePairs(LineList SimplePairs, uint VerticalSize, double Up, double Down)

{

if (SimplePairs.Count > 0)

{

int AdditiveUp = (int)(SimplePairs.MinStringWidth / Up);

int AdditiveDown = (int)(SimplePairs.MinStringWidth / Down);

LineList result = new LineList();

result.VerticalSize = (uint?)VerticalSize;

int LastResidual = 0;

int NextResidual = 0;

Point LastPoint = new Point(Math.Max(SimplePairs[0].X - AdditiveUp, 0), Math.Min(SimplePairs[0].Y + AdditiveDown, (int)SimplePairs.VerticalSize));

Point NextPoint = LastPoint;//???

for (int i = 0; i < SimplePairs.Count - 1; i++)

{

NextPoint.X = SimplePairs[i + 1].X - AdditiveUp; NextPoint.Y = Math.Min(SimplePairs[i + 1].Y + AdditiveDown, (int)SimplePairs.VerticalSize);

NextResidual = (int)Math.Max((LastPoint.Y - NextPoint.X) / 2 + 1, 0);

result.Add(new Point(LastPoint.X + LastResidual, LastPoint.Y - NextResidual));

LastResidual = NextResidual;

LastPoint = NextPoint;

}

if (SimplePairs.Count == 1)

result.Add(LastPoint);

else

result.Add(new Point(LastPoint.X + LastResidual, Math.Min(LastPoint.Y, (int)SimplePairs.VerticalSize)));

return result;

}

else

return SimplePairs;

}

public static LineList GetPairs(double[] sum, LineList Pairs)

{

int ScanSize = 3;

double average = sum.Average();

for (int i = 0; i < Pairs.Count + 1; i++)

{

int index = 0;

Point CurrentInterval = new Point();

CurrentInterval = Pairs.IntervalArray[i]; //not optimal!!!!!!

if ((CurrentInterval.Y - CurrentInterval.X) > (Pairs.AvStringWidth + Pairs.AvStringInterval))

{

for (int j = CurrentInterval.X; j < CurrentInterval.Y - ScanSize + 1; j++)

{

Point CurrentSmallLine = new Point();

if (sum.PartialSum(j, j + ScanSize) / ScanSize > average / 3)

{

CurrentSmallLine.X = j;

for (int k = j; k < CurrentInterval.Y - ScanSize + 1; k++)

if (sum.PartialSum(k, k + ScanSize) / ScanSize < average / 3)

{

CurrentSmallLine.Y = k;

if (k - j > 7)

Pairs.Insert(i + index++, CurrentSmallLine);

j = k;

break;

}

}

}

}

}

return Pairs;

}

#endregion

#region Skew Pairs Search

public static LineList GetSkewSimplePairs(float[,] document,double angle, BorderResult border)

{

//может сюда проще передавать уже посчитаную гистограмму?

double[] sum = TextLineDetector.CountSkewHistogram(document,angle,border);

int ScanSize = 3;

double average = sum.Average();

LineList pairs = new LineList();

pairs.VerticalSize = (uint?)sum.Length;

for (int i = 0; i < sum.Length - ScanSize + 1; i++)

{

Point pair = new Point();

if (sum.PartialSum(i, i + ScanSize) / ScanSize > average)

{

pair.X = i;

for (int j = i; j < sum.Length - ScanSize + 1; j++)

if (sum.PartialSum(j, j + ScanSize) / ScanSize < average)

{

pair.Y = j;

if (j - i > 7)

pairs.Add(pair);

i = j;

break;

}

}

}

return pairs;

}

/// <summary>

/// задаем границы страницы, все считается только внутри них

/// </summary>

/// <param name="LineArray"></param>

/// <param name="angle"></param>

/// <param name="Borders"></param>

/// <returns></returns>

public static double[] CountSkewHistogram(float[,] LineArray, double angle, BorderResult border)

{

float[,] SkewLine = LineArray.GetSkewLines(angle,border);

double[] result = new double[SkewLine.GetLength(0)];

for (int i = 0; i < SkewLine.GetLength(0); i++)

{

for (int j = 0; j < SkewLine.GetLength(1) - 1; j++)

result[i] += Math.Pow(SkewLine[i, j] - SkewLine[i, j + 1], 2);

result[i] = Math.Sqrt(result[i]) / (LineArray.GetLength(1) - 1);

}

return result;

}

#endregion

public static double[] ClearHistogramFromZero(double[] histogramm)

{

// double[] result=(double[])histogramm.Where<double>(x => (x != 0));

IEnumerable<double> result=histogramm.Where<double>(x => (x != 0));;

return result.ToArray<double>();

}

public static BitmapSource GetLinearRegression(LinearCoefficient Coef, BitmapSource Picture)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

Draft.DrawRegressionLine(Coef, Colors.Blue);

//Draft.DrawHorizontalLine(100, Colors.Blue);

return Draft.ConvertToBitmapSource();

}

public static BitmapSource GetLineDraft(int Coordinate, BitmapSource Picture, Direction LinesDirection)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

if (LinesDirection == Direction.Horizontal)

Draft.DrawHorizontalLine(Coordinate, Colors.Blue);

else

Draft.DrawVerticalLine(Coordinate, Colors.Blue);

return Draft.ConvertToBitmapSource();

}

#region GetLinesDraft

public static BitmapSource GetLinesDraft(LineList Pairs, BitmapSource Picture, Direction LinesDirection)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

if (LinesDirection == Direction.Horizontal)

foreach (Point Pair in Pairs)

{

Draft.DrawHorizontalLine(Pair.X, Colors.Red);

Draft.DrawHorizontalLine(Pair.Y, Colors.Blue);

}

else

foreach (Point Pair in Pairs)

{

Draft.DrawVerticalLine(Pair.X, Colors.Red);

Draft.DrawVerticalLine(Pair.Y, Colors.Blue);

}

return Draft.ConvertToBitmapSource();

}

public static BitmapSource GetLinesDraft(int[] Coordinate, BitmapSource Picture, Direction LinesDirection)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

if (LinesDirection == Direction.Horizontal)

foreach (int el in Coordinate)

Draft.DrawHorizontalLine(el, Colors.Blue);

else

foreach (int el in Coordinate)

Draft.DrawVerticalLine(el, Colors.Blue);

return Draft.ConvertToBitmapSource();

}

public static BitmapSource GetLinesDraft(List<int> Coordinate, BitmapSource Picture, Direction LinesDirection)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

if (LinesDirection == Direction.Horizontal)

foreach (int el in Coordinate)

Draft.DrawHorizontalLine(el, Colors.Blue);

else

foreach (int el in Coordinate)

Draft.DrawVerticalLine(el, Colors.Blue);

return Draft.ConvertToBitmapSource();

}

#endregion //GetLinesdraft

public static BitmapSource GetSkewLinesDraft(LineList Pairs, BitmapSource Picture, double Angle)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

Draft.DrawSkewLines(Pairs, Angle);

return Draft.ConvertToBitmapSource();

}

/// <summary>

/// рисуем пары внутри выделеной страницы

/// </summary>

/// <param name="Pairs"></param>

/// <param name="Picture"></param>

/// <param name="Angle"></param>

/// <returns></returns>

public static BitmapSource GetSkewLinesDraft(LineList Pairs, BitmapSource Picture, double Angle, BorderResult border)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

Draft.DrawSkewLines(border, Pairs, Angle);

return Draft.ConvertToBitmapSource();

}

/// <summary>

/// возвращает изображение с нарисованными границами (пока функция не реализована из-за отсутствия функционала)

/// </summary>

/// <param name="TopBorder"></param>

/// <param name="Picture"></param>

/// <param name="Angle"></param>

/// <returns></returns>

public static BitmapSource GetSkewImageBorder(BorderResult Border, BitmapSource Picture, double Angle)

{

BitmapSourceDesigner Draft = new BitmapSourceDesigner(Picture);

Draft.DrawSkewBorder(Border, Angle);

return Draft.ConvertToBitmapSource();

}

/// <summary>

/// результат считается как среднее квадратичное

/// </summary>

/// <param name="LineArray"></param>

/// <returns></returns>

public static double[] CountHistogram(float[,] LineArray)

{

double[] result = new double[LineArray.GetLength(0)];

for (int i = 0; i < LineArray.GetLength(0); i++)

{

for (int j = 0; j < LineArray.GetLength(1) - 1; j++)

result[i] += Math.Pow(LineArray[i, j] - LineArray[i, j + 1], 2);

result[i] = Math.Sqrt(result[i]) / (LineArray.GetLength(1) - 1);

}

return result;

}

/// <summary>

/// результат является как просто среднее (на данный момент нигде не используется)

/// </summary>

/// <param name="LineArray"></param>

/// <returns></returns>

public static double[] CountHistogram2(float[,] LineArray)

{

double[] result = new double[LineArray.GetLength(0)];

for (int i = 0; i < LineArray.GetLength(0); i++)

{

for (int j = 0; j < LineArray.GetLength(1) - 1; j++)

result[i] += Math.Abs(LineArray[i, j] - LineArray[i, j + 1]);

}

return result;

}

public static double[] CumulativeVariationForOneLine(double[] Line)

{

double[] result = new double[Line.Length];

result[0] = 0;

for (int i = 1; i < Line.Length; i++)

result[i] = result[i - 1] + Math.Abs(Line[i] - Line[i - 1]);

return result;

}

public static double[] RegressionLine(double[] sum)

{

List<double> truncatedSumm = new List<double>(sum);

truncatedSumm.RemoveAll(el=>((el==sum.Min())||(el==sum.Max())));

double[] newSum = truncatedSumm.ToArray();

LinearCoefficient Coef = TextLineDetector.LinearRegression(newSum);

Size size = new Size(newSum.Length, newSum.Max());

double[] result = new double[sum.Length];

for (int i = Array.LastIndexOf<double>(sum, sum.Min()); i < sum.Length; i++)

{

int j = i - Array.LastIndexOf<double>(sum, sum.Min());

result[i] = Math.Min(Math.Max(0, Coef.a * j + Coef.b), size.Height);

}

return result;

}

/// <summary>

/// считает кумулятивную вероятность только для прямых линий

/// </summary>

/// <param name="LineArray"></param>

/// <param name="LineNumber"></param>

/// <returns></returns>

public static double[] CumulativeVariation(float[,] LineArray, int LineNumber)

{

if (LineNumber > LineArray.GetLength(0))

throw new ArgumentException("Line Nummber can not be more than Line Array length");

double[] line = LineArray.GetLine(LineNumber);

double[] result = CumulativeVariationForOneLine(line);

return result;

}

/// <summary>

/// кумулятивная вариация при поиске не по строке а под наклоном

/// </summary>

/// <param name="LineArray"></param>

/// <param name="LineNumber"></param>

/// <param name="Angle"></param>

/// <returns></returns>

public static double[] CumulativeVariation(float[,] LineArray, int LineNumber, double Angle)

{

if (LineNumber > LineArray.GetLength(0))

throw new ArgumentException("Line Nummber can not be more than Line Array length");

double[] line = LineArray.GetLine(LineNumber,Angle);

double[] result = CumulativeVariationForOneLine(line);

return result;

}

public static LinearCoefficient LinearRegression(double[] SourceArray)

{

LinearCoefficient result = new LinearCoefficient() { a = 0, b = 0 };

double FAvg = SourceArray.Average();

int N = SourceArray.Length;

double Sum = 0;

for (int i = 0; i < SourceArray.Length; i++)

Sum += (i - N / 2 + 0.5) * (SourceArray[i] - FAvg);

Sum /= N * (Math.Pow(N, 2) - 1) / 12;

result.a = Sum;

result.b = FAvg - Sum * (N - 1) / 2;

return result;

}

public static double[] NumericalDerivative(double[] SourceArray)

{

double[] result = new double[SourceArray.Length];

result[0] = SourceArray[1] - SourceArray[0];

for (int i = 1; i < SourceArray.Length - 1; i++)

result[i] = (SourceArray[i + 1] - SourceArray[i - 1]) / 2;

result[SourceArray.Length - 1] = SourceArray[SourceArray.Length - 1] - SourceArray[SourceArray.Length - 2];

return result;

}

public static double? AngleSearchUsinngHistogramm(int Distance, LineList FirstLine, LineList SecondLine, params LineList[] NextLines)

{

//потом переделать, сделать рассчет для одной строки!!!!!!!

if (Math.Min(FirstLine.Count, SecondLine.Count) < 5)

return null;

LineList BeginEndLength = new LineList();

double Epsilon = 0.3;//надо будет отрегулировать

//удаляем первые и последние строчки, потому что они могут входить не полностью и портят всю статистику

FirstLine.RemoveAt(FirstLine.Count-1); SecondLine.RemoveAt(SecondLine.Count-1);

FirstLine.RemoveAt(0); SecondLine.RemoveAt(0);

//проверка нынешней первой строчки (Довольно корявое, может исключение вылезти)

//здесь надо сделать проверку, что если строки кончились то больше ничего не объединяем

//сделаем систему с флагами, надо ли еще объединять первую строку, и надо ли еще объединять вторую

//надо теперь сделать что если мы зашли

// bool isFirstLineSolid = false;

// bool isSecondLineSolid = false;

//по идее если вышли по брейкам значит все равно нормальные линии не нашли...

while ((double)Math.Abs((FirstLine[0].Distance()) - (SecondLine[0].Distance())) / Math.Max(FirstLine[0].Distance(), SecondLine[0].Distance()) > Epsilon)

if (FirstLine[0].Distance() > SecondLine[0].Distance())

{

if (SecondLine.Count > 1)

SecondLine.JoinWithNext(0);

else

break;

}

else

{

if (FirstLine.Count > 1)

FirstLine.JoinWithNext(0);

else

break;

}

BeginEndLength.Add(new Point(SecondLine[0].X - FirstLine[0].X, SecondLine[0].Y - FirstLine[0].Y));

//проверка остальных строчек

for (int i = 1; i < Math.Min(FirstLine.Count, SecondLine.Count) - 1; i++)

{

Point CurrentPoint = new Point(SecondLine[i].X - FirstLine[i].X, SecondLine[i].Y - FirstLine[i].Y);

//если на первом элементе среднее совсем маленькое, то потом мы всегда сравниваем со слишком маленьким числом и получаем косяки из-за этого

System.Drawing.PointF Av=BeginEndLength.AbsAvarage;

//Х тоже надо сравнивать, иначе косяки могут быть если слепили не те строчки...

bool ForYCondition = Math.Abs(CurrentPoint.Y) > Math.Abs(Av.Y * 3);

bool ForXCondition = Math.Abs(CurrentPoint.X) > Math.Abs(Av.X * 3);

if (ForYCondition)

{

if (CurrentPoint.Y > 0)

FirstLine.JoinWithNext(i);

else

SecondLine.JoinWithNext(i);

i--;

}

else if ((ForXCondition)&&(i!=1))

{

//если на первой строчке - то лажа вылазит

if (CurrentPoint.X > 0)

{

SecondLine.JoinWithNext(i-1); //тут по идее когда то может исключение вылезти

BeginEndLength.RemoveAt(BeginEndLength.Count - 1);

}

else

{

FirstLine.JoinWithNext(i-1); //тут по идее когда то может исключение вылезти

BeginEndLength.RemoveAt(BeginEndLength.Count - 1);

}

i = i - 2;

}

else

BeginEndLength.Add(CurrentPoint);

}

System.Drawing.PointF MyAv;

if (BeginEndLength.Count > 6)

MyAv = BeginEndLength.GetMyAvarage(2);

else

MyAv = BeginEndLength.Avarage;

double beginTangens = (double)Distance / MyAv.X;

double endTangens = (double)Distance / MyAv.Y;

double Tangens = (beginTangens + endTangens) / 2;

double angle = Math.Atan(Tangens) * 180 / Math.PI;

return angle;

}

}

class LineDetector

{

public BitmapSource Picture;

int lineCount;

public double[] histogramInfo;

float[,] document;

BorderResult PageBorder;

public int LineCount

{

get

{

return lineCount;

}

}

public LineDetector(BitmapSource picture)

{

Picture = picture;

document = picture.ToArray();

}

/// <summary>

/// на данный момент функция не используется

/// </summary>

/// <param name="picture"></param>

/// <returns></returns>

public BitmapSource DetectWithoutRotation(BitmapSource picture)

{

float[,] Lines = picture.ToArray();

double[] sum = TextLineDetector.CountHistogram(Lines);

histogramInfo = sum;

LineList SimpleLines = TextLineDetector.GetSimplePairs(Lines);

if (SimpleLines.Count > 0)

{

LineList WidePairs = TextLineDetector.GetWidePairs(SimpleLines, (uint)Lines.GetLength(0), 2.1, 3.3);

LineList ResultPairs = TextLineDetector.GetPairs(sum, WidePairs);//later we will return this collection

lineCount = ResultPairs.Count;

BitmapSource Result = TextLineDetector.GetLinesDraft(ResultPairs, picture, Direction.Horizontal);

return Result;

}

else

return Picture;

}

/// <summary>

/// функция по заданому углу находит строки, рисует их

/// </summary>

/// <param name="angle"></param>

/// <returns></returns>

public BitmapSource DetectWithSkewLines(double Angle)

{

throw new NotImplementedException("Не доделана функция, надо будет подправить");

}

/// <summary>

/// находит строки по первому приближению

/// </summary>

/// <param name="Angle"></param>

/// <returns></returns>

public LineList DetectAproximateLines(double Angle, bool IsDraw, BorderResult Bord=null)

{

Bord=Bord ?? this.DetectBorders(Angle);

this.PageBorder = Bord;

LineList ResultPairs = new LineList();

//надо задать только начальную точку отсечения и передавать ее в функцию CountSkewHistogram

double[] sum = TextLineDetector.CountSkewHistogram(document, Angle, Bord);

LineList SkewSimpleLines = TextLineDetector.GetSkewSimplePairs(document, Angle, Bord);

if (SkewSimpleLines.Count > 0)

{

LineList WidePairs = TextLineDetector.GetWidePairs(SkewSimpleLines, (uint)sum.Length, 2.1, 3.3);

ResultPairs = TextLineDetector.GetPairs(sum, WidePairs);//later we will return this collection

}

else

{

ResultPairs=SkewSimpleLines;

}

if (IsDraw)

Picture=this.GetPictureWithBorderAndLines(Bord, Angle, ResultPairs);

return ResultPairs;

}

public BorderResult DetectBorders(double Angle)

{

Point Borders = BinaryExtractBorders(Angle);

BorderResult Bord = HorizontalBorderSearch(Borders, Angle);

return Bord;

}

/// <summary>

/// новый вариант функции, функционал вынесен в другую функцию, тут только ее вызов

/// сейчас замутим эвристический поиск (если угол не найден, будем расширять поиски до +-10)

/// </summary>

/// <param name="InitialAngle">приблизительный улог</param>

/// <param name="Lines">набор найденых линий, для которых ищем угол</param>

/// <returns>точный угол</returns>

public double SearchAcсurateAngle(double InitialAngle, LineList Lines)

{

BorderResult CurrentBorder = this.PageBorder;

double deltaAngle;//диапазон, в пределах которого ищем верный угол

double AngleStep;

int Count;

deltaAngle = 6;

AngleStep = 0.2;

Count = (int)(deltaAngle/AngleStep);

//ищем угол больше исходного

AngleResult res = SearchDetailAngle(InitialAngle, Lines, Count, AngleStep, true);

if (res.Direction==AngleDirection.None)//если не нашли подходящий угол больше исходного, то ищем меньше

res = SearchDetailAngle(InitialAngle, Lines, Count, AngleStep, false);

//если не нашли меньше исходного, то пока ниче не делаем

if (res.Direction == AngleDirection.None)//если угол так и не найден, переходим к перебору

{

deltaAngle = 10;

AngleStep = 0.2;

Count = (int)(deltaAngle / AngleStep);

//тут можно вызывать ту же функцию, только с другими параметрами

res = SearchDetailAngle(InitialAngle+5, Lines, Count, AngleStep, true);

if (res.Direction == AngleDirection.None)//если не нашли подходящий угол больше исходного, то ищем меньше

res = SearchDetailAngle(InitialAngle-5, Lines, Count, AngleStep, false);

}

return res.Angle;

}

public AngleResult SearchDetailAngle(double InitialAngle, LineList Lines, int Count, double AngleStep, bool isMoreAngle)

{

bool isAlreadyUncrossed = false;//показывает нашли ли мы уже угол при котором не происходит пересечения со строками

AngleResult result = new AngleResult();

double CurrentAngle = InitialAngle;

LineList CurrentLines = Lines;

BorderResult CurrentBorder = this.PageBorder;

if (!isMoreAngle)

{

result.Direction = AngleDirection.Less;

CurrentAngle -= AngleStep;

CurrentBorder = this.DetectBorders(CurrentAngle);

}

double[] testEnd3 = new double[] { };//копируем в эту переменную итоговый массив чтобы его можно было нарисовать

Point point = new Point();

List<DistancePoint> UnIntersections = new List<DistancePoint>();//здесь будут хранится все области "непересечения"

DistancePoint CurrentUnIntersection = new DistancePoint();

//потом перепрогать что смотрим все по второй строке!!!

for (int i = 0; i < Count; i++)

{

//надо потом учесть что мы пропускаем одно значение угла!!!

CurrentAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

CurrentLines = this.DetectAproximateLines(CurrentAngle, false);

CurrentBorder = this.PageBorder;

int ind;

//финт ушами

if (CurrentLines.Count < 2)

continue;

if (CurrentLines.Count > 3)

ind = 3;

else

ind = CurrentLines.Count-1;

int BeginIndex = (int)(CurrentLines[ind].X - (CurrentLines[ind].Y - CurrentLines[ind].X) * 0.1);//индексы относительно выделенной страницы!!!

int EndIndex = (int)(CurrentLines[ind].X + (CurrentLines[ind].Y - CurrentLines[ind].X) * 0.01);

double[] BeginLine = document.GetLine(BeginIndex, CurrentAngle, CurrentBorder);

double[] EndLine = document.GetLine(EndIndex, CurrentAngle, CurrentBorder);

double[] testBegin = TextLineDetector.CumulativeVariationForOneLine(BeginLine);

double[] testBegin2 = TextLineDetector.NumericalDerivative(testBegin);

double[] testEnd = TextLineDetector.CumulativeVariationForOneLine(EndLine);

double[] testEnd2 = TextLineDetector.NumericalDerivative(testEnd);

Intersection CurrentIntersection = IsCrossed(testEnd2, CurrentAngle, CurrentBorder);

//вот здесь гонево пока в условии,надо будет проверить будет ли так все работать

//здесь сейчас надо будет сделать проверку, вместо break запомнить этот угол и искать дальше, пока не найдем где условия начинают не выполняться

//потом этот полный перебор можно заменить бинарным поиском

//если нет пересечения

if (CurrentIntersection.type == IntersectionType.None || CurrentIntersection.type == IntersectionType.Input || CurrentIntersection.type == IntersectionType.Output)

{

if (!isAlreadyUncrossed)

{

testEnd3 = testEnd2;

point.X = BeginIndex; point.Y = EndIndex;

result.Direction = AngleDirection.More;

result.Angle = CurrentAngle;

isAlreadyUncrossed = true;

//зафиксировали начало "области непересечения"

CurrentUnIntersection = new DistancePoint();

CurrentUnIntersection.X = (float)CurrentAngle;

//break;

}

// CurrentAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

// CurrentLines = this.DetectAproximateLines(CurrentAngle, false);

// CurrentBorder = this.PageBorder;

EndIndex = (int)(CurrentLines[1].X + (CurrentLines[1].Y - CurrentLines[1].X) * 0.1);

EndLine = document.GetLine(EndIndex, CurrentAngle, CurrentBorder);

testEnd = TextLineDetector.CumulativeVariationForOneLine(EndLine);

testEnd2 = TextLineDetector.NumericalDerivative(testEnd);

}

if (CurrentIntersection.type == IntersectionType.Both)

{

if (isAlreadyUncrossed)

{

double PreviosAngle = isMoreAngle ? (CurrentAngle - AngleStep) : (CurrentAngle + AngleStep);

//зафиксировали конец "области непересечения" и добавили его в массив

CurrentUnIntersection.Y = (float)PreviosAngle;

UnIntersections.Add(CurrentUnIntersection);

isAlreadyUncrossed = false;

}

//CurrentAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

// CurrentLines = this.DetectAproximateLines(CurrentAngle, false);

// CurrentBorder = this.PageBorder;

}

testEnd3 = testEnd2;

point.X = BeginIndex; point.Y = EndIndex;

}

//вот здесь надо сделать рассчет самой длинной области непересечения (если не вышли за пределы последней - крайнее значение присвоть концу)

if (isAlreadyUncrossed)

{

CurrentUnIntersection.Y = (float)CurrentAngle;

UnIntersections.Add(CurrentUnIntersection);

}

//если нет ни одной области непересечения - выходим

if (UnIntersections.Count == 0)

{

result.Direction = AngleDirection.None;

return result;

}

//ищем область непересечения максимальной длинны

int maxInd = 0;

for (int i = 0; i < UnIntersections.Count; i++)

if (isMoreAngle)

{

if (UnIntersections[i].Distance > UnIntersections[maxInd].Distance)

maxInd = i;

}

else

{

if (UnIntersections[i].ReversDistance > UnIntersections[maxInd].ReversDistance)

maxInd = i;

}

result.Angle = UnIntersections[maxInd].Middle;

//рисуем гистограмму итоговой линии пересечения

return result;

}

/// <summary>

/// переделка SearchDetailAngle без пересчета линий на каждой итерации

/// </summary>

/// <param name="InitialAngle"></param>

/// <param name="Lines"></param>

/// <param name="Count"></param>

/// <param name="AngleStep"></param>

/// <param name="isMoreAngle"></param>

/// <returns></returns>

public AngleResult SearchDetailAngle2(double InitialAngle, LineList Lines, int Count, double AngleStep, bool isMoreAngle)

{

bool isAlreadyUncrossed = false;//показывает нашли ли мы уже угол при котором не происходит пересечения со строками

AngleResult result = new AngleResult();

double CurrentAngle = InitialAngle;

LineList CurrentLines = Lines;

BorderResult CurrentBorder = this.PageBorder;

double[] testEnd3 = new double[] { };//копируем в эту переменную итоговый массив чтобы его можно было написовать

Point point = new Point();

int BeginIndex = (int)(CurrentLines[1].X - (CurrentLines[1].Y - CurrentLines[1].X) * 0.1);//индексы относительно выделенной страницы!!!

int EndIndex = (int)(CurrentLines[1].X + (CurrentLines[1].Y - CurrentLines[1].X) * 0.1);

double[] s = TextLineDetector.CountSkewHistogram(document, InitialAngle, this.PageBorder);

//потом перепрогать что смотрим все по второй строке!!!

for (int i = 0; i < Count; i++)

{

double[] BeginLine = document.GetLine(BeginIndex, CurrentAngle, CurrentBorder);

double[] EndLine = document.GetLine(EndIndex, CurrentAngle, CurrentBorder);

double[] testBegin = TextLineDetector.CumulativeVariationForOneLine(BeginLine);

double[] testBegin2 = TextLineDetector.NumericalDerivative(testBegin);

double[] testEnd = TextLineDetector.CumulativeVariationForOneLine(EndLine);

double[] testEnd2 = TextLineDetector.NumericalDerivative(testEnd);

Intersection CurrentIntersection = IsCrossed(testEnd2, CurrentAngle, CurrentBorder,s);

//вот здесь гонево пока в условии,надо будет проверить будет ли так все работать

//здесь сейчас надо будет сделать проверку, вместо break запомнить этот угол и искать дальше, пока не найдем где условия начинают не выполняться

//потом этот полный перебор можно заменить бинарным поиском

if (CurrentIntersection.type == IntersectionType.None || CurrentIntersection.type == IntersectionType.Input)

{

if (!isAlreadyUncrossed)

{

testEnd3 = testEnd2;

point.X = BeginIndex; point.Y = EndIndex;

result.Direction = AngleDirection.More;

result.Angle = CurrentAngle;

isAlreadyUncrossed = true;

HistogramWindow histogramWindow = new HistogramWindow();

histogramWindow.Histogramm.CreateGraphic(testEnd2);

histogramWindow.Histogramm.Draw();

histogramWindow.Show();

//рисуем сами линии пересечения итоговые

ShowTestLineWindow showTestLineWindow = new ShowTestLineWindow();

showTestLineWindow.TestLinesImage.Source = this.GetPictureWithBorderAndLines(CurrentBorder, CurrentAngle, new LineList() { point });

showTestLineWindow.Show();

}

CurrentAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

EndIndex = (int)(CurrentLines[1].X + (CurrentLines[1].Y - CurrentLines[1].X) * 0.1);

EndLine = document.GetLine(EndIndex, CurrentAngle, CurrentBorder);

testEnd = TextLineDetector.CumulativeVariationForOneLine(EndLine);

testEnd2 = TextLineDetector.NumericalDerivative(testEnd);

HistogramWindow histogramWindow2 = new HistogramWindow();

histogramWindow2.Histogramm.CreateGraphic(testEnd2);

histogramWindow2.Histogramm.Draw();

histogramWindow2.Show();

//рисуем сами линии пересечения итоговые

ShowTestLineWindow showTestLineWindow2 = new ShowTestLineWindow();

showTestLineWindow2.TestLinesImage.Source = this.GetPictureWithBorderAndLines(CurrentBorder, CurrentAngle, new LineList() { point });

showTestLineWindow2.Show();

}

if (CurrentIntersection.type == IntersectionType.Output || CurrentIntersection.type == IntersectionType.Both)

{

if (isAlreadyUncrossed)

{

double PreviosAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

result.Angle = (result.Angle + PreviosAngle) / 2; //итоговый угол берем как среднее арифметическое крайних значений

break;

}

else

{

CurrentAngle = isMoreAngle ? (CurrentAngle + AngleStep) : (CurrentAngle - AngleStep);

}

}

testEnd3 = testEnd2;

point.X = BeginIndex; point.Y = EndIndex;

if ((CurrentAngle>18.2)&&(CurrentAngle<19))

{

CurrentBorder = this.DetectBorders(CurrentAngle);

HistogramWindow histogramWindow3 = new HistogramWindow();

histogramWindow3.Histogramm.CreateGraphic(testEnd2);

histogramWindow3.Histogramm.Draw();

histogramWindow3.Show();

//рисуем сами линии пересечения итоговые

ShowTestLineWindow showTestLineWindow3 = new ShowTestLineWindow();

showTestLineWindow3.TestLinesImage.Source = this.GetPictureWithBorderAndLines(CurrentBorder, CurrentAngle, new LineList() { point });

showTestLineWindow3.Show();

}

}

return result;

}

/// <summary>

/// Должна определять какое было пересечение, возвращает тип пересечения (используется для определения точного угла)

/// передаем сюда уже массив производных

/// </summary>

/// <param name="arr"></param>

public Intersection IsCrossed(double[] sum, double angle, BorderResult border, double[] s=null)

{

bool InputFlag = false;

bool OutputFlag = false;

int ScanSize = 3;

int leftThreeshold = 7;//довольно левая величина для отсечения серых краев с левого края

int iInit = 0;

s = s ?? TextLineDetector.CountSkewHistogram(document, angle, border);

Intersection result = new Intersection();

s = TextLineDetector.ClearHistogramFromZero(s);

double average = s.Average();

for (int i = iInit; i < sum.Length - ScanSize + 1; i++)

{

if (sum.PartialSum(i, i + ScanSize) / ScanSize > average)

{

InputFlag = true;

for (int j = i; j < sum.Length - ScanSize + 1; j++)

if (sum.PartialSum(j, j + ScanSize) / ScanSize < average)

{

if (j - i > 7)

{

if (i < iInit + leftThreeshold)

{

result.type = IntersectionType.Output;

result.Border = new Point(-1, j);

OutputFlag = true;

InputFlag = false;

i = j;

break;

}

else

{

result.type = IntersectionType.Both;

result.Border = new Point(i, j);

return result;

}

}

else

{

InputFlag = false;

break;

}

}

if (InputFlag)

{

result.type = IntersectionType.Input;

result.Border = new Point(i, -1);

return result;

}

}

}

if (OutputFlag)

return result;

else

{

result.type = IntersectionType.None;

result.Border = new Point(-1, -1);

return result;

}

}

/// <summary>

/// бинарным поиском ищем линию, которая отделяет начало строк от полей

/// </summary>

/// <param name="Angle">угол наклона строк</param>

/// <returns>начальная и конечная границы страницы по верхнему краю</returns>

public Point BinaryExtractBorders(double Angle, int Count=10)

{

double HorizontalAngle = Math.Sign(Angle) * (90 - Math.Abs(Angle));

double tg = Math.Tan(Angle * Math.PI / 180);

double htg = Math.Tan(HorizontalAngle * Math.PI / 180);

int firstVertical=0;

Point vertical = new Point();

int lastVertical = (int)(document.GetLength(1) + document.GetLength(0) * Math.Abs(tg));

int lastHorizontal = (int)(document.GetLength(0) + document.GetLength(1) * Math.Abs(tg));

//ищем вертикальные границы

vertical.X = BinarySearch(firstVertical, lastVertical, Count, Angle, true, Direction.Vertical);//левая вертикальная граница

vertical.Y = BinarySearch(vertical.X, lastVertical, Count, Angle, false, Direction.Vertical);//правая вертикальная граница

return vertical;

}

/// <summary>

/// находит горизонтальные границы, зная вертикальные (совершая кучу геометирческих преобразований)

/// </summary>

protected BorderResult HorizontalBorderSearch(Point VerticalBorder, double Angle)

{

double tg = Math.Tan(Angle * Math.PI / 180);

double cos= Math.Cos(Angle * Math.PI / 180);

double sin = Math.Sin(Angle * Math.PI / 180);

int a = document.GetLength(1);

int b = document.GetLength(0);

int X=VerticalBorder.X;

int Y=VerticalBorder.Y;

BorderResult result = new BorderResult() { Borders = new Point[4] };

if (tg < 0)

{

double tgBetta = -tg;

int Noll=(int)(b*tgBetta);

int Xsh = Noll-X;

int Ysh = Noll -Y;

int Xsh2 = X - Noll;

int Ysh2 = Y - Noll;

double h = Math.Abs(Xsh - Ysh) * cos * Math.Abs(sin);

double l = Math.Abs(Xsh - Ysh) * cos * cos;

double d = (a + Ysh) / tgBetta;//по моему d определяется всегда одинаково

double csh = b * tgBetta - Xsh;

//если обе линии слева

if (Ysh > 0)

{

double g = Xsh / tgBetta;

result.Borders[0].X = (int)g; result.Borders[0].Y = 0;

result.Borders[2].X = (int)(g - h); result.Borders[2].Y = (int)l;

if (d + h > b)

{

result.Borders[1].X = (int)b; result.Borders[1].Y = (int)csh;

result.Borders[3].X = (int)(b - h); result.Borders[3].Y = (int)(csh + l);

}

else

{

result.Borders[1].X = (int)(d + h); result.Borders[1].Y = (int)(a - l);

result.Borders[3].X = (int)d; result.Borders[3].Y = (int)a;

}

}

//если обе линии справа

else if (Xsh < 0)

{

result.Borders[0].X = (int)h; result.Borders[0].Y = (int)(Ysh2 - l);

result.Borders[2].X = 0; result.Borders[2].Y = Ysh2;

if (d + h > b)

{

result.Borders[1].X = (int)b; result.Borders[1].Y = (int)csh;

result.Borders[3].X = (int)(b - h); result.Borders[3].Y = (int)(csh + l);

}

else

{

result.Borders[1].X = (int)(d + h); result.Borders[1].Y = (int)(a - l);

result.Borders[3].X = (int)d; result.Borders[3].Y = (int)a;

}

}

else //если линии находятся с разных сторон от угла

{

if (Ysh2 - l < 0)

{

double g = Xsh / tgBetta;

result.Borders[0].X = (int)g; result.Borders[0].Y = 0;

result.Borders[2].X = (int)(g - h); result.Borders[2].Y = (int)l;

}

else

{

result.Borders[0].X = (int)h; result.Borders[0].Y = (int)(Ysh2 - l);

result.Borders[2].X = 0; result.Borders[2].Y = Ysh2;

}

if (d + h > b)

{

result.Borders[1].X = (int)b; result.Borders[1].Y = (int)csh;

result.Borders[3].X = (int)(b - h); result.Borders[3].Y = (int)(csh + l);

}

else

{

result.Borders[1].X = (int)(d + h); result.Borders[1].Y = (int)(a - l);

result.Borders[3].X = (int)d; result.Borders[3].Y = (int)a;

}

}

// throw new NotImplementedException("Не реализован поиск границ для угла < 0");

}

else

{

double d = (Y - a) / tg;

double l = (Y - X) * cos * cos;

double h = (Y - X) * cos * sin;

double g = X / tg;

double csh = Y - b * tg;

//double csh = (b - g) / tg;

double m = b * tg;

if (Y < a)//если обе линии находятся слева от угла

{

result.Borders[0].X = 0; result.Borders[0].Y = X;

result.Borders[2].X = (int)h; result.Borders[2].Y = (int)(X + l);

if (g + h < b)

{

result.Borders[1].X = (int)g; result.Borders[1].Y = 0;

result.Borders[3].X = (int)(g + h); result.Borders[3].Y = (int)l;

}

else

{

csh = Y - m;

result.Borders[1].X = (int)(b - h); result.Borders[1].Y = (int)(csh - l);

result.Borders[3].X = (int)b; result.Borders[3].Y = (int)csh;

}

}

else if (X > a)//если обе линии находятся справа от угла

{

result.Borders[0].X = (int)(d - h); result.Borders[0].Y = (int)(a - l);

result.Borders[2].X = (int)d; result.Borders[2].Y = a;

if (g + h < b)

{

result.Borders[1].X = (int)(b - h); result.Borders[1].Y = (int)(csh - l);

result.Borders[3].X = b; result.Borders[3].Y = (int)csh;

}

else

{

result.Borders[1].X = (int)g; result.Borders[1].Y = 0;

result.Borders[3].X = (int)(g + h); result.Borders[3].Y = (int)l;

}

}

else//если линии находятся с разных сторон от угла

{

if (X + l < a)

{

result.Borders[0].X = 0; result.Borders[0].Y = X;

result.Borders[2].X = (int)h; result.Borders[2].Y = (int)(X + l);

}

else

{

result.Borders[0].X = (int)(d - h); result.Borders[0].Y = (int)(a - l);

result.Borders[2].X = (int)d; result.Borders[2].Y = a;

}

if (g + h < b)

{

result.Borders[1].X = (int)g; result.Borders[1].Y = 0;

result.Borders[3].X = (int)(g + h); result.Borders[3].Y = (int)l;

}

else

{

result.Borders[1].X = (int)(b - h); result.Borders[1].Y = (int)(csh - l);

result.Borders[3].X = b; result.Borders[3].Y = (int)csh;

}

}

}

result.Width = result.Borders[2].Y - result.Borders[0].Y;

result.Height = result.Borders[1].X - result.Borders[0].X;

return result;

}

/// <summary>

/// находит бинарным поиском значение для одной границы

/// </summary>

/// <param name="first"></param>

/// <param name="last"></param>

/// <param name="Count"></param>

/// <param name="IsForward">задает в какую сторону движемся для поиска, если значение true то влево (для левой границы)</param>

/// <returns></returns>

public int BinarySearch(int first, int last, int Count, double Angle, bool IsForward, Direction direction)

{

int middle;

for (int i = 0; (i < Count)&&(first<last); i++)

{

middle = first + (last - first) / 2;

double[] currentElement = (direction == Direction.Vertical) ? document.GetDinamicColumn(middle, Angle) : document.GetDinamicLine(middle, Angle);

//вот здесь надо определить есть ли в столбце строки

if (TextLineDetector.IsLineCrossed(currentElement))

if (IsForward)

last = middle;

else

first = middle + 1;

else

if (IsForward)

first = middle + 1;

else

last = middle;

}

return first;

}

/// <summary>

/// возвращает картинку с нарисованными границами страницы и линиями

/// </summary>

/// <param name="boreder">границы страницы</param>

/// <param name="Angle">угол наклона страницы</param>

/// <param name="Lines">набор текстовых линий</param>

/// <returns></returns>

public BitmapSource GetPictureWithBorderAndLines(BorderResult border, double Angle, LineList Lines)

{

BitmapSource result = Picture.Clone();

result = TextLineDetector.GetSkewImageBorder(border, result, Angle);//рисуем границы

result = TextLineDetector.GetSkewLinesDraft(Lines, result, Angle, border);//рисуем текстовые линии

return result;

}

}

class LineList : List<Point>

{

protected uint? verticalSize;

public int MinStringWidth

{

get

{

return this.Min<Point, int>(P => P.Y - P.X);

}

}

public int AvStringWidth

{

get

{

return (int)this.Average<Point>(P => P.Y - P.X);

}

}

public int AvStringInterval

{

get

{

int _AvStringInterval = 0;

if (this.Count == 1)

{

_AvStringInterval = this[0].X;

}

else

{

for (int i = 0; i < this.Count - 1; i++)

_AvStringInterval += this[i + 1].X - this[i].Y;

_AvStringInterval /= this.Count - 1;

}

return _AvStringInterval;

}

}

public uint? VerticalSize

{

get

{

return verticalSize;

}

set

{

if (value == null)

throw new ArgumentNullException();

verticalSize = value;

}

}

public Point[] IntervalArray

{

get

{

Point[] result = new Point[this.Count + 1];

Point CurrentInterval = new Point();

CurrentInterval.X = 0;

CurrentInterval.Y = this[0].X;

result[0] = CurrentInterval;

for (int i = 0; i < this.Count - 1; i++)

{

CurrentInterval.X = this[i].Y;

CurrentInterval.Y = this[i + 1].X;

result[i + 1] = CurrentInterval;

}

CurrentInterval.X = this[this.Count - 1].Y;

CurrentInterval.Y = (int)VerticalSize;

result[this.Count] = CurrentInterval;

return result;

}

}

public Point[] CutIntervalArray

{

get

{

Point[] result = new Point[this.Count - 1];

Point CurrentInterval = new Point();

for (int i = 0; i < this.Count - 1; i++)

{

CurrentInterval.X = this[i].Y;

CurrentInterval.Y = this[i + 1].X;

result[i] = CurrentInterval;

}

return result;

}

}

public System.Drawing.PointF Avarage

{

get

{

System.Drawing.PointF result=new System.Drawing.PointF(0,0);

foreach (Point line in this)

{

result.X += line.X; result.Y += line.Y;

}

result.X /= this.Count; result.Y /= this.Count;

return result;

}

}

public System.Drawing.PointF AbsAvarage

{

get

{

System.Drawing.PointF result = new System.Drawing.PointF(0, 0);

foreach (System.Drawing.Point line in this)

{

result.X += Math.Abs(line.X); result.Y += Math.Abs(line.Y);

}

result.X /= this.Count; result.Y /= this.Count;

return result;

}

}

public System.Drawing.PointF GetMyAvarage(int edge)

{

List<Point> ListForSorting=new List<Point>(this);

ListForSorting.Sort((First, Second) => (First.X.CompareTo(Second.X)));

//удаляем элементы с конца

ListForSorting.RemoveRange(ListForSorting.Count - edge, edge/2);

//удаляем элементы с начала

ListForSorting.RemoveRange(0, edge/2);

ListForSorting.Sort((First, Second) => (First.Y.CompareTo(Second.Y)));

ListForSorting.RemoveRange(ListForSorting.Count - edge, edge - edge / 2);

ListForSorting.RemoveRange(0, edge - edge / 2);

System.Drawing.PointF result = new System.Drawing.PointF(0,0);

foreach (Point CurrentPoint in ListForSorting)

{

result.X += CurrentPoint.X; result.Y += CurrentPoint.Y;

}

result.X /= ListForSorting.Count; result.Y /= ListForSorting.Count;

return result;

}

public int MyAvStringIntervel(int edges)

{

int[] Intervals = this.CutIntervalArray.GetDistances();

Array.Sort(Intervals);

double Cut = (double)Intervals.PartialSum(edges, Intervals.Length - edges) / (Intervals.Length - edges * 2);

return (int)Cut;

}

public void JoinWithNext(int index)

{

Point JointLine = new Point(this[index].X, this[index + 1].Y);

this.RemoveAt(index + 1);

this.RemoveAt(index);

this.Insert(index, JointLine);

}

}