© Vladimir Kovalevsky 2019
Vladimir KovalevskyModern Algorithms for Image Processinghttps://doi.org/10.1007/978-1-4842-4237-7_13

13. Recognition of Bicycles in Traffic

Vladimir Kovalevsky1 
(1)
Berlin, Germany
 

Due to the good properties of the presented method for circle recognition, I had the idea to use this method to recognize bicycle wheels, which are ideal circles. However, if the bike is positioned so that the plane of its frame makes an acute angle with the viewing direction, then the wheels look like ellipses rather than circles. We thus also need a method of recognizing ellipses. Unfortunatelly we have not succeded with generalizing our method of circle recognition (see Chapter 12) for ellipses. We have tried to use the well-known method of conjugate gradients, but our experiments have shown that this method is not robust: Sometimes it fails when the points to which the ellipse is to be fitted do not lie near an ellipse.

Because an ellipse is defined by only a small number of parameters, namely five, it is possible to use the classical procedure of least squares as described in the next section.

Mathematical Foundation of Ellipse Recognition

An ellipse with axes parallel to the coordinate axes of a Cartesian coordinate system and with the center lying in the origin has the well-known equation

x2 / a2 + y2 / b2 = 1.

However, we need to consider the general case of a shifted and inclined ellipse. We use the general equation of a conic section:

Ax2 + Bxy + Cy2 + Dx + Ey + F = 0.

Our aim is to find parameters of an ellipse for which the sum of the squared distances of a set of given points from the ellipse is minimal. Thus our objective function is
$$ f=sum limits_i{left(A{x}_i^2+B{x}_i{y}_i+C{y}_i^2+D{x}_i+E{y}_i+F
ight)}^2. $$
(13.1)

The expression in the parentheses is approximately proportional to the distance of the point (xi, yi) from the ellipse. It contains six unknown coefficients A, B, C, D, E, and F. However, it is well known that an ellipse is uniquely defined by five parameters. Therefore we divide all terms of Equation 13.1 by A and denote the new coefficients as follows:

B / A = 2k1

C / A = k 2

D / A = 2k3

E / A = 2k4

F / A = k 5

The transformed objective function is
$$ f=sum limits_i{left({x}_i^2+2{k}_1{x}_i{y}_i+{k}_2{y}_i^2+2{k}_3{x}_i+2{k}_4{y}_i+{k}_5
ight)}^2. $$
(13.1a)
The partial derivative of f to k1 is
$$ frac{partial f}{partial {k}_1}=4sum limits_ileft({x}_i^2+2{k}_1{x}_i{y}_i+{k}_2{y}_i^2+2{k}_3{x}_i+2{k}_4{y}_i+{k}_5
ight)ast {x}_i{y}_i. $$
After multiplying all terms in the parentheses by xi*yi we obtain
$$ frac{partial f}{partial {k}_1}=4sum limits_ileft({x}_i^3{y}_i+2{k}_1{x}_i^2{y}_i^2+{k}_2{x}_i{y}_i^3+2{k}_3{x}_i^2{y}_i+2{k}_4{x}_i{y}_i^2+{k}_5{x}_i{y}_i
ight). $$
We divide it by four and denote each $$ sum limits_i{x}_i^m{y}_i^n $$ by S(m, n) and obtain
$$ frac{partial f}{partial {k}_1}=Sleft(3,kern0.5em 1
ight)+2{k}_1Sleft(2,kern0.5em 2
ight)+{k}_2Sleft(1,kern0.5em 3
ight)+2{k}_3Sleft(2,kern0.5em 1
ight)+2{k}_4Sleft(1,kern0.5em 2
ight)+{k}_5Sleft(1,kern0.5em 1
ight). $$
By setting it equal to zero we obtain the first of the five equations for the unknowns k1, k2, k3, k4, and k5.
$$ 2{k}_1Sleft(2,kern0.5em 2
ight)+{k}_2Sleft(1,kern0.5em 3
ight)+2{k}_3Sleft(2,kern0.5em 1
ight)+2{k}_4Sleft(1,kern0.5em 2
ight)+{k}_5Sleft(1,kern0.5em 1
ight)=-Sleft(3,kern0.5em 1
ight) $$
In a similar way we obtain the other four equations:
$$ 2{k}_1Sleft(1,kern0.5em 3
ight)+{k}_2Sleft(0,kern0.5em 4
ight)+2{k}_3Sleft(1,kern0.5em 2
ight)+2{k}_4Sleft(0,kern0.5em 3
ight)+{k}_5Sleft(0,kern0.5em 2
ight)=-Sleft(2,kern0.5em 2
ight) $$
$$ 2{k}_1Sleft(2,kern0.5em 1
ight)+{k}_2Sleft(1,kern0.5em 2
ight)+2{k}_3Sleft(2,kern0.5em 0
ight)+2{k}_4Sleft(1,kern0.5em 1
ight)+{k}_5Sleft(1,kern0.5em 0
ight)=-Sleft(3,kern0.5em 0
ight) $$
$$ 2{k}_1Sleft(1,kern0.5em 2
ight)+{k}_2Sleft(0,kern0.5em 3
ight)+2{k}_3Sleft(1,kern0.5em 1
ight)+2{k}_4Sleft(0,kern0.5em 2
ight)+{k}_5Sleft(0,kern0.5em 1
ight)=-Sleft(2,kern0.5em 1
ight) $$
$$ 2{k}_1Sleft(1,kern0.5em 1
ight)+{k}_2Sleft(0,kern0.5em 2
ight)+2{k}_3Sleft(1,kern0.5em 0
ight)+2{k}_4Sleft(0,kern0.5em 1
ight)+{k}_5Sleft(0,kern0.5em 0
ight)=-Sleft(2,kern0.5em 0
ight) $$

This system of equations is solved by the well-known Gauss method implemented in the method GetEllipseNew using the method Gauss_K. The sums S(xm, yn) are calculated by the method MakeSums2 .

The following is the source code of GetEllipseNew .
public int GetEllipseNew(Point[] Vert, int iv1, int nPoints1, int iv2, int nPoints2,
ref double Delta, ref double f, ref double a, ref double b, ref double c, ref double d)
{
  bool deb = false;
  double[,] A = new double[5, 5];
  double[,] B = new double[5, 1];
  int nSum = 15;
  double[] Sum = new double[nSum];
  MakeSums2(Vert, iv1, nPoints1, iv2, nPoints2, Sum);
  A[0, 0] = 2.0 * Sum[12];
  A[0, 1] = Sum[11];
  A[0, 2] = 2.0 * Sum[8];
  A[0, 3] = 2.0 * Sum[7];
  A[0, 4] = Sum[4];
  A[1, 0] = 2.0 * Sum[11];
  A[1, 1] = Sum[10];
  A[1, 2] = 2.0 * Sum[7];
  A[1, 3] = 2.0 * Sum[6];
  A[1, 4] = Sum[3];
  A[2, 0] = 2.0 * Sum[8];
  A[2, 1] = Sum[7];
  A[2, 2] = 2.0 * Sum[5];
  A[2, 3] = 2.0 * Sum[4];
  A[2, 4] = Sum[2];
  A[3, 0] = 2.0 * Sum[7];
  A[3, 1] = Sum[6];
  A[3, 2] = 2.0 * Sum[4];
  A[3, 3] = 2.0 * Sum[3];
  A[3, 4] = Sum[1];
  A[4, 0] = 2.0 * Sum[4];
  A[4, 1] = Sum[3];
  A[4, 2] = 2.0 * Sum[2];
  A[4, 3] = 2.0 * Sum[1];
  A[4, 4] = Sum[0];
  B[0, 0] = -Sum[13];
  B[1, 0] = -Sum[12];
  B[2, 0] = -Sum[9];
  B[3, 0] = -Sum[8];
  B[4, 0] = -Sum[5];
  Gauss_K(A, 5, B, 1);
  f = -0.5 * Math.Atan2(2.0 * B[0, 0], 1.0 - B[1, 0]);
  c = (B[0, 0] * B[3, 0] - B[1, 0] * B[2, 0]) / (B[1, 0] - B[0, 0] * B[0, 0]);
  d = (B[0, 0] * B[2, 0] - B[3, 0]) / (B[1, 0] - B[0, 0] * B[0, 0]);
  Delta = B[1, 0] - B[0, 0] * B[0, 0];
  double BigDelta = B[1, 0] * B[4, 0] + B[0, 0] * B[3, 0] * B[2, 0] +
       B[0, 0] * B[3, 0] * B[2, 0] - B[2, 0] * B[1, 0] * B[2, 0] - B[3, 0] * B[3, 0] - B[4, 0] * B[0, 0] * B[0, 0];
  double S = 1.0 + B[1, 0];
  double a2, b2;
  double aprim = (1.0 + B[1, 0] + Math.Sqrt((1.0 - B[1, 0]) * (1.0 - B[1, 0]) + 4.0 * B[0, 0] * B[0, 0])) * 0.5;
  double cprim = (1.0 + B[1, 0] - Math.Sqrt((1.0 - B[1, 0]) * (1.0 - B[1, 0]) + 4.0 * B[0, 0] * B[0, 0])) * 0.5;
  a2 = -BigDelta / aprim / Delta;
  b2 = -BigDelta / cprim / Delta;
  a = Math.Sqrt(a2);
  b = Math.Sqrt(b2);
  if (Delta > 0.0)  return 1;
  return -1;
} //***************** end GetEllipseNew *********************************

The Project WFellipseBike

The form of this project is shown in Figure 13-1.
../images/474294_1_En_13_Chapter/474294_1_En_13_Fig1_HTML.jpg
Figure 13-1

The form of the project WFellipseBike

The user clicks Open image, then selects the folder and the image. The image appears in the left picture box. Then the user clicks Detect edges. There is a numeric up and down tool for the selection of the threshold for edge detection. However, the preselected value of 20 is good for all images and should not be changed. The program runs automatically. It uses the methods described in Chapter 12 for edge detection and polygonal approximation of the edges. Then it uses the method MakeArcsTwo for subdividing the polygons into arcs. This method is slightly different from the MakeArcs3 method described in Chapter 12.

The method FindEllipsesMode is then called to find the ellipses of the wheels of a bike. The method uses arcs sorted according to the number of points. The sorting is performed by the method SortingArcs writing the indexes of the sorted arcs into the array SortArcs . The arc with the greatest number of points stays in SortArcs[0]. Thus the arcs can be taken in the order of decreasing number of points.

The recognition of ellipses is not as simple as that of circles: If the arc transferred to the method GetEllipseNew to find the ellipse containing the arc contains fewer than ten points, sometimes false parameters of the ellipse can be calculated. Therefore we have developed additional means to fix this problem. The method QualityOfEllipseNew calculates the number of points in arcs lying near the ellipse as displayed in Figure 13-2.
../images/474294_1_En_13_Chapter/474294_1_En_13_Fig2_HTML.jpg
Figure 13-2

Fragment of a bike image with a recognized ellipse

In Figure 13-2, black lines are the arcs, blue points are the polygon vertices contained in the arcs, and the red line is the recognized ellipse. The quality of the ellipse is estimated as the number Sum of blue points in the tube around the ellipse. This number is compared with the value maxPoints, which is the number of points in the arc ia passed as a parameter to the method GetEllipseNew multiplied with 2π and divided by the angle of the arc. Thus maxPoint is the maximum possible number of points in a closed curve. The ellipse is regarded as good if the value Sum is greater than 0.5*maxNumber. Here is the code for QualityOfEllipseNew .
public int QualityOfEllipseNew(int ia, Ellipse Ellipse, int[] SortArcs, Form1 fm1)
// Returns the sum of the numbers of points of arcs near the ellipse.
{
  bool deb = false, Disp = false; //true; //
  int Dif, goodDartIa, locDart, i, iv, ivm, ive, ja, Sum = 0, x, y, xm, ym, xe, ye;
  double angleDart, a = Ellipse.a, b = Ellipse.b, c = Ellipse.c, d = Ellipse.d;
  double maxPoints = elArc[ia].nPoints * 6.28 / elArc[ia].Angle;
  int ivStart, ivMid, ivEnd, xMain, yMain;
  ivStart = elArc[ia].Start;
  ivMid = ivStart + elArc[ia].nPoints / 2;
  ivEnd = ivStart + elArc[ia].nPoints - 1;
  x = Vert[ivStart].X;
  y = Vert[ivStart].Y;
  double AngleStart = Math.Atan2(y - d, x - c);
  xe = Vert[ivEnd].X;
  ye = Vert[ivEnd].Y;
  double AngleEnd = Math.Atan2(ye - d, xe - c);
  xMain = Vert[ivMid].X;
  yMain = Vert[ivMid].Y;
  double AngleMid = Math.Atan2(yMain - d, xMain - c);
  double minAngle = Math.Min(AngleStart, AngleEnd);
  double maxAngle = Math.Max(AngleStart, AngleEnd), help;
  bool Plus2PI = false;
  if (minAngle < 0.0 && maxAngle > 0.0 && !(AngleMid >= minAngle &&
                                                      AngleMid < maxAngle))
  {
    Plus2PI = true;
    help = maxAngle;
    maxAngle = minAngle + 2 * Math.PI;
    minAngle = help;
  }
  angleDart = 57.3 * Math.Atan2(yMain - elArc[ia].My, xMain - elArc[ia].Mx) + 15.0;
  if (angleDart < 0.0) angleDart += 360.0;
  goodDartIa = 6 + (int)angleDart / 30;
  if (goodDartIa > 11) goodDartIa -= 12;
  double AngleJa, Fx, Fxe;
  for (i = 0; i < nArcs; i++) //=============================
  {
    ja = SortArcs[i];
    if (ja == ia || elArc[ja].nPoints < 5) continue;
    iv = elArc[ja].Start;
    ivm = iv + elArc[ja].nPoints / 2;
    ive = iv + elArc[ja].nPoints - 1;
    x = Vert[iv].X;
    y = Vert[iv].Y;
    xm = Vert[ivm].X;
    ym = Vert[ivm].Y;
    xe = Vert[ive].X;
    ye = Vert[ive].Y;
    Fx = (x - c) * (x - c) / a / a + (y - d) * (y - d) / b / b;
    Fxe = (xe - c) * (xe - c) / a / a + (ye - d) * (ye - d) / b / b;
    if (Fx < 0.6 || Fx > 1.67 || Fxe < 0.6 || Fxe > 1.67) continue;
    angleDart = 57.3 * Math.Atan2((ym - d) * a * a, (xm - c) * b * b);
    if (angleDart < 0.0) angleDart += 360.0;
    locDart = (int)angleDart / 30;
    if (locDart > 11) locDart -= 12;
    Dif = Math.Abs(elArc[ja].Dart - locDart);
    if (Dif > 6) Dif = 12 - Dif;
    if (Disp) DrawOneLongArc(ja, fm1);
    if (Dif < 2)
    {
      if (Disp) DrawOneLongArc(ja, fm1);
      for (iv = elArc[ja].Start; iv < elArc[ja].Start + elArc[ja].nPoints; iv++)
      {
        x = Vert[iv].X;
        y = Vert[iv].Y;
        AngleJa = Math.Atan2(y - d, x - c);
        if (AngleJa < 0.0 && Plus2PI) AngleJa += 6.28;
        if (!(AngleJa > minAngle && AngleJa < maxAngle)) Sum += elArc[ja].nPoints;
      }
    }
  } //================== end for (i = 0; ... ===========================
  return Sum;
} //********************* end QualityOfEllipseNew ************************
If the ellipse is not good, the method HelpArcNew is called. This method obtains the arc ia as an argument and finds different arcs ja lying inside the curvature circle of the arc ia. If the arc ja has a proper orientation and is not too close to the arc ia, it forms a pair with the arc ia. For each pair of arcs (ia, ja) an ellipse is calculated and its quality is estimated. The ellipse with the best quality is returned as the result. Here is the code for HelpArcNew.
public int HelpArcNew(int ia, int[] SortArcs, ref Ellipse Ellipse, int SumStart, Form1 fm1)
{
  bool disp = false;
  int Dif, i, ivMid, ivm, ja, xMain, yMain, xm, ym;
  ivMid = elArc[ia].Start + elArc[ia].nPoints / 2;
  xMain = Vert[ivMid].X;
  yMain = Vert[ivMid].Y;
  double angleDart, a = Ellipse.a, b = Ellipse.b, c = Ellipse.c, d = Ellipse.d;
  int goodDartIa;
  angleDart = 57.3 * Math.Atan2(yMain - elArc[ia].My, xMain - elArc[ia].Mx) + 15.0;
  if (angleDart < 0.0) angleDart += 360.0;
  goodDartIa = 6 + (int)angleDart / 30;
  if (goodDartIa > 11) goodDartIa -= 12;
  double R = elArc[ia].R, Mx = elArc[ia].Mx, My = elArc[ia].My;
  CBox Box = new CBox();
  Box.minX = (int)(Mx - R) - 10;
  if (c - a < Box.minX) Box.minX -= 20;
  Box.maxX = (int)(Mx + R) + 10;
  if (c + a > Box.maxX) Box.maxX += 20;
  Box.minY = (int)(My - R) - 10;
  if (d - b < Box.minY) Box.minY -= 20;
  Box.maxY = (int)(My + R) + 10;
  if (d + b > Box.maxY) Box.maxY += 20;
  DrawRectangleSmart(Box, fm1);
  int Dist2 = 0, minDist2 = (int)(1.5 * elArc[ia].R * elArc[ia].R);
  int[] jBest = new int[100];
  int nBest = 0;
  for (i = 0; i < nArcs; i++) //===================================
  {
    ja = SortArcs[i];
    if (!ArcInBox(ja, Box)) continue;
    if (elArc[ja].nPoints < 4) continue;
    if (disp) DrawOneLongArc(ja, fm1);
    Dif = Math.Abs(elArc[ja].Dart - goodDartIa);
    if (Dif > 6) Dif = 12 - Dif;
    if (Dif > 3) continue;
    ivm = elArc[ja].Start + elArc[ja].nPoints / 2;
    xm = Vert[ivm].X;
    ym = Vert[ivm].Y;
    Dist2 = (xm - xMain) * (xm - xMain) + (ym - yMain) * (ym - yMain);
    if (Dist2 > minDist2)
    {
      jBest[nBest] = ja;
      nBest++;
    }
    if (nBest >= 5) break;
  } //================= end for (i = 0; =============================
  double Delta = 0.0, F = 0.0;
  Ellipse Ellipse1 = new Ellipse();
  int jbestOpt = -1, maxSum = SumStart, Sum = 0;
  for (i = 0; i < nBest; i++) //=========================================
  {
    if (disp) DrawRedArc(jBest[i], fm1);
    GetEllipseNew(Vert, elArc[ia].Start, elArc[ia].nPoints, elArc[jBest[i]].Start,
           elArc[jBest[i]].nPoints, ref Delta, ref Ellipse1.f,
                                        ref Ellipse1.a, ref Ellipse1.b, ref Ellipse1.c, ref Ellipse1.d);
    Sum = QualityOfEllipseNew(ia, Ellipse1, SortArcs, fm1);
    if (disp) DrawEllipse(Ellipse1, fm1);
    if (!(Ellipse1.a > 5.0 && Ellipse1.b > 5.0) ||
                                         Ellipse1.d - Ellipse1.b < fm1.height * 2 / 5) Sum = 0;
    else
    {
      if (Sum > maxSum)
      {
        if (disp) DrawEllipse(Ellipse1, fm1);
        if (disp) DrawRedArc(jBest[i], fm1);
        maxSum = Sum;
        jbestOpt = jBest[i];
        Ellipse = Ellipse1;
      }
    }
  } //================== end for (i ... i < nBest; ======================
  DrawRedArc(jbestOpt, fm1);
  Pen pen = new Pen(Color.Red);
  DrawEllipsePen(Ellipse, pen, fm1);
  return jbestOpt;
} //******************** end HelpArcNew *******************************
The rear wheel of the bicycle is sometimes obscured by the cyclist’s legs so that the ellipse cannot be detected. If a high-quality ellipse of the front wheel is already recognized, a copy of this ellipse is assigned to the rear wheel. So that this assignment can be done right, the tangent at the midpoint MP of an arc ia1 of the rear wheel must be calculated. A point P is found on the ellipse of the front wheel, which has the same tangent and the same orientation as the orientation of the arc ia1. The copy of the ellipse of the front wheel is placed so that the point P lies on the point MP. Then, the parameters of the copy of the ellipse are specified with the method HelpArcNew. The relative position of both ellipses, especially their distance to each other, is checked with the method CminusCel before and after the call of HelpArcNew. All these procedures are performed in the method FindEllipsesMode . Here is the code for this method.
public int FindEllipsesMode(CImage SigmaIm, Ellipse[] ListEllipse, ref int nEllipse, Form1 fm1)
{
    int[] SortArcs = new int[nArcs];
  int maxNP = 0, k = SortingArcs(SortArcs, ref maxNP);
  int i, ia, ia1, i0, i1;
  nEllipse = 0;
  double a = 0.0, b = 0.0, c = 0.0, d = 0.0; //, fret = 0.0;
  int[,] List = new int[20, 1200];
  int[] nArcList = new int[20];
  SCircle[] Circle = new SCircle[20];
  for (i = 0; i < 20; i++)
  {
    Circle[i] = new SCircle();
    Circle[i].goodCirc = true;
  }
  Ellipse[] smalList = new Ellipse[20];
  for (i = 0; i < 20; i++) smalList[i] = new Ellipse();
  int Sum1 = 0;
  double AnglePerPoint = 0.0, maxPoints = 0.0;
  fm1.progressBar1.Visible = true;
  fm1.progressBar1.Step = 1;
  int jump, Len = nArcs, nStep = 20;
  if (Len > 2 * nStep) jump = Len / nStep;
  else
    jump = 2;
  double Delta = 0.0, f = 0.0, F = 0.0;
  Ellipse Ellipse1 = new Ellipse();
  Ellipse Ellipse2 = new Ellipse();
  int[] Pattern = new int[100000];
  double aa = 0.0, bb = 0.0, cc = 0.0, dd = 0.0;
  for (i0 = 0; i0 < nArcs; i0++)  //======================================
  {
    if ((i0 % jump) == jump - 1) fm1.progressBar1.PerformStep();
    ia = SortArcs[i0];
    DrawRedArc(ia, fm1);
    if (elArc[ia].nPoints <= 5) break;
    GetEllipseNew(Vert, elArc[ia].Start, elArc[ia].nPoints, 0, 0, ref Delta, ref f,
                                               ref a, ref b, ref c, ref d);
    DrawEllipse(f, a, b, c, d, fm1);
    if (b < 20.0 || a < 6.0 || d + b > fm1.height || d - 4 * b < 0.0) continue;
    int jbestOpt = -1;
    Ellipse1.a = a;
    Ellipse1.b = b;
    Ellipse1.c = c;
    Ellipse1.d = d;
    Point P1 = new Point(0, 0);
    Point P2 = new Point(0, 0);
    if (a > 5.0 && b > 5.0)
    {
      Sum1 = QualityOfEllipseNew(ia, Ellipse1, SortArcs, fm1);
      AnglePerPoint = elArc[ia].Angle / elArc[ia].nPoints;
      maxPoints = 2 * Math.PI / AnglePerPoint;
      if (b > fm1.height / 4 || elArc[ia].nPoints < 10) Sum1 = 0;
      Pen pen = new Pen(Color.Red);
      if (elArc[ia].nPoints < 10 || d + b > fm1.height * 2 / 5)
      {
        jbestOpt = HelpArcNew(ia, SortArcs, ref Ellipse1, Sum1, fm1);
        DrawEllipse(Ellipse1, fm1);
      }
    }
    for (i1 = i0 + 1; i1 < nArcs; i1++) //=================================
    {
      ia1 = SortArcs[i1];
      if (!Position(ia1, Ellipse1, fm1)) continue;
      if (elArc[ia1].nPoints <= 5)
      {
        MessageBox.Show("Finishing the search for ia1");
        break;
      }
      CBox BoxP1 = new CBox();
      CBox BoxP2 = new CBox();
      int iv = elArc[ia].Start, x = Vert[iv].X, y = Vert[iv].Y;
      int iv1 = elArc[ia1].Start, x1 = Vert[iv1].X, y1 = Vert[iv1].Y;
      GetEllipseNew(Vert, elArc[ia1].Start, elArc[ia1].nPoints, 0, 0, ref Delta, ref f,
                                               ref a, ref b, ref c, ref d);
      DrawEllipse(f, a, b, c, d, fm1);
      if (!(a > 5.0 && b > 5.0)) continue;
      DrawRedArc(ia1, fm1);
      double K2 = DrawTangent(ia1, ref P2, fm1);
      P1 = PointWithTangent(Ellipse1, K2, elArc[ia1].Dart, fm1);
      if (P1.X == 0 && P1.Y == 0) continue;
      Ellipse2 = Ellipse1;
      Ellipse2.c = P2.X + Ellipse1.c - P1.X;
      Ellipse2.d = P2.Y + Ellipse1.d - P1.Y;
      DrawEllipse(Ellipse2, fm1);
      if (d + b > fm1.height || d - b < fm1.height * 2 / 5) continue;
      jbestOpt = -1;
      if (Ellipse2.a > 5.0 && Ellipse2.b > 5.0)
      {
        Sum1 = QualityOfEllipseNew(ia1, Ellipse2, SortArcs, fm1);
        AnglePerPoint = elArc[ia1].Angle / elArc[ia1].nPoints;
        maxPoints = 2 * Math.PI / AnglePerPoint;
        Pen pen = new Pen(Color.Red);
        if ((elArc[ia1].nPoints < 10 || d + b > fm1.height * 2 / 5) &&
                                        CminusCel(Ellipse1, Ellipse2, fm1))
        {
          jbestOpt = HelpArcNew(ia1, SortArcs, ref Ellipse2, Sum1, fm1);
          DrawEllipse(Ellipse2, fm1);
        }
      }
      bool CMINC = CminusCel(Ellipse1, Ellipse2, fm1);
      if (!CMINC) continue;
      ListEllipse[nEllipse] = Ellipse1;
      nEllipse++;
      ListEllipse[nEllipse] = Ellipse2;
      nEllipse++;
      if (nEllipse >= 2)
      {
        fm1.progressBar1.Step = fm1.progressBar1.Maximum - Len / (100 / 6) -
                                                    fm1.progressBar1.Value;
        fm1.progressBar1.PerformStep();
        return 1;
      }
    } //============== end for (i1 = 0; ... ============================
  } //=============== end for (i0 = 0; ... =============================
  MessageBox.Show("FindEllipsesMode: no bike recognized");
  return -1;
} //****************** end FindEllipseMode ******************************
The recognition of the wheels is the most important part of the bicycle recognition. When both ellipses of the wheels are recognized, the method RecoFrame is called. It recognizes the direction of travel of the bicycle. This method contains several simple models of different types of the frame. Each type of the frame is presented two times: one with the fork of the front wheel of the bicycle to the left and one with the fork to the right. These models are tested one after the other. Each model is transformed so that the positions of the wheel axles match the centers of the ellipses. A narrow rectangle is formed around each straight segment of the frame. Then all polygons in the processed image are passed through and the lengths of the polygon edges that fit into the rectangles are summed. The model with the greatest sum prevails. In this way the direction of the movement of the bicycle is recognized. An example of the model of the frame is shown in Figure 13-3.
../images/474294_1_En_13_Chapter/474294_1_En_13_Fig3_HTML.jpg
Figure 13-3

Example of a model of the frame

Another Method of Recognizing the Direction

The method just described works when the plane of the frame is at an acute angle to the viewing direction as, for example, in Figure 13-1. In addition, parts of the frame are often obscured by the cyclist’s legs. Therefore we have developed another method DarkSpots which returns the direction of the bike movement: 0 for right and 2 for left. The method makes a box inside of each wheel, calculates histograms of the lightness and sums SumLengths of lengths of almost horizontal polygon edges in these boxes and decides about the drawing direction of the bike. The decision is made by comparing the sum of histogram values below a threshold, i.e. the number of dark pixels in the box, plus 6*SumLenths in both boxes. The greater value indicates the rear wheel and with it also the direction of drawing: if the rear wheel is on the right hand side then the bike moves to left.

When the ellipses of the wheels and the direction of movement are recognized, the ellipses of the wheels and the model of the frame are shown in the right picture box. The message box in the middle of the display shows the message “Bicycle going to left is recognized.” If the user clicks Save result, a text file will be saved on the disk with context corresponding to the following example:

“A bicycle going to left has elliptical wheels.

First: a = 113; b = 173; c = 864; d = 796.

Second: a = 114; b = 173; c = 469; d = 790.”

The notations are as follows: a is the horizontal half-axis of the ellipse, b is its vertical half-axis, c is the x coordinate of the center of the wheel, and d is its y coordinate.

We have tested about 100 photographs showing bicycles on streets in a city. The bicycles were recognized in all photograps except large images of about 2000 × 1500 pixels with small bicycles of about 150 pixels in length (Figure 13-4).
../images/474294_1_En_13_Chapter/474294_1_En_13_Fig4_HTML.jpg
Figure 13-4

Example of an image with a nonrecognized bicycle

Figure 13-5 provides some examples of images with recognized bicycles.
../images/474294_1_En_13_Chapter/474294_1_En_13_Fig5_HTML.jpg
Figure 13-5

Examples of images with recognized bicycles

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.8.247