diff --git a/src/openalpr/CMakeLists.txt b/src/openalpr/CMakeLists.txt index 67adfa9..52beebf 100644 --- a/src/openalpr/CMakeLists.txt +++ b/src/openalpr/CMakeLists.txt @@ -22,6 +22,7 @@ set(lpr_source_files edges/platelines.cpp edges/textlinecollection.cpp colorfilter.cpp + transformation.cpp textdetection/characteranalysis.cpp textdetection/platemask.cpp textdetection/textcontours.cpp diff --git a/src/openalpr/licenseplatecandidate.cpp b/src/openalpr/licenseplatecandidate.cpp index c7fda6b..e388ed8 100644 --- a/src/openalpr/licenseplatecandidate.cpp +++ b/src/openalpr/licenseplatecandidate.cpp @@ -20,6 +20,8 @@ #include #include "licenseplatecandidate.h" +#include "edges/edgefinder.h" +#include "transformation.h" using namespace std; using namespace cv; @@ -65,6 +67,8 @@ void LicensePlateCandidate::recognize() PlateCorners cornerFinder(pipeline_data->crop_gray, &plateLines, pipeline_data); vector smallPlateCorners = cornerFinder.findPlateCorners(); + EdgeFinder edgeFinder(pipeline_data); + if (cornerFinder.confidence > 0) { @@ -74,11 +78,16 @@ void LicensePlateCandidate::recognize() Mat originalCrop = pipeline_data->crop_gray; - pipeline_data->plate_corners = transformPointsToOriginalImage(this->pipeline_data->grayImg, pipeline_data->crop_gray, expandedRegion, smallPlateCorners); + Transformation imgTransform(this->pipeline_data->grayImg, pipeline_data->crop_gray, expandedRegion); + pipeline_data->plate_corners = imgTransform.transformSmallPointsToBigImage(smallPlateCorners); + + Size cropSize = getCropSize(pipeline_data->plate_corners); + Mat transmtx = imgTransform.getTransformationMatrix(pipeline_data->plate_corners, cropSize); + pipeline_data->crop_gray = imgTransform.crop(cropSize, transmtx); + - 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); + if (this->config->debugGeneral) + displayImage(config, "quadrilateral", pipeline_data->crop_gray); @@ -87,16 +96,14 @@ void LicensePlateCandidate::recognize() 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 textArea = imgTransform.transformSmallPointsToBigImage(pipeline_data->textLines[i].textArea); + vector linePolygon = imgTransform.transformSmallPointsToBigImage(pipeline_data->textLines[i].linePolygon); vector textAreaRemapped; vector linePolygonRemapped; - perspectiveTransform(textArea, textAreaRemapped, transmtx); - perspectiveTransform(linePolygon, linePolygonRemapped, transmtx); + textAreaRemapped = imgTransform.remapSmallPointstoCrop(textArea, transmtx); + linePolygonRemapped = imgTransform.remapSmallPointstoCrop(linePolygon, transmtx); newLines.push_back(TextLine(textAreaRemapped, linePolygonRemapped)); } @@ -123,31 +130,13 @@ void LicensePlateCandidate::recognize() } } -// Re-maps the coordinates from the smallImage to the coordinate space of the bigImage. -vector LicensePlateCandidate::transformPointsToOriginalImage(Mat bigImage, Mat smallImage, Rect region, vector corners) -{ - vector cornerPoints; - for (uint i = 0; i < corners.size(); i++) - { - float bigX = (corners[i].x * ((float) region.width / smallImage.cols)); - float bigY = (corners[i].y * ((float) region.height / smallImage.rows)); - - bigX = bigX + region.x; - bigY = bigY + region.y; - - cornerPoints.push_back(Point2f(bigX, bigY)); - } - - return cornerPoints; -} - -Size LicensePlateCandidate::getOutputImageSize(vector corners) +Size LicensePlateCandidate::getCropSize(vector areaCorners) { // 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)); - LineSegment bottomEdge(round(corners[3].x), round(corners[3].y), round(corners[2].x), round(corners[2].y)); + LineSegment leftEdge(round(areaCorners[3].x), round(areaCorners[3].y), round(areaCorners[0].x), round(areaCorners[0].y)); + LineSegment rightEdge(round(areaCorners[2].x), round(areaCorners[2].y), round(areaCorners[1].x), round(areaCorners[1].y)); + LineSegment topEdge(round(areaCorners[0].x), round(areaCorners[0].y), round(areaCorners[1].x), round(areaCorners[1].y)); + LineSegment bottomEdge(round(areaCorners[3].x), round(areaCorners[3].y), round(areaCorners[2].x), round(areaCorners[2].y)); float w = distanceBetweenPoints(leftEdge.midpoint(), rightEdge.midpoint()); float h = distanceBetweenPoints(bottomEdge.midpoint(), topEdge.midpoint()); @@ -163,37 +152,3 @@ Size LicensePlateCandidate::getOutputImageSize(vector corners) return Size(width, height); } -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(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); - - return transmtx; -} - -Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, Size outputImageSize, Mat transformationMatrix) -{ - - - Mat deskewed(outputImageSize, this->pipeline_data->grayImg.type()); - - // Apply perspective transformation to the image - warpPerspective(inputImage, deskewed, transformationMatrix, deskewed.size(), INTER_CUBIC); - - - - if (this->config->debugGeneral) - displayImage(config, "quadrilateral", deskewed); - - return deskewed; -} - - - diff --git a/src/openalpr/licenseplatecandidate.h b/src/openalpr/licenseplatecandidate.h index 72951ab..3093006 100644 --- a/src/openalpr/licenseplatecandidate.h +++ b/src/openalpr/licenseplatecandidate.h @@ -30,6 +30,7 @@ #include "utility.h" #include "constants.h" #include "edges/platelines.h" +#include "transformation.h" #include "textdetection/characteranalysis.h" #include "segmentation/charactersegmenter.h" #include "edges/platecorners.h" @@ -59,10 +60,7 @@ class LicensePlateCandidate cv::Mat filterByCharacterHue(std::vector > charRegionContours); std::vector findPlateCorners(cv::Mat inputImage, PlateLines plateLines, CharacterAnalysis textAnalysis); // 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 getTransformationMatrix(std::vector corners, cv::Size outputImageSize); - cv::Mat deSkewPlate(cv::Mat inputImage, cv::Size outputImageSize, cv::Mat transformationMatrix); + cv::Size getCropSize(std::vector areaCorners); }; diff --git a/src/openalpr/transformation.cpp b/src/openalpr/transformation.cpp new file mode 100644 index 0000000..ce9afbb --- /dev/null +++ b/src/openalpr/transformation.cpp @@ -0,0 +1,91 @@ +/* + * 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 "transformation.h" + +using namespace std; +using namespace cv; + +Transformation::Transformation(Mat bigImage, Mat smallImage, Rect regionInBigImage) { + this->bigImage = bigImage; + this->smallImage = smallImage; + this->regionInBigImage = regionInBigImage; +} + + +Transformation::~Transformation() { +} + +// Re-maps the coordinates from the smallImage to the coordinate space of the bigImage. +vector Transformation::transformSmallPointsToBigImage(vector points) +{ + vector bigPoints; + for (uint i = 0; i < points.size(); i++) + { + float bigX = (points[i].x * ((float) regionInBigImage.width / smallImage.cols)); + float bigY = (points[i].y * ((float) regionInBigImage.height / smallImage.rows)); + + bigX = bigX + regionInBigImage.x; + bigY = bigY + regionInBigImage.y; + + bigPoints.push_back(Point2f(bigX, bigY)); + } + + return bigPoints; +} + + +Mat Transformation::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(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); + + return transmtx; +} + +Mat Transformation::crop(Size outputImageSize, Mat transformationMatrix) +{ + + + Mat deskewed(outputImageSize, this->bigImage.type()); + + // Apply perspective transformation to the image + warpPerspective(this->bigImage, deskewed, transformationMatrix, deskewed.size(), INTER_CUBIC); + + + + + return deskewed; +} + +vector Transformation::remapSmallPointstoCrop(vector smallPoints, cv::Mat transformationMatrix) +{ + vector remappedPoints; + perspectiveTransform(smallPoints, remappedPoints, transformationMatrix); + + return remappedPoints; +} + diff --git a/src/openalpr/transformation.h b/src/openalpr/transformation.h new file mode 100644 index 0000000..528f87a --- /dev/null +++ b/src/openalpr/transformation.h @@ -0,0 +1,46 @@ +/* + * 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_TRANSFORMATION_H +#define OPENALPR_TRANSFORMATION_H + +#include "opencv2/imgproc/imgproc.hpp" + +class Transformation { +public: + Transformation(cv::Mat bigImage, cv::Mat smallImage, cv::Rect regionInBigImage); + virtual ~Transformation(); + + std::vector transformSmallPointsToBigImage(std::vector points); + + cv::Mat getTransformationMatrix(std::vector corners, cv::Size outputImageSize); + + cv::Mat crop(cv::Size outputImageSize, cv::Mat transformationMatrix); + std::vector remapSmallPointstoCrop(std::vector smallPoints, cv::Mat transformationMatrix); + + +private: + cv::Mat bigImage; + cv::Mat smallImage; + cv::Rect regionInBigImage; + +}; + +#endif /* OPENALPR_TRANSFORMATION_H */ +