Ejemplo n.º 1
0
// Score a collection of lines as a possible license plate region.
// If any segments are missing, extrapolate the missing pieces
void PlateCorners::scoreHorizontals(int h1, int h2)
{
  
  ScoreKeeper scoreKeeper;

  LineSegment top;
  LineSegment bottom;

  float charHeightToPlateHeightRatio = pipelineData->config->plateHeightMM / pipelineData->config->charHeightMM;
  float idealPixelHeight = tlc.charHeight *  charHeightToPlateHeightRatio;

  float confidenceDiff = 0;
  float missingSegmentPenalty = 0;
  
  if (h1 == NO_LINE && h2 == NO_LINE)
  {
//    return;


    top = tlc.centerHorizontalLine.getParallelLine(idealPixelHeight / 2);
    bottom = tlc.centerHorizontalLine.getParallelLine(-1 * idealPixelHeight / 2 );

    missingSegmentPenalty = 2;
    confidenceDiff += 2;
  }
  else if (h1 != NO_LINE && h2 != NO_LINE)
  {
    top = this->plateLines->horizontalLines[h1].line;
    bottom = this->plateLines->horizontalLines[h2].line;
    confidenceDiff += (1.0 - this->plateLines->horizontalLines[h1].confidence);
    confidenceDiff += (1.0 - this->plateLines->horizontalLines[h2].confidence);
  }
  else if (h1 == NO_LINE && h2 != NO_LINE)
  {
    bottom = this->plateLines->horizontalLines[h2].line;
    top = bottom.getParallelLine(idealPixelHeight);
    missingSegmentPenalty++;
    confidenceDiff += (1.0 - this->plateLines->horizontalLines[h2].confidence);
  }
  else if (h1 != NO_LINE && h2 == NO_LINE)
  {
    top = this->plateLines->horizontalLines[h1].line;
    bottom = top.getParallelLine(-1 * idealPixelHeight);
    missingSegmentPenalty++;
    confidenceDiff += (1.0 - this->plateLines->horizontalLines[h1].confidence);
  }
  
  scoreKeeper.setScore("SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL", missingSegmentPenalty, SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL);
  //scoreKeeper.setScore("SCORING_LINE_CONFIDENCE_WEIGHT", confidenceDiff, SCORING_LINE_CONFIDENCE_WEIGHT);


  // Make sure that the top and bottom lines are above and below
  // the text area
  if (tlc.isAboveText(top) < 1 || tlc.isAboveText(bottom) > -1)
    return;
  
  // We now have 4 possible lines.  Let's put them to the test and score them...


  //////////////////////////////////////////////////////////////////////////
  // SCORE the shape wrt character position and height relative to position
  //////////////////////////////////////////////////////////////////////////

  Point topPoint = top.midpoint();
  Point botPoint = bottom.closestPointOnSegmentTo(topPoint);
  float plateHeightPx = distanceBetweenPoints(topPoint, botPoint);

  // Get the height difference

  float heightRatio = tlc.charHeight / plateHeightPx;
  float idealHeightRatio = (pipelineData->config->charHeightMM / pipelineData->config->plateHeightMM);
  float heightRatioDiff = abs(heightRatio - idealHeightRatio);

  scoreKeeper.setScore("SCORING_PLATEHEIGHT_WEIGHT", heightRatioDiff, SCORING_PLATEHEIGHT_WEIGHT);

  //////////////////////////////////////////////////////////////////////////
  // SCORE the middliness of the stuff.  We want our top and bottom line to have the characters right towards the middle
  //////////////////////////////////////////////////////////////////////////

  Point charAreaMidPoint = tlc.centerVerticalLine.midpoint();
  Point topLineSpot = top.closestPointOnSegmentTo(charAreaMidPoint);
  Point botLineSpot = bottom.closestPointOnSegmentTo(charAreaMidPoint);

  float topDistanceFromMiddle = distanceBetweenPoints(topLineSpot, charAreaMidPoint);
  float bottomDistanceFromMiddle = distanceBetweenPoints(botLineSpot, charAreaMidPoint);

  float idealDistanceFromMiddle = idealPixelHeight / 2;

  float middleScore = abs(topDistanceFromMiddle - idealDistanceFromMiddle) / idealDistanceFromMiddle;
  middleScore +=      abs(bottomDistanceFromMiddle - idealDistanceFromMiddle) / idealDistanceFromMiddle;

  scoreKeeper.setScore("SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT", middleScore, SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT);


  //////////////////////////////////////////////////////////////
  // SCORE: the shape for angles matching the character region
  //////////////////////////////////////////////////////////////

  float charanglediff = abs(tlc.charAngle - top.angle) + abs(tlc.charAngle - bottom.angle);

  scoreKeeper.setScore("SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT", charanglediff, SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT);

  if (pipelineData->config->debugPlateCorners)
  {
    scoreKeeper.printDebugScores();
    Mat debugImg(this->inputImage.size(), this->inputImage.type());
    this->inputImage.copyTo(debugImg);
    cvtColor(debugImg, debugImg, CV_GRAY2BGR);
    line(debugImg, top.p1, top.p2, Scalar(0,0,255), 2);
    line(debugImg, bottom.p1, bottom.p2, Scalar(0,0,255), 2);
    //drawAndWait(&debugImg);

  }

  float score = scoreKeeper.getTotal();
  if (score < this->bestHorizontalScore)
  {
    float scorecomponent;

    if (pipelineData->config->debugPlateCorners)
    {
      cout << "Horizontal breakdown Score:" << endl;
      scoreKeeper.printDebugScores();
    }
    this->bestHorizontalScore = score;
    bestTop = LineSegment(top.p1.x, top.p1.y, top.p2.x, top.p2.y);
    bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y);
  }
}
Ejemplo n.º 2
0
#include "catch.hpp"

using namespace std;
using namespace cv;
using namespace alpr;



TEST_CASE( "LineSegment Test", "[2d primitives]" ) {

  // Test a flat horizontal line
  LineSegment flat_horizontal(1,1, 21,1);
  REQUIRE( flat_horizontal.angle == 0 );
  REQUIRE( flat_horizontal.slope == 0 );
  REQUIRE( flat_horizontal.length == 20 );
  REQUIRE( flat_horizontal.midpoint().y == 1 );
  REQUIRE( flat_horizontal.midpoint().x == 11 );
  REQUIRE( flat_horizontal.getPointAt(11) == 1 );
  
  // Test distance between points calculation
  REQUIRE( distanceBetweenPoints(Point(10,10), Point(20,20)) == Approx(14.1421) );
  REQUIRE( distanceBetweenPoints(Point(-5,10), Point(20,-12)) == Approx(33.3017) );
  
  int testarray1[] = {1, 2, 3, 3, 4, 5 };
  int testarray2[] = {0, 2, -3, 3, -4, 5 };
  int *testarray3;
  REQUIRE( median(testarray1, 6) == 3 );
  REQUIRE( median(testarray2, 6) == 1 );
  REQUIRE( median(testarray3, 0) == 0 );
}
Ejemplo n.º 3
0
// Score a collection of lines as a possible license plate region.
// If any segments are missing, extrapolate the missing pieces
void PlateCorners::scoreHorizontals(int h1, int h2)
{
  //if (this->debug)
  //    cout << "PlateCorners::scorePlate" << endl;

  float score = 0;	// Lower is better

  LineSegment top;
  LineSegment bottom;

  float charHeightToPlateHeightRatio = config->plateHeightMM / config->charHeightMM;
  float idealPixelHeight = this->charHeight *  charHeightToPlateHeightRatio;

  if (h1 == NO_LINE && h2 == NO_LINE)
  {
//    return;
    Point centerLeft = charRegion->getCharBoxLeft().midpoint();
    Point centerRight = charRegion->getCharBoxRight().midpoint();
    LineSegment centerLine = LineSegment(centerLeft.x, centerLeft.y, centerRight.x, centerRight.y);

    top = centerLine.getParallelLine(idealPixelHeight / 2);
    bottom = centerLine.getParallelLine(-1 * idealPixelHeight / 2 );

    score += SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL * 2;
  }
  else if (h1 != NO_LINE && h2 != NO_LINE)
  {
    top = this->plateLines->horizontalLines[h1];
    bottom = this->plateLines->horizontalLines[h2];
  }
  else if (h1 == NO_LINE && h2 != NO_LINE)
  {
    bottom = this->plateLines->horizontalLines[h2];
    top = bottom.getParallelLine(idealPixelHeight);
    score += SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL;
  }
  else if (h1 != NO_LINE && h2 == NO_LINE)
  {
    top = this->plateLines->horizontalLines[h1];
    bottom = top.getParallelLine(-1 * idealPixelHeight);
    score += SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL;
  }

  // Make sure this line is above our license plate letters
  if (top.isPointBelowLine(charRegion->getCharBoxTop().midpoint()) == false)
    return;

  // Make sure this line is below our license plate letters
  if (bottom.isPointBelowLine(charRegion->getCharBoxBottom().midpoint()))
    return;

  // We now have 4 possible lines.  Let's put them to the test and score them...

  /////////////////////////////////////////////////////////////////////////
  // Score "Boxiness" of the 4 lines.  How close is it to a parallelogram?
  /////////////////////////////////////////////////////////////////////////

  float horizontalAngleDiff = abs(top.angle - bottom.angle);

  score += (horizontalAngleDiff) * SCORING_BOXINESS_WEIGHT;
//  if (this->debug)
//    cout << "PlateCorners boxiness score: " << (horizontalAngleDiff + verticalAngleDiff) * SCORING_BOXINESS_WEIGHT << endl;

  //////////////////////////////////////////////////////////////////////////
  // SCORE the shape wrt character position and height relative to position
  //////////////////////////////////////////////////////////////////////////

  Point topPoint = top.midpoint();
  Point botPoint = bottom.closestPointOnSegmentTo(topPoint);
  float plateHeightPx = distanceBetweenPoints(topPoint, botPoint);

  // Get the height difference

  float heightRatio = charHeight / plateHeightPx;
  float idealHeightRatio = (config->charHeightMM / config->plateHeightMM);
  //if (leftRatio < MIN_CHAR_HEIGHT_RATIO || leftRatio > MAX_CHAR_HEIGHT_RATIO || rightRatio < MIN_CHAR_HEIGHT_RATIO || rightRatio > MAX_CHAR_HEIGHT_RATIO)
  float heightRatioDiff = abs(heightRatio - idealHeightRatio);
  // Ideal ratio == ~.45

  // Get the distance from the top and the distance from the bottom
  // Take the average distances from the corners of the character region to the top/bottom lines
//  float topDistance  = distanceBetweenPoints(topMidLinePoint, charRegion->getCharBoxTop().midpoint());
//  float bottomDistance = distanceBetweenPoints(bottomMidLinePoint, charRegion->getCharBoxBottom().midpoint());

//  float idealTopDistance = charHeight * (TOP_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM);
//  float idealBottomDistance = charHeight * (BOTTOM_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM);
//  float distScore = abs(topDistance - idealTopDistance) + abs(bottomDistance - idealBottomDistance);

  score += heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT;

  //////////////////////////////////////////////////////////////////////////
  // SCORE the middliness of the stuff.  We want our top and bottom line to have the characters right towards the middle
  //////////////////////////////////////////////////////////////////////////

  Point charAreaMidPoint = charRegion->getCharBoxLeft().midpoint();
  Point topLineSpot = top.closestPointOnSegmentTo(charAreaMidPoint);
  Point botLineSpot = bottom.closestPointOnSegmentTo(charAreaMidPoint);

  float topDistanceFromMiddle = distanceBetweenPoints(topLineSpot, charAreaMidPoint);
  float bottomDistanceFromMiddle = distanceBetweenPoints(topLineSpot, charAreaMidPoint);

  float idealDistanceFromMiddle = idealPixelHeight / 2;

  float middleScore = abs(topDistanceFromMiddle - idealDistanceFromMiddle) + abs(bottomDistanceFromMiddle - idealDistanceFromMiddle);

  score += middleScore * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT;

//  if (this->debug)
//  {
//    cout << "PlateCorners boxiness score: " << avgRatio * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT << endl;
//    cout << "PlateCorners boxiness score: " << distScore * SCORING_PLATEHEIGHT_WEIGHT << endl;
//  }
  //////////////////////////////////////////////////////////////
  // SCORE: the shape for angles matching the character region
  //////////////////////////////////////////////////////////////

  float charanglediff = abs(charAngle - top.angle) + abs(charAngle - bottom.angle);

  score += charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT;

//  if (this->debug)
//    cout << "PlateCorners boxiness score: " << charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT << endl;

  if (score < this->bestHorizontalScore)
  {
    float scorecomponent;

    if (this->config->debugPlateCorners)
    {
      cout << "xx xx Score: charHeight " << this->charHeight << endl;
      cout << "xx xx Score: idealHeight " << idealPixelHeight << endl;
      cout << "xx xx Score: h1,h2= " << h1 << "," << h2 << endl;
      cout << "xx xx Score: Top= " << top.str() << endl;
      cout << "xx xx Score: Bottom= " << bottom.str() << endl;

      cout << "Horizontal breakdown Score:" << endl;
      cout << " -- Boxiness Score: " << horizontalAngleDiff << "  -- Weight (" << SCORING_BOXINESS_WEIGHT << ")" << endl;
      scorecomponent = horizontalAngleDiff * SCORING_BOXINESS_WEIGHT;
      cout << " -- -- Score:       " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl;

      cout << " -- Height Ratio Diff Score: " << heightRatioDiff << "  -- Weight (" << SCORING_PLATEHEIGHT_WEIGHT << ")" << endl;
      scorecomponent = heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT;
      cout << " -- -- " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl;

      cout << " -- Distance Score: " << middleScore << "  -- Weight (" << SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT << ")" << endl;
      scorecomponent = middleScore * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT;
      cout << " -- -- Score:       " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl;

      cout << " -- Char angle Score: " << charanglediff << "  -- Weight (" << SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT << ")" << endl;
      scorecomponent = charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT;
      cout << " -- -- Score:         " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl;

      cout << " -- Score: " << score << endl;
    }
    this->bestHorizontalScore = score;
    bestTop = LineSegment(top.p1.x, top.p1.y, top.p2.x, top.p2.y);
    bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y);
  }
}