From c156e8900e1bf89c02637d67cf2cc48ba0b206be Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Fri, 10 Oct 2014 20:21:41 -0400 Subject: [PATCH] Refactored characteranalysis. Using TextLine class to hold character info. Needed for multiline char support --- src/openalpr/CMakeLists.txt | 1 + src/openalpr/characterregion.cpp | 40 +------------- src/openalpr/characterregion.h | 15 ----- src/openalpr/licenseplatecandidate.cpp | 8 +-- src/openalpr/pipeline_data.h | 2 + src/openalpr/platecorners.cpp | 55 +++++++++---------- src/openalpr/platecorners.h | 5 +- src/openalpr/platelines.cpp | 31 +++++++---- src/openalpr/platelines.h | 6 +- .../textdetection/characteranalysis.cpp | 28 +++++----- .../textdetection/characteranalysis.h | 13 ++--- src/openalpr/textdetection/textcontours.cpp | 24 ++++++-- src/openalpr/textdetection/textcontours.h | 22 ++++++-- src/openalpr/textdetection/textline.cpp | 28 ++++++++++ src/openalpr/textdetection/textline.h | 45 +++++++++++++++ 15 files changed, 188 insertions(+), 135 deletions(-) create mode 100644 src/openalpr/textdetection/textline.cpp create mode 100644 src/openalpr/textdetection/textline.h diff --git a/src/openalpr/CMakeLists.txt b/src/openalpr/CMakeLists.txt index 659916c..04fc165 100644 --- a/src/openalpr/CMakeLists.txt +++ b/src/openalpr/CMakeLists.txt @@ -26,6 +26,7 @@ set(lpr_source_files textdetection/characteranalysis2l.cpp textdetection/platemask.cpp textdetection/textcontours.cpp + textdetection/textline.cpp pipeline_data.cpp trex.c cjson.c diff --git a/src/openalpr/characterregion.cpp b/src/openalpr/characterregion.cpp index ce47747..e698bdf 100644 --- a/src/openalpr/characterregion.cpp +++ b/src/openalpr/characterregion.cpp @@ -75,8 +75,9 @@ CharacterRegion::CharacterRegion(PipelineData* pipeline_data) confidenceDrainers += 91; else if (charSegmentCount < 5) confidenceDrainers += (5 - charSegmentCount) * 10; - - int absangle = abs(charAnalysis->topLine.angle); + + // 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) @@ -102,38 +103,3 @@ CharacterRegion::~CharacterRegion() } -LineSegment CharacterRegion::getTopLine() -{ - return charAnalysis->topLine; -} - -LineSegment CharacterRegion::getBottomLine() -{ - return charAnalysis->bottomLine; -} - -vector CharacterRegion::getCharArea() -{ - return charAnalysis->charArea; -} - -LineSegment CharacterRegion::getCharBoxTop() -{ - return charAnalysis->charBoxTop; -} - -LineSegment CharacterRegion::getCharBoxBottom() -{ - return charAnalysis->charBoxBottom; -} - -LineSegment CharacterRegion::getCharBoxLeft() -{ - return charAnalysis->charBoxLeft; -} - -LineSegment CharacterRegion::getCharBoxRight() -{ - return charAnalysis->charBoxRight; -} - diff --git a/src/openalpr/characterregion.h b/src/openalpr/characterregion.h index 94a1d90..8917d17 100644 --- a/src/openalpr/characterregion.h +++ b/src/openalpr/characterregion.h @@ -39,7 +39,6 @@ class CharacterRegion LineSegment getTopLine(); LineSegment getBottomLine(); - std::vector getCharArea(); LineSegment getCharBoxTop(); LineSegment getCharBoxBottom(); @@ -54,20 +53,6 @@ class CharacterRegion CharacterAnalysis *charAnalysis; cv::Mat findOuterBoxMask(std::vector thresholds, std::vector > > allContours, std::vector > allHierarchy); - std::vector filter(cv::Mat img, std::vector > contours, std::vector hierarchy); - std::vector filterByBoxSize(cv::Mat img, std::vector > contours, std::vector goodIndices, float minHeightPx, float maxHeightPx); - std::vector filterByParentContour( std::vector< std::vector > contours, std::vector hierarchy, std::vector goodIndices); - std::vector filterContourHoles(std::vector > contours, std::vector hierarchy, std::vector goodIndices); - - std::vector getBestVotedLines(cv::Mat img, std::vector > contours, std::vector goodIndices); - //vector getCharSegmentsBetweenLines(Mat img, vector > contours, vector outerPolygon); - std::vector filterBetweenLines(cv::Mat img, std::vector > contours, std::vector hierarchy, std::vector outerPolygon, std::vector goodIndices); - cv::Mat getCharacterMask(cv::Mat img, std::vector > contours, std::vector hierarchy, std::vector goodIndices); - - std::vector wrapContours(std::vector > contours); - bool verifySize(cv::Mat r, float minHeightPx, float maxHeightPx); - - int getGoodIndicesCount(std::vector goodIndices); bool isPlateInverted(cv::Mat threshold, std::vector > contours, std::vector hierarchy, std::vector goodIndices); diff --git a/src/openalpr/licenseplatecandidate.cpp b/src/openalpr/licenseplatecandidate.cpp index b89183a..f21b87a 100644 --- a/src/openalpr/licenseplatecandidate.cpp +++ b/src/openalpr/licenseplatecandidate.cpp @@ -54,14 +54,14 @@ void LicensePlateCandidate::recognize() if (charRegion.confidence > 10) { - PlateLines plateLines(config); + PlateLines plateLines(pipeline_data); if (pipeline_data->hasPlateBorder) - plateLines.processImage(pipeline_data->plateBorderMask, &charRegion, 1.10); + plateLines.processImage(pipeline_data->plateBorderMask, 1.10); - plateLines.processImage(pipeline_data->crop_gray, &charRegion, 0.9); + plateLines.processImage(pipeline_data->crop_gray, 0.9); - PlateCorners cornerFinder(pipeline_data->crop_gray, &plateLines, &charRegion, config); + PlateCorners cornerFinder(pipeline_data->crop_gray, &plateLines, pipeline_data); vector smallPlateCorners = cornerFinder.findPlateCorners(); if (cornerFinder.confidence > 0) diff --git a/src/openalpr/pipeline_data.h b/src/openalpr/pipeline_data.h index 14cd045..e92302e 100644 --- a/src/openalpr/pipeline_data.h +++ b/src/openalpr/pipeline_data.h @@ -5,6 +5,7 @@ #include "opencv2/imgproc/imgproc.hpp" #include "utility.h" #include "config.h" +#include "textdetection/textline.h" class PipelineData { @@ -26,6 +27,7 @@ class PipelineData bool hasPlateBorder; cv::Mat plateBorderMask; + std::vector textLines; std::vector thresholds; diff --git a/src/openalpr/platecorners.cpp b/src/openalpr/platecorners.cpp index 94b78f5..d4e1d0c 100644 --- a/src/openalpr/platecorners.cpp +++ b/src/openalpr/platecorners.cpp @@ -22,26 +22,25 @@ using namespace cv; using namespace std; -PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config) +PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, PipelineData* pipelineData) { - this->config = config; + this->pipelineData = pipelineData; - if (this->config->debugPlateCorners) + if (pipelineData->config->debugPlateCorners) cout << "PlateCorners constructor" << endl; this->inputImage = inputImage; this->plateLines = plateLines; - this->charRegion = charRegion; this->bestHorizontalScore = 9999999999999; this->bestVerticalScore = 9999999999999; - Point topPoint = charRegion->getTopLine().midpoint(); - Point bottomPoint = charRegion->getBottomLine().closestPointOnSegmentTo(topPoint); + Point topPoint = pipelineData->textLines[0].topLine.midpoint(); + Point bottomPoint = pipelineData->textLines[0].bottomLine.closestPointOnSegmentTo(topPoint); this->charHeight = distanceBetweenPoints(topPoint, bottomPoint); - this->charAngle = angleBetweenPoints(charRegion->getCharArea()[0], charRegion->getCharArea()[1]); + this->charAngle = angleBetweenPoints(pipelineData->textLines[0].textArea[0], pipelineData->textLines[0].textArea[1]); } PlateCorners::~PlateCorners() @@ -50,7 +49,7 @@ PlateCorners::~PlateCorners() vector PlateCorners::findPlateCorners() { - if (this->config->debugPlateCorners) + if (pipelineData->config->debugPlateCorners) cout << "PlateCorners::findPlateCorners" << endl; timespec startTime; @@ -81,21 +80,21 @@ vector PlateCorners::findPlateCorners() } } - if (this->config->debugPlateCorners) + if (pipelineData->config->debugPlateCorners) { cout << "Drawing debug stuff..." << endl; Mat imgCorners = Mat(inputImage.size(), inputImage.type()); inputImage.copyTo(imgCorners); for (int i = 0; i < 4; i++) - circle(imgCorners, charRegion->getCharArea()[i], 2, Scalar(0, 0, 0)); + circle(imgCorners, pipelineData->textLines[0].textArea[i], 2, Scalar(0, 0, 0)); line(imgCorners, this->bestTop.p1, this->bestTop.p2, Scalar(255, 0, 0), 1, CV_AA); line(imgCorners, this->bestRight.p1, this->bestRight.p2, Scalar(0, 0, 255), 1, CV_AA); line(imgCorners, this->bestBottom.p1, this->bestBottom.p2, Scalar(0, 0, 255), 1, CV_AA); line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA); - displayImage(config, "Winning top/bottom Boundaries", imgCorners); + displayImage(pipelineData->config, "Winning top/bottom Boundaries", imgCorners); } // Check if a left/right edge has been established. @@ -112,7 +111,7 @@ vector PlateCorners::findPlateCorners() corners.push_back(bestBottom.intersection(bestRight)); corners.push_back(bestBottom.intersection(bestLeft)); - if (config->debugTiming) + if (pipelineData->config->debugTiming) { timespec endTime; getTime(&endTime); @@ -129,7 +128,7 @@ void PlateCorners::scoreVerticals(int v1, int v2) LineSegment left; LineSegment right; - float charHeightToPlateWidthRatio = config->plateWidthMM / config->charHeightMM; + float charHeightToPlateWidthRatio = pipelineData->config->plateWidthMM / pipelineData->config->charHeightMM; float idealPixelWidth = this->charHeight * (charHeightToPlateWidthRatio * 1.03); // Add 3% so we don't clip any characters float confidenceDiff = 0; @@ -138,8 +137,8 @@ void PlateCorners::scoreVerticals(int v1, int v2) if (v1 == NO_LINE && v2 == NO_LINE) { //return; - Point centerTop = charRegion->getCharBoxTop().midpoint(); - Point centerBottom = charRegion->getCharBoxBottom().midpoint(); + Point centerTop = pipelineData->textLines[0].charBoxTop.midpoint(); + Point centerBottom = pipelineData->textLines[0].charBoxBottom.midpoint(); LineSegment centerLine = LineSegment(centerBottom.x, centerBottom.y, centerTop.x, centerTop.y); left = centerLine.getParallelLine(idealPixelWidth / 2); @@ -174,11 +173,11 @@ void PlateCorners::scoreVerticals(int v1, int v2) score += missingSegmentPenalty; // Make sure this line is to the left of our license plate letters - if (left.isPointBelowLine(charRegion->getCharBoxLeft().midpoint()) == false) + if (left.isPointBelowLine(pipelineData->textLines[0].charBoxLeft.midpoint()) == false) return; // Make sure this line is to the right of our license plate letters - if (right.isPointBelowLine(charRegion->getCharBoxRight().midpoint())) + if (right.isPointBelowLine(pipelineData->textLines[0].charBoxRight.midpoint())) return; ///////////////////////////////////////////////////////////////////////// @@ -212,8 +211,8 @@ void PlateCorners::scoreVerticals(int v1, int v2) // 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()); + Point leftMidLinePoint = left.closestPointOnSegmentTo(pipelineData->textLines[0].charBoxLeft.midpoint()); + Point rightMidLinePoint = right.closestPointOnSegmentTo(pipelineData->textLines[0].charBoxRight.midpoint()); float plateDistance = abs(idealPixelWidth - distanceBetweenPoints(leftMidLinePoint, rightMidLinePoint)); @@ -223,7 +222,7 @@ void PlateCorners::scoreVerticals(int v1, int v2) { float scorecomponent; - if (this->config->debugPlateCorners) + if (pipelineData->config->debugPlateCorners) { cout << "xx xx Score: charHeight " << this->charHeight << endl; cout << "xx xx Score: idealwidth " << idealPixelWidth << endl; @@ -278,7 +277,7 @@ void PlateCorners::scoreHorizontals(int h1, int h2) LineSegment top; LineSegment bottom; - float charHeightToPlateHeightRatio = config->plateHeightMM / config->charHeightMM; + float charHeightToPlateHeightRatio = pipelineData->config->plateHeightMM / pipelineData->config->charHeightMM; float idealPixelHeight = this->charHeight * charHeightToPlateHeightRatio; float confidenceDiff = 0; @@ -287,8 +286,8 @@ void PlateCorners::scoreHorizontals(int h1, int h2) if (h1 == NO_LINE && h2 == NO_LINE) { // return; - Point centerLeft = charRegion->getCharBoxLeft().midpoint(); - Point centerRight = charRegion->getCharBoxRight().midpoint(); + Point centerLeft = pipelineData->textLines[0].charBoxLeft.midpoint(); + Point centerRight = pipelineData->textLines[0].charBoxRight.midpoint(); LineSegment centerLine = LineSegment(centerLeft.x, centerLeft.y, centerRight.x, centerRight.y); top = centerLine.getParallelLine(idealPixelHeight / 2); @@ -323,11 +322,11 @@ void PlateCorners::scoreHorizontals(int h1, int h2) score += missingSegmentPenalty; // Make sure this line is above our license plate letters - if (top.isPointBelowLine(charRegion->getCharBoxTop().midpoint()) == false) + if (top.isPointBelowLine(pipelineData->textLines[0].charBoxTop.midpoint()) == false) return; // Make sure this line is below our license plate letters - if (bottom.isPointBelowLine(charRegion->getCharBoxBottom().midpoint())) + if (bottom.isPointBelowLine(pipelineData->textLines[0].charBoxBottom.midpoint())) return; // We now have 4 possible lines. Let's put them to the test and score them... @@ -353,7 +352,7 @@ void PlateCorners::scoreHorizontals(int h1, int h2) // Get the height difference float heightRatio = charHeight / plateHeightPx; - float idealHeightRatio = (config->charHeightMM / config->plateHeightMM); + float idealHeightRatio = (pipelineData->config->charHeightMM / pipelineData->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 @@ -373,7 +372,7 @@ void PlateCorners::scoreHorizontals(int h1, int h2) // 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 charAreaMidPoint = pipelineData->textLines[0].charBoxLeft.midpoint(); Point topLineSpot = top.closestPointOnSegmentTo(charAreaMidPoint); Point botLineSpot = bottom.closestPointOnSegmentTo(charAreaMidPoint); @@ -406,7 +405,7 @@ void PlateCorners::scoreHorizontals(int h1, int h2) { float scorecomponent; - if (this->config->debugPlateCorners) + if (pipelineData->config->debugPlateCorners) { cout << "xx xx Score: charHeight " << this->charHeight << endl; cout << "xx xx Score: idealHeight " << idealPixelHeight << endl; diff --git a/src/openalpr/platecorners.h b/src/openalpr/platecorners.h index c965887..d6a91ac 100644 --- a/src/openalpr/platecorners.h +++ b/src/openalpr/platecorners.h @@ -47,7 +47,7 @@ class PlateCorners { public: - PlateCorners(cv::Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config); + PlateCorners(cv::Mat inputImage, PlateLines* plateLines, PipelineData* pipelineData); virtual ~PlateCorners(); std::vector findPlateCorners(); @@ -56,7 +56,7 @@ class PlateCorners private: - Config* config; + PipelineData* pipelineData; cv::Mat inputImage; float charHeight; float charAngle; @@ -69,7 +69,6 @@ class PlateCorners LineSegment bestRight; PlateLines* plateLines; - CharacterRegion* charRegion; void scoreHorizontals( int h1, int h2 ); void scoreVerticals( int v1, int v2 ); diff --git a/src/openalpr/platelines.cpp b/src/openalpr/platelines.cpp index e244ca6..1f76134 100644 --- a/src/openalpr/platelines.cpp +++ b/src/openalpr/platelines.cpp @@ -25,10 +25,11 @@ using namespace std; const float MIN_CONFIDENCE = 0.3; -PlateLines::PlateLines(Config* config) +PlateLines::PlateLines(PipelineData* pipelineData) { - this->config = config; - this->debug = config->debugPlateLines; + this->pipelineData = pipelineData; + + this->debug = pipelineData->config->debugPlateLines; if (debug) cout << "PlateLines constructor" << endl; @@ -38,7 +39,7 @@ PlateLines::~PlateLines() { } -void PlateLines::processImage(Mat inputImage, CharacterRegion* charRegion, float sensitivity) +void PlateLines::processImage(Mat inputImage, float sensitivity) { if (this->debug) cout << "PlateLines findLines" << endl; @@ -59,7 +60,6 @@ void PlateLines::processImage(Mat inputImage, CharacterRegion* charRegion, float adaptiveBilateralFilter(inputImage, smoothed, Size(3,3), 45, 45); - int morph_elem = 2; int morph_size = 2; Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); @@ -69,11 +69,18 @@ void PlateLines::processImage(Mat inputImage, CharacterRegion* charRegion, float Canny(smoothed, edges, 66, 133); // Create a mask that is dilated based on the detected characters - vector > polygons; - polygons.push_back(charRegion->getCharArea()); + Mat mask = Mat::zeros(inputImage.size(), CV_8U); - fillPoly(mask, polygons, Scalar(255,255,255)); + + for (uint i = 0; i < pipelineData->textLines.size(); i++) + { + vector > polygons; + polygons.push_back(pipelineData->textLines[i].textArea); + fillPoly(mask, polygons, Scalar(255,255,255)); + } + + dilate(mask, mask, getStructuringElement( 1, Size( 1 + 1, 2*1+1 ), Point( 1, 1 ) )); bitwise_not(mask, mask); @@ -114,10 +121,10 @@ void PlateLines::processImage(Mat inputImage, CharacterRegion* charRegion, float images.push_back(debugImgVert); Mat dashboard = drawImageDashboard(images, debugImgVert.type(), 1); - displayImage(config, "Hough Lines", dashboard); + displayImage(pipelineData->config, "Hough Lines", dashboard); } - if (config->debugTiming) + if (pipelineData->config->debugTiming) { timespec endTime; getTime(&endTime); @@ -134,8 +141,8 @@ vector PlateLines::getLines(Mat edges, float sensitivityMultiplier, b if (this->debug) cout << "PlateLines::getLines" << endl; - static int HORIZONTAL_SENSITIVITY = config->plateLinesSensitivityHorizontal; - static int VERTICAL_SENSITIVITY = config->plateLinesSensitivityVertical; + static int HORIZONTAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityHorizontal; + static int VERTICAL_SENSITIVITY = pipelineData->config->plateLinesSensitivityVertical; vector allLines; vector filteredLines; diff --git a/src/openalpr/platelines.h b/src/openalpr/platelines.h index 872a80e..40a9016 100644 --- a/src/openalpr/platelines.h +++ b/src/openalpr/platelines.h @@ -37,10 +37,10 @@ class PlateLines { public: - PlateLines(Config* config); + PlateLines(PipelineData* pipelineData); virtual ~PlateLines(); - void processImage(cv::Mat img, CharacterRegion* charRegion, float sensitivity=1.0); + void processImage(cv::Mat img, float sensitivity=1.0); std::vector horizontalLines; std::vector verticalLines; @@ -49,7 +49,7 @@ class PlateLines private: - Config* config; + PipelineData* pipelineData; bool debug; cv::Mat customGrayscaleConversion(cv::Mat src); diff --git a/src/openalpr/textdetection/characteranalysis.cpp b/src/openalpr/textdetection/characteranalysis.cpp index 426e477..46493dd 100644 --- a/src/openalpr/textdetection/characteranalysis.cpp +++ b/src/openalpr/textdetection/characteranalysis.cpp @@ -44,11 +44,13 @@ void CharacterAnalysis::analyze() pipeline_data->clearThresholds(); pipeline_data->thresholds = produceThresholds(pipeline_data->crop_gray, config); - + timespec startTime; getTime(&startTime); + TextLine textLine; + for (uint i = 0; i < pipeline_data->thresholds.size(); i++) { TextContours tc(pipeline_data->thresholds[i]); @@ -148,28 +150,28 @@ void CharacterAnalysis::analyze() 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(pipeline_data->crop_gray, bestContours); 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); + textLine.topLine = LineSegment(this->linePolygon[0].x, this->linePolygon[0].y, this->linePolygon[1].x, this->linePolygon[1].y); + textLine.bottomLine = LineSegment(this->linePolygon[3].x, this->linePolygon[3].y, this->linePolygon[2].x, this->linePolygon[2].y); + filterBetweenLines(bestThreshold, bestContours, linePolygon); - this->charArea = getCharArea(); + textLine.textArea = getCharArea(textLine.topLine, textLine.bottomLine); - if (this->charArea.size() > 0) + if (textLine.textArea.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); + textLine.charBoxTop = LineSegment(textLine.textArea[0].x, textLine.textArea[0].y, textLine.textArea[1].x, textLine.textArea[1].y); + textLine.charBoxBottom = LineSegment(textLine.textArea[3].x, textLine.textArea[3].y, textLine.textArea[2].x, textLine.textArea[2].y); + textLine.charBoxLeft = LineSegment(textLine.textArea[3].x, textLine.textArea[3].y, textLine.textArea[0].x, textLine.textArea[0].y); + textLine.charBoxRight = LineSegment(textLine.textArea[2].x, textLine.textArea[2].y, textLine.textArea[1].x, textLine.textArea[1].y); } } + pipeline_data->textLines.push_back(textLine); + this->thresholdsInverted = isPlateInverted(); } @@ -733,7 +735,7 @@ bool CharacterAnalysis::verifySize(Mat r, float minHeightPx, float maxHeightPx) return false; } -vector CharacterAnalysis::getCharArea() +vector CharacterAnalysis::getCharArea(LineSegment topLine, LineSegment bottomLine) { const int MAX = 100000; const int MIN= -1; diff --git a/src/openalpr/textdetection/characteranalysis.h b/src/openalpr/textdetection/characteranalysis.h index 94c0516..52bbe36 100644 --- a/src/openalpr/textdetection/characteranalysis.h +++ b/src/openalpr/textdetection/characteranalysis.h @@ -43,15 +43,10 @@ class CharacterAnalysis //std::vector bestCharSegments; //int bestCharSegmentsCount; - LineSegment topLine; - LineSegment bottomLine; - std::vector linePolygon; - std::vector charArea; - LineSegment charBoxTop; - LineSegment charBoxBottom; - LineSegment charBoxLeft; - LineSegment charBoxRight; + std::vector linePolygon; + + bool thresholdsInverted; bool isTwoLine; @@ -79,7 +74,7 @@ class CharacterAnalysis void filterContourHoles(TextContours& textContours); void filterByOuterMask(TextContours& textContours); - std::vector getCharArea(); + std::vector getCharArea(LineSegment topLine, LineSegment bottomLine); std::vector getBestVotedLines(cv::Mat img, TextContours textContours); void filterBetweenLines(cv::Mat img, TextContours& textContours, std::vector outerPolygon ); diff --git a/src/openalpr/textdetection/textcontours.cpp b/src/openalpr/textdetection/textcontours.cpp index ed53fbd..01a2272 100644 --- a/src/openalpr/textdetection/textcontours.cpp +++ b/src/openalpr/textdetection/textcontours.cpp @@ -1,9 +1,21 @@ -/* - * File: textcontours.cpp - * Author: mhill - * - * Created on October 9, 2014, 7:40 PM - */ +/* + * Copyright (c) 2014 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] + * + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ #include "textcontours.h" diff --git a/src/openalpr/textdetection/textcontours.h b/src/openalpr/textdetection/textcontours.h index bc38067..428a767 100644 --- a/src/openalpr/textdetection/textcontours.h +++ b/src/openalpr/textdetection/textcontours.h @@ -1,9 +1,21 @@ -/* - * File: textcontours.h - * Author: mhill +/* + * Copyright (c) 2014 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] * - * Created on October 9, 2014, 7:40 PM - */ + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ #ifndef TEXTCONTOURS_H #define TEXTCONTOURS_H diff --git a/src/openalpr/textdetection/textline.cpp b/src/openalpr/textdetection/textline.cpp new file mode 100644 index 0000000..ccd3b2a --- /dev/null +++ b/src/openalpr/textdetection/textline.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] + * + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ + + +#include "textline.h" + +TextLine::TextLine() { +} + + +TextLine::~TextLine() { +} diff --git a/src/openalpr/textdetection/textline.h b/src/openalpr/textdetection/textline.h new file mode 100644 index 0000000..6172c01 --- /dev/null +++ b/src/openalpr/textdetection/textline.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] + * + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ + + +#ifndef OPENALPR_TEXTLINE_H +#define OPENALPR_TEXTLINE_H + +#include "utility.h" + +class TextLine { +public: + TextLine(); + virtual ~TextLine(); + + std::vector textArea; + LineSegment topLine; + LineSegment bottomLine; + + LineSegment charBoxTop; + LineSegment charBoxBottom; + LineSegment charBoxLeft; + LineSegment charBoxRight; + +private: + +}; + +#endif /* OPENALPR_TEXTLINE_H */ +