mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 02:06:57 +08:00
Added per-line values for character height.
Helps support multiline plates with different heights on each line
This commit is contained in:
@@ -33,7 +33,7 @@ namespace alpr
|
||||
float getFloat(CSimpleIniA* ini, std::string section, std::string key, float defaultValue);
|
||||
std::string getString(CSimpleIniA* ini, std::string section, std::string key, std::string defaultValue);
|
||||
bool getBoolean(CSimpleIniA* ini, std::string section, std::string key, bool defaultValue);
|
||||
|
||||
std::vector<float> getAllFloats(CSimpleIniA* ini, string section, string key);
|
||||
|
||||
Config::Config(const std::string country, const std::string config_file, const std::string runtime_dir)
|
||||
{
|
||||
@@ -214,6 +214,7 @@ namespace alpr
|
||||
void Config::loadCountryValues(string configFile, string country)
|
||||
{
|
||||
CSimpleIniA iniObj;
|
||||
iniObj.SetMultiKey(true);
|
||||
iniObj.LoadFile(configFile.c_str());
|
||||
CSimpleIniA* ini = &iniObj;
|
||||
|
||||
@@ -243,10 +244,23 @@ namespace alpr
|
||||
plateWidthMM = getFloat(ini, "", "plate_width_mm", 100);
|
||||
plateHeightMM = getFloat(ini, "", "plate_height_mm", 100);
|
||||
|
||||
charHeightMM = getFloat(ini, "", "char_height_mm", 100);
|
||||
charWidthMM = getFloat(ini, "", "char_width_mm", 100);
|
||||
charHeightMM = getAllFloats(ini, "", "char_height_mm");
|
||||
charWidthMM = getAllFloats(ini, "", "char_width_mm");
|
||||
|
||||
// Compute the average char height/widths
|
||||
avgCharHeightMM = 0;
|
||||
avgCharWidthMM = 0;
|
||||
for (unsigned int i = 0; i < charHeightMM.size(); i++)
|
||||
{
|
||||
avgCharHeightMM += charHeightMM[i];
|
||||
avgCharWidthMM += charWidthMM[i];
|
||||
}
|
||||
avgCharHeightMM /= charHeightMM.size();
|
||||
avgCharWidthMM /= charHeightMM.size();
|
||||
|
||||
charWhitespaceTopMM = getFloat(ini, "", "char_whitespace_top_mm", 100);
|
||||
charWhitespaceBotMM = getFloat(ini, "", "char_whitespace_bot_mm", 100);
|
||||
charWhitespaceBetweenLinesMM = getFloat(ini, "", "char_whitespace_between_lines_mm", 5);
|
||||
|
||||
templateWidthPx = getInt(ini, "", "template_max_width_px", 100);
|
||||
templateHeightPx = getInt(ini, "", "template_max_height_px", 100);
|
||||
@@ -358,6 +372,27 @@ namespace alpr
|
||||
float val = atof(pszValue);
|
||||
return val;
|
||||
}
|
||||
|
||||
std::vector<float> getAllFloats(CSimpleIniA* ini, string section, string key)
|
||||
{
|
||||
CSimpleIniA::TNamesDepend values;
|
||||
|
||||
ini->GetAllValues(section.c_str(), key.c_str(), values);
|
||||
|
||||
// sort the values into the original load order
|
||||
values.sort(CSimpleIniA::Entry::LoadOrder());
|
||||
|
||||
std::vector<float> response;
|
||||
|
||||
// output all of the items
|
||||
CSimpleIniA::TNamesDepend::const_iterator i;
|
||||
for (i = values.begin(); i != values.end(); ++i) {
|
||||
response.push_back(atof(i->pItem));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
int getInt(CSimpleIniA* ini, string section, string key, int defaultValue)
|
||||
{
|
||||
const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/);
|
||||
|
@@ -70,10 +70,15 @@ namespace alpr
|
||||
float plateWidthMM;
|
||||
float plateHeightMM;
|
||||
|
||||
float charHeightMM;
|
||||
float charWidthMM;
|
||||
std::vector<float> charHeightMM;
|
||||
std::vector<float> charWidthMM;
|
||||
|
||||
float avgCharHeightMM;
|
||||
float avgCharWidthMM;
|
||||
|
||||
float charWhitespaceTopMM;
|
||||
float charWhitespaceBotMM;
|
||||
float charWhitespaceBetweenLinesMM;
|
||||
|
||||
int templateWidthPx;
|
||||
int templateHeightPx;
|
||||
|
@@ -179,7 +179,7 @@ for (int i = 0; i < rects.size(); i++) {
|
||||
int numBlobs = plateBlobs.size();
|
||||
int numBlobsInv = plateBlobsInv.size();
|
||||
|
||||
float idealAspect = config->charWidthMM / config->charHeightMM;
|
||||
float idealAspect = config->avgCharWidthMM / config->avgCharHeightMM;
|
||||
for (int j = 0; j < numBlobs; j++) {
|
||||
cv::Rect r0 = cv::boundingRect(cv::Mat(plateBlobs[j]));
|
||||
|
||||
|
@@ -48,10 +48,11 @@ namespace alpr
|
||||
// If it's a nice, long segment, then guess the correct box based on character height/position
|
||||
if (tlc.longerSegment.length > tlc.charHeight * 3)
|
||||
{
|
||||
float charHeightToPlateWidthRatio = pipeline_data->config->plateWidthMM / pipeline_data->config->charHeightMM;
|
||||
|
||||
float charHeightToPlateWidthRatio = pipeline_data->config->plateWidthMM / pipeline_data->config->avgCharHeightMM;
|
||||
float idealPixelWidth = tlc.charHeight * (charHeightToPlateWidthRatio * 1.03); // Add 3% so we don't clip any characters
|
||||
|
||||
float charHeightToPlateHeightRatio = pipeline_data->config->plateHeightMM / pipeline_data->config->charHeightMM;
|
||||
float charHeightToPlateHeightRatio = pipeline_data->config->plateHeightMM / pipeline_data->config->avgCharHeightMM;
|
||||
float idealPixelHeight = tlc.charHeight * charHeightToPlateHeightRatio;
|
||||
|
||||
|
||||
@@ -76,7 +77,6 @@ namespace alpr
|
||||
else
|
||||
{
|
||||
|
||||
//cout << "HEYOOO!" << endl;
|
||||
int expandX = (int) ((float) pipeline_data->crop_gray.cols) * 0.15f;
|
||||
int expandY = (int) ((float) pipeline_data->crop_gray.rows) * 0.15f;
|
||||
int w = pipeline_data->crop_gray.cols;
|
||||
|
@@ -138,7 +138,7 @@ namespace alpr
|
||||
LineSegment right;
|
||||
|
||||
|
||||
float charHeightToPlateWidthRatio = pipelineData->config->plateWidthMM / pipelineData->config->charHeightMM;
|
||||
float charHeightToPlateWidthRatio = pipelineData->config->plateWidthMM / pipelineData->config->avgCharHeightMM;
|
||||
float idealPixelWidth = tlc.charHeight * (charHeightToPlateWidthRatio * 1.03); // Add 3% so we don't clip any characters
|
||||
|
||||
float confidenceDiff = 0;
|
||||
@@ -242,7 +242,7 @@ namespace alpr
|
||||
LineSegment top;
|
||||
LineSegment bottom;
|
||||
|
||||
float charHeightToPlateHeightRatio = pipelineData->config->plateHeightMM / pipelineData->config->charHeightMM;
|
||||
float charHeightToPlateHeightRatio = pipelineData->config->plateHeightMM / pipelineData->config->avgCharHeightMM;
|
||||
float idealPixelHeight = tlc.charHeight * charHeightToPlateHeightRatio;
|
||||
|
||||
float confidenceDiff = 0;
|
||||
@@ -304,7 +304,7 @@ namespace alpr
|
||||
// Get the height difference
|
||||
|
||||
float heightRatio = tlc.charHeight / plateHeightPx;
|
||||
float idealHeightRatio = (pipelineData->config->charHeightMM / pipelineData->config->plateHeightMM);
|
||||
float idealHeightRatio = (pipelineData->config->avgCharHeightMM / pipelineData->config->plateHeightMM);
|
||||
float heightRatioDiff = abs(heightRatio - idealHeightRatio);
|
||||
|
||||
scoreKeeper.setScore("SCORING_PLATEHEIGHT_WEIGHT", heightRatioDiff, SCORING_PLATEHEIGHT_WEIGHT);
|
||||
|
@@ -70,7 +70,7 @@ namespace alpr
|
||||
this->bottom = pipeline_data->textLines[lineidx].bottomLine;
|
||||
|
||||
float avgCharHeight = pipeline_data->textLines[lineidx].lineHeight;
|
||||
float height_to_width_ratio = pipeline_data->config->charHeightMM / pipeline_data->config->charWidthMM;
|
||||
float height_to_width_ratio = pipeline_data->config->charHeightMM[lineidx] / pipeline_data->config->charWidthMM[lineidx];
|
||||
float avgCharWidth = avgCharHeight / height_to_width_ratio;
|
||||
|
||||
removeSmallContours(pipeline_data->thresholds, avgCharHeight, pipeline_data->textLines[lineidx]);
|
||||
|
@@ -338,7 +338,19 @@ namespace alpr
|
||||
// Goes through the contours for the plate and picks out possible char segments based on min/max height
|
||||
void CharacterAnalysis::filterByBoxSize(TextContours& textContours, int minHeightPx, int maxHeightPx)
|
||||
{
|
||||
float idealAspect=config->charWidthMM / config->charHeightMM;
|
||||
// For multiline plates, we want to target the biggest line for character analysis, since it should be easier to spot.
|
||||
float larger_char_height_mm = 0;
|
||||
float larger_char_width_mm = 0;
|
||||
for (unsigned int i = 0; i < config->charHeightMM.size(); i++)
|
||||
{
|
||||
if (config->charHeightMM[i] > larger_char_height_mm)
|
||||
{
|
||||
larger_char_height_mm = config->charHeightMM[i];
|
||||
larger_char_width_mm = config->charWidthMM[i];
|
||||
}
|
||||
}
|
||||
|
||||
float idealAspect=larger_char_width_mm / larger_char_height_mm;
|
||||
float aspecttolerance=0.25;
|
||||
|
||||
|
||||
@@ -619,31 +631,6 @@ namespace alpr
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CharacterAnalysis::verifySize(Mat r, float minHeightPx, float maxHeightPx)
|
||||
{
|
||||
//Char sizes 45x90
|
||||
float aspect=config->charWidthMM / config->charHeightMM;
|
||||
float charAspect= (float)r.cols/(float)r.rows;
|
||||
float error=0.35;
|
||||
//float minHeight=TEMPLATE_PLATE_HEIGHT * .35;
|
||||
//float maxHeight=TEMPLATE_PLATE_HEIGHT * .65;
|
||||
//We have a different aspect ratio for number 1, and it can be ~0.2
|
||||
float minAspect=0.2;
|
||||
float maxAspect=aspect+aspect*error;
|
||||
//area of pixels
|
||||
float area=countNonZero(r);
|
||||
//bb area
|
||||
float bbArea=r.cols*r.rows;
|
||||
//% of pixel in area
|
||||
float percPixels=area/bbArea;
|
||||
|
||||
//if(DEBUG)
|
||||
//cout << "Aspect: "<< aspect << " ["<< minAspect << "," << maxAspect << "] " << "Area "<< percPixels <<" Char aspect " << charAspect << " Height char "<< r.rows << "\n";
|
||||
if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeightPx && r.rows < maxHeightPx)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<Point> CharacterAnalysis::getCharArea(LineSegment topLine, LineSegment bottomLine)
|
||||
{
|
||||
|
@@ -65,8 +65,6 @@ namespace alpr
|
||||
std::vector<cv::Point> getCharArea(LineSegment topLine, LineSegment bottomLine);
|
||||
void filterBetweenLines(cv::Mat img, TextContours& textContours, std::vector<TextLine> textLines );
|
||||
|
||||
bool verifySize(cv::Mat r, float minHeightPx, float maxHeightPx);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user