Merge pull request #15 from Silex/cleanup

Cleanup
This commit is contained in:
Matthew Hill
2014-03-20 08:37:11 -05:00
70 changed files with 8186 additions and 8553 deletions

View File

@@ -1,6 +1,5 @@
[common]
ocr_img_size_percent = 1.33333333
state_id_img_size_percent = 2.0
@@ -26,20 +25,18 @@ postprocess_min_characters = 4
postprocess_max_characters = 10
[debug]
general = 0
timing = 0
state_id = 0
plate_lines = 0
general = 0
timing = 0
state_id = 0
plate_lines = 0
plate_corners = 0
char_regions = 0
char_segment = 0
char_regions = 0
char_segment = 0
char_analysis = 0
color_filter = 0
ocr = 0
postprocess = 0
show_images = 0
color_filter = 0
ocr = 0
postprocess = 0
show_images = 0
;;; Country Specific variables ;;;;
@@ -70,7 +67,6 @@ template_max_height_px = 60
plateline_sensitivity_vertical = 25
plateline_sensitivity_horizontal = 45
; Regions smaller than this will be disqualified
min_plate_size_width_px = 70
min_plate_size_height_px = 35
@@ -85,7 +81,6 @@ char_analysis_height_range = 0.15
char_analysis_height_step_size = 0.10
char_analysis_height_num_steps = 5
segmentation_min_box_width_px = 8
segmentation_min_charheight_percent = 0.5;
segmentation_max_segment_width_percent_vs_average = 2.0;

View File

@@ -17,90 +17,83 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <stdio.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include "tclap/CmdLine.h"
#include "support/filesystem.h"
#include "support/timing.h"
#include "alpr.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
const std::string MAIN_WINDOW_NAME = "ALPR main window";
const bool SAVE_LAST_VIDEO_STILL = false;
const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg";
#include "tclap/CmdLine.h"
#include "support/filesystem.h"
#include "support/timing.h"
#include "alpr.h"
/** Function Headers */
bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson);
bool measureProcessingTime = false;
int main( int argc, const char** argv )
{
std::string filename;
std::string runtimePath = "";
bool outputJson = false;
int seektoms = 0;
bool detectRegion = false;
std::string templateRegion;
std::string country;
int topn;
const std::string MAIN_WINDOW_NAME = "ALPR main window";
try
{
TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION);
const bool SAVE_LAST_VIDEO_STILL = false;
const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg";
TCLAP::UnlabeledValueArg<std::string> fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" );
TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code");
TCLAP::ValueArg<int> seekToMsArg("","seek","Seek to the specied millisecond in a video file. Default=0",false, 0 ,"integer_ms");
TCLAP::ValueArg<std::string> runtimeDirArg("r","runtime_dir","Path to the OpenAlpr runtime data directory",false, "" ,"runtime_dir");
TCLAP::ValueArg<std::string> templateRegionArg("t","template_region","Attempt to match the plate number against a region template (e.g., md for Maryland, ca for California)",false, "" ,"region code");
TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return. Default=10",false, 10 ,"topN");
/** Function Headers */
bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson);
TCLAP::SwitchArg jsonSwitch("j","json","Output recognition results in JSON format. Default=off", cmd, false);
TCLAP::SwitchArg detectRegionSwitch("d","detect_region","Attempt to detect the region of the plate image. Default=off", cmd, false);
TCLAP::SwitchArg clockSwitch("","clock","Measure/print the total time to process image and all plates. Default=off", cmd, false);
cmd.add( fileArg );
cmd.add( countryCodeArg );
cmd.add( seekToMsArg );
cmd.add( topNArg );
cmd.add( runtimeDirArg );
cmd.add( templateRegionArg );
bool measureProcessingTime = false;
cmd.parse( argc, argv );
int main( int argc, const char** argv )
{
std::string filename;
std::string runtimePath = "";
bool outputJson = false;
int seektoms = 0;
bool detectRegion = false;
std::string templateRegion;
std::string country;
int topn;
filename = fileArg.getValue();
try {
country = countryCodeArg.getValue();
seektoms = seekToMsArg.getValue();
outputJson = jsonSwitch.getValue();
runtimePath = runtimeDirArg.getValue();
detectRegion = detectRegionSwitch.getValue();
templateRegion = templateRegionArg.getValue();
topn = topNArg.getValue();
measureProcessingTime = clockSwitch.getValue();
TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION);
TCLAP::UnlabeledValueArg<std::string> fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" );
TCLAP::ValueArg<std::string> countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code");
TCLAP::ValueArg<int> seekToMsArg("","seek","Seek to the specied millisecond in a video file. Default=0",false, 0 ,"integer_ms");
TCLAP::ValueArg<std::string> runtimeDirArg("r","runtime_dir","Path to the OpenAlpr runtime data directory",false, "" ,"runtime_dir");
TCLAP::ValueArg<std::string> templateRegionArg("t","template_region","Attempt to match the plate number against a region template (e.g., md for Maryland, ca for California)",false, "" ,"region code");
TCLAP::ValueArg<int> topNArg("n","topn","Max number of possible plate numbers to return. Default=10",false, 10 ,"topN");
TCLAP::SwitchArg jsonSwitch("j","json","Output recognition results in JSON format. Default=off", cmd, false);
TCLAP::SwitchArg detectRegionSwitch("d","detect_region","Attempt to detect the region of the plate image. Default=off", cmd, false);
TCLAP::SwitchArg clockSwitch("","clock","Measure/print the total time to process image and all plates. Default=off", cmd, false);
cmd.add( fileArg );
cmd.add( countryCodeArg );
cmd.add( seekToMsArg );
cmd.add( topNArg );
cmd.add( runtimeDirArg );
cmd.add( templateRegionArg );
cmd.parse( argc, argv );
filename = fileArg.getValue();
country = countryCodeArg.getValue();
seektoms = seekToMsArg.getValue();
outputJson = jsonSwitch.getValue();
runtimePath = runtimeDirArg.getValue();
detectRegion = detectRegionSwitch.getValue();
templateRegion = templateRegionArg.getValue();
topn = topNArg.getValue();
measureProcessingTime = clockSwitch.getValue();
} catch (TCLAP::ArgException &e) // catch any exceptions
{
std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
return 1;
}
cv::Mat frame;
}
catch (TCLAP::ArgException &e) // catch any exceptions
{
std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
return 1;
}
cv::Mat frame;
Alpr alpr(country, runtimePath);
alpr.setTopN(topn);
@@ -125,15 +118,15 @@
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
std::cout << "Error opening webcam" << std::endl;
return 1;
std::cout << "Error opening webcam" << std::endl;
return 1;
}
while (cap.read(frame) == true)
{
detectandshow(&alpr, frame, "", outputJson);
cv::waitKey(1);
framenum++;
detectandshow(&alpr, frame, "", outputJson);
cv::waitKey(1);
framenum++;
}
}
else if (hasEnding(filename, ".avi") || hasEnding(filename, ".mp4") || hasEnding(filename, ".webm") || hasEnding(filename, ".flv"))
@@ -148,16 +141,16 @@
while (cap.read(frame) == true)
{
if (SAVE_LAST_VIDEO_STILL == true)
{
cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame);
}
std::cout << "Frame: " << framenum << std::endl;
if (SAVE_LAST_VIDEO_STILL == true)
{
cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame);
}
std::cout << "Frame: " << framenum << std::endl;
detectandshow( &alpr, frame, "", outputJson);
//create a 1ms delay
cv::waitKey(1);
framenum++;
detectandshow( &alpr, frame, "", outputJson);
//create a 1ms delay
cv::waitKey(1);
framenum++;
}
}
else
@@ -179,32 +172,31 @@
std::cerr << "Image file not found: " << filename << std::endl;
}
}
else if (DirectoryExists(filename.c_str()))
{
std::vector<std::string> files = getFilesInDir(filename.c_str());
std::vector<std::string> files = getFilesInDir(filename.c_str());
std::sort( files.begin(), files.end(), stringCompare );
std::sort( files.begin(), files.end(), stringCompare );
for (int i = 0; i< files.size(); i++)
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png"))
{
if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png"))
{
std::string fullpath = filename + "/" + files[i];
std::cout << fullpath << std::endl;
frame = cv::imread( fullpath.c_str() );
if (detectandshow( &alpr, frame, "", outputJson))
{
//while ((char) cv::waitKey(50) != 'c') { }
}
else
{
//cv::waitKey(50);
}
}
std::string fullpath = filename + "/" + files[i];
std::cout << fullpath << std::endl;
frame = cv::imread( fullpath.c_str() );
if (detectandshow( &alpr, frame, "", outputJson))
{
//while ((char) cv::waitKey(50) != 'c') { }
}
else
{
//cv::waitKey(50);
}
}
}
}
else
{
@@ -212,53 +204,45 @@
return 1;
}
return 0;
}
}
bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson)
{
bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson)
{
std::vector<uchar> buffer;
cv::imencode(".bmp", frame, buffer );
timespec startTime;
getTime(&startTime);
std::vector<uchar> buffer;
cv::imencode(".bmp", frame, buffer );
std::vector<AlprResult> results = alpr->recognize(buffer);
timespec startTime;
getTime(&startTime);
std::vector<AlprResult> results = alpr->recognize(buffer);
if (writeJson)
{
if (writeJson)
{
std::cout << alpr->toJson(results) << std::endl;
}
else
{
}
else
{
for (int i = 0; i < results.size(); i++)
{
std::cout << "plate" << i << ": " << results[i].result_count << " results -- Processing Time = " << results[i].processing_time_ms << "ms." << std::endl;
for (int k = 0; k < results[i].topNPlates.size(); k++)
{
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;
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;
}
}
}
}
timespec endTime;
getTime(&endTime);
if (measureProcessingTime)
std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl;
timespec endTime;
getTime(&endTime);
if (measureProcessingTime)
std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl;
if (results.size() > 0)
return true;
return false;
if (results.size() > 0)
return true;
return false;
}
}

View File

@@ -17,12 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <sys/stat.h>
#include <numeric> // std::accumulate
@@ -34,8 +34,8 @@
//#include "utility.h"
#include "support/filesystem.h"
using namespace std;
using namespace cv;
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
@@ -44,47 +44,44 @@ void outputStats(vector<double> datapoints);
int main( int argc, const char** argv )
{
string country;
string benchmarkName;
string inDir;
string outDir;
Mat frame;
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];
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;
}
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;
printf("Input dir does not exist\n");
return 0;
}
if (DirectoryExists(outDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
printf("Output dir does not exist\n");
return 0;
}
vector<string> files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
if (benchmarkName.compare("segocr") == 0)
{
Config* config = new Config(country);
@@ -92,55 +89,50 @@ int main( int argc, const char** argv )
OCR* ocr = new OCR(config);
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
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;
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);
char statecode[3];
statecode[0] = files[i][0];
statecode[1] = files[i][1];
statecode[2] = '\0';
string statecodestr(statecode);
CharacterRegion charRegion(frame, config);
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 );
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() );
rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 );
warpAffine( frame, rotated, rot_mat, frame.size() );
rotated.copyTo(frame);
}
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;
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);
imshow("Current LP", frame);
waitKey(5);
}
@@ -158,14 +150,13 @@ int main( int argc, const char** argv )
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
vector<Rect> regions = plateDetector.detect(frame);
imshow("Current LP", frame);
waitKey(5);
vector<Rect> regions = plateDetector.detect(frame);
imshow("Current LP", frame);
waitKey(5);
}
@@ -173,7 +164,7 @@ int main( int argc, const char** argv )
}
else if (benchmarkName.compare("speed") == 0)
{
// Benchmarks speed of region detection, plate analysis, and OCR
// Benchmarks speed of region detection, plate analysis, and OCR
timespec startTime;
timespec endTime;
@@ -197,75 +188,72 @@ int main( int argc, const char** argv )
vector<double> ocrTimes;
vector<double> postProcessTimes;
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
cout << "Image: " << files[i] << endl;
cout << "Image: " << files[i] << endl;
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
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);
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<Rect> regions = plateDetector.detect(frame);
getTime(&endTime);
getTime(&startTime);
vector<Rect> regions = plateDetector.detect(frame);
getTime(&endTime);
double regionDetectionTime = diffclock(startTime, endTime);
cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl;
regionDetectionTimes.push_back(regionDetectionTime);
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], temp);
getTime(&endTime);
double stateidTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
stateIdTimes.push_back(stateidTime);
for (int z = 0; z < regions.size(); z++)
{
getTime(&startTime);
char temp[5];
stateIdentifier.recognize(frame, regions[z], 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], &config);
lp.recognize();
getTime(&endTime);
double analysisTime = diffclock(startTime, endTime);
cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;
getTime(&startTime);
LicensePlateCandidate lp(frame, regions[z], &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);
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);
}
}
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);
waitKey(5);
}
@@ -273,7 +261,6 @@ int main( int argc, const char** argv )
cout << endl << "---------------------" << endl;
cout << "End to End Time Statistics:" << endl;
outputStats(endToEndTimes);
cout << endl;
@@ -315,24 +302,23 @@ int main( int argc, const char** argv )
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
string fullpath = inDir + "/" + files[i];
frame = imread( fullpath.c_str() );
vector<uchar> buffer;
imencode(".bmp", frame, buffer );
vector<uchar> buffer;
imencode(".bmp", frame, buffer );
vector<AlprResult> results = alpr.recognize(buffer);
vector<AlprResult> 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 << files[i] << ": ";
for (int z = 0; z < results.size(); z++)
{
outputdatafile << results[z].bestPlate.characters << ", ";
}
outputdatafile << endl;
imshow("Current LP", frame);
waitKey(5);
}
@@ -350,7 +336,7 @@ void outputStats(vector<double> datapoints)
std::vector<double> diff(datapoints.size());
std::transform(datapoints.begin(), datapoints.end(), diff.begin(),
std::bind2nd(std::minus<double>(), mean));
std::bind2nd(std::minus<double>(), mean));
double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
double stdev = std::sqrt(sq_sum / datapoints.size());

View File

@@ -31,8 +31,8 @@
#include "support/filesystem.h"
#include "ocr.h"
using namespace std;
using namespace cv;
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
@@ -61,36 +61,34 @@ const int DASHBOARD_COLUMNS = 3;
#endif
void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex);
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state);
int main( int argc, const char** argv )
{
string inDir;
string outDir;
Mat frame;
string inDir;
string outDir;
Mat frame;
//Check if user specify image to process
if(argc == 3)
{
inDir = argv[1];
outDir = argv[2];
inDir = argv[1];
outDir = argv[2];
}else{
printf("Use:\n\t%s indirectory outdirectory\n",argv[0]);
printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]);
return 0;
}
else
{
printf("Use:\n\t%s indirectory outdirectory\n",argv[0]);
printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]);
return 0;
}
if (DirectoryExists(outDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
printf("Output dir does not exist\n");
return 0;
}
cout << "Usage: " << endl;
@@ -110,172 +108,166 @@ int main( int argc, const char** argv )
if (DirectoryExists(inDir.c_str()))
{
vector<string> files = getFilesInDir(inDir.c_str());
vector<string> files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
sort( files.begin(), files.end(), stringCompare );
for (int i = 0; i< files.size(); i++)
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
string fullpath = inDir + "/" + files[i];
cout << fullpath << endl;
frame = imread( fullpath.c_str() );
resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
string fullpath = inDir + "/" + files[i];
cout << fullpath << endl;
frame = imread( fullpath.c_str() );
resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
imshow ("Original", frame);
imshow ("Original", frame);
char statecode[3];
statecode[0] = files[i][0];
statecode[1] = files[i][1];
statecode[2] = '\0';
string statecodestr(statecode);
char statecode[3];
statecode[0] = files[i][0];
statecode[1] = files[i][1];
statecode[2] = '\0';
string statecodestr(statecode);
CharacterRegion regionizer(frame, config);
CharacterRegion regionizer(frame, config);
if (abs(regionizer.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 );
if (abs(regionizer.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, regionizer.getTopLine().angle, 1.0 );
warpAffine( frame, rotated, rot_mat, frame.size() );
rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 );
warpAffine( frame, rotated, rot_mat, frame.size() );
rotated.copyTo(frame);
}
rotated.copyTo(frame);
}
CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config);
CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config);
//ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);
//ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);
ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
ocr.postProcessor->analyze(statecodestr, 25);
cout << "OCR results: " << ocr.postProcessor->bestChars << endl;
ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
ocr.postProcessor->analyze(statecodestr, 25);
cout << "OCR results: " << ocr.postProcessor->bestChars << endl;
vector<bool> selectedBoxes(charSegmenter.getThresholds().size());
for (int z = 0; z < charSegmenter.getThresholds().size(); z++)
selectedBoxes[z] = false;
int curDashboardSelection = 0;
vector<bool> selectedBoxes(charSegmenter.getThresholds().size());
for (int z = 0; z < charSegmenter.getThresholds().size(); z++)
selectedBoxes[z] = false;
vector<char> humanInputs(charSegmenter.characters.size());
int curDashboardSelection = 0;
for (int z = 0; z < charSegmenter.characters.size(); z++)
humanInputs[z] = ' ';
vector<char> humanInputs(charSegmenter.characters.size());
showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0);
for (int z = 0; z < charSegmenter.characters.size(); z++)
humanInputs[z] = ' ';
char waitkey = (char) waitKey(50);
showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0);
while (waitkey != 'n' && waitkey != 'p') // Next image
{
if (waitkey == LEFT_ARROW_KEY) // left arrow key
{
if (curDashboardSelection > 0)
curDashboardSelection--;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
{
if (curDashboardSelection < charSegmenter.getThresholds().size() - 1)
curDashboardSelection++;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == DOWN_ARROW_KEY)
{
if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1)
curDashboardSelection += DASHBOARD_COLUMNS;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == UP_ARROW_KEY)
{
if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
curDashboardSelection -= DASHBOARD_COLUMNS;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == ENTER_KEY)
{
vector<char> tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr);
for (int c = 0; c < charSegmenter.characters.size(); c++)
humanInputs[c] = tempdata[c];
}
else if (waitkey == SPACE_KEY)
{
selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == 's' || waitkey == 'S')
{
bool somethingSelected = false;
bool chardataTagged = false;
for (int c = 0; c < charSegmenter.getThresholds().size(); c++)
{
if (selectedBoxes[c])
{
somethingSelected = true;
break;
}
}
for (int c = 0; c < charSegmenter.characters.size(); c++)
{
if (humanInputs[c] != ' ')
{
chardataTagged = true;
break;
}
}
// Save
if (somethingSelected && chardataTagged)
{
for (int c = 0; c < charSegmenter.characters.size(); c++)
{
if (humanInputs[c] == ' ')
continue;
for (int t = 0; t < charSegmenter.getThresholds().size(); t++)
{
if (selectedBoxes[t] == false)
continue;
char waitkey = (char) waitKey(50);
stringstream filename;
Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]);
filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
imwrite(filename.str(), cropped);
cout << "Writing char image: " << filename.str() << endl;
}
}
}
else if (somethingSelected == false)
cout << "Did not select any boxes" << endl;
else if (chardataTagged == false)
cout << "You have not tagged any characters" << endl;
}
while (waitkey != 'n' && waitkey != 'p') // Next image
{
if (waitkey == LEFT_ARROW_KEY) // left arrow key
{
if (curDashboardSelection > 0)
curDashboardSelection--;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
{
if (curDashboardSelection < charSegmenter.getThresholds().size() - 1)
curDashboardSelection++;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == DOWN_ARROW_KEY)
{
if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1)
curDashboardSelection += DASHBOARD_COLUMNS;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == UP_ARROW_KEY)
{
if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
curDashboardSelection -= DASHBOARD_COLUMNS;
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == ENTER_KEY)
{
vector<char> tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr);
for (int c = 0; c < charSegmenter.characters.size(); c++)
humanInputs[c] = tempdata[c];
}
else if (waitkey == SPACE_KEY)
{
selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
}
else if (waitkey == 's' || waitkey == 'S')
{
bool somethingSelected = false;
bool chardataTagged = false;
for (int c = 0; c < charSegmenter.getThresholds().size(); c++)
{
if (selectedBoxes[c])
{
somethingSelected = true;
break;
}
}
for (int c = 0; c < charSegmenter.characters.size(); c++)
{
if (humanInputs[c] != ' ')
{
chardataTagged = true;
break;
}
}
// Save
if (somethingSelected && chardataTagged)
{
waitkey = (char) waitKey(50);
for (int c = 0; c < charSegmenter.characters.size(); c++)
{
if (humanInputs[c] == ' ')
continue;
}
for (int t = 0; t < charSegmenter.getThresholds().size(); t++)
{
if (selectedBoxes[t] == false)
continue;
stringstream filename;
Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]);
filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
imwrite(filename.str(), cropped);
cout << "Writing char image: " << filename.str() << endl;
}
}
}
else if (somethingSelected == false)
cout << "Did not select any boxes" << endl;
else if (chardataTagged == false)
cout << "You have not tagged any characters" << endl;
}
waitkey = (char) waitKey(50);
}
if (waitkey == 'p')
i = i - 2;
if (i < -1)
i = -1;
}
if (waitkey == 'p')
i = i - 2;
if (i < -1)
i = -1;
}
}
}
}
void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selectedIndex)
{
vector<Mat> vecCopy;
@@ -309,62 +301,60 @@ void showDashboard(vector<Mat> images, vector<bool> selectedImages, int selected
vector<char> showCharSelection(Mat image, vector<Rect> charRegions, string state)
{
int curCharIdx = 0;
int curCharIdx = 0;
vector<char> humanInputs(charRegions.size());
for (int i = 0; i < charRegions.size(); i++)
humanInputs[i] = (char) SPACE_KEY;
vector<char> humanInputs(charRegions.size());
for (int i = 0; i < charRegions.size(); i++)
humanInputs[i] = (char) SPACE_KEY;
char waitkey = (char) waitKey(50);
while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
{
Mat imgCopy(image.size(), image.type());
image.copyTo(imgCopy);
cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
char waitkey = (char) waitKey(50);
while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);
imshow("Character selector", imgCopy);
if (waitkey == LEFT_ARROW_KEY)
curCharIdx--;
else if (waitkey == RIGHT_ARROW_KEY )
curCharIdx++;
else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
{
Mat imgCopy(image.size(), image.type());
image.copyTo(imgCopy);
cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
// Save the character to disk
humanInputs[curCharIdx] = toupper((char) waitkey);
curCharIdx++;
rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);
imshow("Character selector", imgCopy);
if (waitkey == LEFT_ARROW_KEY)
curCharIdx--;
else if (waitkey == RIGHT_ARROW_KEY )
curCharIdx++;
else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
{
// Save the character to disk
humanInputs[curCharIdx] = toupper((char) waitkey);
curCharIdx++;
if (curCharIdx >= charRegions.size())
{
waitkey = (char) ENTER_KEY;
break;
}
}
if (curCharIdx < 0)
curCharIdx = 0;
if (curCharIdx >= charRegions.size())
curCharIdx = charRegions.size() -1;
waitkey = (char) waitKey(50);
{
waitkey = (char) ENTER_KEY;
break;
}
}
if (waitkey == ENTER_KEY)
if (curCharIdx < 0)
curCharIdx = 0;
if (curCharIdx >= charRegions.size())
curCharIdx = charRegions.size() -1;
waitkey = (char) waitKey(50);
}
if (waitkey == ENTER_KEY)
{
// Save all the inputs
for (int i = 0; i < charRegions.size(); i++)
{
// Save all the inputs
for (int i = 0; i < charRegions.size(); i++)
{
if (humanInputs[i] != (char) SPACE_KEY)
cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
}
if (humanInputs[i] != (char) SPACE_KEY)
cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
}
destroyWindow("Character selector");
}
destroyWindow("Character selector");
return humanInputs;
return humanInputs;
}

View File

@@ -17,49 +17,46 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <sys/stat.h>
#include "support/filesystem.h"
using namespace std;
using namespace cv;
using namespace std;
using namespace cv;
// Takes a directory full of single char images, and plops them on a big tif files
// Also creates a box file so Tesseract can recognize it
int main( int argc, const char** argv )
{
string inDir;
string inDir;
//Check if user specify image to process
if(argc == 2)
{
inDir = argv[1];
inDir = argv[1];
}else{
printf("Use:\n\t%s input dir \n",argv[0]);
return 0;
}
else
{
printf("Use:\n\t%s input dir \n",argv[0]);
return 0;
}
if (DirectoryExists(inDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
printf("Output dir does not exist\n");
return 0;
}
cout << "Usage: " << endl;
cout << "\tinputdir -- input dir for benchmark data" << endl;
if (DirectoryExists(inDir.c_str()))
{
const int X_OFFSET = 10;
@@ -74,97 +71,92 @@ int main( int argc, const char** argv )
const int TILE_HEIGHT = 70;
const int CHAR_VERT_OFFSET = 48;
vector<string> files = getFilesInDir(inDir.c_str());
vector<string> files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
sort( files.begin(), files.end(), stringCompare );
int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH);
int lines = files.size() / (tiles_per_row);
int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ;
cout << tiles_per_row << " : " << vertical_resolution << endl;
int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH);
int lines = files.size() / (tiles_per_row);
int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ;
cout << tiles_per_row << " : " << vertical_resolution << endl;
Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U);
bitwise_not(bigTif, bigTif);
Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U);
bitwise_not(bigTif, bigTif);
stringstream boxFileOut;
stringstream boxFileOut;
for (int i = 0; i< files.size(); i++)
{
int col = i % tiles_per_row;
int line = i / tiles_per_row;
for (int i = 0; i< files.size(); i++)
int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X;
int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y;
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
int col = i % tiles_per_row;
int line = i / tiles_per_row;
string fullpath = inDir + "/" + files[i];
int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X;
int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y;
cout << "Processing file: " << (i + 1) << " of " << files.size() << endl;
if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
string fullpath = inDir + "/" + files[i];
char charcode = files[i][0];
cout << "Processing file: " << (i + 1) << " of " << files.size() << endl;
Mat characterImg = imread(fullpath);
Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type());
bitwise_not(charImgCopy, charImgCopy);
char charcode = files[i][0];
characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows)));
cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY);
bitwise_not(charImgCopy, charImgCopy);
Mat characterImg = imread(fullpath);
Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type());
bitwise_not(charImgCopy, charImgCopy);
vector<vector<Point> > contours;
characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows)));
cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY);
bitwise_not(charImgCopy, charImgCopy);
//imshow("copy", charImgCopy);
findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<vector<Point> > contours;
Rect tallestRect(0, 0, 0, 0);
for (int c = 0; c < contours.size(); c++)
{
Rect tmpRect = boundingRect(contours[c]);
if (tmpRect.height > tallestRect.height)
tallestRect = tmpRect;
}
//imshow("copy", charImgCopy);
findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl;
Rect tallestRect(0, 0, 0, 0);
for (int c = 0; c < contours.size(); c++)
{
Rect tmpRect = boundingRect(contours[c]);
if (tmpRect.height > tallestRect.height)
tallestRect = tmpRect;
}
Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height);
//cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl;
//cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl;
Mat cropped(characterImg, cropRect);
cvtColor(cropped, cropped, CV_BGR2GRAY);
Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height);
Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height);
//cout << "1" << endl;
//cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl;
Mat cropped(characterImg, cropRect);
cvtColor(cropped, cropped, CV_BGR2GRAY);
cropped.copyTo(bigTif(destinationRect));
Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height);
int x1= destinationRect.x - 2;
int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2;
int x2 = (destinationRect.x + destinationRect.width) + 2;
int y2 = (vertical_resolution - destinationRect.y) + 2;
//0 70 5602 85 5636 0
boxFileOut << charcode << " " << x1 << " " << y1 << " ";
boxFileOut << x2 << " " << y2 ;
boxFileOut << " 0" << endl;
//cout << "1" << endl;
//rectangle(characterImg, tallestRect, Scalar(0, 255, 0));
//imshow("characterImg", cropped);
cropped.copyTo(bigTif(destinationRect));
int x1= destinationRect.x - 2;
int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2;
int x2 = (destinationRect.x + destinationRect.width) + 2;
int y2 = (vertical_resolution - destinationRect.y) + 2;
//0 70 5602 85 5636 0
boxFileOut << charcode << " " << x1 << " " << y1 << " ";
boxFileOut << x2 << " " << y2 ;
boxFileOut << " 0" << endl;
//rectangle(characterImg, tallestRect, Scalar(0, 255, 0));
//imshow("characterImg", cropped);
waitKey(2);
}
waitKey(2);
}
}
imwrite("combined.tif", bigTif);
ofstream boxFile("combined.box", std::ios::out);
boxFile << boxFileOut.str();
imwrite("combined.tif", bigTif);
ofstream boxFile("combined.box", std::ios::out);
boxFile << boxFileOut.str();
}

View File

@@ -17,11 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <iostream>
#include <stdio.h>
#include <sys/stat.h>
#include "regiondetector.h"
@@ -30,34 +30,34 @@
#include "utility.h"
#include "support/filesystem.h"
using namespace std;
using namespace cv;
using namespace std;
using namespace cv;
// Given a directory full of pre-cropped images, identify the state that each image belongs to.
// This is used to sort our own positive image database as a first step before grabbing characters to use to train the OCR.
bool detectPlate( StateIdentifier* identifier, Mat frame);
bool detectPlate( StateIdentifier* identifier, Mat frame);
int main( int argc, const char** argv )
{
string inDir;
string outDir;
Mat frame;
string inDir;
string outDir;
Mat frame;
//Check if user specify image to process
if(argc == 3 )
{
inDir = argv[1];
outDir = argv[2];
outDir = outDir + "/";
inDir = argv[1];
outDir = argv[2];
outDir = outDir + "/";
}else{
printf("Use:\n\t%s directory \n",argv[0]);
printf("Ex: \n\t%s ./pics/ \n",argv[0]);
return 0;
}
else
{
printf("Use:\n\t%s directory \n",argv[0]);
printf("Ex: \n\t%s ./pics/ \n",argv[0]);
return 0;
}
Config config("us");
@@ -65,53 +65,52 @@ int main( int argc, const char** argv )
if (DirectoryExists(outDir.c_str()) == false)
{
printf("Output dir does not exist\n");
return 0;
printf("Output dir does not exist\n");
return 0;
}
if (DirectoryExists(inDir.c_str()))
{
vector<string> files = getFilesInDir(inDir.c_str());
vector<string> files = getFilesInDir(inDir.c_str());
for (int i = 0; i< files.size(); i++)
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
if (hasEnding(files[i], ".png"))
{
string fullpath = inDir + "/" + files[i];
cout << fullpath << endl;
frame = imread( fullpath.c_str() );
string fullpath = inDir + "/" + files[i];
cout << fullpath << endl;
frame = imread( fullpath.c_str() );
char code[4];
int confidence = identifier.recognize(frame, code);
char code[4];
int confidence = identifier.recognize(frame, code);
if (confidence <= 20)
{
code[0] = 'z';
code[1] = 'z';
confidence = 100;
}
if (confidence <= 20)
{
code[0] = 'z';
code[1] = 'z';
confidence = 100;
}
//imshow("Plate", frame);
if (confidence > 20)
{
cout << confidence << " : " << code;
//imshow("Plate", frame);
if (confidence > 20)
{
cout << confidence << " : " << code;
ostringstream convert; // stream used for the conversion
convert << i; // insert the textual representation of 'Number' in the characters in the stream
string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png";
system( copyCommand.c_str() );
waitKey(50);
//while ((char) waitKey(50) != 'c') { }
}
else
waitKey(50);
}
ostringstream convert; // stream used for the conversion
convert << i; // insert the textual representation of 'Number' in the characters in the stream
string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png";
system( copyCommand.c_str() );
waitKey(50);
//while ((char) waitKey(50) != 'c') { }
}
else
waitKey(50);
}
}
}
}
bool detectPlate( StateIdentifier* identifier, Mat frame);
bool detectPlate( StateIdentifier* identifier, Mat frame);

View File

@@ -31,45 +31,67 @@ extern "C" {
#include "trex.h"
}
struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;};
struct TRexParseException
{
TRexParseException(const TRexChar *c):desc(c) {} const TRexChar *desc;
};
class TRexpp {
public:
TRexpp() { _exp = (TRex *)0; }
~TRexpp() { CleanUp(); }
// compiles a regular expression
void Compile(const TRexChar *pattern) {
const TRexChar *error;
CleanUp();
if(!(_exp = trex_compile(pattern,&error)))
throw TRexParseException(error);
}
// return true if the given text match the expression
bool Match(const TRexChar* text) {
return _exp?(trex_match(_exp,text) != 0):false;
}
// Searches for the first match of the expression in a zero terminated string
bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) {
return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false;
}
// Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) {
return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false;
}
bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
{
TRexMatch match;
TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False;
if(res) {
*out_begin = match.begin;
*out_len = match.len;
return true;
}
return false;
}
int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; }
private:
void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; }
TRex *_exp;
class TRexpp
{
public:
TRexpp()
{
_exp = (TRex *)0;
}
~TRexpp()
{
CleanUp();
}
// compiles a regular expression
void Compile(const TRexChar *pattern)
{
const TRexChar *error;
CleanUp();
if(!(_exp = trex_compile(pattern,&error)))
throw TRexParseException(error);
}
// return true if the given text match the expression
bool Match(const TRexChar* text)
{
return _exp?(trex_match(_exp,text) != 0):false;
}
// Searches for the first match of the expression in a zero terminated string
bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
{
return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false;
}
// Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
{
return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false;
}
bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
{
TRexMatch match;
TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False;
if(res)
{
*out_begin = match.begin;
*out_len = match.len;
return true;
}
return false;
}
int GetSubExpCount()
{
return _exp?trex_getsubexpcount(_exp):0;
}
private:
void CleanUp()
{
if(_exp) trex_free(_exp);
_exp = (TRex *)0;
}
TRex *_exp;
};
#endif //_TREXPP_H_

View File

@@ -20,9 +20,6 @@
#include "alpr.h"
#include "alpr_impl.h"
// ALPR code
Alpr::Alpr(const std::string country, const std::string runtimeDir)
@@ -40,22 +37,19 @@ std::vector<AlprResult> Alpr::recognize(std::string filepath)
}
std::vector<AlprResult> Alpr::recognize(std::vector<unsigned char> imageBuffer)
{
// Not sure if this actually works
// Not sure if this actually works
cv::Mat img = cv::imdecode(Mat(imageBuffer), 1);
return impl->recognize(img);
}
string Alpr::toJson(const vector< AlprResult > results)
{
return impl->toJson(results);
}
void Alpr::setDetectRegion(bool detectRegion)
{
impl->setDetectRegion(detectRegion);
@@ -74,11 +68,8 @@ bool Alpr::isLoaded()
return true;
}
// Results code
AlprResult::AlprResult()
{

View File

@@ -37,8 +37,8 @@ struct AlprPlate
struct AlprCoordinate
{
int x;
int y;
int x;
int y;
};
class AlprResult

View File

@@ -19,7 +19,6 @@
#include "alpr_impl.h"
AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
{
config = new Config(country, runtimeDir);
@@ -39,7 +38,7 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
for (int i = 0; i < platinfo.size(); i++)
{
std::cout << platinfo[i]->platformName << std::endl;
std::cout << platinfo[i]->platformName << std::endl;
}
cv::ocl::DevicesInfo devices;
@@ -68,7 +67,6 @@ AlprImpl::~AlprImpl()
delete ocr;
}
std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
{
timespec startTime;
@@ -76,100 +74,95 @@ std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
vector<AlprResult> response;
vector<Rect> plateRegions = plateDetector->detect(img);
// Recognize.
for (int i = 0; i < plateRegions.size(); i++)
{
timespec platestarttime;
getTime(&platestarttime);
timespec platestarttime;
getTime(&platestarttime);
LicensePlateCandidate lp(img, plateRegions[i], config);
LicensePlateCandidate lp(img, plateRegions[i], config);
lp.recognize();
lp.recognize();
if (lp.confidence > 10)
{
AlprResult plateResult;
plateResult.region = defaultRegion;
plateResult.regionConfidence = 0;
if (lp.confidence > 10)
for (int pointidx = 0; pointidx < 4; pointidx++)
{
AlprResult plateResult;
plateResult.region = defaultRegion;
plateResult.regionConfidence = 0;
for (int pointidx = 0; pointidx < 4; pointidx++)
{
plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x;
plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y;
}
if (detectRegion)
{
char statecode[4];
plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode);
if (plateResult.regionConfidence > 0)
{
plateResult.region = statecode;
}
}
ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
ocr->postProcessor->analyze(plateResult.region, topN);
//plateResult.characters = ocr->postProcessor->bestChars;
const vector<PPResult> ppResults = ocr->postProcessor->getResults();
int bestPlateIndex = 0;
for (int pp = 0; pp < ppResults.size(); pp++)
{
if (pp >= topN)
break;
// Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match
if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate)
bestPlateIndex = pp;
if (ppResults[pp].letters.size() >= config->postProcessMinCharacters &&
ppResults[pp].letters.size() <= config->postProcessMaxCharacters)
{
AlprPlate aplate;
aplate.characters = ppResults[pp].letters;
aplate.overall_confidence = ppResults[pp].totalscore;
aplate.matches_template = ppResults[pp].matchesTemplate;
plateResult.topNPlates.push_back(aplate);
}
}
plateResult.result_count = plateResult.topNPlates.size();
if (plateResult.topNPlates.size() > 0)
plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex];
timespec plateEndTime;
getTime(&plateEndTime);
plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime);
if (plateResult.result_count > 0)
response.push_back(plateResult);
if (config->debugGeneral)
{
rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2);
for (int z = 0; z < 4; z++)
line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2);
}
plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x;
plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y;
}
else
if (detectRegion)
{
if (config->debugGeneral)
rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2);
char statecode[4];
plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode);
if (plateResult.regionConfidence > 0)
{
plateResult.region = statecode;
}
}
ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
ocr->postProcessor->analyze(plateResult.region, topN);
//plateResult.characters = ocr->postProcessor->bestChars;
const vector<PPResult> ppResults = ocr->postProcessor->getResults();
int bestPlateIndex = 0;
for (int pp = 0; pp < ppResults.size(); pp++)
{
if (pp >= topN)
break;
// Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match
if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate)
bestPlateIndex = pp;
if (ppResults[pp].letters.size() >= config->postProcessMinCharacters &&
ppResults[pp].letters.size() <= config->postProcessMaxCharacters)
{
AlprPlate aplate;
aplate.characters = ppResults[pp].letters;
aplate.overall_confidence = ppResults[pp].totalscore;
aplate.matches_template = ppResults[pp].matchesTemplate;
plateResult.topNPlates.push_back(aplate);
}
}
plateResult.result_count = plateResult.topNPlates.size();
if (plateResult.topNPlates.size() > 0)
plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex];
timespec plateEndTime;
getTime(&plateEndTime);
plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime);
if (plateResult.result_count > 0)
response.push_back(plateResult);
if (config->debugGeneral)
{
rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2);
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)
@@ -210,8 +203,6 @@ string AlprImpl::toJson(const vector< AlprResult > results)
return response;
}
cJSON* AlprImpl::createJsonObj(const AlprResult* result)
{
cJSON *root, *coords, *candidates;
@@ -228,7 +219,7 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
cJSON_AddNumberToObject(root,"processing_time_ms", result->processing_time_ms);
cJSON_AddItemToObject(root, "coordinates", coords=cJSON_CreateArray());
for (int i=0;i<4;i++)
for (int i=0; i<4; i++)
{
cJSON *coords_object;
coords_object = cJSON_CreateObject();
@@ -238,7 +229,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
cJSON_AddItemToArray(coords, coords_object);
}
cJSON_AddItemToObject(root, "candidates", candidates=cJSON_CreateArray());
for (int i = 0; i < result->topNPlates.size(); i++)
{
@@ -254,7 +244,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
return root;
}
void AlprImpl::setDetectRegion(bool detectRegion)
{
this->detectRegion = detectRegion;

View File

@@ -33,190 +33,192 @@
#include "binarize_wolf.h"
// *************************************************************
// glide a window across the image and
// create two maps: mean and standard deviation.
// *************************************************************
float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
{
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;
int wxh = winx/2;
int wyh = winy/2;
int x_firstth= wxh;
int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
float winarea = winx*winy;
float m,s,max_s;
long sum, sum_sq;
uchar foo;
int wxh = winx/2;
int wyh = winy/2;
int x_firstth= wxh;
int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
float winarea = winx*winy;
max_s = 0;
for (int j = y_firstth ; j<=y_lastth; j++)
{
// Calculate the initial window at the beginning of the line
sum = sum_sq = 0;
for (int wy=0 ; wy<winy; wy++)
for (int wx=0 ; wx<winx; wx++)
{
foo = im.uget(wx,j-wyh+wy);
sum += foo;
sum_sq += foo*foo;
}
m = ((float)sum) / winarea;
s = sqrt ((((float)sum_sq) - ((float)(sum*sum))/winarea)/winarea);
if (s > max_s)
max_s = s;
map_m.fset(x_firstth, j, m);
map_s.fset(x_firstth, j, s);
// Shift the window, add and remove new/old values to the histogram
for (int i=1 ; i <= im.cols-winx; i++)
{
max_s = 0;
for (int j = y_firstth ; j<=y_lastth; j++)
{
// Calculate the initial window at the beginning of the line
sum = sum_sq = 0;
for (int wy=0 ; wy<winy; wy++)
for (int wx=0 ; wx<winx; wx++) {
foo = im.uget(wx,j-wyh+wy);
sum += foo;
sum_sq += foo*foo;
}
m = ((float)sum) / winarea;
s = sqrt ((((float)sum_sq) - ((float)(sum*sum))/winarea)/winarea);
if (s > max_s)
max_s = s;
map_m.fset(x_firstth, j, m);
map_s.fset(x_firstth, j, s);
// Remove the left old column and add the right new column
for (int wy=0; wy<winy; ++wy)
{
foo = im.uget(i-1,j-wyh+wy);
sum -= foo;
sum_sq -= foo*foo;
foo = im.uget(i+winx-1,j-wyh+wy);
sum += foo;
sum_sq += foo*foo;
}
m = ((float)sum) / winarea;
s = sqrt ((((float)sum_sq) - ((float) (sum*sum))/winarea)/winarea);
if (s > max_s)
max_s = s;
map_m.fset(i+wxh, j, m);
map_s.fset(i+wxh, j, s);
}
}
// 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) {
foo = im.uget(i-1,j-wyh+wy);
sum -= foo;
sum_sq -= foo*foo;
foo = im.uget(i+winx-1,j-wyh+wy);
sum += foo;
sum_sq += foo*foo;
}
m = ((float)sum) / winarea;
s = sqrt ((((float)sum_sq) - ((float) (sum*sum))/winarea)/winarea);
if (s > max_s)
max_s = s;
map_m.fset(i+wxh, j, m);
map_s.fset(i+wxh, j, s);
}
}
return max_s;
return max_s;
}
/**********************************************************
* The binarization routine
**********************************************************/
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
int winx, int winy, float k) {
int winx, int winy, float k)
{
float dR = BINARIZEWOLF_DEFAULTDR;
float dR = BINARIZEWOLF_DEFAULTDR;
float m, s, max_s;
float th=0;
double min_I, max_I;
int wxh = winx/2;
int wyh = winy/2;
int x_firstth= wxh;
int x_lastth = im.cols-wxh-1;
int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
int mx, my;
float m, s, max_s;
float th=0;
double min_I, max_I;
int wxh = winx/2;
int wyh = winy/2;
int x_firstth= wxh;
int x_lastth = im.cols-wxh-1;
int y_lastth = im.rows-wyh-1;
int y_firstth= wyh;
int mx, my;
// Create local statistics and store them in a float matrices
Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F);
Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F);
max_s = calcLocalStats (im, map_m, map_s, winx, winy);
// Create local statistics and store them in a float matrices
Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F);
Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F);
max_s = calcLocalStats (im, map_m, map_s, winx, winy);
minMaxLoc(im, &min_I, &max_I);
minMaxLoc(im, &min_I, &max_I);
Mat thsurf (im.rows, im.cols, CV_32F);
Mat thsurf (im.rows, im.cols, CV_32F);
// Create the threshold surface, including border processing
// ----------------------------------------------------
// Create the threshold surface, including border processing
// ----------------------------------------------------
for (int j = y_firstth ; j<=y_lastth; j++) {
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++) {
// 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);
m = map_m.fget(i+wxh, j);
s = map_s.fget(i+wxh, j);
// Calculate the threshold
switch (version) {
// Calculate the threshold
switch (version)
{
case NIBLACK:
th = m + k*s;
break;
case NIBLACK:
th = m + k*s;
break;
case SAUVOLA:
th = m * (1 + k*(s/dR-1));
break;
case SAUVOLA:
th = m * (1 + k*(s/dR-1));
break;
case WOLFJOLION:
th = m + k * (s/max_s-1) * (m-min_I);
break;
case WOLFJOLION:
th = m + k * (s/max_s-1) * (m-min_I);
break;
default:
cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
exit (1);
}
default:
cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
exit (1);
}
thsurf.fset(i+wxh,j,th);
thsurf.fset(i+wxh,j,th);
if (i==0) {
// LEFT BORDER
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,j,th);
if (i==0)
{
// LEFT BORDER
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,j,th);
// LEFT-UPPER CORNER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
// LEFT-UPPER CORNER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
// LEFT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
}
// LEFT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
for (int i=0; i<=x_firstth; ++i)
thsurf.fset(i,u,th);
}
// UPPER BORDER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
thsurf.fset(i+wxh,u,th);
// UPPER BORDER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
thsurf.fset(i+wxh,u,th);
// LOWER BORDER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
thsurf.fset(i+wxh,u,th);
}
// LOWER BORDER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
thsurf.fset(i+wxh,u,th);
}
// RIGHT BORDER
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,j,th);
// RIGHT BORDER
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,j,th);
// RIGHT-UPPER CORNER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,u,th);
// RIGHT-UPPER CORNER
if (j==y_firstth)
for (int u=0; u<y_firstth; ++u)
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,u,th);
// RIGHT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,u,th);
}
// RIGHT-LOWER CORNER
if (j==y_lastth)
for (int u=y_lastth+1; u<im.rows; ++u)
for (int i=x_lastth; i<im.cols; ++i)
thsurf.fset(i,u,th);
}
for (int y=0; y<im.rows; ++y)
for (int x=0; x<im.cols; ++x)
{
if (im.uget(x,y) >= thsurf.fget(x,y))
{
output.uset(x,y,255);
}
else
{
output.uset(x,y,0);
}
for (int y=0; y<im.rows; ++y)
for (int x=0; x<im.cols; ++x)
{
if (im.uget(x,y) >= thsurf.fget(x,y))
{
output.uset(x,y,255);
}
else
{
output.uset(x,y,0);
}
}
}

View File

@@ -32,9 +32,9 @@ using namespace cv;
enum NiblackVersion
{
NIBLACK=0,
SAUVOLA,
WOLFJOLION,
NIBLACK=0,
SAUVOLA,
WOLFJOLION,
};
#define BINARIZEWOLF_VERSION "2.3 (February 26th, 2013)"
@@ -49,7 +49,7 @@ enum NiblackVersion
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
int winx, int winy, float k);
int winx, int winy, float k);

File diff suppressed because it is too large Load Diff

View File

@@ -28,19 +28,15 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
this->confidence = 0;
if (this->debug)
cout << "Starting CharacterRegion identification" << endl;
timespec startTime;
getTime(&startTime);
charAnalysis = new CharacterAnalysis(img, config);
charAnalysis->analyze();
if (this->debug)
{
vector<Mat> tempDash;
@@ -53,7 +49,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
tempDash.push_back(tmp);
}
Mat bestVal(charAnalysis->bestThreshold.size(), charAnalysis->bestThreshold.type());
charAnalysis->bestThreshold.copyTo(bestVal);
cvtColor(bestVal, bestVal, CV_GRAY2BGR);
@@ -62,18 +57,16 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
{
Scalar dcolor(255,0,0);
if (charAnalysis->bestCharSegments[z])
dcolor = Scalar(0,255,0);
dcolor = Scalar(0,255,0);
drawContours(bestVal, charAnalysis->bestContours, z, dcolor, 1);
}
tempDash.push_back(bestVal);
displayImage(config, "Character Region Step 1 Thresholds", drawImageDashboard(tempDash, bestVal.type(), 3));
}
if (this->debug)
{
/*
/*
Mat img_contours(img_threshold.size(), CV_8U);
img_threshold.copyTo(img_contours);
cvtColor(img_contours, img_contours, CV_GRAY2RGB);
@@ -81,29 +74,26 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
vector<vector<Point> > allowedContours;
for (int i = 0; i < contours.size(); i++)
{
if (charSegments[i])
allowedContours.push_back(contours[i]);
if (charSegments[i])
allowedContours.push_back(contours[i]);
}
drawContours(img_contours, contours,
-1, // draw all contours
cv::Scalar(255,0,0), // in blue
1); // with a thickness of 1
-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
-1, // draw all contours
cv::Scalar(0,255,0), // in green
1); // with a thickness of 1
displayImage(config, "Matching Contours", img_contours);
*/
}
//charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP));
if (charAnalysis->linePolygon.size() > 0)
{
@@ -120,7 +110,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
else if (absangle > 1)
confidenceDrainers += (10 - absangle) * 5;
if (confidenceDrainers >= 100)
this->confidence=1;
else
@@ -128,8 +117,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
}
if (config->debugTiming)
{
timespec endTime;
@@ -144,49 +131,47 @@ CharacterRegion::~CharacterRegion()
delete(charAnalysis);
}
Mat CharacterRegion::getPlateMask()
{
return charAnalysis->plateMask;
return charAnalysis->plateMask;
}
LineSegment CharacterRegion::getTopLine()
{
return charAnalysis->topLine;
return charAnalysis->topLine;
}
LineSegment CharacterRegion::getBottomLine()
{
return charAnalysis->bottomLine;
return charAnalysis->bottomLine;
}
vector<Point> CharacterRegion::getCharArea()
{
return charAnalysis->charArea;
return charAnalysis->charArea;
}
LineSegment CharacterRegion::getCharBoxTop()
{
return charAnalysis->charBoxTop;
return charAnalysis->charBoxTop;
}
LineSegment CharacterRegion::getCharBoxBottom()
{
return charAnalysis->charBoxBottom;
return charAnalysis->charBoxBottom;
}
LineSegment CharacterRegion::getCharBoxLeft()
{
return charAnalysis->charBoxLeft;
return charAnalysis->charBoxLeft;
}
LineSegment CharacterRegion::getCharBoxRight()
{
return charAnalysis->charBoxRight;
return charAnalysis->charBoxRight;
}
bool CharacterRegion::thresholdsInverted()
{
return charAnalysis->thresholdsInverted;
return charAnalysis->thresholdsInverted;
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,8 +24,7 @@
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
/* cJSON Types: */
@@ -40,22 +39,24 @@ extern "C"
#define cJSON_IsReference 256
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
typedef struct cJSON
{
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
typedef struct cJSON_Hooks
{
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */

View File

@@ -17,11 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "colorfilter.h"
ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
{
@@ -32,7 +29,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
this->debug = config->debugColorFiler;
this->grayscale = imageIsGrayscale(image);
if (this->debug)
@@ -48,7 +44,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
findCharColors();
if (config->debugTiming)
{
timespec endTime;
@@ -75,12 +70,12 @@ bool ColorFilter::imageIsGrayscale(Mat image)
if (r == g == b)
{
// So far so good
// So far so good
}
else
{
// Image is color.
return false;
// Image is color.
return false;
}
}
}
@@ -112,16 +107,14 @@ void ColorFilter::findCharColors()
Mat erodedCharMask(charMask.size(), CV_8U);
Mat element = getStructuringElement( 1,
Size( 2 + 1, 2+1 ),
Point( 1, 1 ) );
Size( 2 + 1, 2+1 ),
Point( 1, 1 ) );
erode(charMask, erodedCharMask, element);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(erodedCharMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
vector<float> hMeans, sMeans, vMeans;
vector<float> hStdDevs, sStdDevs, vStdDevs;
@@ -130,50 +123,46 @@ void ColorFilter::findCharColors()
if (hierarchy[i][3] != -1)
continue;
Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U);
Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U);
drawContours(singleCharMask, contours,
i, // draw this contour
cv::Scalar(255,255,255), // in
CV_FILLED,
8,
hierarchy
);
drawContours(singleCharMask, contours,
i, // draw this contour
cv::Scalar(255,255,255), // in
CV_FILLED,
8,
hierarchy
);
// get rid of the outline by drawing a 1 pixel width black line
drawContours(singleCharMask, contours,
i, // draw this contour
cv::Scalar(0,0,0), // in
1,
8,
hierarchy
);
// get rid of the outline by drawing a 1 pixel width black line
drawContours(singleCharMask, contours,
i, // draw this contour
cv::Scalar(0,0,0), // in
1,
8,
hierarchy
);
//drawAndWait(&singleCharMask);
Scalar mean;
Scalar stddev;
meanStdDev(hsv, mean, stddev, singleCharMask);
if (this->debug)
{
cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <<mean[1] << " v: " << setw(7) << mean[2]
<< " | Std: h: " << setw(7) <<stddev[0] << " s: " << setw(7) <<stddev[1] << " v: " << stddev[2] << endl;
}
//drawAndWait(&singleCharMask);
Scalar mean;
Scalar stddev;
meanStdDev(hsv, mean, stddev, singleCharMask);
if (this->debug)
{
cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <<mean[1] << " v: " << setw(7) << mean[2]
<< " | Std: h: " << setw(7) <<stddev[0] << " s: " << setw(7) <<stddev[1] << " v: " << stddev[2] << endl;
}
if (mean[0] == 0 && mean[1] == 0 && mean[2] == 0)
continue;
hMeans.push_back(mean[0]);
sMeans.push_back(mean[1]);
vMeans.push_back(mean[2]);
hStdDevs.push_back(stddev[0]);
sStdDevs.push_back(stddev[1]);
vStdDevs.push_back(stddev[2]);
if (mean[0] == 0 && mean[1] == 0 && mean[2] == 0)
continue;
hMeans.push_back(mean[0]);
sMeans.push_back(mean[1]);
vMeans.push_back(mean[2]);
hStdDevs.push_back(stddev[0]);
sStdDevs.push_back(stddev[1]);
vStdDevs.push_back(stddev[2]);
}
@@ -184,11 +173,9 @@ void ColorFilter::findCharColors()
int bestSatIndex = this->getMajorityOpinion(sMeans, .65, 35);
int bestValIndex = this->getMajorityOpinion(vMeans, .65, 30);
if (sMeans[bestSatIndex] < MINIMUM_SATURATION)
return;
bool doHueFilter = false, doSatFilter = false, doValFilter = false;
float hueMin, hueMax;
float satMin, satMax;
@@ -259,8 +246,6 @@ void ColorFilter::findCharColors()
cout << "ColorFilter Val: " << bestValIndex << " : " << setw(7) << vMeans[bestValIndex] << " -- " << valMin << "-" << valMax << endl;
}
Mat imgDebugHueOnly = Mat::zeros(hsv.size(), hsv.type());
Mat imgDebug = Mat::zeros(hsv.size(), hsv.type());
Mat imgDistanceFromCenter = Mat::zeros(hsv.size(), CV_8U);
@@ -291,19 +276,19 @@ void ColorFilter::findCharColors()
if (doHueFilter && (h < hueMin || h > hueMax))
{
hPasses = false;
imgDebug.at<Vec3b>(row, col)[0] = 0;
debugMask.at<uchar>(row, col) = 0;
hPasses = false;
imgDebug.at<Vec3b>(row, col)[0] = 0;
debugMask.at<uchar>(row, col) = 0;
}
if (doSatFilter && (s < satMin || s > satMax))
{
sPasses = false;
imgDebug.at<Vec3b>(row, col)[1] = 0;
sPasses = false;
imgDebug.at<Vec3b>(row, col)[1] = 0;
}
if (doValFilter && (v < valMin || v > valMax))
{
vPasses = false;
imgDebug.at<Vec3b>(row, col)[2] = 0;
vPasses = false;
imgDebug.at<Vec3b>(row, col)[2] = 0;
}
//if (pixelPasses)
@@ -314,27 +299,24 @@ void ColorFilter::findCharColors()
//imgDebug.at<Vec3b>(row, col)[2] = vPasses & 255;
if ((hPasses) || (hPasses && sPasses))//(hPasses && vPasses) || (sPasses && vPasses) ||
this->colorMask.at<uchar>(row, col) = 255;
this->colorMask.at<uchar>(row, col) = 255;
else
this->colorMask.at<uchar>(row, col) = 0;
this->colorMask.at<uchar>(row, col) = 0;
if ((hPasses && sPasses) || (hPasses && vPasses) || (sPasses && vPasses))
{
vDistance = pow(vDistance, 0.9);
vDistance = pow(vDistance, 0.9);
}
else
{
vDistance = pow(vDistance, 1.1);
vDistance = pow(vDistance, 1.1);
}
if (vDistance > 255)
vDistance = 255;
vDistance = 255;
imgDistanceFromCenter.at<uchar>(row, col) = vDistance;
}
}
vector<Mat> debugImagesSet;
if (this->debug)
@@ -346,14 +328,13 @@ void ColorFilter::findCharColors()
debugImagesSet.push_back(addLabel(maskCopy, "color Mask Before"));
}
Mat bigElement = getStructuringElement( 1,
Size( 3 + 1, 3+1 ),
Point( 1, 1 ) );
Size( 3 + 1, 3+1 ),
Point( 1, 1 ) );
Mat smallElement = getStructuringElement( 1,
Size( 1 + 1, 1+1 ),
Point( 1, 1 ) );
Size( 1 + 1, 1+1 ),
Point( 1, 1 ) );
morphologyEx(this->colorMask, this->colorMask, MORPH_CLOSE, bigElement);
//dilate(this->colorMask, this->colorMask, bigElement);
@@ -378,15 +359,12 @@ void ColorFilter::findCharColors()
debugImagesSet.push_back(addLabel(debugMask, "COLOR Hues off"));
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
// Return -1 if it fails.
int ColorFilter::getMajorityOpinion(vector<float> values, float minPercentAgreement, float maxValDifference)
@@ -403,7 +381,7 @@ int ColorFilter::getMajorityOpinion(vector<float> values, float minPercentAgreem
{
float diff = abs(values[i] - values[j]);
if (diff < maxValDifference)
valuesInRange++;
valuesInRange++;
overallDiff += diff;
}

View File

@@ -19,7 +19,6 @@
#include "config.h"
Config::Config(const std::string country, const std::string runtimeBaseDir)
{
this->runtimeBaseDir = runtimeBaseDir;
@@ -30,7 +29,7 @@ Config::Config(const std::string country, const std::string runtimeBaseDir)
envRuntimeDir = getenv (ENV_VARIABLE_RUNTIME_DIR);
if (runtimeBaseDir.compare("") != 0)
{
// User has supplied a runtime directory. Use that.
// User has supplied a runtime directory. Use that.
}
else if (envRuntimeDir!=NULL)
@@ -93,12 +92,10 @@ void Config::loadValues(string country)
ocrImageWidthPx = round(((float) templateWidthPx) * ocrImagePercent);
ocrImageHeightPx = round(((float)templateHeightPx) * ocrImagePercent);
float stateIdImagePercent = getFloat("common", "state_id_img_size_percent", 100);
stateIdImageWidthPx = round(((float)templateWidthPx) * ocrImagePercent);
stateIdimageHeightPx = round(((float)templateHeightPx) * ocrImagePercent);
charAnalysisMinPercent = getFloat(country, "char_analysis_min_pct", 0);
charAnalysisHeightRange = getFloat(country, "char_analysis_height_range", 0);
charAnalysisHeightStepSize = getFloat(country, "char_analysis_height_step_size", 0);
@@ -150,7 +147,6 @@ void Config::debugOff()
debugPostProcess = false;
}
string Config::getCascadeRuntimeDir()
{
return this->runtimeBaseDir + CASCADE_DIR;
@@ -168,9 +164,6 @@ string Config::getTessdataPrefix()
return "TESSDATA_PREFIX=" + this->runtimeBaseDir + "/ocr/";
}
float Config::getFloat(string section, string key, float defaultValue)
{
const char * pszValue = ini->GetValue(section.c_str(), key.c_str(), NULL /*default*/);

View File

@@ -110,7 +110,7 @@ class Config
string getPostProcessRuntimeDir();
string getTessdataPrefix();
private:
private:
CSimpleIniA* ini;
string runtimeBaseDir;

View File

@@ -23,7 +23,7 @@
#define POSTPROCESS_DIR "/postprocess"
#ifndef DEFAULT_RUNTIME_DIR
#define DEFAULT_RUNTIME_DIR "/default_runtime_data_dir/"
#define DEFAULT_RUNTIME_DIR "/default_runtime_data_dir/"
#endif
#define ENV_VARIABLE_RUNTIME_DIR "OPENALPR_RUNTIME_DIR"

View File

@@ -17,15 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "featurematcher.h"
//const int DEFAULT_QUERY_FEATURES = 305;
//const int DEFAULT_TRAINING_FEATURES = 305;
const float MAX_DISTANCE_TO_MATCH = 100.0f;
FeatureMatcher::FeatureMatcher(Config* config)
{
this->config = config;
@@ -35,7 +32,6 @@ FeatureMatcher::FeatureMatcher(Config* config)
//this->descriptorMatcher = DescriptorMatcher::create( "FlannBased" );
this->detector = new FastFeatureDetector(10, true);
this->extractor = new BRISK(10, 1, 0.9);
}
@@ -52,114 +48,103 @@ FeatureMatcher::~FeatureMatcher()
}
bool FeatureMatcher::isLoaded()
{
if( detector.empty() || extractor.empty() || descriptorMatcher.empty() )
{
return false;
}
if( detector.empty() || extractor.empty() || descriptorMatcher.empty() )
{
return false;
}
return true;
return true;
}
int FeatureMatcher::numTrainingElements()
{
return billMapping.size();
return billMapping.size();
}
void FeatureMatcher::surfStyleMatching( const Mat& queryDescriptors, vector<KeyPoint> queryKeypoints,
vector<DMatch>& matches12 )
vector<DMatch>& matches12 )
{
vector<vector<DMatch> > matchesKnn;
vector<vector<DMatch> > matchesKnn;
this->descriptorMatcher->radiusMatch(queryDescriptors, matchesKnn, MAX_DISTANCE_TO_MATCH);
this->descriptorMatcher->radiusMatch(queryDescriptors, matchesKnn, MAX_DISTANCE_TO_MATCH);
vector<DMatch> tempMatches;
_surfStyleMatching(queryDescriptors, matchesKnn, tempMatches);
vector<DMatch> tempMatches;
_surfStyleMatching(queryDescriptors, matchesKnn, tempMatches);
crisscrossFiltering(queryKeypoints, tempMatches, matches12);
crisscrossFiltering(queryKeypoints, tempMatches, matches12);
}
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;
for (int descInd = 0; descInd < queryDescriptors.rows; descInd++)
//objectMatches.clear();
//objectMatches.resize(objectIds.size());
//cout << "starting matcher" << matchesKnn.size() << endl;
for (int descInd = 0; descInd < queryDescriptors.rows; descInd++)
{
const std::vector<DMatch> & matches = matchesKnn[descInd];
//cout << "two: " << descInd << ":" << matches.size() << endl;
// 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)
//{
float ratioThreshold = 0.75;
// Check if both matches came from the same image. If they both came from the same image, score them slightly less harshly
if (matchesKnn[descInd][0].imgIdx == matchesKnn[descInd][1].imgIdx)
{
const std::vector<DMatch> & matches = matchesKnn[descInd];
//cout << "two: " << descInd << ":" << matches.size() << endl;
// 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)
//{
float ratioThreshold = 0.75;
// Check if both matches came from the same image. If they both came from the same image, score them slightly less harshly
if (matchesKnn[descInd][0].imgIdx == matchesKnn[descInd][1].imgIdx)
{
ratioThreshold = 0.85;
}
if ((matchesKnn[descInd][0].distance / matchesKnn[descInd][1].distance) < ratioThreshold)
{
bool already_exists = false;
// Quickly run through the matches we've already added and make sure it's not a duplicate...
for (int q = 0; q < matches12.size(); q++)
{
if (matchesKnn[descInd][0].queryIdx == matches12[q].queryIdx)
{
already_exists = true;
break;
}
else if ((matchesKnn[descInd][0].trainIdx == matches12[q].trainIdx) &&
(matchesKnn[descInd][0].imgIdx == matches12[q].imgIdx))
{
already_exists = true;
break;
}
}
// Good match.
if (already_exists == false)
matches12.push_back(matchesKnn[descInd][0]);
}
//}
}
else if (matchesKnn[descInd].size() == 1)
{
// Only match? Does this ever happen?
matches12.push_back(matchesKnn[descInd][0]);
}
// In the ratio test, we will compare the quality of a match with the next match that is not from the same object:
// we can accept several matches with similar scores as long as they are for the same object. Those should not be
// part of the model anyway as they are not discriminative enough
//for (unsigned int first_index = 0; first_index < matches.size(); ++first_index)
//{
//matches12.push_back(match);
//}
ratioThreshold = 0.85;
}
if ((matchesKnn[descInd][0].distance / matchesKnn[descInd][1].distance) < ratioThreshold)
{
bool already_exists = false;
// Quickly run through the matches we've already added and make sure it's not a duplicate...
for (int q = 0; q < matches12.size(); q++)
{
if (matchesKnn[descInd][0].queryIdx == matches12[q].queryIdx)
{
already_exists = true;
break;
}
else if ((matchesKnn[descInd][0].trainIdx == matches12[q].trainIdx) &&
(matchesKnn[descInd][0].imgIdx == matches12[q].imgIdx))
{
already_exists = true;
break;
}
}
// Good match.
if (already_exists == false)
matches12.push_back(matchesKnn[descInd][0]);
}
//}
}
else if (matchesKnn[descInd].size() == 1)
{
// Only match? Does this ever happen?
matches12.push_back(matchesKnn[descInd][0]);
}
// In the ratio test, we will compare the quality of a match with the next match that is not from the same object:
// we can accept several matches with similar scores as long as they are for the same object. Those should not be
// part of the model anyway as they are not discriminative enough
//for (unsigned int first_index = 0; first_index < matches.size(); ++first_index)
//{
//matches12.push_back(match);
//}
}
}
@@ -176,8 +161,8 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
vector<DMatch> matchesForOnePlate;
for (int j = 0; j < inputMatches.size(); j++)
{
if (inputMatches[j].imgIdx == i)
matchesForOnePlate.push_back(inputMatches[j]);
if (inputMatches[j].imgIdx == i)
matchesForOnePlate.push_back(inputMatches[j]);
}
// For each plate, compare the lines for the keypoints (training image and query image)
@@ -196,8 +181,6 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
matchIdx.push_back(j);
}
// Iterate through each line (n^2) removing the one with the most criss-crosses until there are none left.
int mostIntersections = 1;
while (mostIntersections > 0 && vlines.size() > 0)
@@ -207,37 +190,37 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
for (int j = 0; j < vlines.size(); j++)
{
int intrCount = 0;
for (int q = 0; q < vlines.size(); q++)
{
Point vintr = vlines[j].intersection(vlines[q]);
Point hintr = hlines[j].intersection(hlines[q]);
float vangleDiff = abs(vlines[j].angle - vlines[q].angle);
float hangleDiff = abs(hlines[j].angle - hlines[q].angle);
if (vintr.inside(crissCrossAreaVertical) && vangleDiff > 10)
{
intrCount++;
}
else if (hintr.inside(crissCrossAreaHorizontal) && hangleDiff > 10)
{
intrCount++;
}
}
int intrCount = 0;
for (int q = 0; q < vlines.size(); q++)
{
Point vintr = vlines[j].intersection(vlines[q]);
Point hintr = hlines[j].intersection(hlines[q]);
float vangleDiff = abs(vlines[j].angle - vlines[q].angle);
float hangleDiff = abs(hlines[j].angle - hlines[q].angle);
if (vintr.inside(crissCrossAreaVertical) && vangleDiff > 10)
{
intrCount++;
}
else if (hintr.inside(crissCrossAreaHorizontal) && hangleDiff > 10)
{
intrCount++;
}
}
if (intrCount > mostIntersections)
{
mostIntersections = intrCount;
mostIntersectionsIndex = j;
}
if (intrCount > mostIntersections)
{
mostIntersections = intrCount;
mostIntersectionsIndex = j;
}
}
if (mostIntersectionsIndex >= 0)
{
if (this->config->debugStateId)
cout << "Filtered intersection! " << billMapping[i] << endl;
vlines.erase(vlines.begin() + mostIntersectionsIndex);
hlines.erase(hlines.begin() + mostIntersectionsIndex);
matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex);
if (this->config->debugStateId)
cout << "Filtered intersection! " << billMapping[i] << endl;
vlines.erase(vlines.begin() + mostIntersectionsIndex);
hlines.erase(hlines.begin() + mostIntersectionsIndex);
matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex);
}
}
@@ -251,135 +234,124 @@ void FeatureMatcher::crisscrossFiltering(const vector<KeyPoint> queryKeypoints,
}
// Returns true if successful, false otherwise
bool FeatureMatcher::loadRecognitionSet(string country)
{
std::ostringstream out;
out << config->getKeypointsRuntimeDir() << "/" << country << "/";
string country_dir = out.str();
std::ostringstream out;
out << config->getKeypointsRuntimeDir() << "/" << country << "/";
string country_dir = out.str();
if (DirectoryExists(country_dir.c_str()))
{
vector<Mat> trainImages;
vector<string> plateFiles = getFilesInDir(country_dir.c_str());
if (DirectoryExists(country_dir.c_str()))
for (int i = 0; i < plateFiles.size(); i++)
{
vector<Mat> trainImages;
vector<string> plateFiles = getFilesInDir(country_dir.c_str());
if (hasEnding(plateFiles[i], ".jpg") == false)
continue;
for (int i = 0; i < plateFiles.size(); i++)
string fullpath = country_dir + plateFiles[i];
Mat img = imread( fullpath );
// convert to gray and resize to the size of the templates
cvtColor(img, img, CV_BGR2GRAY);
resize(img, img, getSizeMaintainingAspect(img, config->stateIdImageWidthPx, config->stateIdimageHeightPx));
if( img.empty() )
{
if (hasEnding(plateFiles[i], ".jpg") == false)
continue;
string fullpath = country_dir + plateFiles[i];
Mat img = imread( fullpath );
// convert to gray and resize to the size of the templates
cvtColor(img, img, CV_BGR2GRAY);
resize(img, img, getSizeMaintainingAspect(img, config->stateIdImageWidthPx, config->stateIdimageHeightPx));
if( img.empty() )
{
cout << "Can not read images" << endl;
return -1;
}
Mat descriptors;
vector<KeyPoint> keypoints;
detector->detect( img, keypoints );
extractor->compute(img, keypoints, descriptors);
if (descriptors.cols > 0)
{
billMapping.push_back(plateFiles[i].substr(0, 2));
trainImages.push_back(descriptors);
trainingImgKeypoints.push_back(keypoints);
}
cout << "Can not read images" << endl;
return -1;
}
Mat descriptors;
this->descriptorMatcher->add(trainImages);
this->descriptorMatcher->train();
vector<KeyPoint> keypoints;
detector->detect( img, keypoints );
extractor->compute(img, keypoints, descriptors);
if (descriptors.cols > 0)
{
billMapping.push_back(plateFiles[i].substr(0, 2));
trainImages.push_back(descriptors);
trainingImgKeypoints.push_back(keypoints);
}
return true;
}
return false;
this->descriptorMatcher->add(trainImages);
this->descriptorMatcher->train();
return true;
}
return false;
}
RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage,
bool debug_on, vector<int> debug_matches_array
)
bool debug_on, vector<int> debug_matches_array
)
{
RecognitionResult result;
RecognitionResult result;
result.haswinner = false;
result.haswinner = false;
Mat queryDescriptors;
vector<KeyPoint> queryKeypoints;
Mat queryDescriptors;
vector<KeyPoint> queryKeypoints;
detector->detect( queryImg, queryKeypoints );
extractor->compute(queryImg, queryKeypoints, queryDescriptors);
detector->detect( queryImg, queryKeypoints );
extractor->compute(queryImg, queryKeypoints, queryDescriptors);
if (queryKeypoints.size() <= 5)
if (queryKeypoints.size() <= 5)
{
// Cut it loose if there's less than 5 keypoints... nothing would ever match anyway and it could crash the matcher.
if (drawOnImage)
{
// Cut it loose if there's less than 5 keypoints... nothing would ever match anyway and it could crash the matcher.
if (drawOnImage)
{
drawKeypoints( queryImg, queryKeypoints, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT );
}
return result;
drawKeypoints( queryImg, queryKeypoints, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT );
}
return result;
}
vector<DMatch> filteredMatches;
surfStyleMatching( queryDescriptors, queryKeypoints, filteredMatches );
vector<DMatch> filteredMatches;
// Create and initialize the counts to 0
std::vector<int> bill_match_counts( billMapping.size() );
surfStyleMatching( queryDescriptors, queryKeypoints, filteredMatches );
for (int i = 0; i < billMapping.size(); i++)
{
bill_match_counts[i] = 0;
}
for (int i = 0; i < filteredMatches.size(); i++)
{
bill_match_counts[filteredMatches[i].imgIdx]++;
//if (filteredMatches[i].imgIdx
}
// Create and initialize the counts to 0
std::vector<int> bill_match_counts( billMapping.size() );
for (int i = 0; i < billMapping.size(); i++) { bill_match_counts[i] = 0; }
for (int i = 0; i < filteredMatches.size(); i++)
float max_count = 0; // represented as a percent (0 to 100)
int secondmost_count = 0;
int maxcount_index = -1;
for (int i = 0; i < billMapping.size(); i++)
{
if (bill_match_counts[i] > max_count && bill_match_counts[i] >= 4)
{
bill_match_counts[filteredMatches[i].imgIdx]++;
//if (filteredMatches[i].imgIdx
secondmost_count = max_count;
if (secondmost_count <= 2) // A value of 1 or 2 is effectively 0
secondmost_count = 0;
max_count = bill_match_counts[i];
maxcount_index = i;
}
}
float max_count = 0; // represented as a percent (0 to 100)
int secondmost_count = 0;
int maxcount_index = -1;
for (int i = 0; i < billMapping.size(); i++)
{
if (bill_match_counts[i] > max_count && bill_match_counts[i] >= 4)
{
secondmost_count = max_count;
if (secondmost_count <= 2) // A value of 1 or 2 is effectively 0
secondmost_count = 0;
max_count = bill_match_counts[i];
maxcount_index = i;
}
}
float score = ((max_count - secondmost_count - 3) / 10) * 100;
if (score < 0)
score = 0;
else if (score > 100)
score = 100;
float score = ((max_count - secondmost_count - 3) / 10) * 100;
if (score < 0)
score = 0;
else if (score > 100)
score = 100;
if (score > 0)
{
@@ -389,28 +361,28 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma
if (drawOnImage)
{
vector<KeyPoint> positiveMatches;
for (int i = 0; i < filteredMatches.size(); i++)
{
if (filteredMatches[i].imgIdx == maxcount_index)
{
positiveMatches.push_back( queryKeypoints[filteredMatches[i].queryIdx] );
}
}
vector<KeyPoint> positiveMatches;
for (int i = 0; i < filteredMatches.size(); i++)
{
if (filteredMatches[i].imgIdx == maxcount_index)
{
positiveMatches.push_back( queryKeypoints[filteredMatches[i].queryIdx] );
}
}
Mat tmpImg;
drawKeypoints( queryImg, queryKeypoints, tmpImg, CV_RGB(185, 0, 0), DrawMatchesFlags::DEFAULT );
drawKeypoints( tmpImg, positiveMatches, *outputImage, CV_RGB(0, 255, 0), DrawMatchesFlags::DEFAULT );
Mat tmpImg;
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 == true)
{
std::ostringstream out;
out << result.winner << " (" << result.confidence << "%)";
std::ostringstream out;
out << result.winner << " (" << result.confidence << "%)";
// we detected a bill, let the people know!
//putText(*outputImage, out.str(), Point(15, 27), FONT_HERSHEY_DUPLEX, 1.1, CV_RGB(0, 0, 0), 2);
}
// we detected a bill, let the people know!
//putText(*outputImage, out.str(), Point(15, 27), FONT_HERSHEY_DUPLEX, 1.1, CV_RGB(0, 0, 0), 2);
}
}
}
@@ -420,12 +392,11 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma
for (int i = 0; i < billMapping.size(); i++)
{
cout << billMapping[i] << " : " << bill_match_counts[i] << endl;
cout << billMapping[i] << " : " << bill_match_counts[i] << endl;
}
}
return result;
}

View File

@@ -38,7 +38,8 @@ using namespace std;
struct RecognitionResult {
struct RecognitionResult
{
bool haswinner;
string winner;
int confidence;
@@ -54,7 +55,7 @@ class FeatureMatcher
RecognitionResult recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage,
bool debug_on, vector<int> debug_matches_array );
bool debug_on, vector<int> debug_matches_array );
bool loadRecognitionSet(string country);
@@ -83,7 +84,7 @@ class FeatureMatcher
void surfStyleMatching( const Mat& queryDescriptors, vector<KeyPoint> queryKeypoints,
vector<DMatch>& matches12 );
vector<DMatch>& matches12 );
};

View File

@@ -19,13 +19,12 @@
#include "licenseplatecandidate.h"
LicensePlateCandidate::LicensePlateCandidate(Mat frame, Rect regionOfInterest, Config* config)
{
this->config = config;
this->config = config;
this->frame = frame;
this->plateRegion = regionOfInterest;
this->frame = frame;
this->plateRegion = regionOfInterest;
}
LicensePlateCandidate::~LicensePlateCandidate()
@@ -38,7 +37,6 @@ void LicensePlateCandidate::recognize()
{
charSegmenter = NULL;
this->confidence = 0;
int expandX = round(this->plateRegion.width * 0.15);
@@ -46,19 +44,14 @@ void LicensePlateCandidate::recognize()
// expand box by 15% in all directions
Rect expandedRegion = expandRect( this->plateRegion, expandX, expandY, frame.cols, frame.rows) ;
Mat plate_bgr = Mat(frame, expandedRegion);
resize(plate_bgr, plate_bgr, Size(config->templateWidthPx, config->templateHeightPx));
Mat plate_bgr_cleaned = Mat(plate_bgr.size(), plate_bgr.type());
this->cleanupColors(plate_bgr, plate_bgr_cleaned);
CharacterRegion charRegion(plate_bgr, config);
if (charRegion.confidence > 10)
{
@@ -75,15 +68,12 @@ void LicensePlateCandidate::recognize()
{
this->plateCorners = transformPointsToOriginalImage(frame, plate_bgr, expandedRegion, smallPlateCorners);
this->deskewed = deSkewPlate(frame, this->plateCorners);
charSegmenter = new CharacterSegmenter(deskewed, charRegion.thresholdsInverted(), config);
//this->recognizedText = ocr->recognizedText;
//strcpy(this->recognizedText, ocr.recognizedText);
//strcpy(this->recognizedText, ocr.recognizedText);
this->confidence = 100;
@@ -91,13 +81,8 @@ void LicensePlateCandidate::recognize()
charRegion.confidence = 0;
}
}
// Re-maps the coordinates from the smallImage to the coordinate space of the bigImage.
vector<Point2f> LicensePlateCandidate::transformPointsToOriginalImage(Mat bigImage, Mat smallImage, Rect region, vector<Point> corners)
{
@@ -116,7 +101,6 @@ vector<Point2f> LicensePlateCandidate::transformPointsToOriginalImage(Mat bigIma
return cornerPoints;
}
Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector<Point2f> corners)
{
@@ -134,8 +118,8 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector<Point2f> corners)
int height = round(((float) width) / aspect);
if (height > config->ocrImageHeightPx)
{
height = config->ocrImageHeightPx;
width = round(((float) height) * aspect);
height = config->ocrImageHeightPx;
width = round(((float) height) * aspect);
}
Mat deskewed(height, width, frame.type());
@@ -159,7 +143,6 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector<Point2f> corners)
return deskewed;
}
void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage)
{
if (this->config->debugGeneral)
@@ -174,26 +157,24 @@ void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage)
// Equalize intensity:
if(intermediate.channels() >= 3)
{
Mat ycrcb;
Mat ycrcb;
cvtColor(intermediate,ycrcb,CV_BGR2YCrCb);
cvtColor(intermediate,ycrcb,CV_BGR2YCrCb);
vector<Mat> channels;
split(ycrcb,channels);
vector<Mat> channels;
split(ycrcb,channels);
equalizeHist(channels[0], channels[0]);
equalizeHist(channels[0], channels[0]);
merge(channels,ycrcb);
merge(channels,ycrcb);
cvtColor(ycrcb,intermediate,CV_YCrCb2BGR);
cvtColor(ycrcb,intermediate,CV_YCrCb2BGR);
//ycrcb.release();
//ycrcb.release();
}
bilateralFilter(intermediate, outputImage, 3, 25, 35);
if (this->config->debugGeneral)
{
displayImage(config, "After cleanup", outputImage);

View File

@@ -17,30 +17,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ocr.h"
OCR::OCR(Config* config)
{
this->config = config;
this->postProcessor = new PostProcess(config);
this->postProcessor = new PostProcess(config);
tesseract=new TessBaseAPI();
tesseract=new TessBaseAPI();
// Tesseract requires the prefix directory to be set as an env variable
vector<char> tessdataPrefix(config->getTessdataPrefix().size() + 1);
// Tesseract requires the prefix directory to be set as an env variable
vector<char> tessdataPrefix(config->getTessdataPrefix().size() + 1);
strcpy(tessdataPrefix.data(), config->getTessdataPrefix().c_str());
putenv(tessdataPrefix.data());
strcpy(tessdataPrefix.data(), config->getTessdataPrefix().c_str());
putenv(tessdataPrefix.data());
tesseract->Init("", config->ocrLanguage.c_str() );
tesseract->SetVariable("save_blob_choices", "T");
//tesseract->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNPQRSTUVWXYZ1234567890");
tesseract->SetPageSegMode(PSM_SINGLE_CHAR);
tesseract->Init("", config->ocrLanguage.c_str() );
tesseract->SetVariable("save_blob_choices", "T");
//tesseract->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNPQRSTUVWXYZ1234567890");
tesseract->SetPageSegMode(PSM_SINGLE_CHAR);
}
OCR::~OCR()
@@ -50,18 +46,14 @@ OCR::~OCR()
delete tesseract;
}
void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
{
timespec startTime;
getTime(&startTime);
postProcessor->clear();
for (int i = 0; i < thresholds.size(); i++)
{
@@ -69,7 +61,6 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
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());
for (int j = 0; j < charRegions.size(); j++)
{
Rect expandedRegion = expandRect( charRegions[j], 2, 2, thresholds[i].cols, thresholds[i].rows) ;
@@ -79,52 +70,54 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
tesseract::ResultIterator* ri = tesseract->GetIterator();
tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL;
do {
const char* symbol = ri->GetUTF8Text(level);
float conf = ri->Confidence(level);
do
{
const char* symbol = ri->GetUTF8Text(level);
float conf = ri->Confidence(level);
bool dontcare;
int fontindex = 0;
int pointsize = 0;
const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex);
bool dontcare;
int fontindex = 0;
int pointsize = 0;
const char* fontName = ri->WordFontAttributes(&dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &dontcare, &pointsize, &fontindex);
if(symbol != 0 && pointsize >= config->ocrMinFontSize) {
postProcessor->addLetter(*symbol, j, conf);
if (this->config->debugOcr)
printf("charpos%d: threshold %d: symbol %s, conf: %f font: %s (index %d) size %dpx", j, i, symbol, conf, fontName, fontindex, pointsize);
bool indent = false;
tesseract::ChoiceIterator ci(*ri);
do {
const char* choice = ci.GetUTF8Text();
postProcessor->addLetter(*choice, j, ci.Confidence());
//letterScores.addScore(*choice, j, ci.Confidence() - MIN_CONFIDENCE);
if (this->config->debugOcr)
{
if (indent) printf("\t\t ");
printf("\t- ");
printf("%s conf: %f\n", choice, ci.Confidence());
}
indent = true;
} while(ci.Next());
}
if(symbol != 0 && pointsize >= config->ocrMinFontSize)
{
postProcessor->addLetter(*symbol, j, conf);
if (this->config->debugOcr)
printf("---------------------------------------------\n");
printf("charpos%d: threshold %d: symbol %s, conf: %f font: %s (index %d) size %dpx", j, i, symbol, conf, fontName, fontindex, pointsize);
delete[] symbol;
} while((ri->Next(level)));
bool indent = false;
tesseract::ChoiceIterator ci(*ri);
do
{
const char* choice = ci.GetUTF8Text();
postProcessor->addLetter(*choice, j, ci.Confidence());
//letterScores.addScore(*choice, j, ci.Confidence() - MIN_CONFIDENCE);
if (this->config->debugOcr)
{
if (indent) printf("\t\t ");
printf("\t- ");
printf("%s conf: %f\n", choice, ci.Confidence());
}
indent = true;
}
while(ci.Next());
}
if (this->config->debugOcr)
printf("---------------------------------------------\n");
delete[] symbol;
}
while((ri->Next(level)));
delete ri;
}
}
if (config->debugTiming)
@@ -134,7 +127,4 @@ void OCR::performOCR(vector<Mat> thresholds, vector<Rect> charRegions)
cout << "OCR Time: " << diffclock(startTime, endTime) << "ms." << endl;
}
}

View File

@@ -23,8 +23,8 @@
#ifndef OCR_H
#define OCR_H
#include <iostream>
#include <stdio.h>
#include <iostream>
#include <stdio.h>
#include "utility.h"
#include "postprocess.h"

View File

@@ -17,7 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "platecorners.h"
PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config)
@@ -27,8 +26,6 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi
if (this->config->debugPlateCorners)
cout << "PlateCorners constructor" << endl;
this->inputImage = inputImage;
this->plateLines = plateLines;
this->charRegion = charRegion;
@@ -36,7 +33,6 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi
this->bestHorizontalScore = 9999999999999;
this->bestVerticalScore = 9999999999999;
Point topPoint = charRegion->getTopLine().midpoint();
Point bottomPoint = charRegion->getBottomLine().closestPointOnSegmentTo(topPoint);
this->charHeight = distanceBetweenPoints(topPoint, bottomPoint);
@@ -57,7 +53,7 @@ PlateCorners::~PlateCorners()
vector<Point> PlateCorners::findPlateCorners()
{
if (this->config->debugPlateCorners)
cout << "PlateCorners::findPlateCorners" << endl;
cout << "PlateCorners::findPlateCorners" << endl;
timespec startTime;
getTime(&startTime);
@@ -65,15 +61,14 @@ vector<Point> PlateCorners::findPlateCorners()
int horizontalLines = this->plateLines->horizontalLines.size();
int verticalLines = this->plateLines->verticalLines.size();
// layout horizontal lines
for (int h1 = NO_LINE; h1 < horizontalLines; h1++)
{
for (int h2 = NO_LINE; h2 < horizontalLines; h2++)
{
if (h1 == h2 && h1 != NO_LINE) continue;
if (h1 == h2 && h1 != NO_LINE) continue;
this->scoreHorizontals(h1, h2);
this->scoreHorizontals(h1, h2);
}
}
@@ -81,35 +76,30 @@ vector<Point> PlateCorners::findPlateCorners()
// layout vertical lines
for (int v1 = NO_LINE; v1 < verticalLines; v1++)
{
for (int v2 = NO_LINE; v2 < verticalLines; v2++)
{
if (v1 == v2 && v1 != NO_LINE) continue;
for (int v2 = NO_LINE; v2 < verticalLines; v2++)
{
if (v1 == v2 && v1 != NO_LINE) continue;
this->scoreVerticals(v1, v2);
}
this->scoreVerticals(v1, v2);
}
}
if (this->config->debugPlateCorners)
{
cout << "Drawing debug stuff..." << endl;
cout << "Drawing debug stuff..." << endl;
Mat imgCorners = Mat(inputImage.size(), inputImage.type());
inputImage.copyTo(imgCorners);
for (int i = 0; i < 4; i++)
circle(imgCorners, charRegion->getCharArea()[i], 2, Scalar(0, 0, 0));
Mat imgCorners = Mat(inputImage.size(), inputImage.type());
inputImage.copyTo(imgCorners);
for (int i = 0; i < 4; i++)
circle(imgCorners, charRegion->getCharArea()[i], 2, Scalar(0, 0, 0));
line(imgCorners, this->bestTop.p1, this->bestTop.p2, Scalar(255, 0, 0), 1, CV_AA);
line(imgCorners, this->bestRight.p1, this->bestRight.p2, Scalar(0, 0, 255), 1, CV_AA);
line(imgCorners, this->bestBottom.p1, this->bestBottom.p2, Scalar(0, 0, 255), 1, CV_AA);
line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA);
line(imgCorners, this->bestTop.p1, this->bestTop.p2, Scalar(255, 0, 0), 1, CV_AA);
line(imgCorners, this->bestRight.p1, this->bestRight.p2, Scalar(0, 0, 255), 1, CV_AA);
line(imgCorners, this->bestBottom.p1, this->bestBottom.p2, Scalar(0, 0, 255), 1, CV_AA);
line(imgCorners, this->bestLeft.p1, this->bestLeft.p2, Scalar(255, 0, 0), 1, CV_AA);
displayImage(config, "Winning top/bottom Boundaries", imgCorners);
displayImage(config, "Winning top/bottom Boundaries", imgCorners);
}
@@ -127,8 +117,6 @@ vector<Point> PlateCorners::findPlateCorners()
corners.push_back(bestBottom.intersection(bestRight));
corners.push_back(bestBottom.intersection(bestLeft));
if (config->debugTiming)
{
timespec endTime;
@@ -139,7 +127,6 @@ vector<Point> PlateCorners::findPlateCorners()
return corners;
}
void PlateCorners::scoreVerticals(int v1, int v2)
{
@@ -148,8 +135,6 @@ void PlateCorners::scoreVerticals(int v1, int v2)
LineSegment left;
LineSegment right;
float charHeightToPlateWidthRatio = config->plateWidthMM / config->charHeightMM;
float idealPixelWidth = this->charHeight * (charHeightToPlateWidthRatio * 1.05); // Add 10% so we don't clip any characters
@@ -183,8 +168,6 @@ void PlateCorners::scoreVerticals(int v1, int v2)
score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL;
}
// Make sure this line is to the left of our license plate letters
if (left.isPointBelowLine(charRegion->getCharBoxLeft().midpoint()) == false)
return;
@@ -193,7 +176,6 @@ void PlateCorners::scoreVerticals(int v1, int v2)
if (right.isPointBelowLine(charRegion->getCharBoxRight().midpoint()))
return;
/////////////////////////////////////////////////////////////////////////
// Score "Distance from the edge...
/////////////////////////////////////////////////////////////////////////
@@ -204,7 +186,6 @@ void PlateCorners::scoreVerticals(int v1, int v2)
float distanceFromEdge = leftDistanceFromEdge + rightDistanceFromEdge;
score += distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT;
/////////////////////////////////////////////////////////////////////////
// Score "Boxiness" of the 4 lines. How close is it to a parallelogram?
/////////////////////////////////////////////////////////////////////////
@@ -213,12 +194,10 @@ void PlateCorners::scoreVerticals(int v1, int v2)
score += (verticalAngleDiff) * SCORING_BOXINESS_WEIGHT;
//////////////////////////////////////////////////////////////////////////
// SCORE the shape wrt character position and height relative to position
//////////////////////////////////////////////////////////////////////////
Point leftMidLinePoint = left.closestPointOnSegmentTo(charRegion->getCharBoxLeft().midpoint());
Point rightMidLinePoint = right.closestPointOnSegmentTo(charRegion->getCharBoxRight().midpoint());
@@ -230,7 +209,6 @@ void PlateCorners::scoreVerticals(int v1, int v2)
{
float scorecomponent;
if (this->config->debugPlateCorners)
{
cout << "xx xx Score: charHeight " << this->charHeight << endl;
@@ -277,7 +255,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
float charHeightToPlateHeightRatio = config->plateHeightMM / config->charHeightMM;
float idealPixelHeight = this->charHeight * charHeightToPlateHeightRatio;
if (h1 == NO_LINE && h2 == NO_LINE)
{
// return;
@@ -308,39 +285,26 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
score += SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL;
}
// Make sure this line is above our license plate letters
if (top.isPointBelowLine(charRegion->getCharBoxTop().midpoint()) == false)
return;
// Make sure this line is below our license plate letters
if (bottom.isPointBelowLine(charRegion->getCharBoxBottom().midpoint()))
return;
// We now have 4 possible lines. Let's put them to the test and score them...
/////////////////////////////////////////////////////////////////////////
// Score "Boxiness" of the 4 lines. How close is it to a parallelogram?
/////////////////////////////////////////////////////////////////////////
float horizontalAngleDiff = abs(top.angle - bottom.angle);
score += (horizontalAngleDiff) * SCORING_BOXINESS_WEIGHT;
// if (this->debug)
// cout << "PlateCorners boxiness score: " << (horizontalAngleDiff + verticalAngleDiff) * SCORING_BOXINESS_WEIGHT << endl;
//////////////////////////////////////////////////////////////////////////
// SCORE the shape wrt character position and height relative to position
//////////////////////////////////////////////////////////////////////////
@@ -351,7 +315,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
// Get the height difference
float heightRatio = charHeight / plateHeightPx;
float idealHeightRatio = (config->charHeightMM / config->plateHeightMM);
//if (leftRatio < MIN_CHAR_HEIGHT_RATIO || leftRatio > MAX_CHAR_HEIGHT_RATIO || rightRatio < MIN_CHAR_HEIGHT_RATIO || rightRatio > MAX_CHAR_HEIGHT_RATIO)
@@ -367,7 +330,6 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
// float idealBottomDistance = charHeight * (BOTTOM_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM);
// float distScore = abs(topDistance - idealTopDistance) + abs(bottomDistance - idealBottomDistance);
score += heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT;
//////////////////////////////////////////////////////////////////////////
@@ -398,14 +360,11 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
float charanglediff = abs(charAngle - top.angle) + abs(charAngle - bottom.angle);
score += charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT;
// if (this->debug)
// cout << "PlateCorners boxiness score: " << charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT << endl;
if (score < this->bestHorizontalScore)
{
float scorecomponent;
@@ -442,6 +401,4 @@ void PlateCorners::scoreHorizontals(int h1, int h2)
bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y);
}
}

View File

@@ -19,7 +19,6 @@
#include "platelines.h"
PlateLines::PlateLines(Config* config)
{
this->config = config;
@@ -28,7 +27,6 @@ PlateLines::PlateLines(Config* config)
if (debug)
cout << "PlateLines constructor" << endl;
}
PlateLines::~PlateLines()
@@ -36,22 +34,18 @@ PlateLines::~PlateLines()
}
void PlateLines::processImage(Mat inputImage, float sensitivity)
{
if (this->debug)
cout << "PlateLines findLines" << endl;
timespec startTime;
getTime(&startTime);
Mat smoothed(inputImage.size(), inputImage.type());
inputImage.copyTo(smoothed);
int morph_elem = 2;
int morph_size = 2;
int morph_elem = 2;
int morph_size = 2;
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
morphologyEx( smoothed, smoothed, MORPH_CLOSE, element );
@@ -65,12 +59,9 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
morphologyEx( smoothed, smoothed, MORPH_OPEN, element );
Mat edges(inputImage.size(), inputImage.type());
Canny(smoothed, edges, 66, 133);
vector<LineSegment> hlines = this->getLines(edges, sensitivity, false);
vector<LineSegment> vlines = this->getLines(edges, sensitivity, true);
for (int i = 0; i < hlines.size(); i++)
@@ -78,9 +69,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
for (int i = 0; i < vlines.size(); i++)
this->verticalLines.push_back(vlines[i]);
// if debug is enabled, draw the image
if (this->debug)
{
@@ -109,8 +97,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
displayImage(config, "Hough Lines", dashboard);
}
if (config->debugTiming)
{
timespec endTime;
@@ -119,7 +105,6 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
}
//smoothed.release();
//////////////// METHOD2!!!!!!!////////////////////
/*
@@ -127,33 +112,28 @@ void PlateLines::processImage(Mat inputImage, float sensitivity)
Mat imgCanny;
GaussianBlur(inputImage, imgBlur, Size(9, 9), 1, 1);
Canny(imgBlur, imgCanny, 10, 30, 3);
//int morph_elem = 2;
//int morph_size = 1;
//Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
morphologyEx( imgCanny, imgCanny, MORPH_CLOSE, element );
Mat imgShaped;
imgCanny.copyTo(imgShaped);
//Find contours of possibles characters
vector< vector< Point> > biggestShapes;
findContours(imgShaped,
biggestShapes, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours
biggestShapes, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours
// Draw blue contours on a white image
//cvtColor(imgShaped, imgShaped, CV_GRAY2RGB);
cv::drawContours(imgShaped,biggestShapes,
-1, // draw all contours
cv::Scalar(255,255,255), // in blue
1); // with a thickness of 1
-1, // draw all contours
cv::Scalar(255,255,255), // in blue
1); // with a thickness of 1
displayImage(config, "Blurred", imgCanny);
displayImage(config, "Blurred Contours", imgShaped);
@@ -187,7 +167,6 @@ vector<LineSegment> PlateLines::getLines(Mat edges, bool vertical)
vector<double> errors;
lswms.run(edges, lsegs, errors);
for( size_t i = 0; i < lsegs.size(); i++ )
{
@@ -247,7 +226,6 @@ vector<LineSegment> PlateLines::getLines(Mat edges, bool vertical)
}
*/
vector<LineSegment> PlateLines::getLines(Mat edges, float sensitivityMultiplier, bool vertical)
{
if (this->debug)
@@ -267,100 +245,92 @@ vector<LineSegment> PlateLines::getLines(Mat edges, float sensitivityMultiplier,
HoughLines( edges, allLines, 1, CV_PI/180, sensitivity, 0, 0 );
for( size_t i = 0; i < allLines.size(); i++ )
{
float rho = allLines[i][0], theta = allLines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
float rho = allLines[i][0], theta = allLines[i][1];
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
double angle = theta * (180 / CV_PI);
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
double angle = theta * (180 / CV_PI);
pt1.x = cvRound(x0 + 1000*(-b));
pt1.y = cvRound(y0 + 1000*(a));
pt2.x = cvRound(x0 - 1000*(-b));
pt2.y = cvRound(y0 - 1000*(a));
if (vertical)
{
if (angle < 20 || angle > 340 || (angle > 160 && angle < 210))
{
// good vertical
if (vertical)
{
if (angle < 20 || angle > 340 || (angle > 160 && angle < 210))
{
// good vertical
LineSegment line;
if (pt1.y <= pt2.y)
line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
else
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
LineSegment line;
if (pt1.y <= pt2.y)
line = LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
else
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
// Helps with debugging/rounding issues later
LineSegment top(0, 0, edges.cols, 0);
LineSegment bottom(0, edges.rows, edges.cols, edges.rows);
Point p1 = line.intersection(bottom);
Point p2 = line.intersection(top);
filteredLines.push_back(LineSegment(p1.x, p1.y, p2.x, p2.y));
}
}
else
{
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
// Helps with debugging/rounding issues later
LineSegment top(0, 0, edges.cols, 0);
LineSegment bottom(0, edges.rows, edges.cols, edges.rows);
Point p1 = line.intersection(bottom);
Point p2 = line.intersection(top);
filteredLines.push_back(LineSegment(p1.x, p1.y, p2.x, p2.y));
}
}
else
{
if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
{
// good horizontal
if ( (angle > 70 && angle < 110) || (angle > 250 && angle < 290))
{
// good horizontal
LineSegment line;
if (pt1.x <= pt2.x)
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
else
line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
LineSegment line;
if (pt1.x <= pt2.x)
line = LineSegment(pt1.x, pt1.y, pt2.x, pt2.y);
else
line =LineSegment(pt2.x, pt2.y, pt1.x, pt1.y);
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
// Helps with debugging/ rounding issues later
int newY1 = line.getPointAt(0);
int newY2 = line.getPointAt(edges.cols);
// Get rid of the -1000, 1000 stuff. Terminate at the edges of the image
// Helps with debugging/ rounding issues later
int newY1 = line.getPointAt(0);
int newY2 = line.getPointAt(edges.cols);
filteredLines.push_back(LineSegment(0, newY1, edges.cols, newY2));
}
}
filteredLines.push_back(LineSegment(0, newY1, edges.cols, newY2));
}
}
}
return filteredLines;
}
Mat PlateLines::customGrayscaleConversion(Mat src)
{
Mat img_hsv;
cvtColor(src,img_hsv,CV_BGR2HSV);
Mat grayscale = Mat(img_hsv.size(), CV_8U );
Mat hue(img_hsv.size(), CV_8U );
Mat grayscale = Mat(img_hsv.size(), CV_8U );
Mat hue(img_hsv.size(), CV_8U );
for (int row = 0; row < img_hsv.rows; row++)
for (int row = 0; row < img_hsv.rows; row++)
{
for (int col = 0; col < img_hsv.cols; col++)
{
for (int col = 0; col < img_hsv.cols; col++)
{
int h = (int) img_hsv.at<Vec3b>(row, col)[0];
int s = (int) img_hsv.at<Vec3b>(row, col)[1];
int v = (int) img_hsv.at<Vec3b>(row, col)[2];
int h = (int) img_hsv.at<Vec3b>(row, col)[0];
int s = (int) img_hsv.at<Vec3b>(row, col)[1];
int v = (int) img_hsv.at<Vec3b>(row, col)[2];
int pixval = pow(v, 1.05);
int pixval = pow(v, 1.05);
if (pixval > 255)
pixval = 255;
grayscale.at<uchar>(row, col) = pixval;
if (pixval > 255)
pixval = 255;
grayscale.at<uchar>(row, col) = pixval;
hue.at<uchar>(row, col) = h * (255.0 / 180.0);
}
hue.at<uchar>(row, col) = h * (255.0 / 180.0);
}
}
//displayImage(config, "Hue", hue);
return grayscale;
//displayImage(config, "Hue", hue);
return grayscale;
}

View File

@@ -19,7 +19,6 @@
#include "postprocess.h"
PostProcess::PostProcess(Config* config)
{
this->config = config;
@@ -29,12 +28,11 @@ PostProcess::PostProcess(Config* config)
std::ifstream infile(filename.str().c_str());
string region, pattern;
while (infile >> region >> pattern)
{
RegexRule* rule = new RegexRule(region, pattern);
//cout << "REGION: " << region << " PATTERN: " << pattern << endl;
//cout << "REGION: " << region << " PATTERN: " << pattern << endl;
if (rules.find(region) == rules.end())
{
@@ -61,16 +59,16 @@ PostProcess::~PostProcess()
// TODO: Delete all entries in rules vector
map<string, vector<RegexRule*> >::iterator iter;
for (iter = rules.begin(); iter != rules.end(); ++iter) {
for (iter = rules.begin(); iter != rules.end(); ++iter)
{
for (int i = 0; i < iter->second.size(); i++)
{
delete iter->second[i];
delete iter->second[i];
}
}
}
void PostProcess::addLetter(char letter, int charposition, float score)
{
if (score < config->postProcessMinConfidence)
@@ -80,8 +78,8 @@ void PostProcess::addLetter(char letter, int charposition, float score)
if (score < config->postProcessConfidenceSkipLevel)
{
float adjustedScore = abs(config->postProcessConfidenceSkipLevel - score) + config->postProcessMinConfidence;
insertLetter(SKIP_CHAR, charposition, adjustedScore );
float adjustedScore = abs(config->postProcessConfidenceSkipLevel - score) + config->postProcessMinConfidence;
insertLetter(SKIP_CHAR, charposition, adjustedScore );
}
//if (letter == '0')
@@ -96,25 +94,24 @@ void PostProcess::insertLetter(char letter, int charposition, float score)
score = score - config->postProcessMinConfidence;
int existingIndex = -1;
if (letters.size() < charposition + 1)
{
for (int i = letters.size(); i < charposition + 1; i++)
{
vector<Letter> tmp;
letters.push_back(tmp);
}
for (int i = letters.size(); i < charposition + 1; i++)
{
vector<Letter> tmp;
letters.push_back(tmp);
}
}
for (int i = 0; i < letters[charposition].size(); i++)
{
if (letters[charposition][i].letter == letter &&
letters[charposition][i].charposition == charposition)
{
existingIndex = i;
break;
}
if (letters[charposition][i].letter == letter &&
letters[charposition][i].charposition == charposition)
{
existingIndex = i;
break;
}
}
if (existingIndex == -1)
@@ -128,18 +125,17 @@ void PostProcess::insertLetter(char letter, int charposition, float score)
}
else
{
letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1;
letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score;
letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1;
letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score;
}
}
void PostProcess::clear()
{
for (int i = 0; i < letters.size(); i++)
{
letters[i].clear();
letters[i].clear();
}
letters.resize(0);
@@ -157,22 +153,18 @@ void PostProcess::analyze(string templateregion, int topn)
timespec startTime;
getTime(&startTime);
// Get a list of missing positions
for (int i = letters.size() -1; i >= 0; i--)
{
if (letters[i].size() == 0)
{
unknownCharPositions.push_back(i);
unknownCharPositions.push_back(i);
}
}
if (letters.size() == 0)
return;
// Sort the letters as they are
for (int i = 0; i < letters.size(); i++)
{
@@ -180,8 +172,6 @@ void PostProcess::analyze(string templateregion, int topn)
sort(letters[i].begin(), letters[i].end(), letterCompare);
}
if (this->config->debugPostProcess)
{
@@ -189,7 +179,7 @@ void PostProcess::analyze(string templateregion, int topn)
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;
cout << "PostProcess Letter: " << letters[i][j].charposition << " " << letters[i][j].letter << " -- score: " << letters[i][j].totalscore << " -- occurences: " << letters[i][j].occurences << endl;
}
}
@@ -211,7 +201,6 @@ void PostProcess::analyze(string templateregion, int topn)
vector<Letter> tmp;
findAllPermutations(tmp, 0, config->postProcessMaxSubstitutions);
timespec sortStartTime;
getTime(&sortStartTime);
@@ -228,11 +217,8 @@ void PostProcess::analyze(string templateregion, int topn)
cout << " -- PostProcess Sort Time: " << diffclock(sortStartTime, sortEndTime) << "ms." << endl;
}
matchesTemplate = false;
if (templateregion != "")
{
vector<RegexRule*> regionRules = rules[templateregion];
@@ -241,22 +227,20 @@ void PostProcess::analyze(string templateregion, int topn)
{
for (int j = 0; j < regionRules.size(); j++)
{
allPossibilities[i].matchesTemplate = regionRules[j]->match(allPossibilities[i].letters);
if (allPossibilities[i].matchesTemplate)
{
allPossibilities[i].letters = regionRules[j]->filterSkips(allPossibilities[i].letters);
//bestChars = regionRules[j]->filterSkips(allPossibilities[i].letters);
matchesTemplate = true;
break;
}
allPossibilities[i].matchesTemplate = regionRules[j]->match(allPossibilities[i].letters);
if (allPossibilities[i].matchesTemplate)
{
allPossibilities[i].letters = regionRules[j]->filterSkips(allPossibilities[i].letters);
//bestChars = regionRules[j]->filterSkips(allPossibilities[i].letters);
matchesTemplate = true;
break;
}
}
if (i >= topn - 1)
break;
break;
//if (matchesTemplate || i >= TOP_N - 1)
//break;
//break;
}
}
@@ -264,11 +248,11 @@ void PostProcess::analyze(string templateregion, int topn)
{
for (int z = 0; z < allPossibilities.size(); z++)
{
if (allPossibilities[z].matchesTemplate)
{
bestChars = allPossibilities[z].letters;
break;
}
if (allPossibilities[z].matchesTemplate)
{
bestChars = allPossibilities[z].letters;
break;
}
}
}
else
@@ -276,7 +260,7 @@ void PostProcess::analyze(string templateregion, int topn)
bestChars = allPossibilities[0].letters;
}
// Now adjust the confidence scores to a percentage value
// Now adjust the confidence scores to a percentage value
if (allPossibilities.size() > 0)
{
float maxPercentScore = calculateMaxConfidenceScore();
@@ -289,28 +273,23 @@ void PostProcess::analyze(string templateregion, int topn)
}
if (this->config->debugPostProcess)
{
// Print top words
for (int i = 0; i < allPossibilities.size(); i++)
{
cout << "Top " << topn << " Possibilities: " << allPossibilities[i].letters << " :\t" << allPossibilities[i].totalscore;
if (allPossibilities[i].letters == bestChars)
cout << " <--- ";
cout << " <--- ";
cout << endl;
if (i >= topn - 1)
break;
break;
}
cout << allPossibilities.size() << " total permutations" << endl;
}
if (config->debugTiming)
{
timespec endTime;
@@ -333,8 +312,8 @@ float PostProcess::calculateMaxConfidenceScore()
{
if (letters[i].size() > 0)
{
totalScore += (letters[i][0].totalscore / letters[i][0].occurences) + config->postProcessMinConfidence;
numScores++;
totalScore += (letters[i][0].totalscore / letters[i][0].occurences) + config->postProcessMinConfidence;
numScores++;
}
}
@@ -372,19 +351,18 @@ vector<int> PostProcess::getMaxDepth(int topn)
nextLeastDropCharPos = getNextLeastDrop(depth);
}
return depth;
}
int PostProcess::getPermutationCount(vector<int> depth)
{
int permutationCount = 1;
for (int i = 0; i < depth.size(); i++)
{
permutationCount *= (depth[i] + 1);
}
for (int i = 0; i < depth.size(); i++)
{
permutationCount *= (depth[i] + 1);
}
return permutationCount;
return permutationCount;
}
int PostProcess::getNextLeastDrop(vector<int> depth)
@@ -392,21 +370,21 @@ int PostProcess::getNextLeastDrop(vector<int> depth)
int nextLeastDropCharPos = -1;
float leastNextDrop = 99999999999;
for (int i = 0; i < letters.size(); i++)
for (int i = 0; i < letters.size(); i++)
{
if (depth[i] + 1 >= letters[i].size())
continue;
float drop = letters[i][depth[i]].totalscore - letters[i][depth[i]+1].totalscore;
if (drop < leastNextDrop)
{
if (depth[i] + 1 >= letters[i].size())
continue;
float drop = letters[i][depth[i]].totalscore - letters[i][depth[i]+1].totalscore;
if (drop < leastNextDrop)
{
nextLeastDropCharPos = i;
leastNextDrop = drop;
}
nextLeastDropCharPos = i;
leastNextDrop = drop;
}
}
return nextLeastDropCharPos;
return nextLeastDropCharPos;
}
const vector<PPResult> PostProcess::getResults()
@@ -426,23 +404,23 @@ void PostProcess::findAllPermutations(vector<Letter> prevletters, int charPos, i
if (charPos == letters.size() - 1)
{
// Last letter, add the word
PPResult possibility;
possibility.letters = "";
possibility.totalscore = 0;
possibility.matchesTemplate = false;
for (int z = 0; z < prevletters.size(); z++)
{
if (prevletters[z].letter != SKIP_CHAR)
possibility.letters = possibility.letters + prevletters[z].letter;
possibility.totalscore = possibility.totalscore + prevletters[z].totalscore;
}
// Last letter, add the word
PPResult possibility;
possibility.letters = "";
possibility.totalscore = 0;
possibility.matchesTemplate = false;
for (int z = 0; z < prevletters.size(); z++)
{
if (prevletters[z].letter != SKIP_CHAR)
possibility.letters = possibility.letters + prevletters[z].letter;
possibility.totalscore = possibility.totalscore + prevletters[z].totalscore;
}
if (letters[charPos][i].letter != SKIP_CHAR)
possibility.letters = possibility.letters + letters[charPos][i].letter;
possibility.totalscore = possibility.totalscore +letters[charPos][i].totalscore;
if (letters[charPos][i].letter != SKIP_CHAR)
possibility.letters = possibility.letters + letters[charPos][i].letter;
possibility.totalscore = possibility.totalscore +letters[charPos][i].totalscore;
allPossibilities.push_back(possibility);
allPossibilities.push_back(possibility);
}
else
{
@@ -450,9 +428,9 @@ void PostProcess::findAllPermutations(vector<Letter> prevletters, int charPos, i
float scorePercentDiff = abs( letters[charPos][0].totalscore - letters[charPos][i].totalscore ) / letters[charPos][0].totalscore;
if (i != 0 && letters[charPos][i].letter != SKIP_CHAR && scorePercentDiff > 0.10f )
findAllPermutations(prevletters, charPos + 1, substitutionsLeft - 1);
findAllPermutations(prevletters, charPos + 1, substitutionsLeft - 1);
else
findAllPermutations(prevletters, charPos + 1, substitutionsLeft);
findAllPermutations(prevletters, charPos + 1, substitutionsLeft);
prevletters.pop_back();
}
@@ -460,19 +438,15 @@ void PostProcess::findAllPermutations(vector<Letter> prevletters, int charPos, i
if (letters[charPos].size() == 0)
{
// No letters for this char position...
// Just pass it along
findAllPermutations(prevletters, charPos + 1, substitutionsLeft);
// No letters for this char position...
// Just pass it along
findAllPermutations(prevletters, charPos + 1, substitutionsLeft);
}
}
bool wordCompare( const PPResult &left, const PPResult &right ){
bool wordCompare( const PPResult &left, const PPResult &right )
{
if (left.totalscore < right.totalscore)
return false;
return true;
@@ -486,7 +460,6 @@ bool letterCompare( const Letter &left, const Letter &right )
return true;
}
RegexRule::RegexRule(string region, string pattern)
{
this->original = pattern;
@@ -495,31 +468,31 @@ RegexRule::RegexRule(string region, string pattern)
numchars = 0;
for (int i = 0; i < pattern.size(); i++)
{
if (pattern.at(i) == '[')
if (pattern.at(i) == '[')
{
while (pattern.at(i) != ']' )
{
while (pattern.at(i) != ']' )
{
this->regex = this->regex + pattern.at(i);
i++;
}
this->regex = this->regex + ']';
this->regex = this->regex + pattern.at(i);
i++;
}
this->regex = this->regex + ']';
}
else if (pattern.at(i) == '?')
{
this->regex = this->regex + '.';
this->skipPositions.push_back(numchars);
}
else if (pattern.at(i) == '@')
{
this->regex = this->regex + "\\a";
}
else if (pattern.at(i) == '#')
{
this->regex = this->regex + "\\d";
}
}
else if (pattern.at(i) == '?')
{
this->regex = this->regex + '.';
this->skipPositions.push_back(numchars);
}
else if (pattern.at(i) == '@')
{
this->regex = this->regex + "\\a";
}
else if (pattern.at(i) == '#')
{
this->regex = this->regex + "\\d";
}
numchars++;
numchars++;
}
trexp.Compile(this->regex.c_str());
@@ -529,7 +502,6 @@ RegexRule::RegexRule(string region, string pattern)
// cout << "AA Skip position: " << skipPositions[z] << endl;
}
bool RegexRule::match(string text)
{
if (text.length() != numchars)
@@ -544,17 +516,17 @@ string RegexRule::filterSkips(string text)
for (int i = 0; i < text.size(); i++)
{
bool skip = false;
for (int j = 0; j < skipPositions.size(); j++)
for (int j = 0; j < skipPositions.size(); j++)
{
if (skipPositions[j] == i)
{
if (skipPositions[j] == i)
{
skip = true;
break;
}
skip = true;
break;
}
}
if (skip == false)
response = response + text[i];
if (skip == false)
response = response + text[i];
}
return response;

View File

@@ -21,13 +21,13 @@
#ifndef POSTPROCESS_H
#define POSTPROCESS_H
#include "TRexpp.h"
#include "constants.h"
#include "utility.h"
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <vector>
#include "TRexpp.h"
#include "constants.h"
#include "utility.h"
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <vector>
#include "config.h"
using namespace std;
@@ -37,17 +37,17 @@ using namespace std;
struct Letter
{
char letter;
int charposition;
float totalscore;
int occurences;
char letter;
int charposition;
float totalscore;
int occurences;
};
struct PPResult
{
string letters;
float totalscore;
bool matchesTemplate;
string letters;
float totalscore;
bool matchesTemplate;
};

View File

@@ -17,39 +17,33 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "regiondetector.h"
RegionDetector::RegionDetector(Config* config)
{
this->config = config;
// Don't scale. Can change this in the future (i.e., maximum resolution preference, or some such).
this->scale_factor = 1.0f;
// Load either the regular or OpenCL version of the cascade classifier
if (config->opencl_enabled)
{
this->plate_cascade = new ocl::OclCascadeClassifier();
}
else
{
this->plate_cascade = new CascadeClassifier();
}
if( this->plate_cascade->load( config->getCascadeRuntimeDir() + config->country + ".xml" ) )
{
this->loaded = true;
}
else
{
this->loaded = false;
printf("--(!)Error loading classifier\n");
}
this->scale_factor = 1.0f;
// Load either the regular or OpenCL version of the cascade classifier
if (config->opencl_enabled)
{
this->plate_cascade = new ocl::OclCascadeClassifier();
}
else
{
this->plate_cascade = new CascadeClassifier();
}
if( this->plate_cascade->load( config->getCascadeRuntimeDir() + config->country + ".xml" ) )
{
this->loaded = true;
}
else
{
this->loaded = false;
printf("--(!)Error loading classifier\n");
}
}
@@ -58,14 +52,11 @@ RegionDetector::~RegionDetector()
delete this->plate_cascade;
}
bool RegionDetector::isLoaded()
{
return this->loaded;
}
vector<Rect> RegionDetector::detect(Mat frame)
{
@@ -77,7 +68,6 @@ vector<Rect> RegionDetector::detect(Mat frame)
return regionsOfInterest;
}
/** @function detectAndDisplay */
vector<Rect> RegionDetector::doCascade(Mat frame)
{
@@ -91,44 +81,41 @@ vector<Rect> RegionDetector::doCascade(Mat frame)
resize(frame, frame, Size(w * this->scale_factor, h * this->scale_factor));
//-- Detect plates
timespec startTime;
getTime(&startTime);
timespec startTime;
getTime(&startTime);
Size minSize(config->minPlateSizeWidthPx * this->scale_factor, config->minPlateSizeHeightPx * this->scale_factor);
Size maxSize(w * config->maxPlateWidthPercent * this->scale_factor, h * config->maxPlateHeightPercent * this->scale_factor);
Size minSize(config->minPlateSizeWidthPx * this->scale_factor, config->minPlateSizeHeightPx * this->scale_factor);
Size maxSize(w * config->maxPlateWidthPercent * this->scale_factor, h * config->maxPlateHeightPercent * this->scale_factor);
if (config->opencl_enabled)
{
ocl::oclMat openclFrame(frame);
((ocl::OclCascadeClassifier*) plate_cascade)->detectMultiScale(openclFrame, plates, 1.1, 3, 0, minSize, maxSize);
}
else
{
if (config->opencl_enabled)
{
ocl::oclMat openclFrame(frame);
((ocl::OclCascadeClassifier*) plate_cascade)->detectMultiScale(openclFrame, plates, 1.1, 3, 0, minSize, maxSize);
}
else
{
plate_cascade->detectMultiScale( frame, plates, 1.1, 3,
0,
//0|CV_HAAR_SCALE_IMAGE,
minSize, maxSize );
}
plate_cascade->detectMultiScale( frame, plates, 1.1, 3,
0,
//0|CV_HAAR_SCALE_IMAGE,
minSize, maxSize );
}
if (config->debugTiming)
{
timespec endTime;
getTime(&endTime);
cout << "LBP Time: " << diffclock(startTime, endTime) << "ms." << endl;
}
if (config->debugTiming)
{
timespec endTime;
getTime(&endTime);
cout << "LBP Time: " << diffclock(startTime, endTime) << "ms." << endl;
}
for( int i = 0; i < plates.size(); i++ )
{
plates[i].x = plates[i].x / scale_factor;
plates[i].y = plates[i].y / scale_factor;
plates[i].width = plates[i].width / scale_factor;
plates[i].height = plates[i].height / scale_factor;
}
for( int i = 0; i < plates.size(); i++ )
{
plates[i].x = plates[i].x / scale_factor;
plates[i].y = plates[i].y / scale_factor;
plates[i].width = plates[i].width / scale_factor;
plates[i].height = plates[i].height / scale_factor;
}
return plates;
return plates;
}

View File

@@ -99,16 +99,18 @@ typedef unsigned char Boolean; /* 0 or 1 */
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
typedef enum
{
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
typedef enum
{
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
@@ -117,28 +119,28 @@ extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);

File diff suppressed because it is too large Load Diff

View File

@@ -19,105 +19,106 @@
bool
snippets(
const char * a_pszFile,
bool a_bIsUtf8,
bool a_bUseMultiKey,
bool a_bUseMultiLine
)
const char * a_pszFile,
bool a_bIsUtf8,
bool a_bUseMultiKey,
bool a_bUseMultiLine
)
{
// LOADING DATA
// LOADING DATA
// load from a data file
CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
SI_Error rc = ini.LoadFile(a_pszFile);
if (rc < 0) return false;
// load from a data file
CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
SI_Error rc = ini.LoadFile(a_pszFile);
if (rc < 0) return false;
// load from a string
std::string strData;
rc = ini.LoadData(strData.c_str(), strData.size());
if (rc < 0) return false;
// load from a string
std::string strData;
rc = ini.LoadData(strData.c_str(), strData.size());
if (rc < 0) return false;
// GETTING SECTIONS AND KEYS
// GETTING SECTIONS AND KEYS
// get all sections
CSimpleIniA::TNamesDepend sections;
ini.GetAllSections(sections);
// get all sections
CSimpleIniA::TNamesDepend sections;
ini.GetAllSections(sections);
// get all keys in a section
CSimpleIniA::TNamesDepend keys;
ini.GetAllKeys("section-name", keys);
// get all keys in a section
CSimpleIniA::TNamesDepend keys;
ini.GetAllKeys("section-name", keys);
// GETTING VALUES
// GETTING VALUES
// get the value of a key
const char * pszValue = ini.GetValue("section-name",
"key-name", NULL /*default*/);
// get the value of a key
const char * pszValue = ini.GetValue("section-name",
"key-name", NULL /*default*/);
// get the value of a key which may have multiple
// values. If bHasMultipleValues is true, then just
// one value has been returned
bool bHasMultipleValues;
pszValue = ini.GetValue("section-name", "key-name",
NULL /*default*/, &bHasMultipleValues);
// get the value of a key which may have multiple
// values. If bHasMultipleValues is true, then just
// one value has been returned
bool bHasMultipleValues;
pszValue = ini.GetValue("section-name", "key-name",
NULL /*default*/, &bHasMultipleValues);
// get all values of a key with multiple values
CSimpleIniA::TNamesDepend values;
ini.GetAllValues("section-name", "key-name", values);
// get all values of a key with multiple values
CSimpleIniA::TNamesDepend values;
ini.GetAllValues("section-name", "key-name", values);
// sort the values into the original load order
// sort the values into the original load order
#if defined(_MSC_VER) && _MSC_VER <= 1200
/** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
values.sort();
/** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
values.sort();
#else
values.sort(CSimpleIniA::Entry::LoadOrder());
values.sort(CSimpleIniA::Entry::LoadOrder());
#endif
// output all of the items
CSimpleIniA::TNamesDepend::const_iterator i;
for (i = values.begin(); i != values.end(); ++i) {
printf("key-name = '%s'\n", i->pItem);
}
// output all of the items
CSimpleIniA::TNamesDepend::const_iterator i;
for (i = values.begin(); i != values.end(); ++i)
{
printf("key-name = '%s'\n", i->pItem);
}
// MODIFYING DATA
// MODIFYING DATA
// adding a new section
rc = ini.SetValue("new-section", NULL, NULL);
if (rc < 0) return false;
printf("section: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// adding a new section
rc = ini.SetValue("new-section", NULL, NULL);
if (rc < 0) return false;
printf("section: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// adding a new key ("new-section" will be added
// automatically if it doesn't already exist.
rc = ini.SetValue("new-section", "new-key", "value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// adding a new key ("new-section" will be added
// automatically if it doesn't already exist.
rc = ini.SetValue("new-section", "new-key", "value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// changing the value of a key
rc = ini.SetValue("section", "key", "updated-value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// changing the value of a key
rc = ini.SetValue("section", "key", "updated-value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// DELETING DATA
// DELETING DATA
// deleting a key from a section. Optionally the entire
// section may be deleted if it is now empty.
ini.Delete("section-name", "key-name",
true /*delete the section if empty*/);
// deleting a key from a section. Optionally the entire
// section may be deleted if it is now empty.
ini.Delete("section-name", "key-name",
true /*delete the section if empty*/);
// deleting an entire section and all keys in it
ini.Delete("section-name", NULL);
// deleting an entire section and all keys in it
ini.Delete("section-name", NULL);
// SAVING DATA
// SAVING DATA
// save the data to a string
rc = ini.Save(strData);
if (rc < 0) return false;
// save the data to a string
rc = ini.Save(strData);
if (rc < 0) return false;
// save the data back to the file
rc = ini.SaveFile(a_pszFile);
if (rc < 0) return false;
// save the data back to the file
rc = ini.SaveFile(a_pszFile);
if (rc < 0) return false;
return true;
return true;
}

View File

@@ -19,20 +19,19 @@
#include "stateidentifier.h"
StateIdentifier::StateIdentifier(Config* config)
{
this->config = config;
featureMatcher = new FeatureMatcher(config);
featureMatcher = new FeatureMatcher(config);
if (featureMatcher->isLoaded() == false)
{
cout << "Can not create detector or descriptor extractor or descriptor matcher of given types" << endl;
return;
}
if (featureMatcher->isLoaded() == false)
{
cout << "Can not create detector or descriptor extractor or descriptor matcher of given types" << endl;
return;
}
featureMatcher->loadRecognitionSet(config->country);
featureMatcher->loadRecognitionSet(config->country);
}
StateIdentifier::~StateIdentifier()
@@ -66,19 +65,16 @@ int StateIdentifier::recognize(Mat img, char* stateCode)
plateImg.copyTo(debugImg);
vector<int> matchesArray(featureMatcher->numTrainingElements());
RecognitionResult result = featureMatcher->recognize(plateImg, true, &debugImg, true, matchesArray );
if (this->config->debugStateId)
{
displayImage(config, "State Identifier1", plateImg);
displayImage(config, "State Identifier", debugImg);
cout << result.haswinner << " : " << result.confidence << " : " << result.winner << endl;
}
if (config->debugTiming)
{
timespec endTime;
@@ -86,12 +82,10 @@ int StateIdentifier::recognize(Mat img, char* stateCode)
cout << "State Identification Time: " << diffclock(startTime, endTime) << "ms." << endl;
}
if (result.haswinner == false)
return 0;
strcpy(stateCode, result.winner.c_str());
return result.confidence;
}

View File

@@ -1,43 +1,44 @@
#include "filesystem.h"
bool hasEnding (std::string const &fullString, std::string const &ending)
{
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
} else {
return false;
}
if (fullString.length() >= ending.length())
{
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
}
else
{
return false;
}
}
bool DirectoryExists( const char* pzPath )
{
if ( pzPath == NULL) return false;
if ( pzPath == NULL) return false;
DIR *pDir;
bool bExists = false;
DIR *pDir;
bool bExists = false;
pDir = opendir (pzPath);
pDir = opendir (pzPath);
if (pDir != NULL)
{
bExists = true;
(void) closedir (pDir);
}
if (pDir != NULL)
{
bExists = true;
(void) closedir (pDir);
}
return bExists;
return bExists;
}
bool fileExists( const char* pzPath )
{
if (pzPath == NULL) return false;
if (pzPath == NULL) return false;
bool fExists = false;
std::ifstream f(pzPath);
fExists = f.is_open();
f.close();
return fExists;
bool fExists = false;
std::ifstream f(pzPath);
fExists = f.is_open();
f.close();
return fExists;
}
std::vector<std::string> getFilesInDir(const char* dirPath)
@@ -47,14 +48,18 @@ std::vector<std::string> getFilesInDir(const char* dirPath)
std::vector<std::string> files;
struct dirent *ent;
if ((dir = opendir (dirPath)) != NULL) {
if ((dir = opendir (dirPath)) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
while ((ent = readdir (dir)) != NULL)
{
if (strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0)
files.push_back(ent->d_name);
files.push_back(ent->d_name);
}
closedir (dir);
} else {
}
else
{
/* could not open directory */
perror ("");
return files;
@@ -63,14 +68,14 @@ std::vector<std::string> getFilesInDir(const char* dirPath)
return files;
}
bool stringCompare( const std::string &left, const std::string &right ){
for( std::string::const_iterator lit = left.begin(), rit = right.begin(); lit != left.end() && rit != right.end(); ++lit, ++rit )
if( tolower( *lit ) < tolower( *rit ) )
return true;
else if( tolower( *lit ) > tolower( *rit ) )
return false;
if( left.size() < right.size() )
bool stringCompare( const std::string &left, const std::string &right )
{
for( std::string::const_iterator lit = left.begin(), rit = right.begin(); lit != left.end() && rit != right.end(); ++lit, ++rit )
if( tolower( *lit ) < tolower( *rit ) )
return true;
return false;
else if( tolower( *lit ) > tolower( *rit ) )
return false;
if( left.size() < right.size() )
return true;
return false;
}

View File

@@ -4,12 +4,12 @@
#ifdef WINDOWS
#include "windows/dirent.h"
#include "windows/utils.h"
#include "windows/unistd_partial.h"
#include "windows/dirent.h"
#include "windows/utils.h"
#include "windows/unistd_partial.h"
#else
#include <dirent.h>
#include <unistd.h>
#include <dirent.h>
#include <unistd.h>
#endif
#include <fstream>
@@ -19,12 +19,12 @@
#include <vector>
bool hasEnding (std::string const &fullString, std::string const &ending);
bool DirectoryExists( const char* pzPath );
bool fileExists( const char* pzPath );
std::vector<std::string> getFilesInDir(const char* dirPath);
bool hasEnding (std::string const &fullString, std::string const &ending);
bool DirectoryExists( const char* pzPath );
bool fileExists( const char* pzPath );
std::vector<std::string> getFilesInDir(const char* dirPath);
bool stringCompare( const std::string &left, const std::string &right );
bool stringCompare( const std::string &left, const std::string &right );
#endif // FILESYSTEM_H

View File

@@ -1,143 +1,144 @@
#include "timing.h"
timespec diff(timespec start, timespec end);
#ifdef WINDOWS
// Windows timing code
LARGE_INTEGER getFILETIMEoffset()
{
SYSTEMTIME s;
FILETIME f;
LARGE_INTEGER t;
SYSTEMTIME s;
FILETIME f;
LARGE_INTEGER t;
s.wYear = 1970;
s.wMonth = 1;
s.wDay = 1;
s.wHour = 0;
s.wMinute = 0;
s.wSecond = 0;
s.wMilliseconds = 0;
SystemTimeToFileTime(&s, &f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
return (t);
s.wYear = 1970;
s.wMonth = 1;
s.wDay = 1;
s.wHour = 0;
s.wMinute = 0;
s.wSecond = 0;
s.wMilliseconds = 0;
SystemTimeToFileTime(&s, &f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
return (t);
}
int clock_gettime(int X, timespec *tv)
{
LARGE_INTEGER t;
FILETIME f;
double microseconds;
static LARGE_INTEGER offset;
static double frequencyToMicroseconds;
static int initialized = 0;
static BOOL usePerformanceCounter = 0;
LARGE_INTEGER t;
FILETIME f;
double microseconds;
static LARGE_INTEGER offset;
static double frequencyToMicroseconds;
static int initialized = 0;
static BOOL usePerformanceCounter = 0;
if (!initialized) {
LARGE_INTEGER performanceFrequency;
initialized = 1;
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
if (usePerformanceCounter) {
QueryPerformanceCounter(&offset);
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
} else {
offset = getFILETIMEoffset();
frequencyToMicroseconds = 10.;
}
if (!initialized)
{
LARGE_INTEGER performanceFrequency;
initialized = 1;
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
if (usePerformanceCounter)
{
QueryPerformanceCounter(&offset);
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
}
if (usePerformanceCounter) QueryPerformanceCounter(&t);
else {
GetSystemTimeAsFileTime(&f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
else
{
offset = getFILETIMEoffset();
frequencyToMicroseconds = 10.;
}
}
if (usePerformanceCounter) QueryPerformanceCounter(&t);
else
{
GetSystemTimeAsFileTime(&f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
}
t.QuadPart -= offset.QuadPart;
microseconds = (double)t.QuadPart / frequencyToMicroseconds;
t.QuadPart = microseconds;
tv->tv_sec = t.QuadPart / 1000000;
tv->tv_usec = t.QuadPart % 1000000;
return (0);
t.QuadPart -= offset.QuadPart;
microseconds = (double)t.QuadPart / frequencyToMicroseconds;
t.QuadPart = microseconds;
tv->tv_sec = t.QuadPart / 1000000;
tv->tv_usec = t.QuadPart % 1000000;
return (0);
}
void getTime(timespec* time)
{
clock_gettime(0, time);
clock_gettime(0, time);
}
double diffclock(timespec time1,timespec time2)
{
timespec delta = diff(time1,time2);
double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0);
timespec delta = diff(time1,time2);
double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0);
return milliseconds;
return milliseconds;
}
timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_usec-start.tv_usec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_usec = 1000000+end.tv_usec-start.tv_usec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_usec = end.tv_usec-start.tv_usec;
}
return temp;
timespec temp;
if ((end.tv_usec-start.tv_usec)<0)
{
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_usec = 1000000+end.tv_usec-start.tv_usec;
}
else
{
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_usec = end.tv_usec-start.tv_usec;
}
return temp;
}
#else
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;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
time->tv_sec = mts.tv_sec;
time->tv_nsec = mts.tv_nsec;
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
time->tv_sec = mts.tv_sec;
time->tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, time);
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 delta = diff(time1,time2);
double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_nsec) / 1000000.0);
return milliseconds;
}
timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0)
{
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
}
else
{
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}
#endif

View File

@@ -11,13 +11,13 @@
// Support for Windows
#ifdef WINDOWS
#include <windows.h>
#include <windows.h>
#define timespec timeval
#define timespec timeval
#endif
void getTime(timespec* time);
double diffclock(timespec time1,timespec time2);
void getTime(timespec* time);
double diffclock(timespec time1,timespec time2);
#endif

View File

@@ -61,30 +61,30 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
typedef struct
{
char path[_TINYDIR_PATH_MAX];
char name[_TINYDIR_FILENAME_MAX];
int is_dir;
int is_reg;
char path[_TINYDIR_PATH_MAX];
char name[_TINYDIR_FILENAME_MAX];
int is_dir;
int is_reg;
#ifdef _MSC_VER
#else
struct stat _s;
struct stat _s;
#endif
} tinydir_file;
typedef struct
{
char path[_TINYDIR_PATH_MAX];
int has_next;
int n_files;
char path[_TINYDIR_PATH_MAX];
int has_next;
int n_files;
tinydir_file *_files;
tinydir_file *_files;
#ifdef _MSC_VER
HANDLE _h;
WIN32_FIND_DATA _f;
HANDLE _h;
WIN32_FIND_DATA _f;
#else
DIR *_d;
struct dirent *_e;
DIR *_d;
struct dirent *_e;
#endif
} tinydir_dir;
@@ -116,308 +116,288 @@ int _tinydir_file_cmp(const void *a, const void *b);
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const char *path)
{
if (dir == NULL || path == NULL || strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* initialise dir */
dir->_files = NULL;
if (dir == NULL || path == NULL || strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* initialise dir */
dir->_files = NULL;
#ifdef _MSC_VER
dir->_h = INVALID_HANDLE_VALUE;
dir->_h = INVALID_HANDLE_VALUE;
#else
dir->_d = NULL;
dir->_d = NULL;
#endif
tinydir_close(dir);
strcpy(dir->path, path);
tinydir_close(dir);
strcpy(dir->path, path);
#ifdef _MSC_VER
strcat(dir->path, "\\*");
dir->_h = FindFirstFile(dir->path, &dir->_f);
dir->path[strlen(dir->path) - 2] = '\0';
if (dir->_h == INVALID_HANDLE_VALUE)
strcat(dir->path, "\\*");
dir->_h = FindFirstFile(dir->path, &dir->_f);
dir->path[strlen(dir->path) - 2] = '\0';
if (dir->_h == INVALID_HANDLE_VALUE)
#else
dir->_d = opendir(path);
if (dir->_d == NULL)
dir->_d = opendir(path);
if (dir->_d == NULL)
#endif
{
errno = ENOENT;
goto bail;
}
/* read first file */
dir->has_next = 1;
{
errno = ENOENT;
goto bail;
}
/* read first file */
dir->has_next = 1;
#ifndef _MSC_VER
dir->_e = readdir(dir->_d);
if (dir->_e == NULL)
{
dir->has_next = 0;
}
dir->_e = readdir(dir->_d);
if (dir->_e == NULL)
{
dir->has_next = 0;
}
#endif
return 0;
return 0;
bail:
tinydir_close(dir);
return -1;
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const char *path)
{
if (tinydir_open(dir, path) == -1)
{
return -1;
}
dir->n_files = 0;
while (dir->has_next)
{
tinydir_file *p_file;
dir->n_files++;
dir->_files = (tinydir_file *)realloc(dir->_files, sizeof(tinydir_file)*dir->n_files);
if (dir->_files == NULL)
{
errno = ENOMEM;
goto bail;
}
p_file = &dir->_files[dir->n_files - 1];
if (tinydir_readfile(dir, p_file) == -1)
{
goto bail;
}
if (tinydir_next(dir) == -1)
{
goto bail;
}
}
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
return 0;
if (tinydir_open(dir, path) == -1)
{
return -1;
}
dir->n_files = 0;
while (dir->has_next)
{
tinydir_file *p_file;
dir->n_files++;
dir->_files = (tinydir_file *)realloc(dir->_files, sizeof(tinydir_file)*dir->n_files);
if (dir->_files == NULL)
{
errno = ENOMEM;
goto bail;
}
p_file = &dir->_files[dir->n_files - 1];
if (tinydir_readfile(dir, p_file) == -1)
{
goto bail;
}
if (tinydir_next(dir) == -1)
{
goto bail;
}
}
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
return 0;
bail:
tinydir_close(dir);
return -1;
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir)
{
if (dir == NULL)
{
return;
}
memset(dir->path, 0, sizeof(dir->path));
dir->has_next = 0;
dir->n_files = -1;
if (dir->_files != NULL)
{
free(dir->_files);
}
dir->_files = NULL;
if (dir == NULL)
{
return;
}
memset(dir->path, 0, sizeof(dir->path));
dir->has_next = 0;
dir->n_files = -1;
if (dir->_files != NULL)
{
free(dir->_files);
}
dir->_files = NULL;
#ifdef _MSC_VER
if (dir->_h != INVALID_HANDLE_VALUE)
{
FindClose(dir->_h);
}
dir->_h = INVALID_HANDLE_VALUE;
if (dir->_h != INVALID_HANDLE_VALUE)
{
FindClose(dir->_h);
}
dir->_h = INVALID_HANDLE_VALUE;
#else
if (dir->_d)
{
closedir(dir->_d);
}
dir->_d = NULL;
dir->_e = NULL;
if (dir->_d)
{
closedir(dir->_d);
}
dir->_d = NULL;
dir->_e = NULL;
#endif
}
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir)
{
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (!dir->has_next)
{
errno = ENOENT;
return -1;
}
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (!dir->has_next)
{
errno = ENOENT;
return -1;
}
#ifdef _MSC_VER
if (FindNextFile(dir->_h, &dir->_f) == 0)
if (FindNextFile(dir->_h, &dir->_f) == 0)
#else
dir->_e = readdir(dir->_d);
if (dir->_e == NULL)
dir->_e = readdir(dir->_d);
if (dir->_e == NULL)
#endif
{
dir->has_next = 0;
{
dir->has_next = 0;
#ifdef _MSC_VER
if (GetLastError() != ERROR_SUCCESS &&
GetLastError() != ERROR_NO_MORE_FILES)
{
tinydir_close(dir);
errno = EIO;
return -1;
}
if (GetLastError() != ERROR_SUCCESS &&
GetLastError() != ERROR_NO_MORE_FILES)
{
tinydir_close(dir);
errno = EIO;
return -1;
}
#endif
}
return 0;
}
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
{
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
#ifdef _MSC_VER
if (dir->_h == INVALID_HANDLE_VALUE)
if (dir->_h == INVALID_HANDLE_VALUE)
#else
if (dir->_e == NULL)
if (dir->_e == NULL)
#endif
{
errno = ENOENT;
return -1;
}
if (strlen(dir->path) +
strlen(
{
errno = ENOENT;
return -1;
}
if (strlen(dir->path) +
strlen(
#ifdef _MSC_VER
dir->_f.cFileName
dir->_f.cFileName
#else
dir->_e->d_name
dir->_e->d_name
#endif
) + 1 + _TINYDIR_PATH_EXTRA >=
_TINYDIR_PATH_MAX)
{
/* the path for the file will be too long */
errno = ENAMETOOLONG;
return -1;
}
if (strlen(
) + 1 + _TINYDIR_PATH_EXTRA >=
_TINYDIR_PATH_MAX)
{
/* the path for the file will be too long */
errno = ENAMETOOLONG;
return -1;
}
if (strlen(
#ifdef _MSC_VER
dir->_f.cFileName
dir->_f.cFileName
#else
dir->_e->d_name
dir->_e->d_name
#endif
) >= _TINYDIR_FILENAME_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
strcpy(file->path, dir->path);
strcat(file->path, "/");
strcpy(file->name,
) >= _TINYDIR_FILENAME_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
strcpy(file->path, dir->path);
strcat(file->path, "/");
strcpy(file->name,
#ifdef _MSC_VER
dir->_f.cFileName
dir->_f.cFileName
#else
dir->_e->d_name
dir->_e->d_name
#endif
);
strcat(file->path, file->name);
);
strcat(file->path, file->name);
#ifndef _MSC_VER
if (stat(file->path, &file->_s) == -1)
{
return -1;
}
if (stat(file->path, &file->_s) == -1)
{
return -1;
}
#endif
file->is_dir =
file->is_dir =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
#else
S_ISDIR(file->_s.st_mode);
S_ISDIR(file->_s.st_mode);
#endif
file->is_reg =
file->is_reg =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
(
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
(
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
#endif
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
#endif
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
#else
S_ISREG(file->_s.st_mode);
S_ISREG(file->_s.st_mode);
#endif
return 0;
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, int i)
{
if (dir == NULL || file == NULL || i < 0)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files)
{
errno = ENOENT;
return -1;
}
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
return 0;
if (dir == NULL || file == NULL || i < 0)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files)
{
errno = ENOENT;
return -1;
}
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
return 0;
}
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, int i)
{
char path[_TINYDIR_PATH_MAX];
if (dir == NULL || i < 0)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files || !dir->_files[i].is_dir)
{
errno = ENOENT;
return -1;
}
strcpy(path, dir->_files[i].path);
tinydir_close(dir);
if (tinydir_open_sorted(dir, path) == -1)
{
return -1;
}
return 0;
char path[_TINYDIR_PATH_MAX];
if (dir == NULL || i < 0)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files || !dir->_files[i].is_dir)
{
errno = ENOENT;
return -1;
}
strcpy(path, dir->_files[i].path);
tinydir_close(dir);
if (tinydir_open_sorted(dir, path) == -1)
{
return -1;
}
return 0;
}
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b)
{
const tinydir_file *fa = (const tinydir_file *)a;
const tinydir_file *fb = (const tinydir_file *)b;
if (fa->is_dir != fb->is_dir)
{
return -(fa->is_dir - fb->is_dir);
}
return strncasecmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
const tinydir_file *fa = (const tinydir_file *)a;
const tinydir_file *fb = (const tinydir_file *)b;
if (fa->is_dir != fb->is_dir)
{
return -(fa->is_dir - fb->is_dir);
}
return strncasecmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -3,5 +3,5 @@
static inline double round(double val)
{
return floor(val + 0.5);
return floor(val + 0.5);
}

View File

@@ -51,9 +51,10 @@
typedef unsigned int TRexBool;
typedef struct TRex TRex;
typedef struct {
const TRexChar *begin;
int len;
typedef struct
{
const TRexChar *begin;
int len;
} TRexMatch;
TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);

View File

@@ -17,12 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "utility.h"
Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY)
{
Rect expandedRegion = Rect(original);
@@ -48,22 +44,22 @@ Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, i
Mat drawImageDashboard(vector<Mat> images, int imageType, int numColumns)
{
int numRows = ceil((float) images.size() / (float) numColumns);
int numRows = ceil((float) images.size() / (float) numColumns);
Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType);
Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType);
for (int i = 0; i < numColumns * numRows; i++)
{
if (i < images.size())
images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows)));
else
{
Mat black = Mat::zeros(images[0].size(), imageType);
black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows)));
}
}
for (int i = 0; i < numColumns * numRows; i++)
{
if (i < images.size())
images[i].copyTo(dashboard(Rect((i%numColumns) * images[i].cols, floor((float) i/numColumns) * images[i].rows, images[i].cols, images[i].rows)));
else
{
Mat black = Mat::zeros(images[0].size(), imageType);
black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows)));
}
}
return dashboard;
return dashboard;
}
Mat addLabel(Mat input, string label)
@@ -90,15 +86,13 @@ Mat addLabel(Mat input, string label)
return newImage;
}
void drawAndWait(cv::Mat* frame)
{
cv::imshow("Temp Window", *frame);
while (cv::waitKey(50) == -1)
{
// loop
// loop
}
cv::destroyWindow("Temp Window");
@@ -137,7 +131,8 @@ vector<Mat> produceThresholds(const Mat img_gray, Config* config)
NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35));
bitwise_not(thresholds[i-1], thresholds[i-1]);
k = 1; win = 22;
k = 1;
win = 22;
NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35));
bitwise_not(thresholds[i-1], thresholds[i-1]);
//NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35));
@@ -151,11 +146,6 @@ vector<Mat> produceThresholds(const Mat img_gray, Config* config)
NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k);
bitwise_not(thresholds[i-1], thresholds[i-1]);
if (config->debugTiming)
{
timespec endTime;
@@ -180,7 +170,6 @@ double median(int array[], int arraySize)
return arraySize % 2 ? array[arraySize / 2] : (array[arraySize / 2 - 1] + array[arraySize / 2]) / 2;
}
Mat equalizeBrightness(Mat img)
{
@@ -194,7 +183,6 @@ Mat equalizeBrightness(Mat img)
normalize(img, img, 0, 255, NORM_MINMAX);
img.convertTo(img, CV_8U); // convert back to unsigned int
return img;
}
@@ -218,18 +206,17 @@ void fillMask(Mat img, const Mat mask, Scalar color)
if (m)
{
for (int z = 0; z < 3; z++)
{
int prevVal = img.at<Vec3b>(row, col)[z];
img.at<Vec3b>(row, col)[z] = ((int) color[z]) | prevVal;
}
for (int z = 0; z < 3; z++)
{
int prevVal = img.at<Vec3b>(row, col)[z];
img.at<Vec3b>(row, col)[z] = ((int) color[z]) | prevVal;
}
}
}
}
}
void drawX(Mat img, Rect rect, Scalar color, int thickness)
{
Point tl(rect.x, rect.y);
@@ -251,28 +238,26 @@ double distanceBetweenPoints(Point p1, Point p2)
float angleBetweenPoints(Point p1, Point p2)
{
int deltaY = p2.y - p1.y;
int deltaX = p2.x - p1.x;
int deltaY = p2.y - p1.y;
int deltaX = p2.x - p1.x;
return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI);
return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI);
}
Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight)
{
float aspect = ((float) inputImg.cols) / ((float) inputImg.rows);
float aspect = ((float) inputImg.cols) / ((float) inputImg.rows);
if (maxWidth / aspect > maxHeight)
{
return Size(maxHeight * aspect, maxHeight);
}
else
{
return Size(maxWidth, maxWidth / aspect);
}
if (maxWidth / aspect > maxHeight)
{
return Size(maxHeight * aspect, maxHeight);
}
else
{
return Size(maxWidth, maxWidth / aspect);
}
}
LineSegment::LineSegment()
{
init(0, 0, 0, 0);
@@ -292,18 +277,19 @@ void LineSegment::init(int x1, int y1, int x2, int y2)
this->p1 = Point(x1, y1);
this->p2 = Point(x2, y2);
if (p2.x - p1.x == 0)
this->slope = 0.00000000001;
else
this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x);
if (p2.x - p1.x == 0)
this->slope = 0.00000000001;
else
this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x);
this->length = distanceBetweenPoints(p1, p2);
this->length = distanceBetweenPoints(p1, p2);
this->angle = angleBetweenPoints(p1, p2);
this->angle = angleBetweenPoints(p1, p2);
}
bool LineSegment::isPointBelowLine( Point tp ){
return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0;
bool LineSegment::isPointBelowLine( Point tp )
{
return ((p2.x - p1.x)*(tp.y - p1.y) - (p2.y - p1.y)*(tp.x - p1.x)) > 0;
}
float LineSegment::getPointAt(float x)
@@ -328,41 +314,38 @@ Point LineSegment::closestPointOnSegmentTo(Point p)
Point LineSegment::intersection(LineSegment line)
{
float c1, c2;
float intersection_X = -1, intersection_Y= -1;
float c1, c2;
float intersection_X = -1, intersection_Y= -1;
c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2
c1 = p1.y - slope * p1.x; // which is same as y2 - slope * x2
c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2
c2 = line.p2.y - line.slope * line.p2.x; // which is same as y2 - slope * x2
if( (slope - line.slope) == 0)
{
//std::cout << "No Intersection between the lines" << endl;
}
else if (p1.x == p2.x)
{
// Line1 is vertical
return Point(p1.x, line.getPointAt(p1.x));
}
else if (line.p1.x == line.p2.x)
{
// Line2 is vertical
return Point(line.p1.x, getPointAt(line.p1.x));
}
else
{
intersection_X = (c2 - c1) / (slope - line.slope);
intersection_Y = slope * intersection_X + c1;
if( (slope - line.slope) == 0)
{
//std::cout << "No Intersection between the lines" << endl;
}
else if (p1.x == p2.x)
{
// Line1 is vertical
return Point(p1.x, line.getPointAt(p1.x));
}
else if (line.p1.x == line.p2.x)
{
// Line2 is vertical
return Point(line.p1.x, getPointAt(line.p1.x));
}
else
{
intersection_X = (c2 - c1) / (slope - line.slope);
intersection_Y = slope * intersection_X + c1;
}
}
return Point(intersection_X, intersection_Y);
return Point(intersection_X, intersection_Y);
}
Point LineSegment::midpoint()
{
// Handle the case where the line is vertical
@@ -381,17 +364,17 @@ Point LineSegment::midpoint()
LineSegment LineSegment::getParallelLine(float distance)
{
float diff_x = p2.x - p1.x;
float diff_y = p2.y - p1.y;
float angle = atan2( diff_x, diff_y);
float dist_x = distance * cos(angle);
float dist_y = -distance * sin(angle);
float diff_x = p2.x - p1.x;
float diff_y = p2.y - p1.y;
float angle = atan2( diff_x, diff_y);
float dist_x = distance * cos(angle);
float dist_y = -distance * sin(angle);
int offsetX = (int)round(dist_x);
int offsetY = (int)round(dist_y);
int offsetX = (int)round(dist_x);
int offsetY = (int)round(dist_y);
LineSegment result(p1.x + offsetX, p1.y + offsetY,
p2.x + offsetX, p2.y + offsetY);
LineSegment result(p1.x + offsetX, p1.y + offsetY,
p2.x + offsetX, p2.y + offsetY);
return result;
return result;
}

View File

@@ -32,8 +32,8 @@
#include "constants.h"
#include "support/timing.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include "binarize_wolf.h"
#include <vector>
@@ -41,13 +41,13 @@
/*
/*
struct LineSegment
{
float x1;
float y1;
float x2;
float y2;
float x1;
float y1;
float x2;
float y2;
};
*/
@@ -61,7 +61,7 @@ class LineSegment
float length;
float angle;
// LineSegment(Point point1, Point point2);
// LineSegment(Point point1, Point point2);
LineSegment();
LineSegment(int x1, int y1, int x2, int y2);
LineSegment(Point p1, Point p2);
@@ -90,30 +90,30 @@ class LineSegment
};
double median(int array[], int arraySize);
double median(int array[], int arraySize);
vector<Mat> produceThresholds(const Mat img_gray, Config* config);
vector<Mat> produceThresholds(const Mat img_gray, Config* config);
Mat drawImageDashboard(vector<Mat> images, int imageType, int numColumns);
Mat drawImageDashboard(vector<Mat> images, int imageType, int numColumns);
void displayImage(Config* config, string windowName, cv::Mat frame);
void drawAndWait(cv::Mat* frame);
void displayImage(Config* config, string windowName, cv::Mat frame);
void drawAndWait(cv::Mat* frame);
double distanceBetweenPoints(Point p1, Point p2);
double distanceBetweenPoints(Point p1, Point p2);
void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness);
void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness);
void drawX(Mat img, Rect rect, Scalar color, int thickness);
void fillMask(Mat img, const Mat mask, Scalar color);
void drawX(Mat img, Rect rect, Scalar color, int thickness);
void fillMask(Mat img, const Mat mask, Scalar color);
float angleBetweenPoints(Point p1, Point p2);
float angleBetweenPoints(Point p1, Point p2);
Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight);
Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight);
Mat equalizeBrightness(Mat img);
Mat equalizeBrightness(Mat img);
Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY);
Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY);
Mat addLabel(Mat input, string label);
Mat addLabel(Mat input, string label);
#endif // UTILITY_H

View File

@@ -23,8 +23,6 @@ VerticalHistogram::VerticalHistogram(Mat inputImage, Mat mask)
{
analyzeImage(inputImage, mask);
}
VerticalHistogram::~VerticalHistogram()
@@ -33,42 +31,38 @@ VerticalHistogram::~VerticalHistogram()
colHeights.clear();
}
void VerticalHistogram::analyzeImage(Mat inputImage, Mat mask)
{
highestPeak = 0;
lowestValley = inputImage.rows;
highestPeak = 0;
lowestValley = inputImage.rows;
histoImg = Mat::zeros(inputImage.size(), CV_8U);
histoImg = Mat::zeros(inputImage.size(), CV_8U);
int columnCount;
int columnCount;
for (int col = 0; col < inputImage.cols; col++)
{
columnCount = 0;
for (int col = 0; col < inputImage.cols; col++)
for (int row = 0; row < inputImage.rows; row++)
{
columnCount = 0;
for (int row = 0; row < inputImage.rows; row++)
{
if (inputImage.at<uchar>(row, col) > 0 && mask.at<uchar>(row, col) > 0)
columnCount++;
}
this->colHeights.push_back(columnCount);
if (columnCount < lowestValley)
lowestValley = columnCount;
if (columnCount > highestPeak)
highestPeak = columnCount;
for (; columnCount > 0; columnCount--)
histoImg.at<uchar>(inputImage.rows - columnCount, col) = 255;
if (inputImage.at<uchar>(row, col) > 0 && mask.at<uchar>(row, col) > 0)
columnCount++;
}
this->colHeights.push_back(columnCount);
if (columnCount < lowestValley)
lowestValley = columnCount;
if (columnCount > highestPeak)
highestPeak = columnCount;
for (; columnCount > 0; columnCount--)
histoImg.at<uchar>(inputImage.rows - columnCount, col) = 255;
}
}
int VerticalHistogram::getLocalMinimum(int leftX, int rightX)
@@ -107,7 +101,7 @@ int VerticalHistogram::getLocalMaximum(int leftX, int rightX)
int VerticalHistogram::getHeightAt(int x)
{
return colHeights[x];
return colHeights[x];
}
void VerticalHistogram::findValleys()
@@ -130,8 +124,7 @@ void VerticalHistogram::findValleys()
if (aboveMidpoint)
{
if (colHeights[i] > relativePeakHeight)
relativePeakHeight = colHeights[i];
relativePeakHeight = colHeights[i];
prevDirection = FLAT;
@@ -171,7 +164,7 @@ HistogramDirection VerticalHistogram::getHistogramDirection(int index)
for (int i = index; i >= trailStartIndex; i--)
{
trailingAverage += colHeights[i];
trailingAverage += colHeights[i];
}
trailingAverage = trailingAverage / ((float) (1 + index - trailStartIndex));
@@ -181,7 +174,6 @@ HistogramDirection VerticalHistogram::getHistogramDirection(int index)
}
forwardAverage = forwardAverage / ((float) (1 + forwardEndIndex - index));
float diff = forwardAverage - trailingAverage;
float minDiff = ((float) (highestPeak - lowestValley)) * 0.10;

View File

@@ -29,10 +29,10 @@ using namespace std;
struct Valley
{
int startIndex;
int endIndex;
int width;
int pixelsWithin;
int startIndex;
int endIndex;
int width;
int pixelsWithin;
};
enum HistogramDirection { RISING, FALLING, FLAT };

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,8 @@
#include <string>
#include <exception>
namespace TCLAP {
namespace TCLAP
{
/**
* A simple class that defines and argument exception. Should be caught
@@ -35,82 +36,85 @@ namespace TCLAP {
*/
class ArgException : public std::exception
{
public:
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source.
* \param td - Text describing the type of ArgException it is.
* of the exception.
*/
ArgException( const std::string& text = "undefined exception",
const std::string& id = "undefined",
const std::string& td = "Generic ArgException")
: std::exception(),
_errorText(text),
_argId( id ),
_typeDescription(td)
{ }
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source.
* \param td - Text describing the type of ArgException it is.
* of the exception.
*/
ArgException( const std::string& text = "undefined exception",
const std::string& id = "undefined",
const std::string& td = "Generic ArgException")
: std::exception(),
_errorText(text),
_argId( id ),
_typeDescription(td)
{ }
/**
* Destructor.
*/
virtual ~ArgException() throw() { }
/**
* Destructor.
*/
virtual ~ArgException() throw() { }
/**
* Returns the error text.
*/
std::string error() const { return ( _errorText ); }
/**
* Returns the error text.
*/
std::string error() const
{
return ( _errorText );
}
/**
* Returns the argument id.
*/
std::string argId() const
{
if ( _argId == "undefined" )
return " ";
else
return ( "Argument: " + _argId );
}
/**
* Returns the argument id.
*/
std::string argId() const
{
if ( _argId == "undefined" )
return " ";
else
return ( "Argument: " + _argId );
}
/**
* Returns the arg id and error text.
*/
const char* what() const throw()
{
static std::string ex;
ex = _argId + " -- " + _errorText;
return ex.c_str();
}
/**
* Returns the arg id and error text.
*/
const char* what() const throw()
{
static std::string ex;
ex = _argId + " -- " + _errorText;
return ex.c_str();
}
/**
* Returns the type of the exception. Used to explain and distinguish
* between different child exceptions.
*/
std::string typeDescription() const
{
return _typeDescription;
}
/**
* Returns the type of the exception. Used to explain and distinguish
* between different child exceptions.
*/
std::string typeDescription() const
{
return _typeDescription;
}
private:
private:
/**
* The text of the exception message.
*/
std::string _errorText;
/**
* The text of the exception message.
*/
std::string _errorText;
/**
* The argument related to this exception.
*/
std::string _argId;
/**
* The argument related to this exception.
*/
std::string _argId;
/**
* Describes the type of the exception. Used to distinguish
* between different child exceptions.
*/
std::string _typeDescription;
/**
* Describes the type of the exception. Used to distinguish
* between different child exceptions.
*/
std::string _typeDescription;
};
@@ -120,20 +124,20 @@ class ArgException : public std::exception
*/
class ArgParseException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
ArgParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found while parsing " ) +
std::string( "the value the Arg has been passed." ))
{ }
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
ArgParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found while parsing " ) +
std::string( "the value the Arg has been passed." ))
{ }
};
/**
@@ -142,22 +146,22 @@ class ArgParseException : public ArgException
*/
class CmdLineParseException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
CmdLineParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found when the values ") +
std::string( "on the command line do not meet ") +
std::string( "the requirements of the defined ") +
std::string( "Args." ))
{ }
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
CmdLineParseException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string( "Exception found when the values ") +
std::string( "on the command line do not meet ") +
std::string( "the requirements of the defined ") +
std::string( "Args." ))
{ }
};
/**
@@ -166,32 +170,36 @@ class CmdLineParseException : public ArgException
*/
class SpecificationException : public ArgException
{
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
SpecificationException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string("Exception found when an Arg object ")+
std::string("is improperly defined by the ") +
std::string("developer." ))
{ }
public:
/**
* Constructor.
* \param text - The text of the exception.
* \param id - The text identifying the argument source
* of the exception.
*/
SpecificationException( const std::string& text = "undefined exception",
const std::string& id = "undefined" )
: ArgException( text,
id,
std::string("Exception found when an Arg object ")+
std::string("is improperly defined by the ") +
std::string("developer." ))
{ }
};
class ExitException {
public:
ExitException(int estat) : _estat(estat) {}
class ExitException
{
public:
ExitException(int estat) : _estat(estat) {}
int getExitStatus() const { return _estat; }
int getExitStatus() const
{
return _estat;
}
private:
int _estat;
private:
int _estat;
};
} // namespace TCLAP

View File

@@ -26,7 +26,8 @@
#ifndef TCLAP_ARGTRAITS_H
#define TCLAP_ARGTRAITS_H
namespace TCLAP {
namespace TCLAP
{
// We use two empty structs to get compile type specialization
// function to work
@@ -35,9 +36,10 @@ namespace TCLAP {
* A value like argument value type is a value that can be set using
* operator>>. This is the default value type.
*/
struct ValueLike {
typedef ValueLike ValueCategory;
virtual ~ValueLike() {}
struct ValueLike
{
typedef ValueLike ValueCategory;
virtual ~ValueLike() {}
};
/**
@@ -45,8 +47,9 @@ struct ValueLike {
* operator=(string). Usefull if the value type contains spaces which
* will be broken up into individual tokens by operator>>.
*/
struct StringLike {
virtual ~StringLike() {}
struct StringLike
{
virtual ~StringLike() {}
};
/**
@@ -54,9 +57,10 @@ struct StringLike {
* traits. This is a compile time thing and does not add any overhead
* to the inherenting class.
*/
struct StringLikeTrait {
typedef StringLike ValueCategory;
virtual ~StringLikeTrait() {}
struct StringLikeTrait
{
typedef StringLike ValueCategory;
virtual ~StringLikeTrait() {}
};
/**
@@ -64,9 +68,10 @@ struct StringLikeTrait {
* traits. This is a compile time thing and does not add any overhead
* to the inherenting class.
*/
struct ValueLikeTrait {
typedef ValueLike ValueCategory;
virtual ~ValueLikeTrait() {}
struct ValueLikeTrait
{
typedef ValueLike ValueCategory;
virtual ~ValueLikeTrait() {}
};
/**
@@ -76,10 +81,11 @@ struct ValueLikeTrait {
* supported types are StringLike and ValueLike.
*/
template<typename T>
struct ArgTraits {
typedef typename T::ValueCategory ValueCategory;
virtual ~ArgTraits() {}
//typedef ValueLike ValueCategory;
struct ArgTraits
{
typedef typename T::ValueCategory ValueCategory;
virtual ~ArgTraits() {}
//typedef ValueLike ValueCategory;
};
#endif

View File

@@ -48,18 +48,19 @@
#include <algorithm>
#include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
namespace TCLAP {
namespace TCLAP
{
template<typename T> void DelPtr(T ptr)
{
delete ptr;
delete ptr;
}
template<typename C> void ClearContainer(C &c)
{
typedef typename C::value_type value_type;
std::for_each(c.begin(), c.end(), DelPtr<value_type>);
c.clear();
typedef typename C::value_type value_type;
std::for_each(c.begin(), c.end(), DelPtr<value_type>);
c.clear();
}
@@ -69,249 +70,249 @@ template<typename C> void ClearContainer(C &c)
*/
class CmdLine : public CmdLineInterface
{
protected:
protected:
/**
* The list of arguments that will be tested against the
* command line.
*/
std::list<Arg*> _argList;
/**
* The list of arguments that will be tested against the
* command line.
*/
std::list<Arg*> _argList;
/**
* The name of the program. Set to argv[0].
*/
std::string _progName;
/**
* The name of the program. Set to argv[0].
*/
std::string _progName;
/**
* A message used to describe the program. Used in the usage output.
*/
std::string _message;
/**
* A message used to describe the program. Used in the usage output.
*/
std::string _message;
/**
* The version to be displayed with the --version switch.
*/
std::string _version;
/**
* The version to be displayed with the --version switch.
*/
std::string _version;
/**
* The number of arguments that are required to be present on
* the command line. This is set dynamically, based on the
* Args added to the CmdLine object.
*/
int _numRequired;
/**
* The number of arguments that are required to be present on
* the command line. This is set dynamically, based on the
* Args added to the CmdLine object.
*/
int _numRequired;
/**
* The character that is used to separate the argument flag/name
* from the value. Defaults to ' ' (space).
*/
char _delimiter;
/**
* The character that is used to separate the argument flag/name
* from the value. Defaults to ' ' (space).
*/
char _delimiter;
/**
* The handler that manages xoring lists of args.
*/
XorHandler _xorHandler;
/**
* The handler that manages xoring lists of args.
*/
XorHandler _xorHandler;
/**
* A list of Args to be explicitly deleted when the destructor
* is called. At the moment, this only includes the three default
* Args.
*/
std::list<Arg*> _argDeleteOnExitList;
/**
* A list of Args to be explicitly deleted when the destructor
* is called. At the moment, this only includes the three default
* Args.
*/
std::list<Arg*> _argDeleteOnExitList;
/**
* A list of Visitors to be explicitly deleted when the destructor
* is called. At the moment, these are the Vistors created for the
* default Args.
*/
std::list<Visitor*> _visitorDeleteOnExitList;
/**
* A list of Visitors to be explicitly deleted when the destructor
* is called. At the moment, these are the Vistors created for the
* default Args.
*/
std::list<Visitor*> _visitorDeleteOnExitList;
/**
* Object that handles all output for the CmdLine.
*/
CmdLineOutput* _output;
/**
* Object that handles all output for the CmdLine.
*/
CmdLineOutput* _output;
/**
* Should CmdLine handle parsing exceptions internally?
*/
bool _handleExceptions;
/**
* Should CmdLine handle parsing exceptions internally?
*/
bool _handleExceptions;
/**
* Throws an exception listing the missing args.
*/
void missingArgsException();
/**
* Throws an exception listing the missing args.
*/
void missingArgsException();
/**
* Checks whether a name/flag string matches entirely matches
* the Arg::blankChar. Used when multiple switches are combined
* into a single argument.
* \param s - The message to be used in the usage.
*/
bool _emptyCombined(const std::string& s);
/**
* Checks whether a name/flag string matches entirely matches
* the Arg::blankChar. Used when multiple switches are combined
* into a single argument.
* \param s - The message to be used in the usage.
*/
bool _emptyCombined(const std::string& s);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Arg* ptr);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Arg* ptr);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Visitor* ptr);
/**
* Perform a delete ptr; operation on ptr when this object is deleted.
*/
void deleteOnExit(Visitor* ptr);
private:
private:
/**
* Prevent accidental copying.
*/
CmdLine(const CmdLine& rhs);
CmdLine& operator=(const CmdLine& rhs);
/**
* Prevent accidental copying.
*/
CmdLine(const CmdLine& rhs);
CmdLine& operator=(const CmdLine& rhs);
/**
* Encapsulates the code common to the constructors
* (which is all of it).
*/
void _constructor();
/**
* Encapsulates the code common to the constructors
* (which is all of it).
*/
void _constructor();
/**
* Is set to true when a user sets the output object. We use this so
* that we don't delete objects that are created outside of this lib.
*/
bool _userSetOutput;
/**
* Is set to true when a user sets the output object. We use this so
* that we don't delete objects that are created outside of this lib.
*/
bool _userSetOutput;
/**
* Whether or not to automatically create help and version switches.
*/
bool _helpAndVersion;
/**
* Whether or not to automatically create help and version switches.
*/
bool _helpAndVersion;
public:
public:
/**
* Command line constructor. Defines how the arguments will be
* parsed.
* \param message - The message to be used in the usage
* output.
* \param delimiter - The character that is used to separate
* the argument flag/name from the value. Defaults to ' ' (space).
* \param version - The version number to be used in the
* --version switch.
* \param helpAndVersion - Whether or not to create the Help and
* Version switches. Defaults to true.
*/
CmdLine(const std::string& message,
const char delimiter = ' ',
const std::string& version = "none",
bool helpAndVersion = true);
/**
* Command line constructor. Defines how the arguments will be
* parsed.
* \param message - The message to be used in the usage
* output.
* \param delimiter - The character that is used to separate
* the argument flag/name from the value. Defaults to ' ' (space).
* \param version - The version number to be used in the
* --version switch.
* \param helpAndVersion - Whether or not to create the Help and
* Version switches. Defaults to true.
*/
CmdLine(const std::string& message,
const char delimiter = ' ',
const std::string& version = "none",
bool helpAndVersion = true);
/**
* Deletes any resources allocated by a CmdLine object.
*/
virtual ~CmdLine();
/**
* Deletes any resources allocated by a CmdLine object.
*/
virtual ~CmdLine();
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
void add( Arg& a );
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
void add( Arg& a );
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
void add( Arg* a );
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
void add( Arg* a );
/**
* Add two Args that will be xor'd. If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
void xorAdd( Arg& a, Arg& b );
/**
* Add two Args that will be xor'd. If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
void xorAdd( Arg& a, Arg& b );
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
void xorAdd( std::vector<Arg*>& xors );
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
void xorAdd( std::vector<Arg*>& xors );
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
void parse(int argc, const char * const * argv);
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
void parse(int argc, const char * const * argv);
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
*
*/
CmdLineOutput* getOutput();
/**
*
*/
CmdLineOutput* getOutput();
/**
*
*/
void setOutput(CmdLineOutput* co);
/**
*
*/
void setOutput(CmdLineOutput* co);
/**
*
*/
std::string& getVersion();
/**
*
*/
std::string& getVersion();
/**
*
*/
std::string& getProgramName();
/**
*
*/
std::string& getProgramName();
/**
*
*/
std::list<Arg*>& getArgList();
/**
*
*/
std::list<Arg*>& getArgList();
/**
*
*/
XorHandler& getXorHandler();
/**
*
*/
XorHandler& getXorHandler();
/**
*
*/
char getDelimiter();
/**
*
*/
char getDelimiter();
/**
*
*/
std::string& getMessage();
/**
*
*/
std::string& getMessage();
/**
*
*/
bool hasHelpAndVersion();
/**
*
*/
bool hasHelpAndVersion();
/**
* Disables or enables CmdLine's internal parsing exception handling.
*
* @param state Should CmdLine handle parsing exceptions internally?
*/
void setExceptionHandling(const bool state);
/**
* Disables or enables CmdLine's internal parsing exception handling.
*
* @param state Should CmdLine handle parsing exceptions internally?
*/
void setExceptionHandling(const bool state);
/**
* Returns the current state of the internal exception handling.
*
* @retval true Parsing exceptions are handled internally.
* @retval false Parsing exceptions are propagated to the caller.
*/
bool getExceptionHandling() const;
/**
* Returns the current state of the internal exception handling.
*
* @retval true Parsing exceptions are handled internally.
* @retval false Parsing exceptions are propagated to the caller.
*/
bool getExceptionHandling() const;
/**
* Allows the CmdLine object to be reused.
*/
void reset();
/**
* Allows the CmdLine object to be reused.
*/
void reset();
};
@@ -324,7 +325,7 @@ inline CmdLine::CmdLine(const std::string& m,
char delim,
const std::string& v,
bool help )
:
:
_argList(std::list<Arg*>()),
_progName("not_set_yet"),
_message(m),
@@ -339,288 +340,272 @@ inline CmdLine::CmdLine(const std::string& m,
_userSetOutput(false),
_helpAndVersion(help)
{
_constructor();
_constructor();
}
inline CmdLine::~CmdLine()
{
ClearContainer(_argDeleteOnExitList);
ClearContainer(_visitorDeleteOnExitList);
if ( !_userSetOutput ) {
delete _output;
_output = 0;
}
ClearContainer(_argDeleteOnExitList);
ClearContainer(_visitorDeleteOnExitList);
if ( !_userSetOutput )
{
delete _output;
_output = 0;
}
}
inline void CmdLine::_constructor()
{
_output = new StdOutput;
Arg::setDelimiter( _delimiter );
Visitor* v;
if ( _helpAndVersion )
{
v = new HelpVisitor( this, &_output );
SwitchArg* help = new SwitchArg("h","help",
"Displays usage information and exits.",
false, v);
add( help );
deleteOnExit(help);
deleteOnExit(v);
v = new VersionVisitor( this, &_output );
SwitchArg* vers = new SwitchArg("","version",
"Displays version information and exits.",
false, v);
add( vers );
deleteOnExit(vers);
deleteOnExit(v);
}
v = new IgnoreRestVisitor();
SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
Arg::ignoreNameString(),
"Ignores the rest of the labeled arguments following this flag.",
false, v);
add( ignore );
deleteOnExit(ignore);
deleteOnExit(v);
_output = new StdOutput;
Arg::setDelimiter( _delimiter );
Visitor* v;
if ( _helpAndVersion )
{
v = new HelpVisitor( this, &_output );
SwitchArg* help = new SwitchArg("h","help",
"Displays usage information and exits.",
false, v);
add( help );
deleteOnExit(help);
deleteOnExit(v);
v = new VersionVisitor( this, &_output );
SwitchArg* vers = new SwitchArg("","version",
"Displays version information and exits.",
false, v);
add( vers );
deleteOnExit(vers);
deleteOnExit(v);
}
v = new IgnoreRestVisitor();
SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
Arg::ignoreNameString(),
"Ignores the rest of the labeled arguments following this flag.",
false, v);
add( ignore );
deleteOnExit(ignore);
deleteOnExit(v);
}
inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
{
_xorHandler.add( ors );
for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
{
(*it)->forceRequired();
(*it)->setRequireLabel( "OR required" );
add( *it );
}
_xorHandler.add( ors );
for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
{
(*it)->forceRequired();
(*it)->setRequireLabel( "OR required" );
add( *it );
}
}
inline void CmdLine::xorAdd( Arg& a, Arg& b )
{
std::vector<Arg*> ors;
ors.push_back( &a );
ors.push_back( &b );
xorAdd( ors );
std::vector<Arg*> ors;
ors.push_back( &a );
ors.push_back( &b );
xorAdd( ors );
}
inline void CmdLine::add( Arg& a )
{
add( &a );
add( &a );
}
inline void CmdLine::add( Arg* a )
{
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
if ( *a == *(*it) )
throw( SpecificationException(
"Argument with same flag/name already exists!",
a->longID() ) );
a->addToList( _argList );
if ( a->isRequired() )
_numRequired++;
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
if ( *a == *(*it) )
throw( SpecificationException(
"Argument with same flag/name already exists!",
a->longID() ) );
a->addToList( _argList );
if ( a->isRequired() )
_numRequired++;
}
inline void CmdLine::parse(int argc, const char * const * argv)
{
// this step is necessary so that we have easy access to
// mutable strings.
std::vector<std::string> args;
for (int i = 0; i < argc; i++)
args.push_back(argv[i]);
parse(args);
// this step is necessary so that we have easy access to
// mutable strings.
std::vector<std::string> args;
for (int i = 0; i < argc; i++)
args.push_back(argv[i]);
parse(args);
}
inline void CmdLine::parse(std::vector<std::string>& args)
{
bool shouldExit = false;
int estat = 0;
try {
_progName = args.front();
args.erase(args.begin());
int requiredCount = 0;
for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
{
bool matched = false;
for (ArgListIterator it = _argList.begin();
it != _argList.end(); it++) {
if ( (*it)->processArg( &i, args ) )
{
requiredCount += _xorHandler.check( *it );
matched = true;
break;
}
}
// checks to see if the argument is an empty combined
// switch and if so, then we've actually matched it
if ( !matched && _emptyCombined( args[i] ) )
matched = true;
if ( !matched && !Arg::ignoreRest() )
throw(CmdLineParseException("Couldn't find match "
"for argument",
args[i]));
}
if ( requiredCount < _numRequired )
missingArgsException();
if ( requiredCount > _numRequired )
throw(CmdLineParseException("Too many arguments!"));
} catch ( ArgException& e ) {
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions) {
throw;
}
try {
_output->failure(*this,e);
} catch ( ExitException &ee ) {
estat = ee.getExitStatus();
shouldExit = true;
}
} catch (ExitException &ee) {
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions) {
throw;
}
estat = ee.getExitStatus();
shouldExit = true;
}
if (shouldExit)
exit(estat);
bool shouldExit = false;
int estat = 0;
try
{
_progName = args.front();
args.erase(args.begin());
int requiredCount = 0;
for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
{
bool matched = false;
for (ArgListIterator it = _argList.begin();
it != _argList.end(); it++)
{
if ( (*it)->processArg( &i, args ) )
{
requiredCount += _xorHandler.check( *it );
matched = true;
break;
}
}
// checks to see if the argument is an empty combined
// switch and if so, then we've actually matched it
if ( !matched && _emptyCombined( args[i] ) )
matched = true;
if ( !matched && !Arg::ignoreRest() )
throw(CmdLineParseException("Couldn't find match "
"for argument",
args[i]));
}
if ( requiredCount < _numRequired )
missingArgsException();
if ( requiredCount > _numRequired )
throw(CmdLineParseException("Too many arguments!"));
}
catch ( ArgException& e )
{
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions)
{
throw;
}
try
{
_output->failure(*this,e);
}
catch ( ExitException &ee )
{
estat = ee.getExitStatus();
shouldExit = true;
}
}
catch (ExitException &ee)
{
// If we're not handling the exceptions, rethrow.
if ( !_handleExceptions)
{
throw;
}
estat = ee.getExitStatus();
shouldExit = true;
}
if (shouldExit)
exit(estat);
}
inline bool CmdLine::_emptyCombined(const std::string& s)
{
if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
return false;
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
if ( s[i] != Arg::blankChar() )
return false;
return true;
if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
return false;
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
if ( s[i] != Arg::blankChar() )
return false;
return true;
}
inline void CmdLine::missingArgsException()
{
int count = 0;
std::string missingArgList;
for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
{
if ( (*it)->isRequired() && !(*it)->isSet() )
{
missingArgList += (*it)->getName();
missingArgList += ", ";
count++;
}
}
missingArgList = missingArgList.substr(0,missingArgList.length()-2);
std::string msg;
if ( count > 1 )
msg = "Required arguments missing: ";
else
msg = "Required argument missing: ";
msg += missingArgList;
throw(CmdLineParseException(msg));
int count = 0;
std::string missingArgList;
for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
{
if ( (*it)->isRequired() && !(*it)->isSet() )
{
missingArgList += (*it)->getName();
missingArgList += ", ";
count++;
}
}
missingArgList = missingArgList.substr(0,missingArgList.length()-2);
std::string msg;
if ( count > 1 )
msg = "Required arguments missing: ";
else
msg = "Required argument missing: ";
msg += missingArgList;
throw(CmdLineParseException(msg));
}
inline void CmdLine::deleteOnExit(Arg* ptr)
{
_argDeleteOnExitList.push_back(ptr);
_argDeleteOnExitList.push_back(ptr);
}
inline void CmdLine::deleteOnExit(Visitor* ptr)
{
_visitorDeleteOnExitList.push_back(ptr);
_visitorDeleteOnExitList.push_back(ptr);
}
inline CmdLineOutput* CmdLine::getOutput()
{
return _output;
return _output;
}
inline void CmdLine::setOutput(CmdLineOutput* co)
{
if ( !_userSetOutput )
delete _output;
_userSetOutput = true;
_output = co;
if ( !_userSetOutput )
delete _output;
_userSetOutput = true;
_output = co;
}
inline std::string& CmdLine::getVersion()
{
return _version;
return _version;
}
inline std::string& CmdLine::getProgramName()
{
return _progName;
return _progName;
}
inline std::list<Arg*>& CmdLine::getArgList()
{
return _argList;
return _argList;
}
inline XorHandler& CmdLine::getXorHandler()
{
return _xorHandler;
return _xorHandler;
}
inline char CmdLine::getDelimiter()
{
return _delimiter;
return _delimiter;
}
inline std::string& CmdLine::getMessage()
{
return _message;
return _message;
}
inline bool CmdLine::hasHelpAndVersion()
{
return _helpAndVersion;
return _helpAndVersion;
}
inline void CmdLine::setExceptionHandling(const bool state)
{
_handleExceptions = state;
_handleExceptions = state;
}
inline bool CmdLine::getExceptionHandling() const
{
return _handleExceptions;
return _handleExceptions;
}
inline void CmdLine::reset()
{
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
(*it)->reset();
_progName.clear();
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
(*it)->reset();
_progName.clear();
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -30,7 +30,8 @@
#include <algorithm>
namespace TCLAP {
namespace TCLAP
{
class Arg;
class CmdLineOutput;
@@ -42,106 +43,106 @@ class XorHandler;
*/
class CmdLineInterface
{
public:
public:
/**
* Destructor
*/
virtual ~CmdLineInterface() {}
/**
* Destructor
*/
virtual ~CmdLineInterface() {}
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
virtual void add( Arg& a )=0;
/**
* Adds an argument to the list of arguments to be parsed.
* \param a - Argument to be added.
*/
virtual void add( Arg& a )=0;
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
virtual void add( Arg* a )=0;
/**
* An alternative add. Functionally identical.
* \param a - Argument to be added.
*/
virtual void add( Arg* a )=0;
/**
* Add two Args that will be xor'd.
* If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
virtual void xorAdd( Arg& a, Arg& b )=0;
/**
* Add two Args that will be xor'd.
* If this method is used, add does
* not need to be called.
* \param a - Argument to be added and xor'd.
* \param b - Argument to be added and xor'd.
*/
virtual void xorAdd( Arg& a, Arg& b )=0;
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
virtual void xorAdd( std::vector<Arg*>& xors )=0;
/**
* Add a list of Args that will be xor'd. If this method is used,
* add does not need to be called.
* \param xors - List of Args to be added and xor'd.
*/
virtual void xorAdd( std::vector<Arg*>& xors )=0;
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
virtual void parse(int argc, const char * const * argv)=0;
/**
* Parses the command line.
* \param argc - Number of arguments.
* \param argv - Array of arguments.
*/
virtual void parse(int argc, const char * const * argv)=0;
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
* Parses the command line.
* \param args - A vector of strings representing the args.
* args[0] is still the program name.
*/
void parse(std::vector<std::string>& args);
/**
* Returns the CmdLineOutput object.
*/
virtual CmdLineOutput* getOutput()=0;
/**
* Returns the CmdLineOutput object.
*/
virtual CmdLineOutput* getOutput()=0;
/**
* \param co - CmdLineOutput object that we want to use instead.
*/
virtual void setOutput(CmdLineOutput* co)=0;
/**
* \param co - CmdLineOutput object that we want to use instead.
*/
virtual void setOutput(CmdLineOutput* co)=0;
/**
* Returns the version string.
*/
virtual std::string& getVersion()=0;
/**
* Returns the version string.
*/
virtual std::string& getVersion()=0;
/**
* Returns the program name string.
*/
virtual std::string& getProgramName()=0;
/**
* Returns the program name string.
*/
virtual std::string& getProgramName()=0;
/**
* Returns the argList.
*/
virtual std::list<Arg*>& getArgList()=0;
/**
* Returns the argList.
*/
virtual std::list<Arg*>& getArgList()=0;
/**
* Returns the XorHandler.
*/
virtual XorHandler& getXorHandler()=0;
/**
* Returns the XorHandler.
*/
virtual XorHandler& getXorHandler()=0;
/**
* Returns the delimiter string.
*/
virtual char getDelimiter()=0;
/**
* Returns the delimiter string.
*/
virtual char getDelimiter()=0;
/**
* Returns the message string.
*/
virtual std::string& getMessage()=0;
/**
* Returns the message string.
*/
virtual std::string& getMessage()=0;
/**
* Indicates whether or not the help and version switches were created
* automatically.
*/
virtual bool hasHelpAndVersion()=0;
/**
* Indicates whether or not the help and version switches were created
* automatically.
*/
virtual bool hasHelpAndVersion()=0;
/**
* Resets the instance as if it had just been constructed so that the
* instance can be reused.
*/
virtual void reset()=0;
/**
* Resets the instance as if it had just been constructed so that the
* instance can be reused.
*/
virtual void reset()=0;
};
} //namespace

View File

@@ -30,7 +30,8 @@
#include <iomanip>
#include <algorithm>
namespace TCLAP {
namespace TCLAP
{
class CmdLineInterface;
class ArgException;
@@ -41,32 +42,32 @@ class ArgException;
class CmdLineOutput
{
public:
public:
/**
* Virtual destructor.
*/
virtual ~CmdLineOutput() {}
/**
* Virtual destructor.
*/
virtual ~CmdLineOutput() {}
/**
* Generates some sort of output for the USAGE.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c)=0;
/**
* Generates some sort of output for the USAGE.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c)=0;
/**
* Generates some sort of output for the version.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c)=0;
/**
* Generates some sort of output for the version.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c)=0;
/**
* Generates some sort of output for a failure.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure( CmdLineInterface& c,
ArgException& e )=0;
/**
* Generates some sort of output for a failure.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure( CmdLineInterface& c,
ArgException& e )=0;
};

View File

@@ -29,7 +29,8 @@
#include <iomanip>
#include <algorithm>
namespace TCLAP {
namespace TCLAP
{
/**
* The interface that defines the interaction between the Arg and Constraint.
@@ -38,30 +39,33 @@ template<class T>
class Constraint
{
public:
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const =0;
public:
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const =0;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const =0;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const =0;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const =0;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const =0;
/**
* Destructor.
* Silences warnings about Constraint being a base class with virtual
* functions but without a virtual destructor.
*/
virtual ~Constraint() { ; }
/**
* Destructor.
* Silences warnings about Constraint being a base class with virtual
* functions but without a virtual destructor.
*/
virtual ~Constraint()
{
;
}
};
} //namespace TCLAP

View File

@@ -34,7 +34,8 @@
#include <tclap/XorHandler.h>
#include <tclap/Arg.h>
namespace TCLAP {
namespace TCLAP
{
/**
* A class that generates DocBook output for usage() method for the
@@ -43,256 +44,226 @@ namespace TCLAP {
class DocBookOutput : public CmdLineOutput
{
public:
public:
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
protected:
protected:
/**
* Substitutes the char r for string x in string s.
* \param s - The string to operate on.
* \param r - The char to replace.
* \param x - What to replace r with.
*/
void substituteSpecialChars( std::string& s, char r, std::string& x );
void removeChar( std::string& s, char r);
void basename( std::string& s );
/**
* Substitutes the char r for string x in string s.
* \param s - The string to operate on.
* \param r - The char to replace.
* \param x - What to replace r with.
*/
void substituteSpecialChars( std::string& s, char r, std::string& x );
void removeChar( std::string& s, char r);
void basename( std::string& s );
void printShortArg(Arg* it);
void printLongArg(Arg* it);
void printShortArg(Arg* it);
void printLongArg(Arg* it);
char theDelimiter;
char theDelimiter;
};
inline void DocBookOutput::version(CmdLineInterface& _cmd)
{
std::cout << _cmd.getVersion() << std::endl;
std::cout << _cmd.getVersion() << std::endl;
}
inline void DocBookOutput::usage(CmdLineInterface& _cmd )
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
basename(progName);
std::cout << "<?xml version='1.0'?>" << std::endl;
std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl;
std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl << std::endl;
std::cout << "<refentry>" << std::endl;
std::cout << "<refmeta>" << std::endl;
std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl;
std::cout << "<manvolnum>1</manvolnum>" << std::endl;
std::cout << "</refmeta>" << std::endl;
std::cout << "<refnamediv>" << std::endl;
std::cout << "<refname>" << progName << "</refname>" << std::endl;
std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl;
std::cout << "</refnamediv>" << std::endl;
std::cout << "<refsynopsisdiv>" << std::endl;
std::cout << "<cmdsynopsis>" << std::endl;
std::cout << "<command>" << progName << "</command>" << std::endl;
// xor
for ( int i = 0; (unsigned int)i < xorList.size(); i++ )
{
std::cout << "<group choice='req'>" << std::endl;
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
printShortArg((*it));
std::cout << "</group>" << std::endl;
}
// rest of args
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
printShortArg((*it));
std::cout << "</cmdsynopsis>" << std::endl;
std::cout << "</refsynopsisdiv>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Description</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << _cmd.getMessage() << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Options</title>" << std::endl;
std::cout << "<variablelist>" << std::endl;
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
printLongArg((*it));
std::cout << "</variablelist>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Version</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << xversion << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "</refentry>" << std::endl;
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
basename(progName);
std::cout << "<?xml version='1.0'?>" << std::endl;
std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl;
std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl << std::endl;
std::cout << "<refentry>" << std::endl;
std::cout << "<refmeta>" << std::endl;
std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl;
std::cout << "<manvolnum>1</manvolnum>" << std::endl;
std::cout << "</refmeta>" << std::endl;
std::cout << "<refnamediv>" << std::endl;
std::cout << "<refname>" << progName << "</refname>" << std::endl;
std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl;
std::cout << "</refnamediv>" << std::endl;
std::cout << "<refsynopsisdiv>" << std::endl;
std::cout << "<cmdsynopsis>" << std::endl;
std::cout << "<command>" << progName << "</command>" << std::endl;
// xor
for ( int i = 0; (unsigned int)i < xorList.size(); i++ )
{
std::cout << "<group choice='req'>" << std::endl;
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
printShortArg((*it));
std::cout << "</group>" << std::endl;
}
// rest of args
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
printShortArg((*it));
std::cout << "</cmdsynopsis>" << std::endl;
std::cout << "</refsynopsisdiv>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Description</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << _cmd.getMessage() << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Options</title>" << std::endl;
std::cout << "<variablelist>" << std::endl;
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
printLongArg((*it));
std::cout << "</variablelist>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "<refsect1>" << std::endl;
std::cout << "<title>Version</title>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << xversion << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</refsect1>" << std::endl;
std::cout << "</refentry>" << std::endl;
}
inline void DocBookOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
ArgException& e )
{
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
throw ExitException(1);
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
throw ExitException(1);
}
inline void DocBookOutput::substituteSpecialChars( std::string& s,
char r,
std::string& x )
char r,
std::string& x )
{
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
s.insert(p,x);
}
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
s.insert(p,x);
}
}
inline void DocBookOutput::removeChar( std::string& s, char r)
{
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
}
size_t p;
while ( (p = s.find_first_of(r)) != std::string::npos )
{
s.erase(p,1);
}
}
inline void DocBookOutput::basename( std::string& s )
{
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
}
inline void DocBookOutput::printShortArg(Arg* a)
{
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string id = a->shortID();
substituteSpecialChars(id,'<',lt);
substituteSpecialChars(id,'>',gt);
removeChar(id,'[');
removeChar(id,']');
std::string choice = "opt";
if ( a->isRequired() )
choice = "plain";
std::cout << "<arg choice='" << choice << '\'';
if ( a->acceptsMultipleValues() )
std::cout << " rep='repeat'";
std::cout << '>';
if ( !a->getFlag().empty() )
std::cout << a->flagStartChar() << a->getFlag();
else
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</arg>" << std::endl;
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string id = a->shortID();
substituteSpecialChars(id,'<',lt);
substituteSpecialChars(id,'>',gt);
removeChar(id,'[');
removeChar(id,']');
std::string choice = "opt";
if ( a->isRequired() )
choice = "plain";
std::cout << "<arg choice='" << choice << '\'';
if ( a->acceptsMultipleValues() )
std::cout << " rep='repeat'";
std::cout << '>';
if ( !a->getFlag().empty() )
std::cout << a->flagStartChar() << a->getFlag();
else
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</arg>" << std::endl;
}
inline void DocBookOutput::printLongArg(Arg* a)
{
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string desc = a->getDescription();
substituteSpecialChars(desc,'<',lt);
substituteSpecialChars(desc,'>',gt);
std::cout << "<varlistentry>" << std::endl;
if ( !a->getFlag().empty() )
{
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->flagStartChar() << a->getFlag();
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
}
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
std::cout << "<listitem>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << desc << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</listitem>" << std::endl;
std::cout << "</varlistentry>" << std::endl;
std::string lt = "&lt;";
std::string gt = "&gt;";
std::string desc = a->getDescription();
substituteSpecialChars(desc,'<',lt);
substituteSpecialChars(desc,'>',gt);
std::cout << "<varlistentry>" << std::endl;
if ( !a->getFlag().empty() )
{
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->flagStartChar() << a->getFlag();
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
}
std::cout << "<term>" << std::endl;
std::cout << "<option>";
std::cout << a->nameStartString() << a->getName();
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
removeChar(arg,'[');
removeChar(arg,']');
removeChar(arg,'<');
removeChar(arg,'>');
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
std::cout << theDelimiter;
std::cout << "<replaceable>" << arg << "</replaceable>";
}
std::cout << "</option>" << std::endl;
std::cout << "</term>" << std::endl;
std::cout << "<listitem>" << std::endl;
std::cout << "<para>" << std::endl;
std::cout << desc << std::endl;
std::cout << "</para>" << std::endl;
std::cout << "</listitem>" << std::endl;
std::cout << "</varlistentry>" << std::endl;
}
} //namespace TCLAP

View File

@@ -26,7 +26,8 @@
#include "CmdLineOutput.h"
#include "Visitor.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A Visitor object that calls the usage method of the given CmdLineOutput
@@ -34,40 +35,44 @@ namespace TCLAP {
*/
class HelpVisitor: public Visitor
{
private:
/**
* Prevent accidental copying.
*/
HelpVisitor(const HelpVisitor& rhs);
HelpVisitor& operator=(const HelpVisitor& rhs);
private:
/**
* Prevent accidental copying.
*/
HelpVisitor(const HelpVisitor& rhs);
HelpVisitor& operator=(const HelpVisitor& rhs);
protected:
protected:
/**
* The CmdLine the output will be generated for.
*/
CmdLineInterface* _cmd;
/**
* The CmdLine the output will be generated for.
*/
CmdLineInterface* _cmd;
/**
* The output object.
*/
CmdLineOutput** _out;
/**
* The output object.
*/
CmdLineOutput** _out;
public:
public:
/**
* Constructor.
* \param cmd - The CmdLine the output will be generated for.
* \param out - The type of output.
*/
HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out)
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Constructor.
* \param cmd - The CmdLine the output will be generated for.
* \param out - The type of output.
*/
HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out)
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Calls the usage method of the CmdLineOutput for the
* specified CmdLine.
*/
void visit() { (*_out)->usage(*_cmd); throw ExitException(0); }
/**
* Calls the usage method of the CmdLineOutput for the
* specified CmdLine.
*/
void visit()
{
(*_out)->usage(*_cmd);
throw ExitException(0);
}
};

View File

@@ -26,7 +26,8 @@
#include "Visitor.h"
#include "Arg.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A Vistor that tells the CmdLine to begin ignoring arguments after
@@ -34,17 +35,20 @@ namespace TCLAP {
*/
class IgnoreRestVisitor: public Visitor
{
public:
public:
/**
* Constructor.
*/
IgnoreRestVisitor() : Visitor() {}
/**
* Constructor.
*/
IgnoreRestVisitor() : Visitor() {}
/**
* Sets Arg::_ignoreRest.
*/
void visit() { Arg::beginIgnoring(); }
/**
* Sets Arg::_ignoreRest.
*/
void visit()
{
Arg::beginIgnoring();
}
};
}

View File

@@ -29,7 +29,8 @@
#include "Arg.h"
#include "Constraint.h"
namespace TCLAP {
namespace TCLAP
{
/**
* An argument that allows multiple values of type T to be specified. Very
* similar to a ValueArg, except a vector of values will be returned
@@ -38,195 +39,201 @@ namespace TCLAP {
template<class T>
class MultiArg : public Arg
{
public:
typedef std::vector<T> container_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
public:
typedef std::vector<T> container_type;
typedef typename container_type::iterator iterator;
typedef typename container_type::const_iterator const_iterator;
protected:
protected:
/**
* The list of values parsed from the CmdLine.
*/
std::vector<T> _values;
/**
* The list of values parsed from the CmdLine.
*/
std::vector<T> _values;
/**
* The description of type T to be used in the usage.
*/
std::string _typeDesc;
/**
* The description of type T to be used in the usage.
*/
std::string _typeDesc;
/**
* A list of constraint on this Arg.
*/
Constraint<T>* _constraint;
/**
* A list of constraint on this Arg.
*/
Constraint<T>* _constraint;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - The string to be read.
*/
void _extractValue( const std::string& val );
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - The string to be read.
*/
void _extractValue( const std::string& val );
/**
* Used by XorHandler to decide whether to keep parsing for this arg.
*/
bool _allowMore;
/**
* Used by XorHandler to decide whether to keep parsing for this arg.
*/
bool _allowMore;
public:
public:
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns a vector of type T containing the values parsed from
* the command line.
*/
const std::vector<T>& getValue();
/**
* Returns a vector of type T containing the values parsed from
* the command line.
*/
const std::vector<T>& getValue();
/**
* Returns an iterator over the values parsed from the command
* line.
*/
const_iterator begin() const { return _values.begin(); }
/**
* Returns an iterator over the values parsed from the command
* line.
*/
const_iterator begin() const
{
return _values.begin();
}
/**
* Returns the end of the values parsed from the command
* line.
*/
const_iterator end() const { return _values.end(); }
/**
* Returns the end of the values parsed from the command
* line.
*/
const_iterator end() const
{
return _values.end();
}
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
virtual bool isRequired() const;
/**
* Once we've matched the first value, then the arg is no longer
* required.
*/
virtual bool isRequired() const;
virtual bool allowMore();
virtual bool allowMore();
virtual void reset();
virtual void reset();
private:
/**
* Prevent accidental copying
*/
MultiArg<T>(const MultiArg<T>& rhs);
MultiArg<T>& operator=(const MultiArg<T>& rhs);
private:
/**
* Prevent accidental copying
*/
MultiArg<T>(const MultiArg<T>& rhs);
MultiArg<T>& operator=(const MultiArg<T>& rhs);
};
@@ -237,13 +244,13 @@ MultiArg<T>::MultiArg(const std::string& flag,
bool req,
const std::string& typeDesc,
Visitor* v) :
Arg( flag, name, desc, req, true, v ),
Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( typeDesc ),
_constraint( NULL ),
_allowMore(false)
{
_acceptsMultipleValues = true;
_acceptsMultipleValues = true;
}
template<class T>
@@ -254,14 +261,14 @@ MultiArg<T>::MultiArg(const std::string& flag,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( typeDesc ),
_constraint( NULL ),
_allowMore(false)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( typeDesc ),
_constraint( NULL ),
_allowMore(false)
{
parser.add( this );
_acceptsMultipleValues = true;
parser.add( this );
_acceptsMultipleValues = true;
}
/**
@@ -274,13 +281,13 @@ MultiArg<T>::MultiArg(const std::string& flag,
bool req,
Constraint<T>* constraint,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( constraint->shortID() ),
_constraint( constraint ),
_allowMore(false)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( constraint->shortID() ),
_constraint( constraint ),
_allowMore(false)
{
_acceptsMultipleValues = true;
_acceptsMultipleValues = true;
}
template<class T>
@@ -291,68 +298,63 @@ MultiArg<T>::MultiArg(const std::string& flag,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( constraint->shortID() ),
_constraint( constraint ),
_allowMore(false)
: Arg( flag, name, desc, req, true, v ),
_values(std::vector<T>()),
_typeDesc( constraint->shortID() ),
_constraint( constraint ),
_allowMore(false)
{
parser.add( this );
_acceptsMultipleValues = true;
parser.add( this );
_acceptsMultipleValues = true;
}
template<class T>
const std::vector<T>& MultiArg<T>::getValue() { return _values; }
const std::vector<T>& MultiArg<T>::getValue()
{
return _values;
}
template<class T>
bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
{
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException(
"Couldn't find delimiter for this argument!",
toString() ) );
// always take the first one, regardless of start string
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
_extractValue( value );
/*
// continuing taking the args until we hit one with a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
_checkWithVisitor();
return true;
}
else
return false;
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
{
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException(
"Couldn't find delimiter for this argument!",
toString() ) );
// always take the first one, regardless of start string
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
_extractValue( value );
/*
// continuing taking the args until we hit one with a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
_checkWithVisitor();
return true;
}
else
return false;
}
/**
@@ -361,8 +363,8 @@ bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args)
template<class T>
std::string MultiArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID(_typeDesc) + " ... ";
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID(_typeDesc) + " ... ";
}
/**
@@ -371,8 +373,8 @@ std::string MultiArg<T>::shortID(const std::string& val) const
template<class T>
std::string MultiArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID(_typeDesc) + " (accepted multiple times)";
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID(_typeDesc) + " (accepted multiple times)";
}
/**
@@ -382,50 +384,51 @@ std::string MultiArg<T>::longID(const std::string& val) const
template<class T>
bool MultiArg<T>::isRequired() const
{
if ( _required )
{
if ( _values.size() > 1 )
return false;
else
return true;
}
else
return false;
if ( _required )
{
if ( _values.size() > 1 )
return false;
else
return true;
}
else
return false;
}
template<class T>
void MultiArg<T>::_extractValue( const std::string& val )
{
try {
T tmp;
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
_values.push_back(tmp);
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _values.back() ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
try
{
T tmp;
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
_values.push_back(tmp);
}
catch( ArgParseException &e)
{
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _values.back() ) )
throw( CmdLineParseException( "Value '" + val +
"' does not meet constraint: " +
_constraint->description(),
toString() ) );
}
template<class T>
bool MultiArg<T>::allowMore()
{
bool am = _allowMore;
_allowMore = true;
return am;
bool am = _allowMore;
_allowMore = true;
return am;
}
template<class T>
void MultiArg<T>::reset()
{
Arg::reset();
_values.clear();
Arg::reset();
_values.clear();
}
} // namespace TCLAP

View File

@@ -30,7 +30,8 @@
#include "SwitchArg.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A multiple switch argument. If the switch is set on the command line, then
@@ -38,89 +39,89 @@ namespace TCLAP {
*/
class MultiSwitchArg : public SwitchArg
{
protected:
protected:
/**
* The value of the switch.
*/
int _value;
/**
* The value of the switch.
*/
int _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
int _default;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
int _default;
public:
public:
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
int init = 0,
Visitor* v = NULL);
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
int init = 0,
Visitor* v = NULL);
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init = 0,
Visitor* v = NULL);
/**
* MultiSwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param init - Optional. The initial/default value of this Arg.
* Defaults to 0.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init = 0,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the SwitchArg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the SwitchArg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns int, the number of times the switch has been set.
*/
int getValue();
/**
* Returns int, the number of times the switch has been set.
*/
int getValue();
/**
* Returns the shortID for this Arg.
*/
std::string shortID(const std::string& val) const;
/**
* Returns the shortID for this Arg.
*/
std::string shortID(const std::string& val) const;
/**
* Returns the longID for this Arg.
*/
std::string longID(const std::string& val) const;
/**
* Returns the longID for this Arg.
*/
std::string longID(const std::string& val) const;
void reset();
void reset();
};
@@ -128,83 +129,78 @@ class MultiSwitchArg : public SwitchArg
//BEGIN MultiSwitchArg.cpp
//////////////////////////////////////////////////////////////////////
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
const std::string& name,
const std::string& desc,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
{ }
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
int init,
Visitor* v )
: SwitchArg(flag, name, desc, false, v),
_value( init ),
_default( init )
{
parser.add( this );
parser.add( this );
}
inline int MultiSwitchArg::getValue() { return _value; }
inline int MultiSwitchArg::getValue()
{
return _value;
}
inline bool MultiSwitchArg::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( argMatches( args[*i] ))
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
_checkWithVisitor();
return true;
}
else if ( combinedSwitchesMatch( args[*i] ) )
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
// Check for more in argument and increment value.
while ( combinedSwitchesMatch( args[*i] ) )
++_value;
_checkWithVisitor();
return false;
}
else
return false;
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( argMatches( args[*i] ))
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
_checkWithVisitor();
return true;
}
else if ( combinedSwitchesMatch( args[*i] ) )
{
// so the isSet() method will work
_alreadySet = true;
// Matched argument: increment value.
++_value;
// Check for more in argument and increment value.
while ( combinedSwitchesMatch( args[*i] ) )
++_value;
_checkWithVisitor();
return false;
}
else
return false;
}
inline std::string
MultiSwitchArg::shortID(const std::string& val) const
{
return Arg::shortID(val) + " ... ";
return Arg::shortID(val) + " ... ";
}
inline std::string
MultiSwitchArg::longID(const std::string& val) const
{
return Arg::longID(val) + " (accepted multiple times)";
return Arg::longID(val) + " (accepted multiple times)";
}
inline void
MultiSwitchArg::reset()
{
MultiSwitchArg::_value = MultiSwitchArg::_default;
MultiSwitchArg::_value = MultiSwitchArg::_default;
}
//////////////////////////////////////////////////////////////////////

View File

@@ -26,34 +26,44 @@
#include <string>
namespace TCLAP {
namespace TCLAP
{
class OptionalUnlabeledTracker
{
public:
public:
static void check( bool req, const std::string& argName );
static void check( bool req, const std::string& argName );
static void gotOptional() { alreadyOptionalRef() = true; }
static void gotOptional()
{
alreadyOptionalRef() = true;
}
static bool& alreadyOptional() { return alreadyOptionalRef(); }
static bool& alreadyOptional()
{
return alreadyOptionalRef();
}
private:
private:
static bool& alreadyOptionalRef() { static bool ct = false; return ct; }
static bool& alreadyOptionalRef()
{
static bool ct = false;
return ct;
}
};
inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName )
{
if ( OptionalUnlabeledTracker::alreadyOptional() )
throw( SpecificationException(
"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg",
argName ) );
if ( !req )
OptionalUnlabeledTracker::gotOptional();
if ( OptionalUnlabeledTracker::alreadyOptional() )
throw( SpecificationException(
"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg",
argName ) );
if ( !req )
OptionalUnlabeledTracker::gotOptional();
}

View File

@@ -39,7 +39,8 @@
#endif
#endif
namespace TCLAP {
namespace TCLAP
{
// ======================================================================
// Integer types
@@ -49,32 +50,36 @@ namespace TCLAP {
* longs have value-like semantics.
*/
template<>
struct ArgTraits<long> {
typedef ValueLike ValueCategory;
struct ArgTraits<long>
{
typedef ValueLike ValueCategory;
};
/**
* ints have value-like semantics.
*/
template<>
struct ArgTraits<int> {
typedef ValueLike ValueCategory;
struct ArgTraits<int>
{
typedef ValueLike ValueCategory;
};
/**
* shorts have value-like semantics.
*/
template<>
struct ArgTraits<short> {
typedef ValueLike ValueCategory;
struct ArgTraits<short>
{
typedef ValueLike ValueCategory;
};
/**
* chars have value-like semantics.
*/
template<>
struct ArgTraits<char> {
typedef ValueLike ValueCategory;
struct ArgTraits<char>
{
typedef ValueLike ValueCategory;
};
#ifdef HAVE_LONG_LONG
@@ -82,8 +87,9 @@ struct ArgTraits<char> {
* long longs have value-like semantics.
*/
template<>
struct ArgTraits<long long> {
typedef ValueLike ValueCategory;
struct ArgTraits<long long>
{
typedef ValueLike ValueCategory;
};
#endif
@@ -95,32 +101,36 @@ struct ArgTraits<long long> {
* unsigned longs have value-like semantics.
*/
template<>
struct ArgTraits<unsigned long> {
typedef ValueLike ValueCategory;
struct ArgTraits<unsigned long>
{
typedef ValueLike ValueCategory;
};
/**
* unsigned ints have value-like semantics.
*/
template<>
struct ArgTraits<unsigned int> {
typedef ValueLike ValueCategory;
struct ArgTraits<unsigned int>
{
typedef ValueLike ValueCategory;
};
/**
* unsigned shorts have value-like semantics.
*/
template<>
struct ArgTraits<unsigned short> {
typedef ValueLike ValueCategory;
struct ArgTraits<unsigned short>
{
typedef ValueLike ValueCategory;
};
/**
* unsigned chars have value-like semantics.
*/
template<>
struct ArgTraits<unsigned char> {
typedef ValueLike ValueCategory;
struct ArgTraits<unsigned char>
{
typedef ValueLike ValueCategory;
};
// Microsoft implements size_t awkwardly.
@@ -129,8 +139,9 @@ struct ArgTraits<unsigned char> {
* size_ts have value-like semantics.
*/
template<>
struct ArgTraits<size_t> {
typedef ValueLike ValueCategory;
struct ArgTraits<size_t>
{
typedef ValueLike ValueCategory;
};
#endif
@@ -140,8 +151,9 @@ struct ArgTraits<size_t> {
* unsigned long longs have value-like semantics.
*/
template<>
struct ArgTraits<unsigned long long> {
typedef ValueLike ValueCategory;
struct ArgTraits<unsigned long long>
{
typedef ValueLike ValueCategory;
};
#endif
@@ -153,16 +165,18 @@ struct ArgTraits<unsigned long long> {
* floats have value-like semantics.
*/
template<>
struct ArgTraits<float> {
typedef ValueLike ValueCategory;
struct ArgTraits<float>
{
typedef ValueLike ValueCategory;
};
/**
* doubles have value-like semantics.
*/
template<>
struct ArgTraits<double> {
typedef ValueLike ValueCategory;
struct ArgTraits<double>
{
typedef ValueLike ValueCategory;
};
// ======================================================================
@@ -173,8 +187,9 @@ struct ArgTraits<double> {
* bools have value-like semantics.
*/
template<>
struct ArgTraits<bool> {
typedef ValueLike ValueCategory;
struct ArgTraits<bool>
{
typedef ValueLike ValueCategory;
};
@@ -183,8 +198,9 @@ struct ArgTraits<bool> {
*/
#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
template<>
struct ArgTraits<wchar_t> {
typedef ValueLike ValueCategory;
struct ArgTraits<wchar_t>
{
typedef ValueLike ValueCategory;
};
#endif
@@ -192,14 +208,15 @@ struct ArgTraits<wchar_t> {
* Strings have string like argument traits.
*/
template<>
struct ArgTraits<std::string> {
typedef StringLike ValueCategory;
struct ArgTraits<std::string>
{
typedef StringLike ValueCategory;
};
template<typename T>
void SetString(T &dst, const std::string &src)
{
dst = src;
dst = src;
}
} // namespace

View File

@@ -34,7 +34,8 @@
#include "XorHandler.h"
#include "Arg.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A class that isolates any output from the CmdLine object so that it
@@ -43,255 +44,223 @@ namespace TCLAP {
class StdOutput : public CmdLineOutput
{
public:
public:
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
protected:
protected:
/**
* Writes a brief usage message with short args.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* Writes a brief usage message with short args.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* Writes a longer usage message with long and short args,
* provides descriptions and prints message.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* Writes a longer usage message with long and short args,
* provides descriptions and prints message.
* \param c - The CmdLine object the output is generated for.
* \param os - The stream to write the message to.
*/
void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
/**
* This function inserts line breaks and indents long strings
* according the params input. It will only break lines at spaces,
* commas and pipes.
* \param os - The stream to be printed to.
* \param s - The string to be printed.
* \param maxWidth - The maxWidth allowed for the output line.
* \param indentSpaces - The number of spaces to indent the first line.
* \param secondLineOffset - The number of spaces to indent the second
* and all subsequent lines in addition to indentSpaces.
*/
void spacePrint( std::ostream& os,
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const;
/**
* This function inserts line breaks and indents long strings
* according the params input. It will only break lines at spaces,
* commas and pipes.
* \param os - The stream to be printed to.
* \param s - The string to be printed.
* \param maxWidth - The maxWidth allowed for the output line.
* \param indentSpaces - The number of spaces to indent the first line.
* \param secondLineOffset - The number of spaces to indent the second
* and all subsequent lines in addition to indentSpaces.
*/
void spacePrint( std::ostream& os,
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const;
};
inline void StdOutput::version(CmdLineInterface& _cmd)
{
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
std::cout << std::endl << progName << " version: "
<< xversion << std::endl << std::endl;
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
std::cout << std::endl << progName << " version: "
<< xversion << std::endl << std::endl;
}
inline void StdOutput::usage(CmdLineInterface& _cmd )
{
std::cout << std::endl << "USAGE: " << std::endl << std::endl;
_shortUsage( _cmd, std::cout );
std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
_longUsage( _cmd, std::cout );
std::cout << std::endl;
std::cout << std::endl << "USAGE: " << std::endl << std::endl;
_shortUsage( _cmd, std::cout );
std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
_longUsage( _cmd, std::cout );
std::cout << std::endl;
}
inline void StdOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
ArgException& e )
{
std::string progName = _cmd.getProgramName();
std::cerr << "PARSE ERROR: " << e.argId() << std::endl
<< " " << e.error() << std::endl << std::endl;
if ( _cmd.hasHelpAndVersion() )
{
std::cerr << "Brief USAGE: " << std::endl;
_shortUsage( _cmd, std::cerr );
std::cerr << std::endl << "For complete USAGE and HELP type: "
<< std::endl << " " << progName << " --help"
<< std::endl << std::endl;
}
else
usage(_cmd);
throw ExitException(1);
std::string progName = _cmd.getProgramName();
std::cerr << "PARSE ERROR: " << e.argId() << std::endl
<< " " << e.error() << std::endl << std::endl;
if ( _cmd.hasHelpAndVersion() )
{
std::cerr << "Brief USAGE: " << std::endl;
_shortUsage( _cmd, std::cerr );
std::cerr << std::endl << "For complete USAGE and HELP type: "
<< std::endl << " " << progName << " --help"
<< std::endl << std::endl;
}
else
usage(_cmd);
throw ExitException(1);
}
inline void
StdOutput::_shortUsage( CmdLineInterface& _cmd,
std::ostream& os ) const
std::ostream& os ) const
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
std::string s = progName + " ";
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
s += " {";
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
s += (*it)->shortID() + "|";
s[s.length()-1] = '}';
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
s += " " + (*it)->shortID();
// if the program name is too long, then adjust the second line offset
int secondLineOffset = static_cast<int>(progName.length()) + 2;
if ( secondLineOffset > 75/2 )
secondLineOffset = static_cast<int>(75/2);
spacePrint( os, s, 75, 3, secondLineOffset );
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
std::string s = progName + " ";
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
s += " {";
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end(); it++ )
s += (*it)->shortID() + "|";
s[s.length()-1] = '}';
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
s += " " + (*it)->shortID();
// if the program name is too long, then adjust the second line offset
int secondLineOffset = static_cast<int>(progName.length()) + 2;
if ( secondLineOffset > 75/2 )
secondLineOffset = static_cast<int>(75/2);
spacePrint( os, s, 75, 3, secondLineOffset );
}
inline void
StdOutput::_longUsage( CmdLineInterface& _cmd,
std::ostream& os ) const
std::ostream& os ) const
{
std::list<Arg*> argList = _cmd.getArgList();
std::string message = _cmd.getMessage();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++ )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
if ( it+1 != xorList[i].end() )
spacePrint(os, "-- OR --", 75, 9, 0);
}
os << std::endl << std::endl;
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
os << std::endl;
}
os << std::endl;
spacePrint( os, message, 75, 3, 0 );
std::list<Arg*> argList = _cmd.getArgList();
std::string message = _cmd.getMessage();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
// first the xor
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++ )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
if ( it+1 != xorList[i].end() )
spacePrint(os, "-- OR --", 75, 9, 0);
}
os << std::endl << std::endl;
}
// then the rest
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
if ( !xorHandler.contains( (*it) ) )
{
spacePrint( os, (*it)->longID(), 75, 3, 3 );
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
os << std::endl;
}
os << std::endl;
spacePrint( os, message, 75, 3, 0 );
}
inline void StdOutput::spacePrint( std::ostream& os,
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const
const std::string& s,
int maxWidth,
int indentSpaces,
int secondLineOffset ) const
{
int len = static_cast<int>(s.length());
if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
{
int allowedLen = maxWidth - indentSpaces;
int start = 0;
while ( start < len )
{
// find the substring length
// int stringLen = std::min<int>( len - start, allowedLen );
// doing it this way to support a VisualC++ 2005 bug
using namespace std;
int stringLen = min<int>( len - start, allowedLen );
// trim the length so it doesn't end in middle of a word
if ( stringLen == allowedLen )
while ( stringLen >= 0 &&
s[stringLen+start] != ' ' &&
s[stringLen+start] != ',' &&
s[stringLen+start] != '|' )
stringLen--;
// ok, the word is longer than the line, so just split
// wherever the line ends
if ( stringLen <= 0 )
stringLen = allowedLen;
// check for newlines
for ( int i = 0; i < stringLen; i++ )
if ( s[start+i] == '\n' )
stringLen = i+1;
// print the indent
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
if ( start == 0 )
{
// handle second line offsets
indentSpaces += secondLineOffset;
// adjust allowed len
allowedLen -= secondLineOffset;
}
os << s.substr(start,stringLen) << std::endl;
// so we don't start a line with a space
while ( s[stringLen+start] == ' ' && start < len )
start++;
start += stringLen;
}
}
else
{
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
os << s << std::endl;
}
int len = static_cast<int>(s.length());
if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
{
int allowedLen = maxWidth - indentSpaces;
int start = 0;
while ( start < len )
{
// find the substring length
// int stringLen = std::min<int>( len - start, allowedLen );
// doing it this way to support a VisualC++ 2005 bug
using namespace std;
int stringLen = min<int>( len - start, allowedLen );
// trim the length so it doesn't end in middle of a word
if ( stringLen == allowedLen )
while ( stringLen >= 0 &&
s[stringLen+start] != ' ' &&
s[stringLen+start] != ',' &&
s[stringLen+start] != '|' )
stringLen--;
// ok, the word is longer than the line, so just split
// wherever the line ends
if ( stringLen <= 0 )
stringLen = allowedLen;
// check for newlines
for ( int i = 0; i < stringLen; i++ )
if ( s[start+i] == '\n' )
stringLen = i+1;
// print the indent
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
if ( start == 0 )
{
// handle second line offsets
indentSpaces += secondLineOffset;
// adjust allowed len
allowedLen -= secondLineOffset;
}
os << s.substr(start,stringLen) << std::endl;
// so we don't start a line with a space
while ( s[stringLen+start] == ' ' && start < len )
start++;
start += stringLen;
}
}
else
{
for ( int i = 0; i < indentSpaces; i++ )
os << " ";
os << s << std::endl;
}
}
} //namespace TCLAP

View File

@@ -29,7 +29,8 @@
#include "Arg.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A simple switch argument. If the switch is set on the command line, then
@@ -38,95 +39,95 @@ namespace TCLAP {
*/
class SwitchArg : public Arg
{
protected:
protected:
/**
* The value of the switch.
*/
bool _value;
/**
* The value of the switch.
*/
bool _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
bool _default;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
bool _default;
public:
public:
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool def = false,
Visitor* v = NULL);
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
bool def = false,
Visitor* v = NULL);
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
bool def = false,
Visitor* v = NULL);
/**
* SwitchArg constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param parser - A CmdLine parser object to add this Arg to
* \param def - The default value for this Switch.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
SwitchArg(const std::string& flag,
const std::string& name,
const std::string& desc,
CmdLineInterface& parser,
bool def = false,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Checks a string to see if any of the chars in the string
* match the flag for this Switch.
*/
bool combinedSwitchesMatch(std::string& combined);
/**
* Checks a string to see if any of the chars in the string
* match the flag for this Switch.
*/
bool combinedSwitchesMatch(std::string& combined);
/**
* Returns bool, whether or not the switch has been set.
*/
bool getValue();
/**
* Returns bool, whether or not the switch has been set.
*/
bool getValue();
virtual void reset();
virtual void reset();
private:
/**
* Checks to see if we've found the last match in
* a combined string.
*/
bool lastCombined(std::string& combined);
private:
/**
* Checks to see if we've found the last match in
* a combined string.
*/
bool lastCombined(std::string& combined);
/**
* Does the common processing of processArg.
*/
void commonProcessing();
/**
* Does the common processing of processArg.
*/
void commonProcessing();
};
//////////////////////////////////////////////////////////////////////
@@ -137,9 +138,9 @@ inline SwitchArg::SwitchArg(const std::string& flag,
const std::string& desc,
bool default_val,
Visitor* v )
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default( default_val )
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default( default_val )
{ }
inline SwitchArg::SwitchArg(const std::string& flag,
@@ -148,114 +149,104 @@ inline SwitchArg::SwitchArg(const std::string& flag,
CmdLineInterface& parser,
bool default_val,
Visitor* v )
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default(default_val)
: Arg(flag, name, desc, false, false, v),
_value( default_val ),
_default(default_val)
{
parser.add( this );
parser.add( this );
}
inline bool SwitchArg::getValue() { return _value; }
inline bool SwitchArg::getValue()
{
return _value;
}
inline bool SwitchArg::lastCombined(std::string& combinedSwitches )
{
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( combinedSwitches[i] != Arg::blankChar() )
return false;
return true;
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( combinedSwitches[i] != Arg::blankChar() )
return false;
return true;
}
inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches )
{
// make sure this is actually a combined switch
if ( combinedSwitches.length() > 0 &&
combinedSwitches[0] != Arg::flagStartString()[0] )
return false;
// make sure it isn't a long name
if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) ==
Arg::nameStartString() )
return false;
// make sure the delimiter isn't in the string
if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos )
return false;
// ok, we're not specifying a ValueArg, so we know that we have
// a combined switch list.
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( _flag.length() > 0 &&
combinedSwitches[i] == _flag[0] &&
_flag[0] != Arg::flagStartString()[0] )
{
// update the combined switches so this one is no longer present
// this is necessary so that no unlabeled args are matched
// later in the processing.
//combinedSwitches.erase(i,1);
combinedSwitches[i] = Arg::blankChar();
return true;
}
// none of the switches passed in the list match.
return false;
// make sure this is actually a combined switch
if ( combinedSwitches.length() > 0 &&
combinedSwitches[0] != Arg::flagStartString()[0] )
return false;
// make sure it isn't a long name
if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) ==
Arg::nameStartString() )
return false;
// make sure the delimiter isn't in the string
if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos )
return false;
// ok, we're not specifying a ValueArg, so we know that we have
// a combined switch list.
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
if ( _flag.length() > 0 &&
combinedSwitches[i] == _flag[0] &&
_flag[0] != Arg::flagStartString()[0] )
{
// update the combined switches so this one is no longer present
// this is necessary so that no unlabeled args are matched
// later in the processing.
//combinedSwitches.erase(i,1);
combinedSwitches[i] = Arg::blankChar();
return true;
}
// none of the switches passed in the list match.
return false;
}
inline void SwitchArg::commonProcessing()
{
if ( _xorSet )
throw(CmdLineParseException(
"Mutually exclusive argument already set!", toString()));
if ( _alreadySet )
throw(CmdLineParseException("Argument already set!", toString()));
_alreadySet = true;
if ( _value == true )
_value = false;
else
_value = true;
_checkWithVisitor();
if ( _xorSet )
throw(CmdLineParseException(
"Mutually exclusive argument already set!", toString()));
if ( _alreadySet )
throw(CmdLineParseException("Argument already set!", toString()));
_alreadySet = true;
if ( _value == true )
_value = false;
else
_value = true;
_checkWithVisitor();
}
inline bool SwitchArg::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
// if the whole string matches the flag or name string
if ( argMatches( args[*i] ) )
{
commonProcessing();
return true;
}
// if a substring matches the flag as part of a combination
else if ( combinedSwitchesMatch( args[*i] ) )
{
// check again to ensure we don't misinterpret
// this as a MultiSwitchArg
if ( combinedSwitchesMatch( args[*i] ) )
throw(CmdLineParseException("Argument already set!",
toString()));
commonProcessing();
// We only want to return true if we've found the last combined
// match in the string, otherwise we return true so that other
// switches in the combination will have a chance to match.
return lastCombined( args[*i] );
}
else
return false;
if ( _ignoreable && Arg::ignoreRest() )
return false;
// if the whole string matches the flag or name string
if ( argMatches( args[*i] ) )
{
commonProcessing();
return true;
}
// if a substring matches the flag as part of a combination
else if ( combinedSwitchesMatch( args[*i] ) )
{
// check again to ensure we don't misinterpret
// this as a MultiSwitchArg
if ( combinedSwitchesMatch( args[*i] ) )
throw(CmdLineParseException("Argument already set!",
toString()));
commonProcessing();
// We only want to return true if we've found the last combined
// match in the string, otherwise we return true so that other
// switches in the combination will have a chance to match.
return lastCombined( args[*i] );
}
else
return false;
}
inline void SwitchArg::reset()
{
Arg::reset();
_value = _default;
Arg::reset();
_value = _default;
}
//////////////////////////////////////////////////////////////////////
//End SwitchArg.cpp

View File

@@ -29,7 +29,8 @@
#include "MultiArg.h"
#include "OptionalUnlabeledTracker.h"
namespace TCLAP {
namespace TCLAP
{
/**
* Just like a MultiArg, except that the arguments are unlabeled. Basically,
@@ -40,260 +41,253 @@ template<class T>
class UnlabeledMultiArg : public MultiArg<T>
{
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is requried to prevent undef. symbols
using MultiArg<T>::_ignoreable;
using MultiArg<T>::_hasBlanks;
using MultiArg<T>::_extractValue;
using MultiArg<T>::_typeDesc;
using MultiArg<T>::_name;
using MultiArg<T>::_description;
using MultiArg<T>::_alreadySet;
using MultiArg<T>::toString;
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is requried to prevent undef. symbols
using MultiArg<T>::_ignoreable;
using MultiArg<T>::_hasBlanks;
using MultiArg<T>::_extractValue;
using MultiArg<T>::_typeDesc;
using MultiArg<T>::_name;
using MultiArg<T>::_description;
using MultiArg<T>::_alreadySet;
using MultiArg<T>::toString;
public:
public:
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Constructor.
* \param name - The name of the Arg. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Whether or not this argument can be ignored
* using the "--" flag.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
UnlabeledMultiArg( const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a short id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Returns the a long id string. Used in the usage.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Opertor ==.
* \param a - The Arg to be compared to this.
*/
virtual bool operator==(const Arg& a) const;
/**
* Opertor ==.
* \param a - The Arg to be compared to this.
*/
virtual bool operator==(const Arg& a) const;
/**
* Pushes this to back of list rather than front.
* \param argList - The list this should be added to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
/**
* Pushes this to back of list rather than front.
* \param argList - The list this should be added to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
};
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
const std::string& desc,
bool req,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
const std::string& desc,
bool req,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
const std::string& desc,
bool req,
Constraint<T>* constraint,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
}
template<class T>
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
const std::string& desc,
bool req,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: MultiArg<T>("", name, desc, req, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(true, toString());
parser.add( this );
}
template<class T>
bool UnlabeledMultiArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled multi arg
// always take the first value, regardless of the start string
_extractValue( args[(*i)] );
/*
// continue taking args until we hit the end or a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled multi arg
// always take the first value, regardless of the start string
_extractValue( args[(*i)] );
/*
// continue taking args until we hit the end or a start string
while ( (unsigned int)(*i)+1 < args.size() &&
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
return true;
_extractValue( args[++(*i)] );
*/
_alreadySet = true;
return true;
}
template<class T>
std::string UnlabeledMultiArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> ...";
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> ...";
}
template<class T>
std::string UnlabeledMultiArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> (accepted multiple times)";
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + "> (accepted multiple times)";
}
template<class T>
bool UnlabeledMultiArg<T>::operator==(const Arg& a) const
{
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
}
template<class T>
void UnlabeledMultiArg<T>::addToList( std::list<Arg*>& argList ) const
{
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
}
}

View File

@@ -31,7 +31,8 @@
#include "OptionalUnlabeledTracker.h"
namespace TCLAP {
namespace TCLAP
{
/**
* The basic unlabeled argument that parses a value.
@@ -43,166 +44,166 @@ template<class T>
class UnlabeledValueArg : public ValueArg<T>
{
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is requried to prevent undef. symbols
using ValueArg<T>::_ignoreable;
using ValueArg<T>::_hasBlanks;
using ValueArg<T>::_extractValue;
using ValueArg<T>::_typeDesc;
using ValueArg<T>::_name;
using ValueArg<T>::_description;
using ValueArg<T>::_alreadySet;
using ValueArg<T>::toString;
// If compiler has two stage name lookup (as gcc >= 3.4 does)
// this is requried to prevent undef. symbols
using ValueArg<T>::_ignoreable;
using ValueArg<T>::_hasBlanks;
using ValueArg<T>::_extractValue;
using ValueArg<T>::_typeDesc;
using ValueArg<T>::_name;
using ValueArg<T>::_description;
using ValueArg<T>::_alreadySet;
using ValueArg<T>::toString;
public:
public:
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL);
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
bool ignoreable = false,
Visitor* v = NULL);
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
bool ignoreable = false,
Visitor* v = NULL );
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL);
/**
* UnlabeledValueArg constructor.
* \param name - A one word name for the argument. Note that this is used for
* identification, not as a long flag.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to
* \param ignoreable - Allows you to specify that this argument can be
* ignored if the '--' flag is set. This defaults to false (cannot
* be ignored) and should generally stay that way unless you have
* some special need for certain arguments to be ignored.
* \param v - Optional Vistor. You should leave this blank unless
* you have a very good reason.
*/
UnlabeledValueArg( const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable = false,
Visitor* v = NULL);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. Handling specific to
* unlabled arguments.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings.
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. Handling specific to
* unlabled arguments.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings.
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Overrides shortID for specific behavior.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Overrides shortID for specific behavior.
*/
virtual std::string shortID(const std::string& val="val") const;
/**
* Overrides longID for specific behavior.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Overrides longID for specific behavior.
*/
virtual std::string longID(const std::string& val="val") const;
/**
* Overrides operator== for specific behavior.
*/
virtual bool operator==(const Arg& a ) const;
/**
* Overrides operator== for specific behavior.
*/
virtual bool operator==(const Arg& a ) const;
/**
* Instead of pushing to the front of list, push to the back.
* \param argList - The list to add this to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
/**
* Instead of pushing to the front of list, push to the back.
* \param argList - The list to add this to.
*/
virtual void addToList( std::list<Arg*>& argList ) const;
};
@@ -211,34 +212,32 @@ class UnlabeledValueArg : public ValueArg<T>
*/
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
}
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
const std::string& desc,
bool req,
T val,
const std::string& typeDesc,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
}
/**
@@ -247,31 +246,31 @@ UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
bool req,
T val,
Constraint<T>* constraint,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
}
template<class T>
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
const std::string& desc,
bool req,
T val,
Constraint<T>* constraint,
CmdLineInterface& parser,
bool ignoreable,
Visitor* v)
: ValueArg<T>("", name, desc, req, val, constraint, v)
{
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
_ignoreable = ignoreable;
OptionalUnlabeledTracker::check(req, toString());
parser.add( this );
}
/**
@@ -280,18 +279,14 @@ UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
template<class T>
bool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _alreadySet )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled arg
_extractValue( args[*i] );
_alreadySet = true;
return true;
if ( _alreadySet )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
// never ignore an unlabeled arg
_extractValue( args[*i] );
_alreadySet = true;
return true;
}
/**
@@ -300,8 +295,8 @@ bool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args)
template<class T>
std::string UnlabeledValueArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + ">";
static_cast<void>(val); // Ignore input, don't warn
return std::string("<") + _typeDesc + ">";
}
/**
@@ -310,12 +305,11 @@ std::string UnlabeledValueArg<T>::shortID(const std::string& val) const
template<class T>
std::string UnlabeledValueArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
// Ideally we would like to be able to use RTTI to return the name
// of the type required for this argument. However, g++ at least,
// doesn't appear to return terribly useful "names" of the types.
return std::string("<") + _typeDesc + ">";
static_cast<void>(val); // Ignore input, don't warn
// Ideally we would like to be able to use RTTI to return the name
// of the type required for this argument. However, g++ at least,
// doesn't appear to return terribly useful "names" of the types.
return std::string("<") + _typeDesc + ">";
}
/**
@@ -324,16 +318,16 @@ std::string UnlabeledValueArg<T>::longID(const std::string& val) const
template<class T>
bool UnlabeledValueArg<T>::operator==(const Arg& a ) const
{
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
if ( _name == a.getName() || _description == a.getDescription() )
return true;
else
return false;
}
template<class T>
void UnlabeledValueArg<T>::addToList( std::list<Arg*>& argList ) const
{
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
}
}

View File

@@ -29,7 +29,8 @@
#include "Arg.h"
#include "Constraint.h"
namespace TCLAP {
namespace TCLAP
{
/**
* The basic labeled argument that parses a value.
@@ -42,206 +43,206 @@ namespace TCLAP {
template<class T>
class ValueArg : public Arg
{
protected:
protected:
/**
* The value parsed from the command line.
* Can be of any type, as long as the >> operator for the type
* is defined.
*/
T _value;
/**
* The value parsed from the command line.
* Can be of any type, as long as the >> operator for the type
* is defined.
*/
T _value;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
T _default;
/**
* Used to support the reset() method so that ValueArg can be
* reset to their constructed value.
*/
T _default;
/**
* A human readable description of the type to be parsed.
* This is a hack, plain and simple. Ideally we would use RTTI to
* return the name of type T, but until there is some sort of
* consistent support for human readable names, we are left to our
* own devices.
*/
std::string _typeDesc;
/**
* A human readable description of the type to be parsed.
* This is a hack, plain and simple. Ideally we would use RTTI to
* return the name of type T, but until there is some sort of
* consistent support for human readable names, we are left to our
* own devices.
*/
std::string _typeDesc;
/**
* A Constraint this Arg must conform to.
*/
Constraint<T>* _constraint;
/**
* A Constraint this Arg must conform to.
*/
Constraint<T>* _constraint;
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - value to be parsed.
*/
void _extractValue( const std::string& val );
/**
* Extracts the value from the string.
* Attempts to parse string as type T, if this fails an exception
* is thrown.
* \param val - value to be parsed.
*/
void _extractValue( const std::string& val );
public:
public:
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
Visitor* v = NULL);
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param typeDesc - A short, human readable description of the
* type that this object expects. This is used in the generation
* of the USAGE statement. The goal is to be helpful to the end user
* of the program.
* \param parser - A CmdLine parser object to add this Arg to
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param parser - A CmdLine parser object to add this Arg to.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Labeled ValueArg constructor.
* You could conceivably call this constructor with a blank flag,
* but that would make you a bad person. It would also cause
* an exception to be thrown. If you want an unlabeled argument,
* use the other constructor.
* \param flag - The one character flag that identifies this
* argument on the command line.
* \param name - A one word name for the argument. Can be
* used as a long flag on the command line.
* \param desc - A description of what the argument is for or
* does.
* \param req - Whether the argument is required on the command
* line.
* \param value - The default value assigned to this argument if it
* is not present on the command line.
* \param constraint - A pointer to a Constraint object used
* to constrain this Arg.
* \param v - An optional visitor. You probably should not
* use this unless you have a very good reason.
*/
ValueArg( const std::string& flag,
const std::string& name,
const std::string& desc,
bool req,
T value,
Constraint<T>* constraint,
Visitor* v = NULL );
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Handles the processing of the argument.
* This re-implements the Arg version of this method to set the
* _value of the argument appropriately. It knows the difference
* between labeled and unlabeled.
* \param i - Pointer the the current argument in the list.
* \param args - Mutable list of strings. Passed
* in from main().
*/
virtual bool processArg(int* i, std::vector<std::string>& args);
/**
* Returns the value of the argument.
*/
T& getValue() ;
/**
* Returns the value of the argument.
*/
T& getValue() ;
/**
* Specialization of shortID.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val = "val") const;
/**
* Specialization of shortID.
* \param val - value to be used.
*/
virtual std::string shortID(const std::string& val = "val") const;
/**
* Specialization of longID.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val = "val") const;
/**
* Specialization of longID.
* \param val - value to be used.
*/
virtual std::string longID(const std::string& val = "val") const;
virtual void reset() ;
virtual void reset() ;
private:
/**
* Prevent accidental copying
*/
ValueArg<T>(const ValueArg<T>& rhs);
ValueArg<T>& operator=(const ValueArg<T>& rhs);
private:
/**
* Prevent accidental copying
*/
ValueArg<T>(const ValueArg<T>& rhs);
ValueArg<T>& operator=(const ValueArg<T>& rhs);
};
@@ -256,11 +257,11 @@ ValueArg<T>::ValueArg(const std::string& flag,
T val,
const std::string& typeDesc,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
{ }
template<class T>
@@ -272,13 +273,13 @@ ValueArg<T>::ValueArg(const std::string& flag,
const std::string& typeDesc,
CmdLineInterface& parser,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( typeDesc ),
_constraint( NULL )
{
parser.add( this );
parser.add( this );
}
template<class T>
@@ -289,11 +290,11 @@ ValueArg<T>::ValueArg(const std::string& flag,
T val,
Constraint<T>* constraint,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( constraint->shortID() ),
_constraint( constraint )
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( constraint->shortID() ),
_constraint( constraint )
{ }
template<class T>
@@ -305,13 +306,13 @@ ValueArg<T>::ValueArg(const std::string& flag,
Constraint<T>* constraint,
CmdLineInterface& parser,
Visitor* v)
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( constraint->shortID() ),
_constraint( constraint )
: Arg(flag, name, desc, req, true, v),
_value( val ),
_default( val ),
_typeDesc( constraint->shortID() ),
_constraint( constraint )
{
parser.add( this );
parser.add( this );
}
@@ -319,7 +320,10 @@ ValueArg<T>::ValueArg(const std::string& flag,
* Implementation of getValue().
*/
template<class T>
T& ValueArg<T>::getValue() { return _value; }
T& ValueArg<T>::getValue()
{
return _value;
}
/**
* Implementation of processArg().
@@ -327,53 +331,46 @@ T& ValueArg<T>::getValue() { return _value; }
template<class T>
bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
{
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
if ( _ignoreable && Arg::ignoreRest() )
return false;
if ( _hasBlanks( args[*i] ) )
return false;
std::string flag = args[*i];
std::string value = "";
trimFlag( flag, value );
if ( argMatches( flag ) )
{
if ( _alreadySet )
{
if ( _alreadySet )
{
if ( _xorSet )
throw( CmdLineParseException(
"Mutually exclusive argument already set!",
toString()) );
else
throw( CmdLineParseException("Argument already set!",
toString()) );
}
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException(
"Couldn't find delimiter for this argument!",
toString() ) );
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
_extractValue( value );
_alreadySet = true;
_checkWithVisitor();
return true;
if ( _xorSet )
throw( CmdLineParseException(
"Mutually exclusive argument already set!",
toString()) );
else
throw( CmdLineParseException("Argument already set!",
toString()) );
}
if ( Arg::delimiter() != ' ' && value == "" )
throw( ArgParseException(
"Couldn't find delimiter for this argument!",
toString() ) );
if ( value == "" )
{
(*i)++;
if ( static_cast<unsigned int>(*i) < args.size() )
_extractValue( args[*i] );
else
throw( ArgParseException("Missing a value for this argument!",
toString() ) );
}
else
return false;
_extractValue( value );
_alreadySet = true;
_checkWithVisitor();
return true;
}
else
return false;
}
/**
@@ -382,8 +379,8 @@ bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
template<class T>
std::string ValueArg<T>::shortID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID( _typeDesc );
static_cast<void>(val); // Ignore input, don't warn
return Arg::shortID( _typeDesc );
}
/**
@@ -392,32 +389,34 @@ std::string ValueArg<T>::shortID(const std::string& val) const
template<class T>
std::string ValueArg<T>::longID(const std::string& val) const
{
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID( _typeDesc );
static_cast<void>(val); // Ignore input, don't warn
return Arg::longID( _typeDesc );
}
template<class T>
void ValueArg<T>::_extractValue( const std::string& val )
{
try {
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
} catch( ArgParseException &e) {
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _value ) )
throw( CmdLineParseException( "Value '" + val +
+ "' does not meet constraint: "
+ _constraint->description(),
toString() ) );
try
{
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
}
catch( ArgParseException &e)
{
throw ArgParseException(e.error(), toString());
}
if ( _constraint != NULL )
if ( ! _constraint->check( _value ) )
throw( CmdLineParseException( "Value '" + val +
+ "' does not meet constraint: "
+ _constraint->description(),
toString() ) );
}
template<class T>
void ValueArg<T>::reset()
{
Arg::reset();
_value = _default;
Arg::reset();
_value = _default;
}
} // namespace TCLAP

View File

@@ -41,7 +41,8 @@
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
namespace TCLAP {
namespace TCLAP
{
/**
* A Constraint that constrains the Arg to only those values specified
@@ -51,95 +52,91 @@ template<class T>
class ValuesConstraint : public Constraint<T>
{
public:
public:
/**
* Constructor.
* \param allowed - vector of allowed values.
*/
ValuesConstraint(std::vector<T>& allowed);
/**
* Constructor.
* \param allowed - vector of allowed values.
*/
ValuesConstraint(std::vector<T>& allowed);
/**
* Virtual destructor.
*/
virtual ~ValuesConstraint() {}
/**
* Virtual destructor.
*/
virtual ~ValuesConstraint() {}
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const;
/**
* Returns a description of the Constraint.
*/
virtual std::string description() const;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const;
/**
* Returns the short ID for the Constraint.
*/
virtual std::string shortID() const;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const;
/**
* The method used to verify that the value parsed from the command
* line meets the constraint.
* \param value - The value that will be checked.
*/
virtual bool check(const T& value) const;
protected:
protected:
/**
* The list of valid values.
*/
std::vector<T> _allowed;
/**
* The list of valid values.
*/
std::vector<T> _allowed;
/**
* The string used to describe the allowed values of this constraint.
*/
std::string _typeDesc;
/**
* The string used to describe the allowed values of this constraint.
*/
std::string _typeDesc;
};
template<class T>
ValuesConstraint<T>::ValuesConstraint(std::vector<T>& allowed)
: _allowed(allowed),
_typeDesc("")
: _allowed(allowed),
_typeDesc("")
{
for ( unsigned int i = 0; i < _allowed.size(); i++ )
{
for ( unsigned int i = 0; i < _allowed.size(); i++ )
{
#if defined(HAVE_SSTREAM)
std::ostringstream os;
std::ostringstream os;
#elif defined(HAVE_STRSTREAM)
std::ostrstream os;
std::ostrstream os;
#else
#error "Need a stringstream (sstream or strstream) to compile!"
#endif
os << _allowed[i];
std::string temp( os.str() );
if ( i > 0 )
_typeDesc += "|";
_typeDesc += temp;
}
os << _allowed[i];
std::string temp( os.str() );
if ( i > 0 )
_typeDesc += "|";
_typeDesc += temp;
}
}
template<class T>
bool ValuesConstraint<T>::check( const T& val ) const
{
if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )
return false;
else
return true;
if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )
return false;
else
return true;
}
template<class T>
std::string ValuesConstraint<T>::shortID() const
{
return _typeDesc;
return _typeDesc;
}
template<class T>
std::string ValuesConstraint<T>::description() const
{
return _typeDesc;
return _typeDesc;
}

View File

@@ -28,7 +28,8 @@
#include "CmdLineOutput.h"
#include "Visitor.h"
namespace TCLAP {
namespace TCLAP
{
/**
* A Vistor that will call the version method of the given CmdLineOutput
@@ -36,43 +37,44 @@ namespace TCLAP {
*/
class VersionVisitor: public Visitor
{
private:
/**
* Prevent accidental copying
*/
VersionVisitor(const VersionVisitor& rhs);
VersionVisitor& operator=(const VersionVisitor& rhs);
private:
/**
* Prevent accidental copying
*/
VersionVisitor(const VersionVisitor& rhs);
VersionVisitor& operator=(const VersionVisitor& rhs);
protected:
protected:
/**
* The CmdLine of interest.
*/
CmdLineInterface* _cmd;
/**
* The CmdLine of interest.
*/
CmdLineInterface* _cmd;
/**
* The output object.
*/
CmdLineOutput** _out;
/**
* The output object.
*/
CmdLineOutput** _out;
public:
public:
/**
* Constructor.
* \param cmd - The CmdLine the output is generated for.
* \param out - The type of output.
*/
VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out )
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Constructor.
* \param cmd - The CmdLine the output is generated for.
* \param out - The type of output.
*/
VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out )
: Visitor(), _cmd( cmd ), _out( out ) { }
/**
* Calls the version method of the output object using the
* specified CmdLine.
*/
void visit() {
(*_out)->version(*_cmd);
throw ExitException(0);
}
/**
* Calls the version method of the output object using the
* specified CmdLine.
*/
void visit()
{
(*_out)->version(*_cmd);
throw ExitException(0);
}
};

View File

@@ -23,29 +23,30 @@
#ifndef TCLAP_VISITOR_H
#define TCLAP_VISITOR_H
namespace TCLAP {
namespace TCLAP
{
/**
* A base class that defines the interface for visitors.
*/
class Visitor
{
public:
public:
/**
* Constructor. Does nothing.
*/
Visitor() { }
/**
* Constructor. Does nothing.
*/
Visitor() { }
/**
* Destructor. Does nothing.
*/
virtual ~Visitor() { }
/**
* Destructor. Does nothing.
*/
virtual ~Visitor() { }
/**
* Does nothing. Should be overridden by child.
*/
virtual void visit() { }
/**
* Does nothing. Should be overridden by child.
*/
virtual void visit() { }
};
}

View File

@@ -29,7 +29,8 @@
#include <algorithm>
#include <iostream>
namespace TCLAP {
namespace TCLAP
{
/**
* This class handles lists of Arg's that are to be XOR'd on the command
@@ -37,54 +38,54 @@ namespace TCLAP {
*/
class XorHandler
{
protected:
protected:
/**
* The list of of lists of Arg's to be or'd together.
*/
std::vector< std::vector<Arg*> > _orList;
/**
* The list of of lists of Arg's to be or'd together.
*/
std::vector< std::vector<Arg*> > _orList;
public:
public:
/**
* Constructor. Does nothing.
*/
XorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}
/**
* Constructor. Does nothing.
*/
XorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}
/**
* Add a list of Arg*'s that will be orred together.
* \param ors - list of Arg* that will be xor'd.
*/
void add( std::vector<Arg*>& ors );
/**
* Add a list of Arg*'s that will be orred together.
* \param ors - list of Arg* that will be xor'd.
*/
void add( std::vector<Arg*>& ors );
/**
* Checks whether the specified Arg is in one of the xor lists and
* if it does match one, returns the size of the xor list that the
* Arg matched. If the Arg matches, then it also sets the rest of
* the Arg's in the list. You shouldn't use this.
* \param a - The Arg to be checked.
*/
int check( const Arg* a );
/**
* Checks whether the specified Arg is in one of the xor lists and
* if it does match one, returns the size of the xor list that the
* Arg matched. If the Arg matches, then it also sets the rest of
* the Arg's in the list. You shouldn't use this.
* \param a - The Arg to be checked.
*/
int check( const Arg* a );
/**
* Returns the XOR specific short usage.
*/
std::string shortUsage();
/**
* Returns the XOR specific short usage.
*/
std::string shortUsage();
/**
* Prints the XOR specific long usage.
* \param os - Stream to print to.
*/
void printLongUsage(std::ostream& os);
/**
* Prints the XOR specific long usage.
* \param os - Stream to print to.
*/
void printLongUsage(std::ostream& os);
/**
* Simply checks whether the Arg is contained in one of the arg
* lists.
* \param a - The Arg to be checked.
*/
bool contains( const Arg* a );
/**
* Simply checks whether the Arg is contained in one of the arg
* lists.
* \param a - The Arg to be checked.
*/
bool contains( const Arg* a );
std::vector< std::vector<Arg*> >& getXorList();
std::vector< std::vector<Arg*> >& getXorList();
};
@@ -94,65 +95,61 @@ class XorHandler
//////////////////////////////////////////////////////////////////////
inline void XorHandler::add( std::vector<Arg*>& ors )
{
_orList.push_back( ors );
_orList.push_back( ors );
}
inline int XorHandler::check( const Arg* a )
{
// iterate over each XOR list
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
{
// if the XOR list contains the arg..
ArgVectorIterator ait = std::find( _orList[i].begin(),
_orList[i].end(), a );
if ( ait != _orList[i].end() )
{
// first check to see if a mutually exclusive switch
// has not already been set
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) && (*it)->isSet() )
throw(CmdLineParseException(
"Mutually exclusive argument already set!",
(*it)->toString()));
// go through and set each arg that is not a
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) )
(*it)->xorSet();
// return the number of required args that have now been set
if ( (*ait)->allowMore() )
return 0;
else
return static_cast<int>(_orList[i].size());
}
}
if ( a->isRequired() )
return 1;
else
return 0;
// iterate over each XOR list
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
{
// if the XOR list contains the arg..
ArgVectorIterator ait = std::find( _orList[i].begin(),
_orList[i].end(), a );
if ( ait != _orList[i].end() )
{
// first check to see if a mutually exclusive switch
// has not already been set
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) && (*it)->isSet() )
throw(CmdLineParseException(
"Mutually exclusive argument already set!",
(*it)->toString()));
// go through and set each arg that is not a
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a != (*it) )
(*it)->xorSet();
// return the number of required args that have now been set
if ( (*ait)->allowMore() )
return 0;
else
return static_cast<int>(_orList[i].size());
}
}
if ( a->isRequired() )
return 1;
else
return 0;
}
inline bool XorHandler::contains( const Arg* a )
{
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a == (*it) )
return true;
return false;
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
for ( ArgVectorIterator it = _orList[i].begin();
it != _orList[i].end();
it++ )
if ( a == (*it) )
return true;
return false;
}
inline std::vector< std::vector<Arg*> >& XorHandler::getXorList()
{
return _orList;
return _orList;
}

View File

@@ -34,7 +34,8 @@
#include <tclap/XorHandler.h>
#include <tclap/Arg.h>
namespace TCLAP {
namespace TCLAP
{
/**
* A class that generates a Zsh completion function as output from the usage()
@@ -43,280 +44,266 @@ namespace TCLAP {
class ZshCompletionOutput : public CmdLineOutput
{
public:
public:
ZshCompletionOutput();
ZshCompletionOutput();
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the usage to stdout. Can be overridden to
* produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void usage(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints the version to stdout. Can be overridden
* to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
*/
virtual void version(CmdLineInterface& c);
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
/**
* Prints (to stderr) an error message, short usage
* Can be overridden to produce alternative behavior.
* \param c - The CmdLine object the output is generated for.
* \param e - The ArgException that caused the failure.
*/
virtual void failure(CmdLineInterface& c,
ArgException& e );
protected:
protected:
void basename( std::string& s );
void quoteSpecialChars( std::string& s );
void basename( std::string& s );
void quoteSpecialChars( std::string& s );
std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
void printOption( Arg* it, std::string mutex );
void printArg( Arg* it );
std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
void printOption( Arg* it, std::string mutex );
void printArg( Arg* it );
std::map<std::string, std::string> common;
char theDelimiter;
std::map<std::string, std::string> common;
char theDelimiter;
};
ZshCompletionOutput::ZshCompletionOutput()
: common(std::map<std::string, std::string>()),
theDelimiter('=')
: common(std::map<std::string, std::string>()),
theDelimiter('=')
{
common["host"] = "_hosts";
common["hostname"] = "_hosts";
common["file"] = "_files";
common["filename"] = "_files";
common["user"] = "_users";
common["username"] = "_users";
common["directory"] = "_directories";
common["path"] = "_directories";
common["url"] = "_urls";
common["host"] = "_hosts";
common["hostname"] = "_hosts";
common["file"] = "_files";
common["filename"] = "_files";
common["user"] = "_users";
common["username"] = "_users";
common["directory"] = "_directories";
common["path"] = "_directories";
common["url"] = "_urls";
}
inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
{
std::cout << _cmd.getVersion() << std::endl;
std::cout << _cmd.getVersion() << std::endl;
}
inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
{
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
basename(progName);
std::cout << "#compdef " << progName << std::endl << std::endl <<
"# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
"_arguments -s -S";
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
{
if ( (*it)->shortID().at(0) == '<' )
printArg((*it));
else if ( (*it)->getFlag() != "-" )
printOption((*it), getMutexList(_cmd, *it));
}
std::cout << std::endl;
std::list<Arg*> argList = _cmd.getArgList();
std::string progName = _cmd.getProgramName();
std::string xversion = _cmd.getVersion();
theDelimiter = _cmd.getDelimiter();
basename(progName);
std::cout << "#compdef " << progName << std::endl << std::endl <<
"# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
"_arguments -s -S";
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
{
if ( (*it)->shortID().at(0) == '<' )
printArg((*it));
else if ( (*it)->getFlag() != "-" )
printOption((*it), getMutexList(_cmd, *it));
}
std::cout << std::endl;
}
inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
ArgException& e )
ArgException& e )
{
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
static_cast<void>(_cmd); // unused
std::cout << e.what() << std::endl;
}
inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
{
size_t idx = s.find_last_of(':');
while ( idx != std::string::npos )
{
s.insert(idx, 1, '\\');
idx = s.find_last_of(':', idx);
}
idx = s.find_last_of('\'');
while ( idx != std::string::npos )
{
s.insert(idx, "'\\'");
if (idx == 0)
idx = std::string::npos;
else
idx = s.find_last_of('\'', --idx);
}
size_t idx = s.find_last_of(':');
while ( idx != std::string::npos )
{
s.insert(idx, 1, '\\');
idx = s.find_last_of(':', idx);
}
idx = s.find_last_of('\'');
while ( idx != std::string::npos )
{
s.insert(idx, "'\\'");
if (idx == 0)
idx = std::string::npos;
else
idx = s.find_last_of('\'', --idx);
}
}
inline void ZshCompletionOutput::basename( std::string& s )
{
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
size_t p = s.find_last_of('/');
if ( p != std::string::npos )
{
s.erase(0, p + 1);
}
}
inline void ZshCompletionOutput::printArg(Arg* a)
{
static int count = 1;
std::cout << " \\" << std::endl << " '";
if ( a->acceptsMultipleValues() )
std::cout << '*';
else
std::cout << count++;
std::cout << ':';
if ( !a->isRequired() )
std::cout << ':';
std::cout << a->getName() << ':';
std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
if ( compArg != common.end() )
{
std::cout << compArg->second;
}
else
{
std::cout << "_guard \"^-*\" " << a->getName();
}
std::cout << '\'';
static int count = 1;
std::cout << " \\" << std::endl << " '";
if ( a->acceptsMultipleValues() )
std::cout << '*';
else
std::cout << count++;
std::cout << ':';
if ( !a->isRequired() )
std::cout << ':';
std::cout << a->getName() << ':';
std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
if ( compArg != common.end() )
{
std::cout << compArg->second;
}
else
{
std::cout << "_guard \"^-*\" " << a->getName();
}
std::cout << '\'';
}
inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
{
std::string flag = a->flagStartChar() + a->getFlag();
std::string name = a->nameStartString() + a->getName();
std::string desc = a->getDescription();
// remove full stop and capitalisation from description as
// this is the convention for zsh function
if (!desc.compare(0, 12, "(required) "))
{
desc.erase(0, 12);
}
if (!desc.compare(0, 15, "(OR required) "))
{
desc.erase(0, 15);
}
size_t len = desc.length();
if (len && desc.at(--len) == '.')
{
desc.erase(len);
}
if (len)
{
desc.replace(0, 1, 1, tolower(desc.at(0)));
}
std::cout << " \\" << std::endl << " '" << mutex;
if ( a->getFlag().empty() )
{
std::cout << name;
}
else
{
std::cout << "'{" << flag << ',' << name << "}'";
}
if ( theDelimiter == '=' && a->isValueRequired() )
std::cout << "=-";
quoteSpecialChars(desc);
std::cout << '[' << desc << ']';
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
if ( arg.at(arg.length()-1) == ']' )
arg.erase(arg.length()-1);
if ( arg.at(arg.length()-1) == ']' )
{
arg.erase(arg.length()-1);
}
if ( arg.at(0) == '<' )
{
arg.erase(arg.length()-1);
arg.erase(0, 1);
}
size_t p = arg.find('|');
if ( p != std::string::npos )
{
do
{
arg.replace(p, 1, 1, ' ');
}
while ( (p = arg.find_first_of('|', p)) != std::string::npos );
quoteSpecialChars(arg);
std::cout << ": :(" << arg << ')';
}
else
{
std::cout << ':' << arg;
std::map<std::string, std::string>::iterator compArg = common.find(arg);
if ( compArg != common.end() )
{
std::cout << ':' << compArg->second;
}
}
}
std::cout << '\'';
std::string flag = a->flagStartChar() + a->getFlag();
std::string name = a->nameStartString() + a->getName();
std::string desc = a->getDescription();
// remove full stop and capitalisation from description as
// this is the convention for zsh function
if (!desc.compare(0, 12, "(required) "))
{
desc.erase(0, 12);
}
if (!desc.compare(0, 15, "(OR required) "))
{
desc.erase(0, 15);
}
size_t len = desc.length();
if (len && desc.at(--len) == '.')
{
desc.erase(len);
}
if (len)
{
desc.replace(0, 1, 1, tolower(desc.at(0)));
}
std::cout << " \\" << std::endl << " '" << mutex;
if ( a->getFlag().empty() )
{
std::cout << name;
}
else
{
std::cout << "'{" << flag << ',' << name << "}'";
}
if ( theDelimiter == '=' && a->isValueRequired() )
std::cout << "=-";
quoteSpecialChars(desc);
std::cout << '[' << desc << ']';
if ( a->isValueRequired() )
{
std::string arg = a->shortID();
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
if ( arg.at(arg.length()-1) == ']' )
arg.erase(arg.length()-1);
if ( arg.at(arg.length()-1) == ']' )
{
arg.erase(arg.length()-1);
}
if ( arg.at(0) == '<' )
{
arg.erase(arg.length()-1);
arg.erase(0, 1);
}
size_t p = arg.find('|');
if ( p != std::string::npos )
{
do
{
arg.replace(p, 1, 1, ' ');
}
while ( (p = arg.find_first_of('|', p)) != std::string::npos );
quoteSpecialChars(arg);
std::cout << ": :(" << arg << ')';
}
else
{
std::cout << ':' << arg;
std::map<std::string, std::string>::iterator compArg = common.find(arg);
if ( compArg != common.end() )
{
std::cout << ':' << compArg->second;
}
}
}
std::cout << '\'';
}
inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
{
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
if (a->getName() == "help" || a->getName() == "version")
{
return "(-)";
}
std::ostringstream list;
if ( a->acceptsMultipleValues() )
{
list << '*';
}
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++)
if ( a == (*it) )
{
list << '(';
for ( ArgVectorIterator iu = xorList[i].begin();
iu != xorList[i].end();
iu++ )
{
bool notCur = (*iu) != a;
bool hasFlag = !(*iu)->getFlag().empty();
if ( iu != xorList[i].begin() && (notCur || hasFlag) )
list << ' ';
if (hasFlag)
list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
if ( notCur || hasFlag )
list << (*iu)->nameStartString() << (*iu)->getName();
}
list << ')';
return list.str();
}
}
// wasn't found in xor list
if (!a->getFlag().empty()) {
list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
a->nameStartString() << a->getName() << ')';
}
return list.str();
XorHandler xorHandler = _cmd.getXorHandler();
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
if (a->getName() == "help" || a->getName() == "version")
{
return "(-)";
}
std::ostringstream list;
if ( a->acceptsMultipleValues() )
{
list << '*';
}
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
{
for ( ArgVectorIterator it = xorList[i].begin();
it != xorList[i].end();
it++)
if ( a == (*it) )
{
list << '(';
for ( ArgVectorIterator iu = xorList[i].begin();
iu != xorList[i].end();
iu++ )
{
bool notCur = (*iu) != a;
bool hasFlag = !(*iu)->getFlag().empty();
if ( iu != xorList[i].begin() && (notCur || hasFlag) )
list << ' ';
if (hasFlag)
list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
if ( notCur || hasFlag )
list << (*iu)->nameStartString() << (*iu)->getName();
}
list << ')';
return list.str();
}
}
// wasn't found in xor list
if (!a->getFlag().empty())
{
list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
a->nameStartString() << a->getName() << ')';
}
return list.str();
}
} //namespace TCLAP