Приложение
Тексты классов 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);
}
}