mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 12:56:49 +08:00
Wrapped OpenALPR library in "alpr" namespace. Resolves issue #60.
This commit is contained in:
@@ -22,178 +22,183 @@
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
PlateMask::PlateMask(PipelineData* pipeline_data) {
|
||||
this->pipeline_data = pipeline_data;
|
||||
this->hasPlateMask = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
PlateMask::~PlateMask() {
|
||||
}
|
||||
|
||||
cv::Mat PlateMask::getMask() {
|
||||
return this->plateMask;
|
||||
}
|
||||
|
||||
void PlateMask::findOuterBoxMask( vector<TextContours > contours )
|
||||
namespace alpr
|
||||
{
|
||||
double min_parent_area = pipeline_data->config->templateHeightPx * pipeline_data->config->templateWidthPx * 0.10; // Needs to be at least 10% of the plate area to be considered.
|
||||
|
||||
int winningIndex = -1;
|
||||
int winningParentId = -1;
|
||||
int bestCharCount = 0;
|
||||
double lowestArea = 99999999999999;
|
||||
PlateMask::PlateMask(PipelineData* pipeline_data) {
|
||||
this->pipeline_data = pipeline_data;
|
||||
this->hasPlateMask = false;
|
||||
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
cout << "CharacterAnalysis::findOuterBoxMask" << endl;
|
||||
|
||||
for (uint imgIndex = 0; imgIndex < contours.size(); imgIndex++)
|
||||
{
|
||||
//vector<bool> charContours = filter(thresholds[imgIndex], allContours[imgIndex], allHierarchy[imgIndex]);
|
||||
|
||||
int charsRecognized = 0;
|
||||
int parentId = -1;
|
||||
bool hasParent = false;
|
||||
for (uint i = 0; i < contours[imgIndex].goodIndices.size(); i++)
|
||||
{
|
||||
if (contours[imgIndex].goodIndices[i]) charsRecognized++;
|
||||
if (contours[imgIndex].goodIndices[i] && contours[imgIndex].hierarchy[i][3] != -1)
|
||||
{
|
||||
parentId = contours[imgIndex].hierarchy[i][3];
|
||||
hasParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (charsRecognized == 0)
|
||||
continue;
|
||||
|
||||
if (hasParent)
|
||||
{
|
||||
double boxArea = contourArea(contours[imgIndex].contours[parentId]);
|
||||
if (boxArea < min_parent_area)
|
||||
continue;
|
||||
|
||||
if ((charsRecognized > bestCharCount) ||
|
||||
(charsRecognized == bestCharCount && boxArea < lowestArea))
|
||||
//(boxArea < lowestArea)
|
||||
{
|
||||
bestCharCount = charsRecognized;
|
||||
winningIndex = imgIndex;
|
||||
winningParentId = parentId;
|
||||
lowestArea = boxArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
cout << "Winning image index (findOuterBoxMask) is: " << winningIndex << endl;
|
||||
|
||||
if (winningIndex != -1 && bestCharCount >= 3)
|
||||
PlateMask::~PlateMask() {
|
||||
}
|
||||
|
||||
cv::Mat PlateMask::getMask() {
|
||||
return this->plateMask;
|
||||
}
|
||||
|
||||
void PlateMask::findOuterBoxMask( vector<TextContours > contours )
|
||||
{
|
||||
int longestChildIndex = -1;
|
||||
double longestChildLength = 0;
|
||||
// Find the child with the longest permiter/arc length ( just for kicks)
|
||||
for (uint i = 0; i < contours[winningIndex].size(); i++)
|
||||
double min_parent_area = pipeline_data->config->templateHeightPx * pipeline_data->config->templateWidthPx * 0.10; // Needs to be at least 10% of the plate area to be considered.
|
||||
|
||||
int winningIndex = -1;
|
||||
int winningParentId = -1;
|
||||
int bestCharCount = 0;
|
||||
double lowestArea = 99999999999999;
|
||||
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
cout << "CharacterAnalysis::findOuterBoxMask" << endl;
|
||||
|
||||
for (uint imgIndex = 0; imgIndex < contours.size(); imgIndex++)
|
||||
{
|
||||
for (uint j = 0; j < contours[winningIndex].size(); j++)
|
||||
//vector<bool> charContours = filter(thresholds[imgIndex], allContours[imgIndex], allHierarchy[imgIndex]);
|
||||
|
||||
int charsRecognized = 0;
|
||||
int parentId = -1;
|
||||
bool hasParent = false;
|
||||
for (uint i = 0; i < contours[imgIndex].goodIndices.size(); i++)
|
||||
{
|
||||
if (contours[winningIndex].hierarchy[j][3] == winningParentId)
|
||||
if (contours[imgIndex].goodIndices[i]) charsRecognized++;
|
||||
if (contours[imgIndex].goodIndices[i] && contours[imgIndex].hierarchy[i][3] != -1)
|
||||
{
|
||||
double arclength = arcLength(contours[winningIndex].contours[j], false);
|
||||
if (arclength > longestChildLength)
|
||||
{
|
||||
longestChildIndex = j;
|
||||
longestChildLength = arclength;
|
||||
}
|
||||
parentId = contours[imgIndex].hierarchy[i][3];
|
||||
hasParent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (charsRecognized == 0)
|
||||
continue;
|
||||
|
||||
if (hasParent)
|
||||
{
|
||||
double boxArea = contourArea(contours[imgIndex].contours[parentId]);
|
||||
if (boxArea < min_parent_area)
|
||||
continue;
|
||||
|
||||
if ((charsRecognized > bestCharCount) ||
|
||||
(charsRecognized == bestCharCount && boxArea < lowestArea))
|
||||
//(boxArea < lowestArea)
|
||||
{
|
||||
bestCharCount = charsRecognized;
|
||||
winningIndex = imgIndex;
|
||||
winningParentId = parentId;
|
||||
lowestArea = boxArea;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mat mask = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
cout << "Winning image index (findOuterBoxMask) is: " << winningIndex << endl;
|
||||
|
||||
// get rid of the outline by drawing a 1 pixel width black line
|
||||
drawContours(mask, contours[winningIndex].contours,
|
||||
winningParentId, // draw this contour
|
||||
cv::Scalar(255,255,255), // in
|
||||
CV_FILLED,
|
||||
8,
|
||||
contours[winningIndex].hierarchy,
|
||||
0
|
||||
);
|
||||
|
||||
// Morph Open the mask to get rid of any little connectors to non-plate portions
|
||||
int morph_elem = 2;
|
||||
int morph_size = 3;
|
||||
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
|
||||
//morphologyEx( mask, mask, MORPH_CLOSE, element );
|
||||
morphologyEx( mask, mask, MORPH_OPEN, element );
|
||||
|
||||
//morph_size = 1;
|
||||
//element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
//dilate(mask, mask, element);
|
||||
|
||||
// Drawing the edge black effectively erodes the image. This may clip off some extra junk from the edges.
|
||||
// We'll want to do the contour again and find the larges one so that we remove the clipped portion.
|
||||
|
||||
vector<vector<Point> > contoursSecondRound;
|
||||
|
||||
findContours(mask, contoursSecondRound, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
|
||||
int biggestContourIndex = -1;
|
||||
double largestArea = 0;
|
||||
for (uint c = 0; c < contoursSecondRound.size(); c++)
|
||||
if (winningIndex != -1 && bestCharCount >= 3)
|
||||
{
|
||||
double area = contourArea(contoursSecondRound[c]);
|
||||
if (area > largestArea)
|
||||
int longestChildIndex = -1;
|
||||
double longestChildLength = 0;
|
||||
// Find the child with the longest permiter/arc length ( just for kicks)
|
||||
for (uint i = 0; i < contours[winningIndex].size(); i++)
|
||||
{
|
||||
biggestContourIndex = c;
|
||||
largestArea = area;
|
||||
for (uint j = 0; j < contours[winningIndex].size(); j++)
|
||||
{
|
||||
if (contours[winningIndex].hierarchy[j][3] == winningParentId)
|
||||
{
|
||||
double arclength = arcLength(contours[winningIndex].contours[j], false);
|
||||
if (arclength > longestChildLength)
|
||||
{
|
||||
longestChildIndex = j;
|
||||
longestChildLength = arclength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (biggestContourIndex != -1)
|
||||
{
|
||||
mask = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
Mat mask = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
|
||||
vector<Point> smoothedMaskPoints;
|
||||
approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true);
|
||||
|
||||
vector<vector<Point> > tempvec;
|
||||
tempvec.push_back(smoothedMaskPoints);
|
||||
//fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255));
|
||||
drawContours(mask, tempvec,
|
||||
0, // draw this contour
|
||||
// get rid of the outline by drawing a 1 pixel width black line
|
||||
drawContours(mask, contours[winningIndex].contours,
|
||||
winningParentId, // draw this contour
|
||||
cv::Scalar(255,255,255), // in
|
||||
CV_FILLED,
|
||||
8,
|
||||
contours[winningIndex].hierarchy,
|
||||
0
|
||||
);
|
||||
|
||||
// Morph Open the mask to get rid of any little connectors to non-plate portions
|
||||
int morph_elem = 2;
|
||||
int morph_size = 3;
|
||||
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
|
||||
//morphologyEx( mask, mask, MORPH_CLOSE, element );
|
||||
morphologyEx( mask, mask, MORPH_OPEN, element );
|
||||
|
||||
//morph_size = 1;
|
||||
//element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
|
||||
//dilate(mask, mask, element);
|
||||
|
||||
// Drawing the edge black effectively erodes the image. This may clip off some extra junk from the edges.
|
||||
// We'll want to do the contour again and find the larges one so that we remove the clipped portion.
|
||||
|
||||
vector<vector<Point> > contoursSecondRound;
|
||||
|
||||
findContours(mask, contoursSecondRound, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
|
||||
int biggestContourIndex = -1;
|
||||
double largestArea = 0;
|
||||
for (uint c = 0; c < contoursSecondRound.size(); c++)
|
||||
{
|
||||
double area = contourArea(contoursSecondRound[c]);
|
||||
if (area > largestArea)
|
||||
{
|
||||
biggestContourIndex = c;
|
||||
largestArea = area;
|
||||
}
|
||||
}
|
||||
|
||||
if (biggestContourIndex != -1)
|
||||
{
|
||||
mask = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
|
||||
vector<Point> smoothedMaskPoints;
|
||||
approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true);
|
||||
|
||||
vector<vector<Point> > tempvec;
|
||||
tempvec.push_back(smoothedMaskPoints);
|
||||
//fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255));
|
||||
drawContours(mask, tempvec,
|
||||
0, // draw this contour
|
||||
cv::Scalar(255,255,255), // in
|
||||
CV_FILLED,
|
||||
8,
|
||||
contours[winningIndex].hierarchy,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
{
|
||||
vector<Mat> debugImgs;
|
||||
Mat debugImgMasked = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
|
||||
pipeline_data->thresholds[winningIndex].copyTo(debugImgMasked, mask);
|
||||
|
||||
debugImgs.push_back(mask);
|
||||
debugImgs.push_back(pipeline_data->thresholds[winningIndex]);
|
||||
debugImgs.push_back(debugImgMasked);
|
||||
|
||||
Mat dashboard = drawImageDashboard(debugImgs, CV_8U, 1);
|
||||
displayImage(pipeline_data->config, "Winning outer box", dashboard);
|
||||
}
|
||||
|
||||
hasPlateMask = true;
|
||||
this->plateMask = mask;
|
||||
}
|
||||
|
||||
if (pipeline_data->config->debugCharAnalysis)
|
||||
{
|
||||
vector<Mat> debugImgs;
|
||||
Mat debugImgMasked = Mat::zeros(pipeline_data->thresholds[winningIndex].size(), CV_8U);
|
||||
hasPlateMask = false;
|
||||
Mat fullMask = Mat::zeros(pipeline_data->thresholds[0].size(), CV_8U);
|
||||
bitwise_not(fullMask, fullMask);
|
||||
|
||||
pipeline_data->thresholds[winningIndex].copyTo(debugImgMasked, mask);
|
||||
|
||||
debugImgs.push_back(mask);
|
||||
debugImgs.push_back(pipeline_data->thresholds[winningIndex]);
|
||||
debugImgs.push_back(debugImgMasked);
|
||||
|
||||
Mat dashboard = drawImageDashboard(debugImgs, CV_8U, 1);
|
||||
displayImage(pipeline_data->config, "Winning outer box", dashboard);
|
||||
}
|
||||
|
||||
hasPlateMask = true;
|
||||
this->plateMask = mask;
|
||||
this->plateMask = fullMask;
|
||||
}
|
||||
|
||||
hasPlateMask = false;
|
||||
Mat fullMask = Mat::zeros(pipeline_data->thresholds[0].size(), CV_8U);
|
||||
bitwise_not(fullMask, fullMask);
|
||||
|
||||
this->plateMask = fullMask;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user