Updated segmentation to work with multiline text

This commit is contained in:
Matt Hill
2014-10-19 19:08:00 -04:00
parent a691d8a6fe
commit be99e8219b
2 changed files with 68 additions and 82 deletions

View File

@@ -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; float avgCharHeight = pipeline_data->textLines[lineidx].lineHeight;
for (uint i = 0; i < charAnalysis->bestContours.size(); i++) float height_to_width_ratio = pipeline_data->config->charHeightMM / pipeline_data->config->charWidthMM;
{ float avgCharWidth = avgCharHeight / height_to_width_ratio;
if (charAnalysis->bestContours.goodIndices[i]) //float avgCharWidth = median(charWidths.data(), charWidths.size());
allowedContours.push_back(charAnalysis->bestContours.contours[i]);
}
drawContours(img_contours, charAnalysis->bestContours.contours, //removeSmallContours(pipeline_data->thresholds, charAnalysis->allTextContours, avgCharWidth, avgCharHeight);
-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);
}
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)
{ {

View File

@@ -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;