Exemple #1
0
int Plane::Clip(const Triangle &triangle, Triangle &t1, Triangle &t2) const
{
	bool side[3];
	side[0] = IsOnPositiveSide(triangle.a);
	side[1] = IsOnPositiveSide(triangle.b);
	side[2] = IsOnPositiveSide(triangle.c);
	int nPos = (side[0] ? 1 : 0) + (side[1] ? 1 : 0) + (side[2] ? 1 : 0);
	if (nPos == 0) // Everything should be clipped?
		return 0;
	// We will output at least one triangle, so copy the input to t1 for processing.
	t1 = triangle;

	if (nPos == 3) // All vertices of the triangle are in positive side?
		return 1;

	if (nPos == 1)
	{
		if (side[1])
		{
			vec tmp = t1.a;
			t1.a = t1.b;
			t1.b = t1.c;
			t1.c = tmp;
		}
		else if (side[2])
		{
			vec tmp = t1.a;
			t1.a = t1.c;
			t1.c = t1.b;
			t1.b = tmp;
		}

		// After the above cycling, t1.a is the triangle on the positive side.
		float t;
		Intersects(LineSegment(t1.a, t1.b), &t);
		t1.b = t1.a + (t1.b-t1.a)*t;
		Intersects(LineSegment(t1.a, t1.c), &t);
		t1.c = t1.a + (t1.c-t1.a)*t;
		return 1;
	}
	// Must be nPos == 2.
	if (!side[1])
	{
		vec tmp = t1.a;
		t1.a = t1.b;
		t1.b = t1.c;
		t1.c = tmp;
	}
	else if (!side[2])
	{
		vec tmp = t1.a;
		t1.a = t1.c;
		t1.c = t1.b;
		t1.b = tmp;
	}
	// After the above cycling, t1.a is the triangle on the negative side.

	float t, r;
	Intersects(LineSegment(t1.a, t1.b), &t);
	vec ab = t1.a + (t1.b-t1.a)*t;
	Intersects(LineSegment(t1.a, t1.c), &r);
	vec ac = t1.a + (t1.c-t1.a)*r;
	t1.a = ab;

	t2.a = t1.c;
	t2.b = ac;
	t2.c = ab;

	return 2;
}
void RowBitmapLineSegmentFinder::reset() {
  currentRowIndex = -1;
  firstLineSegmentPreviousRow = LineSegment();
  secondLineSegmentPreviousRow = LineSegment();
}
Exemple #3
0
LineSegment Plane::Project(const LineSegment &lineSegment) const
{
	return LineSegment(Project(lineSegment.a), Project(lineSegment.b));
}
  vector<PlateLine> PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical)
  {
    if (this->debug)
      cout << "PlateLines::getLines" << endl;

    int HORIZONTAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityHorizontal;
    int VERTICAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityVertical;

    vector<Vec2f> allLines;
    vector<PlateLine> filteredLines;

    int sensitivity;
    if (vertical)
      sensitivity = VERTICAL_SENSITIVITY * (1.0 / sensitivityMultiplier);
    else
      sensitivity = HORIZONTAL_SENSITIVITY * (1.0 / sensitivityMultiplier);

    HoughLines( edges, allLines, 1, CV_PI/180, sensitivity, 0, 0 );

    for( size_t i = 0; i < allLines.size(); i++ )
    {
      float rho = allLines[i][0], theta = allLines[i][1];
      Point pt1, pt2;
      double a = cos(theta), b = sin(theta);
      double x0 = a*rho, y0 = b*rho;

      double angle = theta * (180 / CV_PI);
      pt1.x = cvRound(x0 + 1000*(-b));
      pt1.y = cvRound(y0 + 1000*(a));
      pt2.x = cvRound(x0 - 1000*(-b));
      pt2.y = cvRound(y0 - 1000*(a));

      if (vertical)
      {
        if (angle < 20 || angle > 340 || (angle > 160 && angle < 210))
        {
          // good vertical

          LineSegment line;
          if (pt1.y <= pt2.y)
            line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
          else
            line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);

          // Get rid of the -1000, 1000 stuff.  Terminate at the edges of the image
          // Helps with debugging/rounding issues later
          LineSegment top(0, 0, edges.cols, 0);
          LineSegment bottom(0, edges.rows, edges.cols, edges.rows);
          Point p1 = line.intersection(bottom);
          Point p2 = line.intersection(top);

          PlateLine plateLine;
          plateLine.line = LineSegment(p1.x, p1.y, p2.x, p2.y);
          plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
          filteredLines.push_back(plateLine);
        }
      }
      else
      {
        if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
        {
          // good horizontal

          LineSegment line;
          if (pt1.x <= pt2.x)
            line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
          else
            line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);

          // Get rid of the -1000, 1000 stuff.  Terminate at the edges of the image
          // Helps with debugging/ rounding issues later
          int newY1 = line.getPointAt(0);
          int newY2 = line.getPointAt(edges.cols);

          PlateLine plateLine;
          plateLine.line = LineSegment(0, newY1, edges.cols, newY2);
          plateLine.confidence = (1.0 - MIN_CONFIDENCE) * ((float) (allLines.size() - i)) / ((float)allLines.size()) + MIN_CONFIDENCE;
          filteredLines.push_back(plateLine);
        }
      }
    }

    return filteredLines;
  }
void CharacterAnalysis::analyze()
{


    thresholds = produceThresholds(img_gray, config);


    /*
      // Morph Close the gray image to make it easier to detect blobs
      int morph_elem  = 1;
      int morph_size = 1;
      Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );

      for (int i = 0; i < thresholds.size(); i++)
      {
        //morphologyEx( mask, mask, MORPH_CLOSE, element );
        morphologyEx( thresholds[i], thresholds[i], MORPH_OPEN, element );
        //dilate( thresholds[i], thresholds[i],  element );

      }
    */


    timespec startTime;
    getTime(&startTime);


    for (int i = 0; i < thresholds.size(); i++)
    {
        vector<vector<Point> > contours;
        vector<Vec4i> hierarchy;

        Mat tempThreshold(thresholds[i].size(), CV_8U);
        thresholds[i].copyTo(tempThreshold);
        findContours(tempThreshold,
                     contours, // a vector of contours
                     hierarchy,
                     CV_RETR_TREE, // retrieve all contours
                     CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours

        allContours.push_back(contours);
        allHierarchy.push_back(hierarchy);
    }




    if (config->debugTiming)
    {
        timespec endTime;
        getTime(&endTime);
        cout << "  -- Character Analysis Find Contours Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }
    //Mat img_equalized = equalizeBrightness(img_gray);


    getTime(&startTime);

    for (int i = 0; i < thresholds.size(); i++)
    {
        vector<bool> goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]);
        charSegments.push_back(goodIndices);

        if (config->debugCharAnalysis)
            cout << "Threshold " << i << " had " << getGoodIndicesCount(goodIndices) << " good indices." << endl;
    }

    if (config->debugTiming)
    {
        timespec endTime;
        getTime(&endTime);
        cout << "  -- Character Analysis Filter Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }



    this->plateMask = findOuterBoxMask();

    if (hasPlateMask)
    {
        // Filter out bad contours now that we have an outer box mask...
        for (int i = 0; i < thresholds.size(); i++)
        {
            charSegments[i] = filterByOuterMask(allContours[i], allHierarchy[i], charSegments[i]);
        }
    }


    int bestFitScore = -1;
    int bestFitIndex = -1;
    for (int i = 0; i < thresholds.size(); i++)
    {

        //vector<bool> goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]);
        //charSegments.push_back(goodIndices);

        int segmentCount = getGoodIndicesCount(charSegments[i]);


        if (segmentCount > bestFitScore)
        {
            bestFitScore = segmentCount;
            bestFitIndex = i;
            bestCharSegments = charSegments[i];
            bestThreshold = thresholds[i];
            bestContours = allContours[i];
            bestHierarchy = allHierarchy[i];
            bestCharSegmentsCount = segmentCount;
        }
    }

    if (this->config->debugCharAnalysis)
        cout << "Best fit score: " << bestFitScore << " Index: " << bestFitIndex << endl;


    if (bestFitScore <= 1)
        return;


    //getColorMask(img, allContours, allHierarchy, charSegments);

    if (this->config->debugCharAnalysis)
    {

        Mat img_contours(bestThreshold.size(), CV_8U);
        bestThreshold.copyTo(img_contours);
        cvtColor(img_contours, img_contours, CV_GRAY2RGB);

        vector<vector<Point> > allowedContours;
        for (int i = 0; i < bestContours.size(); i++)
        {
            if (bestCharSegments[i])
                allowedContours.push_back(bestContours[i]);
        }

        drawContours(img_contours, bestContours,
                     -1, // draw all contours
                     cv::Scalar(255,0,0), // in blue
                     1); // with a thickness of 1

        drawContours(img_contours, allowedContours,
                     -1, // draw all contours
                     cv::Scalar(0,255,0), // in green
                     1); // with a thickness of 1


        displayImage(config, "Matching Contours", img_contours);
    }


    //charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP));



    this->linePolygon =  getBestVotedLines(img_gray, bestContours, bestCharSegments);

    if (this->linePolygon.size() > 0)
    {
        this->topLine = LineSegment(this->linePolygon[0].x, this->linePolygon[0].y, this->linePolygon[1].x, this->linePolygon[1].y);
        this->bottomLine = LineSegment(this->linePolygon[3].x, this->linePolygon[3].y, this->linePolygon[2].x, this->linePolygon[2].y);
        //this->charArea = getCharSegmentsBetweenLines(bestThreshold, bestContours, this->linePolygon);
        filterBetweenLines(bestThreshold, bestContours, bestHierarchy, linePolygon, bestCharSegments);

        this->charArea = getCharArea();

        if (this->charArea.size() > 0)
        {
            this->charBoxTop = LineSegment(this->charArea[0].x, this->charArea[0].y, this->charArea[1].x, this->charArea[1].y);
            this->charBoxBottom = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[2].x, this->charArea[2].y);
            this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y);
            this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y);


        }
    }

    this->thresholdsInverted = isPlateInverted();



}
bool Localization::Calculate(vector<LineSegment> &clusteredLines,
		bool circleDetected, const Point2f &FieldHullRealCenter,
		const vector<cv::Point2f> &FieldHullReal,
		const Point2d &resultCircleRotated, const vector<Point2f> &goalPosition,
		const bool &confiused, vector<LineContainer> &AllLines,
		vector<FeatureContainer> &AllFeatures)
{
	if (_cameraProjections == NULL)
	{
		ROS_ERROR("Error in programming");
		return false;
	}

	AllLines.reserve(clusteredLines.size());
	AllFeatures.reserve(5);

	const double MAX_FASHER = 200.;
	atLeastOneObservation = false;

	double UPDATENORMAL = params.loc->UPDATENORMAL()
			* params.loc->TOTALGAIN();
	double UPDATESTRONG = params.loc->UPDATESTRONG()
			* params.loc->TOTALGAIN();
	double UPDATEWEAK = params.loc->UPDATEWEAK() * params.loc->TOTALGAIN();

	LineSegment HorLine(cv::Point(0, -10), cv::Point(0, 10));
	LineSegment VerLine(cv::Point(10, 0), cv::Point(-10, 0));

	for (size_t i = 0; i < clusteredLines.size(); i++)
	{
		LineSegment lineSeg = clusteredLines[i];

		if (lineSeg.GetLength() > params.loc->minLineLen())
		{
			cv::Point2d mid = lineSeg.GetMiddle();

			if (lineSeg.GetAbsMinAngleDegree(VerLine) < 45)
			{
				LineType thisType = VerUndef;
				double angleDiffVer = lineSeg.GetExteriorAngleDegree(VerLine);
				if (angleDiffVer < -90)
					angleDiffVer += 180;
				if (angleDiffVer > 90)
					angleDiffVer += -180;

				if (lineSeg.DistanceFromLine(cv::Point(0, 0))
						> params.loc->VerLineMinDistanceToUpdate())
				{
					LandmarkType ltype = CenterL;
					double estimatedY = 0;
					if (mid.y > 0)
					{
						thisType = VerLeft;
						estimatedY = B2 - mid.y;
						ltype = LeftL;
					}
					else
					{
						thisType = VerRight;
						estimatedY = -B2 + abs(mid.y);
						ltype = RightL;
					}
					addObservation(Point2d(0, estimatedY), 0,
							MAX_FASHER * getUpdateCoef(UPDATENORMAL, lineSeg),
							ltype);
				}
				else if (lineSeg.DistanceFromLine(FieldHullRealCenter)
						> (params.loc->VerLineMinDistanceToUpdate() / 2.)
						&& cv::contourArea(FieldHullReal) > 4)
				{
					LandmarkType ltype = CenterL;
					LineSegment l2Test = lineSeg;
					if (lineSeg.P1.x > lineSeg.P2.x)
					{
						l2Test.P1 = lineSeg.P2;
						l2Test.P2 = lineSeg.P1;
					}

					double estimatedY = 0;
					if (l2Test.GetSide(FieldHullRealCenter) < 0)
					{
						thisType = VerLeftNear;
						estimatedY = B2 - mid.y;
						ltype = LeftL;
					}
					else
					{
						thisType = VerRightNear;
						estimatedY = -B2 + abs(mid.y);
						ltype = RightL;
					}
					addObservation(Point2d(0, estimatedY), 0,
							MAX_FASHER * getUpdateCoef(UPDATENORMAL, lineSeg),
							ltype);
				}
				AllLines.push_back(LineContainer(lineSeg, thisType));
			}
			else
			{
				LineType thisType = HorUndef;
				double angleDiffHor = lineSeg.GetExteriorAngleDegree(HorLine);
				if (angleDiffHor < -90)
					angleDiffHor += 180;
				if (angleDiffHor > 90)
					angleDiffHor += -180;

				if (circleDetected
						&& DistanceFromLineSegment(lineSeg, resultCircleRotated)
								< 1)
				{
					thisType = HorCenter;
					double estimatedX = -mid.x;

					addObservation(Point2d(estimatedX, 0),
							MAX_FASHER * UPDATENORMAL, 0, CenterL);
				}

				if (goalPosition.size() >= 2
						&& lineSeg.DistanceFromLine(goalPosition[0]) < 0.5
						&& lineSeg.DistanceFromLine(goalPosition[1]) < 0.5)
				{

					LandmarkType typel = CenterL;
					double estimatedX = 0;
					if (mid.x > 0)
					{
						typel = FrontL;
						estimatedX = A2 - mid.x;
					}
					else
					{
						typel = BackL;
						estimatedX = -A2 + abs(mid.x);
					}
					double lowPC = getUpdateCoef(
							(goalPosition.size() == 2 ?
									UPDATESTRONG : UPDATENORMAL), lineSeg);
					addObservation(Point2d(estimatedX, 0), MAX_FASHER * lowPC,
							0, typel);
					thisType = HorGoal;

				}

				AllLines.push_back(LineContainer(lineSeg, thisType));
			}
		}
	}

	for (size_t i = 0; i < AllLines.size(); i++)
	{
		LineContainer hI = AllLines[i];
		if (hI.type != HorUndef)
			continue;
		for (size_t j = i; j < AllLines.size(); j++)
		{
			LineContainer hJ = AllLines[j];
			if (hJ.type != HorUndef)
				continue;
			cv::Point2d midI = hI.lineTransformed.GetMiddle();
			cv::Point2d midJ = hJ.lineTransformed.GetMiddle();
			double distanceToEachOther = dist3D_Segment_to_Segment(
					hI.lineTransformed, hJ.lineTransformed);

			double midPointsLSAngleToOne =
					hI.lineTransformed.GetAbsMinAngleDegree(
							LineSegment(midI, midJ));
			if (distanceToEachOther < E * 1.5 && distanceToEachOther > E * 0.5
					&& hI.lineTransformed.GetAbsMinAngleDegree(
							hJ.lineTransformed) < 30
					&& midPointsLSAngleToOne > 25)
			{

				bool hJ_Is_Goal_Line = hJ.lineTransformed.DistanceFromLine(
						cv::Point(0, 0))
						> hI.lineTransformed.DistanceFromLine(cv::Point(0, 0));
				cv::Point2d mid = hJ_Is_Goal_Line ? midJ : midI;
				double estimatedX = 0;
				if ((hJ_Is_Goal_Line ? hJ.lineTransformed : hI.lineTransformed).DistanceFromLine(
						cv::Point(0, 0)) > 1.2)
				{
					LandmarkType typel = CenterL;
					if (mid.x > 0)
					{
						estimatedX = A2 - mid.x;
						typel = FrontL;
					}
					else
					{
						estimatedX = -A2 + abs(mid.x);
						typel = BackL;
					}
					double lowPC = getUpdateCoef(UPDATESTRONG,
							hJ_Is_Goal_Line ?
									hJ.lineTransformed : hI.lineTransformed);
					addObservation(Point2d(estimatedX, 0), MAX_FASHER * lowPC,
							0, typel);
				}
			}
		}
	}

	if (circleDetected)
	{

		double estimatedX = -resultCircleRotated.x;
		double estimatedY = -resultCircleRotated.y;

		addObservation(Point2d(estimatedX, estimatedY),
				MAX_FASHER * UPDATEWEAK, MAX_FASHER * UPDATEWEAK, CenterL);

	}

	if (atLeastOneObservation)
	{
		updateVertexIdx();
		if ((nodeCounter % 30 == 0) && PreviousVertexId > 0)
		{
			optimizer.initializeOptimization();
			optimizer.optimize(1);
			Vector3d tmpV;
			optimizer.vertex(PreviousVertexId)->getEstimateData(tmpV.data());
			location.x = tmpV(0);
			location.y = tmpV(1);
		}
	}
	return true;
}
void PlateCorners::scoreVerticals(int v1, int v2)
{
  float score = 0;	// Lower is better

  LineSegment left;
  LineSegment right;

  float charHeightToPlateWidthRatio = config->plateWidthMM / config->charHeightMM;
  float idealPixelWidth = this->charHeight *  (charHeightToPlateWidthRatio * 1.03);	// Add 3% so we don't clip any characters

  if (v1 == NO_LINE && v2 == NO_LINE)
  {
    //return;
    Point centerTop = charRegion->getCharBoxTop().midpoint();
    Point centerBottom = charRegion->getCharBoxBottom().midpoint();
    LineSegment centerLine = LineSegment(centerBottom.x, centerBottom.y, centerTop.x, centerTop.y);

    left = centerLine.getParallelLine(idealPixelWidth / 2);
    right = centerLine.getParallelLine(-1 * idealPixelWidth / 2 );

    score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL * 2;
  }
  else if (v1 != NO_LINE && v2 != NO_LINE)
  {
    left = this->plateLines->verticalLines[v1];
    right = this->plateLines->verticalLines[v2];
  }
  else if (v1 == NO_LINE && v2 != NO_LINE)
  {
    right = this->plateLines->verticalLines[v2];
    left = right.getParallelLine(idealPixelWidth);
    score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL;
  }
  else if (v1 != NO_LINE && v2 == NO_LINE)
  {
    left = this->plateLines->verticalLines[v1];
    right = left.getParallelLine(-1 * idealPixelWidth);
    score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL;
  }

  // Make sure this line is to the left of our license plate letters
  if (left.isPointBelowLine(charRegion->getCharBoxLeft().midpoint()) == false)
    return;

  // Make sure this line is to the right of our license plate letters
  if (right.isPointBelowLine(charRegion->getCharBoxRight().midpoint()))
    return;

  /////////////////////////////////////////////////////////////////////////
  // Score "Distance from the edge...
  /////////////////////////////////////////////////////////////////////////

  float leftDistanceFromEdge =  abs((float) (left.p1.x + left.p2.x) / 2);
  float rightDistanceFromEdge = abs(this->inputImage.cols - ((float) (right.p1.x + right.p2.x) / 2));

  float distanceFromEdge = leftDistanceFromEdge + rightDistanceFromEdge;
  score += distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT;

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

  float verticalAngleDiff = abs(left.angle - right.angle);

  score += (verticalAngleDiff) * SCORING_BOXINESS_WEIGHT;

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

  Point leftMidLinePoint = left.closestPointOnSegmentTo(charRegion->getCharBoxLeft().midpoint());
  Point rightMidLinePoint = right.closestPointOnSegmentTo(charRegion->getCharBoxRight().midpoint());

  float plateDistance = abs(idealPixelWidth - distanceBetweenPoints(leftMidLinePoint, rightMidLinePoint));

  score += plateDistance * SCORING_VERTICALDISTANCE_WEIGHT;

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

    if (this->config->debugPlateCorners)
    {
      cout << "xx xx Score: charHeight " << this->charHeight << endl;
      cout << "xx xx Score: idealwidth " << idealPixelWidth << endl;
      cout << "xx xx Score: v1,v2= " << v1 << "," << v2 << endl;
      cout << "xx xx Score: Left= " << left.str() << endl;
      cout << "xx xx Score: Right= " << right.str() << endl;

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

      cout << " -- Distance From Edge Score: " << distanceFromEdge << " -- Weight (" << SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT << ")" << endl;
      scorecomponent = distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT;
      cout << " -- -- Score:       " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl;

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

      cout << " -- Score: " << score << endl;
    }

    this->bestVerticalScore = score;
    bestLeft = LineSegment(left.p1.x, left.p1.y, left.p2.x, left.p2.y);
    bestRight = LineSegment(right.p1.x, right.p1.y, right.p2.x, right.p2.y);
  }
}
Exemple #8
0
LineSegment Ray::ToLineSegment(float dStart, float dEnd) const
{
	return LineSegment(GetPoint(dStart), GetPoint(dEnd));
}
Exemple #9
0
static inline void appendLineSegments(const IntShapeIntervals& intervals, SegmentList& result)
{
    for (unsigned i = 0; i < intervals.size(); i++)
        result.append(LineSegment(intervals[i].x1(), intervals[i].x2() + 1));
}
Exemple #10
0
LineSegment AABB::Edge(int edgeIndex) const
{
	assume(0 <= edgeIndex && edgeIndex <= 11);
	switch(edgeIndex)
	{
		default: // For release builds where assume() is disabled, return always the first option if out-of-bounds.
		/* For documentation, here's the segments that are returned:
		case 0: return LineSegment(CornerPoint(0), CornerPoint(1));
		case 1: return LineSegment(CornerPoint(0), CornerPoint(2));
		case 2: return LineSegment(CornerPoint(0), CornerPoint(4));
		case 3: return LineSegment(CornerPoint(1), CornerPoint(3));
		case 4: return LineSegment(CornerPoint(1), CornerPoint(5));
		case 5: return LineSegment(CornerPoint(2), CornerPoint(3));
		case 6: return LineSegment(CornerPoint(2), CornerPoint(6));
		case 7: return LineSegment(CornerPoint(3), CornerPoint(7));
		case 8: return LineSegment(CornerPoint(4), CornerPoint(5));
		case 9: return LineSegment(CornerPoint(4), CornerPoint(6));
		case 10: return LineSegment(CornerPoint(5), CornerPoint(7));
		case 11: return LineSegment(CornerPoint(6), CornerPoint(7));
		*/
		// Force-optimize to avoid calling to CornerPoint for another switch-case statement.
		case 0: return LineSegment(POINT_VEC(minPoint.x, minPoint.y, minPoint.z), POINT_VEC(minPoint.x, minPoint.y, maxPoint.z));
		case 1: return LineSegment(POINT_VEC(minPoint.x, minPoint.y, minPoint.z), POINT_VEC(minPoint.x, maxPoint.y, minPoint.z));
		case 2: return LineSegment(POINT_VEC(minPoint.x, minPoint.y, minPoint.z), POINT_VEC(maxPoint.x, minPoint.y, minPoint.z));
		case 3: return LineSegment(POINT_VEC(minPoint.x, minPoint.y, maxPoint.z), POINT_VEC(minPoint.x, maxPoint.y, maxPoint.z));
		case 4: return LineSegment(POINT_VEC(minPoint.x, minPoint.y, maxPoint.z), POINT_VEC(maxPoint.x, minPoint.y, maxPoint.z));
		case 5: return LineSegment(POINT_VEC(minPoint.x, maxPoint.y, minPoint.z), POINT_VEC(minPoint.x, maxPoint.y, maxPoint.z));
		case 6: return LineSegment(POINT_VEC(minPoint.x, maxPoint.y, minPoint.z), POINT_VEC(maxPoint.x, maxPoint.y, minPoint.z));
		case 7: return LineSegment(POINT_VEC(minPoint.x, maxPoint.y, maxPoint.z), POINT_VEC(maxPoint.x, maxPoint.y, maxPoint.z));
		case 8: return LineSegment(POINT_VEC(maxPoint.x, minPoint.y, minPoint.z), POINT_VEC(maxPoint.x, minPoint.y, maxPoint.z));
		case 9: return LineSegment(POINT_VEC(maxPoint.x, minPoint.y, minPoint.z), POINT_VEC(maxPoint.x, maxPoint.y, minPoint.z));
		case 10: return LineSegment(POINT_VEC(maxPoint.x, minPoint.y, maxPoint.z), POINT_VEC(maxPoint.x, maxPoint.y, maxPoint.z));
		case 11: return LineSegment(POINT_VEC(maxPoint.x, maxPoint.y, minPoint.z), POINT_VEC(maxPoint.x, maxPoint.y, maxPoint.z));
	}
}
Exemple #11
0
LineSegment Ray::ToLineSegment(float d) const
{
	return LineSegment(pos, GetPoint(d));
}
// Implements a basic rudimentary layout analysis based on Leptonica
// works OK for Arabic. For other languages, the function TesseractPageAnalysis
// should be called instead.
bool CubeLineSegmenter::FindLines() {
  // convert the image to gray scale if necessary
  Pix *gray_scale_img = NULL;
  if (orig_img_->d != 2 && orig_img_->d != 8) {
    gray_scale_img = pixConvertTo8(orig_img_, false);
    if (gray_scale_img == NULL) {
      return false;
    }
  } else {
    gray_scale_img = orig_img_;
  }

  // threshold image
  Pix *thresholded_img;
  thresholded_img = pixThresholdToBinary(gray_scale_img, 128);
  // free the gray scale image if necessary
  if (gray_scale_img != orig_img_) {
    pixDestroy(&gray_scale_img);
  }
  // bail-out if thresholding failed
  if (thresholded_img == NULL)  {
    return false;
  }

  // deskew
  Pix *deskew_img = pixDeskew(thresholded_img, 2);
  if (deskew_img == NULL) {
    return false;
  }

  pixDestroy(&thresholded_img);

  img_ = CleanUp(deskew_img);
  pixDestroy(&deskew_img);
  if (img_ == NULL) {
    return false;
  }

  pixDestroy(&deskew_img);

  // compute connected components
  Boxa *boxa = pixConnComp(img_, &con_comps_, 8);
  if (boxa == NULL) {
    return false;
  }

  boxaDestroy(&boxa);

  // estimate dot and alef hgts
  if (EstimateFontParams() == false) {
    return false;
  }

  // perform line segmentation
  if (LineSegment() == false) {
    return false;
  }

  // success
  init_ = true;
  return true;
}
LineSegment RandomLineSegmentNearOrigin(float maxDistanceFromOrigin)
{
	return LineSegment(RandomPointNearOrigin(maxDistanceFromOrigin), RandomPointNearOrigin(maxDistanceFromOrigin));
}
//
// Calculate borders of this mask zone using MCS.
//
void ZoneBorder::Calculate(
	int nType,
	float2 fUpperLeft,
	float2 fLowerRight)
{
	m_nType = nType;

	m_zoneBorder_ccs[MASK_ZONE_TOP] =
		LineSegment
		(
			float2
			{ 
				fUpperLeft.x,
				fUpperLeft.y
			},
			float2
			{ 
				fLowerRight.x,
				fUpperLeft.y
			}
		);

	m_zoneBorder_ccs[MASK_ZONE_RIGHT] =
		LineSegment
		(
			float2
			{ 
				fLowerRight.x,
				fUpperLeft.y
			},
			float2
			{ 
				fLowerRight.x,
				fLowerRight.y
			}
		);

	m_zoneBorder_ccs[MASK_ZONE_BOTTOM] =
		LineSegment
		(
			float2
			{ 
				fLowerRight.x,
				fLowerRight.y
			},
			float2
			{ 
				fUpperLeft.x,
				fLowerRight.y
			}
		);

	m_zoneBorder_ccs[MASK_ZONE_LEFT] =
		LineSegment
		(
			float2
			{ 
				fUpperLeft.x,
				fLowerRight.y
			},
			float2
			{ 
				fUpperLeft.x,
				fUpperLeft.y
			}
		);
}
Exemple #15
0
void process(const vector<string> &args, MyWindow *w)
{
    int i;
    ArgData a = processArgs(args);

    Debugging::setOutStream(cout);

    Mesh m(a.filename);
    if(m.vertices.size() == 0) {
        cout << "Error reading file.  Aborting." << endl;
        exit(0);
        return;
    }            
    
    for(i = 0; i < (int)m.vertices.size(); ++i)
        m.vertices[i].pos = a.meshTransform * m.vertices[i].pos;
    m.normalizeBoundingBox();
    m.computeVertexNormals();

    Skeleton given = a.skeleton;
    given.scale(a.skelScale * 0.7);

    if(a.stopAtMesh) { //if early bailout
        w->addMesh(new StaticDisplayMesh(m));
        return;
    }

    PinocchioOutput o;
    if(!a.noFit) { //do everything
        o = autorig(given, m);
    }
    else { //skip the fitting step--assume the skeleton is already correct for the mesh
        TreeType *distanceField = constructDistanceField(m);
        VisTester<TreeType> *tester = new VisTester<TreeType>(distanceField);

        o.embedding = a.skeleton.fGraph().verts;
        for(i = 0; i < (int)o.embedding.size(); ++i)
            o.embedding[i] = m.toAdd + o.embedding[i] * m.scale;

        o.attachment = new Attachment(m, a.skeleton, o.embedding, tester);

        delete tester;
        delete distanceField;
    }

    if(o.embedding.size() == 0) {
        cout << "Error embedding" << endl;
        exit(0);
    }

    if(a.motionname.size() > 0) {
        w->addMesh(new DefMesh(m, given, o.embedding, *(o.attachment), new Motion(a.motionname)));
    }
    else {
        w->addMesh(new StaticDisplayMesh(m));

        for(i = 1; i < (int)o.embedding.size(); ++i)
        {
            w->addLine(LineSegment(o.embedding[i], o.embedding[given.fPrev()[i]], Vector3(.5, .5, 0), 4.));
        }
    }

    //output skeleton embedding
    for(i = 0; i < (int)o.embedding.size(); ++i)
        o.embedding[i] = (o.embedding[i] - m.toAdd) / m.scale;
    ofstream os("skeleton.out");
    for(i = 0; i < (int)o.embedding.size(); ++i) {
        os << i << " " << o.embedding[i][0] << " " << o.embedding[i][1] <<
                   " " << o.embedding[i][2] << " " << a.skeleton.fPrev()[i] << endl;
    }

    //output attachment
    std::ofstream astrm("attachment.out");
    for(i = 0; i < (int)m.vertices.size(); ++i) {
        Vector<double, -1> v = o.attachment->getWeights(i);
        for(int j = 0; j < v.size(); ++j) {
            double d = floor(0.5 + v[j] * 10000.) / 10000.;
            astrm << d << " ";
        }
        astrm << endl;
    }

    delete o.attachment;
}
Exemple #16
0
  // Compares the matches keypoints for parallel lines.  Removes matches that are criss-crossing too much
  // We assume that license plates won't be upside-down or backwards.  So expect lines to be closely parallel
  void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints, const vector<DMatch> inputMatches, vector<DMatch> &outputMatches)
  {
    Rect crissCrossAreaVertical(0, 0, config->stateIdImageWidthPx, config->stateIdimageHeightPx * 2);
    Rect crissCrossAreaHorizontal(0, 0, config->stateIdImageWidthPx * 2, config->stateIdimageHeightPx);

    for (unsigned int i = 0; i < billMapping.size(); i++)
    {
      vector<DMatch> matchesForOnePlate;
      for (unsigned int j = 0; j < inputMatches.size(); j++)
      {
        if (inputMatches[j].imgIdx == (int) i)
          matchesForOnePlate.push_back(inputMatches[j]);
      }

      // For each plate, compare the lines for the keypoints (training image and query image)
      // go through each line between keypoints and filter out matches that are criss-crossing
      vector<LineSegment> vlines;
      vector<LineSegment> hlines;
      vector<int> matchIdx;

      for (unsigned int j = 0; j < matchesForOnePlate.size(); j++)
      {
        KeyPoint tkp = trainingImgKeypoints[i][matchesForOnePlate[j].trainIdx];
        KeyPoint qkp = queryKeypoints[matchesForOnePlate[j].queryIdx];

        vlines.push_back(LineSegment(tkp.pt.x, tkp.pt.y + config->stateIdimageHeightPx, qkp.pt.x, qkp.pt.y));
        hlines.push_back(LineSegment(tkp.pt.x, tkp.pt.y, qkp.pt.x + config->stateIdImageWidthPx, qkp.pt.y));
        matchIdx.push_back(j);
      }

      // Iterate through each line (n^2) removing the one with the most criss-crosses until there are none left.
      int mostIntersections = 1;
      while (mostIntersections > 0 && vlines.size() > 0)
      {
        int mostIntersectionsIndex = -1;
        mostIntersections = 0;

        for (unsigned int j = 0; j < vlines.size(); j++)
        {
          int intrCount = 0;
          for (unsigned int q = 0; q < vlines.size(); q++)
          {
            Point vintr = vlines[j].intersection(vlines[q]);
            Point hintr = hlines[j].intersection(hlines[q]);
            float vangleDiff = abs(vlines[j].angle - vlines[q].angle);
            float hangleDiff = abs(hlines[j].angle - hlines[q].angle);
            if (vintr.inside(crissCrossAreaVertical) && vangleDiff > 10)
            {
              intrCount++;
            }
            else if (hintr.inside(crissCrossAreaHorizontal) && hangleDiff > 10)
            {
              intrCount++;
            }
          }

          if (intrCount > mostIntersections)
          {
            mostIntersections = intrCount;
            mostIntersectionsIndex = j;
          }
        }

        if (mostIntersectionsIndex >= 0)
        {
          if (this->config->debugStateId)
            cout << "Filtered intersection! " << billMapping[i] <<  endl;
          vlines.erase(vlines.begin() + mostIntersectionsIndex);
          hlines.erase(hlines.begin() + mostIntersectionsIndex);
          matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex);
        }
      }

      // Push the non-crisscrosses back on the list
      for (unsigned int j = 0; j < matchIdx.size(); j++)
      {
        outputMatches.push_back(matchesForOnePlate[matchIdx[j]]);
      }
    }
  }
CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* config)
{

  this->config = config;
  
  this->confidence = 0;
 
  if (this->config->debugCharSegmenter)
    cout << "Starting CharacterSegmenter" << endl;
  
  //CharacterRegion charRegion(img, debug);
  
  timespec startTime;
  getTime(&startTime);

  
  Mat img_gray(img.size(), CV_8U);
  cvtColor( img, img_gray, CV_BGR2GRAY );
  //normalize(img_gray, img_gray, 0, 255, CV_MINMAX );
  medianBlur(img_gray, img_gray, 3);
  
  if (invertedColors)
    bitwise_not(img_gray, img_gray);
  
  
  charAnalysis = new CharacterAnalysis(img_gray, config);
  charAnalysis->analyze();
  
  
  
  if (this->config->debugCharSegmenter)
  {
      displayImage(config, "CharacterSegmenter  Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3));
  }
  

  
  
  

  if (this->config->debugCharSegmenter)
  {
      
    Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U);
    charAnalysis->bestThreshold.copyTo(img_contours);
    cvtColor(img_contours, img_contours, CV_GRAY2RGB);
    
    vector<vector<Point> > allowedContours;
    for (int i = 0; i < charAnalysis->bestContours.size(); i++)
    {
	if (charAnalysis->bestCharSegments[i])
	  allowedContours.push_back(charAnalysis->bestContours[i]);
    }
    
    drawContours(img_contours, charAnalysis->bestContours,
	    -1, // draw all contours
	    cv::Scalar(255,0,0), // in blue
	    1); // with a thickness of 1
    
    drawContours(img_contours, allowedContours,
	    -1, // draw all contours
	    cv::Scalar(0,255,0), // in green
	    1); // with a thickness of 1
    
    if (charAnalysis->linePolygon.size() > 0)
    {
      line(img_contours, charAnalysis->linePolygon[0], charAnalysis->linePolygon[1], Scalar(255, 0, 255), 1);
      line(img_contours, charAnalysis->linePolygon[3], charAnalysis->linePolygon[2], Scalar(255, 0, 255), 1);
    }
    
    Mat bordered = addLabel(img_contours, "Best Contours");
    imgDbgGeneral.push_back(bordered);
  }
  
  // Figure out the average character width
  float totalCharWidth = 0;
  float totalCharHeight = 0;
  
  if (charAnalysis->linePolygon.size() > 0)
  {
    this->top = LineSegment(charAnalysis->linePolygon[0].x, charAnalysis->linePolygon[0].y, charAnalysis->linePolygon[1].x, charAnalysis->linePolygon[1].y);
    this->bottom = LineSegment(charAnalysis->linePolygon[3].x, charAnalysis->linePolygon[3].y, charAnalysis->linePolygon[2].x, charAnalysis->linePolygon[2].y);
    
    for (int i = 0; i < charAnalysis->bestContours.size(); i++)
    {
	if (charAnalysis->bestCharSegments[i] == false)
	  continue;
	
	Rect mr = boundingRect(charAnalysis->bestContours[i]);
	totalCharWidth += mr.width;
	totalCharHeight += mr.height;
    }
    
    int numSamples = charAnalysis->bestCharSegmentsCount;
    float avgCharWidth = totalCharWidth / numSamples;
    float avgCharHeight = totalCharHeight / numSamples;
  
    removeSmallContours(charAnalysis->thresholds, charAnalysis->allContours, avgCharWidth, avgCharHeight);
  
    // Do the histogram analysis to figure out char regions
    
    
    timespec startTime;
    getTime(&startTime);

    
    vector<Mat> allHistograms;
    
    vector<Rect> allBoxes;
    for (int i = 0; i < charAnalysis->allContours.size(); i++)
    {


      Mat histogramMask = Mat::zeros(charAnalysis->thresholds[i].size(), CV_8U);

      fillConvexPoly(histogramMask, charAnalysis->linePolygon.data(), charAnalysis->linePolygon.size(), Scalar(255,255,255));
      
      
      VerticalHistogram vertHistogram(charAnalysis->thresholds[i], histogramMask);
      

      if (this->config->debugCharSegmenter)
      {
	Mat histoCopy(vertHistogram.debugImg.size(), vertHistogram.debugImg.type());
	//vertHistogram.copyTo(histoCopy);
	cvtColor(vertHistogram.debugImg, histoCopy, CV_GRAY2RGB);
	allHistograms.push_back(histoCopy);
      }

//       
      float score = 0;
      vector<Rect> charBoxes = getHistogramBoxes(vertHistogram.debugImg, avgCharWidth, avgCharHeight, &score); 
      
      
      if (this->config->debugCharSegmenter)
      {
	for (int cboxIdx = 0; cboxIdx < charBoxes.size(); cboxIdx++)
	{
	    rectangle(allHistograms[i], charBoxes[cboxIdx], Scalar(0, 255, 0));
	}
	
	Mat histDashboard = drawImageDashboard(allHistograms, allHistograms[0].type(), 3);
	displayImage(config, "Char seg histograms", histDashboard);
      }
      
      for (int z = 0; z < charBoxes.size(); z++)
	allBoxes.push_back(charBoxes[z]);
      //drawAndWait(&histogramMask);
    }
    

    float biggestCharWidth = avgCharWidth;
    // Compute largest char width
    for (int i = 0; i < allBoxes.size(); i++)
    {
      if (allBoxes[i].width > biggestCharWidth)
	biggestCharWidth = allBoxes[i].width;
    }
      

    if (config->debugTiming)
    {
      timespec endTime;
      getTime(&endTime);
      cout << "  -- Character Segmentation Create and Score Histograms Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }
    
    //ColorFilter colorFilter(img, charAnalysis->getCharacterMask());    
    vector<Rect> candidateBoxes = getBestCharBoxes(charAnalysis->thresholds[0], allBoxes, biggestCharWidth);
    
    
    if (this->config->debugCharSegmenter)
    {
	// Setup the dashboard images to show the cleaning filters
      for (int i = 0; i < charAnalysis->thresholds.size(); i++)
      {
	Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type());
	Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes);
	charAnalysis->thresholds[i].copyTo(cleanImg);
	bitwise_and(cleanImg, boxMask, cleanImg);
	cvtColor(cleanImg, cleanImg, CV_GRAY2BGR);
	
	for (int c = 0; c < candidateBoxes.size(); c++)
	  rectangle(cleanImg, candidateBoxes[c], Scalar(0, 255, 0), 1);
	imgDbgCleanStages.push_back(cleanImg);
      }
    }
    
    
    getTime(&startTime);
    
    filterEdgeBoxes(charAnalysis->thresholds, candidateBoxes, biggestCharWidth, avgCharHeight);
    
    candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes);
 
    candidateBoxes = combineCloseBoxes(candidateBoxes, biggestCharWidth);

    cleanCharRegions(charAnalysis->thresholds, candidateBoxes);
    cleanMostlyFullBoxes(charAnalysis->thresholds, candidateBoxes);
    
    //cleanBasedOnColor(thresholds, colorFilter.colorMask, candidateBoxes);
    
    candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes);
    this->characters = candidateBoxes;
    
    if (config->debugTiming)
    {
      timespec endTime;
      getTime(&endTime);
      cout << "  -- Character Segmentation Box cleaning/filtering Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }
    
    if (this->config->debugCharSegmenter)
    {
      
      
      Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3);
      displayImage(config, "Segmentation after cleaning", imgDash);
      
      Mat generalDash = drawImageDashboard(this->imgDbgGeneral, this->imgDbgGeneral[0].type(), 2);
      displayImage(config, "Segmentation General", generalDash);
      
      Mat cleanImgDash = drawImageDashboard(this->imgDbgCleanStages, this->imgDbgCleanStages[0].type(), 3);
      displayImage(config, "Segmentation Clean Filters", cleanImgDash);
    }
  }
  
  
  
  
  
  
  if (config->debugTiming)
  {
    timespec endTime;
    getTime(&endTime);
    cout << "Character Segmenter Time: " << diffclock(startTime, endTime) << "ms." << endl;
  }
}
/**
 * Creates a LineSegment from a template.
 */
LIBSBML_EXTERN
LineSegment_t *
LineSegment_createFrom (const LineSegment_t *temp)
{
  return new(std::nothrow) LineSegment(temp ? *temp : LineSegment());
}
  void CharacterAnalysis::analyze()
  {
    timespec startTime;
    getTimeMonotonic(&startTime);

    pipeline_data->clearThresholds();
    pipeline_data->thresholds = produceThresholds(pipeline_data->crop_gray, config);

    timespec contoursStartTime;
    getTimeMonotonic(&contoursStartTime);

    pipeline_data->textLines.clear();

    for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
    {
      TextContours tc(pipeline_data->thresholds[i]);

      allTextContours.push_back(tc);
    }

    if (config->debugTiming)
    {
      timespec contoursEndTime;
      getTimeMonotonic(&contoursEndTime);
      cout << "  -- Character Analysis Find Contours Time: " << diffclock(contoursStartTime, contoursEndTime) << "ms." << endl;
    }
    //Mat img_equalized = equalizeBrightness(img_gray);

    timespec filterStartTime;
    getTimeMonotonic(&filterStartTime);

    for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
    {
      this->filter(pipeline_data->thresholds[i], allTextContours[i]);

      if (config->debugCharAnalysis)
        cout << "Threshold " << i << " had " << allTextContours[i].getGoodIndicesCount() << " good indices." << endl;
    }

    if (config->debugTiming)
    {
      timespec filterEndTime;
      getTimeMonotonic(&filterEndTime);
      cout << "  -- Character Analysis Filter Time: " << diffclock(filterStartTime, filterEndTime) << "ms." << endl;
    }

    PlateMask plateMask(pipeline_data);
    plateMask.findOuterBoxMask(allTextContours);

    pipeline_data->hasPlateBorder = plateMask.hasPlateMask;
    pipeline_data->plateBorderMask = plateMask.getMask();

    if (plateMask.hasPlateMask)
    {
      // Filter out bad contours now that we have an outer box mask...
      for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
      {
        filterByOuterMask(allTextContours[i]);
      }
    }

    int bestFitScore = -1;
    int bestFitIndex = -1;
    for (unsigned int i = 0; i < pipeline_data->thresholds.size(); i++)
    {

      int segmentCount = allTextContours[i].getGoodIndicesCount();

      if (segmentCount > bestFitScore)
      {
        bestFitScore = segmentCount;
        bestFitIndex = i;
        bestThreshold = pipeline_data->thresholds[i];
        bestContours = allTextContours[i];
      }
    }

    if (this->config->debugCharAnalysis)
      cout << "Best fit score: " << bestFitScore << " Index: " << bestFitIndex << endl;

    if (bestFitScore <= 1)
    {
      pipeline_data->disqualified = true;
      pipeline_data->disqualify_reason = "Low best fit score in characteranalysis";
      return;
    }

    //getColorMask(img, allContours, allHierarchy, charSegments);

    if (this->config->debugCharAnalysis)
    {
      Mat img_contours = bestContours.drawDebugImage(bestThreshold);

      displayImage(config, "Matching Contours", img_contours);
    }

    LineFinder lf(pipeline_data);
    vector<vector<Point> > linePolygons = lf.findLines(pipeline_data->crop_gray, bestContours);

    vector<TextLine> tempTextLines;
    for (unsigned int i = 0; i < linePolygons.size(); i++)
    {
      vector<Point> linePolygon = linePolygons[i];

      LineSegment topLine = LineSegment(linePolygon[0].x, linePolygon[0].y, linePolygon[1].x, linePolygon[1].y);
      LineSegment bottomLine = LineSegment(linePolygon[3].x, linePolygon[3].y, linePolygon[2].x, linePolygon[2].y);

      vector<Point> textArea = getCharArea(topLine, bottomLine);

      TextLine textLine(textArea, linePolygon, pipeline_data->crop_gray.size());

      tempTextLines.push_back(textLine);
    }

    filterBetweenLines(bestThreshold, bestContours, tempTextLines);

    // Sort the lines from top to bottom.
    std::sort(tempTextLines.begin(), tempTextLines.end(), sort_text_line);

    // Now that we've filtered a few more contours, re-do the text area.
    for (unsigned int i = 0; i < tempTextLines.size(); i++)
    {
      vector<Point> updatedTextArea = getCharArea(tempTextLines[i].topLine, tempTextLines[i].bottomLine);
      vector<Point> linePolygon = tempTextLines[i].linePolygon;
      if (updatedTextArea.size() > 0 && linePolygon.size() > 0)
      {
        pipeline_data->textLines.push_back(TextLine(updatedTextArea, linePolygon, pipeline_data->crop_gray.size()));
      }

    }

    pipeline_data->plate_inverted = isPlateInverted();


    if (pipeline_data->textLines.size() > 0)
    {
      int confidenceDrainers = 0;
      int charSegmentCount = this->bestContours.getGoodIndicesCount();
      if (charSegmentCount == 1)
        confidenceDrainers += 91;
      else if (charSegmentCount < 5)
        confidenceDrainers += (5 - charSegmentCount) * 10;

      // Use the angle for the first line -- assume they'll always be parallel for multi-line plates
      int absangle = abs(pipeline_data->textLines[0].topLine.angle);
      if (absangle > config->maxPlateAngleDegrees)
        confidenceDrainers += 91;
      else if (absangle > 1)
        confidenceDrainers += (config->maxPlateAngleDegrees - absangle) ;

      // If a multiline plate has only one line, disqualify
      if (pipeline_data->isMultiline && pipeline_data->textLines.size() < 2)
      {
        if (config->debugCharAnalysis)
          std::cout << "Did not detect multiple lines on multi-line plate" << std::endl;
        confidenceDrainers += 95;
      }

      if (confidenceDrainers >= 90)
      {
        pipeline_data->disqualified = true;
        pipeline_data->disqualify_reason = "Low confidence in characteranalysis";
      }
      else
      {
        float confidence = 100 - confidenceDrainers;
        pipeline_data->confidence_weights.setScore("CHARACTER_ANALYSIS_SCORE", confidence, 1.0);
      }
    }
    else
    {
        pipeline_data->disqualified = true;
        pipeline_data->disqualify_reason = "No text lines found in characteranalysis";
    }

    if (config->debugTiming)
    {
      timespec endTime;
      getTimeMonotonic(&endTime);
      cout << "Character Analysis Time: " << diffclock(startTime, endTime) << "ms." << endl;
    }

    // Draw debug dashboard
    if (this->pipeline_data->config->debugCharAnalysis && pipeline_data->textLines.size() > 0)
    {
      vector<Mat> tempDash;
      for (unsigned int z = 0; z < pipeline_data->thresholds.size(); z++)
      {
        Mat tmp(pipeline_data->thresholds[z].size(), pipeline_data->thresholds[z].type());
        pipeline_data->thresholds[z].copyTo(tmp);
        cvtColor(tmp, tmp, CV_GRAY2BGR);

        tempDash.push_back(tmp);
      }

      Mat bestVal(this->bestThreshold.size(), this->bestThreshold.type());
      this->bestThreshold.copyTo(bestVal);
      cvtColor(bestVal, bestVal, CV_GRAY2BGR);

      for (unsigned int z = 0; z < this->bestContours.size(); z++)
      {
        Scalar dcolor(255,0,0);
        if (this->bestContours.goodIndices[z])
          dcolor = Scalar(0,255,0);
        drawContours(bestVal, this->bestContours.contours, z, dcolor, 1);
      }
      tempDash.push_back(bestVal);
      displayImage(config, "Character Region Step 1 Thresholds", drawImageDashboard(tempDash, bestVal.type(), 3));
    }
  }
Exemple #20
0
LineSegment Frustum::UnProjectLineSegment(float x, float y) const
{
	vec nearPlanePos = NearPlanePos(x, y);
	vec farPlanePos = FarPlanePos(x, y);
	return LineSegment(nearPlanePos, farPlanePos);
}
// 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);
  }
}
Exemple #22
0
LineSegment Frustum::Edge(int edgeIndex) const
{
	assume(0 <= edgeIndex && edgeIndex <= 11);
	switch(edgeIndex)
	{
		default: // For release builds where assume() is disabled, return always the first option if out-of-bounds.
		case 0: return LineSegment(CornerPoint(0), CornerPoint(1));
		case 1: return LineSegment(CornerPoint(0), CornerPoint(2));
		case 2: return LineSegment(CornerPoint(0), CornerPoint(4));
		case 3: return LineSegment(CornerPoint(1), CornerPoint(3));
		case 4: return LineSegment(CornerPoint(1), CornerPoint(5));
		case 5: return LineSegment(CornerPoint(2), CornerPoint(3));
		case 6: return LineSegment(CornerPoint(2), CornerPoint(6));
		case 7: return LineSegment(CornerPoint(3), CornerPoint(7));
		case 8: return LineSegment(CornerPoint(4), CornerPoint(5));
		case 9: return LineSegment(CornerPoint(4), CornerPoint(6));
		case 10: return LineSegment(CornerPoint(5), CornerPoint(7));
		case 11: return LineSegment(CornerPoint(6), CornerPoint(7));
	}
}
Exemple #23
0
bool PhysicalPolygon::intersectCircle(float radius, LineSegment displacement, sf::Vector2f& centerAfterCollision, sf::Vector2f& intersectionPoint, sf::Vector2f& intersectionNormal) const {
	float minDsq{MAX_FLOAT};
	sf::Vector2f closestCenterAfterCollision;
	sf::Vector2f closestIntersectionPoint;
	sf::Vector2f closestIntersectionNormal;
	sf::Vector2f p1;
	sf::Vector2f p2;

	for (auto pVertex = vertices_.begin() + 1; pVertex != vertices_.end(); pVertex++) {
		sf::Vector2f normal(-(*(pVertex-1)-*pVertex).y, (*(pVertex-1)-*pVertex).x);
		normal = normalize( (dot(displacement.start - *pVertex, normal) > 0) ? normal : -normal );
		Line shiftedLine(displacement.start - normal * radius, displacement.end - displacement.start);

		float t, u;
		if (lineIntersect(shiftedLine, LineSegment(*(pVertex - 1), *pVertex), t, u)) {
			if (t >= 0.0f && t <= 1.0f && u >= 0.0f && u <= 1.0f) {
				float dsq = lengthsq(t*shiftedLine.direction);
				if (dsq < minDsq) {
					minDsq = dsq;
					closestCenterAfterCollision = displacement.start + t*shiftedLine.direction;
					closestIntersectionPoint = shiftedLine.origin + t*shiftedLine.direction;
					closestIntersectionNormal = normal;
					p1 = *(pVertex-1); // end points to exclude
					p2 = *pVertex;
				}
			}
		}
	}

	for (auto pVertex = vertices_.begin(); pVertex != vertices_.end(); pVertex++) {
		if (*pVertex == p1 || *pVertex == p2)
			continue;

		sf::Vector2f v = displacement.end - displacement.start;

		sf::Vector2f p = *pVertex;
		sf::Vector2f w = p - displacement.start;
		float a = dot(w, v)/lengthsq(v);
		float b = radius * radius - lengthsq(w - a*v);
		if (b >= 0) {
			float d = a - sqrtf(b/dot(v, v));
			if (d > 0.0f && d < 1.0f && d < sqrtf(minDsq)) {
				minDsq = d*d;
				closestCenterAfterCollision = displacement.start + d*v;
				closestIntersectionPoint = p;
				closestIntersectionNormal = closestCenterAfterCollision - p;
			}
		}
	}


	if (minDsq == MAX_FLOAT)
		return false;
	else {
		centerAfterCollision = closestCenterAfterCollision - 0.1f*normalize(displacement.end - displacement.start);
		intersectionPoint = closestIntersectionPoint;
		intersectionNormal = normalize(closestIntersectionNormal);
	}

	return true;
}
Exemple #24
0
// Returns a polygon "stripe" across the width of the character region.  The lines are voted and the polygon starts at 0 and extends to image width
vector<Point> CharacterAnalysis::getBestVotedLines(Mat img, vector<vector<Point> > contours, vector<bool> goodIndices)
{

    //if (this->debug)
    //  cout << "CharacterAnalysis::getBestVotedLines" << endl;

    vector<Point> bestStripe;

    vector<Rect> charRegions;

    for (int i = 0; i < contours.size(); i++)
    {
        if (goodIndices[i])
            charRegions.push_back(boundingRect(contours[i]));
    }


    // Find the best fit line segment that is parallel with the most char segments
    if (charRegions.size() <= 1)
    {
        // Maybe do something about this later, for now let's just ignore
    }
    else
    {
        vector<LineSegment> topLines;
        vector<LineSegment> bottomLines;
        // Iterate through each possible char and find all possible lines for the top and bottom of each char segment
        for (int i = 0; i < charRegions.size() - 1; i++)
        {
            for (int k = i+1; k < charRegions.size(); k++)
            {
                //Mat tempImg;
                //result.copyTo(tempImg);


                Rect* leftRect;
                Rect* rightRect;
                if (charRegions[i].x < charRegions[k].x)
                {
                    leftRect = &charRegions[i];
                    rightRect = &charRegions[k];
                }
                else
                {
                    leftRect = &charRegions[k];
                    rightRect = &charRegions[i];
                }

                //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2);
                //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2);

                int x1, y1, x2, y2;

                if (leftRect->y > rightRect->y)	// Rising line, use the top left corner of the rect
                {
                    x1 = leftRect->x;
                    x2 = rightRect->x;
                }
                else					// falling line, use the top right corner of the rect
                {
                    x1 = leftRect->x + leftRect->width;
                    x2 = rightRect->x + rightRect->width;
                }
                y1 = leftRect->y;
                y2 = rightRect->y;

                //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255));
                topLines.push_back(LineSegment(x1, y1, x2, y2));


                if (leftRect->y > rightRect->y)	// Rising line, use the bottom right corner of the rect
                {
                    x1 = leftRect->x + leftRect->width;
                    x2 = rightRect->x + rightRect->width;
                }
                else					// falling line, use the bottom left corner of the rect
                {
                    x1 = leftRect->x;
                    x2 = rightRect->x;
                }
                y1 = leftRect->y + leftRect->height;
                y2 = rightRect->y + leftRect->height;

                //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255));
                bottomLines.push_back(LineSegment(x1, y1, x2, y2));

                //drawAndWait(&tempImg);
            }
        }

        int bestScoreIndex = 0;
        int bestScore = -1;
        int bestScoreDistance = -1; // Line segment distance is used as a tie breaker

        // Now, among all possible lines, find the one that is the best fit
        for (int i = 0; i < topLines.size(); i++)
        {
            float SCORING_MIN_THRESHOLD = 0.97;
            float SCORING_MAX_THRESHOLD = 1.03;


            int curScore = 0;
            for (int charidx = 0; charidx < charRegions.size(); charidx++)
            {

                float topYPos = topLines[i].getPointAt(charRegions[charidx].x);
                float botYPos = bottomLines[i].getPointAt(charRegions[charidx].x);

                float minTop = charRegions[charidx].y * SCORING_MIN_THRESHOLD;
                float maxTop = charRegions[charidx].y * SCORING_MAX_THRESHOLD;
                float minBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MIN_THRESHOLD;
                float maxBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MAX_THRESHOLD;
                if ( (topYPos >= minTop && topYPos <= maxTop) &&
                        (botYPos >= minBot && botYPos <= maxBot))
                {
                    curScore++;
                }

                //cout << "Slope: " << topslope << " yPos: " << topYPos << endl;
                //drawAndWait(&tempImg);

            }


            // Tie goes to the one with longer line segments
            if ((curScore > bestScore) ||
                    (curScore == bestScore && topLines[i].length > bestScoreDistance))
            {
                bestScore = curScore;
                bestScoreIndex = i;
                // Just use x distance for now
                bestScoreDistance = topLines[i].length;
            }
        }


        if (this->config->debugCharAnalysis)
        {
            cout << "The winning score is: " << bestScore << endl;
            // Draw the winning line segment
            //Mat tempImg;
            //result.copyTo(tempImg);
            //cv::line(tempImg, topLines[bestScoreIndex].p1, topLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2);
            //cv::line(tempImg, bottomLines[bestScoreIndex].p1, bottomLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2);

            //displayImage(config, "Lines", tempImg);
        }

        //winningLines.push_back(topLines[bestScoreIndex]);
        //winningLines.push_back(bottomLines[bestScoreIndex]);

        Point topLeft 		= Point(0, topLines[bestScoreIndex].getPointAt(0) );
        Point topRight 		= Point(img.cols, topLines[bestScoreIndex].getPointAt(img.cols));
        Point bottomRight 	= Point(img.cols, bottomLines[bestScoreIndex].getPointAt(img.cols));
        Point bottomLeft 	= Point(0, bottomLines[bestScoreIndex].getPointAt(0));


        bestStripe.push_back(topLeft);
        bestStripe.push_back(topRight);
        bestStripe.push_back(bottomRight);
        bestStripe.push_back(bottomLeft);


    }


    return bestStripe;
}