vector<PlateLine> PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical) { if (this->debug) cout << "PlateLines::getLines" << endl; static int HORIZONTAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityHorizontal; static 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; }
Vector<2, NumericT> normal(const LineSegment<2, NumericT> & line_segment) { return normal(line_segment.direction()); }
std::vector<LineSegment> EdgelDetector::findLineSegment(std::vector<Edgel> edgels) { std::vector<LineSegment> lineSegments; LineSegment lineSegmentInRun; srand(time(NULL)); do { lineSegmentInRun.supportEdgels.clear(); for (int i = 0; i < 25; i++) { Edgel r1; Edgel r2; const int max_iterations = 100; int iteration = 0, ir1, ir2; //pak 2 random edgels welke compatible zijn met elkaar. do { ir1 = (rand()%(edgels.size())); ir2 = (rand()%(edgels.size())); r1 = edgels.at(ir1); r2 = edgels.at(ir2); iteration++; } while ( ( ir1 == ir2 || !r1.isOrientationCompatible( r2 ) ) && iteration < max_iterations ); if( iteration < max_iterations ) { // 2 edgels gevonden! LineSegment lineSegment; lineSegment.start = r1; lineSegment.end = r2; lineSegment.slope = r1.slope; //check welke edgels op dezelfde line liggen en voeg deze toe als support for (unsigned int o = 0; o < edgels.size(); o++) { if ( lineSegment.atLine( edgels.at(o) ) ) { lineSegment.addSupport( edgels.at(o) ); } } if( lineSegment.supportEdgels.size() > lineSegmentInRun.supportEdgels.size() ) { lineSegmentInRun = lineSegment; } } } // slope van de line bepalen if( lineSegmentInRun.supportEdgels.size() >= EDGELSONLINE ) { float u1 = 0; float u2 = 50000; const Vector2f slope = (lineSegmentInRun.start.position - lineSegmentInRun.end.position); const Vector2f orientation = Vector2f( -lineSegmentInRun.start.slope.y, lineSegmentInRun.start.slope.x ); if (abs (slope.x) <= abs(slope.y)) { for (std::vector<Edgel>::iterator it = lineSegmentInRun.supportEdgels.begin(); it!=lineSegmentInRun.supportEdgels.end(); ++it) { if ((*it).position.y > u1) { u1 = (*it).position.y; lineSegmentInRun.start = (*it); } if ((*it).position.y < u2) { u2 = (*it).position.y; lineSegmentInRun.end = (*it); } } } else { for (std::vector<Edgel>::iterator it = lineSegmentInRun.supportEdgels.begin(); it!=lineSegmentInRun.supportEdgels.end(); ++it) { if ((*it).position.x > u1) { u1 = (*it).position.x; lineSegmentInRun.start = (*it); } if ((*it).position.x < u2) { u2 = (*it).position.x; lineSegmentInRun.end = (*it); } } } // switch startpoint and endpoint according to orientation of edge if( dot( lineSegmentInRun.end.position - lineSegmentInRun.start.position, orientation ) < 0.0f ) { std::swap( lineSegmentInRun.start, lineSegmentInRun.end ); } lineSegmentInRun.slope = (lineSegmentInRun.end.position - lineSegmentInRun.start.position).get_normalized(); // heeft de lineSegmentInRun voldoende dan toevoegen aan lineSegments, // gebruikte edgels verwijderen.. lineSegments.push_back( lineSegmentInRun ); //TODO: Dit moet sneller! for(unsigned int i=0; i<lineSegmentInRun.supportEdgels.size(); i++) { for (std::vector<Edgel>::iterator it = edgels.begin(); it!=edgels.end(); ++it) { if( (*it).position.x == lineSegmentInRun.supportEdgels.at(i).position.x && (*it).position.y == lineSegmentInRun.supportEdgels.at(i).position.y ) { edgels.erase( it ); break; } } } } } while( lineSegmentInRun.supportEdgels.size() >= EDGELSONLINE && edgels.size() >= EDGELSONLINE ); return lineSegments; }
template<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const LineSegment<dimensions>& other) const { return Distance::lineSegmentPointSquared(other.a(), other.b(), _position) < Math::pow<2>(_radius); }
bool LL_SHARED intersection_of_lines_in_two_dimensions(LineSegment first_line,LineSegment second_line, float* x,float* y) { if(first_line.get_dimension()!=second_line.get_dimension() or first_line.get_dimension()!=2) return false; if((first_line.get_ini_point()==first_line.get_end_point()) or (second_line.get_ini_point()==second_line.get_end_point())) return false; if(((first_line.get_end_point()[0]-first_line.get_ini_point()[0]) *(second_line.get_end_point()[1]-second_line.get_ini_point()[1])) !=((first_line.get_end_point()[1]-first_line.get_ini_point()[1]) *(second_line.get_end_point()[0]-second_line.get_ini_point()[0]))) { float intersection_point_x,intersection_point_y; if(first_line.get_end_point()[0]==first_line.get_ini_point()[0]) { float m2=((second_line.get_end_point()[1]-second_line.get_ini_point()[1])/ (second_line.get_end_point()[0]-second_line.get_ini_point()[0])); float b2=second_line.get_ini_point()[1]-m2*second_line.get_ini_point()[0]; intersection_point_x=first_line.get_ini_point()[0]; intersection_point_y=m2*intersection_point_x+b2; } else if(second_line.get_end_point()[0]==second_line.get_ini_point()[0]) { float m1=((first_line.get_end_point()[1]-first_line.get_ini_point()[1])/ (first_line.get_end_point()[0]-first_line.get_ini_point()[0])); float b1=first_line.get_ini_point()[1]-m1*first_line.get_ini_point()[0]; intersection_point_x=second_line.get_ini_point()[0]; intersection_point_y=m1*intersection_point_x+b1; } else { float m1=((first_line.get_end_point()[1]-first_line.get_ini_point()[1])/ (first_line.get_end_point()[0]-first_line.get_ini_point()[0])); float b1=first_line.get_ini_point()[1]-m1*first_line.get_ini_point()[0]; float m2=((second_line.get_end_point()[1]-second_line.get_ini_point()[1])/ (second_line.get_end_point()[0]-second_line.get_ini_point()[0])); float b2=second_line.get_ini_point()[1]-m2*second_line.get_ini_point()[0]; intersection_point_x=(b2-b1)/(m1-m2); intersection_point_y=m1*intersection_point_x+b1; } if(x and y) { *x=intersection_point_x; *y=intersection_point_y; } return true; } return false; }
Ray::Ray(const LineSegment &lineSegment) :pos(lineSegment.a), dir(lineSegment.Dir()) { }
std::vector<cv::Point2f> EdgeFinder::findEdgeCorners() { TextLineCollection tlc(pipeline_data->textLines); vector<Point> corners; // If the character segment is especially small, just expand the existing box // If it's a nice, long segment, then guess the correct box based on character height/position if (tlc.longerSegment.length > tlc.charHeight * 3) { float charHeightToPlateWidthRatio = pipeline_data->config->plateWidthMM / pipeline_data->config->avgCharHeightMM; float idealPixelWidth = tlc.charHeight * (charHeightToPlateWidthRatio * 1.03); // Add 3% so we don't clip any characters float charHeightToPlateHeightRatio = pipeline_data->config->plateHeightMM / pipeline_data->config->avgCharHeightMM; float idealPixelHeight = tlc.charHeight * charHeightToPlateHeightRatio; float verticalOffset = (idealPixelHeight * 1.5 / 2); float horizontalOffset = (idealPixelWidth * 1.25 / 2); LineSegment topLine = tlc.centerHorizontalLine.getParallelLine(verticalOffset); LineSegment bottomLine = tlc.centerHorizontalLine.getParallelLine(-1 * verticalOffset); LineSegment leftLine = tlc.centerVerticalLine.getParallelLine(-1 * horizontalOffset); LineSegment rightLine = tlc.centerVerticalLine.getParallelLine(horizontalOffset); Point topLeft = topLine.intersection(leftLine); Point topRight = topLine.intersection(rightLine); Point botRight = bottomLine.intersection(rightLine); Point botLeft = bottomLine.intersection(leftLine); corners.push_back(topLeft); corners.push_back(topRight); corners.push_back(botRight); corners.push_back(botLeft); } else { int expandX = (int) ((float) pipeline_data->crop_gray.cols) * 0.15f; int expandY = (int) ((float) pipeline_data->crop_gray.rows) * 0.15f; int w = pipeline_data->crop_gray.cols; int h = pipeline_data->crop_gray.rows; corners.push_back(Point(-1 * expandX, -1 * expandY)); corners.push_back(Point(expandX + w, -1 * expandY)); corners.push_back(Point(expandX + w, expandY + h)); corners.push_back(Point(-1 * expandX, expandY + h)); // for (int i = 0; i < 4; i++) // { // std::cout << "CORNER: " << corners[i].x << " - " << corners[i].y << std::endl; // } } // Re-crop an image (from the original image) using the new coordinates Transformation imgTransform(pipeline_data->grayImg, pipeline_data->crop_gray, pipeline_data->regionOfInterest); vector<Point2f> remappedCorners = imgTransform.transformSmallPointsToBigImage(corners); Size cropSize = imgTransform.getCropSize(remappedCorners, Size(pipeline_data->config->templateWidthPx, pipeline_data->config->templateHeightPx)); Mat transmtx = imgTransform.getTransformationMatrix(remappedCorners, cropSize); Mat newCrop = imgTransform.crop(cropSize, transmtx); // Re-map the textline coordinates to the new crop vector<TextLine> newLines; for (unsigned int i = 0; i < pipeline_data->textLines.size(); i++) { vector<Point2f> textArea = imgTransform.transformSmallPointsToBigImage(pipeline_data->textLines[i].textArea); vector<Point2f> linePolygon = imgTransform.transformSmallPointsToBigImage(pipeline_data->textLines[i].linePolygon); vector<Point2f> textAreaRemapped; vector<Point2f> linePolygonRemapped; textAreaRemapped = imgTransform.remapSmallPointstoCrop(textArea, transmtx); linePolygonRemapped = imgTransform.remapSmallPointstoCrop(linePolygon, transmtx); newLines.push_back(TextLine(textAreaRemapped, linePolygonRemapped, newCrop.size())); } // Find the PlateLines for this crop PlateLines plateLines(pipeline_data); plateLines.processImage(newCrop, newLines, 1.05); // Get the best corners PlateCorners cornerFinder(newCrop, &plateLines, pipeline_data, newLines); vector<Point> smallPlateCorners = cornerFinder.findPlateCorners(); // Transform the best corner points back to the original image std::vector<Point2f> imgArea; imgArea.push_back(Point2f(0, 0)); imgArea.push_back(Point2f(newCrop.cols, 0)); imgArea.push_back(Point2f(newCrop.cols, newCrop.rows)); imgArea.push_back(Point2f(0, newCrop.rows)); Mat newCropTransmtx = imgTransform.getTransformationMatrix(imgArea, remappedCorners); vector<Point2f> cornersInOriginalImg = imgTransform.remapSmallPointstoCrop(smallPlateCorners, newCropTransmtx); return cornersInOriginalImg; }
/* NOTE: this is called findSegmentIndexToSnap in JTS */ CoordinateList::iterator LineStringSnapper::findSegmentToSnap( const Coordinate& snapPt, CoordinateList::iterator from, CoordinateList::iterator too_far) { LineSegment seg; double minDist = snapTolerance; // make sure the first closer then // snapTolerance is accepted CoordinateList::iterator match = too_far; // TODO: use std::find_if for(; from != too_far; ++from) { seg.p0 = *from; CoordinateList::iterator to = from; ++to; seg.p1 = *to; #if GEOS_DEBUG cerr << " Checking segment " << seg << endl; #endif /** * Check if the snap pt is equal to one of * the segment endpoints. * * If the snap pt is already in the src list, * don't snap at all (unless allowSnappingToSourceVertices * is set to true) */ if(seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt)) { if(allowSnappingToSourceVertices) { #if GEOS_DEBUG cerr << " snap point matches a segment endpoint, checking next segment" << endl; #endif continue; } else { #if GEOS_DEBUG cerr << " snap point matches a segment endpoint, giving up seek" << endl; #endif return too_far; } } double dist = seg.distance(snapPt); if(dist >= minDist) { #if GEOS_DEBUG cerr << " snap point distance " << dist << " not smaller than tolerance " << snapTolerance << " or previous closest " << minDist << endl; #endif continue; } #if GEOS_DEBUG cerr << " snap point distance " << dist << " within tolerance " << snapTolerance << " and closer than previous candidate " << minDist << endl; #endif if(dist == 0.0) { return from; // can't find any closer } match = from; minDist = dist; } return match; }
float3 Ray::ClosestPoint(const LineSegment &other, float *d, float *d2) const { float u, u2; float3 closestPoint = Line::ClosestPointLineLine(pos, pos + dir, other.a, other.b, &u, &u2); if (u < 0.f) { if (u2 >= 0.f && u2 <= 1.f) { if (d) *d = 0.f; if (d2) other.ClosestPoint(pos, d2); return pos; } float3 p; float t2; if (u2 < 0.f) { p = other.a; t2 = 0.f; } else // u2 > 1.f { p = other.b; t2 = 1.f; } closestPoint = ClosestPoint(p, &u); float3 closestPoint2 = other.ClosestPoint(pos, &u2); if (closestPoint.DistanceSq(p) <= closestPoint2.DistanceSq(pos)) { if (d) *d = u; if (d2) *d2 = t2; return closestPoint; } else { if (d) *d = 0.f; if (d2) *d2 = u2; return pos; } } else if (u2 < 0.f) { closestPoint = ClosestPoint(other.a, d); if (d2) *d2 = 0.f; return closestPoint; } else if (u2 > 1.f) { closestPoint = ClosestPoint(other.b, d); if (d2) *d2 = 1.f; return closestPoint; } else { if (d) *d = u; if (d2) *d2 = u2; return closestPoint; } }
Option<Vec2> Intersection::get(const LineSegment& a, const LineSegment& b) { auto Intersection = get(a.containingLine(), b.containingLine()); if (!Intersection) return nullptr; if (aeq(Intersection.value(), a.pointA())) Intersection = a.pointA(); if (aeq(Intersection.value(), a.pointB())) Intersection = a.pointB(); if (aeq(Intersection.value(), b.pointA())) Intersection = b.pointA(); if (aeq(Intersection.value(), b.pointB())) Intersection = b.pointB(); auto dirA = a.pointB() - a.pointA(); const auto dirALen = dirA.length(); dirA /= dirALen; auto dirB = b.pointB() - b.pointA(); const auto dirBLen = dirB.length(); dirB /= dirBLen; const auto t = dot(Intersection.value() - a.pointA(), dirA); const auto u = dot(Intersection.value() - b.pointA(), dirB); if (t >= 0 && u >= 0 && t <= dirALen && u <= dirBLen) return Intersection; else return nullptr; }
bool Intersection::test(const LineSegment& a, const Vec2& b) { return a.containsPoint(b, true); }
inline double getUpdateCoef(double coef, LineSegment line) { return getUpdateCoef(coef, line.GetClosestPointOnLineSegment(cv::Point2d(0, 0))) * line.getProbability(); }
inline double length(const LineSegment& s) { return (s.p2()-s.p1()).norm(); }
inline double squared_length(const LineSegment& s) { return (s.p2()-s.p1()).squaredNorm(); }
inline Vector2d dir(const LineSegment& s) { return s.p2() - s.p1(); }
Line::Line(const LineSegment &lineSegment) :pos(lineSegment.a), dir(lineSegment.Dir()) { }