diff --git a/src/openalpr/licenseplatecandidate.cpp b/src/openalpr/licenseplatecandidate.cpp index 4406718..0c04cc5 100644 --- a/src/openalpr/licenseplatecandidate.cpp +++ b/src/openalpr/licenseplatecandidate.cpp @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#include + #include "licenseplatecandidate.h" using namespace std; @@ -67,14 +69,49 @@ void LicensePlateCandidate::recognize() if (cornerFinder.confidence > 0) { + cout << "Transforming" << endl; + + + Mat originalCrop = pipeline_data->crop_gray; + pipeline_data->plate_corners = transformPointsToOriginalImage(this->pipeline_data->grayImg, pipeline_data->crop_gray, expandedRegion, smallPlateCorners); - pipeline_data->crop_gray = deSkewPlate(this->pipeline_data->grayImg, pipeline_data->plate_corners); + Size outputImageSize = getOutputImageSize(pipeline_data->plate_corners); + Mat transmtx = getTransformationMatrix(pipeline_data->plate_corners, outputImageSize); + pipeline_data->crop_gray = deSkewPlate(this->pipeline_data->grayImg, outputImageSize, transmtx); + cout << "Size: " << outputImageSize.width << " - " << outputImageSize.height << endl; + + + // Apply a perspective transformation to the TextLine objects + // to match the newly deskewed license plate crop + vector newLines; + for (uint i = 0; i < pipeline_data->textLines.size(); i++) + { + vector textArea = transformPointsToOriginalImage(this->pipeline_data->grayImg, originalCrop, expandedRegion, + pipeline_data->textLines[i].textArea); + vector linePolygon = transformPointsToOriginalImage(this->pipeline_data->grayImg, originalCrop, expandedRegion, + pipeline_data->textLines[i].linePolygon); + + vector textAreaRemapped; + vector linePolygonRemapped; + + perspectiveTransform(textArea, textAreaRemapped, transmtx); + perspectiveTransform(linePolygon, linePolygonRemapped, transmtx); + + newLines.push_back(TextLine(textAreaRemapped, linePolygonRemapped)); + } + + pipeline_data->textLines.clear(); + for (uint i = 0; i < newLines.size(); i++) + pipeline_data->textLines.push_back(newLines[i]); + + + Mat debugImg = pipeline_data->textLines[0].drawDebugImage(pipeline_data->crop_gray); + drawAndWait(&debugImg); + charSegmenter = new CharacterSegmenter(pipeline_data); - //this->recognizedText = ocr->recognizedText; - //strcpy(this->recognizedText, ocr.recognizedText); pipeline_data->plate_area_confidence = 100; } @@ -100,13 +137,9 @@ vector LicensePlateCandidate::transformPointsToOriginalImage(Mat bigIma return cornerPoints; } -Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) +Size LicensePlateCandidate::getOutputImageSize(vector corners) { - - timespec startTime; - getTime(&startTime); - - // Figure out the appoximate width/height of the license plate region, so we can maintain the aspect ratio. + // Figure out the approximate width/height of the license plate region, so we can maintain the aspect ratio. LineSegment leftEdge(round(corners[3].x), round(corners[3].y), round(corners[0].x), round(corners[0].y)); LineSegment rightEdge(round(corners[2].x), round(corners[2].y), round(corners[1].x), round(corners[1].y)); LineSegment topEdge(round(corners[0].x), round(corners[0].y), round(corners[1].x), round(corners[1].y)); @@ -115,7 +148,6 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) float w = distanceBetweenPoints(leftEdge.midpoint(), rightEdge.midpoint()); float h = distanceBetweenPoints(bottomEdge.midpoint(), topEdge.midpoint()); float aspect = w/h; - int width = config->ocrImageWidthPx; int height = round(((float) width) / aspect); if (height > config->ocrImageHeightPx) @@ -123,22 +155,37 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) height = config->ocrImageHeightPx; width = round(((float) height) * aspect); } + + return Size(width, height); +} - Mat deskewed(height, width, this->pipeline_data->grayImg.type()); - +Mat LicensePlateCandidate::getTransformationMatrix(vector corners, Size outputImageSize) +{ // Corners of the destination image vector quad_pts; quad_pts.push_back(Point2f(0, 0)); - quad_pts.push_back(Point2f(deskewed.cols, 0)); - quad_pts.push_back(Point2f(deskewed.cols, deskewed.rows)); - quad_pts.push_back(Point2f(0, deskewed.rows)); + quad_pts.push_back(Point2f(outputImageSize.width, 0)); + quad_pts.push_back(Point2f(outputImageSize.width, outputImageSize.height)); + quad_pts.push_back(Point2f(0, outputImageSize.height)); // Get transformation matrix Mat transmtx = getPerspectiveTransform(corners, quad_pts); - // Apply perspective transformation - warpPerspective(inputImage, deskewed, transmtx, deskewed.size(), INTER_CUBIC); + return transmtx; +} +Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, Size outputImageSize, Mat transformationMatrix) +{ + + timespec startTime; + getTime(&startTime); + + Mat deskewed(outputImageSize, this->pipeline_data->grayImg.type()); + + // Apply perspective transformation to the image + warpPerspective(inputImage, deskewed, transformationMatrix, deskewed.size(), INTER_CUBIC); + + if (config->debugTiming) { timespec endTime; @@ -152,3 +199,8 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) return deskewed; } +//void LicensePlateCandidate::remapTextArea(cv::Mat inputImage, std::vector corners) { +// +//} + + diff --git a/src/openalpr/licenseplatecandidate.h b/src/openalpr/licenseplatecandidate.h index 2ec48ea..63534f5 100644 --- a/src/openalpr/licenseplatecandidate.h +++ b/src/openalpr/licenseplatecandidate.h @@ -59,9 +59,11 @@ class LicensePlateCandidate cv::Mat filterByCharacterHue(std::vector > charRegionContours); std::vector findPlateCorners(cv::Mat inputImage, PlateLines plateLines, CharacterRegion charRegion); // top-left, top-right, bottom-right, bottom-left + cv::Size getOutputImageSize(std::vector corners); std::vector transformPointsToOriginalImage(cv::Mat bigImage, cv::Mat smallImage, cv::Rect region, std::vector corners); - cv::Mat deSkewPlate(cv::Mat inputImage, std::vector corners); - + cv::Mat getTransformationMatrix(std::vector corners, cv::Size outputImageSize); + cv::Mat deSkewPlate(cv::Mat inputImage, cv::Size outputImageSize, cv::Mat transformationMatrix); + }; #endif // OPENALPR_LICENSEPLATECANDIDATE_H diff --git a/src/openalpr/textdetection/textline.cpp b/src/openalpr/textdetection/textline.cpp index 90baafb..46405e4 100644 --- a/src/openalpr/textdetection/textline.cpp +++ b/src/openalpr/textdetection/textline.cpp @@ -24,9 +24,35 @@ using namespace cv; +TextLine::TextLine(std::vector textArea, std::vector linePolygon) { + std::vector textAreaInts, linePolygonInts; + + for (uint i = 0; i < textArea.size(); i++) + textAreaInts.push_back(Point(round(textArea[i].x), round(textArea[i].y))); + for (uint i = 0; i < linePolygon.size(); i++) + linePolygonInts.push_back(Point(round(linePolygon[i].x), round(linePolygon[i].y))); + + initialize(textAreaInts, linePolygonInts); +} + TextLine::TextLine(std::vector textArea, std::vector linePolygon) { + initialize(textArea, linePolygon); +} + + +TextLine::~TextLine() { +} + + + +void TextLine::initialize(std::vector textArea, std::vector linePolygon) { if (textArea.size() > 0) { + if (this->textArea.size() > 0) + this->textArea.clear(); + if (this->linePolygon.size() > 0) + this->linePolygon.clear(); + for (uint i = 0; i < textArea.size(); i++) this->textArea.push_back(textArea[i]); @@ -53,9 +79,6 @@ TextLine::TextLine(std::vector textArea, std::vector lineP } -TextLine::~TextLine() { -} - cv::Mat TextLine::drawDebugImage(cv::Mat baseImage) { cv::Mat debugImage(baseImage.size(), baseImage.type()); diff --git a/src/openalpr/textdetection/textline.h b/src/openalpr/textdetection/textline.h index bc0b6f6..ec9e6d5 100644 --- a/src/openalpr/textdetection/textline.h +++ b/src/openalpr/textdetection/textline.h @@ -27,8 +27,10 @@ class TextLine { public: TextLine(std::vector textArea, std::vector linePolygon); + TextLine(std::vector textArea, std::vector linePolygon); virtual ~TextLine(); + std::vector linePolygon; std::vector textArea; LineSegment topLine; @@ -45,6 +47,7 @@ public: cv::Mat drawDebugImage(cv::Mat baseImage); private: + void initialize(std::vector textArea, std::vector linePolygon); }; #endif /* OPENALPR_TEXTLINE_H */