/*
* Copyright (c) 2013 New Designs Unlimited, LLC
* Opensource Automated License Plate Recognition [http://www.openalpr.com]
*
* This file is part of OpenAlpr.
*
* OpenAlpr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License
* version 3 as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
#include
#include
#include // std::accumulate
#include "alpr_impl.h"
//#include "stage1.h"
//#include "stage2.h"
//#include "stateidentifier.h"
//#include "utility.h"
#include "support/filesystem.h"
using namespace std;
using namespace cv;
// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR
void outputStats(vector datapoints);
int main( int argc, const char** argv )
{
string country;
string benchmarkName;
string inDir;
string outDir;
Mat frame;
//Check if user specify image to process
if(argc == 5)
{
country = argv[1];
benchmarkName = argv[2];
inDir = argv[3];
outDir = argv[4];
}
else
{
printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]);
printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]);
printf("\n");
printf("\ttest names are: speed, segocr, detection\n\n" );
return 0;
}
if (DirectoryExists(inDir.c_str()) == false)
{
printf("Input dir does not exist\n");
return 0;
}
if (DirectoryExists(outDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
}
vector files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
if (benchmarkName.compare("segocr") == 0)
{
Config* config = new Config(country);
config->debugOff();
OCR* ocr = new OCR(config);
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
Rect plateCoords;
plateCoords.x = 0;
plateCoords.y = 0;
plateCoords.width = frame.cols;
plateCoords.height = frame.rows;
char statecode[3];
statecode[0] = files[i][0];
statecode[1] = files[i][1];
statecode[2] = '\0';
string statecodestr(statecode);
CharacterRegion charRegion(frame, config);
if (abs(charRegion.getTopLine().angle) > 4)
{
// Rotate image:
Mat rotated(frame.size(), frame.type());
Mat rot_mat( 2, 3, CV_32FC1 );
Point center = Point( frame.cols/2, frame.rows/2 );
rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 );
warpAffine( frame, rotated, rot_mat, frame.size() );
rotated.copyTo(frame);
}
CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config);
ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
ocr->postProcessor->analyze(statecode, 25);
cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl;
imshow("Current LP", frame);
waitKey(5);
}
}
delete config;
delete ocr;
}
else if (benchmarkName.compare("detection") == 0)
{
Config config(country);
RegionDetector plateDetector(&config);
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
vector regions = plateDetector.detect(frame);
imshow("Current LP", frame);
waitKey(5);
}
}
}
else if (benchmarkName.compare("speed") == 0)
{
// Benchmarks speed of region detection, plate analysis, and OCR
timespec startTime;
timespec endTime;
Config config(country);
config.debugOff();
AlprImpl alpr(country);
alpr.config->debugOff();
alpr.setDetectRegion(true);
RegionDetector plateDetector(&config);
StateIdentifier stateIdentifier(&config);
OCR ocr(&config);
vector endToEndTimes;
vector regionDetectionTimes;
vector stateIdTimes;
vector lpAnalysisPositiveTimes;
vector lpAnalysisNegativeTimes;
vector ocrTimes;
vector postProcessTimes;
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
cout << "Image: " << files[i] << endl;
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
getTime(&startTime);
alpr.recognize(frame);
getTime(&endTime);
double endToEndTime = diffclock(startTime, endTime);
cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl;
endToEndTimes.push_back(endToEndTime);
getTime(&startTime);
vector regions = plateDetector.detect(frame);
getTime(&endTime);
double regionDetectionTime = diffclock(startTime, endTime);
cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl;
regionDetectionTimes.push_back(regionDetectionTime);
for (int z = 0; z < regions.size(); z++)
{
getTime(&startTime);
char temp[5];
stateIdentifier.recognize(frame, regions[z].rect, temp);
getTime(&endTime);
double stateidTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
stateIdTimes.push_back(stateidTime);
getTime(&startTime);
LicensePlateCandidate lp(frame, regions[z].rect, &config);
lp.recognize();
getTime(&endTime);
double analysisTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;
if (lp.confidence > 10)
{
lpAnalysisPositiveTimes.push_back(analysisTime);
getTime(&startTime);
ocr.performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
getTime(&endTime);
double ocrTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl;
ocrTimes.push_back(ocrTime);
getTime(&startTime);
ocr.postProcessor->analyze("", 25);
getTime(&endTime);
double postProcessTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl;
postProcessTimes.push_back(postProcessTime);
}
else
{
lpAnalysisNegativeTimes.push_back(analysisTime);
}
}
waitKey(5);
}
}
cout << endl << "---------------------" << endl;
cout << "End to End Time Statistics:" << endl;
outputStats(endToEndTimes);
cout << endl;
cout << "Region Detection Time Statistics:" << endl;
outputStats(regionDetectionTimes);
cout << endl;
cout << "State ID Time Statistics:" << endl;
outputStats(stateIdTimes);
cout << endl;
cout << "Positive Region Analysis Time Statistics:" << endl;
outputStats(lpAnalysisPositiveTimes);
cout << endl;
cout << "Negative Region Analysis Time Statistics:" << endl;
outputStats(lpAnalysisNegativeTimes);
cout << endl;
cout << "OCR Time Statistics:" << endl;
outputStats(ocrTimes);
cout << endl;
cout << "Post Processing Time Statistics:" << endl;
outputStats(postProcessTimes);
cout << endl;
}
else if (benchmarkName.compare("endtoend") == 0)
{
Alpr alpr(country);
alpr.setDetectRegion(true);
ofstream outputdatafile;
outputdatafile.open("results.txt");
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
vector buffer;
imencode(".bmp", frame, buffer );
vector results = alpr.recognize(buffer);
outputdatafile << files[i] << ": ";
for (int z = 0; z < results.size(); z++)
{
outputdatafile << results[z].bestPlate.characters << ", ";
}
outputdatafile << endl;
imshow("Current LP", frame);
waitKey(5);
}
}
outputdatafile.close();
}
}
void outputStats(vector datapoints)
{
double sum = std::accumulate(datapoints.begin(), datapoints.end(), 0.0);
double mean = sum / datapoints.size();
std::vector diff(datapoints.size());
std::transform(datapoints.begin(), datapoints.end(), diff.begin(),
std::bind2nd(std::minus(), mean));
double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
double stdev = std::sqrt(sq_sum / datapoints.size());
cout << "\t" << datapoints.size() << " samples, avg: " << mean << "ms, stdev: " << stdev << endl;
}