mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 06:56:49 +08:00
Merge branch 'develop' of https://github.com/Silex/openalpr into develop
Conflicts: src/openalpr/regiondetector.cpp
This commit is contained in:
24
src/main.cpp
24
src/main.cpp
@@ -51,7 +51,6 @@ int main( int argc, const char** argv )
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION);
|
||||
|
||||
TCLAP::UnlabeledValueArg<std::string> fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" );
|
||||
@@ -85,7 +84,6 @@ int main( int argc, const char** argv )
|
||||
templateRegion = templateRegionArg.getValue();
|
||||
topn = topNArg.getValue();
|
||||
measureProcessingTime = clockSwitch.getValue();
|
||||
|
||||
}
|
||||
catch (TCLAP::ArgException &e) // catch any exceptions
|
||||
{
|
||||
@@ -101,10 +99,8 @@ int main( int argc, const char** argv )
|
||||
if (detectRegion)
|
||||
alpr.setDetectRegion(detectRegion);
|
||||
|
||||
if (strcmp(templateRegion.c_str(), "") != 0)
|
||||
{
|
||||
if (templateRegion.empty() == false)
|
||||
alpr.setDefaultRegion(templateRegion);
|
||||
}
|
||||
|
||||
if (alpr.isLoaded() == false)
|
||||
{
|
||||
@@ -112,7 +108,7 @@ int main( int argc, const char** argv )
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(filename.c_str(), "webcam") == 0)
|
||||
if (filename == "webcam")
|
||||
{
|
||||
int framenum = 0;
|
||||
cv::VideoCapture cap(0);
|
||||
@@ -122,7 +118,7 @@ int main( int argc, const char** argv )
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (cap.read(frame) == true)
|
||||
while (cap.read(frame))
|
||||
{
|
||||
detectandshow(&alpr, frame, "", outputJson);
|
||||
cv::waitKey(1);
|
||||
@@ -139,9 +135,9 @@ int main( int argc, const char** argv )
|
||||
cap.open(filename);
|
||||
cap.set(CV_CAP_PROP_POS_MSEC, seektoms);
|
||||
|
||||
while (cap.read(frame) == true)
|
||||
while (cap.read(frame))
|
||||
{
|
||||
if (SAVE_LAST_VIDEO_STILL == true)
|
||||
if (SAVE_LAST_VIDEO_STILL)
|
||||
{
|
||||
cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame);
|
||||
}
|
||||
@@ -157,7 +153,6 @@ int main( int argc, const char** argv )
|
||||
{
|
||||
std::cerr << "Video file not found: " << filename << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
else if (hasEnding(filename, ".png") || hasEnding(filename, ".jpg") || hasEnding(filename, ".gif"))
|
||||
{
|
||||
@@ -171,7 +166,6 @@ int main( int argc, const char** argv )
|
||||
{
|
||||
std::cerr << "Image file not found: " << filename << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
else if (DirectoryExists(filename.c_str()))
|
||||
{
|
||||
@@ -195,7 +189,6 @@ int main( int argc, const char** argv )
|
||||
//cv::waitKey(50);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -209,7 +202,6 @@ int main( int argc, const char** argv )
|
||||
|
||||
bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson)
|
||||
{
|
||||
|
||||
std::vector<uchar> buffer;
|
||||
cv::imencode(".bmp", frame, buffer );
|
||||
|
||||
@@ -232,7 +224,6 @@ bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJso
|
||||
{
|
||||
std::cout << " - " << results[i].topNPlates[k].characters << "\t confidence: " << results[i].topNPlates[k].overall_confidence << "\t template_match: " << results[i].topNPlates[k].matches_template << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,8 +232,5 @@ bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJso
|
||||
if (measureProcessingTime)
|
||||
std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl;
|
||||
|
||||
if (results.size() > 0)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
return results.size() > 0;
|
||||
}
|
||||
|
@@ -57,7 +57,6 @@ int main( int argc, const char** argv )
|
||||
benchmarkName = argv[2];
|
||||
inDir = argv[3];
|
||||
outDir = argv[4];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -133,9 +132,7 @@ int main( int argc, const char** argv )
|
||||
|
||||
imshow("Current LP", frame);
|
||||
waitKey(5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete config;
|
||||
@@ -157,9 +154,7 @@ int main( int argc, const char** argv )
|
||||
|
||||
imshow("Current LP", frame);
|
||||
waitKey(5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (benchmarkName.compare("speed") == 0)
|
||||
@@ -254,9 +249,7 @@ int main( int argc, const char** argv )
|
||||
}
|
||||
|
||||
waitKey(5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cout << endl << "---------------------" << endl;
|
||||
@@ -319,14 +312,11 @@ int main( int argc, const char** argv )
|
||||
|
||||
imshow("Current LP", frame);
|
||||
waitKey(5);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
outputdatafile.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void outputStats(vector<double> datapoints)
|
||||
@@ -341,5 +331,4 @@ void outputStats(vector<double> datapoints)
|
||||
double stdev = std::sqrt(sq_sum / datapoints.size());
|
||||
|
||||
cout << "\t" << datapoints.size() << " samples, avg: " << mean << "ms, stdev: " << stdev << endl;
|
||||
|
||||
}
|
||||
|
@@ -66,7 +66,6 @@ vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
|
||||
string inDir;
|
||||
string outDir;
|
||||
Mat frame;
|
||||
@@ -76,7 +75,6 @@ int main( int argc, const char** argv )
|
||||
{
|
||||
inDir = argv[1];
|
||||
outDir = argv[2];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -227,7 +225,6 @@ int main( int argc, const char** argv )
|
||||
// Save
|
||||
if (somethingSelected && chardataTagged)
|
||||
{
|
||||
|
||||
for (int c = 0; c < charSegmenter.characters.size(); c++)
|
||||
{
|
||||
if (humanInputs[c] == ' ')
|
||||
@@ -253,19 +250,15 @@ int main( int argc, const char** argv )
|
||||
}
|
||||
|
||||
waitkey = (char) waitKey(50);
|
||||
|
||||
}
|
||||
|
||||
if (waitkey == 'p')
|
||||
i = i - 2;
|
||||
if (i < -1)
|
||||
i = -1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
|
||||
@@ -286,7 +279,7 @@ void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selected
|
||||
{
|
||||
rectangle(imgCopy, Point(1,1), Point(imgCopy.size().width - 1, imgCopy.size().height -1), Scalar(0, 255, 0), 1);
|
||||
}
|
||||
if (selectedImages[i] == true)
|
||||
if (selectedImages[i])
|
||||
{
|
||||
rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1);
|
||||
}
|
||||
@@ -351,7 +344,6 @@ vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state
|
||||
if (humanInputs[i] != (char) SPACE_KEY)
|
||||
cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
destroyWindow("Character selector");
|
||||
|
@@ -33,14 +33,12 @@ using namespace cv;
|
||||
// Also creates a box file so Tesseract can recognize it
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
|
||||
string inDir;
|
||||
|
||||
//Check if user specify image to process
|
||||
if(argc == 2)
|
||||
{
|
||||
inDir = argv[1];
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -149,15 +147,11 @@ int main( int argc, const char** argv )
|
||||
//imshow("characterImg", cropped);
|
||||
|
||||
waitKey(2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
imwrite("combined.tif", bigTif);
|
||||
ofstream boxFile("combined.box", std::ios::out);
|
||||
boxFile << boxFileOut.str();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -40,7 +40,6 @@ bool detectPlate( StateIdentifier* identifier, Mat frame);
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
|
||||
string inDir;
|
||||
string outDir;
|
||||
Mat frame;
|
||||
@@ -51,7 +50,6 @@ int main( int argc, const char** argv )
|
||||
inDir = argv[1];
|
||||
outDir = argv[2];
|
||||
outDir = outDir + "/";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -107,10 +105,8 @@ int main( int argc, const char** argv )
|
||||
else
|
||||
waitKey(50);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool detectPlate( StateIdentifier* identifier, Mat frame);
|
||||
|
@@ -26,15 +26,16 @@ Alpr::Alpr(const std::string country, const std::string runtimeDir)
|
||||
{
|
||||
impl = new AlprImpl(country, runtimeDir);
|
||||
}
|
||||
|
||||
Alpr::~Alpr()
|
||||
{
|
||||
delete impl;
|
||||
}
|
||||
|
||||
std::vector<AlprResult> Alpr::recognize(std::string filepath)
|
||||
{
|
||||
cv::Mat img = cv::imread(filepath, CV_LOAD_IMAGE_COLOR);
|
||||
return impl->recognize(img);
|
||||
|
||||
}
|
||||
|
||||
std::vector<AlprResult> Alpr::recognize(std::vector<unsigned char> imageBuffer)
|
||||
@@ -54,10 +55,12 @@ void Alpr::setDetectRegion(bool detectRegion)
|
||||
{
|
||||
impl->setDetectRegion(detectRegion);
|
||||
}
|
||||
|
||||
void Alpr::setTopN(int topN)
|
||||
{
|
||||
impl->setTopN(topN);
|
||||
}
|
||||
|
||||
void Alpr::setDefaultRegion(std::string region)
|
||||
{
|
||||
impl->setDefaultRegion(region);
|
||||
@@ -72,9 +75,8 @@ bool Alpr::isLoaded()
|
||||
|
||||
AlprResult::AlprResult()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AlprResult::~AlprResult()
|
||||
{
|
||||
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ALPR_H
|
||||
#define ALPR_H
|
||||
|
||||
@@ -60,8 +59,6 @@ class AlprResult
|
||||
std::string region;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AlprImpl;
|
||||
class Alpr
|
||||
{
|
||||
|
@@ -32,7 +32,6 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
|
||||
|
||||
if (config->opencl_enabled)
|
||||
{
|
||||
|
||||
cv::ocl::PlatformsInfo platinfo;
|
||||
cv::ocl::getOpenCLPlatforms(platinfo);
|
||||
|
||||
@@ -59,6 +58,7 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlprImpl::~AlprImpl()
|
||||
{
|
||||
delete config;
|
||||
@@ -155,14 +155,12 @@ std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
|
||||
for (int z = 0; z < 4; z++)
|
||||
line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (config->debugGeneral)
|
||||
rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (config->debugTiming)
|
||||
@@ -248,10 +246,12 @@ void AlprImpl::setDetectRegion(bool detectRegion)
|
||||
{
|
||||
this->detectRegion = detectRegion;
|
||||
}
|
||||
|
||||
void AlprImpl::setTopN(int topn)
|
||||
{
|
||||
this->topN = topn;
|
||||
}
|
||||
|
||||
void AlprImpl::setDefaultRegion(string region)
|
||||
{
|
||||
this->defaultRegion = region;
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ALPRIMPL_H
|
||||
#define ALPRIMPL_H
|
||||
|
||||
@@ -35,8 +34,6 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include "opencv2/ocl/ocl.hpp"
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_TOPN 25
|
||||
#define DEFAULT_DETECT_REGION false
|
||||
|
||||
|
@@ -40,7 +40,6 @@
|
||||
|
||||
float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
|
||||
{
|
||||
|
||||
float m,s,max_s;
|
||||
long sum, sum_sq;
|
||||
uchar foo;
|
||||
@@ -73,7 +72,6 @@ float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
|
||||
// Shift the window, add and remove new/old values to the histogram
|
||||
for (int i=1 ; i <= im.cols-winx; i++)
|
||||
{
|
||||
|
||||
// Remove the left old column and add the right new column
|
||||
for (int wy=0; wy<winy; ++wy)
|
||||
{
|
||||
@@ -103,7 +101,6 @@ float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
|
||||
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
|
||||
int winx, int winy, float k)
|
||||
{
|
||||
|
||||
float dR = BINARIZEWOLF_DEFAULTDR;
|
||||
|
||||
float m, s, max_s;
|
||||
@@ -131,18 +128,15 @@ void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
|
||||
|
||||
for (int j = y_firstth ; j<=y_lastth; j++)
|
||||
{
|
||||
|
||||
// NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
|
||||
for (int i=0 ; i <= im.cols-winx; i++)
|
||||
{
|
||||
|
||||
m = map_m.fget(i+wxh, j);
|
||||
s = map_s.fget(i+wxh, j);
|
||||
|
||||
// Calculate the threshold
|
||||
switch (version)
|
||||
{
|
||||
|
||||
case NIBLACK:
|
||||
th = m + k*s;
|
||||
break;
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BINARIZEWOLF_H
|
||||
#define BINARIZEWOLF_H
|
||||
|
||||
@@ -40,17 +39,12 @@ enum NiblackVersion
|
||||
#define BINARIZEWOLF_VERSION "2.3 (February 26th, 2013)"
|
||||
#define BINARIZEWOLF_DEFAULTDR 128
|
||||
|
||||
|
||||
#define uget(x,y) at<unsigned char>(y,x)
|
||||
#define uset(x,y,v) at<unsigned char>(y,x)=v;
|
||||
#define fget(x,y) at<float>(y,x)
|
||||
#define fset(x,y,v) at<float>(y,x)=v;
|
||||
|
||||
|
||||
|
||||
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
|
||||
int winx, int winy, float k);
|
||||
|
||||
|
||||
|
||||
#endif // BINARIZEWOLF_H
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
CharacterAnalysis::CharacterAnalysis(Mat img, Config* config)
|
||||
{
|
||||
|
||||
this->config = config;
|
||||
|
||||
this->hasPlateMask = false;
|
||||
@@ -36,7 +35,6 @@ CharacterAnalysis::CharacterAnalysis(Mat img, Config* config)
|
||||
img_gray = Mat(img.size(), img.type());
|
||||
img.copyTo(img_gray);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CharacterAnalysis::~CharacterAnalysis()
|
||||
@@ -50,7 +48,6 @@ CharacterAnalysis::~CharacterAnalysis()
|
||||
|
||||
void CharacterAnalysis::analyze()
|
||||
{
|
||||
|
||||
thresholds = produceThresholds(img_gray, config);
|
||||
|
||||
/*
|
||||
@@ -64,7 +61,6 @@ void CharacterAnalysis::analyze()
|
||||
//morphologyEx( mask, mask, MORPH_CLOSE, element );
|
||||
morphologyEx( thresholds[i], thresholds[i], MORPH_OPEN, element );
|
||||
//dilate( thresholds[i], thresholds[i], element );
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -129,7 +125,6 @@ void CharacterAnalysis::analyze()
|
||||
int bestFitIndex = -1;
|
||||
for (int i = 0; i < thresholds.size(); i++)
|
||||
{
|
||||
|
||||
//vector<bool> goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]);
|
||||
//charSegments.push_back(goodIndices);
|
||||
|
||||
@@ -157,7 +152,6 @@ void CharacterAnalysis::analyze()
|
||||
|
||||
if (this->config->debugCharAnalysis)
|
||||
{
|
||||
|
||||
Mat img_contours(bestThreshold.size(), CV_8U);
|
||||
bestThreshold.copyTo(img_contours);
|
||||
cvtColor(img_contours, img_contours, CV_GRAY2RGB);
|
||||
@@ -201,12 +195,10 @@ void CharacterAnalysis::analyze()
|
||||
this->charBoxBottom = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[2].x, this->charArea[2].y);
|
||||
this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y);
|
||||
this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this->thresholdsInverted = isPlateInverted();
|
||||
|
||||
}
|
||||
|
||||
int CharacterAnalysis::getGoodIndicesCount(vector<bool> goodIndices)
|
||||
@@ -269,7 +261,6 @@ Mat CharacterAnalysis::findOuterBoxMask()
|
||||
lowestArea = boxArea;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this->config->debugCharAnalysis)
|
||||
@@ -356,7 +347,6 @@ Mat CharacterAnalysis::findOuterBoxMask()
|
||||
allHierarchy[winningIndex],
|
||||
0
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if (this->config->debugCharAnalysis)
|
||||
@@ -382,12 +372,10 @@ Mat CharacterAnalysis::findOuterBoxMask()
|
||||
Mat fullMask = Mat::zeros(thresholds[0].size(), CV_8U);
|
||||
bitwise_not(fullMask, fullMask);
|
||||
return fullMask;
|
||||
|
||||
}
|
||||
|
||||
Mat CharacterAnalysis::getCharacterMask()
|
||||
{
|
||||
|
||||
Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U);
|
||||
|
||||
for (int i = 0; i < bestContours.size(); i++)
|
||||
@@ -421,7 +409,6 @@ Mat CharacterAnalysis::getCharacterMask()
|
||||
// Returns a polygon "stripe" across the width of the character region. The lines are voted and the polygon starts at 0 and extends to image width
|
||||
vector<Point> CharacterAnalysis::getBestVotedLines(Mat img, vector<vector<Point> > contours, vector<bool> goodIndices)
|
||||
{
|
||||
|
||||
//if (this->debug)
|
||||
// cout << "CharacterAnalysis::getBestVotedLines" << endl;
|
||||
|
||||
@@ -519,7 +506,6 @@ vector<Point> CharacterAnalysis::getBestVotedLines(Mat img, vector<vector<Point>
|
||||
int curScore = 0;
|
||||
for (int charidx = 0; charidx < charRegions.size(); charidx++)
|
||||
{
|
||||
|
||||
float topYPos = topLines[i].getPointAt(charRegions[charidx].x);
|
||||
float botYPos = bottomLines[i].getPointAt(charRegions[charidx].x);
|
||||
|
||||
@@ -535,7 +521,6 @@ vector<Point> CharacterAnalysis::getBestVotedLines(Mat img, vector<vector<Point>
|
||||
|
||||
//cout << "Slope: " << topslope << " yPos: " << topYPos << endl;
|
||||
//drawAndWait(&tempImg);
|
||||
|
||||
}
|
||||
|
||||
// Tie goes to the one with longer line segments
|
||||
@@ -573,7 +558,6 @@ vector<Point> CharacterAnalysis::getBestVotedLines(Mat img, vector<vector<Point>
|
||||
bestStripe.push_back(topRight);
|
||||
bestStripe.push_back(bottomRight);
|
||||
bestStripe.push_back(bottomLeft);
|
||||
|
||||
}
|
||||
|
||||
return bestStripe;
|
||||
@@ -624,7 +608,6 @@ vector<bool> CharacterAnalysis::filter(Mat img, vector<vector<Point> > contours,
|
||||
// Goes through the contours for the plate and picks out possible char segments based on min/max height
|
||||
vector<bool> CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contours, vector<bool> goodIndices, int minHeightPx, int maxHeightPx)
|
||||
{
|
||||
|
||||
float idealAspect=config->charWidthMM / config->charHeightMM;
|
||||
float aspecttolerance=0.25;
|
||||
|
||||
@@ -645,7 +628,6 @@ vector<bool> CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contour
|
||||
//Mat auxRoi(img, mr);
|
||||
if(mr.height >= minHeightPx && mr.height <= maxHeightPx && mr.width > minWidth)
|
||||
{
|
||||
|
||||
float charAspect= (float)mr.width/(float)mr.height;
|
||||
|
||||
if (abs(charAspect - idealAspect) < aspecttolerance)
|
||||
@@ -654,12 +636,10 @@ vector<bool> CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contour
|
||||
}
|
||||
|
||||
return includedIndices;
|
||||
|
||||
}
|
||||
|
||||
vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > contours, vector< Vec4i > hierarchy, vector< bool > goodIndices)
|
||||
{
|
||||
|
||||
vector<bool> includedIndices(contours.size());
|
||||
for (int j = 0; j < contours.size(); j++)
|
||||
includedIndices.push_back(false);
|
||||
@@ -671,7 +651,7 @@ vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > c
|
||||
|
||||
int parentIndex = hierarchy[i][3];
|
||||
|
||||
if (parentIndex >= 0 && goodIndices[parentIndex] == true)
|
||||
if (parentIndex >= 0 && goodIndices[parentIndex])
|
||||
{
|
||||
// this contour is a child of an already identified contour. REMOVE it
|
||||
if (this->config->debugCharAnalysis)
|
||||
@@ -692,7 +672,6 @@ vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > c
|
||||
// returns a vector of indices corresponding to valid contours
|
||||
vector<bool> CharacterAnalysis::filterByParentContour( vector< vector< Point> > contours, vector<Vec4i> hierarchy, vector<bool> goodIndices)
|
||||
{
|
||||
|
||||
vector<bool> includedIndices(contours.size());
|
||||
for (int j = 0; j < contours.size(); j++)
|
||||
includedIndices[j] = false;
|
||||
@@ -725,7 +704,6 @@ vector<bool> CharacterAnalysis::filterByParentContour( vector< vector< Point> >
|
||||
{
|
||||
votes[voteIndex] = votes[voteIndex] + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Tally up the votes, pick the winner
|
||||
@@ -816,7 +794,6 @@ vector<bool> CharacterAnalysis::filterBetweenLines(Mat img, vector<vector<Point>
|
||||
for (int tempContourIdx = 0; tempContourIdx < tempContours.size(); tempContourIdx++)
|
||||
{
|
||||
areaBetweenLines += contourArea(tempContours[tempContourIdx]);
|
||||
|
||||
}
|
||||
|
||||
if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES)
|
||||
@@ -882,7 +859,6 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point >
|
||||
|
||||
bool CharacterAnalysis::isPlateInverted()
|
||||
{
|
||||
|
||||
Mat charMask = getCharacterMask();
|
||||
|
||||
Scalar meanVal = mean(bestThreshold, charMask)[0];
|
||||
@@ -920,7 +896,6 @@ bool CharacterAnalysis::verifySize(Mat r, float minHeightPx, float maxHeightPx)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
vector<Point> CharacterAnalysis::getCharArea()
|
||||
|
@@ -17,8 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CHARACTERANALYSIS_H
|
||||
#define CHARACTERANALYSIS_H
|
||||
|
||||
@@ -30,7 +28,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CharacterAnalysis
|
||||
{
|
||||
|
||||
@@ -68,8 +65,6 @@ class CharacterAnalysis
|
||||
|
||||
Mat getCharacterMask();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
Config* config;
|
||||
|
||||
@@ -77,7 +72,6 @@ class CharacterAnalysis
|
||||
|
||||
Mat findOuterBoxMask( );
|
||||
|
||||
|
||||
bool isPlateInverted();
|
||||
vector<bool> filter(Mat img, vector<vector<Point> > contours, vector<Vec4i> hierarchy);
|
||||
|
||||
@@ -95,7 +89,6 @@ class CharacterAnalysis
|
||||
|
||||
int getGoodIndicesCount(vector<bool> goodIndices);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // CHARACTERANALYSIS_H
|
||||
|
@@ -96,7 +96,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
|
||||
|
||||
if (charAnalysis->linePolygon.size() > 0)
|
||||
{
|
||||
|
||||
int confidenceDrainers = 0;
|
||||
int charSegmentCount = charAnalysis->bestCharSegmentsCount;
|
||||
if (charSegmentCount == 1)
|
||||
@@ -114,7 +113,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
|
||||
this->confidence=1;
|
||||
else
|
||||
this->confidence = 100 - confidenceDrainers;
|
||||
|
||||
}
|
||||
|
||||
if (config->debugTiming)
|
||||
@@ -123,7 +121,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
|
||||
getTime(&endTime);
|
||||
cout << "Character Region Time: " << diffclock(startTime, endTime) << "ms." << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CharacterRegion::~CharacterRegion()
|
||||
|
@@ -17,8 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CHARACTERREGION_H
|
||||
#define CHARACTERREGION_H
|
||||
|
||||
@@ -31,7 +29,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
class CharacterRegion
|
||||
{
|
||||
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* config)
|
||||
{
|
||||
|
||||
this->config = config;
|
||||
|
||||
this->confidence = 0;
|
||||
@@ -52,7 +51,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
|
||||
|
||||
if (this->config->debugCharSegmenter)
|
||||
{
|
||||
|
||||
Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U);
|
||||
charAnalysis->bestThreshold.copyTo(img_contours);
|
||||
cvtColor(img_contours, img_contours, CV_GRAY2RGB);
|
||||
@@ -118,7 +116,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
|
||||
vector<Rect> allBoxes;
|
||||
for (int i = 0; i < charAnalysis->allContours.size(); i++)
|
||||
{
|
||||
|
||||
Mat histogramMask = Mat::zeros(charAnalysis->thresholds[i].size(), CV_8U);
|
||||
|
||||
fillConvexPoly(histogramMask, charAnalysis->linePolygon.data(), charAnalysis->linePolygon.size(), Scalar(255,255,255));
|
||||
@@ -215,7 +212,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
|
||||
|
||||
if (this->config->debugCharSegmenter)
|
||||
{
|
||||
|
||||
Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3);
|
||||
displayImage(config, "Segmentation after cleaning", imgDash);
|
||||
|
||||
@@ -257,7 +253,6 @@ vector<Rect> CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram,
|
||||
|
||||
for (int i = 0; i < allBoxes.size(); i++)
|
||||
{
|
||||
|
||||
if (allBoxes[i].width >= config->segmentationMinBoxWidthPx && allBoxes[i].width <= MAX_SEGMENT_WIDTH &&
|
||||
allBoxes[i].height > MIN_HISTOGRAM_HEIGHT )
|
||||
{
|
||||
@@ -292,7 +287,6 @@ vector<Rect> CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram,
|
||||
charBoxes.push_back(Rect(topLeft, allBoxes[i].br()) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return charBoxes;
|
||||
@@ -300,7 +294,6 @@ vector<Rect> CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram,
|
||||
|
||||
vector<Rect> CharacterSegmenter::getBestCharBoxes(Mat img, vector<Rect> charBoxes, float avgCharWidth)
|
||||
{
|
||||
|
||||
float MAX_SEGMENT_WIDTH = avgCharWidth * 1.55;
|
||||
|
||||
// This histogram is based on how many char boxes (from ALL of the many thresholded images) are covering each column
|
||||
@@ -410,7 +403,6 @@ vector<Rect> CharacterSegmenter::getBestCharBoxes(Mat img, vector<Rect> charBoxe
|
||||
|
||||
this->imgDbgGeneral.push_back(addLabel(histoImg, "All Histograms"));
|
||||
this->imgDbgGeneral.push_back(addLabel(imgBestBoxes, "Best Boxes"));
|
||||
|
||||
}
|
||||
|
||||
return bestBoxes;
|
||||
@@ -432,8 +424,7 @@ vector<Rect> CharacterSegmenter::get1DHits(Mat img, int yOffset)
|
||||
curSegmentLength++;
|
||||
}
|
||||
|
||||
if ((isOn == false && onSegment == true) ||
|
||||
(col == img.cols - 1 && onSegment == true))
|
||||
if (onSegment && (isOn == false || (col == img.cols - 1)))
|
||||
{
|
||||
// A segment just ended or we're at the very end of the row and we're on a segment
|
||||
Point topLeft = Point(col - curSegmentLength, top.getPointAt(col - curSegmentLength) - 1);
|
||||
@@ -443,7 +434,6 @@ vector<Rect> CharacterSegmenter::get1DHits(Mat img, int yOffset)
|
||||
onSegment = false;
|
||||
curSegmentLength = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return hits;
|
||||
@@ -456,7 +446,6 @@ void CharacterSegmenter::removeSmallContours(vector<Mat> thresholds, vector<vect
|
||||
|
||||
for (int i = 0; i < thresholds.size(); i++)
|
||||
{
|
||||
|
||||
for (int c = 0; c < allContours[i].size(); c++)
|
||||
{
|
||||
if (allContours[i][c].size() == 0)
|
||||
@@ -469,7 +458,6 @@ void CharacterSegmenter::removeSmallContours(vector<Mat> thresholds, vector<vect
|
||||
drawContours(thresholds[i], allContours[i], c, Scalar(0, 0, 0), -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,7 +501,6 @@ vector<Rect> CharacterSegmenter::combineCloseBoxes( vector<Rect> charBoxes, floa
|
||||
{
|
||||
newCharBoxes.push_back(charBoxes[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return newCharBoxes;
|
||||
@@ -577,14 +564,12 @@ void CharacterSegmenter::cleanCharRegions(vector<Mat> thresholds, vector<Rect> c
|
||||
tallestContourHeight = r.height;
|
||||
|
||||
totalArea += contourArea(contours[c]);
|
||||
|
||||
}
|
||||
//else if (r.height > tallestContourHeight)
|
||||
//{
|
||||
// tallestContourIndex = c;
|
||||
// tallestContourHeight = h;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
if (totalArea < MIN_CONTOUR_AREA)
|
||||
@@ -612,7 +597,6 @@ void CharacterSegmenter::cleanCharRegions(vector<Mat> thresholds, vector<Rect> c
|
||||
}
|
||||
rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Mat closureElement = getStructuringElement( 1,
|
||||
@@ -633,7 +617,6 @@ void CharacterSegmenter::cleanCharRegions(vector<Mat> thresholds, vector<Rect> c
|
||||
line(thresholds[i], Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y), Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CharacterSegmenter::cleanBasedOnColor(vector<Mat> thresholds, Mat colorMask, vector<Rect> charRegions)
|
||||
@@ -644,10 +627,8 @@ void CharacterSegmenter::cleanBasedOnColor(vector<Mat> thresholds, Mat colorMask
|
||||
|
||||
for (int i = 0; i < thresholds.size(); i++)
|
||||
{
|
||||
|
||||
for (int j = 0; j < charRegions.size(); j++)
|
||||
{
|
||||
|
||||
Mat boxChar = Mat::zeros(thresholds[i].size(), CV_8U);
|
||||
rectangle(boxChar, charRegions[j], Scalar(255,255,255), CV_FILLED);
|
||||
|
||||
@@ -687,7 +668,6 @@ void CharacterSegmenter::cleanBasedOnColor(vector<Mat> thresholds, Mat colorMask
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,6 +696,7 @@ void CharacterSegmenter::cleanMostlyFullBoxes(vector<Mat> thresholds, const vect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<Rect> CharacterSegmenter::filterMostlyEmptyBoxes(vector<Mat> thresholds, const vector<Rect> charRegions)
|
||||
{
|
||||
// Of the n thresholded images, if box 3 (for example) is empty in half (for example) of the thresholded images,
|
||||
@@ -733,7 +714,6 @@ vector<Rect> CharacterSegmenter::filterMostlyEmptyBoxes(vector<Mat> thresholds,
|
||||
|
||||
for (int i = 0; i < thresholds.size(); i++)
|
||||
{
|
||||
|
||||
for (int j = 0; j < charRegions.size(); j++)
|
||||
{
|
||||
//float minArea = charRegions[j].area() * MIN_AREA_PERCENT;
|
||||
@@ -755,7 +735,6 @@ vector<Rect> CharacterSegmenter::filterMostlyEmptyBoxes(vector<Mat> thresholds,
|
||||
|
||||
for (int z = 0; z < contours[c].size(); z++)
|
||||
allPointsInBox.push_back(contours[c][z]);
|
||||
|
||||
}
|
||||
|
||||
float height = 0;
|
||||
@@ -772,9 +751,7 @@ vector<Rect> CharacterSegmenter::filterMostlyEmptyBoxes(vector<Mat> thresholds,
|
||||
{
|
||||
drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vector<Rect> newCharRegions;
|
||||
@@ -809,7 +786,6 @@ vector<Rect> CharacterSegmenter::filterMostlyEmptyBoxes(vector<Mat> thresholds,
|
||||
|
||||
drawX(imgDbgCleanStages[z], charRegions[i], COLOR_DEBUG_EMPTYFILTER, 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,7 +855,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Re
|
||||
int col = charRegions[0].x + charRegions[0].width;
|
||||
while (col >= 0)
|
||||
{
|
||||
|
||||
int rowLength = getLongestBlobLengthBetweenLines(rotated, col);
|
||||
|
||||
if (rowLength > MIN_CONNECTED_EDGE_PIXELS)
|
||||
@@ -894,7 +869,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Re
|
||||
col = charRegions[charRegions.size() - 1].x;
|
||||
while (col < rotated.cols)
|
||||
{
|
||||
|
||||
int rowLength = getLongestBlobLengthBetweenLines(rotated, col);
|
||||
|
||||
if (rowLength > MIN_CONNECTED_EDGE_PIXELS)
|
||||
@@ -909,7 +883,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Re
|
||||
leftEdges.push_back(leftEdgeX);
|
||||
if (rightEdgeX != thresholds[i].cols)
|
||||
rightEdges.push_back(rightEdgeX);
|
||||
|
||||
}
|
||||
|
||||
int leftEdge = 0;
|
||||
@@ -1032,7 +1005,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Re
|
||||
// for now, just mask the whole thing
|
||||
if (this->debug)
|
||||
{
|
||||
|
||||
rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2);
|
||||
cout << "Edge Filter: threshold " << i << " box " << boxidx << endl;
|
||||
}
|
||||
@@ -1045,12 +1017,10 @@ void CharacterSegmenter::filterEdgeBoxes(vector<Mat> thresholds, const vector<Re
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
|
||||
{
|
||||
|
||||
int longestBlobLength = 0;
|
||||
|
||||
bool onSegment = false;
|
||||
@@ -1083,8 +1053,7 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
|
||||
wasbetweenLines = true;
|
||||
}
|
||||
|
||||
if ((isOn == false && onSegment == true) ||
|
||||
(row == img.rows - 1 && onSegment == true))
|
||||
if (onSegment && (isOn == false || (row == img.rows - 1)))
|
||||
{
|
||||
if (wasbetweenLines && curSegmentLength > longestBlobLength)
|
||||
longestBlobLength = curSegmentLength;
|
||||
@@ -1093,7 +1062,6 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
|
||||
isbetweenLines = false;
|
||||
curSegmentLength = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return longestBlobLength;
|
||||
@@ -1145,7 +1113,6 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector<ve
|
||||
|
||||
if (tallestContourIdx != -1)
|
||||
{
|
||||
|
||||
//cout << "Edge Filter: " << tallestContourHeight << " -- " << avgCharHeight << endl;
|
||||
if (tallestContourHeight >= avgCharHeight * 0.9 &&
|
||||
((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1)))
|
||||
@@ -1162,7 +1129,6 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector<ve
|
||||
|
||||
Mat CharacterSegmenter::getCharBoxMask(Mat img_threshold, vector<Rect> charBoxes)
|
||||
{
|
||||
|
||||
Mat mask = Mat::zeros(img_threshold.size(), CV_8U);
|
||||
for (int i = 0; i < charBoxes.size(); i++)
|
||||
rectangle(mask, charBoxes[i], Scalar(255, 255, 255), -1);
|
||||
|
@@ -17,8 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CHARACTERSEGMENTER_H
|
||||
#define CHARACTERSEGMENTER_H
|
||||
|
||||
|
@@ -62,7 +62,6 @@ typedef struct cJSON_Hooks
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
|
||||
extern cJSON *cJSON_Parse(const char *value);
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
|
||||
{
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
@@ -54,7 +53,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
|
||||
|
||||
ColorFilter::~ColorFilter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ColorFilter::imageIsGrayscale(Mat image)
|
||||
@@ -163,7 +161,6 @@ void ColorFilter::findCharColors()
|
||||
hStdDevs.push_back(stddev[0]);
|
||||
sStdDevs.push_back(stddev[1]);
|
||||
vStdDevs.push_back(stddev[2]);
|
||||
|
||||
}
|
||||
|
||||
if (hMeans.size() == 0)
|
||||
@@ -362,7 +359,6 @@ void ColorFilter::findCharColors()
|
||||
Mat dashboard = drawImageDashboard(debugImagesSet, imgDebugHueOnly.type(), 3);
|
||||
displayImage(config, "Color Filter Images", dashboard);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Goes through an array of values, picks the winner based on the highest percentage of other values that are within the maxValDifference
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef COLORFILTER_H
|
||||
#define COLORFILTER_H
|
||||
|
||||
@@ -31,8 +30,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
class ColorFilter
|
||||
{
|
||||
|
||||
@@ -42,8 +39,6 @@ class ColorFilter
|
||||
|
||||
Mat colorMask;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Config* config;
|
||||
@@ -52,7 +47,6 @@ class ColorFilter
|
||||
Mat hsv;
|
||||
Mat charMask;
|
||||
|
||||
|
||||
bool grayscale;
|
||||
|
||||
void preprocessImage();
|
||||
|
@@ -30,7 +30,6 @@ Config::Config(const std::string country, const std::string runtimeBaseDir)
|
||||
if (runtimeBaseDir.compare("") != 0)
|
||||
{
|
||||
// User has supplied a runtime directory. Use that.
|
||||
|
||||
}
|
||||
else if (envRuntimeDir!=NULL)
|
||||
{
|
||||
@@ -62,6 +61,7 @@ Config::Config(const std::string country, const std::string runtimeBaseDir)
|
||||
|
||||
loadValues(country);
|
||||
}
|
||||
|
||||
Config::~Config()
|
||||
{
|
||||
delete ini;
|
||||
@@ -69,7 +69,6 @@ Config::~Config()
|
||||
|
||||
void Config::loadValues(string country)
|
||||
{
|
||||
|
||||
opencl_enabled = getBoolean("common", "opencl_enabled", false);
|
||||
|
||||
detection_iteration_increase = getFloat("common", "detection_iteration_increase", 1.1);
|
||||
@@ -132,7 +131,6 @@ void Config::loadValues(string country)
|
||||
debugOcr = getBoolean("debug", "ocr", false);
|
||||
debugPostProcess = getBoolean("debug", "postprocess", false);
|
||||
debugShowImages = getBoolean("debug", "show_images", false);
|
||||
|
||||
}
|
||||
|
||||
void Config::debugOff()
|
||||
@@ -154,14 +152,17 @@ string Config::getCascadeRuntimeDir()
|
||||
{
|
||||
return this->runtimeBaseDir + CASCADE_DIR;
|
||||
}
|
||||
|
||||
string Config::getKeypointsRuntimeDir()
|
||||
{
|
||||
return this->runtimeBaseDir + KEYPOINTS_DIR;
|
||||
}
|
||||
|
||||
string Config::getPostProcessRuntimeDir()
|
||||
{
|
||||
return this->runtimeBaseDir + POSTPROCESS_DIR;
|
||||
}
|
||||
|
||||
string Config::getTessdataPrefix()
|
||||
{
|
||||
return "TESSDATA_PREFIX=" + this->runtimeBaseDir + "/ocr/";
|
||||
@@ -179,6 +180,7 @@ float Config::getFloat(string section, string key, float defaultValue)
|
||||
float val = atof(pszValue);
|
||||
return val;
|
||||
}
|
||||
|
||||
int Config::getInt(string section, string key, int defaultValue)
|
||||
{
|
||||
const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/);
|
||||
@@ -191,6 +193,7 @@ int Config::getInt(string section, string key, int defaultValue)
|
||||
int val = atoi(pszValue);
|
||||
return val;
|
||||
}
|
||||
|
||||
bool Config::getBoolean(string section, string key, bool defaultValue)
|
||||
{
|
||||
const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/);
|
||||
@@ -203,6 +206,7 @@ bool Config::getBoolean(string section, string key, bool defaultValue)
|
||||
int val = atoi(pszValue);
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
string Config::getString(string section, string key, string defaultValue)
|
||||
{
|
||||
const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/);
|
||||
|
@@ -17,11 +17,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
|
||||
#include "simpleini/simpleini.h"
|
||||
#include "support/filesystem.h"
|
||||
|
||||
@@ -91,7 +89,6 @@ class Config
|
||||
int postProcessMinCharacters;
|
||||
int postProcessMaxCharacters;
|
||||
|
||||
|
||||
bool debugGeneral;
|
||||
bool debugTiming;
|
||||
bool debugStateId;
|
||||
@@ -125,5 +122,4 @@ class Config
|
||||
bool getBoolean(string section, string key, bool defaultValue);
|
||||
};
|
||||
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
@@ -45,7 +45,6 @@ FeatureMatcher::~FeatureMatcher()
|
||||
descriptorMatcher.release();
|
||||
detector.release();
|
||||
extractor.release();
|
||||
|
||||
}
|
||||
|
||||
bool FeatureMatcher::isLoaded()
|
||||
@@ -78,7 +77,6 @@ void FeatureMatcher::surfStyleMatching( const Mat& queryDescriptors, vector<KeyP
|
||||
|
||||
void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector<vector<DMatch> > matchesKnn, vector<DMatch>& matches12)
|
||||
{
|
||||
|
||||
//objectMatches.clear();
|
||||
//objectMatches.resize(objectIds.size());
|
||||
//cout << "starting matcher" << matchesKnn.size() << endl;
|
||||
@@ -90,7 +88,6 @@ void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector<vect
|
||||
// Check to make sure we have 2 matches. I think this is always the case, but it doesn't hurt to be sure
|
||||
if (matchesKnn[descInd].size() > 1)
|
||||
{
|
||||
|
||||
// Next throw out matches with a crappy score
|
||||
// Ignore... already handled by the radiusMatch
|
||||
//if (matchesKnn[descInd][0].distance < MAX_DISTANCE_TO_MATCH)
|
||||
@@ -140,19 +137,15 @@ void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector<vect
|
||||
|
||||
//for (unsigned int first_index = 0; first_index < matches.size(); ++first_index)
|
||||
//{
|
||||
|
||||
//matches12.push_back(match);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Compares the matches keypoints for parallel lines. Removes matches that are criss-crossing too much
|
||||
// We assume that license plates won't be upside-down or backwards. So expect lines to be closely parallel
|
||||
void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints, const vector<DMatch> inputMatches, vector<DMatch> &outputMatches)
|
||||
{
|
||||
|
||||
Rect crissCrossAreaVertical(0, 0, config->stateIdImageWidthPx, config->stateIdimageHeightPx * 2);
|
||||
Rect crissCrossAreaHorizontal(0, 0, config->stateIdImageWidthPx * 2, config->stateIdimageHeightPx);
|
||||
|
||||
@@ -222,7 +215,6 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
|
||||
hlines.erase(hlines.begin() + mostIntersectionsIndex);
|
||||
matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Push the non-crisscrosses back on the list
|
||||
@@ -231,7 +223,6 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
|
||||
outputMatches.push_back(matchesForOnePlate[matchIdx[j]]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns true if successful, false otherwise
|
||||
@@ -276,7 +267,6 @@ bool FeatureMatcher::loadRecognitionSet(string country)
|
||||
trainImages.push_back(descriptors);
|
||||
trainingImgKeypoints.push_back(keypoints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this->descriptorMatcher->add(trainImages);
|
||||
@@ -286,7 +276,6 @@ bool FeatureMatcher::loadRecognitionSet(string country)
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage,
|
||||
@@ -374,9 +363,8 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma
|
||||
drawKeypoints( queryImg, queryKeypoints, tmpImg, CV_RGB(185, 0, 0), DrawMatchesFlags::DEFAULT );
|
||||
drawKeypoints( tmpImg, positiveMatches, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT );
|
||||
|
||||
if (result.haswinner == true)
|
||||
if (result.haswinner)
|
||||
{
|
||||
|
||||
std::ostringstream out;
|
||||
out << result.winner << " (" << result.confidence << "%)";
|
||||
|
||||
@@ -384,19 +372,15 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma
|
||||
//putText(*outputImage, out.str(), Point(15, 27), FONT_HERSHEY_DUPLEX, 1.1, CV_RGB(0, 0, 0), 2);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this->config->debugStateId)
|
||||
{
|
||||
|
||||
for (int i = 0; i < billMapping.size(); i++)
|
||||
{
|
||||
cout << billMapping[i] << " : " << bill_match_counts[i] << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
@@ -17,9 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef FEATUREMATCHER_H
|
||||
#define FEATUREMATCHER_H
|
||||
|
||||
@@ -36,8 +33,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
struct RecognitionResult
|
||||
{
|
||||
bool haswinner;
|
||||
@@ -52,12 +47,9 @@ class FeatureMatcher
|
||||
FeatureMatcher(Config* config);
|
||||
virtual ~FeatureMatcher();
|
||||
|
||||
|
||||
|
||||
RecognitionResult recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage,
|
||||
bool debug_on, vector<int> debug_matches_array );
|
||||
|
||||
|
||||
bool loadRecognitionSet(string country);
|
||||
|
||||
bool isLoaded();
|
||||
@@ -71,18 +63,14 @@ class FeatureMatcher
|
||||
Ptr<FastFeatureDetector> detector;
|
||||
Ptr<BRISK> extractor;
|
||||
|
||||
|
||||
vector<vector<KeyPoint> > trainingImgKeypoints;
|
||||
|
||||
|
||||
void _surfStyleMatching(const Mat& queryDescriptors, vector<vector<DMatch> > matchesKnn, vector<DMatch>& matches12);
|
||||
|
||||
void crisscrossFiltering(const vector<KeyPoint> queryKeypoints, const vector<DMatch> inputMatches, vector<DMatch> &outputMatches);
|
||||
|
||||
vector<string> billMapping;
|
||||
|
||||
|
||||
|
||||
void surfStyleMatching( const Mat& queryDescriptors, vector<KeyPoint> queryKeypoints,
|
||||
vector<DMatch>& matches12 );
|
||||
|
||||
|
@@ -54,7 +54,6 @@ void LicensePlateCandidate::recognize()
|
||||
|
||||
if (charRegion.confidence > 10)
|
||||
{
|
||||
|
||||
PlateLines plateLines(config);
|
||||
//Mat boogedy = charRegion.getPlateMask();
|
||||
|
||||
@@ -76,11 +75,9 @@ void LicensePlateCandidate::recognize()
|
||||
//strcpy(this->recognizedText, ocr.recognizedText);
|
||||
|
||||
this->confidence = 100;
|
||||
|
||||
}
|
||||
charRegion.confidence = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Re-maps the coordinates from the smallImage to the coordinate space of the bigImage.
|
||||
@@ -103,7 +100,6 @@ vector<Point2f> LicensePlateCandidate::transformPointsToOriginalImage(Mat bigIma
|
||||
|
||||
Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector<Point2f> corners)
|
||||
{
|
||||
|
||||
// Figure out the appoximate width/height of the license plate region, so we can maintain the aspect ratio.
|
||||
LineSegment leftEdge(round(corners[3].x), round(corners[3].y), round(corners[0].x), round(corners[0].y));
|
||||
LineSegment rightEdge(round(corners[2].x), round(corners[2].y), round(corners[1].x), round(corners[1].y));
|
||||
@@ -179,5 +175,4 @@ void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage)
|
||||
{
|
||||
displayImage(config, "After cleanup", outputImage);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef STAGE2_H
|
||||
#define STAGE2_H
|
||||
|
||||
@@ -39,8 +38,6 @@
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
|
||||
|
||||
//vector<Rect> getCharacterRegions(Mat frame, vector<Rect> regionsOfInterest);
|
||||
//vector<RotatedRect> getCharSegmentsBetweenLines(Mat img, vector<vector<Point> > contours, LineSegment top, LineSegment bottom);
|
||||
|
||||
@@ -64,7 +61,6 @@ class LicensePlateCandidate
|
||||
|
||||
Config* config;
|
||||
|
||||
|
||||
Mat frame;
|
||||
Rect plateRegion;
|
||||
|
||||
@@ -77,5 +73,4 @@ class LicensePlateCandidate
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // STAGE2_H
|
||||
|
@@ -48,7 +48,6 @@ OCR::~OCR()
|
||||
|
||||
void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
|
||||
{
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
@@ -56,7 +55,6 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
|
||||
|
||||
for (int i = 0; i < thresholds.size(); i++)
|
||||
{
|
||||
|
||||
// Make it black text on white background
|
||||
bitwise_not(thresholds[i], thresholds[i]);
|
||||
tesseract->SetImage((uchar*) thresholds[i].data, thresholds[i].size().width, thresholds[i].size().height, thresholds[i].channels(), thresholds[i].step1());
|
||||
@@ -117,7 +115,6 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
|
||||
|
||||
delete ri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (config->debugTiming)
|
||||
@@ -126,5 +123,4 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
|
||||
getTime(&endTime);
|
||||
cout << "OCR Time: " << diffclock(startTime, endTime) << "ms." << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,9 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef OCR_H
|
||||
#define OCR_H
|
||||
|
||||
@@ -38,7 +35,6 @@ using namespace tesseract;
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
|
||||
class OCR
|
||||
{
|
||||
|
||||
@@ -53,16 +49,11 @@ class OCR
|
||||
//float confidence;
|
||||
//float overallConfidence;
|
||||
|
||||
|
||||
private:
|
||||
Config* config;
|
||||
|
||||
TessBaseAPI *tesseract;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // OCR_H
|
||||
|
@@ -47,7 +47,6 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi
|
||||
|
||||
PlateCorners::~PlateCorners()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
vector<Point> PlateCorners::findPlateCorners()
|
||||
@@ -69,7 +68,6 @@ vector<Point> PlateCorners::findPlateCorners()
|
||||
if (h1 == h2 && h1 != NO_LINE) continue;
|
||||
|
||||
this->scoreHorizontals(h1, h2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +84,6 @@ vector<Point> PlateCorners::findPlateCorners()
|
||||
|
||||
if (this->config->debugPlateCorners)
|
||||
{
|
||||
|
||||
cout << "Drawing debug stuff..." << endl;
|
||||
|
||||
Mat imgCorners = Mat(inputImage.size(), inputImage.type());
|
||||
@@ -100,7 +97,6 @@ vector<Point> PlateCorners::findPlateCorners()
|
||||
line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA);
|
||||
|
||||
displayImage(config, "Winning top/bottom Boundaries", imgCorners);
|
||||
|
||||
}
|
||||
|
||||
// Check if a left/right edge has been established.
|
||||
@@ -129,7 +125,6 @@ vector<Point> PlateCorners::findPlateCorners()
|
||||
|
||||
void PlateCorners::scoreVerticals(int v1, int v2)
|
||||
{
|
||||
|
||||
float score = 0; // Lower is better
|
||||
|
||||
LineSegment left;
|
||||
@@ -237,13 +232,11 @@ void PlateCorners::scoreVerticals(int v1, int v2)
|
||||
bestLeft = LineSegment(left.p1.x, left.p1.y, left.p2.x, left.p2.y);
|
||||
bestRight = LineSegment(right.p1.x, right.p1.y, right.p2.x, right.p2.y);
|
||||
}
|
||||
|
||||
}
|
||||
// Score a collection of lines as a possible license plate region.
|
||||
// If any segments are missing, extrapolate the missing pieces
|
||||
void PlateCorners::scoreHorizontals(int h1, int h2)
|
||||
{
|
||||
|
||||
//if (this->debug)
|
||||
// cout << "PlateCorners::scorePlate" << endl;
|
||||
|
||||
@@ -400,5 +393,4 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
|
||||
bestTop = LineSegment(top.p1.x, top.p1.y, top.p2.x, top.p2.y);
|
||||
bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PLATECORNERS_H
|
||||
#define PLATECORNERS_H
|
||||
|
||||
@@ -32,7 +31,6 @@ using namespace std;
|
||||
|
||||
#define NO_LINE -1
|
||||
|
||||
|
||||
#define SCORING_MISSING_SEGMENT_PENALTY_VERTICAL 10
|
||||
#define SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL 15
|
||||
|
||||
|
@@ -26,12 +26,10 @@ PlateLines::PlateLines(Config* config)
|
||||
|
||||
if (debug)
|
||||
cout << "PlateLines constructor" << endl;
|
||||
|
||||
}
|
||||
|
||||
PlateLines::~PlateLines()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PlateLines::processImage(Mat inputImage, float sensitivity)
|
||||
@@ -150,13 +148,11 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
|
||||
//minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
vector<LineSegment> PlateLines::getLines(Mat edges, bool vertical)
|
||||
{
|
||||
|
||||
vector<LineSegment> filteredLines;
|
||||
|
||||
int sensitivity;
|
||||
@@ -169,7 +165,6 @@ vector<LineSegment> PlateLines::getLines(Mat edges, bool vertical)
|
||||
|
||||
for( size_t i = 0; i < lsegs.size(); i++ )
|
||||
{
|
||||
|
||||
if (vertical)
|
||||
{
|
||||
LineSegment candidate;
|
||||
@@ -213,7 +208,6 @@ vector<LineSegment> PlateLines::getLines(Mat edges, bool vertical)
|
||||
|
||||
for( size_t i = 0; i < filteredLines.size(); i++ )
|
||||
{
|
||||
|
||||
line( debugImg, filteredLines[i].p1, filteredLines[i].p2, Scalar(0,0,255), 1, CV_AA);
|
||||
}
|
||||
if (vertical)
|
||||
@@ -281,7 +275,6 @@ vector<LineSegment> PlateLines::getLines(Mat edges, float sensitivityMultiplier,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
|
||||
{
|
||||
// good horizontal
|
||||
|
@@ -17,8 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef PLATELINES_H
|
||||
#define PLATELINES_H
|
||||
|
||||
@@ -31,7 +29,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
class PlateLines
|
||||
{
|
||||
|
||||
@@ -50,7 +47,6 @@ class PlateLines
|
||||
Config* config;
|
||||
bool debug;
|
||||
|
||||
|
||||
Mat customGrayscaleConversion(Mat src);
|
||||
void findLines(Mat inputImage);
|
||||
vector<LineSegment> getLines(Mat edges, float sensitivityMultiplier, bool vertical);
|
||||
|
@@ -51,7 +51,6 @@ PostProcess::PostProcess(Config* config)
|
||||
//vector<RegexRule> test = rules["base"];
|
||||
//for (int i = 0; i < test.size(); i++)
|
||||
// cout << "Rule: " << test[i].regex << endl;
|
||||
|
||||
}
|
||||
|
||||
PostProcess::~PostProcess()
|
||||
@@ -65,7 +64,6 @@ PostProcess::~PostProcess()
|
||||
{
|
||||
delete iter->second[i];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +84,10 @@ void PostProcess::addLetter(char letter, int charposition, float score)
|
||||
//{
|
||||
// insertLetter('O', charposition, score - 0.5);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
void PostProcess::insertLetter(char letter, int charposition, float score)
|
||||
{
|
||||
|
||||
score = score - config->postProcessMinConfidence;
|
||||
|
||||
int existingIndex = -1;
|
||||
@@ -128,7 +124,6 @@ void PostProcess::insertLetter(char letter, int charposition, float score)
|
||||
letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1;
|
||||
letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PostProcess::clear()
|
||||
@@ -147,9 +142,9 @@ void PostProcess::clear()
|
||||
bestChars = "";
|
||||
matchesTemplate = false;
|
||||
}
|
||||
|
||||
void PostProcess::analyze(string templateregion, int topn)
|
||||
{
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
@@ -174,14 +169,12 @@ void PostProcess::analyze(string templateregion, int topn)
|
||||
|
||||
if (this->config->debugPostProcess)
|
||||
{
|
||||
|
||||
// Print all letters
|
||||
for (int i = 0; i < letters.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < letters[i].size(); j++)
|
||||
cout << "PostProcess Letter: " << letters[i][j].charposition << " " << letters[i][j].letter << " -- score: " << letters[i][j].totalscore << " -- occurences: " << letters[i][j].occurences << endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Prune the letters based on the topN value.
|
||||
@@ -270,12 +263,10 @@ void PostProcess::analyze(string templateregion, int topn)
|
||||
{
|
||||
allPossibilities[i].totalscore = maxPercentScore * (allPossibilities[i].totalscore / highestRelativeScore);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this->config->debugPostProcess)
|
||||
{
|
||||
|
||||
// Print top words
|
||||
for (int i = 0; i < allPossibilities.size(); i++)
|
||||
{
|
||||
@@ -335,7 +326,6 @@ float PostProcess::calculateMaxConfidenceScore()
|
||||
// Y-95 Z-90
|
||||
vector<int> PostProcess::getMaxDepth(int topn)
|
||||
{
|
||||
|
||||
vector<int> depth;
|
||||
for (int i = 0; i < letters.size(); i++)
|
||||
depth.push_back(0);
|
||||
@@ -394,14 +384,12 @@ const vector<PPResult> PostProcess::getResults()
|
||||
|
||||
void PostProcess::findAllPermutations(vector<Letter> prevletters, int charPos, int substitutionsLeft)
|
||||
{
|
||||
|
||||
if (substitutionsLeft < 0)
|
||||
return;
|
||||
|
||||
// Add my letter to the chain and recurse
|
||||
for (int i = 0; i < letters[charPos].size(); i++)
|
||||
{
|
||||
|
||||
if (charPos == letters.size() - 1)
|
||||
{
|
||||
// Last letter, add the word
|
||||
@@ -442,7 +430,6 @@ void PostProcess::findAllPermutations(vector<Letter> prevletters, int charPos, i
|
||||
// Just pass it along
|
||||
findAllPermutations(prevletters, charPos + 1, substitutionsLeft);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool wordCompare( const PPResult &left, const PPResult &right )
|
||||
@@ -450,7 +437,6 @@ bool wordCompare( const PPResult &left, const PPResult &right )
|
||||
if (left.totalscore < right.totalscore)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool letterCompare( const Letter &left, const Letter &right )
|
||||
@@ -476,7 +462,6 @@ RegexRule::RegexRule(string region, string pattern)
|
||||
i++;
|
||||
}
|
||||
this->regex = this->regex + ']';
|
||||
|
||||
}
|
||||
else if (pattern.at(i) == '?')
|
||||
{
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef POSTPROCESS_H
|
||||
#define POSTPROCESS_H
|
||||
|
||||
@@ -32,7 +31,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define SKIP_CHAR '~'
|
||||
|
||||
struct Letter
|
||||
@@ -50,17 +48,14 @@ struct PPResult
|
||||
bool matchesTemplate;
|
||||
};
|
||||
|
||||
|
||||
bool wordCompare( const PPResult &left, const PPResult &right );
|
||||
bool letterCompare( const Letter &left, const Letter &right );
|
||||
|
||||
|
||||
class RegexRule
|
||||
{
|
||||
public:
|
||||
RegexRule(string region, string pattern);
|
||||
|
||||
|
||||
bool match(string text);
|
||||
string filterSkips(string text);
|
||||
|
||||
@@ -73,7 +68,6 @@ class RegexRule
|
||||
vector<int> skipPositions;
|
||||
};
|
||||
|
||||
|
||||
class PostProcess
|
||||
{
|
||||
public:
|
||||
@@ -104,7 +98,6 @@ class PostProcess
|
||||
vector<vector<Letter> > letters;
|
||||
vector<int> unknownCharPositions;
|
||||
|
||||
|
||||
vector<PPResult> allPossibilities;
|
||||
|
||||
// Functions used to prune the list of letters (based on topn) to improve performance
|
||||
|
@@ -17,9 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef REGIONDETECTOR_H
|
||||
#define REGIONDETECTOR_H
|
||||
|
||||
@@ -36,10 +33,6 @@
|
||||
#include "support/timing.h"
|
||||
#include "constants.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class RegionDetector
|
||||
{
|
||||
|
||||
@@ -62,7 +55,4 @@ class RegionDetector
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // REGIONDETECTOR_H
|
||||
|
@@ -16,7 +16,6 @@
|
||||
Windows and Linux/Unix. It is fast, simple and source code using this
|
||||
component will compile unchanged on either OS.
|
||||
|
||||
|
||||
@section features FEATURES
|
||||
|
||||
- MIT Licence allows free use in all software (including GPL and commercial)
|
||||
@@ -44,7 +43,6 @@
|
||||
- Windows/VC 2005 (warning level 4)
|
||||
- Linux/gcc (-Wall)
|
||||
|
||||
|
||||
@section usage USAGE SUMMARY
|
||||
|
||||
-# Define the appropriate symbol for the converter you wish to use and
|
||||
@@ -267,7 +265,6 @@ enum SI_Error
|
||||
# define SI_WCHAR_T UChar
|
||||
#endif
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MAIN TEMPLATE CLASS
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1226,7 +1223,6 @@ class CSimpleIniTempl
|
||||
return (ch == ';' || ch == '#');
|
||||
}
|
||||
|
||||
|
||||
/** Skip over a newline character (or characters) for either DOS or UNIX */
|
||||
inline void SkipNewLine(SI_CHAR *& a_pData) const
|
||||
{
|
||||
@@ -2881,7 +2877,6 @@ class SI_ConvertA
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SI_CONVERT_GENERIC
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -3103,7 +3098,6 @@ class SI_ConvertW
|
||||
|
||||
#endif // SI_CONVERT_GENERIC
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SI_CONVERT_ICU
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -3299,7 +3293,6 @@ class SI_ConvertW
|
||||
|
||||
#endif // SI_CONVERT_ICU
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SI_CONVERT_WIN32
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -3475,7 +3468,6 @@ class SI_ConvertW
|
||||
|
||||
#endif // SI_CONVERT_WIN32
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TYPE DEFINITIONS
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@@ -49,7 +49,6 @@ int StateIdentifier::recognize(Mat img, Rect frame, char* stateCode)
|
||||
// with the value of the country/state
|
||||
int StateIdentifier::recognize(Mat img, char* stateCode)
|
||||
{
|
||||
|
||||
timespec startTime;
|
||||
getTime(&startTime);
|
||||
|
||||
@@ -69,7 +68,6 @@ int StateIdentifier::recognize(Mat img, char* stateCode)
|
||||
|
||||
if (this->config->debugStateId)
|
||||
{
|
||||
|
||||
displayImage(config, "State Identifier1", plateImg);
|
||||
displayImage(config, "State Identifier", debugImg);
|
||||
cout << result.haswinner << " : " << result.confidence << " : " << result.winner << endl;
|
||||
|
@@ -17,8 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef STATEIDENTIFIER_H
|
||||
#define STATEIDENTIFIER_H
|
||||
|
||||
@@ -28,8 +26,6 @@
|
||||
#include "utility.h"
|
||||
#include "config.h"
|
||||
|
||||
|
||||
|
||||
class StateIdentifier
|
||||
{
|
||||
|
||||
@@ -45,10 +41,8 @@ class StateIdentifier
|
||||
protected:
|
||||
Config* config;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
FeatureMatcher* featureMatcher;
|
||||
|
||||
};
|
||||
|
@@ -2,7 +2,6 @@
|
||||
#ifndef FILESYSTEM_H
|
||||
#define FILESYSTEM_H
|
||||
|
||||
|
||||
#ifdef WINDOWS
|
||||
#include "windows/dirent.h"
|
||||
#include "windows/utils.h"
|
||||
@@ -18,7 +17,6 @@
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
bool hasEnding (std::string const &fullString, std::string const &ending);
|
||||
bool DirectoryExists( const char* pzPath );
|
||||
bool fileExists( const char* pzPath );
|
||||
@@ -26,5 +24,4 @@ std::vector<std::string> getFilesInDir(const char* dirPath);
|
||||
|
||||
bool stringCompare( const std::string &left, const std::string &right );
|
||||
|
||||
|
||||
#endif // FILESYSTEM_H
|
||||
|
@@ -71,8 +71,8 @@ int clock_gettime(int X, timespec *tv)
|
||||
void getTime(timespec* time)
|
||||
{
|
||||
clock_gettime(0, time);
|
||||
|
||||
}
|
||||
|
||||
double diffclock(timespec time1,timespec time2)
|
||||
{
|
||||
timespec delta = diff(time1,time2);
|
||||
@@ -101,7 +101,6 @@ timespec diff(timespec start, timespec end)
|
||||
|
||||
void getTime(timespec* time)
|
||||
{
|
||||
|
||||
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
@@ -113,16 +112,14 @@ void getTime(timespec* time)
|
||||
#else
|
||||
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, time);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
double diffclock(timespec time1,timespec time2)
|
||||
{
|
||||
|
||||
timespec delta = diff(time1,time2);
|
||||
double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_nsec) / 1000000.0);
|
||||
|
||||
return milliseconds;
|
||||
|
||||
}
|
||||
|
||||
timespec diff(timespec start, timespec end)
|
||||
|
@@ -19,5 +19,4 @@
|
||||
void getTime(timespec* time);
|
||||
double diffclock(timespec time1,timespec time2);
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -37,7 +37,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* types */
|
||||
|
||||
#define _TINYDIR_PATH_MAX 4096
|
||||
@@ -88,7 +87,6 @@ typedef struct
|
||||
#endif
|
||||
} tinydir_dir;
|
||||
|
||||
|
||||
/* declarations */
|
||||
|
||||
_TINYDIR_FUNC
|
||||
@@ -110,7 +108,6 @@ int tinydir_open_subdir_n(tinydir_dir *dir, int i);
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b);
|
||||
|
||||
|
||||
/* definitions*/
|
||||
|
||||
_TINYDIR_FUNC
|
||||
|
@@ -212,12 +212,10 @@
|
||||
/* Return number of bytes needed to store d_namlen */
|
||||
#define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Wide-character version */
|
||||
struct _wdirent
|
||||
{
|
||||
@@ -244,7 +242,6 @@ static struct _wdirent *_wreaddir (_WDIR *dirp);
|
||||
static int _wclosedir (_WDIR *dirp);
|
||||
static void _wrewinddir (_WDIR* dirp);
|
||||
|
||||
|
||||
/* For compatibility with Symbian */
|
||||
#define wdirent _wdirent
|
||||
#define WDIR _WDIR
|
||||
@@ -253,7 +250,6 @@ static void _wrewinddir (_WDIR* dirp);
|
||||
#define wclosedir _wclosedir
|
||||
#define wrewinddir _wrewinddir
|
||||
|
||||
|
||||
/* Multi-byte character versions */
|
||||
struct dirent
|
||||
{
|
||||
@@ -277,7 +273,6 @@ static struct dirent *readdir (DIR *dirp);
|
||||
static int closedir (DIR *dirp);
|
||||
static void rewinddir (DIR* dirp);
|
||||
|
||||
|
||||
/* Internal utility functions */
|
||||
static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
|
||||
static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
|
||||
@@ -873,7 +868,6 @@ dirent_set_errno(
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -155,7 +155,6 @@ vector<Mat> produceThresholds(const Mat img_gray, Config* config)
|
||||
|
||||
return thresholds;
|
||||
//threshold(img_equalized, img_threshold, 100, 255, THRESH_BINARY);
|
||||
|
||||
}
|
||||
|
||||
double median(int array[], int arraySize)
|
||||
@@ -172,7 +171,6 @@ double median(int array[], int arraySize)
|
||||
|
||||
Mat equalizeBrightness(Mat img)
|
||||
{
|
||||
|
||||
// Divide the image by its morphologically closed counterpart
|
||||
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
|
||||
Mat closed;
|
||||
@@ -188,12 +186,10 @@ Mat equalizeBrightness(Mat img)
|
||||
|
||||
void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness)
|
||||
{
|
||||
|
||||
Point2f rect_points[4];
|
||||
rect.points( rect_points );
|
||||
for( int j = 0; j < 4; j++ )
|
||||
line( *img, rect_points[j], rect_points[(j+1)%4], color, thickness, 8 );
|
||||
|
||||
}
|
||||
|
||||
void fillMask(Mat img, const Mat mask, Scalar color)
|
||||
@@ -212,7 +208,6 @@ void fillMask(Mat img, const Mat mask, Scalar color)
|
||||
img.at<Vec3b>(row, col)[z] = ((int) color[z]) | prevVal;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,6 +262,7 @@ LineSegment::LineSegment(Point p1, Point p2)
|
||||
{
|
||||
init(p1.x, p1.y, p2.x, p2.y);
|
||||
}
|
||||
|
||||
LineSegment::LineSegment(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
init(x1, y1, x2, y2);
|
||||
@@ -339,11 +335,9 @@ Point LineSegment::intersection(LineSegment line)
|
||||
{
|
||||
intersection_X = (c2 - c1) / (slope - line.slope);
|
||||
intersection_Y = slope * intersection_X + c1;
|
||||
|
||||
}
|
||||
|
||||
return Point(intersection_X, intersection_Y);
|
||||
|
||||
}
|
||||
|
||||
Point LineSegment::midpoint()
|
||||
|
@@ -17,15 +17,9 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef UTILITY_H
|
||||
#define UTILITY_H
|
||||
|
||||
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -39,8 +33,6 @@
|
||||
#include <vector>
|
||||
#include "config.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
struct LineSegment
|
||||
{
|
||||
@@ -51,7 +43,6 @@ struct LineSegment
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
class LineSegment
|
||||
{
|
||||
|
||||
@@ -87,7 +78,6 @@ class LineSegment
|
||||
return ss.str() ;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
double median(int array[], int arraySize);
|
||||
|
@@ -22,7 +22,6 @@
|
||||
VerticalHistogram::VerticalHistogram(Mat inputImage, Mat mask)
|
||||
{
|
||||
analyzeImage(inputImage, mask);
|
||||
|
||||
}
|
||||
|
||||
VerticalHistogram::~VerticalHistogram()
|
||||
@@ -46,7 +45,6 @@ void VerticalHistogram::analyzeImage(Mat inputImage, Mat mask)
|
||||
|
||||
for (int row = 0; row < inputImage.rows; row++)
|
||||
{
|
||||
|
||||
if (inputImage.at<uchar>(row, col) > 0 && mask.at<uchar>(row, col) > 0)
|
||||
columnCount++;
|
||||
}
|
||||
@@ -60,9 +58,7 @@ void VerticalHistogram::analyzeImage(Mat inputImage, Mat mask)
|
||||
|
||||
for (; columnCount > 0; columnCount--)
|
||||
histoImg.at<uchar>(inputImage.rows - columnCount, col) = 255;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int VerticalHistogram::getLocalMinimum(int leftX, int rightX)
|
||||
@@ -127,7 +123,6 @@ void VerticalHistogram::findValleys()
|
||||
relativePeakHeight = colHeights[i];
|
||||
|
||||
prevDirection = FLAT;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -137,14 +132,11 @@ void VerticalHistogram::findValleys()
|
||||
|
||||
if ((prevDirection == FALLING || prevDirection == FLAT) && direction == RISING)
|
||||
{
|
||||
|
||||
}
|
||||
else if ((prevDirection == FALLING || prevDirection == FLAT) && direction == RISING)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VERTICALHISTOGRAM_H
|
||||
#define VERTICALHISTOGRAM_H
|
||||
|
||||
@@ -26,7 +25,6 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct Valley
|
||||
{
|
||||
int startIndex;
|
||||
|
Reference in New Issue
Block a user