From 4b6d2cc6ec7e6107b1860f88d43b1f7495c81967 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Mon, 1 Jun 2015 22:26:49 -0400 Subject: [PATCH] Added character bounding box and confidence to API output --- src/openalpr/alpr.h | 25 ++++++--- src/openalpr/alpr_impl.cpp | 67 ++++++++++++++++++++++++ src/openalpr/alpr_impl.h | 1 + src/openalpr/postprocess/postprocess.cpp | 6 +++ src/openalpr/postprocess/postprocess.h | 1 + 5 files changed, 92 insertions(+), 8 deletions(-) diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h index 636cdaa..e0ac7f0 100644 --- a/src/openalpr/alpr.h +++ b/src/openalpr/alpr.h @@ -28,19 +28,28 @@ namespace alpr { - struct AlprPlate - { - std::string characters; - float overall_confidence; - - bool matches_template; - }; - struct AlprCoordinate { int x; int y; }; + + struct AlprChar + { + AlprCoordinate corners[4]; + float confidence; + std::string character; + }; + + struct AlprPlate + { + std::string characters; + float overall_confidence; + + std::vector character_details; + bool matches_template; + }; + class AlprRegionOfInterest { diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index 6750919..907534c 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -209,6 +209,19 @@ namespace alpr aplate.characters = ppResults[pp].letters; aplate.overall_confidence = ppResults[pp].totalscore; aplate.matches_template = ppResults[pp].matchesTemplate; + + // Grab detailed results for each character + for (unsigned int c_idx = 0; c_idx < ppResults[pp].letter_details.size(); c_idx++) + { + AlprChar character_details; + character_details.character = ppResults[pp].letter_details[c_idx].letter; + character_details.confidence = ppResults[pp].letter_details[c_idx].totalscore; + cv::Rect char_rect = pipeline_data.charRegions[ppResults[pp].letter_details[c_idx].charposition]; + std::vector charpoints = getCharacterPoints(char_rect, &pipeline_data ); + for (int cpt = 0; cpt < 4; cpt++) + character_details.corners[cpt] = charpoints[cpt]; + aplate.character_details.push_back(character_details); + } plateResult.topNPlates.push_back(aplate); } @@ -220,6 +233,7 @@ namespace alpr bestPlate.characters = plateResult.topNPlates[bestPlateIndex].characters; bestPlate.matches_template = plateResult.topNPlates[bestPlateIndex].matches_template; bestPlate.overall_confidence = plateResult.topNPlates[bestPlateIndex].overall_confidence; + bestPlate.character_details = plateResult.topNPlates[bestPlateIndex].character_details; plateResult.bestPlate = bestPlate; } @@ -277,6 +291,7 @@ namespace alpr for (unsigned int i = 0; i < response.results.plates.size(); i++) { + // Draw a box around the license plate for (int z = 0; z < 4; z++) { AlprCoordinate* coords = response.results.plates[i].plate_points; @@ -284,6 +299,16 @@ namespace alpr Point p2(coords[(z + 1) % 4].x, coords[(z + 1) % 4].y); line(img, p1, p2, Scalar(255,0,255), 2); } + + // Draw the individual character boxes + for (int q = 0; q < response.results.plates[0].bestPlate.character_details.size(); q++) + { + AlprChar details = response.results.plates[0].bestPlate.character_details[q]; + line(img, Point(details.corners[0].x, details.corners[0].y), Point(details.corners[1].x, details.corners[1].y), Scalar(0,255,0), 1); + line(img, Point(details.corners[1].x, details.corners[1].y), Point(details.corners[2].x, details.corners[2].y), Scalar(0,255,0), 1); + line(img, Point(details.corners[2].x, details.corners[2].y), Point(details.corners[3].x, details.corners[3].y), Scalar(0,255,0), 1); + line(img, Point(details.corners[3].x, details.corners[3].y), Point(details.corners[0].x, details.corners[0].y), Scalar(0,255,0), 1); + } } @@ -560,6 +585,48 @@ namespace alpr ss << OPENALPR_MAJOR_VERSION << "." << OPENALPR_MINOR_VERSION << "." << OPENALPR_PATCH_VERSION; return ss.str(); } + + std::vector AlprImpl::getCharacterPoints(cv::Rect char_rect, PipelineData* pipeline_data ) { + + + + std::vector points; + points.push_back(Point2f(char_rect.x, char_rect.y)); + points.push_back(Point2f(char_rect.x + char_rect.width, char_rect.y)); + points.push_back(Point2f(char_rect.x + char_rect.width, char_rect.y + char_rect.height)); + points.push_back(Point2f(char_rect.x, char_rect.y + char_rect.height)); + + Mat img = pipeline_data->colorImg; + Mat debugImg(img.size(), img.type()); + img.copyTo(debugImg); + + + + std::vector crop_corners; + crop_corners.push_back(Point2f(0,0)); + crop_corners.push_back(Point2f(pipeline_data->crop_gray.cols,0)); + crop_corners.push_back(Point2f(pipeline_data->crop_gray.cols,pipeline_data->crop_gray.rows)); + crop_corners.push_back(Point2f(0,pipeline_data->crop_gray.rows)); + + // Transform the points from the cropped region (skew corrected license plate region) back to the original image + cv::Mat transmtx = cv::getPerspectiveTransform(crop_corners, pipeline_data->plate_corners); + cv::perspectiveTransform(points, points, transmtx); + + // If using prewarp, remap the points to the original image + points = prewarp->projectPoints(points, true); + + + std::vector cornersvector; + for (int i = 0; i < 4; i++) + { + AlprCoordinate coord; + coord.x = round(points[i].x); + coord.y = round(points[i].y); + cornersvector.push_back(coord); + } + + return cornersvector; + } } diff --git a/src/openalpr/alpr_impl.h b/src/openalpr/alpr_impl.h index 1cea1ca..0872651 100644 --- a/src/openalpr/alpr_impl.h +++ b/src/openalpr/alpr_impl.h @@ -107,6 +107,7 @@ namespace alpr bool detectRegion; std::string defaultRegion; + std::vector getCharacterPoints(cv::Rect char_rect, PipelineData* pipeline_data); std::vector convertRects(std::vector regionsOfInterest); }; diff --git a/src/openalpr/postprocess/postprocess.cpp b/src/openalpr/postprocess/postprocess.cpp index 989e31b..0b42b29 100644 --- a/src/openalpr/postprocess/postprocess.cpp +++ b/src/openalpr/postprocess/postprocess.cpp @@ -411,12 +411,18 @@ namespace alpr for (int z = 0; z < prevletters.size(); z++) { if (prevletters[z].letter != SKIP_CHAR) + { possibility.letters = possibility.letters + prevletters[z].letter; + possibility.letter_details.push_back(prevletters[z]); + } possibility.totalscore = possibility.totalscore + prevletters[z].totalscore; } if (letters[charPos][i].letter != SKIP_CHAR) + { possibility.letters = possibility.letters + letters[charPos][i].letter; + possibility.letter_details.push_back(letters[charPos][i]); + } possibility.totalscore = possibility.totalscore +letters[charPos][i].totalscore; allPossibilities.push_back(possibility); diff --git a/src/openalpr/postprocess/postprocess.h b/src/openalpr/postprocess/postprocess.h index 7760b07..bc9196a 100644 --- a/src/openalpr/postprocess/postprocess.h +++ b/src/openalpr/postprocess/postprocess.h @@ -48,6 +48,7 @@ namespace alpr std::string letters; float totalscore; bool matchesTemplate; + std::vector letter_details; }; bool wordCompare( const PPResult &left, const PPResult &right );