RecognitionResult GeometricRecognizer::recognize(Path2D points)
	{
		//--- Make sure we have some templates to compare this to
		//---  or else recognition will be impossible
        
        if (points.size() < 5){
            return RecognitionResult("Unknown", NULL);
        }
        
        if (templates.empty())
		{
			std::cout << "No templates loaded so no symbols to match." << std::endl;
			return RecognitionResult("Unknown", NULL);
		}

		points = normalizePath(points);
	
		//--- Initialize best distance to the largest possible number
		//--- That way everything will be better than that
		double bestDistance = MAX_DOUBLE;
		//--- We haven't found a good match yet
		int indexOfBestMatch = -1;

		//--- Check the shape passed in against every shape in our database
		for (int i = 0; i < (int)templates.size(); i++)
		{
			//--- Calculate the total distance of each point in the passed in
			//---  shape against the corresponding point in the template
			//--- We'll rotate the shape a few degrees in each direction to
			//---  see if that produces a better match
			double distance = distanceAtBestAngle(points, templates[i]);
			if (distance < bestDistance)
			{
				bestDistance     = distance;
				indexOfBestMatch = i;
			}
		}

		//--- Turn the distance into a percentage by dividing it by 
		//---  half the maximum possible distance (across the diagonal 
		//---  of the square we scaled everything too)
		//--- Distance = hwo different they are
		//--- Subtract that from 1 (100%) to get the similarity
		double score = 1.0 - (bestDistance / halfDiagonal);

		//--- Make sure we actually found a good match
		//--- Sometimes we don't, like when the user doesn't draw enough points
		if (-1 == indexOfBestMatch)
		{
			//cout << "Couldn't find a good match." << endl;
			return RecognitionResult("Unknown", 1);
		}

        cout<<score<<endl;
		RecognitionResult bestMatch(templates[indexOfBestMatch].name, score);
		return bestMatch;
	};
Ejemplo n.º 2
0
void ShapeDetector::report( const std::string &i_name, const std::vector<CGPoint> &i_path )
{
	Path2D p;
	for ( auto pt : i_path )
	{
		if ( p.size() == 0 )
			p.move_to( pt );
		else
			p.line_to( pt );
	}
	shapeDetected( i_name, p );
}
	Point2D GeometricRecognizer::centroid(Path2D points)
	{
		double x = 0.0, y = 0.0;
		for (Path2DIterator i = points.begin(); i != points.end(); i++)
		{
			Point2D point = *i;
			x += point.x;
			y += point.y;
		}
		x /= points.size();
		y /= points.size();
		return Point2D(x, y);
	}	
Ejemplo n.º 4
0
std::vector<Vector2f> GeneratePathNormals(const Path2D& path, bool is_closed,
                                          bool outward) {
  assert(path.size() >= 2);
  // Here we are going to use a simple 3-point interpolation method
  // first we need to make the path in ccw direction
  ClipperLib::Path scaled_path = UScalePathDiaToClipper(path);
  if (!ClipperLib::Orientation(scaled_path)) {
    ClipperLib::ReversePath(scaled_path);
  }
  Path2D ccw_path = DScalePathClipperToDia(scaled_path);

  // Special treatment for the first and last point.
  std::vector<Vector2f> output_vecs(path.size());
  if (is_closed) {
    output_vecs[0] =
        GetNormalFromTwoPoints(ccw_path[ccw_path.size() - 1], ccw_path[1]);
    output_vecs.back() =
        GetNormalFromTwoPoints(ccw_path[ccw_path.size() - 2], ccw_path[0]);
  } else {
    output_vecs[0] = GetNormalFromTwoPoints(ccw_path[0], ccw_path[1]);
    output_vecs.back() = GetNormalFromTwoPoints(ccw_path[ccw_path.size() - 2],
                                                ccw_path[ccw_path.size() - 1]);
  }

  // We use the point before and after ith point to interpolate its normal.
  for (size_t i = 1; i < ccw_path.size() - 1; ++i) {
    output_vecs[i] = GetNormalFromTwoPoints(ccw_path[i - 1], ccw_path[i + 1]);
  }

  // Reverse normal direction
  if (!outward) {
    for (size_t i = 0; i < ccw_path.size(); ++i) {
      output_vecs[i] = -output_vecs[i];
    }
  }
  return output_vecs;
}
        vector<double> GeometricRecognizer::vectorize(Path2D points) // for Protractor
        {
                double sum = 0.0;
                vector<double> vectorized;

                // Preprocessing, Move from .x.y notation to 1D vector notation
                // points[i](.x,.y) => vectorized(i, i+1, ...)
                for (unsigned int i = 0; i < points.size(); i++)
                {
                    vectorized.push_back(points[i].x);
                    vectorized.push_back(points[i].y);
                    sum += points[i].x * points[i].x + points[i].y * points[i].y;
                }
                // normalize values : dividing by magnitude
                // magnitude = sqrt ( sum_i(x²) + sum_i(y²) )
                double magnitude = sqrt(sum);
                for (unsigned int i = 0; i < vectorized.size(); i++)
                        vectorized[i] /= magnitude;
                return vectorized;
        }
Ejemplo n.º 6
0
std::vector<Vector2f> SimplifyPolyline(const Path2D& path, float rel_tol) {
  if (path.size() <= 2) {
    return path;
  }

  std::vector<Vector2f> out;
  if (true) {
    // we compute the boundary square size of the path
    AABB bound = GetAABBWithPadding(path, 0);
    Vector2f span = bound.upper_bound - bound.lower_bound;
    // set a tolerance to remove points that are too close to
    // each other. the relative tolerance is 0.5% of max size
    // so the simplified curve is still pretty smooth
    float tol = std::max(span(0), span(1)) * rel_tol;
    out = PolylineDouglasPeuckerIterative(path, tol);
  } else {
    // only one method implemented
    // the douglas_peucker method may change the topology of input curves
    assert(0);
  }
  return out;
}