mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 19:22:49 +08:00
Updated segmentation to work with multiline text
This commit is contained in:
@@ -37,6 +37,8 @@ CharacterSegmenter::CharacterSegmenter(PipelineData* pipeline_data)
|
|||||||
timespec startTime;
|
timespec startTime;
|
||||||
getTime(&startTime);
|
getTime(&startTime);
|
||||||
|
|
||||||
|
pipeline_data->clearThresholds();
|
||||||
|
pipeline_data->thresholds = produceThresholds(pipeline_data->crop_gray, config);
|
||||||
|
|
||||||
medianBlur(pipeline_data->crop_gray, pipeline_data->crop_gray, 3);
|
medianBlur(pipeline_data->crop_gray, pipeline_data->crop_gray, 3);
|
||||||
|
|
||||||
@@ -44,71 +46,56 @@ CharacterSegmenter::CharacterSegmenter(PipelineData* pipeline_data)
|
|||||||
if (pipeline_data->plate_inverted)
|
if (pipeline_data->plate_inverted)
|
||||||
bitwise_not(pipeline_data->crop_gray, pipeline_data->crop_gray);
|
bitwise_not(pipeline_data->crop_gray, pipeline_data->crop_gray);
|
||||||
|
|
||||||
charAnalysis = new CharacterAnalysis(pipeline_data);
|
|
||||||
charAnalysis->analyze();
|
|
||||||
|
|
||||||
if (this->config->debugCharSegmenter)
|
if (this->config->debugCharSegmenter)
|
||||||
{
|
{
|
||||||
displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(pipeline_data->thresholds, CV_8U, 3));
|
displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(pipeline_data->thresholds, CV_8U, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->config->debugCharSegmenter && pipeline_data->textLines.size() > 0)
|
// if (this->config->debugCharSegmenter && pipeline_data->textLines.size() > 0)
|
||||||
|
// {
|
||||||
|
// Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U);
|
||||||
|
// charAnalysis->bestThreshold.copyTo(img_contours);
|
||||||
|
// cvtColor(img_contours, img_contours, CV_GRAY2RGB);
|
||||||
|
//
|
||||||
|
// vector<vector<Point> > allowedContours;
|
||||||
|
// for (uint i = 0; i < charAnalysis->bestContours.size(); i++)
|
||||||
|
// {
|
||||||
|
// if (charAnalysis->bestContours.goodIndices[i])
|
||||||
|
// allowedContours.push_back(charAnalysis->bestContours.contours[i]);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// drawContours(img_contours, charAnalysis->bestContours.contours,
|
||||||
|
// -1, // draw all contours
|
||||||
|
// cv::Scalar(255,0,0), // in blue
|
||||||
|
// 1); // with a thickness of 1
|
||||||
|
//
|
||||||
|
// drawContours(img_contours, allowedContours,
|
||||||
|
// -1, // draw all contours
|
||||||
|
// cv::Scalar(0,255,0), // in green
|
||||||
|
// 1); // with a thickness of 1
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// line(img_contours, pipeline_data->textLines[0].linePolygon[0], pipeline_data->textLines[0].linePolygon[1], Scalar(255, 0, 255), 1);
|
||||||
|
// line(img_contours, pipeline_data->textLines[0].linePolygon[3], pipeline_data->textLines[0].linePolygon[2], Scalar(255, 0, 255), 1);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Mat bordered = addLabel(img_contours, "Best Contours");
|
||||||
|
// imgDbgGeneral.push_back(bordered);
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (uint lineidx = 0; lineidx < pipeline_data->textLines.size(); lineidx++)
|
||||||
{
|
{
|
||||||
Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U);
|
this->top = pipeline_data->textLines[lineidx].topLine;
|
||||||
charAnalysis->bestThreshold.copyTo(img_contours);
|
this->bottom = pipeline_data->textLines[lineidx].bottomLine;
|
||||||
cvtColor(img_contours, img_contours, CV_GRAY2RGB);
|
|
||||||
|
|
||||||
vector<vector<Point> > allowedContours;
|
|
||||||
for (uint i = 0; i < charAnalysis->bestContours.size(); i++)
|
|
||||||
{
|
|
||||||
if (charAnalysis->bestContours.goodIndices[i])
|
|
||||||
allowedContours.push_back(charAnalysis->bestContours.contours[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawContours(img_contours, charAnalysis->bestContours.contours,
|
|
||||||
-1, // draw all contours
|
|
||||||
cv::Scalar(255,0,0), // in blue
|
|
||||||
1); // with a thickness of 1
|
|
||||||
|
|
||||||
drawContours(img_contours, allowedContours,
|
|
||||||
-1, // draw all contours
|
|
||||||
cv::Scalar(0,255,0), // in green
|
|
||||||
1); // with a thickness of 1
|
|
||||||
|
|
||||||
|
|
||||||
line(img_contours, pipeline_data->textLines[0].linePolygon[0], pipeline_data->textLines[0].linePolygon[1], Scalar(255, 0, 255), 1);
|
float avgCharHeight = pipeline_data->textLines[lineidx].lineHeight;
|
||||||
line(img_contours, pipeline_data->textLines[0].linePolygon[3], pipeline_data->textLines[0].linePolygon[2], Scalar(255, 0, 255), 1);
|
float height_to_width_ratio = pipeline_data->config->charHeightMM / pipeline_data->config->charWidthMM;
|
||||||
|
float avgCharWidth = avgCharHeight / height_to_width_ratio;
|
||||||
|
//float avgCharWidth = median(charWidths.data(), charWidths.size());
|
||||||
|
|
||||||
|
//removeSmallContours(pipeline_data->thresholds, charAnalysis->allTextContours, avgCharWidth, avgCharHeight);
|
||||||
Mat bordered = addLabel(img_contours, "Best Contours");
|
|
||||||
imgDbgGeneral.push_back(bordered);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pipeline_data->textLines.size() > 0)
|
|
||||||
{
|
|
||||||
this->top = LineSegment(pipeline_data->textLines[0].linePolygon[0].x, pipeline_data->textLines[0].linePolygon[0].y,
|
|
||||||
pipeline_data->textLines[0].linePolygon[1].x, pipeline_data->textLines[0].linePolygon[1].y);
|
|
||||||
this->bottom = LineSegment(pipeline_data->textLines[0].linePolygon[3].x, pipeline_data->textLines[0].linePolygon[3].y,
|
|
||||||
pipeline_data->textLines[0].linePolygon[2].x, pipeline_data->textLines[0].linePolygon[2].y);
|
|
||||||
|
|
||||||
vector<int> charWidths;
|
|
||||||
vector<int> charHeights;
|
|
||||||
|
|
||||||
for (uint i = 0; i < charAnalysis->bestContours.size(); i++)
|
|
||||||
{
|
|
||||||
if (charAnalysis->bestContours.goodIndices[i] == false)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Rect mr = boundingRect(charAnalysis->bestContours.contours[i]);
|
|
||||||
|
|
||||||
charWidths.push_back(mr.width);
|
|
||||||
charHeights.push_back(mr.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
float avgCharWidth = median(charWidths.data(), charWidths.size());
|
|
||||||
float avgCharHeight = median(charHeights.data(), charHeights.size());
|
|
||||||
|
|
||||||
removeSmallContours(pipeline_data->thresholds, charAnalysis->allTextContours, avgCharWidth, avgCharHeight);
|
|
||||||
|
|
||||||
// Do the histogram analysis to figure out char regions
|
// Do the histogram analysis to figure out char regions
|
||||||
|
|
||||||
@@ -118,11 +105,11 @@ CharacterSegmenter::CharacterSegmenter(PipelineData* pipeline_data)
|
|||||||
vector<Mat> allHistograms;
|
vector<Mat> allHistograms;
|
||||||
|
|
||||||
vector<Rect> allBoxes;
|
vector<Rect> allBoxes;
|
||||||
for (uint i = 0; i < charAnalysis->allTextContours.size(); i++)
|
for (uint i = 0; i < pipeline_data->thresholds.size(); i++)
|
||||||
{
|
{
|
||||||
Mat histogramMask = Mat::zeros(pipeline_data->thresholds[i].size(), CV_8U);
|
Mat histogramMask = Mat::zeros(pipeline_data->thresholds[i].size(), CV_8U);
|
||||||
|
|
||||||
fillConvexPoly(histogramMask, pipeline_data->textLines[0].linePolygon.data(), pipeline_data->textLines[0].linePolygon.size(), Scalar(255,255,255));
|
fillConvexPoly(histogramMask, pipeline_data->textLines[lineidx].linePolygon.data(), pipeline_data->textLines[lineidx].linePolygon.size(), Scalar(255,255,255));
|
||||||
|
|
||||||
VerticalHistogram vertHistogram(pipeline_data->thresholds[i], histogramMask);
|
VerticalHistogram vertHistogram(pipeline_data->thresholds[i], histogramMask);
|
||||||
|
|
||||||
@@ -239,7 +226,7 @@ CharacterSegmenter::CharacterSegmenter(PipelineData* pipeline_data)
|
|||||||
|
|
||||||
CharacterSegmenter::~CharacterSegmenter()
|
CharacterSegmenter::~CharacterSegmenter()
|
||||||
{
|
{
|
||||||
delete charAnalysis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a histogram and the horizontal line boundaries, respond with an array of boxes where the characters are
|
// Given a histogram and the horizontal line boundaries, respond with an array of boxes where the characters are
|
||||||
@@ -445,28 +432,28 @@ vector<Rect> CharacterSegmenter::get1DHits(Mat img, int yOffset)
|
|||||||
return hits;
|
return hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterSegmenter::removeSmallContours(vector<Mat> thresholds, vector<TextContours> contours, float avgCharWidth, float avgCharHeight)
|
//void CharacterSegmenter::removeSmallContours(vector<Mat> thresholds, vector<TextContours> contours, float avgCharWidth, float avgCharHeight)
|
||||||
{
|
//{
|
||||||
//const float MIN_CHAR_AREA = 0.02 * avgCharWidth * avgCharHeight; // To clear out the tiny specks
|
// //const float MIN_CHAR_AREA = 0.02 * avgCharWidth * avgCharHeight; // To clear out the tiny specks
|
||||||
const float MIN_CONTOUR_HEIGHT = 0.3 * avgCharHeight;
|
// const float MIN_CONTOUR_HEIGHT = 0.3 * avgCharHeight;
|
||||||
|
//
|
||||||
for (uint i = 0; i < thresholds.size(); i++)
|
// for (uint i = 0; i < thresholds.size(); i++)
|
||||||
{
|
// {
|
||||||
for (uint c = 0; c < contours[i].contours.size(); c++)
|
// for (uint c = 0; c < contours[i].contours.size(); c++)
|
||||||
{
|
// {
|
||||||
if (contours[i].contours[c].size() == 0)
|
// if (contours[i].contours[c].size() == 0)
|
||||||
continue;
|
// continue;
|
||||||
|
//
|
||||||
Rect mr = boundingRect(contours[i].contours[c]);
|
// Rect mr = boundingRect(contours[i].contours[c]);
|
||||||
if (mr.height < MIN_CONTOUR_HEIGHT)
|
// if (mr.height < MIN_CONTOUR_HEIGHT)
|
||||||
{
|
// {
|
||||||
// Erase it
|
// // Erase it
|
||||||
drawContours(thresholds[i], contours[i].contours, c, Scalar(0, 0, 0), -1);
|
// drawContours(thresholds[i], contours[i].contours, c, Scalar(0, 0, 0), -1);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
vector<Rect> CharacterSegmenter::combineCloseBoxes( vector<Rect> charBoxes, float biggestCharWidth)
|
vector<Rect> CharacterSegmenter::combineCloseBoxes( vector<Rect> charBoxes, float biggestCharWidth)
|
||||||
{
|
{
|
||||||
|
@@ -55,7 +55,6 @@ class CharacterSegmenter
|
|||||||
Config* config;
|
Config* config;
|
||||||
PipelineData* pipeline_data;
|
PipelineData* pipeline_data;
|
||||||
|
|
||||||
CharacterAnalysis* charAnalysis;
|
|
||||||
|
|
||||||
LineSegment top;
|
LineSegment top;
|
||||||
LineSegment bottom;
|
LineSegment bottom;
|
||||||
|
Reference in New Issue
Block a user