diff --git a/README.md b/README.md index 8f454da..37ddf87 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ User Guide OpenALPR includes a command line utility. Simply typing "alpr [image file path]" is enough to get started recognizing license plate images. -For example, the following output is created by analyzing this image: +For example, the following output is created by analyzing this image: ![Plate Image](http://www.openalpr.com/images/demoscreenshots/plate3.png "Input image") @@ -39,7 +39,7 @@ Detailed command line usage: ``` user@linux:~/openalpr$ alpr --help -USAGE: +USAGE: alpr [-t ] [-r ] [-n ] [--seek ] [-c ] @@ -47,7 +47,7 @@ USAGE: -Where: +Where: -t , --template_region Attempt to match the plate number against a region template (e.g., md @@ -63,11 +63,11 @@ Where: Seek to the specied millisecond in a video file. Default=0 -c , --country - Country code to identify (either us for USA or eu for Europe). + Country code to identify (either us for USA or eu for Europe). Default=us --clock - Measure/print the total time to process image and all plates. + Measure/print the total time to process image and all plates. Default=off -d, --detect_region @@ -100,7 +100,7 @@ OpenALPR compiles and runs on Linux, Mac OSX and Windows. OpenALPR requires the following additional libraries: - - Tesseract OCR v3.x (https://code.google.com/p/tesseract-ocr/) + - Tesseract OCR v3.x (https://code.google.com/p/tesseract-ocr/) - OpenCV v2.4.x (http://opencv.org/) After cloning this GitHub repository, you should download and extract Tesseract and OpenCV source code into their own directories. Compile both libraries. @@ -127,5 +127,3 @@ License Affero GPLv3 http://www.gnu.org/licenses/agpl-3.0.html - - diff --git a/runtime_data/openalpr.conf b/runtime_data/openalpr.conf index dd9a616..a6d2803 100644 --- a/runtime_data/openalpr.conf +++ b/runtime_data/openalpr.conf @@ -14,7 +14,7 @@ ocr_min_font_point = 6 ; Minimum OCR confidence percent to consider. postprocess_min_confidence = 60 -; Any OCR character lower than this will also add an equally likely +; Any OCR character lower than this will also add an equally likely ; chance that the character is incorrect and will be skipped. Value is a confidence percent postprocess_confidence_skip_level = 75 @@ -110,7 +110,3 @@ min_plate_size_width_px = 100 min_plate_size_height_px = 20 ocr_language = leu - - - - diff --git a/runtime_data/postprocess/us.patterns b/runtime_data/postprocess/us.patterns index be3ce6a..0644ea5 100644 --- a/runtime_data/postprocess/us.patterns +++ b/runtime_data/postprocess/us.patterns @@ -1,8 +1,8 @@ -base @@@#### +base @@@#### base @@@### base ###@@@ -al #@##@## -al ##@##@# +al #@##@## +al ##@##@# al @@##### al #####@@ al #@####@ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ec33b0a..de66841 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,26 +1,26 @@ project(src) -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 2.6) SET(OpenCV_DIR "${CMAKE_SOURCE_DIR}/../libraries/opencv/") SET(Tesseract_DIR "${CMAKE_SOURCE_DIR}/../libraries/tesseract-ocr") - + include_directories( ${Tesseract_DIR}/api ${Tesseract_DIR}/ccutil/ ${Tesseract_DIR}/ccstruct/ ${Tesseract_DIR}/ccmain/ ) - + IF (WIN32) add_definitions( -DWINDOWS) add_definitions( -DNOMINMAX) - - link_directories( ${Tesseract_DIR}/vs2008/LIB_Release/ ) + + link_directories( ${Tesseract_DIR}/vs2008/LIB_Release/ ) ELSE() - link_directories( ${Tesseract_DIR}/api/.libs/ ) + link_directories( ${Tesseract_DIR}/api/.libs/ ) ENDIF() @@ -40,10 +40,10 @@ ADD_EXECUTABLE( alpr main.cpp ) IF (WIN32) # Extra linker dependencies for Windows - TARGET_LINK_LIBRARIES(alpr + TARGET_LINK_LIBRARIES(alpr openalpr support - ${OpenCV_LIBS} + ${OpenCV_LIBS} libtesseract302-static liblept168 liblept168-static-mtdll @@ -54,17 +54,16 @@ IF (WIN32) zlib125-static-mtdll ws2_32.lib ) - + ELSE() - TARGET_LINK_LIBRARIES(alpr + TARGET_LINK_LIBRARIES(alpr openalpr support - ${OpenCV_LIBS} + ${OpenCV_LIBS} tesseract ) ENDIF() - + add_subdirectory(openalpr) add_subdirectory(misc_utilities) - diff --git a/src/main.cpp b/src/main.cpp index 3bd3c49..78569c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -32,20 +32,20 @@ #include "alpr.h" - + 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"; - + /** 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; @@ -56,19 +56,19 @@ std::string templateRegion; std::string country; int topn; - - try { - + + try { + TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION); - + TCLAP::UnlabeledValueArg fileArg( "image_file", "Image containing license plates", true, "", "image_file_path" ); - + TCLAP::ValueArg countryCodeArg("c","country","Country code to identify (either us for USA or eu for Europe). Default=us",false, "us" ,"country_code"); TCLAP::ValueArg seekToMsArg("","seek","Seek to the specied millisecond in a video file. Default=0",false, 0 ,"integer_ms"); TCLAP::ValueArg runtimeDirArg("r","runtime_dir","Path to the OpenAlpr runtime data directory",false, "" ,"runtime_dir"); TCLAP::ValueArg 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 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); @@ -78,12 +78,12 @@ cmd.add( seekToMsArg ); cmd.add( topNArg ); cmd.add( runtimeDirArg ); - cmd.add( templateRegionArg ); - + cmd.add( templateRegionArg ); + cmd.parse( argc, argv ); - + filename = fileArg.getValue(); - + country = countryCodeArg.getValue(); seektoms = seekToMsArg.getValue(); outputJson = jsonSwitch.getValue(); @@ -92,33 +92,33 @@ 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; + { + std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; return 1; } - + cv::Mat frame; - + Alpr alpr(country, runtimePath); alpr.setTopN(topn); - + if (detectRegion) alpr.setDetectRegion(detectRegion); - + if (strcmp(templateRegion.c_str(), "") != 0) { alpr.setDefaultRegion(templateRegion); } - + if (alpr.isLoaded() == false) { std::cerr << "Error loading OpenAlpr" << std::endl; return 1; } - + if (strcmp(filename.c_str(), "webcam") == 0) { int framenum = 0; @@ -141,11 +141,11 @@ if (fileExists(filename.c_str())) { int framenum = 0; - + cv::VideoCapture cap=cv::VideoCapture(); cap.open(filename); cap.set(CV_CAP_PROP_POS_MSEC, seektoms); - + while (cap.read(frame) == true) { if (SAVE_LAST_VIDEO_STILL == true) @@ -153,7 +153,7 @@ cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame); } std::cout << "Frame: " << framenum << std::endl; - + detectandshow( &alpr, frame, "", outputJson); //create a 1ms delay cv::waitKey(1); @@ -164,29 +164,29 @@ { std::cerr << "Video file not found: " << filename << std::endl; } - + } else if (hasEnding(filename, ".png") || hasEnding(filename, ".jpg") || hasEnding(filename, ".gif")) { if (fileExists(filename.c_str())) { frame = cv::imread( filename ); - + detectandshow( &alpr, frame, "", outputJson); } else { std::cerr << "Image file not found: " << filename << std::endl; } - - + + } else if (DirectoryExists(filename.c_str())) { std::vector files = getFilesInDir(filename.c_str()); - + std::sort( files.begin(), files.end(), stringCompare ); - + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png")) @@ -203,7 +203,7 @@ //cv::waitKey(50); } } - + } } else @@ -211,28 +211,28 @@ std::cerr << "Unknown file type" << std::endl; return 1; } - - + + return 0; } - + bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson) { - + std::vector buffer; cv::imencode(".bmp", frame, buffer ); - - + + timespec startTime; getTime(&startTime); - - + + std::vector results = alpr->recognize(buffer); - - + + if (writeJson) { std::cout << alpr->toJson(results) << std::endl; @@ -242,12 +242,12 @@ 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; } - + } } @@ -255,14 +255,10 @@ 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; - + } - - - - diff --git a/src/misc_utilities/CMakeLists.txt b/src/misc_utilities/CMakeLists.txt index f2786b9..3151749 100644 --- a/src/misc_utilities/CMakeLists.txt +++ b/src/misc_utilities/CMakeLists.txt @@ -4,35 +4,33 @@ target_link_libraries(openalpr) ADD_EXECUTABLE( sortstate sortstate.cpp ) -TARGET_LINK_LIBRARIES(sortstate +TARGET_LINK_LIBRARIES(sortstate openalpr support - ${OpenCV_LIBS} + ${OpenCV_LIBS} tesseract ) - + ADD_EXECUTABLE( classifychars classifychars.cpp ) -TARGET_LINK_LIBRARIES(classifychars +TARGET_LINK_LIBRARIES(classifychars openalpr support - ${OpenCV_LIBS} + ${OpenCV_LIBS} tesseract ) - - + + ADD_EXECUTABLE( benchmark benchmark.cpp ) -TARGET_LINK_LIBRARIES(benchmark +TARGET_LINK_LIBRARIES(benchmark openalpr support - ${OpenCV_LIBS} + ${OpenCV_LIBS} tesseract ) - - + + ADD_EXECUTABLE( prepcharsfortraining prepcharsfortraining.cpp ) -TARGET_LINK_LIBRARIES(prepcharsfortraining +TARGET_LINK_LIBRARIES(prepcharsfortraining support - ${OpenCV_LIBS} + ${OpenCV_LIBS} ) - - \ No newline at end of file diff --git a/src/misc_utilities/benchmark.cpp b/src/misc_utilities/benchmark.cpp index 364dbfc..909775b 100644 --- a/src/misc_utilities/benchmark.cpp +++ b/src/misc_utilities/benchmark.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -39,9 +39,9 @@ // Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters. // These will be used to train the OCR - + void outputStats(vector datapoints); - + int main( int argc, const char** argv ) { string country; @@ -49,8 +49,8 @@ int main( int argc, const char** argv ) string inDir; string outDir; Mat frame; - - + + //Check if user specify image to process if(argc == 5) { @@ -58,17 +58,17 @@ int main( int argc, const char** argv ) benchmarkName = argv[2]; inDir = argv[3]; outDir = argv[4]; - - + + }else{ printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]); printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]); printf("\n"); printf("\ttest names are: speed, segocr, detection\n\n" ); return 0; - } - - + } + + if (DirectoryExists(inDir.c_str()) == false) { printf("Input dir does not exist\n"); @@ -79,20 +79,20 @@ int main( int argc, const char** argv ) printf("Output dir does not exist\n"); return 0; } - - + + vector files = getFilesInDir(inDir.c_str()); sort( files.begin(), files.end(), stringCompare ); - - + + if (benchmarkName.compare("segocr") == 0) { - Config* config = new Config(country); + Config* config = new Config(country); config->debugOff(); - + OCR* ocr = new OCR(config); - - + + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) @@ -101,51 +101,51 @@ int main( int argc, const char** argv ) frame = imread( fullpath.c_str() ); resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); - + Rect plateCoords; plateCoords.x = 0; plateCoords.y = 0; plateCoords.width = frame.cols; plateCoords.height = frame.rows; - + char statecode[3]; statecode[0] = files[i][0]; statecode[1] = files[i][1]; statecode[2] = '\0'; string statecodestr(statecode); - + CharacterRegion charRegion(frame, config); - + if (abs(charRegion.getTopLine().angle) > 4) { // Rotate image: Mat rotated(frame.size(), frame.type()); Mat rot_mat( 2, 3, CV_32FC1 ); Point center = Point( frame.cols/2, frame.rows/2 ); - + rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 ); warpAffine( frame, rotated, rot_mat, frame.size() ); - + rotated.copyTo(frame); } - - + + CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config); ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters); ocr->postProcessor->analyze(statecode, 25); - + cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl; - + imshow("Current LP", frame); waitKey(5); - - + + } - + } - + delete config; delete ocr; } @@ -153,42 +153,42 @@ int main( int argc, const char** argv ) { Config config(country); RegionDetector plateDetector(&config); - + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) { string fullpath = inDir + "/" + files[i]; frame = imread( fullpath.c_str() ); - + vector regions = plateDetector.detect(frame); - + imshow("Current LP", frame); waitKey(5); - - + + } - + } } else if (benchmarkName.compare("speed") == 0) { // Benchmarks speed of region detection, plate analysis, and OCR - + timespec startTime; timespec endTime; - + Config config(country); config.debugOff(); - + AlprImpl alpr(country); alpr.config->debugOff(); alpr.setDetectRegion(true); - + RegionDetector plateDetector(&config); StateIdentifier stateIdentifier(&config); OCR ocr(&config); - + vector endToEndTimes; vector regionDetectionTimes; vector stateIdTimes; @@ -196,33 +196,33 @@ int main( int argc, const char** argv ) vector lpAnalysisNegativeTimes; vector ocrTimes; vector postProcessTimes; - - + + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) { cout << "Image: " << files[i] << endl; - + string fullpath = inDir + "/" + files[i]; frame = imread( fullpath.c_str() ); - - + + getTime(&startTime); alpr.recognize(frame); getTime(&endTime); double endToEndTime = diffclock(startTime, endTime); cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl; endToEndTimes.push_back(endToEndTime); - + getTime(&startTime); vector regions = plateDetector.detect(frame); getTime(&endTime); - + double regionDetectionTime = diffclock(startTime, endTime); cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl; regionDetectionTimes.push_back(regionDetectionTime); - + for (int z = 0; z < regions.size(); z++) { getTime(&startTime); @@ -232,26 +232,26 @@ int main( int argc, const char** argv ) 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; - + 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); @@ -264,40 +264,40 @@ int main( int argc, const char** argv ) lpAnalysisNegativeTimes.push_back(analysisTime); } } - + waitKey(5); - + } - + } - + cout << endl << "---------------------" << endl; - - + + cout << "End to End Time Statistics:" << endl; outputStats(endToEndTimes); cout << endl; - + cout << "Region Detection Time Statistics:" << endl; outputStats(regionDetectionTimes); cout << endl; - + cout << "State ID Time Statistics:" << endl; outputStats(stateIdTimes); cout << endl; - + cout << "Positive Region Analysis Time Statistics:" << endl; outputStats(lpAnalysisPositiveTimes); cout << endl; - + cout << "Negative Region Analysis Time Statistics:" << endl; outputStats(lpAnalysisNegativeTimes); cout << endl; - + cout << "OCR Time Statistics:" << endl; outputStats(ocrTimes); cout << endl; - + cout << "Post Processing Time Statistics:" << endl; outputStats(postProcessTimes); cout << endl; @@ -306,41 +306,41 @@ int main( int argc, const char** argv ) { Alpr alpr(country); alpr.setDetectRegion(true); - + ofstream outputdatafile; - + outputdatafile.open("results.txt"); - + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) { string fullpath = inDir + "/" + files[i]; frame = imread( fullpath.c_str() ); - + vector buffer; imencode(".bmp", frame, buffer ); - + vector results = alpr.recognize(buffer); - + outputdatafile << files[i] << ": "; for (int z = 0; z < results.size(); z++) { outputdatafile << results[z].bestPlate.characters << ", "; } outputdatafile << endl; - + imshow("Current LP", frame); waitKey(5); - - + + } - + } - + outputdatafile.close(); } - + } void outputStats(vector datapoints) @@ -357,5 +357,3 @@ void outputStats(vector datapoints) cout << "\t" << datapoints.size() << " samples, avg: " << mean << "ms, stdev: " << stdev << endl; } - - diff --git a/src/misc_utilities/classifychars.cpp b/src/misc_utilities/classifychars.cpp index f5ce503..47c200b 100644 --- a/src/misc_utilities/classifychars.cpp +++ b/src/misc_utilities/classifychars.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -43,7 +43,7 @@ const int RIGHT_ARROW_KEY = 3; const int SPACE_KEY = 32; const int ENTER_KEY = 13; const int ESCAPE_KEY = 27; - + const int DOWN_ARROW_KEY = 1; const int UP_ARROW_KEY= 0; const int DASHBOARD_COLUMNS = 9; @@ -54,7 +54,7 @@ const int RIGHT_ARROW_KEY = 83; const int SPACE_KEY = 32; const int ENTER_KEY = 10; const int ESCAPE_KEY = 27; - + const int DOWN_ARROW_KEY = 84; const int UP_ARROW_KEY= 82; const int DASHBOARD_COLUMNS = 3; @@ -64,35 +64,35 @@ const int DASHBOARD_COLUMNS = 3; void showDashboard(vector images, vector selectedImages, int selectedIndex); vector showCharSelection(Mat image, vector charRegions, string state); - + int main( int argc, const char** argv ) { - + string inDir; string outDir; Mat frame; - - + + //Check if user specify image to process if(argc == 3) { 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; - } - - + } + + if (DirectoryExists(outDir.c_str()) == false) { printf("Output dir does not exist\n"); return 0; } - + cout << "Usage: " << endl; cout << "\tn -- Next plate" << endl; cout << "\tp -- Previous plate" << endl; @@ -104,16 +104,16 @@ int main( int argc, const char** argv ) cout << "\t<- and -> -- Cycle between characters" << endl; cout << "\t[0-9A-Z] -- Identify a character (saves the image)" << endl; cout << "\tESC/Ent/Space -- Back to plate selection" << endl; - + Config* config = new Config("eu"); OCR ocr(config); - + if (DirectoryExists(inDir.c_str())) { vector files = getFilesInDir(inDir.c_str()); - + sort( files.begin(), files.end(), stringCompare ); - + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg")) @@ -122,57 +122,57 @@ int main( int argc, const char** argv ) cout << fullpath << endl; frame = imread( fullpath.c_str() ); resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx)); - + imshow ("Original", frame); - - + + char statecode[3]; statecode[0] = files[i][0]; statecode[1] = files[i][1]; statecode[2] = '\0'; string statecodestr(statecode); - + 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 ); - + rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 ); warpAffine( frame, rotated, rot_mat, frame.size() ); - + rotated.copyTo(frame); } - + CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config); - + //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters); - + ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters); ocr.postProcessor->analyze(statecodestr, 25); cout << "OCR results: " << ocr.postProcessor->bestChars << endl; - - + + vector selectedBoxes(charSegmenter.getThresholds().size()); for (int z = 0; z < charSegmenter.getThresholds().size(); z++) selectedBoxes[z] = false; - + int curDashboardSelection = 0; - + vector humanInputs(charSegmenter.characters.size()); - + for (int z = 0; z < charSegmenter.characters.size(); z++) humanInputs[z] = ' '; - + showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0); - - - + + + char waitkey = (char) waitKey(50); - + while (waitkey != 'n' && waitkey != 'p') // Next image { if (waitkey == LEFT_ARROW_KEY) // left arrow key @@ -233,17 +233,17 @@ int main( int argc, const char** argv ) // 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; - + stringstream filename; Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]); filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i]; @@ -257,34 +257,34 @@ int main( int argc, const char** argv ) 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; - - + + } - + } } - + } void showDashboard(vector images, vector selectedImages, int selectedIndex) { vector vecCopy; - + if (selectedIndex < 0) selectedIndex = 0; if (selectedIndex >= images.size()) selectedIndex = images.size() -1; - + for (int i = 0; i < images.size(); i++) { Mat imgCopy(images[i].size(), images[i].type()); @@ -298,35 +298,35 @@ void showDashboard(vector images, vector selectedImages, int selected { rectangle(imgCopy, Point(2,2), Point(imgCopy.size().width - 2, imgCopy.size().height -2), Scalar(255, 0, 0), 1); } - + vecCopy.push_back(imgCopy); } - + Mat dashboard = drawImageDashboard(vecCopy, vecCopy[0].type(), DASHBOARD_COLUMNS); - + imshow("Selection dashboard", dashboard); } vector showCharSelection(Mat image, vector charRegions, string state) { int curCharIdx = 0; - + vector 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); - + 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 ) @@ -336,22 +336,22 @@ vector showCharSelection(Mat image, vector charRegions, string state // 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); } - + if (waitkey == ENTER_KEY) { // Save all the inputs @@ -360,11 +360,11 @@ vector showCharSelection(Mat image, vector charRegions, string state if (humanInputs[i] != (char) SPACE_KEY) cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl; } - + } - + destroyWindow("Character selector"); - - + + return humanInputs; -} \ No newline at end of file +} diff --git a/src/misc_utilities/prepcharsfortraining.cpp b/src/misc_utilities/prepcharsfortraining.cpp index 2ed31fd..6f51ce1 100644 --- a/src/misc_utilities/prepcharsfortraining.cpp +++ b/src/misc_utilities/prepcharsfortraining.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -35,89 +35,89 @@ // Also creates a box file so Tesseract can recognize it int main( int argc, const char** argv ) { - + string inDir; - - + + //Check if user specify image to process if(argc == 2) { inDir = argv[1]; - + }else{ 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; } - + cout << "Usage: " << endl; cout << "\tinputdir -- input dir for benchmark data" << endl; - - + + if (DirectoryExists(inDir.c_str())) { const int X_OFFSET = 10; const int Y_OFFSET = 10; - + const int PAGE_MARGIN_X = 70; const int PAGE_MARGIN_Y = 70; const int HORIZONTAL_RESOLUTION = 3500; - + const int TILE_WIDTH = 55; const int CHAR_HORIZ_OFFSET = 40; const int TILE_HEIGHT = 70; const int CHAR_VERT_OFFSET = 48; - + vector files = getFilesInDir(inDir.c_str()); - + 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; - + Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U); bitwise_not(bigTif, bigTif); - + stringstream boxFileOut; - + for (int i = 0; i< files.size(); i++) { int col = i % tiles_per_row; int line = i / tiles_per_row; - + 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")) { string fullpath = inDir + "/" + files[i]; cout << "Processing file: " << (i + 1) << " of " << files.size() << endl; - + char charcode = files[i][0]; - + Mat characterImg = imread(fullpath); Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type()); bitwise_not(charImgCopy, charImgCopy); - + characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows))); cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY); bitwise_not(charImgCopy, charImgCopy); - + vector > contours; - + //imshow("copy", charImgCopy); findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - + Rect tallestRect(0, 0, 0, 0); for (int c = 0; c < contours.size(); c++) { @@ -125,23 +125,23 @@ int main( int argc, const char** argv ) if (tmpRect.height > tallestRect.height) tallestRect = tmpRect; } - + //cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl; - + Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height); - - + + //cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl; Mat cropped(characterImg, cropRect); cvtColor(cropped, cropped, CV_BGR2GRAY); - + Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height); - + //cout << "1" << endl; - + 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; @@ -150,24 +150,22 @@ int main( int argc, const char** argv ) boxFileOut << charcode << " " << x1 << " " << y1 << " "; boxFileOut << x2 << " " << y2 ; boxFileOut << " 0" << endl; - + //rectangle(characterImg, tallestRect, Scalar(0, 255, 0)); //imshow("characterImg", cropped); - + waitKey(2); - - + + } - + } - - + + imwrite("combined.tif", bigTif); ofstream boxFile("combined.box", std::ios::out); boxFile << boxFileOut.str(); } - + } - - diff --git a/src/misc_utilities/sortstate.cpp b/src/misc_utilities/sortstate.cpp index d71dab3..d43fbe9 100644 --- a/src/misc_utilities/sortstate.cpp +++ b/src/misc_utilities/sortstate.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -37,42 +37,42 @@ // 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); - + int main( int argc, const char** argv ) { - + string inDir; string outDir; Mat frame; - - + + //Check if user specify image to process if(argc == 3 ) { 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; - } - + } + Config config("us"); StateIdentifier identifier(&config); - + if (DirectoryExists(outDir.c_str()) == false) { printf("Output dir does not exist\n"); return 0; } - + if (DirectoryExists(inDir.c_str())) { vector files = getFilesInDir(inDir.c_str()); - + for (int i = 0; i< files.size(); i++) { if (hasEnding(files[i], ".png")) @@ -80,26 +80,26 @@ int main( int argc, const char** argv ) string fullpath = inDir + "/" + files[i]; cout << fullpath << endl; frame = imread( fullpath.c_str() ); - + char code[4]; int confidence = identifier.recognize(frame, code); - + if (confidence <= 20) { code[0] = 'z'; code[1] = 'z'; confidence = 100; } - + //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); @@ -108,10 +108,10 @@ int main( int argc, const char** argv ) else waitKey(50); } - + } } - + } - bool detectPlate( StateIdentifier* identifier, Mat frame); \ No newline at end of file + bool detectPlate( StateIdentifier* identifier, Mat frame); diff --git a/src/openalpr/CMakeLists.txt b/src/openalpr/CMakeLists.txt index c983253..9f01fab 100644 --- a/src/openalpr/CMakeLists.txt +++ b/src/openalpr/CMakeLists.txt @@ -25,7 +25,7 @@ set(lpr_source_files cjson.c ) - + add_subdirectory(simpleini) add_subdirectory(support) @@ -35,4 +35,4 @@ add_library(openalpr ${lpr_source_files}) # Add definition for default runtime dir -add_definitions(-DDEFAULT_RUNTIME_DIR="${CMAKE_SOURCE_DIR}/../runtime_data/") \ No newline at end of file +add_definitions(-DDEFAULT_RUNTIME_DIR="${CMAKE_SOURCE_DIR}/../runtime_data/") diff --git a/src/openalpr/TRexpp.h b/src/openalpr/TRexpp.h index 8391e47..6ed6761 100644 --- a/src/openalpr/TRexpp.h +++ b/src/openalpr/TRexpp.h @@ -5,11 +5,11 @@ Copyright (C) 2003-2004 Alberto Demichelis - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be held + This software is provided 'as-is', without any express + or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for + Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: @@ -38,28 +38,28 @@ public: TRexpp() { _exp = (TRex *)0; } ~TRexpp() { CleanUp(); } // compiles a regular expression - void Compile(const TRexChar *pattern) { + 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; + 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; + 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 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; + TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False; if(res) { *out_begin = match.begin; *out_len = match.len; @@ -72,4 +72,4 @@ private: void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; } TRex *_exp; }; -#endif //_TREXPP_H_ \ No newline at end of file +#endif //_TREXPP_H_ diff --git a/src/openalpr/alpr.cpp b/src/openalpr/alpr.cpp index 074d992..c5e2c9e 100644 --- a/src/openalpr/alpr.cpp +++ b/src/openalpr/alpr.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -24,7 +24,7 @@ // ALPR code - + Alpr::Alpr(const std::string country, const std::string runtimeDir) { impl = new AlprImpl(country, runtimeDir); @@ -37,7 +37,7 @@ std::vector Alpr::recognize(std::string filepath) { cv::Mat img = cv::imread(filepath, CV_LOAD_IMAGE_COLOR); return impl->recognize(img); - + } @@ -45,7 +45,7 @@ std::vector Alpr::recognize(std::vector imageBuffer) { // Not sure if this actually works cv::Mat img = cv::imdecode(Mat(imageBuffer), 1); - + return impl->recognize(img); } diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h index 74e8939..69db91f 100644 --- a/src/openalpr/alpr.h +++ b/src/openalpr/alpr.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -30,7 +30,7 @@ struct AlprPlate { std::string characters; float overall_confidence; - + bool matches_template; //int char_confidence[]; }; @@ -46,16 +46,16 @@ class AlprResult public: AlprResult(); virtual ~AlprResult(); - + int requested_topn; int result_count; - + AlprPlate bestPlate; std::vector topNPlates; - + float processing_time_ms; AlprCoordinate plate_points[4]; - + int regionConfidence; std::string region; }; @@ -73,16 +73,16 @@ class Alpr void setDetectRegion(bool detectRegion); void setTopN(int topN); void setDefaultRegion(std::string region); - + std::vector recognize(std::string filepath); std::vector recognize(std::vector imageBuffer); - + std::string toJson(const std::vector results); - + bool isLoaded(); - + private: AlprImpl* impl; }; -#endif // APLR_H \ No newline at end of file +#endif // APLR_H diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index 2eee2d8..1bab02a 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -26,32 +26,32 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir) plateDetector = new RegionDetector(config); stateIdentifier = new StateIdentifier(config); ocr = new OCR(config); - + this->detectRegion = DEFAULT_DETECT_REGION; this->topN = DEFAULT_TOPN; this->defaultRegion = ""; - + if (config->opencl_enabled) { - + cv::ocl::PlatformsInfo platinfo; cv::ocl::getOpenCLPlatforms(platinfo); - + for (int i = 0; i < platinfo.size(); i++) { std::cout << platinfo[i]->platformName << std::endl; } - + cv::ocl::DevicesInfo devices; cv::ocl::getOpenCLDevices(devices, cv::ocl::CVCL_DEVICE_TYPE_CPU); - + for (int i = 0; i < devices.size(); i++) std:: cout << devices[i]->deviceName << std::endl; - + if (devices.size() > 0) { cv::ocl::setDevice(devices[0]); - + cout << "Using OpenCL Device: " << devices[0]->deviceName << endl; } else @@ -73,9 +73,9 @@ std::vector AlprImpl::recognize(cv::Mat img) { timespec startTime; getTime(&startTime); - + vector response; - + vector plateRegions = plateDetector->detect(img); @@ -86,24 +86,24 @@ std::vector AlprImpl::recognize(cv::Mat img) { timespec platestarttime; getTime(&platestarttime); - + LicensePlateCandidate lp(img, plateRegions[i], config); - + lp.recognize(); - + if (lp.confidence > 10) { 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]; @@ -113,26 +113,26 @@ std::vector AlprImpl::recognize(cv::Mat img) plateResult.region = statecode; } } - - + + ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); - + ocr->postProcessor->analyze(plateResult.region, topN); //plateResult.characters = ocr->postProcessor->bestChars; const vector 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) { @@ -144,32 +144,32 @@ std::vector AlprImpl::recognize(cv::Mat img) } } 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) @@ -178,7 +178,7 @@ std::vector AlprImpl::recognize(cv::Mat img) getTime(&endTime); cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << endl; } - + if (config->debugGeneral && config->debugShowImages) { displayImage(config, "Main Image", img); @@ -191,21 +191,21 @@ std::vector AlprImpl::recognize(cv::Mat img) string AlprImpl::toJson(const vector< AlprResult > results) { - cJSON *root = cJSON_CreateArray(); - + cJSON *root = cJSON_CreateArray(); + for (int i = 0; i < results.size(); i++) { cJSON *resultObj = createJsonObj( &results[i] ); cJSON_AddItemToArray(root, resultObj); } - + // Print the JSON object to a string and return char *out; out=cJSON_PrintUnformatted(root); cJSON_Delete(root); - + string response(out); - + free(out); return response; } @@ -215,18 +215,18 @@ string AlprImpl::toJson(const vector< AlprResult > results) cJSON* AlprImpl::createJsonObj(const AlprResult* result) { cJSON *root, *coords, *candidates; - - root=cJSON_CreateObject(); - + + root=cJSON_CreateObject(); + cJSON_AddStringToObject(root,"plate", result->bestPlate.characters.c_str()); cJSON_AddNumberToObject(root,"confidence", result->bestPlate.overall_confidence); cJSON_AddNumberToObject(root,"matches_template", result->bestPlate.matches_template); - + cJSON_AddStringToObject(root,"region", result->region.c_str()); cJSON_AddNumberToObject(root,"region_confidence", result->regionConfidence); - + cJSON_AddNumberToObject(root,"processing_time_ms", result->processing_time_ms); - + cJSON_AddItemToObject(root, "coordinates", coords=cJSON_CreateArray()); for (int i=0;i<4;i++) { @@ -237,8 +237,8 @@ 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++) { @@ -250,7 +250,7 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result) cJSON_AddItemToArray(candidates, candidate_object); } - + return root; } @@ -267,4 +267,3 @@ void AlprImpl::setDefaultRegion(string region) { this->defaultRegion = region; } - diff --git a/src/openalpr/alpr_impl.h b/src/openalpr/alpr_impl.h index 9960901..a8ce479 100644 --- a/src/openalpr/alpr_impl.h +++ b/src/openalpr/alpr_impl.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -34,7 +34,7 @@ #include #include "opencv2/ocl/ocl.hpp" - + #define DEFAULT_TOPN 25 @@ -48,28 +48,28 @@ class AlprImpl virtual ~AlprImpl(); std::vector recognize(cv::Mat img); - + void applyRegionTemplate(AlprResult* result, std::string region); - + void setDetectRegion(bool detectRegion); void setTopN(int topn); void setDefaultRegion(string region); - + std::string toJson(const vector results); - + Config* config; - + private: - + RegionDetector* plateDetector; StateIdentifier* stateIdentifier; OCR* ocr; - + int topN; bool detectRegion; std::string defaultRegion; - + cJSON* createJsonObj(const AlprResult* result); }; -#endif // ALPRIMPL_H \ No newline at end of file +#endif // ALPRIMPL_H diff --git a/src/openalpr/binarize_wolf.cpp b/src/openalpr/binarize_wolf.cpp index c5ecb84..a80fe7e 100644 --- a/src/openalpr/binarize_wolf.cpp +++ b/src/openalpr/binarize_wolf.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -54,7 +54,7 @@ float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) { max_s = 0; - for (int j = y_firstth ; j<=y_lastth; j++) + for (int j = y_firstth ; j<=y_lastth; j++) { // Calculate the initial window at the beginning of the line sum = sum_sq = 0; @@ -91,7 +91,7 @@ float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) { map_s.fset(i+wxh, j, s); } } - + return max_s; } @@ -103,9 +103,9 @@ float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) { void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, int winx, int winy, float k) { - + float dR = BINARIZEWOLF_DEFAULTDR; - + float m, s, max_s; float th=0; double min_I, max_I; @@ -121,11 +121,11 @@ void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, 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); - + Mat thsurf (im.rows, im.cols, CV_32F); - + // Create the threshold surface, including border processing // ---------------------------------------------------- @@ -151,12 +151,12 @@ void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, case WOLFJOLION: th = m + k * (s/max_s-1) * (m-min_I); break; - + default: cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n"; exit (1); } - + thsurf.fset(i+wxh,j,th); if (i==0) { @@ -205,10 +205,10 @@ void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, thsurf.fset(i,u,th); } - - - for (int y=0; y= thsurf.fget(x,y)) { diff --git a/src/openalpr/binarize_wolf.h b/src/openalpr/binarize_wolf.h index 73c0491..fae86e0 100644 --- a/src/openalpr/binarize_wolf.h +++ b/src/openalpr/binarize_wolf.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -30,7 +30,7 @@ using namespace std; using namespace cv; -enum NiblackVersion +enum NiblackVersion { NIBLACK=0, SAUVOLA, @@ -53,4 +53,4 @@ void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version, -#endif // BINARIZEWOLF_H \ No newline at end of file +#endif // BINARIZEWOLF_H diff --git a/src/openalpr/characteranalysis.cpp b/src/openalpr/characteranalysis.cpp index 08da0a5..c15a112 100644 --- a/src/openalpr/characteranalysis.cpp +++ b/src/openalpr/characteranalysis.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,13 +23,13 @@ CharacterAnalysis::CharacterAnalysis(Mat img, Config* config) { this->config = config; - + this->hasPlateMask = false; - + if (this->config->debugCharAnalysis) cout << "Starting CharacterAnalysis identification" << endl; - - + + if (img.type() != CV_8U) cvtColor( img, this->img_gray, CV_BGR2GRAY ); else @@ -54,7 +54,7 @@ CharacterAnalysis::~CharacterAnalysis() void CharacterAnalysis::analyze() { - + thresholds = produceThresholds(img_gray, config); @@ -69,20 +69,20 @@ void CharacterAnalysis::analyze() //morphologyEx( mask, mask, MORPH_CLOSE, element ); morphologyEx( thresholds[i], thresholds[i], MORPH_OPEN, element ); //dilate( thresholds[i], thresholds[i], element ); - + } */ timespec startTime; getTime(&startTime); - - + + for (int i = 0; i < thresholds.size(); i++) { vector > contours; vector hierarchy; - + Mat tempThreshold(thresholds[i].size(), CV_8U); thresholds[i].copyTo(tempThreshold); findContours(tempThreshold, @@ -90,13 +90,13 @@ void CharacterAnalysis::analyze() hierarchy, CV_RETR_TREE, // retrieve all contours CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours - + allContours.push_back(contours); allHierarchy.push_back(hierarchy); } - - + + if (config->debugTiming) { @@ -105,28 +105,28 @@ void CharacterAnalysis::analyze() cout << " -- Character Analysis Find Contours Time: " << diffclock(startTime, endTime) << "ms." << endl; } //Mat img_equalized = equalizeBrightness(img_gray); - - + + getTime(&startTime); - + for (int i = 0; i < thresholds.size(); i++) { vector goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]); charSegments.push_back(goodIndices); - + if (config->debugCharAnalysis) cout << "Threshold " << i << " had " << getGoodIndicesCount(goodIndices) << " good indices." << endl; } - + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Analysis Filter Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - - + + + this->plateMask = findOuterBoxMask(); if (hasPlateMask) @@ -137,19 +137,19 @@ void CharacterAnalysis::analyze() charSegments[i] = filterByOuterMask(allContours[i], allHierarchy[i], charSegments[i]); } } - + int bestFitScore = -1; int bestFitIndex = -1; for (int i = 0; i < thresholds.size(); i++) { - + //vector goodIndices = this->filter(thresholds[i], allContours[i], allHierarchy[i]); //charSegments.push_back(goodIndices); - + int segmentCount = getGoodIndicesCount(charSegments[i]); - - + + if (segmentCount > bestFitScore) { bestFitScore = segmentCount; @@ -161,52 +161,52 @@ void CharacterAnalysis::analyze() bestCharSegmentsCount = segmentCount; } } - + if (this->config->debugCharAnalysis) cout << "Best fit score: " << bestFitScore << " Index: " << bestFitIndex << endl; - - + + if (bestFitScore <= 1) return; - - + + //getColorMask(img, allContours, allHierarchy, charSegments); - + if (this->config->debugCharAnalysis) { - + Mat img_contours(bestThreshold.size(), CV_8U); bestThreshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); - + vector > allowedContours; for (int i = 0; i < bestContours.size(); i++) { if (bestCharSegments[i]) allowedContours.push_back(bestContours[i]); } - + drawContours(img_contours, bestContours, -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 - - + + 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)); - - + + this->linePolygon = getBestVotedLines(img_gray, bestContours, bestCharSegments); - + if (this->linePolygon.size() > 0) { this->topLine = LineSegment(this->linePolygon[0].x, this->linePolygon[0].y, this->linePolygon[1].x, this->linePolygon[1].y); @@ -215,22 +215,22 @@ void CharacterAnalysis::analyze() filterBetweenLines(bestThreshold, bestContours, bestHierarchy, linePolygon, bestCharSegments); this->charArea = getCharArea(); - + if (this->charArea.size() > 0) { this->charBoxTop = LineSegment(this->charArea[0].x, this->charArea[0].y, this->charArea[1].x, this->charArea[1].y); this->charBoxBottom = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[2].x, this->charArea[2].y); this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y); this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y); - - + + } } - - this->thresholdsInverted = isPlateInverted(); - - + this->thresholdsInverted = isPlateInverted(); + + + } int CharacterAnalysis::getGoodIndicesCount(vector goodIndices) @@ -241,7 +241,7 @@ int CharacterAnalysis::getGoodIndicesCount(vector goodIndices) if (goodIndices[i]) count++; } - + return count; } @@ -250,43 +250,43 @@ int CharacterAnalysis::getGoodIndicesCount(vector goodIndices) Mat CharacterAnalysis::findOuterBoxMask() { double min_parent_area = config->templateHeightPx * config->templateWidthPx * 0.10; // Needs to be at least 10% of the plate area to be considered. - + int winningIndex = -1; int winningParentId = -1; int bestCharCount = 0; double lowestArea = 99999999999999; - - + + if (this->config->debugCharAnalysis) cout << "CharacterAnalysis::findOuterBoxMask" << endl; - + for (int imgIndex = 0; imgIndex < allContours.size(); imgIndex++) { //vector charContours = filter(thresholds[imgIndex], allContours[imgIndex], allHierarchy[imgIndex]); - + int charsRecognized = 0; int parentId = -1; bool hasParent = false; - for (int i = 0; i < charSegments[imgIndex].size(); i++) - { - if (charSegments[imgIndex][i]) charsRecognized++; + for (int i = 0; i < charSegments[imgIndex].size(); i++) + { + if (charSegments[imgIndex][i]) charsRecognized++; if (charSegments[imgIndex][i] && allHierarchy[imgIndex][i][3] != -1) { parentId = allHierarchy[imgIndex][i][3]; hasParent = true; } } - + if (charsRecognized == 0) continue; - + if (hasParent) { double boxArea = contourArea(allContours[imgIndex][parentId]); if (boxArea < min_parent_area) continue; - - if ((charsRecognized > bestCharCount) || + + if ((charsRecognized > bestCharCount) || (charsRecognized == bestCharCount && boxArea < lowestArea)) //(boxArea < lowestArea) { @@ -296,16 +296,16 @@ Mat CharacterAnalysis::findOuterBoxMask() lowestArea = boxArea; } } - - + + } - + if (this->config->debugCharAnalysis) cout << "Winning image index is: " << winningIndex << endl; - - - - + + + + if (winningIndex != -1 && bestCharCount >= 3) { int longestChildIndex = -1; @@ -326,24 +326,24 @@ Mat CharacterAnalysis::findOuterBoxMask() } } } - - - - + + + + Mat mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U); - + // get rid of the outline by drawing a 1 pixel width black line drawContours(mask, allContours[winningIndex], winningParentId, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, allHierarchy[winningIndex], 0 - ); - - + ); + + // Morph Open the mask to get rid of any little connectors to non-plate portions int morph_elem = 2; int morph_size = 3; @@ -351,17 +351,17 @@ Mat CharacterAnalysis::findOuterBoxMask() //morphologyEx( mask, mask, MORPH_CLOSE, element ); morphologyEx( mask, mask, MORPH_OPEN, element ); - + //morph_size = 1; //element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); //dilate(mask, mask, element); - - - // Drawing the edge black effectively erodes the image. This may clip off some extra junk from the edges. + + + // Drawing the edge black effectively erodes the image. This may clip off some extra junk from the edges. // We'll want to do the contour again and find the larges one so that we remove the clipped portion. - + vector > contoursSecondRound; - + findContours(mask, contoursSecondRound, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); int biggestContourIndex = -1; double largestArea = 0; @@ -374,91 +374,91 @@ Mat CharacterAnalysis::findOuterBoxMask() largestArea = area; } } - + if (biggestContourIndex != -1) { mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U); - + vector smoothedMaskPoints; approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true); - + vector > tempvec; tempvec.push_back(smoothedMaskPoints); //fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255)); drawContours(mask, tempvec, 0, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, allHierarchy[winningIndex], 0 - ); - - - + ); + + + } - + if (this->config->debugCharAnalysis) { vector debugImgs; Mat debugImgMasked = Mat::zeros(thresholds[winningIndex].size(), CV_8U); - + thresholds[winningIndex].copyTo(debugImgMasked, mask); - + debugImgs.push_back(mask); debugImgs.push_back(thresholds[winningIndex]); debugImgs.push_back(debugImgMasked); - + Mat dashboard = drawImageDashboard(debugImgs, CV_8U, 1); displayImage(config, "Winning outer box", dashboard); } - + hasPlateMask = true; return mask; } - + hasPlateMask = false; Mat fullMask = Mat::zeros(thresholds[0].size(), CV_8U); bitwise_not(fullMask, fullMask); return fullMask; - - - + + + } Mat CharacterAnalysis::getCharacterMask() { - + Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U); - + for (int i = 0; i < bestContours.size(); i++) { if (bestCharSegments[i] == false) continue; - - + + drawContours(charMask, bestContours, i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, bestHierarchy, 1 - ); - + ); + // get rid of the outline by drawing a 1 pixel width black line drawContours(charMask, bestContours, i, // draw this contour - cv::Scalar(0,0,0), // in - 1, - 8, + cv::Scalar(0,0,0), // in + 1, + 8, bestHierarchy, 1 - ); + ); } - - + + return charMask; } @@ -467,21 +467,21 @@ Mat CharacterAnalysis::getCharacterMask() // Returns a polygon "stripe" across the width of the character region. The lines are voted and the polygon starts at 0 and extends to image width vector CharacterAnalysis::getBestVotedLines(Mat img, vector > contours, vector goodIndices) { - + //if (this->debug) // cout << "CharacterAnalysis::getBestVotedLines" << endl; - + vector bestStripe; - + vector charRegions; - + for (int i = 0; i < contours.size(); i++) { if (goodIndices[i]) charRegions.push_back(boundingRect(contours[i])); } - - + + // Find the best fit line segment that is parallel with the most char segments if (charRegions.size() <= 1) { @@ -498,8 +498,8 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector { //Mat tempImg; //result.copyTo(tempImg); - - + + Rect* leftRect; Rect* rightRect; if (charRegions[i].x < charRegions[k].x) @@ -512,12 +512,12 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector leftRect = &charRegions[k]; rightRect = &charRegions[i]; } - + //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2); //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2); - + int x1, y1, x2, y2; - + if (leftRect->y > rightRect->y) // Rising line, use the top left corner of the rect { x1 = leftRect->x; @@ -530,10 +530,10 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector } y1 = leftRect->y; y2 = rightRect->y; - + //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); topLines.push_back(LineSegment(x1, y1, x2, y2)); - + if (leftRect->y > rightRect->y) // Rising line, use the bottom right corner of the rect { @@ -547,32 +547,32 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector } y1 = leftRect->y + leftRect->height; y2 = rightRect->y + leftRect->height; - + //cv::line(tempImg, Point(x1, y1), Point(x2, y2), Scalar(0, 0, 255)); bottomLines.push_back(LineSegment(x1, y1, x2, y2)); - + //drawAndWait(&tempImg); } } - + int bestScoreIndex = 0; int bestScore = -1; int bestScoreDistance = -1; // Line segment distance is used as a tie breaker - + // Now, among all possible lines, find the one that is the best fit - for (int i = 0; i < topLines.size(); i++) + for (int i = 0; i < topLines.size(); i++) { float SCORING_MIN_THRESHOLD = 0.97; float SCORING_MAX_THRESHOLD = 1.03; - - + + int curScore = 0; for (int charidx = 0; charidx < charRegions.size(); charidx++) { float topYPos = topLines[i].getPointAt(charRegions[charidx].x); float botYPos = bottomLines[i].getPointAt(charRegions[charidx].x); - + float minTop = charRegions[charidx].y * SCORING_MIN_THRESHOLD; float maxTop = charRegions[charidx].y * SCORING_MAX_THRESHOLD; float minBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MIN_THRESHOLD; @@ -582,15 +582,15 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector { curScore++; } - + //cout << "Slope: " << topslope << " yPos: " << topYPos << endl; //drawAndWait(&tempImg); - + } - - + + // Tie goes to the one with longer line segments - if ((curScore > bestScore) || + if ((curScore > bestScore) || (curScore == bestScore && topLines[i].length > bestScoreDistance)) { bestScore = curScore; @@ -599,38 +599,38 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector bestScoreDistance = topLines[i].length; } } - - + + if (this->config->debugCharAnalysis) { cout << "The winning score is: " << bestScore << endl; // Draw the winning line segment //Mat tempImg; - //result.copyTo(tempImg); + //result.copyTo(tempImg); //cv::line(tempImg, topLines[bestScoreIndex].p1, topLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); //cv::line(tempImg, bottomLines[bestScoreIndex].p1, bottomLines[bestScoreIndex].p2, Scalar(0, 0, 255), 2); //displayImage(config, "Lines", tempImg); } - + //winningLines.push_back(topLines[bestScoreIndex]); //winningLines.push_back(bottomLines[bestScoreIndex]); - + Point topLeft = Point(0, topLines[bestScoreIndex].getPointAt(0) ); Point topRight = Point(img.cols, topLines[bestScoreIndex].getPointAt(img.cols)); Point bottomRight = Point(img.cols, bottomLines[bestScoreIndex].getPointAt(img.cols)); Point bottomLeft = Point(0, bottomLines[bestScoreIndex].getPointAt(0)); - - + + bestStripe.push_back(topLeft); bestStripe.push_back(topRight); bestStripe.push_back(bottomRight); bestStripe.push_back(bottomLeft); - - + + } - - + + return bestStripe; } @@ -643,24 +643,24 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, static int HEIGHT_STEP = round (((float) img.rows) * config->charAnalysisHeightStepSize); static int NUM_STEPS = config->charAnalysisNumSteps; - + vector charSegments; int bestFitScore = -1; for (int i = 0; i < NUM_STEPS; i++) { int goodIndicesCount; - + vector goodIndices(contours.size()); for (int z = 0; z < goodIndices.size(); z++) goodIndices[z] = true; - + goodIndices = this->filterByBoxSize(contours, goodIndices, STARTING_MIN_HEIGHT + (i * HEIGHT_STEP), STARTING_MAX_HEIGHT + (i * HEIGHT_STEP)); - - + + goodIndicesCount = getGoodIndicesCount(goodIndices); if ( goodIndicesCount > 0 && goodIndicesCount <= bestFitScore) // Don't bother doing more filtering if we already lost... continue; goodIndices = this->filterContourHoles(contours, hierarchy, goodIndices); - + goodIndicesCount = getGoodIndicesCount(goodIndices); if ( goodIndicesCount > 0 && goodIndicesCount <= bestFitScore) // Don't bother doing more filtering if we already lost... continue; @@ -668,17 +668,17 @@ vector CharacterAnalysis::filter(Mat img, vector > contours, vector lines = getBestVotedLines(img, contours, goodIndices); goodIndices = this->filterBetweenLines(img, contours, hierarchy, lines, goodIndices); - + int segmentCount = getGoodIndicesCount(goodIndices); - + if (segmentCount > bestFitScore) { bestFitScore = segmentCount; charSegments = goodIndices; } } - - + + return charSegments; } @@ -689,34 +689,34 @@ vector CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contour float idealAspect=config->charWidthMM / config->charHeightMM; float aspecttolerance=0.25; - - + + vector includedIndices(contours.size()); for (int j = 0; j < contours.size(); j++) includedIndices.push_back(false); - + for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; - + //Create bounding rect of object Rect mr= boundingRect(contours[i]); - + float minWidth = mr.height * 0.2; //Crop image //Mat auxRoi(img, mr); if(mr.height >= minHeightPx && mr.height <= maxHeightPx && mr.width > minWidth){ - + float charAspect= (float)mr.width/(float)mr.height; - - if (abs(charAspect - idealAspect) < aspecttolerance) + + if (abs(charAspect - idealAspect) < aspecttolerance) includedIndices[i] = true; } } - + return includedIndices; - + } @@ -727,20 +727,20 @@ vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > c vector includedIndices(contours.size()); for (int j = 0; j < contours.size(); j++) includedIndices.push_back(false); - + for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; - + int parentIndex = hierarchy[i][3]; - + if (parentIndex >= 0 && goodIndices[parentIndex] == true) { // this contour is a child of an already identified contour. REMOVE it if (this->config->debugCharAnalysis) { - cout << "filterContourHoles: contour index: " << i << endl; + cout << "filterContourHoles: contour index: " << i << endl; } } else @@ -748,7 +748,7 @@ vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > c includedIndices[i] = true; } } - + return includedIndices; } @@ -757,19 +757,19 @@ vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > c // returns a vector of indices corresponding to valid contours vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > contours, vector hierarchy, vector goodIndices) { - + vector includedIndices(contours.size()); for (int j = 0; j < contours.size(); j++) includedIndices[j] = false; - + vector parentIDs; vector votes; - + for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; - + int voteIndex = -1; int parentID = hierarchy[i][3]; // check if parentID is already in the lsit @@ -790,9 +790,9 @@ vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > { votes[voteIndex] = votes[voteIndex] + 1; } - + } - + // Tally up the votes, pick the winner int totalVotes = 0; int winningParentId = 0; @@ -806,13 +806,13 @@ vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > } totalVotes += votes[i]; } - + // Now filter out all the contours with a different parent ID (assuming the totalVotes > 2) for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; - + if (totalVotes <= 2) { includedIndices[i] = true; @@ -822,7 +822,7 @@ vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > includedIndices[i] = true; } } - + return includedIndices; } @@ -830,21 +830,21 @@ vector CharacterAnalysis::filterByParentContour( vector< vector< Point> > vector CharacterAnalysis::filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices) { static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88; - + vector includedIndices(contours.size()); for (int j = 0; j < contours.size(); j++) includedIndices[j] = false; - - + + if (outerPolygon.size() == 0) return includedIndices; - + vector validPoints; - + // Figure out the line height LineSegment topLine(outerPolygon[0].x, outerPolygon[0].y, outerPolygon[1].x, outerPolygon[1].y); LineSegment bottomLine(outerPolygon[3].x, outerPolygon[3].y, outerPolygon[2].x, outerPolygon[2].y); - + float x = ((float) img.cols) / 2; Point midpoint = Point(x, bottomLine.getPointAt(x)); Point acrossFromMidpoint = topLine.closestPointOnSegmentTo(midpoint); @@ -854,50 +854,50 @@ vector CharacterAnalysis::filterBetweenLines(Mat img, vector Mat outerMask = Mat::zeros(img.size(), CV_8U); Mat innerArea = Mat::zeros(img.size(), CV_8U); fillConvexPoly(outerMask, outerPolygon.data(), outerPolygon.size(), Scalar(255,255,255)); - - + + for (int i = 0; i < contours.size(); i++) { if (goodIndices[i] == false) continue; - + // get rid of the outline by drawing a 1 pixel width black line drawContours(innerArea, contours, i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, + cv::Scalar(255,255,255), // in + CV_FILLED, + 8, hierarchy, 0 - ); - - + ); + + bitwise_and(innerArea, outerMask, innerArea); - - + + vector > tempContours; findContours(innerArea, tempContours, CV_RETR_EXTERNAL, // retrieve the external contours CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours ); - + double totalArea = contourArea(contours[i]); double areaBetweenLines = 0; - + for (int tempContourIdx = 0; tempContourIdx < tempContours.size(); tempContourIdx++) { areaBetweenLines += contourArea(tempContours[tempContourIdx]); - + } - - + + if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES) { includedIndices[i] = true; } - + innerArea.setTo(Scalar(0,0,0)); } - + return includedIndices; } @@ -905,69 +905,69 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > { float MINIMUM_PERCENT_LEFT_AFTER_MASK = 0.1; float MINIMUM_PERCENT_OF_CHARS_INSIDE_PLATE_MASK = 0.6; - + if (hasPlateMask == false) return goodIndices; - - + + vector passingIndices; for (int i = 0; i < goodIndices.size(); i++) passingIndices.push_back(false); - + Mat tempMaskedContour = Mat::zeros(plateMask.size(), CV_8U); Mat tempFullContour = Mat::zeros(plateMask.size(), CV_8U); - + int charsInsideMask = 0; int totalChars = 0; - + for (int i=0; i < goodIndices.size(); i++) { if (goodIndices[i] == false) continue; - + totalChars++; - + drawContours(tempFullContour, contours, i, Scalar(255,255,255), CV_FILLED, 8, hierarchy); bitwise_and(tempFullContour, plateMask, tempMaskedContour); - + float beforeMaskWhiteness = mean(tempFullContour)[0]; float afterMaskWhiteness = mean(tempMaskedContour)[0]; - + if (afterMaskWhiteness / beforeMaskWhiteness > MINIMUM_PERCENT_LEFT_AFTER_MASK) { charsInsideMask++; passingIndices[i] = true; } } - + if (totalChars == 0) return goodIndices; - + // Check to make sure that this is a valid box. If the box is too small (e.g., 1 char is inside, and 3 are outside) // then don't use this to filter. float percentCharsInsideMask = ((float) charsInsideMask) / ((float) totalChars); if (percentCharsInsideMask < MINIMUM_PERCENT_OF_CHARS_INSIDE_PLATE_MASK) return goodIndices; - + return passingIndices; } - + bool CharacterAnalysis::isPlateInverted() { Mat charMask = getCharacterMask(); - + Scalar meanVal = mean(bestThreshold, charMask)[0]; - + if (this->config->debugCharAnalysis) cout << "CharacterAnalysis, plate inverted: MEAN: " << meanVal << " : " << bestThreshold.type() << endl; - - + + if (meanVal[0] < 100) // Half would be 122.5. Give it a little extra oomf before saying it needs inversion. Most states aren't inverted. return true; - + return false; } @@ -1004,15 +1004,15 @@ vector CharacterAnalysis::getCharArea() { const int MAX = 100000; const int MIN= -1; - + int leftX = MAX; int rightX = MIN; - + for (int i = 0; i < bestContours.size(); i++) { if (bestCharSegments[i] == false) continue; - + for (int z = 0; z < bestContours[i].size(); z++) { if (bestContours[i][z].x < leftX) @@ -1021,7 +1021,7 @@ vector CharacterAnalysis::getCharArea() rightX = bestContours[i][z].x; } } - + vector charArea; if (leftX != MAX && rightX != MIN) { @@ -1034,6 +1034,6 @@ vector CharacterAnalysis::getCharArea() charArea.push_back(br); charArea.push_back(bl); } - + return charArea; } diff --git a/src/openalpr/characteranalysis.h b/src/openalpr/characteranalysis.h index d60145a..4b483b8 100644 --- a/src/openalpr/characteranalysis.h +++ b/src/openalpr/characteranalysis.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -40,64 +40,62 @@ class CharacterAnalysis bool hasPlateMask; Mat plateMask; - + Mat bestThreshold; vector > bestContours; vector bestHierarchy; vector bestCharSegments; int bestCharSegmentsCount; - + LineSegment topLine; LineSegment bottomLine; vector linePolygon; vector charArea; - + LineSegment charBoxTop; LineSegment charBoxBottom; LineSegment charBoxLeft; LineSegment charBoxRight; - + bool thresholdsInverted; - + vector thresholds; vector > > allContours; vector > allHierarchy; vector > charSegments; - + void analyze(); - + Mat getCharacterMask(); - - - + + + private: Config* config; - + Mat img_gray; - + Mat findOuterBoxMask( ); - - + + bool isPlateInverted(); vector filter(Mat img, vector > contours, vector hierarchy); - + vector filterByBoxSize(vector > contours, vector goodIndices, int minHeightPx, int maxHeightPx); vector filterByParentContour( vector< vector< Point> > contours, vector hierarchy, vector goodIndices); vector filterContourHoles(vector > contours, vector hierarchy, vector goodIndices); vector filterByOuterMask(vector > contours, vector hierarchy, vector goodIndices); - + vector getCharArea(); vector getBestVotedLines(Mat img, vector > contours, vector goodIndices); //vector getCharSegmentsBetweenLines(Mat img, vector > contours, vector outerPolygon); vector filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices); - + bool verifySize(Mat r, float minHeightPx, float maxHeightPx); - + int getGoodIndicesCount(vector goodIndices); - - + + }; #endif // CHARACTERANALYSIS_H - - diff --git a/src/openalpr/characterregion.cpp b/src/openalpr/characterregion.cpp index 70515c4..9660c73 100644 --- a/src/openalpr/characterregion.cpp +++ b/src/openalpr/characterregion.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -25,22 +25,22 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) { this->config = config; this->debug = config->debugCharRegions; - + 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 tempDash; @@ -49,15 +49,15 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) Mat tmp(charAnalysis->thresholds[z].size(), charAnalysis->thresholds[z].type()); charAnalysis->thresholds[z].copyTo(tmp); cvtColor(tmp, tmp, CV_GRAY2BGR); - + tempDash.push_back(tmp); } - - + + Mat bestVal(charAnalysis->bestThreshold.size(), charAnalysis->bestThreshold.type()); charAnalysis->bestThreshold.copyTo(bestVal); cvtColor(bestVal, bestVal, CV_GRAY2BGR); - + for (int z = 0; z < charAnalysis->bestContours.size(); z++) { Scalar dcolor(255,0,0); @@ -70,73 +70,73 @@ CharacterRegion::CharacterRegion(Mat img, Config* config) } - + if (this->debug) { /* Mat img_contours(img_threshold.size(), CV_8U); img_threshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); - + vector > allowedContours; for (int i = 0; i < contours.size(); 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 - + drawContours(img_contours, allowedContours, -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) { - + int confidenceDrainers = 0; int charSegmentCount = charAnalysis->bestCharSegmentsCount; if (charSegmentCount == 1) confidenceDrainers += 91; else if (charSegmentCount < 5) confidenceDrainers += (5 - charSegmentCount) * 10; - + int absangle = abs(charAnalysis->topLine.angle); if (absangle > 10) confidenceDrainers += 91; else if (absangle > 1) confidenceDrainers += (10 - absangle) * 5; - - + + if (confidenceDrainers >= 100) this->confidence=1; else this->confidence = 100 - confidenceDrainers; - + } - - - + + + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << "Character Region Time: " << diffclock(startTime, endTime) << "ms." << endl; } - + } CharacterRegion::~CharacterRegion() @@ -150,45 +150,43 @@ Mat CharacterRegion::getPlateMask() { return charAnalysis->plateMask; } - + LineSegment CharacterRegion::getTopLine() { - return charAnalysis->topLine; + return charAnalysis->topLine; } LineSegment CharacterRegion::getBottomLine() { - return charAnalysis->bottomLine; + return charAnalysis->bottomLine; } vector 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; } - - diff --git a/src/openalpr/characterregion.h b/src/openalpr/characterregion.h index 2b71227..3a43243 100644 --- a/src/openalpr/characterregion.h +++ b/src/openalpr/characterregion.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -40,47 +40,45 @@ class CharacterRegion virtual ~CharacterRegion(); CharacterAnalysis *charAnalysis; - + int confidence; Mat getPlateMask(); - + LineSegment getTopLine(); LineSegment getBottomLine(); //vector getLinePolygon(); vector getCharArea(); - + LineSegment getCharBoxTop(); LineSegment getCharBoxBottom(); LineSegment getCharBoxLeft(); LineSegment getCharBoxRight(); - + bool thresholdsInverted(); - + protected: Config* config; bool debug; - + Mat findOuterBoxMask(vector thresholds, vector > > allContours, vector > allHierarchy); - + vector filter(Mat img, vector > contours, vector hierarchy); vector filterByBoxSize(Mat img, vector > contours, vector goodIndices, float minHeightPx, float maxHeightPx); vector filterByParentContour( vector< vector< Point> > contours, vector hierarchy, vector goodIndices); vector filterContourHoles(vector > contours, vector hierarchy, vector goodIndices); - + vector getBestVotedLines(Mat img, vector > contours, vector goodIndices); //vector getCharSegmentsBetweenLines(Mat img, vector > contours, vector outerPolygon); vector filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices); Mat getCharacterMask(Mat img, vector > contours, vector hierarchy, vector goodIndices); - + vector wrapContours(vector > contours); bool verifySize(Mat r, float minHeightPx, float maxHeightPx); - + int getGoodIndicesCount(vector goodIndices); - + bool isPlateInverted(Mat threshold, vector > contours, vector hierarchy, vector goodIndices); - + }; #endif // CHARACTERREGION_H - - diff --git a/src/openalpr/charactersegmenter.cpp b/src/openalpr/charactersegmenter.cpp index 1808892..81777eb 100644 --- a/src/openalpr/charactersegmenter.cpp +++ b/src/openalpr/charactersegmenter.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,112 +23,112 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con { this->config = config; - + this->confidence = 0; - + if (this->config->debugCharSegmenter) cout << "Starting CharacterSegmenter" << endl; - + //CharacterRegion charRegion(img, debug); - + timespec startTime; getTime(&startTime); - + Mat img_gray(img.size(), CV_8U); cvtColor( img, img_gray, CV_BGR2GRAY ); medianBlur(img_gray, img_gray, 3); - + if (invertedColors) bitwise_not(img_gray, img_gray); - - + + charAnalysis = new CharacterAnalysis(img_gray, config); charAnalysis->analyze(); - - + + if (this->config->debugCharSegmenter) { displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3)); } - - - - + + + + if (this->config->debugCharSegmenter) { - + Mat img_contours(charAnalysis->bestThreshold.size(), CV_8U); charAnalysis->bestThreshold.copyTo(img_contours); cvtColor(img_contours, img_contours, CV_GRAY2RGB); - + vector > allowedContours; for (int i = 0; i < charAnalysis->bestContours.size(); i++) { if (charAnalysis->bestCharSegments[i]) allowedContours.push_back(charAnalysis->bestContours[i]); } - + drawContours(img_contours, charAnalysis->bestContours, -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 - + if (charAnalysis->linePolygon.size() > 0) { line(img_contours, charAnalysis->linePolygon[0], charAnalysis->linePolygon[1], Scalar(255, 0, 255), 1); line(img_contours, charAnalysis->linePolygon[3], charAnalysis->linePolygon[2], Scalar(255, 0, 255), 1); } - + Mat bordered = addLabel(img_contours, "Best Contours"); imgDbgGeneral.push_back(bordered); } - - + + if (charAnalysis->linePolygon.size() > 0) { this->top = LineSegment(charAnalysis->linePolygon[0].x, charAnalysis->linePolygon[0].y, charAnalysis->linePolygon[1].x, charAnalysis->linePolygon[1].y); this->bottom = LineSegment(charAnalysis->linePolygon[3].x, charAnalysis->linePolygon[3].y, charAnalysis->linePolygon[2].x, charAnalysis->linePolygon[2].y); - + vector charWidths; vector charHeights; - + for (int i = 0; i < charAnalysis->bestContours.size(); i++) { if (charAnalysis->bestCharSegments[i] == false) continue; - - + + Rect mr = boundingRect(charAnalysis->bestContours[i]); charWidths.push_back(mr.width); charHeights.push_back(mr.height); } - + float avgCharWidth = median(charWidths.data(), charWidths.size()); float avgCharHeight = median(charHeights.data(), charHeights.size()); - + removeSmallContours(charAnalysis->thresholds, charAnalysis->allContours, avgCharWidth, avgCharHeight); - + // Do the histogram analysis to figure out char regions - - + + timespec startTime; getTime(&startTime); - + vector allHistograms; - + vector allBoxes; for (int i = 0; i < charAnalysis->allContours.size(); i++) { @@ -137,10 +137,10 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con Mat histogramMask = Mat::zeros(charAnalysis->thresholds[i].size(), CV_8U); fillConvexPoly(histogramMask, charAnalysis->linePolygon.data(), charAnalysis->linePolygon.size(), Scalar(255,255,255)); - - + + VerticalHistogram vertHistogram(charAnalysis->thresholds[i], histogramMask); - + if (this->config->debugCharSegmenter) { @@ -150,27 +150,27 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con allHistograms.push_back(histoCopy); } -// +// float score = 0; - vector charBoxes = getHistogramBoxes(vertHistogram, avgCharWidth, avgCharHeight, &score); - - + vector charBoxes = getHistogramBoxes(vertHistogram, avgCharWidth, avgCharHeight, &score); + + if (this->config->debugCharSegmenter) { for (int cboxIdx = 0; cboxIdx < charBoxes.size(); cboxIdx++) { rectangle(allHistograms[i], charBoxes[cboxIdx], Scalar(0, 255, 0)); } - + Mat histDashboard = drawImageDashboard(allHistograms, allHistograms[0].type(), 3); displayImage(config, "Char seg histograms", histDashboard); } - + for (int z = 0; z < charBoxes.size(); z++) allBoxes.push_back(charBoxes[z]); //drawAndWait(&histogramMask); } - + float medianCharWidth = avgCharWidth; vector widthValues; @@ -179,9 +179,9 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con { widthValues.push_back(allBoxes[i].width); } - + medianCharWidth = median(widthValues.data(), widthValues.size()); - + if (config->debugTiming) { @@ -189,11 +189,11 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con getTime(&endTime); cout << " -- Character Segmentation Create and Score Histograms Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - //ColorFilter colorFilter(img, charAnalysis->getCharacterMask()); + + //ColorFilter colorFilter(img, charAnalysis->getCharacterMask()); vector candidateBoxes = getBestCharBoxes(charAnalysis->thresholds[0], allBoxes, medianCharWidth); - - + + if (this->config->debugCharSegmenter) { // Setup the dashboard images to show the cleaning filters @@ -204,57 +204,57 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con charAnalysis->thresholds[i].copyTo(cleanImg); bitwise_and(cleanImg, boxMask, cleanImg); cvtColor(cleanImg, cleanImg, CV_GRAY2BGR); - + for (int c = 0; c < candidateBoxes.size(); c++) rectangle(cleanImg, candidateBoxes[c], Scalar(0, 255, 0), 1); imgDbgCleanStages.push_back(cleanImg); } } - - + + getTime(&startTime); - + filterEdgeBoxes(charAnalysis->thresholds, candidateBoxes, medianCharWidth, avgCharHeight); - + candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes); - + candidateBoxes = combineCloseBoxes(candidateBoxes, medianCharWidth); cleanCharRegions(charAnalysis->thresholds, candidateBoxes); cleanMostlyFullBoxes(charAnalysis->thresholds, candidateBoxes); - + //cleanBasedOnColor(thresholds, colorFilter.colorMask, candidateBoxes); - + candidateBoxes = filterMostlyEmptyBoxes(charAnalysis->thresholds, candidateBoxes); this->characters = candidateBoxes; - + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Character Segmentation Box cleaning/filtering Time: " << diffclock(startTime, endTime) << "ms." << endl; } - + if (this->config->debugCharSegmenter) { - - + + Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3); displayImage(config, "Segmentation after cleaning", imgDash); - + Mat generalDash = drawImageDashboard(this->imgDbgGeneral, this->imgDbgGeneral[0].type(), 2); displayImage(config, "Segmentation General", generalDash); - + Mat cleanImgDash = drawImageDashboard(this->imgDbgCleanStages, this->imgDbgCleanStages[0].type(), 3); displayImage(config, "Segmentation Clean Filters", cleanImgDash); } } - - - - - - + + + + + + if (config->debugTiming) { timespec endTime; @@ -278,23 +278,23 @@ CharacterSegmenter::~CharacterSegmenter() vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, float avgCharWidth, float avgCharHeight, float* score) { float MIN_HISTOGRAM_HEIGHT = avgCharHeight * config->segmentationMinCharHeightPercent; - + float MAX_SEGMENT_WIDTH = avgCharWidth * config->segmentationMaxCharWidthvsAverage; - + //float MIN_BOX_AREA = (avgCharWidth * avgCharHeight) * 0.25; - + int pxLeniency = 2; - + vector charBoxes; vector allBoxes = get1DHits(histogram.histoImg, pxLeniency); - + for (int i = 0; i < allBoxes.size(); i++) { - + if (allBoxes[i].width >= config->segmentationMinBoxWidthPx && allBoxes[i].width <= MAX_SEGMENT_WIDTH && allBoxes[i].height > MIN_HISTOGRAM_HEIGHT ) - { - charBoxes.push_back(allBoxes[i]); + { + charBoxes.push_back(allBoxes[i]); } else if (allBoxes[i].width > avgCharWidth * 2 && allBoxes[i].width < MAX_SEGMENT_WIDTH * 2 && allBoxes[i].height > MIN_HISTOGRAM_HEIGHT) { @@ -303,15 +303,15 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, // Try to split up doubles into two good char regions, check for a break between 40% and 60% int leftEdge = allBoxes[i].x + (int) (((float) allBoxes[i].width) * 0.4f); int rightEdge = allBoxes[i].x + (int) (((float) allBoxes[i].width) * 0.6f); - + int minX = histogram.getLocalMinimum(leftEdge, rightEdge); int maxXChar1 = histogram.getLocalMaximum(allBoxes[i].x, minX); int maxXChar2 = histogram.getLocalMaximum(minX, allBoxes[i].x + allBoxes[i].width); int minHeight = histogram.getHeightAt(minX); - + int maxHeightChar1 = histogram.getHeightAt(maxXChar1); int maxHeightChar2 = histogram.getHeightAt(maxXChar2); - + if (maxHeightChar1 > MIN_HISTOGRAM_HEIGHT && minHeight < (0.25 * ((float) maxHeightChar1))) { // Add a box for Char1 @@ -325,65 +325,65 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, charBoxes.push_back(Rect(topLeft, allBoxes[i].br()) ); } } - + } - - - + + + return charBoxes; } vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxes, float avgCharWidth) { - - + + float MAX_SEGMENT_WIDTH = avgCharWidth * 1.55; - + // This histogram is based on how many char boxes (from ALL of the many thresholded images) are covering each column // Makes a sort of histogram from all the previous char boxes. Figures out the best fit from that. - + Mat histoImg = Mat::zeros(Size(img.cols, img.rows), CV_8U); int columnCount; - + for (int col = 0; col < img.cols; col++) { columnCount = 0; - + for (int i = 0; i < charBoxes.size(); i++) { if (col >= charBoxes[i].x && col < (charBoxes[i].x + charBoxes[i].width)) columnCount++; } - + // Fill the line of the histogram for (; columnCount > 0; columnCount--) histoImg.at(histoImg.rows - columnCount, col) = 255; } - + VerticalHistogram histogram(histoImg, Mat::ones(histoImg.size(), CV_8U)); - + // Go through each row in the histoImg and score it. Try to find the single line that gives me the most right-sized character regions (based on avgCharWidth) - + int bestRowIndex = 0; float bestRowScore = 0; vector bestBoxes; - - + + for (int row = 0; row < histoImg.rows; row++) { vector validBoxes; vector allBoxes = get1DHits(histoImg, row); - + if (this->config->debugCharSegmenter) cout << "All Boxes size " << allBoxes.size() << endl; - + if (allBoxes.size() == 0) break; - + float rowScore = 0; - + for (int boxidx = 0; boxidx < allBoxes.size(); boxidx++) { int w = allBoxes[boxidx].width; @@ -391,11 +391,11 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe { float widthDiffPixels = abs(w - avgCharWidth); float widthDiffPercent = widthDiffPixels / avgCharWidth; - rowScore += 10 * (1 - widthDiffPercent); - + rowScore += 10 * (1 - widthDiffPercent); + if (widthDiffPercent < 0.25) // Bonus points when it's close to the average character width rowScore += 8; - + validBoxes.push_back(allBoxes[boxidx]); } else if (w > avgCharWidth * 2 && w <= MAX_SEGMENT_WIDTH * 2 ) @@ -403,15 +403,15 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe // Try to split up doubles into two good char regions, check for a break between 40% and 60% int leftEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.4f); int rightEdge = allBoxes[boxidx].x + (int) (((float) allBoxes[boxidx].width) * 0.6f); - + int minX = histogram.getLocalMinimum(leftEdge, rightEdge); int maxXChar1 = histogram.getLocalMaximum(allBoxes[boxidx].x, minX); int maxXChar2 = histogram.getLocalMaximum(minX, allBoxes[boxidx].x + allBoxes[boxidx].width); int minHeight = histogram.getHeightAt(minX); - + int maxHeightChar1 = histogram.getHeightAt(maxXChar1); int maxHeightChar2 = histogram.getHeightAt(maxXChar2); - + if ( minHeight < (0.25 * ((float) maxHeightChar1))) { // Add a box for Char1 @@ -426,9 +426,9 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe } } } - - - + + + if (rowScore > bestRowScore) { bestRowScore = rowScore; @@ -436,25 +436,25 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe bestBoxes = validBoxes; } } - - - + + + if (this->config->debugCharSegmenter) { cvtColor(histoImg, histoImg, CV_GRAY2BGR); line(histoImg, Point(0, histoImg.rows - 1 - bestRowIndex), Point(histoImg.cols, histoImg.rows - 1 - bestRowIndex), Scalar(0, 255, 0)); - + Mat imgBestBoxes(img.size(), img.type()); img.copyTo(imgBestBoxes); cvtColor(imgBestBoxes, imgBestBoxes, CV_GRAY2BGR); for (int i = 0; i < bestBoxes.size(); i++) rectangle(imgBestBoxes, bestBoxes[i], Scalar(0, 255, 0)); - + this->imgDbgGeneral.push_back(addLabel(histoImg, "All Histograms")); this->imgDbgGeneral.push_back(addLabel(imgBestBoxes, "Best Boxes")); } - + return bestBoxes; } @@ -462,7 +462,7 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe vector CharacterSegmenter::get1DHits(Mat img, int yOffset) { vector hits; - + bool onSegment = false; int curSegmentLength = 0; for (int col = 0; col < img.cols; col++) @@ -474,7 +474,7 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset) onSegment = true; curSegmentLength++; } - + if ((isOn == false && onSegment == true) || (col == img.cols - 1 && onSegment == true)) { @@ -482,14 +482,14 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset) Point topLeft = Point(col - curSegmentLength, top.getPointAt(col - curSegmentLength) - 1); Point botRight = Point(col, bottom.getPointAt(col) + 1); hits.push_back(Rect(topLeft, botRight)); - + onSegment = false; curSegmentLength = 0; } - + } - - + + return hits; } @@ -498,15 +498,15 @@ void CharacterSegmenter::removeSmallContours(vector thresholds, vector thresholds, vector thresholds, vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, float biggestCharWidth) { vector newCharBoxes; - + for (int i = 0; i < charBoxes.size(); i++) { if (i == charBoxes.size() - 1) @@ -531,12 +531,12 @@ vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa break; } float bigWidth = (charBoxes[i + 1].x + charBoxes[i + 1].width - charBoxes[i].x); - + float w1Diff = abs(charBoxes[i].width - biggestCharWidth); float w2Diff = abs(charBoxes[i + 1].width - biggestCharWidth); float bigDiff = abs(bigWidth - biggestCharWidth); - bigDiff *= 1.3; // Make it a little harder to merge boxes. - + bigDiff *= 1.3; // Make it a little harder to merge boxes. + if (bigDiff < w1Diff && bigDiff < w2Diff) { Rect bigRect(charBoxes[i].x, charBoxes[i].y, bigWidth, charBoxes[i].height); @@ -551,18 +551,18 @@ vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa } cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl; } - + i++; } else { newCharBoxes.push_back(charBoxes[i]); } - - - + + + } - + return newCharBoxes; } @@ -572,18 +572,18 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c const float MIN_SPECKLE_WIDTH_PX = 3; const float MIN_CONTOUR_AREA_PERCENT = 0.1; const float MIN_CONTOUR_HEIGHT_PERCENT = 0.60; - + Mat mask = getCharBoxMask(thresholds[0], charRegions); - - + + for (int i = 0; i < thresholds.size(); i++) { bitwise_and(thresholds[i], mask, thresholds[i]); vector > contours; - + Mat tempImg(thresholds[i].size(), thresholds[i].type()); thresholds[i].copyTo(tempImg); - + //Mat element = getStructuringElement( 1, // Size( 2 + 1, 2+1 ), // Point( 1, 1 ) ); @@ -592,13 +592,13 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c //drawAndWait(&tempImg); findContours(tempImg, contours, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - + for (int j = 0; j < charRegions.size(); j++) { const float MIN_SPECKLE_HEIGHT = ((float)charRegions[j].height) * MIN_SPECKLE_HEIGHT_PERCENT; const float MIN_CONTOUR_AREA = ((float)charRegions[j].area()) * MIN_CONTOUR_AREA_PERCENT; - - + + int tallestContourHeight = 0; float totalArea = 0; for (int c = 0; c < contours.size(); c++) @@ -607,16 +607,16 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c continue; if (charRegions[j].contains(contours[c][0]) == false) continue; - - - + + + Rect r = boundingRect(contours[c]); - + if (r.height <= MIN_SPECKLE_HEIGHT || r.width <= MIN_SPECKLE_WIDTH_PX) { // Erase this speckle - drawContours(thresholds[i], contours, c, Scalar(0,0,0), CV_FILLED); - + drawContours(thresholds[i], contours, c, Scalar(0,0,0), CV_FILLED); + if (this->config->debugCharSegmenter) { drawContours(imgDbgCleanStages[i], contours, c, COLOR_DEBUG_SPECKLES, CV_FILLED); @@ -626,9 +626,9 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c { if (r.height > tallestContourHeight) tallestContourHeight = r.height; - + totalArea += contourArea(contours[c]); - + } //else if (r.height > tallestContourHeight) @@ -640,19 +640,19 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c } - + if (totalArea < MIN_CONTOUR_AREA) { // Character is not voluminous enough. Erase it. if (this->config->debugCharSegmenter) { cout << "Character CLEAN: (area) removing box " << j << " in threshold " << i << " -- Area " << totalArea << " < " << MIN_CONTOUR_AREA << endl; - + Rect boxTop(charRegions[j].x, charRegions[j].y - 10, charRegions[j].width, 10); rectangle(imgDbgCleanStages[i], boxTop, COLOR_DEBUG_MIN_AREA, -1); } - - + + rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); } else if (tallestContourHeight < ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT)) @@ -661,27 +661,27 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c if (this->config->debugCharSegmenter) { cout << "Character CLEAN: (height) removing box " << j << " in threshold " << i << " -- Height " << tallestContourHeight << " < " << ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT) << endl; - + Rect boxBottom(charRegions[j].x, charRegions[j].y + charRegions[j].height, charRegions[j].width, 10); rectangle(imgDbgCleanStages[i], boxBottom, COLOR_DEBUG_MIN_HEIGHT, -1); } rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1); } - + } - - + + Mat closureElement = getStructuringElement( 1, Size( 2 + 1, 2+1 ), Point( 1, 1 ) ); - + //morphologyEx(thresholds[i], thresholds[i], MORPH_OPEN, element); - + //dilate(thresholds[i], thresholds[i], element); //erode(thresholds[i], thresholds[i], element); - + morphologyEx(thresholds[i], thresholds[i], MORPH_CLOSE, closureElement); - + // Lastly, draw a clipping line between each character boxes for (int j = 0; j < charRegions.size(); j++) { @@ -689,7 +689,7 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c line(thresholds[i], Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y), Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0)); } } - + } @@ -698,31 +698,31 @@ void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask // If I knock out x% of the contour area from this thing (after applying the color filter) // Consider it a bad news bear. REmove the whole area. const float MIN_PERCENT_CHUNK_REMOVED = 0.6; - + for (int i = 0; i < thresholds.size(); i++) { - + for (int j = 0; j < charRegions.size(); j++) { - + Mat boxChar = Mat::zeros(thresholds[i].size(), CV_8U); rectangle(boxChar, charRegions[j], Scalar(255,255,255), CV_FILLED); - + bitwise_and(thresholds[i], boxChar, boxChar); - - - + + + float meanBefore = mean(boxChar, boxChar)[0]; - + Mat thresholdCopy(thresholds[i].size(), CV_8U); bitwise_and(colorMask, boxChar, thresholdCopy); - + float meanAfter = mean(thresholdCopy, boxChar)[0]; - + if (meanAfter < meanBefore * (1-MIN_PERCENT_CHUNK_REMOVED)) { rectangle(thresholds[i], charRegions[j], Scalar(0,0,0), CV_FILLED); - + if (this->config->debugCharSegmenter) { //vector tmpDebug; @@ -737,17 +737,17 @@ void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask // Mat tmpytmp = addLabel(thresholdCopy2, "box Mask + Thresh + Color"); // Mat tmpx = drawImageDashboard(tmpDebug, tmpytmp.type(), 1); //drawAndWait( &tmpx ); - - + + cout << "Segmentation Filter Clean by Color: Removed Threshold " << i << " charregion " << j << endl; cout << "Segmentation Filter Clean by Color: before=" << meanBefore << " after=" << meanAfter << endl; - + Point topLeft(charRegions[j].x, charRegions[j].y); circle(imgDbgCleanStages[i], topLeft, 5, COLOR_DEBUG_COLORFILTER, CV_FILLED); } } } - + } } @@ -755,19 +755,19 @@ void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask void CharacterSegmenter::cleanMostlyFullBoxes(vector thresholds, const vector charRegions) { float MAX_FILLED = 0.95 * 255; - + for (int i = 0; i < charRegions.size(); i++) { Mat mask = Mat::zeros(thresholds[0].size(), CV_8U); rectangle(mask, charRegions[i], Scalar(255,255,255), -1); - + for (int j = 0; j < thresholds.size(); j++) { if (mean(thresholds[j], mask)[0] > MAX_FILLED) { // Empty the rect rectangle(thresholds[j], charRegions[i], Scalar(0,0,0), -1); - + if (this->config->debugCharSegmenter) { Rect inset(charRegions[i].x + 2, charRegions[i].y - 2, charRegions[i].width - 4, charRegions[i].height - 4); @@ -779,35 +779,35 @@ void CharacterSegmenter::cleanMostlyFullBoxes(vector thresholds, const vect } vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, const vector charRegions) { - // Of the n thresholded images, if box 3 (for example) is empty in half (for example) of the thresholded images, + // Of the n thresholded images, if box 3 (for example) is empty in half (for example) of the thresholded images, // clear all data for every box #3. - + //const float MIN_AREA_PERCENT = 0.1; const float MIN_CONTOUR_HEIGHT_PERCENT = 0.65; - + Mat mask = getCharBoxMask(thresholds[0], charRegions); - + vector boxScores(charRegions.size()); - + for (int i = 0; i < charRegions.size(); i++) boxScores[i] = 0; - + for (int i = 0; i < thresholds.size(); i++) { - + for (int j = 0; j < charRegions.size(); j++) { //float minArea = charRegions[j].area() * MIN_AREA_PERCENT; - + Mat tempImg = Mat::zeros(thresholds[i].size(), thresholds[i].type()); rectangle(tempImg, charRegions[j], Scalar(255,255,255), CV_FILLED); bitwise_and(thresholds[i], tempImg, tempImg); vector > contours; findContours(tempImg, contours, RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); - + float biggestContourHeight = 0; - + vector allPointsInBox; for (int c = 0; c < contours.size(); c++) { @@ -816,7 +816,7 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, for (int z = 0; z < contours[c].size(); z++) allPointsInBox.push_back(contours[c][z]); - + } float height = 0; @@ -824,8 +824,8 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, { height = boundingRect(allPointsInBox).height; } - - + + if (height >= ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT)) { boxScores[j] = boxScores[j] + 1; @@ -835,23 +835,23 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3); } - + } - + } - + vector newCharRegions; - + int maxBoxScore = 0; for (int i = 0; i < charRegions.size(); i++) { if (boxScores[i] > maxBoxScore) maxBoxScore = boxScores[i]; } - + // Need a good char sample in at least 50% of the boxes for it to be valid. int MIN_FULL_BOXES = maxBoxScore * 0.49; - + // Now check each score. If it's below the minimum, remove the charRegion for (int i = 0; i < charRegions.size(); i++) { @@ -865,21 +865,21 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, cout << "Mostly Empty Filter: box index: " << i; cout << " this box had a score of : " << boxScores[i];; cout << " MIN_FULL_BOXES: " << MIN_FULL_BOXES << endl;; - + for (int z = 0; z < thresholds.size(); z++) { rectangle(thresholds[z], charRegions[i], Scalar(0,0,0), -1); - + drawX(imgDbgCleanStages[z], charRegions[i], COLOR_DEBUG_EMPTYFILTER, 1); } - + } } - + if (this->config->debugCharSegmenter) cout << " Box Score: " << boxScores[i] << endl; } - + return newCharRegions; } @@ -887,48 +887,48 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector avgCharHeight) MIN_CONNECTED_EDGE_PIXELS = alternate; - - // + + // // Pay special attention to the edge boxes. If it's a skinny box, and the vertical height extends above our bounds... remove it. //while (charBoxes.size() > 0 && charBoxes[charBoxes.size() - 1].width < MIN_SEGMENT_WIDTH_EDGES) // charBoxes.erase(charBoxes.begin() + charBoxes.size() - 1); // Now filter the "edge" boxes. We don't want to include skinny boxes on the edges, since these could be plate boundaries //while (charBoxes.size() > 0 && charBoxes[0].width < MIN_SEGMENT_WIDTH_EDGES) - // charBoxes.erase(charBoxes.begin() + 0); - - + // charBoxes.erase(charBoxes.begin() + 0); + + // TECHNIQUE #1 // Check for long vertical lines. Once the line is too long, mask the whole region - + if (charRegions.size() <= 1) return; - + // Check both sides to see where the edges are // The first starts at the right edge of the leftmost char region and works its way left // The second starts at the left edge of the rightmost char region and works its way right. // We start by rotating the threshold image to the correct angle // then check each column 1 by 1. - + vector leftEdges; vector rightEdges; - + for (int i = 0; i < thresholds.size(); i++) { Mat rotated; - + if (top.angle > MIN_ANGLE_FOR_ROTATION) { // Rotate image: rotated = Mat(thresholds[i].size(), thresholds[i].type()); Mat rot_mat( 2, 3, CV_32FC1 ); Point center = Point( thresholds[i].cols/2, thresholds[i].rows/2 ); - + rot_mat = getRotationMatrix2D( center, top.angle, 1.0 ); warpAffine( thresholds[i], rotated, rot_mat, thresholds[i].size() ); } @@ -943,24 +943,24 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector= 0) { - + int rowLength = getLongestBlobLengthBetweenLines(rotated, col); - + if (rowLength > MIN_CONNECTED_EDGE_PIXELS) { leftEdgeX = col; break; } - + col--; } - + col = charRegions[charRegions.size() - 1].x; while (col < rotated.cols) { - + int rowLength = getLongestBlobLengthBetweenLines(rotated, col); - + if (rowLength > MIN_CONNECTED_EDGE_PIXELS) { rightEdgeX = col; @@ -968,18 +968,18 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector 1) { @@ -991,23 +991,23 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector MIN_ANGLE_FOR_ROTATION) { // Rotate mask: Mat rot_mat( 2, 3, CV_32FC1 ); Point center = Point( mask.cols/2, mask.rows/2 ); - + rot_mat = getRotationMatrix2D( center, top.angle * -1, 1.0 ); warpAffine( mask, mask, rot_mat, mask.size() ); } - + // If our edge mask covers more than x% of the char region, mask the whole thing... const float MAX_COVERAGE_PERCENT = 0.6; int leftCoveragePx = leftEdge - charRegions[0].x; @@ -1028,37 +1028,37 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vectorconfig->debugCharSegmenter) cout << "Edge Filter: Entire right region is erased" << endl; } - + for (int i = 0; i < thresholds.size(); i++) { bitwise_and(thresholds[i], mask, thresholds[i]); } - - + + if (this->config->debugCharSegmenter) { - cout << "Edge Filter: left=" << leftEdge << " right=" << rightEdge << endl; + cout << "Edge Filter: left=" << leftEdge << " right=" << rightEdge << endl; Mat bordered = addLabel(mask, "Edge Filter #1"); imgDbgGeneral.push_back(bordered); - + Mat invertedMask(mask.size(), mask.type()); bitwise_not(mask, invertedMask); for (int z = 0; z < imgDbgCleanStages.size(); z++) fillMask(imgDbgCleanStages[z], invertedMask, Scalar(0,0,255)); } } - + // TECHNIQUE #2 // Check for tall skinny blobs on the edge boxes. If they're too long and skinny, maks the whole char region /* - * + * float MIN_EDGE_CONTOUR_HEIGHT = avgCharHeight * 0.7; float MIN_EDGE_CONTOUR_AREA_PCT = avgCharHeight * 0.1; - + for (int i = 0; i < thresholds.size(); i++) { // Just check the first and last char box. If the contour extends too far above/below the line. Drop it. - + for (int boxidx = 0; boxidx < charRegions.size(); boxidx++) { if (boxidx != 0 || boxidx != charRegions.size() -1) @@ -1066,11 +1066,11 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector > contours; Mat mask = Mat::zeros(thresholds[i].size(),CV_8U); rectangle(mask, charRegions[boxidx], Scalar(255,255,255), CV_FILLED); - + bitwise_and(thresholds[i], mask, mask); findContours(mask, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //int tallContourIndex = isSkinnyLineInsideBox(thresholds[i], charRegions[boxidx], allContours[i], hierarchy[i], avgCharWidth, avgCharHeight); @@ -1088,9 +1088,9 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector biggestContourArea) biggestContourArea = a; } - + float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT; - if ((fattestContourWidth < MIN_BOX_WIDTH_PX) || + if ((fattestContourWidth < MIN_BOX_WIDTH_PX) || (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) || (biggestContourArea < minArea) ) @@ -1099,7 +1099,7 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vectordebug) { - + rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2); cout << "Edge Filter: threshold " << i << " box " << boxidx << endl; } @@ -1107,41 +1107,41 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector(row, col); // check two rows at a time. if (!isOn && col < img.cols) isOn = img.at(row, col); - + if (isOn) { // We're on a segment. Increment the length isbetweenLines = top.isPointBelowLine(Point(col, row)) && !bottom.isPointBelowLine(Point(col, row)); float incrementBy = 1; - + // Add a little extra to the score if this is outside of the lines if (!isbetweenLines) incrementBy = 1.1; - + onSegment = true; curSegmentLength += incrementBy; } @@ -1149,21 +1149,21 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col) { wasbetweenLines = true; } - + if ((isOn == false && onSegment == true) || (row == img.rows - 1 && onSegment == true)) { if (wasbetweenLines && curSegmentLength > longestBlobLength) longestBlobLength = curSegmentLength; - + onSegment = false; isbetweenLines = false; curSegmentLength = 0; } - + } - - + + return longestBlobLength; } @@ -1172,28 +1172,28 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col) int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector > contours, vector hierarchy, float avgCharWidth, float avgCharHeight) { float MIN_EDGE_CONTOUR_HEIGHT = avgCharHeight * 1.25; - + // Sometimes the threshold is smaller than the MIN_EDGE_CONTOUR_HEIGHT. // In that case, adjust to be smaller int alternate = threshold.rows * 0.92; if (alternate < MIN_EDGE_CONTOUR_HEIGHT && alternate > avgCharHeight) MIN_EDGE_CONTOUR_HEIGHT = alternate; - + Rect slightlySmallerBox(box.x, box.y, box.width, box.height); Mat boxMask = Mat::zeros(threshold.size(), CV_8U); rectangle(boxMask, slightlySmallerBox, Scalar(255, 255, 255), -1); - - + + for (int i = 0; i < contours.size(); i++) { // Only bother with the big boxes if (boundingRect(contours[i]).height < MIN_EDGE_CONTOUR_HEIGHT) continue; - + Mat tempImg = Mat::zeros(threshold.size(), CV_8U); drawContours(tempImg, contours, i, Scalar(255,255,255), -1, 8, hierarchy, 1); bitwise_and(tempImg, boxMask, tempImg); - + vector > subContours; findContours(tempImg, subContours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); int tallestContourIdx = -1; @@ -1211,13 +1211,13 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector= avgCharHeight * 0.9 && + if (tallestContourHeight >= avgCharHeight * 0.9 && ((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1))) { cout << "Edge Filter: Avg contour width: " << avgCharWidth << " This guy is: " << tallestContourWidth << endl; @@ -1226,7 +1226,7 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector charBoxes) { - + Mat mask = Mat::zeros(img_threshold.size(), CV_8U); for (int i = 0; i < charBoxes.size(); i++) rectangle(mask, charBoxes[i], Scalar(255, 255, 255), -1); - + return mask; } vector CharacterSegmenter::getThresholds() { - return charAnalysis->thresholds; + return charAnalysis->thresholds; } - - diff --git a/src/openalpr/charactersegmenter.h b/src/openalpr/charactersegmenter.h index c4c7703..9baabb9 100644 --- a/src/openalpr/charactersegmenter.h +++ b/src/openalpr/charactersegmenter.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -53,53 +53,51 @@ class CharacterSegmenter vector characters; int confidence; - + vector getThresholds(); - + private: Config* config; - + CharacterAnalysis* charAnalysis; - + LineSegment top; LineSegment bottom; - + vector imgDbgGeneral; vector imgDbgCleanStages; - + vector filter(Mat img, vector > contours, vector hierarchy); vector filterByBoxSize(vector< vector< Point> > contours, vector goodIndices, float minHeightPx, float maxHeightPx); vector filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices); vector filterContourHoles(vector > contours, vector hierarchy, vector goodIndices); - + vector getBestVotedLines(Mat img, vector > contours, vector goodIndices); int getGoodIndicesCount(vector goodIndices); - + Mat getCharacterMask(Mat img_threshold, vector > contours, vector hierarchy, vector goodIndices); Mat getCharBoxMask(Mat img_threshold, vector charBoxes); - + void removeSmallContours(vector thresholds, vector > > allContours, float avgCharWidth, float avgCharHeight); - + Mat getVerticalHistogram(Mat img, Mat mask); vector getHistogramBoxes(VerticalHistogram histogram, float avgCharWidth, float avgCharHeight, float* score); vector getBestCharBoxes(Mat img, vector charBoxes, float avgCharWidth); vector combineCloseBoxes( vector charBoxes, float avgCharWidth); - + vector get1DHits(Mat img, int yOffset); - + void cleanCharRegions(vector thresholds, vector charRegions); void cleanBasedOnColor(vector thresholds, Mat colorMask, vector charRegions); void cleanMostlyFullBoxes(vector thresholds, const vector charRegions); vector filterMostlyEmptyBoxes(vector thresholds, const vector charRegions); void filterEdgeBoxes(vector thresholds, const vector charRegions, float avgCharWidth, float avgCharHeight); - + int getLongestBlobLengthBetweenLines(Mat img, int col); - + int isSkinnyLineInsideBox(Mat threshold, Rect box, vector > contours, vector hierarchy, float avgCharWidth, float avgCharHeight); - + vector getEncapsulatingLines(Mat img, vector > contours, vector goodIndices); }; #endif // CHARACTERSEGMENTER_H - - diff --git a/src/openalpr/cjson.c b/src/openalpr/cjson.c index 7331258..6094a8b 100644 --- a/src/openalpr/cjson.c +++ b/src/openalpr/cjson.c @@ -107,7 +107,7 @@ static const char *parse_number(cJSON *item,const char *num) } n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ - + item->valuedouble=n; item->valueint=(int)n; item->type=cJSON_Number; @@ -156,12 +156,12 @@ static const char *parse_string(cJSON *item,const char *str) { const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; if (*str!='\"') {ep=str;return 0;} /* not a string! */ - + while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ - + out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ if (!out) return 0; - + ptr=str+1;ptr2=out; while (*ptr!='\"' && *ptr) { @@ -190,7 +190,7 @@ static const char *parse_string(cJSON *item,const char *str) } len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; - + switch (len) { case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; @@ -215,10 +215,10 @@ static const char *parse_string(cJSON *item,const char *str) static char *print_string_ptr(const char *str) { const char *ptr;char *ptr2,*out;int len=0;unsigned char token; - + if (!str) return cJSON_strdup(""); ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} - + out=(char*)cJSON_malloc(len+3); if (!out) return 0; @@ -351,7 +351,7 @@ static char *print_array(cJSON *item,int depth,int fmt) char *out=0,*ptr,*ret;int len=5; cJSON *child=item->child; int numentries=0,i=0,fail=0; - + /* How many entries in the array? */ while (child) numentries++,child=child->next; /* Explicitly handle numentries==0 */ @@ -374,7 +374,7 @@ static char *print_array(cJSON *item,int depth,int fmt) if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; child=child->next; } - + /* If we didn't fail, try to malloc the output string */ if (!fail) out=(char*)cJSON_malloc(len); /* If that fails, we fail. */ @@ -387,7 +387,7 @@ static char *print_array(cJSON *item,int depth,int fmt) cJSON_free(entries); return 0; } - + /* Compose the output array. */ *out='['; ptr=out+1;*ptr=0; @@ -399,7 +399,7 @@ static char *print_array(cJSON *item,int depth,int fmt) } cJSON_free(entries); *ptr++=']';*ptr++=0; - return out; + return out; } /* Build an object from the text. */ @@ -407,11 +407,11 @@ static const char *parse_object(cJSON *item,const char *value) { cJSON *child; if (*value!='{') {ep=value;return 0;} /* not an object! */ - + item->type=cJSON_Object; value=skip(value+1); if (*value=='}') return value+1; /* empty array. */ - + item->child=child=cJSON_New_Item(); if (!item->child) return 0; value=skip(parse_string(child,skip(value))); @@ -420,7 +420,7 @@ static const char *parse_object(cJSON *item,const char *value) if (*value!=':') {ep=value;return 0;} /* fail! */ value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; - + while (*value==',') { cJSON *new_item; @@ -433,7 +433,7 @@ static const char *parse_object(cJSON *item,const char *value) value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ if (!value) return 0; } - + if (*value=='}') return value+1; /* end of array */ ep=value;return 0; /* malformed. */ } @@ -474,7 +474,7 @@ static char *print_object(cJSON *item,int depth,int fmt) if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; child=child->next; } - + /* Try to allocate the output string */ if (!fail) out=(char*)cJSON_malloc(len); if (!out) fail=1; @@ -486,7 +486,7 @@ static char *print_object(cJSON *item,int depth,int fmt) cJSON_free(names);cJSON_free(entries); return 0; } - + /* Compose the output: */ *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0; for (i=0;i. */ @@ -24,31 +24,31 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config) { - + timespec startTime; getTime(&startTime); - + this->config = config; - + this->debug = config->debugColorFiler; - + this->grayscale = imageIsGrayscale(image); - + if (this->debug) cout << "ColorFilter: isGrayscale = " << grayscale << endl; - + this->hsv = Mat(image.size(), image.type()); cvtColor( image, this->hsv, CV_BGR2HSV ); preprocessImage(); - + this->charMask = characterMask; - + this->colorMask = Mat(image.size(), CV_8U); - + findCharColors(); - - + + if (config->debugTiming) { timespec endTime; @@ -72,7 +72,7 @@ bool ColorFilter::imageIsGrayscale(Mat image) int r = (int) image.at(row, col)[0]; int g = (int) image.at(row, col)[1]; int b = (int) image.at(row, col)[2]; - + if (r == g == b) { // So far so good @@ -84,7 +84,7 @@ bool ColorFilter::imageIsGrayscale(Mat image) } } } - + return true; } @@ -94,7 +94,7 @@ void ColorFilter::preprocessImage() vector channels; split(this->hsv,channels); Mat img_equalized = equalizeBrightness(channels[2]); - merge(channels,this->hsv); + merge(channels,this->hsv); } // Gets the hue/sat/val for areas that we believe are license plate characters @@ -102,14 +102,14 @@ void ColorFilter::preprocessImage() void ColorFilter::findCharColors() { int MINIMUM_SATURATION = 45; - + if (this->debug) cout << "ColorFilter::findCharColors" << endl; - + //charMask.copyTo(this->colorMask); this->colorMask = Mat::zeros(charMask.size(), CV_8U); bitwise_not(this->colorMask, this->colorMask); - + Mat erodedCharMask(charMask.size(), CV_8U); Mat element = getStructuringElement( 1, Size( 2 + 1, 2+1 ), @@ -120,80 +120,80 @@ void ColorFilter::findCharColors() vector hierarchy; findContours(erodedCharMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE); - - + + vector hMeans, sMeans, vMeans; vector hStdDevs, sStdDevs, vStdDevs; - + for (int i = 0; i < contours.size(); i++) { if (hierarchy[i][3] != -1) continue; - + Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U); - + drawContours(singleCharMask, contours, i, // draw this contour - cv::Scalar(255,255,255), // in - CV_FILLED, - 8, + 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, + 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) <getMajorityOpinion(hMeans, .65, 30); 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; float valMin, valMax; - + if (this->debug) cout << "ColorFilter Winning indices:" << endl; if (bestHueIndex != -1) @@ -201,64 +201,64 @@ void ColorFilter::findCharColors() doHueFilter = true; hueMin = hMeans[bestHueIndex] - (2 * hStdDevs[bestHueIndex]); hueMax = hMeans[bestHueIndex] + (2 * hStdDevs[bestHueIndex]); - + if (abs(hueMin - hueMax) < 20) { hueMin = hMeans[bestHueIndex] - 20; hueMax = hMeans[bestHueIndex] + 20; } - + if (hueMin < 0) hueMin = 0; if (hueMax > 180) hueMax = 180; - + if (this->debug) cout << "ColorFilter Hue: " << bestHueIndex << " : " << setw(7) << hMeans[bestHueIndex] << " -- " << hueMin << "-" << hueMax << endl; } if (bestSatIndex != -1) { doSatFilter = true; - + satMin = sMeans[bestSatIndex] - (2 * sStdDevs[bestSatIndex]); satMax = sMeans[bestSatIndex] + (2 * sStdDevs[bestSatIndex]); - + if (abs(satMin - satMax) < 20) { satMin = sMeans[bestSatIndex] - 20; satMax = sMeans[bestSatIndex] + 20; } - + if (satMin < 0) satMin = 0; if (satMax > 255) satMax = 255; - + if (this->debug) cout << "ColorFilter Sat: " << bestSatIndex << " : " << setw(7) << sMeans[bestSatIndex] << " -- " << satMin << "-" << satMax << endl; } if (bestValIndex != -1) { doValFilter = true; - + valMin = vMeans[bestValIndex] - (1.5 * vStdDevs[bestValIndex]); valMax = vMeans[bestValIndex] + (1.5 * vStdDevs[bestValIndex]); - + if (abs(valMin - valMax) < 20) { valMin = vMeans[bestValIndex] - 20; valMax = vMeans[bestValIndex] + 20; } - + if (valMin < 0) valMin = 0; if (valMax > 255) valMax = 255; - + if (this->debug) cout << "ColorFilter Val: " << bestValIndex << " : " << setw(7) << vMeans[bestValIndex] << " -- " << valMin << "-" << valMax << endl; } - + Mat imgDebugHueOnly = Mat::zeros(hsv.size(), hsv.type()); @@ -266,7 +266,7 @@ void ColorFilter::findCharColors() Mat imgDistanceFromCenter = Mat::zeros(hsv.size(), CV_8U); Mat debugMask = Mat::zeros(hsv.size(), CV_8U); bitwise_not(debugMask, debugMask); - + for (int row = 0; row < charMask.rows; row++) { for (int col = 0; col < charMask.cols; col++) @@ -274,21 +274,21 @@ void ColorFilter::findCharColors() int h = (int) hsv.at(row, col)[0]; int s = (int) hsv.at(row, col)[1]; int v = (int) hsv.at(row, col)[2]; - + bool hPasses = true; bool sPasses = true; bool vPasses = true; int vDistance = abs(v - vMeans[bestValIndex]); - + imgDebugHueOnly.at(row, col)[0] = h; imgDebugHueOnly.at(row, col)[1] = 255; imgDebugHueOnly.at(row, col)[2] = 255; - + imgDebug.at(row, col)[0] = 255; imgDebug.at(row, col)[1] = 255; imgDebug.at(row, col)[2] = 255; - + if (doHueFilter && (h < hueMin || h > hueMax)) { hPasses = false; @@ -305,20 +305,20 @@ void ColorFilter::findCharColors() vPasses = false; imgDebug.at(row, col)[2] = 0; } - + //if (pixelPasses) // colorMask.at(row, col) = 255; //else //imgDebug.at(row, col)[0] = hPasses & 255; //imgDebug.at(row, col)[1] = sPasses & 255; //imgDebug.at(row, col)[2] = vPasses & 255; - + if ((hPasses) || (hPasses && sPasses))//(hPasses && vPasses) || (sPasses && vPasses) || this->colorMask.at(row, col) = 255; else this->colorMask.at(row, col) = 0; - - + + if ((hPasses && sPasses) || (hPasses && vPasses) || (sPasses && vPasses)) { vDistance = pow(vDistance, 0.9); @@ -332,11 +332,11 @@ void ColorFilter::findCharColors() imgDistanceFromCenter.at(row, col) = vDistance; } } - - + + vector debugImagesSet; - + if (this->debug) { debugImagesSet.push_back(addLabel(charMask, "Charecter mask")); @@ -345,40 +345,40 @@ void ColorFilter::findCharColors() colorMask.copyTo(maskCopy); debugImagesSet.push_back(addLabel(maskCopy, "color Mask Before")); } - - + + Mat bigElement = getStructuringElement( 1, Size( 3 + 1, 3+1 ), Point( 1, 1 ) ); - + Mat smallElement = getStructuringElement( 1, Size( 1 + 1, 1+1 ), Point( 1, 1 ) ); - + morphologyEx(this->colorMask, this->colorMask, MORPH_CLOSE, bigElement); //dilate(this->colorMask, this->colorMask, bigElement); - + Mat combined(charMask.size(), charMask.type()); bitwise_and(charMask, colorMask, combined); - + if (this->debug) { debugImagesSet.push_back(addLabel(colorMask, "Color Mask After")); debugImagesSet.push_back(addLabel(combined, "Combined")); - + //displayImage(config, "COLOR filter Mask", colorMask); debugImagesSet.push_back(addLabel(imgDebug, "Color filter Debug")); - + cvtColor(imgDebugHueOnly, imgDebugHueOnly, CV_HSV2BGR); debugImagesSet.push_back(addLabel(imgDebugHueOnly, "Color Filter Hue")); - + equalizeHist(imgDistanceFromCenter, imgDistanceFromCenter); debugImagesSet.push_back(addLabel(imgDistanceFromCenter, "COLOR filter Distance")); - + debugImagesSet.push_back(addLabel(debugMask, "COLOR Hues off")); - - + + Mat dashboard = drawImageDashboard(debugImagesSet, imgDebugHueOnly.type(), 3); displayImage(config, "Color Filter Images", dashboard); } @@ -394,7 +394,7 @@ int ColorFilter::getMajorityOpinion(vector values, float minPercentAgreem float bestPercentAgreement = 0; float lowestOverallDiff = 1000000000; int bestPercentAgreementIndex = -1; - + for (int i = 0; i < values.size(); i++) { int valuesInRange = 0; @@ -404,10 +404,10 @@ int ColorFilter::getMajorityOpinion(vector values, float minPercentAgreem float diff = abs(values[i] - values[j]); if (diff < maxValDifference) valuesInRange++; - + overallDiff += diff; } - + float percentAgreement = ((float) valuesInRange) / ((float) values.size()); if (overallDiff < lowestOverallDiff && percentAgreement >= bestPercentAgreement && percentAgreement >= minPercentAgreement) { @@ -416,6 +416,6 @@ int ColorFilter::getMajorityOpinion(vector values, float minPercentAgreem lowestOverallDiff = overallDiff; } } - + return bestPercentAgreementIndex; } diff --git a/src/openalpr/colorfilter.h b/src/openalpr/colorfilter.h index 9e553ac..694bde4 100644 --- a/src/openalpr/colorfilter.h +++ b/src/openalpr/colorfilter.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -43,23 +43,23 @@ class ColorFilter Mat colorMask; - + private: - + Config* config; bool debug; - + Mat hsv; Mat charMask; - - + + bool grayscale; - + void preprocessImage(); void findCharColors(); - + bool imageIsGrayscale(Mat image); int getMajorityOpinion(vector values, float minPercentAgreement, float maxValDifference); }; -#endif // COLORFILTER_H \ No newline at end of file +#endif // COLORFILTER_H diff --git a/src/openalpr/config.cpp b/src/openalpr/config.cpp index 282719e..5d84e09 100644 --- a/src/openalpr/config.cpp +++ b/src/openalpr/config.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,15 +23,15 @@ Config::Config(const std::string country, const std::string runtimeBaseDir) { this->runtimeBaseDir = runtimeBaseDir; - + ini = new CSimpleIniA(); - + char* envRuntimeDir; envRuntimeDir = getenv (ENV_VARIABLE_RUNTIME_DIR); if (runtimeBaseDir.compare("") != 0) { // User has supplied a runtime directory. Use that. - + } else if (envRuntimeDir!=NULL) { @@ -43,9 +43,9 @@ Config::Config(const std::string country, const std::string runtimeBaseDir) // Use the default this->runtimeBaseDir = DEFAULT_RUNTIME_DIR; } - + string configFile = (this->runtimeBaseDir + CONFIG_FILE); - + if (DirectoryExists(this->runtimeBaseDir.c_str()) == false) { std::cerr << "--(!)Runtime directory '" << this->runtimeBaseDir << "' does not exist!" << endl; @@ -56,11 +56,11 @@ Config::Config(const std::string country, const std::string runtimeBaseDir) std::cerr << "--(!)Runtime directory '" << this->runtimeBaseDir << "' does not contain a config file '" << CONFIG_FILE << "'!" << endl; return; } - + ini->LoadFile(configFile.c_str()); - + this->country = country; - + loadValues(country); } Config::~Config() @@ -70,56 +70,56 @@ Config::~Config() void Config::loadValues(string country) { - + opencl_enabled = getBoolean("common", "opencl_enabled", false); maxPlateWidthPercent = getFloat("common", "max_plate_width_percent", 100); maxPlateHeightPercent = getFloat("common", "max_plate_height_percent", 100); minPlateSizeWidthPx = getInt(country, "min_plate_size_width_px", 100); minPlateSizeHeightPx = getInt(country, "min_plate_size_height_px", 100); - + plateWidthMM = getFloat(country, "plate_width_mm", 100); plateHeightMM = getFloat(country, "plate_height_mm", 100); - + charHeightMM = getFloat(country, "char_height_mm", 100); charWidthMM = getFloat(country, "char_width_mm", 100); charWhitespaceTopMM = getFloat(country, "char_whitespace_top_mm", 100); charWhitespaceBotMM = getFloat(country, "char_whitespace_bot_mm", 100); - + templateWidthPx = getInt(country, "template_max_width_px", 100); templateHeightPx = getInt(country, "template_max_height_px", 100); - + float ocrImagePercent = getFloat("common", "ocr_img_size_percent", 100); 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); charAnalysisNumSteps = getInt(country, "char_analysis_height_num_steps", 0); - + segmentationMinBoxWidthPx = getInt(country, "segmentation_min_box_width_px", 0); segmentationMinCharHeightPercent = getFloat(country, "segmentation_min_charheight_percent", 0); segmentationMaxCharWidthvsAverage = getFloat(country, "segmentation_max_segment_width_percent_vs_average", 0); - + plateLinesSensitivityVertical = getFloat(country, "plateline_sensitivity_vertical", 0); plateLinesSensitivityHorizontal = getFloat(country, "plateline_sensitivity_horizontal", 0); - + ocrLanguage = getString(country, "ocr_language", "none"); ocrMinFontSize = getInt("common", "ocr_min_font_point", 100); - + postProcessMinConfidence = getFloat("common", "postprocess_min_confidence", 100); postProcessConfidenceSkipLevel = getFloat("common", "postprocess_confidence_skip_level", 100); postProcessMaxSubstitutions = getInt("common", "postprocess_max_substitutions", 100); postProcessMinCharacters = getInt("common", "postprocess_min_characers", 100); postProcessMaxCharacters = getInt("common", "postprocess_max_characers", 100); - + debugGeneral = getBoolean("debug", "general", false); debugTiming = getBoolean("debug", "timing", false); debugStateId = getBoolean("debug", "state_id", false); @@ -132,7 +132,7 @@ void Config::loadValues(string country) debugOcr = getBoolean("debug", "ocr", false); debugPostProcess = getBoolean("debug", "postprocess", false); debugShowImages = getBoolean("debug", "show_images", false); - + } void Config::debugOff() @@ -179,7 +179,7 @@ float Config::getFloat(string section, string key, float defaultValue) std::cout << "Error: missing configuration entry for: " << section << "->" << key << endl; return defaultValue; } - + float val = atof(pszValue); return val; } @@ -191,7 +191,7 @@ int Config::getInt(string section, string key, int defaultValue) std::cout << "Error: missing configuration entry for: " << section << "->" << key << endl; return defaultValue; } - + int val = atoi(pszValue); return val; } @@ -203,7 +203,7 @@ bool Config::getBoolean(string section, string key, bool defaultValue) std::cout << "Error: missing configuration entry for: " << section << "->" << key << endl; return defaultValue; } - + int val = atoi(pszValue); return val != 0; } @@ -215,7 +215,7 @@ string Config::getString(string section, string key, string defaultValue) std::cout << "Error: missing configuration entry for: " << section << "->" << key << endl; return defaultValue; } - + string val = string(pszValue); return val; } diff --git a/src/openalpr/config.h b/src/openalpr/config.h index 1858b91..a1f259c 100644 --- a/src/openalpr/config.h +++ b/src/openalpr/config.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -42,54 +42,54 @@ class Config virtual ~Config(); string country; - + bool opencl_enabled; - + float maxPlateWidthPercent; float maxPlateHeightPercent; - + float minPlateSizeWidthPx; float minPlateSizeHeightPx; - + float plateWidthMM; float plateHeightMM; - + float charHeightMM; float charWidthMM; float charWhitespaceTopMM; float charWhitespaceBotMM; - + int templateWidthPx; int templateHeightPx; - + int ocrImageWidthPx; int ocrImageHeightPx; - + int stateIdImageWidthPx; int stateIdimageHeightPx; - + float charAnalysisMinPercent; float charAnalysisHeightRange; float charAnalysisHeightStepSize; int charAnalysisNumSteps; - + float plateLinesSensitivityVertical; float plateLinesSensitivityHorizontal; int segmentationMinBoxWidthPx; float segmentationMinCharHeightPercent; float segmentationMaxCharWidthvsAverage; - + string ocrLanguage; int ocrMinFontSize; - + float postProcessMinConfidence; float postProcessConfidenceSkipLevel; int postProcessMaxSubstitutions; int postProcessMinCharacters; int postProcessMaxCharacters; - + bool debugGeneral; bool debugTiming; bool debugStateId; @@ -102,9 +102,9 @@ class Config bool debugOcr; bool debugPostProcess; bool debugShowImages; - + void debugOff(); - + string getKeypointsRuntimeDir(); string getCascadeRuntimeDir(); string getPostProcessRuntimeDir(); @@ -114,9 +114,9 @@ private: CSimpleIniA* ini; string runtimeBaseDir; - + void loadValues(string country); - + int getInt(string section, string key, int defaultValue); float getFloat(string section, string key, float defaultValue); string getString(string section, string key, string defaultValue); @@ -124,4 +124,4 @@ private: }; -#endif // CONFIG_H \ No newline at end of file +#endif // CONFIG_H diff --git a/src/openalpr/constants.h b/src/openalpr/constants.h index a3f3f3d..8c9f35c 100644 --- a/src/openalpr/constants.h +++ b/src/openalpr/constants.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -26,4 +26,4 @@ #define DEFAULT_RUNTIME_DIR "/default_runtime_data_dir/" #endif -#define ENV_VARIABLE_RUNTIME_DIR "OPENALPR_RUNTIME_DIR" \ No newline at end of file +#define ENV_VARIABLE_RUNTIME_DIR "OPENALPR_RUNTIME_DIR" diff --git a/src/openalpr/featurematcher.cpp b/src/openalpr/featurematcher.cpp index b21a289..d04e536 100644 --- a/src/openalpr/featurematcher.cpp +++ b/src/openalpr/featurematcher.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -29,13 +29,13 @@ const float MAX_DISTANCE_TO_MATCH = 100.0f; FeatureMatcher::FeatureMatcher(Config* config) { this->config = config; - + //this->descriptorMatcher = DescriptorMatcher::create( "BruteForce-HammingLUT" ); this->descriptorMatcher = new BFMatcher(NORM_HAMMING, false); - + //this->descriptorMatcher = DescriptorMatcher::create( "FlannBased" ); - - + + this->detector = new FastFeatureDetector(10, true); this->extractor = new BRISK(10, 1, 0.9); } @@ -45,11 +45,11 @@ FeatureMatcher::~FeatureMatcher() for (int i = 0; i < trainingImgKeypoints.size(); i++) trainingImgKeypoints[i].clear(); trainingImgKeypoints.clear(); - + descriptorMatcher.release(); detector.release(); extractor.release(); - + } @@ -59,7 +59,7 @@ bool FeatureMatcher::isLoaded() { return false; } - + return true; } @@ -75,13 +75,13 @@ void FeatureMatcher::surfStyleMatching( const Mat& queryDescriptors, vector& matches12 ) { vector > matchesKnn; - + this->descriptorMatcher->radiusMatch(queryDescriptors, matchesKnn, MAX_DISTANCE_TO_MATCH); - - + + vector tempMatches; _surfStyleMatching(queryDescriptors, matchesKnn, tempMatches); - + crisscrossFiltering(queryKeypoints, tempMatches, matches12); } @@ -101,13 +101,13 @@ void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector 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) { @@ -125,20 +125,20 @@ void FeatureMatcher::_surfStyleMatching(const Mat& queryDescriptors, vector queryKeypoints, const vector inputMatches, vector &outputMatches) { - + Rect crissCrossAreaVertical(0, 0, config->stateIdImageWidthPx, config->stateIdimageHeightPx * 2); Rect crissCrossAreaHorizontal(0, 0, config->stateIdImageWidthPx * 2, config->stateIdimageHeightPx); - + for (int i = 0; i < billMapping.size(); i++) { vector matchesForOnePlate; @@ -179,32 +179,32 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, if (inputMatches[j].imgIdx == i) matchesForOnePlate.push_back(inputMatches[j]); } - + // For each plate, compare the lines for the keypoints (training image and query image) // go through each line between keypoints and filter out matches that are criss-crossing vector vlines; vector hlines; vector matchIdx; - + for (int j = 0; j < matchesForOnePlate.size(); j++) { KeyPoint tkp = trainingImgKeypoints[i][matchesForOnePlate[j].trainIdx]; KeyPoint qkp = queryKeypoints[matchesForOnePlate[j].queryIdx]; - + vlines.push_back(LineSegment(tkp.pt.x, tkp.pt.y + config->stateIdimageHeightPx, qkp.pt.x, qkp.pt.y)); hlines.push_back(LineSegment(tkp.pt.x, tkp.pt.y, qkp.pt.x + config->stateIdImageWidthPx, qkp.pt.y)); 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) { int mostIntersectionsIndex = -1; mostIntersections = 0; - + for (int j = 0; j < vlines.size(); j++) { int intrCount = 0; @@ -223,14 +223,14 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, intrCount++; } } - + if (intrCount > mostIntersections) { mostIntersections = intrCount; mostIntersectionsIndex = j; } } - + if (mostIntersectionsIndex >= 0) { if (this->config->debugStateId) @@ -239,75 +239,75 @@ void FeatureMatcher::crisscrossFiltering(const vector queryKeypoints, hlines.erase(hlines.begin() + mostIntersectionsIndex); matchIdx.erase(matchIdx.begin() + mostIntersectionsIndex); } - + } - + // Push the non-crisscrosses back on the list for (int j = 0; j < matchIdx.size(); j++) { outputMatches.push_back(matchesForOnePlate[matchIdx[j]]); } } - + } // Returns true if successful, false otherwise bool FeatureMatcher::loadRecognitionSet(string country) { - std::ostringstream out; + std::ostringstream out; out << config->getKeypointsRuntimeDir() << "/" << country << "/"; string country_dir = out.str(); - + if (DirectoryExists(country_dir.c_str())) { vector trainImages; vector plateFiles = getFilesInDir(country_dir.c_str()); - + for (int i = 0; i < plateFiles.size(); i++) { 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 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); } - + } - - + + this->descriptorMatcher->add(trainImages); this->descriptorMatcher->train(); - + return true; } return false; - + } @@ -317,16 +317,16 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma ) { RecognitionResult result; - + result.haswinner = false; Mat queryDescriptors; vector queryKeypoints; - + detector->detect( queryImg, queryKeypoints ); extractor->compute(queryImg, queryKeypoints, queryDescriptors); - + if (queryKeypoints.size() <= 5) { @@ -337,27 +337,27 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma } return result; } - + vector filteredMatches; surfStyleMatching( queryDescriptors, queryKeypoints, filteredMatches ); - + // Create and initialize the counts to 0 std::vector 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++) { bill_match_counts[filteredMatches[i].imgIdx]++; //if (filteredMatches[i].imgIdx } - - + + float max_count = 0; // represented as a percent (0 to 100) int secondmost_count = 0; int maxcount_index = -1; @@ -368,25 +368,25 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma 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; - + if (score > 0) { result.haswinner = true; result.winner = billMapping[maxcount_index]; result.confidence = score; - + if (drawOnImage) { vector positiveMatches; @@ -397,36 +397,35 @@ RecognitionResult FeatureMatcher::recognize( const Mat& queryImg, bool drawOnIma 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 ); - + if (result.haswinner == true) { - - std::ostringstream out; + + 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); } } - + } - + if (this->config->debugStateId) { - + for (int i = 0; i < billMapping.size(); i++) { cout << billMapping[i] << " : " << bill_match_counts[i] << endl; } - + } - + return result; - -} +} diff --git a/src/openalpr/featurematcher.h b/src/openalpr/featurematcher.h index b1a737a..a2ea8b3 100644 --- a/src/openalpr/featurematcher.h +++ b/src/openalpr/featurematcher.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -55,31 +55,31 @@ class FeatureMatcher RecognitionResult recognize( const Mat& queryImg, bool drawOnImage, Mat* outputImage, bool debug_on, vector debug_matches_array ); - + bool loadRecognitionSet(string country); - + bool isLoaded(); int numTrainingElements(); - + private: Config* config; - + Ptr descriptorMatcher; Ptr detector; Ptr extractor; - - - vector > trainingImgKeypoints; - - + + + vector > trainingImgKeypoints; + + void _surfStyleMatching(const Mat& queryDescriptors, vector > matchesKnn, vector& matches12); void crisscrossFiltering(const vector queryKeypoints, const vector inputMatches, vector &outputMatches); - + vector billMapping; - + void surfStyleMatching( const Mat& queryDescriptors, vector queryKeypoints, @@ -88,5 +88,3 @@ class FeatureMatcher }; #endif // FEATUREMATCHER_H - - diff --git a/src/openalpr/licenseplatecandidate.cpp b/src/openalpr/licenseplatecandidate.cpp index 2de4c6d..5c92af4 100644 --- a/src/openalpr/licenseplatecandidate.cpp +++ b/src/openalpr/licenseplatecandidate.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,7 +23,7 @@ LicensePlateCandidate::LicensePlateCandidate(Mat frame, Rect regionOfInterest, Config* config) { this->config = config; - + this->frame = frame; this->plateRegion = regionOfInterest; } @@ -37,61 +37,61 @@ LicensePlateCandidate::~LicensePlateCandidate() void LicensePlateCandidate::recognize() { charSegmenter = NULL; - - + + this->confidence = 0; - + int expandX = round(this->plateRegion.width * 0.15); int expandY = round(this->plateRegion.height * 0.10); // 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) { - + PlateLines plateLines(config); //Mat boogedy = charRegion.getPlateMask(); - + plateLines.processImage(charRegion.getPlateMask(), 1.15); plateLines.processImage(plate_bgr_cleaned, 0.9); - + PlateCorners cornerFinder(plate_bgr, &plateLines, &charRegion, config); vector smallPlateCorners = cornerFinder.findPlateCorners(); - + if (cornerFinder.confidence > 0) { 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); - + this->confidence = 100; - + } charRegion.confidence = 0; } - - + + } @@ -106,30 +106,30 @@ vector LicensePlateCandidate::transformPointsToOriginalImage(Mat bigIma { float bigX = (corners[i].x * ((float) region.width / smallImage.cols)); float bigY = (corners[i].y * ((float) region.height / smallImage.rows)); - + bigX = bigX + region.x; bigY = bigY + region.y; - + cornerPoints.push_back(Point2f(bigX, bigY)); } - + return cornerPoints; } Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) { - + // Figure out the appoximate width/height of the license plate region, so we can maintain the aspect ratio. LineSegment leftEdge(round(corners[3].x), round(corners[3].y), round(corners[0].x), round(corners[0].y)); LineSegment rightEdge(round(corners[2].x), round(corners[2].y), round(corners[1].x), round(corners[1].y)); LineSegment topEdge(round(corners[0].x), round(corners[0].y), round(corners[1].x), round(corners[1].y)); LineSegment bottomEdge(round(corners[3].x), round(corners[3].y), round(corners[2].x), round(corners[2].y)); - + float w = distanceBetweenPoints(leftEdge.midpoint(), rightEdge.midpoint()); float h = distanceBetweenPoints(bottomEdge.midpoint(), topEdge.midpoint()); float aspect = w/h; - + int width = config->ocrImageWidthPx; int height = round(((float) width) / aspect); if (height > config->ocrImageHeightPx) @@ -137,9 +137,9 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) height = config->ocrImageHeightPx; width = round(((float) height) * aspect); } - + Mat deskewed(height, width, frame.type()); - + // Corners of the destination image vector quad_pts; quad_pts.push_back(Point2f(0, 0)); @@ -152,10 +152,10 @@ Mat LicensePlateCandidate::deSkewPlate(Mat inputImage, vector corners) // Apply perspective transformation warpPerspective(inputImage, deskewed, transmtx, deskewed.size()); - + if (this->config->debugGeneral) displayImage(config, "quadrilateral", deskewed); - + return deskewed; } @@ -164,13 +164,13 @@ void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage) { if (this->config->debugGeneral) cout << "LicensePlate::cleanupColors" << endl; - + //Mat normalized(inputImage.size(), inputImage.type()); - + Mat intermediate(inputImage.size(), inputImage.type()); - + normalize(inputImage, intermediate, 0, 255, CV_MINMAX ); - + // Equalize intensity: if(intermediate.channels() >= 3) { @@ -189,14 +189,14 @@ void LicensePlateCandidate::cleanupColors(Mat inputImage, Mat outputImage) //ycrcb.release(); } - - - bilateralFilter(intermediate, outputImage, 3, 25, 35); - - + + + bilateralFilter(intermediate, outputImage, 3, 25, 35); + + if (this->config->debugGeneral) { displayImage(config, "After cleanup", outputImage); } - + } diff --git a/src/openalpr/licenseplatecandidate.h b/src/openalpr/licenseplatecandidate.h index 25e002f..04ab72a 100644 --- a/src/openalpr/licenseplatecandidate.h +++ b/src/openalpr/licenseplatecandidate.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -54,28 +54,28 @@ class LicensePlateCandidate float confidence; // 0-100 //vector points; // top-left, top-right, bottom-right, bottom-left vector plateCorners; - + void recognize(); - + Mat deskewed; CharacterSegmenter* charSegmenter; private: - + Config* config; - - + + Mat frame; Rect plateRegion; - + void cleanupColors(Mat inputImage, Mat outputImage); Mat filterByCharacterHue(vector > charRegionContours); vector findPlateCorners(Mat inputImage, PlateLines plateLines, CharacterRegion charRegion); // top-left, top-right, bottom-right, bottom-left - + vector transformPointsToOriginalImage(Mat bigImage, Mat smallImage, Rect region, vector corners); Mat deSkewPlate(Mat inputImage, vector corners); }; -#endif // STAGE2_H \ No newline at end of file +#endif // STAGE2_H diff --git a/src/openalpr/ocr.cpp b/src/openalpr/ocr.cpp index 3ed962d..ff7be2a 100644 --- a/src/openalpr/ocr.cpp +++ b/src/openalpr/ocr.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -25,9 +25,9 @@ OCR::OCR(Config* config) { this->config = config; - + this->postProcessor = new PostProcess(config); - + tesseract=new TessBaseAPI(); // Tesseract requires the prefix directory to be set as an env variable @@ -35,11 +35,11 @@ OCR::OCR(Config* config) 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->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNPQRSTUVWXYZ1234567890"); tesseract->SetPageSegMode(PSM_SINGLE_CHAR); } @@ -53,56 +53,56 @@ OCR::~OCR() void OCR::performOCR(vector thresholds, vector charRegions) { - - + + timespec startTime; getTime(&startTime); - - + + postProcessor->clear(); - + for (int i = 0; i < thresholds.size(); i++) { - + // Make it black text on white background bitwise_not(thresholds[i], thresholds[i]); - tesseract->SetImage((uchar*) thresholds[i].data, thresholds[i].size().width, thresholds[i].size().height, thresholds[i].channels(), thresholds[i].step1()); - - + 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) ; - + tesseract->SetRectangle(expandedRegion.x, expandedRegion.y, expandedRegion.width, expandedRegion.height); tesseract->Recognize(NULL); - + tesseract::ResultIterator* ri = tesseract->GetIterator(); tesseract::PageIteratorLevel level = tesseract::RIL_SYMBOL; 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); - + 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) { @@ -110,36 +110,31 @@ void OCR::performOCR(vector thresholds, vector charRegions) 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) { timespec endTime; getTime(&endTime); cout << "OCR Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - - + + + } - - - - - diff --git a/src/openalpr/ocr.h b/src/openalpr/ocr.h index b0a7c35..90a28da 100644 --- a/src/openalpr/ocr.h +++ b/src/openalpr/ocr.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -25,7 +25,7 @@ #include #include - + #include "utility.h" #include "postprocess.h" #include "config.h" @@ -45,22 +45,22 @@ class OCR public: OCR(Config* config); virtual ~OCR(); - + void performOCR(vector thresholds, vector charRegions); - + PostProcess* postProcessor; //string recognizedText; //float confidence; //float overallConfidence; - - + + private: Config* config; - + TessBaseAPI *tesseract; - - - + + + }; diff --git a/src/openalpr/platecorners.cpp b/src/openalpr/platecorners.cpp index bd298b5..f8d2c43 100644 --- a/src/openalpr/platecorners.cpp +++ b/src/openalpr/platecorners.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,20 +23,20 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config) { this->config = config; - + if (this->config->debugPlateCorners) cout << "PlateCorners constructor" << endl; - - - + + + this->inputImage = inputImage; this->plateLines = plateLines; this->charRegion = charRegion; this->bestHorizontalScore = 9999999999999; this->bestVerticalScore = 9999999999999; - - + + Point topPoint = charRegion->getTopLine().midpoint(); Point bottomPoint = charRegion->getBottomLine().closestPointOnSegmentTo(topPoint); this->charHeight = distanceBetweenPoints(topPoint, bottomPoint); @@ -45,7 +45,7 @@ PlateCorners::PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegi //this->charHeight = this->charHeight - 2; // Adjust since this height is a box around our char. // Adjust the char height for the difference in size... //this->charHeight = ((float) inputImage.size().height / (float) TEMPLATE_PLATE_HEIGHT) * this->charHeight; - + this->charAngle = angleBetweenPoints(charRegion->getCharArea()[0], charRegion->getCharArea()[1]); } @@ -58,61 +58,61 @@ vector PlateCorners::findPlateCorners() { if (this->config->debugPlateCorners) cout << "PlateCorners::findPlateCorners" << endl; - + timespec startTime; getTime(&startTime); - + 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; - + this->scoreHorizontals(h1, h2); - + } } - + // 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; - + this->scoreVerticals(v1, v2); } } - - + + if (this->config->debugPlateCorners) { - + 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)); - - + + 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); + } - + // Check if a left/right edge has been established. if (bestLeft.p1.x == 0 && bestLeft.p1.y == 0 && bestLeft.p2.x == 0 && bestLeft.p2.y == 0) confidence = 0; @@ -120,49 +120,49 @@ vector PlateCorners::findPlateCorners() confidence = 0; else confidence = 100; - + vector corners; corners.push_back(bestTop.intersection(bestLeft)); corners.push_back(bestTop.intersection(bestRight)); corners.push_back(bestBottom.intersection(bestRight)); corners.push_back(bestBottom.intersection(bestLeft)); - - - + + + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << "Plate Corners Time: " << diffclock(startTime, endTime) << "ms." << endl; } - + return corners; } void PlateCorners::scoreVerticals(int v1, int v2) { - + float score = 0; // Lower is better - + 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 - + if (v1 == NO_LINE && v2 == NO_LINE) { //return; Point centerTop = charRegion->getCharBoxTop().midpoint(); Point centerBottom = charRegion->getCharBoxBottom().midpoint(); LineSegment centerLine = LineSegment(centerBottom.x, centerBottom.y, centerTop.x, centerTop.y); - + left = centerLine.getParallelLine(idealPixelWidth / 2); right = centerLine.getParallelLine(-1 * idealPixelWidth / 2 ); - + score += SCORING_MISSING_SEGMENT_PENALTY_VERTICAL * 2; } else if (v1 != NO_LINE && v2 != NO_LINE) @@ -182,109 +182,109 @@ void PlateCorners::scoreVerticals(int v1, int v2) right = left.getParallelLine(-1 * idealPixelWidth); 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; - + // Make sure this line is to the right of our license plate letters if (right.isPointBelowLine(charRegion->getCharBoxRight().midpoint())) return; - ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// // Score "Distance from the edge... - ///////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////// float leftDistanceFromEdge = abs((float) (left.p1.x + left.p2.x) / 2); float rightDistanceFromEdge = abs(this->inputImage.cols - ((float) (right.p1.x + right.p2.x) / 2)); - + float distanceFromEdge = leftDistanceFromEdge + rightDistanceFromEdge; score += distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT; - - ///////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////// // Score "Boxiness" of the 4 lines. How close is it to a parallelogram? - ///////////////////////////////////////////////////////////////////////// - + ///////////////////////////////////////////////////////////////////////// + float verticalAngleDiff = abs(left.angle - right.angle); - + 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()); - + float plateDistance = abs(idealPixelWidth - distanceBetweenPoints(leftMidLinePoint, rightMidLinePoint)); - + score += plateDistance * SCORING_VERTICALDISTANCE_WEIGHT; - + if (score < this->bestVerticalScore) { float scorecomponent; - - + + if (this->config->debugPlateCorners) { - cout << "xx xx Score: charHeight " << this->charHeight << endl; - cout << "xx xx Score: idealwidth " << idealPixelWidth << endl; - cout << "xx xx Score: v1,v2= " << v1 << "," << v2 << endl; - cout << "xx xx Score: Left= " << left.str() << endl; - cout << "xx xx Score: Right= " << right.str() << endl; - + cout << "xx xx Score: charHeight " << this->charHeight << endl; + cout << "xx xx Score: idealwidth " << idealPixelWidth << endl; + cout << "xx xx Score: v1,v2= " << v1 << "," << v2 << endl; + cout << "xx xx Score: Left= " << left.str() << endl; + cout << "xx xx Score: Right= " << right.str() << endl; + cout << "Vertical breakdown Score:" << endl; cout << " -- Boxiness Score: " << verticalAngleDiff << " -- Weight (" << SCORING_BOXINESS_WEIGHT << ")" << endl; - scorecomponent = verticalAngleDiff * SCORING_BOXINESS_WEIGHT; + scorecomponent = verticalAngleDiff * SCORING_BOXINESS_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Distance From Edge Score: " << distanceFromEdge << " -- Weight (" << SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT << ")" << endl; - scorecomponent = distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT; + scorecomponent = distanceFromEdge * SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Distance Score: " << plateDistance << " -- Weight (" << SCORING_VERTICALDISTANCE_WEIGHT << ")" << endl; - scorecomponent = plateDistance * SCORING_VERTICALDISTANCE_WEIGHT; + scorecomponent = plateDistance * SCORING_VERTICALDISTANCE_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Score: " << score << endl; } - + this->bestVerticalScore = score; bestLeft = LineSegment(left.p1.x, left.p1.y, left.p2.x, left.p2.y); bestRight = LineSegment(right.p1.x, right.p1.y, right.p2.x, right.p2.y); } - + } -// Score a collection of lines as a possible license plate region. +// Score a collection of lines as a possible license plate region. // If any segments are missing, extrapolate the missing pieces void PlateCorners::scoreHorizontals(int h1, int h2) { - + //if (this->debug) // cout << "PlateCorners::scorePlate" << endl; - + float score = 0; // Lower is better - + LineSegment top; LineSegment bottom; - + float charHeightToPlateHeightRatio = config->plateHeightMM / config->charHeightMM; - float idealPixelHeight = this->charHeight * charHeightToPlateHeightRatio; - - + float idealPixelHeight = this->charHeight * charHeightToPlateHeightRatio; + + if (h1 == NO_LINE && h2 == NO_LINE) { // return; Point centerLeft = charRegion->getCharBoxLeft().midpoint(); Point centerRight = charRegion->getCharBoxRight().midpoint(); LineSegment centerLine = LineSegment(centerLeft.x, centerLeft.y, centerRight.x, centerRight.y); - + top = centerLine.getParallelLine(idealPixelHeight / 2); bottom = centerLine.getParallelLine(-1 * idealPixelHeight / 2 ); @@ -307,141 +307,141 @@ void PlateCorners::scoreHorizontals(int h1, int h2) bottom = top.getParallelLine(-1 * idealPixelHeight); 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 - ////////////////////////////////////////////////////////////////////////// - + ////////////////////////////////////////////////////////////////////////// + Point topPoint = top.midpoint(); Point botPoint = bottom.closestPointOnSegmentTo(topPoint); float plateHeightPx = distanceBetweenPoints(topPoint, botPoint); - + // 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) float heightRatioDiff = abs(heightRatio - idealHeightRatio); // Ideal ratio == ~.45 - + // Get the distance from the top and the distance from the bottom // Take the average distances from the corners of the character region to the top/bottom lines // float topDistance = distanceBetweenPoints(topMidLinePoint, charRegion->getCharBoxTop().midpoint()); // float bottomDistance = distanceBetweenPoints(bottomMidLinePoint, charRegion->getCharBoxBottom().midpoint()); - + // float idealTopDistance = charHeight * (TOP_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM); // float idealBottomDistance = charHeight * (BOTTOM_WHITESPACE_HEIGHT_MM / CHARACTER_HEIGHT_MM); // float distScore = abs(topDistance - idealTopDistance) + abs(bottomDistance - idealBottomDistance); - - + + score += heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT; - - ////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////// // SCORE the middliness of the stuff. We want our top and bottom line to have the characters right towards the middle - ////////////////////////////////////////////////////////////////////////// - + ////////////////////////////////////////////////////////////////////////// + Point charAreaMidPoint = charRegion->getCharBoxLeft().midpoint(); Point topLineSpot = top.closestPointOnSegmentTo(charAreaMidPoint); Point botLineSpot = bottom.closestPointOnSegmentTo(charAreaMidPoint); - + float topDistanceFromMiddle = distanceBetweenPoints(topLineSpot, charAreaMidPoint); float bottomDistanceFromMiddle = distanceBetweenPoints(topLineSpot, charAreaMidPoint); - + float idealDistanceFromMiddle = idealPixelHeight / 2; - + float middleScore = abs(topDistanceFromMiddle - idealDistanceFromMiddle) + abs(bottomDistanceFromMiddle - idealDistanceFromMiddle); score += middleScore * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT; - + // if (this->debug) // { // cout << "PlateCorners boxiness score: " << avgRatio * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT << endl; // cout << "PlateCorners boxiness score: " << distScore * SCORING_PLATEHEIGHT_WEIGHT << endl; // } - ////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////// // SCORE: the shape for angles matching the character region - ////////////////////////////////////////////////////////////// - + ////////////////////////////////////////////////////////////// + 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; - + if (this->config->debugPlateCorners) { - cout << "xx xx Score: charHeight " << this->charHeight << endl; - cout << "xx xx Score: idealHeight " << idealPixelHeight << endl; - cout << "xx xx Score: h1,h2= " << h1 << "," << h2 << endl; - cout << "xx xx Score: Top= " << top.str() << endl; - cout << "xx xx Score: Bottom= " << bottom.str() << endl; - + cout << "xx xx Score: charHeight " << this->charHeight << endl; + cout << "xx xx Score: idealHeight " << idealPixelHeight << endl; + cout << "xx xx Score: h1,h2= " << h1 << "," << h2 << endl; + cout << "xx xx Score: Top= " << top.str() << endl; + cout << "xx xx Score: Bottom= " << bottom.str() << endl; + cout << "Horizontal breakdown Score:" << endl; cout << " -- Boxiness Score: " << horizontalAngleDiff << " -- Weight (" << SCORING_BOXINESS_WEIGHT << ")" << endl; - scorecomponent = horizontalAngleDiff * SCORING_BOXINESS_WEIGHT; + scorecomponent = horizontalAngleDiff * SCORING_BOXINESS_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Height Ratio Diff Score: " << heightRatioDiff << " -- Weight (" << SCORING_PLATEHEIGHT_WEIGHT << ")" << endl; - scorecomponent = heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT; + scorecomponent = heightRatioDiff * SCORING_PLATEHEIGHT_WEIGHT; cout << " -- -- " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Distance Score: " << middleScore << " -- Weight (" << SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT << ")" << endl; - scorecomponent = middleScore * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT; + scorecomponent = middleScore * SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Char angle Score: " << charanglediff << " -- Weight (" << SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT << ")" << endl; - scorecomponent = charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT; + scorecomponent = charanglediff * SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT; cout << " -- -- Score: " << scorecomponent << " = " << scorecomponent / score * 100 << "% of score" << endl; - + cout << " -- Score: " << score << endl; } this->bestHorizontalScore = score; bestTop = LineSegment(top.p1.x, top.p1.y, top.p2.x, top.p2.y); bestBottom = LineSegment(bottom.p1.x, bottom.p1.y, bottom.p2.x, bottom.p2.y); } - - - + + + } diff --git a/src/openalpr/platecorners.h b/src/openalpr/platecorners.h index e10bb32..ff068cf 100644 --- a/src/openalpr/platecorners.h +++ b/src/openalpr/platecorners.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -36,13 +36,13 @@ using namespace std; #define SCORING_MISSING_SEGMENT_PENALTY_VERTICAL 10 #define SCORING_MISSING_SEGMENT_PENALTY_HORIZONTAL 15 -#define SCORING_BOXINESS_WEIGHT 0.8 -#define SCORING_PLATEHEIGHT_WEIGHT 2.2 -#define SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT 0.05 -#define SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT 1.1 -#define SCORING_VERTICALDISTANCE_WEIGHT 0.1 +#define SCORING_BOXINESS_WEIGHT 0.8 +#define SCORING_PLATEHEIGHT_WEIGHT 2.2 +#define SCORING_TOP_BOTTOM_SPACE_VS_CHARHEIGHT_WEIGHT 0.05 +#define SCORING_ANGLE_MATCHES_LPCHARS_WEIGHT 1.1 +#define SCORING_VERTICALDISTANCE_WEIGHT 0.1 -#define SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT 0.05 +#define SCORING_VERTICALDISTANCE_FROMEDGE_WEIGHT 0.05 class PlateCorners { @@ -50,33 +50,31 @@ class PlateCorners public: PlateCorners(Mat inputImage, PlateLines* plateLines, CharacterRegion* charRegion, Config* config); virtual ~PlateCorners(); - + vector findPlateCorners(); - + float confidence; - + private: - + Config* config; Mat inputImage; float charHeight; float charAngle; - + float bestHorizontalScore; float bestVerticalScore; LineSegment bestTop; LineSegment bestBottom; LineSegment bestLeft; LineSegment bestRight; - + PlateLines* plateLines; CharacterRegion* charRegion; - + void scoreHorizontals( int h1, int h2 ); void scoreVerticals( int v1, int v2 ); - + }; #endif // PLATELINES_H - - diff --git a/src/openalpr/platelines.cpp b/src/openalpr/platelines.cpp index c07d297..f19e05b 100644 --- a/src/openalpr/platelines.cpp +++ b/src/openalpr/platelines.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -24,10 +24,10 @@ PlateLines::PlateLines(Config* config) { this->config = config; this->debug = config->debugPlateLines; - + if (debug) cout << "PlateLines constructor" << endl; - + } @@ -36,18 +36,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; @@ -55,31 +55,31 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) 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 ); - + morph_size = 1; element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) ); - + //morphologyEx( thresholded, thresholded, MORPH_GRADIENT, element ); - + morph_size = 1; 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 hlines = this->getLines(edges, sensitivity, false); vector vlines = this->getLines(edges, sensitivity, true); for (int i = 0; i < hlines.size(); i++) this->horizontalLines.push_back(hlines[i]); for (int i = 0; i < vlines.size(); i++) this->verticalLines.push_back(vlines[i]); - - - + + + // if debug is enabled, draw the image if (this->debug) @@ -90,27 +90,27 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) edges.copyTo(debugImgVert); cvtColor(debugImgHoriz,debugImgHoriz,CV_GRAY2BGR); cvtColor(debugImgVert,debugImgVert,CV_GRAY2BGR); - + for( size_t i = 0; i < this->horizontalLines.size(); i++ ) { line( debugImgHoriz, this->horizontalLines[i].p1, this->horizontalLines[i].p2, Scalar(0,0,255), 1, CV_AA); } - + for( size_t i = 0; i < this->verticalLines.size(); i++ ) { line( debugImgVert, this->verticalLines[i].p1, this->verticalLines[i].p2, Scalar(0,0,255), 1, CV_AA); } - + vector images; images.push_back(debugImgHoriz); images.push_back(debugImgVert); - + Mat dashboard = drawImageDashboard(images, debugImgVert.type(), 1); displayImage(config, "Hough Lines", dashboard); } - - + + if (config->debugTiming) { timespec endTime; @@ -118,27 +118,27 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) cout << "Plate Lines Time: " << diffclock(startTime, endTime) << "ms." << endl; } //smoothed.release(); - - + + //////////////// METHOD2!!!!!!!//////////////////// - + /* Mat imgBlur; Mat imgCanny; GaussianBlur(inputImage, imgBlur, Size(9, 9), 1, 1); - - - Canny(imgBlur, imgCanny, 10, 30, 3); - - - + + + 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 @@ -147,26 +147,26 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) 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 - + displayImage(config, "Blurred", imgCanny); displayImage(config, "Blurred Contours", imgShaped); - + vector shapeRects( biggestShapes.size() ); - + vector >hull( biggestShapes.size() ); for( int i = 0; i < biggestShapes.size(); i++ ) - { + { //approxPolyDP( Mat(biggestShapes[i]), shapeRects[i], 3, true ); convexHull( biggestShapes[i], hull[i], false ); //approxPolyDP( biggestShapes[i], hull[i], 10, true ); - + //minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] ); } */ @@ -176,21 +176,21 @@ void PlateLines::processImage(Mat inputImage, float sensitivity) /* vector PlateLines::getLines(Mat edges, bool vertical) { - + vector filteredLines; - + int sensitivity; - + LSWMS lswms(Size(edges.cols, edges.rows), 3, 155, false); - + vector lsegs; vector errors; lswms.run(edges, lsegs, errors); - - + + for( size_t i = 0; i < lsegs.size(); i++ ) { - + if (vertical) { LineSegment candidate; @@ -198,13 +198,13 @@ vector PlateLines::getLines(Mat edges, bool vertical) candidate = LineSegment(lsegs[i][0].x, lsegs[i][0].y, lsegs[i][1].x, lsegs[i][1].y); else candidate = LineSegment(lsegs[i][1].x, lsegs[i][1].y, lsegs[i][0].x, lsegs[i][0].y); - + cout << "VERT Angle: " << candidate.angle << endl; //if ((candidate.angle > 70 && candidate.angle < 110) || (candidate.angle > 250 && candidate.angle < 290)) //{ // good vertical filteredLines.push_back(candidate); - + //} } else @@ -215,26 +215,26 @@ vector PlateLines::getLines(Mat edges, bool vertical) else candidate = LineSegment(lsegs[i][1].x, lsegs[i][1].y, lsegs[i][0].x, lsegs[i][0].y); cout << "HORIZAngle: " << candidate.angle << endl; - + //if ( (candidate.angle > -20 && candidate.angle < 20) || (candidate.angle > 160 && candidate.angle < 200)) //{ // good horizontal filteredLines.push_back(candidate); - + //} } } - + // if debug is enabled, draw the image if (this->debug) { Mat debugImg(edges.size(), edges.type()); edges.copyTo(debugImg); cvtColor(debugImg,debugImg,CV_GRAY2BGR); - + for( size_t i = 0; i < filteredLines.size(); i++ ) { - + line( debugImg, filteredLines[i].p1, filteredLines[i].p2, Scalar(0,0,255), 1, CV_AA); } if (vertical) @@ -242,7 +242,7 @@ vector PlateLines::getLines(Mat edges, bool vertical) else displayImage(config, "Lines Horizontal", debugImg); } - + return filteredLines; } */ @@ -252,47 +252,47 @@ vector PlateLines::getLines(Mat edges, float sensitivityMultiplier, { if (this->debug) cout << "PlateLines::getLines" << endl; - + static int HORIZONTAL_SENSITIVITY = config->plateLinesSensitivityHorizontal; static int VERTICAL_SENSITIVITY = config->plateLinesSensitivityVertical; - + vector allLines; vector filteredLines; - + int sensitivity; if (vertical) sensitivity = VERTICAL_SENSITIVITY * (1.0 / sensitivityMultiplier); else sensitivity = HORIZONTAL_SENSITIVITY * (1.0 / 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; - + 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 - + 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); @@ -304,28 +304,28 @@ vector PlateLines::getLines(Mat edges, float sensitivityMultiplier, } else { - + 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); - + // 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)); } } } - - + + return filteredLines; } @@ -337,11 +337,11 @@ 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 ); - + for (int row = 0; row < img_hsv.rows; row++) { for (int col = 0; col < img_hsv.cols; col++) @@ -349,18 +349,18 @@ Mat PlateLines::customGrayscaleConversion(Mat src) int h = (int) img_hsv.at(row, col)[0]; int s = (int) img_hsv.at(row, col)[1]; int v = (int) img_hsv.at(row, col)[2]; - + int pixval = pow(v, 1.05); - - + + if (pixval > 255) pixval = 255; grayscale.at(row, col) = pixval; - + hue.at(row, col) = h * (255.0 / 180.0); } } - + //displayImage(config, "Hue", hue); return grayscale; -} \ No newline at end of file +} diff --git a/src/openalpr/platelines.h b/src/openalpr/platelines.h index 70170e1..51cdbaf 100644 --- a/src/openalpr/platelines.h +++ b/src/openalpr/platelines.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -38,24 +38,22 @@ class PlateLines public: PlateLines(Config* config); virtual ~PlateLines(); - + void processImage(Mat img, float sensitivity=1.0); vector horizontalLines; vector verticalLines; - + vector winningCorners; - + private: Config* config; bool debug; - - + + Mat customGrayscaleConversion(Mat src); void findLines(Mat inputImage); vector getLines(Mat edges, float sensitivityMultiplier, bool vertical); }; #endif // PLATELINES_H - - diff --git a/src/openalpr/postprocess.cpp b/src/openalpr/postprocess.cpp index 2ff1124..6501810 100644 --- a/src/openalpr/postprocess.cpp +++ b/src/openalpr/postprocess.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -23,19 +23,19 @@ PostProcess::PostProcess(Config* config) { this->config = config; - + stringstream filename; filename << config->getPostProcessRuntimeDir() << "/" << config->country << ".patterns"; - + 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; - + if (rules.find(region) == rules.end()) { vector newRule; @@ -49,7 +49,7 @@ PostProcess::PostProcess(Config* config) rules[region] = oldRule; } } - + //vector test = rules["base"]; //for (int i = 0; i < test.size(); i++) // cout << "Rule: " << test[i].regex << endl; @@ -66,7 +66,7 @@ PostProcess::~PostProcess() { delete iter->second[i]; } - + } } @@ -75,28 +75,28 @@ void PostProcess::addLetter(char letter, int charposition, float score) { if (score < config->postProcessMinConfidence) return; - + insertLetter(letter, charposition, score); - + if (score < config->postProcessConfidenceSkipLevel) { float adjustedScore = abs(config->postProcessConfidenceSkipLevel - score) + config->postProcessMinConfidence; insertLetter(SKIP_CHAR, charposition, adjustedScore ); } - + //if (letter == '0') //{ // insertLetter('O', charposition, score - 0.5); //} - + } void PostProcess::insertLetter(char letter, int charposition, float score) { - + score = score - config->postProcessMinConfidence; - - + + int existingIndex = -1; if (letters.size() < charposition + 1) { @@ -106,7 +106,7 @@ void PostProcess::insertLetter(char letter, int charposition, float score) letters.push_back(tmp); } } - + for (int i = 0; i < letters[charposition].size(); i++) { if (letters[charposition][i].letter == letter && @@ -116,7 +116,7 @@ void PostProcess::insertLetter(char letter, int charposition, float score) break; } } - + if (existingIndex == -1) { Letter newLetter; @@ -131,7 +131,7 @@ void PostProcess::insertLetter(char letter, int charposition, float score) letters[charposition][existingIndex].occurences = letters[charposition][existingIndex].occurences + 1; letters[charposition][existingIndex].totalscore = letters[charposition][existingIndex].totalscore + score; } - + } @@ -142,23 +142,23 @@ void PostProcess::clear() letters[i].clear(); } letters.resize(0); - + unknownCharPositions.clear(); unknownCharPositions.resize(0); allPossibilities.clear(); //allPossibilities.resize(0); - + bestChars = ""; matchesTemplate = false; } 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--) { @@ -167,38 +167,38 @@ void PostProcess::analyze(string templateregion, int topn) unknownCharPositions.push_back(i); } } - - + + if (letters.size() == 0) return; - - + + // Sort the letters as they are for (int i = 0; i < letters.size(); i++) { if (letters[i].size() > 0) sort(letters[i].begin(), letters[i].end(), letterCompare); } - - - + + + if (this->config->debugPostProcess) { - + // Print all letters for (int i = 0; i < letters.size(); i++) { for (int j = 0; j < letters[i].size(); j++) cout << "PostProcess Letter: " << letters[i][j].charposition << " " << letters[i][j].letter << " -- score: " << letters[i][j].totalscore << " -- occurences: " << letters[i][j].occurences << endl; } - + } // Prune the letters based on the topN value. // If our topN value is 3, for example, we can get rid of a lot of low scoring letters // because it would be impossible for them to be a part of our topN results. vector maxDepth = getMaxDepth(topn); - + for (int i = 0; i < letters.size(); i++) { for (int k = letters[i].size() - 1; k > maxDepth[i]; k--) @@ -206,37 +206,37 @@ void PostProcess::analyze(string templateregion, int topn) letters[i].erase(letters[i].begin() + k); } } - + //getTopN(); vector tmp; findAllPermutations(tmp, 0, config->postProcessMaxSubstitutions); - - + + timespec sortStartTime; getTime(&sortStartTime); - + int numelements = topn; if (allPossibilities.size() < topn) numelements = allPossibilities.size() - 1; - + partial_sort( allPossibilities.begin(), allPossibilities.begin() + numelements, allPossibilities.end(), wordCompare ); - + if (config->debugTiming) { timespec sortEndTime; getTime(&sortEndTime); cout << " -- PostProcess Sort Time: " << diffclock(sortStartTime, sortEndTime) << "ms." << endl; } - - + + matchesTemplate = false; - - + + if (templateregion != "") { vector regionRules = rules[templateregion]; - + for (int i = 0; i < allPossibilities.size(); i++) { for (int j = 0; j < regionRules.size(); j++) @@ -250,16 +250,16 @@ void PostProcess::analyze(string templateregion, int topn) break; } } - - - + + + if (i >= topn - 1) break; //if (matchesTemplate || i >= TOP_N - 1) //break; } } - + if (matchesTemplate) { for (int z = 0; z < allPossibilities.size(); z++) @@ -275,26 +275,26 @@ void PostProcess::analyze(string templateregion, int topn) { bestChars = allPossibilities[0].letters; } - + // Now adjust the confidence scores to a percentage value if (allPossibilities.size() > 0) { float maxPercentScore = calculateMaxConfidenceScore(); float highestRelativeScore = (float) allPossibilities[0].totalscore; - + for (int i = 0; i < allPossibilities.size(); i++) { allPossibilities[i].totalscore = maxPercentScore * (allPossibilities[i].totalscore / highestRelativeScore); } - + } - - - + + + if (this->config->debugPostProcess) { - - + + // Print top words for (int i = 0; i < allPossibilities.size(); i++) { @@ -302,22 +302,22 @@ void PostProcess::analyze(string templateregion, int topn) if (allPossibilities[i].letters == bestChars) cout << " <--- "; cout << endl; - + if (i >= topn - 1) break; } cout << allPossibilities.size() << " total permutations" << endl; } - - + + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << "PostProcess Time: " << diffclock(startTime, endTime) << "ms." << endl; } - + if (this->config->debugPostProcess) cout << "PostProcess Analysis Complete: " << bestChars << " -- MATCH: " << matchesTemplate << endl; } @@ -325,7 +325,7 @@ void PostProcess::analyze(string templateregion, int topn) float PostProcess::calculateMaxConfidenceScore() { // Take the best score for each char position and average it. - + float totalScore = 0; int numScores = 0; // Get a list of missing positions @@ -337,15 +337,15 @@ float PostProcess::calculateMaxConfidenceScore() numScores++; } } - + if (numScores == 0) return 0; - + return totalScore / ((float) numScores); } // Finds the minimum number of letters to include in the recursive sorting algorithm. -// For example, if I have letters +// For example, if I have letters // A-200 B-100 C-100 // X-99 Y-95 Z-90 // Q-55 R-80 @@ -356,23 +356,23 @@ float PostProcess::calculateMaxConfidenceScore() // Y-95 Z-90 vector PostProcess::getMaxDepth(int topn) { - + vector depth; for (int i = 0; i < letters.size(); i++) depth.push_back(0); - + int nextLeastDropCharPos = getNextLeastDrop(depth); while (nextLeastDropCharPos != -1) { if (getPermutationCount(depth) >= topn) break; - + depth[nextLeastDropCharPos] = depth[nextLeastDropCharPos] + 1; - + nextLeastDropCharPos = getNextLeastDrop(depth); } - - + + return depth; } @@ -383,7 +383,7 @@ int PostProcess::getPermutationCount(vector depth) { permutationCount *= (depth[i] + 1); } - + return permutationCount; } @@ -391,21 +391,21 @@ int PostProcess::getNextLeastDrop(vector depth) { int nextLeastDropCharPos = -1; float leastNextDrop = 99999999999; - + 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) { nextLeastDropCharPos = i; leastNextDrop = drop; } } - + return nextLeastDropCharPos; } @@ -416,14 +416,14 @@ const vector PostProcess::getResults() void PostProcess::findAllPermutations(vector prevletters, int charPos, int substitutionsLeft) { - + if (substitutionsLeft < 0) return; - + // Add my letter to the chain and recurse for (int i = 0; i < letters[charPos].size(); i++) { - + if (charPos == letters.size() - 1) { // Last letter, add the word @@ -437,27 +437,27 @@ void PostProcess::findAllPermutations(vector prevletters, int charPos, i 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; - + allPossibilities.push_back(possibility); } else { prevletters.push_back(letters[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); else findAllPermutations(prevletters, charPos + 1, substitutionsLeft); - + prevletters.pop_back(); } } - + if (letters[charPos].size() == 0) { // No letters for this char position... @@ -465,8 +465,8 @@ void PostProcess::findAllPermutations(vector prevletters, int charPos, i findAllPermutations(prevletters, charPos + 1, substitutionsLeft); } - - + + } @@ -491,7 +491,7 @@ RegexRule::RegexRule(string region, string pattern) { this->original = pattern; this->region = region; - + numchars = 0; for (int i = 0; i < pattern.size(); i++) { @@ -503,7 +503,7 @@ RegexRule::RegexRule(string region, string pattern) i++; } this->regex = this->regex + ']'; - + } else if (pattern.at(i) == '?') { @@ -518,12 +518,12 @@ RegexRule::RegexRule(string region, string pattern) { this->regex = this->regex + "\\d"; } - + numchars++; } - + trexp.Compile(this->regex.c_str()); - + //cout << "AA " << this->region << ": " << original << " regex: " << regex << endl; //for (int z = 0; z < this->skipPositions.size(); z++) // cout << "AA Skip position: " << skipPositions[z] << endl; @@ -534,7 +534,7 @@ bool RegexRule::match(string text) { if (text.length() != numchars) return false; - + return trexp.Match(text.c_str()); } @@ -552,10 +552,10 @@ string RegexRule::filterSkips(string text) break; } } - + if (skip == false) response = response + text[i]; } - + return response; } diff --git a/src/openalpr/postprocess.h b/src/openalpr/postprocess.h index 2f4438a..78a3377 100644 --- a/src/openalpr/postprocess.h +++ b/src/openalpr/postprocess.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -35,7 +35,7 @@ using namespace std; #define SKIP_CHAR '~' -struct Letter +struct Letter { char letter; int charposition; @@ -60,10 +60,10 @@ class RegexRule public: RegexRule(string region, string pattern); - + bool match(string text); string filterSkips(string text); - + private: int numchars; TRexpp trexp; @@ -79,34 +79,34 @@ class PostProcess public: PostProcess(Config* config); ~PostProcess(); - + void addLetter(char letter, int charposition, float score); - + void clear(); void analyze(string templateregion, int topn); - + string bestChars; bool matchesTemplate; - + const vector getResults(); - + private: Config* config; //void getTopN(); void findAllPermutations(vector prevletters, int charPos, int substitutionsLeft); - + void insertLetter(char letter, int charPosition, float score); - + map > rules; - + float calculateMaxConfidenceScore(); - + vector > letters; vector unknownCharPositions; - - + + vector allPossibilities; - + // Functions used to prune the list of letters (based on topn) to improve performance vector getMaxDepth(int topn); int getPermutationCount(vector depth); @@ -118,18 +118,18 @@ class LetterScores { public: LetterScores(int numCharPositions); - + void addScore(char letter, int charposition, float score); - + vector getBestScore(); float getConfidence(); - + private: int numCharPositions; - + vector letters; vector charpositions; vector scores; }; */ -#endif // POSTPROCESS_H \ No newline at end of file +#endif // POSTPROCESS_H diff --git a/src/openalpr/regiondetector.cpp b/src/openalpr/regiondetector.cpp index 9839da8..3394d8e 100644 --- a/src/openalpr/regiondetector.cpp +++ b/src/openalpr/regiondetector.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -27,18 +27,18 @@ 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(); + 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; @@ -46,11 +46,11 @@ RegionDetector::RegionDetector(Config* config) else { this->loaded = false; - printf("--(!)Error loading classifier\n"); + printf("--(!)Error loading classifier\n"); } - - + + } RegionDetector::~RegionDetector() @@ -68,10 +68,10 @@ bool RegionDetector::isLoaded() vector RegionDetector::detect(Mat frame) { - + Mat frame_gray; cvtColor( frame, frame_gray, CV_BGR2GRAY ); - + vector regionsOfInterest = doCascade(frame_gray); return regionsOfInterest; @@ -84,19 +84,19 @@ vector RegionDetector::doCascade(Mat frame) //float scale_factor = 1; int w = frame.size().width; int h = frame.size().height; - + vector plates; equalizeHist( frame, frame ); resize(frame, frame, Size(w * this->scale_factor, h * this->scale_factor)); - + //-- Detect plates 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); - + if (config->opencl_enabled) { ocl::oclMat openclFrame(frame); @@ -104,14 +104,14 @@ vector RegionDetector::doCascade(Mat frame) } else { - - plate_cascade->detectMultiScale( frame, plates, 1.1, 3, + + plate_cascade->detectMultiScale( frame, plates, 1.1, 3, 0, //0|CV_HAAR_SCALE_IMAGE, minSize, maxSize ); } - - + + if (config->debugTiming) { timespec endTime; @@ -120,15 +120,15 @@ vector RegionDetector::doCascade(Mat frame) } - + 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; + plates[i].height = plates[i].height / scale_factor; } - - return plates; + + return plates; } diff --git a/src/openalpr/regiondetector.h b/src/openalpr/regiondetector.h index 561934c..45b0242 100644 --- a/src/openalpr/regiondetector.h +++ b/src/openalpr/regiondetector.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -25,7 +25,7 @@ #include #include - + #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/core/core.hpp" @@ -36,10 +36,10 @@ #include "support/timing.h" #include "constants.h" - - - + + + class RegionDetector { @@ -52,17 +52,17 @@ class RegionDetector private: Config* config; - + float scale_factor; CascadeClassifier* plate_cascade; - + bool loaded; - + vector doCascade(Mat frame); }; - - + + #endif // REGIONDETECTOR_H diff --git a/src/openalpr/simpleini/CMakeLists.txt b/src/openalpr/simpleini/CMakeLists.txt index 36baec2..4514cd9 100644 --- a/src/openalpr/simpleini/CMakeLists.txt +++ b/src/openalpr/simpleini/CMakeLists.txt @@ -4,5 +4,5 @@ set(simpleini_source_files ConvertUTF.c ) - -add_library(simpleini ${simpleini_source_files}) \ No newline at end of file + +add_library(simpleini ${simpleini_source_files}) diff --git a/src/openalpr/simpleini/ConvertUTF.c b/src/openalpr/simpleini/ConvertUTF.c index 9b3deeb..20b7edc 100644 --- a/src/openalpr/simpleini/ConvertUTF.c +++ b/src/openalpr/simpleini/ConvertUTF.c @@ -1,8 +1,8 @@ /* * Copyright 2001-2004 Unicode, Inc. - * + * * Disclaimer - * + * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine @@ -10,9 +10,9 @@ * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. - * + * * Limitations on Rights to Redistribute This Code - * + * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form @@ -59,7 +59,7 @@ static const UTF32 halfMask = 0x3FFUL; /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; @@ -108,7 +108,7 @@ ConversionResult ConvertUTF32toUTF16 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; @@ -187,7 +187,7 @@ static const char trailingBytesForUTF8[256] = { * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* @@ -212,7 +212,7 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF16* source = *sourceStart; @@ -221,7 +221,7 @@ ConversionResult ConvertUTF16toUTF8 ( UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; + const UTF32 byteMark = 0x80; const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ @@ -334,7 +334,7 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; @@ -407,7 +407,7 @@ ConversionResult ConvertUTF8toUTF16 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF32* source = *sourceStart; @@ -416,7 +416,7 @@ ConversionResult ConvertUTF32toUTF8 ( UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; + const UTF32 byteMark = 0x80; ch = *source++; if (flags == strictConversion ) { /* UTF-16 surrogate values are illegal in UTF-32 */ @@ -438,7 +438,7 @@ ConversionResult ConvertUTF32toUTF8 ( ch = UNI_REPLACEMENT_CHAR; result = sourceIllegal; } - + target += bytesToWrite; if (target > targetEnd) { --source; /* Back up source pointer! */ @@ -460,7 +460,7 @@ ConversionResult ConvertUTF32toUTF8 ( /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { ConversionResult result = conversionOK; const UTF8* source = *sourceStart; diff --git a/src/openalpr/simpleini/ConvertUTF.h b/src/openalpr/simpleini/ConvertUTF.h index 14d7b70..558383b 100644 --- a/src/openalpr/simpleini/ConvertUTF.h +++ b/src/openalpr/simpleini/ConvertUTF.h @@ -1,8 +1,8 @@ /* * Copyright 2001-2004 Unicode, Inc. - * + * * Disclaimer - * + * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine @@ -10,9 +10,9 @@ * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. - * + * * Limitations on Rights to Redistribute This Code - * + * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form @@ -33,7 +33,7 @@ Each routine converts the text between *sourceStart and sourceEnd, putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. + targetEnd. Note: the end pointers are *after* the last item: e.g. *(sourceEnd - 1) is the last item. The return result indicates whether the conversion was successful, @@ -71,7 +71,7 @@ sequence is malformed. When "sourceIllegal" is returned, the source value will point to the illegal value that caused the problem. E.g., in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. + malformed sequence. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. @@ -117,27 +117,27 @@ extern "C" { #endif ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - + ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - + ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); diff --git a/src/openalpr/simpleini/README.md b/src/openalpr/simpleini/README.md index 2e0d25e..f0d4dd5 100644 --- a/src/openalpr/simpleini/README.md +++ b/src/openalpr/simpleini/README.md @@ -78,14 +78,14 @@ ini.GetAllKeys("section-name", keys); ```c++ // get the value of a key -const char * pszValue = ini.GetValue("section-name", +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 +// 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", +pszValue = ini.GetValue("section-name", "key-name", NULL /*default*/, &bHasMultipleValues); // get all values of a key with multiple values @@ -97,7 +97,7 @@ values.sort(CSimpleIniA::Entry::LoadOrder()); // output all of the items CSimpleIniA::TNamesDepend::const_iterator i; -for (i = values.begin(); i != values.end(); ++i) { +for (i = values.begin(); i != values.end(); ++i) { printf("key-name = '%s'\n", i->pItem); } ``` @@ -108,20 +108,20 @@ for (i = values.begin(); i != values.end(); ++i) { // adding a new section rc = ini.SetValue("new-section", NULL, NULL); if (rc < 0) return false; -printf("section: %s\n", rc == SI_INSERTED ? +printf("section: %s\n", rc == SI_INSERTED ? "inserted" : "updated"); -// adding a new key ("new-section" will be added +// 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 ? +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 ? +printf("key: %s\n", rc == SI_INSERTED ? "inserted" : "updated"); ``` @@ -130,7 +130,7 @@ printf("key: %s\n", rc == SI_INSERTED ? ```c++ // deleting a key from a section. Optionally the entire // section may be deleted if it is now empty. -ini.Delete("section-name", "key-name", +ini.Delete("section-name", "key-name", true /*delete the section if empty*/); // deleting an entire section and all keys in it diff --git a/src/openalpr/simpleini/ini.syn b/src/openalpr/simpleini/ini.syn index b9c9d01..6ee539e 100644 --- a/src/openalpr/simpleini/ini.syn +++ b/src/openalpr/simpleini/ini.syn @@ -1,5 +1,5 @@ ; Syntax file for ini files - contributed by Brodie Thiesfield -; +; ; Suggested Colors: ; Comments (;#) Comments, Comments 2 Green ; Sections Characters Red @@ -13,24 +13,24 @@ IgnoreCase = Yes KeyWordLength = 1 BracketChars = OperatorChars = -PreprocStart = +PreprocStart = SyntaxStart = SyntaxEnd = HexPrefix = -CommentStart = -CommentEnd = -CommentStartAlt = -CommentEndAlt = +CommentStart = +CommentEnd = +CommentStartAlt = +CommentEndAlt = SingleComment = # SingleCommentCol = SingleCommentAlt = ; SingleCommentColAlt = SingleCommentEsc = StringsSpanLines = No -StringStart = -StringEnd = +StringStart = +StringEnd = StringAlt = = -StringEsc = +StringEsc = CharStart = [ CharEnd = ] CharEsc = diff --git a/src/openalpr/simpleini/simpleini.doxy b/src/openalpr/simpleini/simpleini.doxy index b9291e7..24cf75d 100644 --- a/src/openalpr/simpleini/simpleini.doxy +++ b/src/openalpr/simpleini/simpleini.doxy @@ -14,75 +14,75 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = SimpleIni -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = D:/src/simpleini-doc -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class " \ @@ -97,125 +97,125 @@ ABBREVIATE_BRIEF = "The $name class " \ an \ the -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = "D:/src/simpleini/ " -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member +# If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. -ALIASES = +ALIASES = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO @@ -225,33 +225,33 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is -# documented as struct with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code where the coding convention is that all structs are +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct (or union) is +# documented as struct with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code where the coding convention is that all structs are # typedef'ed and only the typedef is referenced never the struct's name. TYPEDEF_HIDES_STRUCT = NO @@ -260,347 +260,347 @@ TYPEDEF_HIDES_STRUCT = NO # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file +# If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO -# If this flag is set to YES, the members of anonymous namespaces will be extracted -# and appear in the documentation as a namespace called 'anonymous_namespace{file}', -# where file will be replaced with the base name of the file that contains the anonymous +# If this flag is set to YES, the members of anonymous namespaces will be extracted +# and appear in the documentation as a namespace called 'anonymous_namespace{file}', +# where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the +# Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional +# The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = YES -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file($line) : $text " -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = D:/src/simpleini/SimpleIni.h -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = +EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. -INPUT_FILTER = +INPUT_FILTER = -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO @@ -609,34 +609,34 @@ FILTER_SOURCE_FILES = NO # configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH -# then you must also enable this option. If you don't then doxygen will produce +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH +# then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = YES -# Setting the INLINE_SOURCES tag to YES will include the body +# Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES @@ -648,16 +648,16 @@ REFERENCES_RELATION = YES REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES @@ -666,141 +666,141 @@ VERBATIM_HEADERS = YES # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a # standard header. -HTML_HEADER = +HTML_HEADER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a # standard footer. -HTML_FOOTER = +HTML_FOOTER = -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! -HTML_STYLESHEET = +HTML_STYLESHEET = -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be # written to the html output directory. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members +# The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) +# This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 @@ -809,74 +809,74 @@ TREEVIEW_WIDTH = 250 # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO @@ -885,68 +885,68 @@ LATEX_HIDE_INDICES = NO # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO @@ -955,33 +955,33 @@ MAN_LINKS = NO # configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +XML_SCHEMA = -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +XML_DTD = -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES @@ -990,10 +990,10 @@ XML_PROGRAMLISTING = YES # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO @@ -1002,320 +1002,320 @@ GENERATE_AUTOGEN_DEF = NO # configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = SI_HAS_WIDE_FILE \ SI_SUPPORT_IOSTREAMS -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen +# If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES -# The PERL_PATH should be the absolute path and name of the perl script +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. -MSCGEN_PATH = +MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO -# If set to YES, the inheritance and collaboration graphs will show the +# If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES -# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected +# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO -# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected +# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png -# The tag DOT_PATH can be used to specify the path where the dot tool can be +# The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the number -# of direct children of the root node in a graph is already larger than -# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the number +# of direct children of the root node in a graph is already larger than +# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- -# Configuration::additions related to the search engine +# Configuration::additions related to the search engine #--------------------------------------------------------------------------- -# The SEARCHENGINE tag specifies whether or not a search engine should be +# The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO diff --git a/src/openalpr/simpleini/simpleini.h b/src/openalpr/simpleini/simpleini.h index 366a7f7..41d8907 100644 --- a/src/openalpr/simpleini/simpleini.h +++ b/src/openalpr/simpleini/simpleini.h @@ -163,7 +163,7 @@ SI_NO_MBCS. This is defined automatically on Windows CE platforms. @section contrib CONTRIBUTIONS - + - 2010/05/03: Tobias Gehrig: added GetDoubleValue() @section licence MIT LICENCE @@ -530,7 +530,7 @@ public: bool IsMultiLine() const { return m_bAllowMultiLine; } /** Should spaces be added around the equals sign when writing key/value - pairs out. When true, the result will be "key = value". When false, + pairs out. When true, the result will be "key = value". When false, the result will be "key=value". This value may be changed at any time. \param a_bSpaces Add spaces around the equals sign? @@ -541,7 +541,7 @@ public: /** Query the status of spaces output */ bool UsingSpaces() const { return m_bSpaces; } - + /*-----------------------------------------------------------------------*/ /** @} @{ @name Loading INI Data */ @@ -771,8 +771,8 @@ public: ) const; /** Retrieve all unique key names in a section. The sort order of the - returned strings is NOT DEFINED. You can sort the names into the load - order if desired. Search this file for ".sort" for an example. Only + returned strings is NOT DEFINED. You can sort the names into the load + order if desired. Search this file for ".sort" for an example. Only unique key names are returned. NOTE! This structure contains only pointers to strings. The actual @@ -793,8 +793,8 @@ public: ) const; /** Retrieve all values for a specific key. This method can be used when - multiple keys are both enabled and disabled. Note that the sort order - of the returned strings is NOT DEFINED. You can sort the names into + multiple keys are both enabled and disabled. Note that the sort order + of the returned strings is NOT DEFINED. You can sort the names into the load order if desired. Search this file for ".sort" for an example. NOTE! The returned values are pointers to string data stored in memory @@ -915,7 +915,7 @@ public: Strings starting with "t", "y", "on" or "1" are returned as logically true. Strings starting with "f", "n", "of" or "0" are returned as logically false. - For all other values the default is returned. Character comparisons are + For all other values the default is returned. Character comparisons are case-insensitive. @param a_pSection Section to search @@ -954,9 +954,9 @@ public: character starting every line). @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has - no effect if not using multi-key files. The + no effect if not using multi-key files. The difference between Delete/SetValue and SetValue - with a_bForceReplace = true, is that the load + with a_bForceReplace = true, is that the load order and comment will be preserved this way. @return SI_Error See error definitions @@ -978,19 +978,19 @@ public: when multiple keys are enabled. @param a_pSection Section to add or update - @param a_pKey Key to add or update. - @param a_nValue Value to set. - @param a_pComment Comment to be associated with the key. See the + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. - @param a_bUseHex By default the value will be written to the file - in decimal format. Set this to true to write it + @param a_bUseHex By default the value will be written to the file + in decimal format. Set this to true to write it as hexadecimal. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has - no effect if not using multi-key files. The - difference between Delete/SetLongValue and - SetLongValue with a_bForceReplace = true, is that - the load order and comment will be preserved this + no effect if not using multi-key files. The + difference between Delete/SetLongValue and + SetLongValue with a_bForceReplace = true, is that + the load order and comment will be preserved this way. @return SI_Error See error definitions @@ -1010,16 +1010,16 @@ public: when multiple keys are enabled. @param a_pSection Section to add or update - @param a_pKey Key to add or update. - @param a_nValue Value to set. - @param a_pComment Comment to be associated with the key. See the + @param a_pKey Key to add or update. + @param a_nValue Value to set. + @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has - no effect if not using multi-key files. The - difference between Delete/SetDoubleValue and - SetDoubleValue with a_bForceReplace = true, is that - the load order and comment will be preserved this + no effect if not using multi-key files. The + difference between Delete/SetDoubleValue and + SetDoubleValue with a_bForceReplace = true, is that + the load order and comment will be preserved this way. @return SI_Error See error definitions @@ -1038,16 +1038,16 @@ public: when multiple keys are enabled. @param a_pSection Section to add or update - @param a_pKey Key to add or update. - @param a_bValue Value to set. - @param a_pComment Comment to be associated with the key. See the + @param a_pKey Key to add or update. + @param a_bValue Value to set. + @param a_pComment Comment to be associated with the key. See the notes on SetValue() for comments. @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has - no effect if not using multi-key files. The - difference between Delete/SetBoolValue and - SetBoolValue with a_bForceReplace = true, is that - the load order and comment will be preserved this + no effect if not using multi-key files. The + difference between Delete/SetBoolValue and + SetBoolValue with a_bForceReplace = true, is that + the load order and comment will be preserved this way. @return SI_Error See error definitions @@ -1141,9 +1141,9 @@ private: comment character starting every line). @param a_bForceReplace Should all existing values in a multi-key INI file be replaced with this entry. This option has - no effect if not using multi-key files. The + no effect if not using multi-key files. The difference between Delete/AddEntry and AddEntry - with a_bForceReplace = true, is that the load + with a_bForceReplace = true, is that the load order and comment will be preserved this way. @param a_bCopyStrings Should copies of the strings be made or not. If false then the pointers will be used as is. @@ -1238,7 +1238,7 @@ private: /** Should spaces be written out surrounding the equals sign? */ bool m_bSpaces; - + /** Next order value, used to ensure sections and keys are output in the same order that they are loaded/added. */ @@ -1358,14 +1358,14 @@ CSimpleIniTempl::LoadFile( if (lSize == 0) { return SI_OK; } - + // allocate and ensure NULL terminated char * pData = new char[lSize+1]; if (!pData) { return SI_NOMEM; } pData[lSize] = 0; - + // load data into buffer fseek(a_fpFile, 0, SEEK_SET); size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile); @@ -2018,15 +2018,15 @@ CSimpleIniTempl::GetLongValue( } // any invalid strings will return the default value - if (*pszSuffix) { - return a_nDefault; + if (*pszSuffix) { + return a_nDefault; } return nValue; } template -SI_Error +SI_Error CSimpleIniTempl::SetLongValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, @@ -2050,7 +2050,7 @@ CSimpleIniTempl::SetLongValue( // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(szInput, strlen(szInput) + 1, + c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it @@ -2081,15 +2081,15 @@ CSimpleIniTempl::GetDoubleValue( double nValue = strtod(szValue, &pszSuffix); // any invalid strings will return the default value - if (!pszSuffix || *pszSuffix) { - return a_nDefault; + if (!pszSuffix || *pszSuffix) { + return a_nDefault; } return nValue; } template -SI_Error +SI_Error CSimpleIniTempl::SetDoubleValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, @@ -2112,7 +2112,7 @@ CSimpleIniTempl::SetDoubleValue( // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(szInput, strlen(szInput) + 1, + c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it @@ -2155,7 +2155,7 @@ CSimpleIniTempl::GetBoolValue( } template -SI_Error +SI_Error CSimpleIniTempl::SetBoolValue( const SI_CHAR * a_pSection, const SI_CHAR * a_pKey, @@ -2173,13 +2173,13 @@ CSimpleIniTempl::SetBoolValue( // convert to output text SI_CHAR szOutput[64]; SI_CONVERTER c(m_bStoreIsUtf8); - c.ConvertFromStore(pszInput, strlen(pszInput) + 1, + c.ConvertFromStore(pszInput, strlen(pszInput) + 1, szOutput, sizeof(szOutput) / sizeof(SI_CHAR)); // actually add it return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true); } - + template bool CSimpleIniTempl::GetAllValues( @@ -3383,4 +3383,3 @@ typedef CSimpleIniTempl. */ @@ -23,15 +23,15 @@ StateIdentifier::StateIdentifier(Config* config) { this->config = 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; } - + featureMatcher->loadRecognitionSet(config->country); } @@ -43,56 +43,55 @@ StateIdentifier::~StateIdentifier() int StateIdentifier::recognize(Mat img, Rect frame, char* stateCode) { Mat croppedImage = Mat(img, frame); - + return this->recognize(croppedImage, stateCode); } -// Attempts to recognize the plate. Returns a confidence level. Updates teh "stateCode" variable +// Attempts to recognize the plate. Returns a confidence level. Updates teh "stateCode" variable // with the value of the country/state int StateIdentifier::recognize(Mat img, char* stateCode) { timespec startTime; getTime(&startTime); - + cvtColor(img, img, CV_BGR2GRAY); - + resize(img, img, getSizeMaintainingAspect(img, config->stateIdImageWidthPx, config->stateIdimageHeightPx)); - + Mat plateImg(img.size(), img.type()); //plateImg = equalizeBrightness(img); img.copyTo(plateImg); - + Mat debugImg(plateImg.size(), plateImg.type()); plateImg.copyTo(debugImg); vector 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; getTime(&endTime); cout << "State Identification Time: " << diffclock(startTime, endTime) << "ms." << endl; } - - + + if (result.haswinner == false) return 0; - + strcpy(stateCode, result.winner.c_str()); - - + + return result.confidence; } - diff --git a/src/openalpr/stateidentifier.h b/src/openalpr/stateidentifier.h index 362fbb7..e991ca6 100644 --- a/src/openalpr/stateidentifier.h +++ b/src/openalpr/stateidentifier.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -39,20 +39,18 @@ class StateIdentifier int recognize(Mat img, Rect frame, char* stateCode); int recognize(Mat img, char* stateCode); - + //int confidence; - + protected: Config* config; - - + + private: - + FeatureMatcher* featureMatcher; - + }; #endif // STATEIDENTIFIER_H - - diff --git a/src/openalpr/support/CMakeLists.txt b/src/openalpr/support/CMakeLists.txt index 10898a3..4cfbd6f 100644 --- a/src/openalpr/support/CMakeLists.txt +++ b/src/openalpr/support/CMakeLists.txt @@ -5,5 +5,5 @@ set(support_source_files timing.cpp ) - -add_library(support ${support_source_files}) \ No newline at end of file + +add_library(support ${support_source_files}) diff --git a/src/openalpr/support/filesystem.cpp b/src/openalpr/support/filesystem.cpp index 32fe1cd..e3cd1ee 100644 --- a/src/openalpr/support/filesystem.cpp +++ b/src/openalpr/support/filesystem.cpp @@ -22,7 +22,7 @@ bool DirectoryExists( const char* pzPath ) if (pDir != NULL) { - bExists = true; + bExists = true; (void) closedir (pDir); } @@ -34,7 +34,7 @@ bool fileExists( const char* pzPath ) if (pzPath == NULL) return false; bool fExists = false; - std::ifstream f(pzPath); + std::ifstream f(pzPath); fExists = f.is_open(); f.close(); return fExists; @@ -43,9 +43,9 @@ bool fileExists( const char* pzPath ) std::vector getFilesInDir(const char* dirPath) { DIR *dir; - + std::vector files; - + struct dirent *ent; if ((dir = opendir (dirPath)) != NULL) { /* print all the files and directories within directory */ @@ -59,7 +59,7 @@ std::vector getFilesInDir(const char* dirPath) perror (""); return files; } - + return files; } @@ -73,4 +73,4 @@ bool stringCompare( const std::string &left, const std::string &right ){ if( left.size() < right.size() ) return true; return false; -} \ No newline at end of file +} diff --git a/src/openalpr/support/filesystem.h b/src/openalpr/support/filesystem.h index cb83b30..61e052c 100644 --- a/src/openalpr/support/filesystem.h +++ b/src/openalpr/support/filesystem.h @@ -23,8 +23,8 @@ bool DirectoryExists( const char* pzPath ); bool fileExists( const char* pzPath ); std::vector getFilesInDir(const char* dirPath); - + bool stringCompare( const std::string &left, const std::string &right ); - - -#endif // FILESYSTEM_H \ No newline at end of file + + +#endif // FILESYSTEM_H diff --git a/src/openalpr/support/timing.cpp b/src/openalpr/support/timing.cpp index 7e31290..066af2a 100644 --- a/src/openalpr/support/timing.cpp +++ b/src/openalpr/support/timing.cpp @@ -76,8 +76,8 @@ double diffclock(timespec time1,timespec time2) { timespec delta = diff(time1,time2); double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0); - - + + return milliseconds; } @@ -116,13 +116,13 @@ void getTime(timespec* time) } 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; - + } diff --git a/src/openalpr/support/timing.h b/src/openalpr/support/timing.h index 66763f7..608877d 100644 --- a/src/openalpr/support/timing.h +++ b/src/openalpr/support/timing.h @@ -18,6 +18,6 @@ void getTime(timespec* time); double diffclock(timespec time1,timespec time2); - - -#endif \ No newline at end of file + + +#endif diff --git a/src/openalpr/support/windows/dirent.h b/src/openalpr/support/windows/dirent.h index cf3fe56..718bde1 100644 --- a/src/openalpr/support/windows/dirent.h +++ b/src/openalpr/support/windows/dirent.h @@ -33,7 +33,7 @@ * capital W) in order to maintain compatibility with MingW. * * Version 1.12, Sep 30 2012, Toni Ronkko - * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR, + * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR, * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir(). * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code. * @@ -410,11 +410,11 @@ _wreaddir( if (datap) { size_t n; DWORD attr; - + /* Pointer to directory entry to return */ entp = &dirp->ent; - /* + /* * Copy file name as wide-character string. If the file name is too * long to fit in to the destination buffer, then truncate file name * to PATH_MAX characters and zero-terminate the buffer. @@ -570,12 +570,12 @@ dirent_next( return p; } -/* +/* * Open directory stream using plain old C-string. */ static DIR* opendir( - const char *dirname) + const char *dirname) { struct DIR *dirp; int error; @@ -608,7 +608,7 @@ opendir( } } else { - /* + /* * Cannot convert file name to wide-character string. This * occurs if the string contains invalid multi-byte sequences or * the output buffer is too small to contain the resulting @@ -646,7 +646,7 @@ opendir( */ static struct dirent* readdir( - DIR *dirp) + DIR *dirp) { WIN32_FIND_DATAW *datap; struct dirent *entp; @@ -661,7 +661,7 @@ readdir( error = dirent_wcstombs_s( &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); - /* + /* * If the file name cannot be represented by a multi-byte string, * then attempt to use old 8+3 file name. This allows traditional * Unix-code to access some file names despite of unicode @@ -674,7 +674,7 @@ readdir( if (error && datap->cAlternateFileName[0] != '\0') { error = dirent_wcstombs_s( &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName, - sizeof (datap->cAlternateFileName) / + sizeof (datap->cAlternateFileName) / sizeof (datap->cAlternateFileName[0])); } @@ -702,7 +702,7 @@ readdir( entp->d_reclen = sizeof (struct dirent); } else { - /* + /* * Cannot convert file name to multi-byte string so construct * an errornous directory entry and return that. Note that * we cannot return NULL as that would stop the processing @@ -730,7 +730,7 @@ readdir( */ static int closedir( - DIR *dirp) + DIR *dirp) { int ok; if (dirp) { @@ -757,7 +757,7 @@ closedir( */ static void rewinddir( - DIR* dirp) + DIR* dirp) { /* Rewind wide-character string directory stream */ _wrewinddir (dirp->wdirp); @@ -886,4 +886,3 @@ dirent_set_errno( } #endif #endif /*DIRENT_H*/ - diff --git a/src/openalpr/support/windows/unistd_partial.h b/src/openalpr/support/windows/unistd_partial.h index 3c2ef38..a335c26 100644 --- a/src/openalpr/support/windows/unistd_partial.h +++ b/src/openalpr/support/windows/unistd_partial.h @@ -1,9 +1,9 @@ #ifndef _UNISTD_H #define _UNISTD_H 1 -/* This file intended to serve as a drop-in replacement for +/* This file intended to serve as a drop-in replacement for * unistd.h on Windows - * Please add functionality as neeeded + * Please add functionality as neeeded */ #include @@ -31,7 +31,7 @@ #define STDERR_FILENO 2 /* should be in some equivalent to */ typedef __int8 int8_t; -typedef __int16 int16_t; +typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; @@ -39,4 +39,4 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; -#endif /* unistd.h */ \ No newline at end of file +#endif /* unistd.h */ diff --git a/src/openalpr/support/windows/utils.h b/src/openalpr/support/windows/utils.h index 7519f41..0049234 100644 --- a/src/openalpr/support/windows/utils.h +++ b/src/openalpr/support/windows/utils.h @@ -2,6 +2,6 @@ #include static inline double round(double val) -{ +{ return floor(val + 0.5); -} \ No newline at end of file +} diff --git a/src/openalpr/trex.c b/src/openalpr/trex.c index b9e0690..0fe98b8 100644 --- a/src/openalpr/trex.c +++ b/src/openalpr/trex.c @@ -105,7 +105,7 @@ static void trex_error(TRex *exp,const TRexChar *error) } static void trex_expect(TRex *exp, int n){ - if((*exp->_p) != n) + if((*exp->_p) != n) trex_error(exp, _SC("expected paren")); exp->_p++; } @@ -144,31 +144,31 @@ static int trex_charnode(TRex *exp,TRexBool isclass) case 'r': exp->_p++; return trex_newnode(exp,'\r'); case 'f': exp->_p++; return trex_newnode(exp,'\f'); case 'v': exp->_p++; return trex_newnode(exp,'\v'); - case 'a': case 'A': case 'w': case 'W': case 's': case 'S': - case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': - case 'p': case 'P': case 'l': case 'u': + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': { - t = *exp->_p; exp->_p++; + t = *exp->_p; exp->_p++; return trex_charclass(exp,t); } - case 'b': + case 'b': case 'B': if(!isclass) { int node = trex_newnode(exp,OP_WB); exp->_nodes[node].left = *exp->_p; - exp->_p++; + exp->_p++; return node; } //else default - default: - t = *exp->_p; exp->_p++; + default: + t = *exp->_p; exp->_p++; return trex_newnode(exp,t); } } else if(!scisprint(*exp->_p)) { - + trex_error(exp,_SC("letter expected")); } - t = *exp->_p; exp->_p++; + t = *exp->_p; exp->_p++; return trex_newnode(exp,t); } static int trex_class(TRex *exp) @@ -179,11 +179,11 @@ static int trex_class(TRex *exp) ret = trex_newnode(exp,OP_NCLASS); exp->_p++; }else ret = trex_newnode(exp,OP_CLASS); - + if(*exp->_p == ']') trex_error(exp,_SC("empty class")); chain = ret; while(*exp->_p != ']' && exp->_p != exp->_eol) { - if(*exp->_p == '-' && first != -1){ + if(*exp->_p == '-' && first != -1){ int r,t; if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range")); r = trex_newnode(exp,OP_RANGE); @@ -297,7 +297,7 @@ static int trex_element(TRex *exp) trex_error(exp,_SC(", or } expected")); } /*******************************/ - isgreedy = TRex_True; + isgreedy = TRex_True; break; } @@ -384,7 +384,7 @@ static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c) static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next) { - + TRexNodeType type = node->type; switch(type) { case OP_GREEDY: { @@ -428,7 +428,7 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s } } } - + if(s >= exp->_eol) break; } @@ -467,7 +467,7 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s exp->_matches[capture].begin = cur; exp->_currsubexp++; } - + do { TRexNode *subnext = NULL; if(n->next != -1) { @@ -484,10 +484,10 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s } } while((n->next != -1) && (n = &exp->_nodes[n->next])); - if(capture != -1) + if(capture != -1) exp->_matches[capture].len = cur - exp->_matches[capture].begin; return cur; - } + } case OP_WB: if(str == exp->_bol && !isspace(*str) || (str == exp->_eol && !isspace(*(str-1))) @@ -640,4 +640,3 @@ TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp) *subexp = exp->_matches[n]; return TRex_True; } - diff --git a/src/openalpr/trex.h b/src/openalpr/trex.h index bf268b1..dbca867 100644 --- a/src/openalpr/trex.h +++ b/src/openalpr/trex.h @@ -5,11 +5,11 @@ Copyright (C) 2003-2006 Alberto Demichelis - This software is provided 'as-is', without any express - or implied warranty. In no event will the authors be held + This software is provided 'as-is', without any express + or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. - Permission is granted to anyone to use this software for + Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: @@ -30,13 +30,13 @@ #ifdef _UNICODE #define TRexChar unsigned short #define MAX_CHAR 0xFFFF -#define _TREXC(c) L##c +#define _TREXC(c) L##c #define trex_strlen wcslen #define trex_printf wprintf #else #define TRexChar char #define MAX_CHAR 0xFF -#define _TREXC(c) (c) +#define _TREXC(c) (c) #define trex_strlen strlen #define trex_printf printf #endif diff --git a/src/openalpr/utility.cpp b/src/openalpr/utility.cpp index 8b30359..595e314 100644 --- a/src/openalpr/utility.cpp +++ b/src/openalpr/utility.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -26,14 +26,14 @@ Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY) { Rect expandedRegion = Rect(original); - + float halfX = round((float) expandXPixels / 2.0); float halfY = round((float) expandYPixels / 2.0); expandedRegion.x = expandedRegion.x - halfX; expandedRegion.width = expandedRegion.width + expandXPixels; expandedRegion.y = expandedRegion.y - halfY; expandedRegion.height = expandedRegion.height + expandYPixels; - + if (expandedRegion.x < 0) expandedRegion.x = 0; if (expandedRegion.y < 0) @@ -42,16 +42,16 @@ Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, i expandedRegion.width = maxX - expandedRegion.x; if (expandedRegion.y + expandedRegion.height > maxY) expandedRegion.height = maxY - expandedRegion.y; - + return expandedRegion; } Mat drawImageDashboard(vector images, int imageType, int numColumns) { int numRows = ceil((float) images.size() / (float) numColumns); - + Mat dashboard(Size(images[0].cols * numColumns, images[0].rows * numRows), imageType); - + for (int i = 0; i < numColumns * numRows; i++) { if (i < images.size()) @@ -62,7 +62,7 @@ Mat drawImageDashboard(vector images, int imageType, int numColumns) black.copyTo(dashboard(Rect((i%numColumns) * images[0].cols, floor((float) i/numColumns) * images[0].rows, images[0].cols, images[0].rows))); } } - + return dashboard; } @@ -73,20 +73,20 @@ Mat addLabel(Mat input, string label) const int extraHeight = 20; const Scalar bg(222,222,222); const Scalar fg(0,0,0); - + Rect destinationRect(border_size, extraHeight, input.cols, input.rows); Mat newImage(Size(input.cols + (border_size), input.rows + extraHeight + (border_size )), input.type()); input.copyTo(newImage(destinationRect)); - + cout << " Adding label " << label << endl; if (input.type() == CV_8U) cvtColor(newImage, newImage, CV_GRAY2BGR); rectangle(newImage, Point(0,0), Point(input.cols, extraHeight), bg, CV_FILLED); putText(newImage, label, Point(5, extraHeight - 5), CV_FONT_HERSHEY_PLAIN , 0.7, fg); - + rectangle(newImage, Point(0,0), Point(newImage.cols - 1, newImage.rows -1), border_color, border_size); - + return newImage; } @@ -95,12 +95,12 @@ Mat addLabel(Mat input, string label) void drawAndWait(cv::Mat* frame) { cv::imshow("Temp Window", *frame); - + while (cv::waitKey(50) == -1) { // loop } - + cv::destroyWindow("Temp Window"); } @@ -114,35 +114,35 @@ vector produceThresholds(const Mat img_gray, Config* config) { const int THRESHOLD_COUNT = 4; //Mat img_equalized = equalizeBrightness(img_gray); - + timespec startTime; getTime(&startTime); vector thresholds; - + for (int i = 0; i < THRESHOLD_COUNT; i++) thresholds.push_back(Mat(img_gray.size(), CV_8U)); - + int i = 0; - + // Adaptive //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 7, 3); //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 13, 3); //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 17, 3); - + // Wolf int k = 0, win=18; //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)); bitwise_not(thresholds[i-1], thresholds[i-1]); - + 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)); //bitwise_not(thresholds[i-1], thresholds[i-1]); - + // Sauvola k = 1; NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k); @@ -150,22 +150,22 @@ vector produceThresholds(const Mat img_gray, Config* config) k=2; NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k); bitwise_not(thresholds[i-1], thresholds[i-1]); - - - - - + + + + + if (config->debugTiming) { timespec endTime; getTime(&endTime); cout << " -- Produce Threshold Time: " << diffclock(startTime, endTime) << "ms." << endl; } - + return thresholds; //threshold(img_equalized, img_threshold, 100, 255, THRESH_BINARY); - + } double median(int array[], int arraySize) @@ -175,7 +175,7 @@ double median(int array[], int arraySize) //std::cerr << "Median calculation requested on empty array" << endl; return 0; } - + std::sort(&array[0], &array[arraySize]); return arraySize % 2 ? array[arraySize / 2] : (array[arraySize / 2 - 1] + array[arraySize / 2]) / 2; } @@ -183,7 +183,7 @@ double median(int array[], int arraySize) Mat equalizeBrightness(Mat img) { - + // Divide the image by its morphologically closed counterpart Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19)); Mat closed; @@ -193,7 +193,7 @@ Mat equalizeBrightness(Mat img) divide(img, closed, img, 1, CV_32FC1); normalize(img, img, 0, 255, NORM_MINMAX); img.convertTo(img, CV_8U); // convert back to unsigned int - + return img; } @@ -201,7 +201,7 @@ Mat equalizeBrightness(Mat img) void drawRotatedRect(Mat* img, RotatedRect rect, Scalar color, int thickness) { - Point2f rect_points[4]; + Point2f rect_points[4]; rect.points( rect_points ); for( int j = 0; j < 4; j++ ) line( *img, rect_points[j], rect_points[(j+1)%4], color, thickness, 8 ); @@ -215,7 +215,7 @@ void fillMask(Mat img, const Mat mask, Scalar color) for (int col = 0; col < img.cols; col++) { int m = (int) mask.at(row, col); - + if (m) { for (int z = 0; z < 3; z++) @@ -236,7 +236,7 @@ void drawX(Mat img, Rect rect, Scalar color, int thickness) Point tr(rect.x + rect.width, rect.y); Point bl(rect.x, rect.y + rect.height); Point br(rect.x + rect.width, rect.y + rect.height); - + line(img, tl, br, color, thickness); line(img, bl, tr, color, thickness); } @@ -245,7 +245,7 @@ double distanceBetweenPoints(Point p1, Point p2) { float asquared = (p2.x - p1.x)*(p2.x - p1.x); float bsquared = (p2.y - p1.y)*(p2.y - p1.y); - + return sqrt(asquared + bsquared); } @@ -253,7 +253,7 @@ float angleBetweenPoints(Point p1, Point p2) { int deltaY = p2.y - p1.y; int deltaX = p2.x - p1.x; - + return atan2((float) deltaY, (float) deltaX) * (180 / CV_PI); } @@ -261,7 +261,7 @@ float angleBetweenPoints(Point p1, Point p2) Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight) { float aspect = ((float) inputImg.cols) / ((float) inputImg.rows); - + if (maxWidth / aspect > maxHeight) { return Size(maxHeight * aspect, maxHeight); @@ -296,9 +296,9 @@ void LineSegment::init(int x1, int y1, int x2, int y2) this->slope = 0.00000000001; else this->slope = (float) (p2.y - p1.y) / (float) (p2.x - p1.x); - + this->length = distanceBetweenPoints(p1, p2); - + this->angle = angleBetweenPoints(p1, p2); } @@ -314,15 +314,15 @@ float LineSegment::getPointAt(float x) Point LineSegment::closestPointOnSegmentTo(Point p) { float top = (p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y)*(p2.y - p1.y); - + float bottom = distanceBetweenPoints(p2, p1); bottom = bottom * bottom; - + float u = top / bottom; - + float x = p1.x + u * (p2.x - p1.x); float y = p1.y + u * (p2.y - p1.y); - + return Point(x, y); } @@ -330,12 +330,12 @@ Point LineSegment::intersection(LineSegment line) { float c1, c2; float intersection_X = -1, intersection_Y= -1; - - + + 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 - + if( (slope - line.slope) == 0) { //std::cout << "No Intersection between the lines" << endl; @@ -344,7 +344,7 @@ Point LineSegment::intersection(LineSegment line) { // Line1 is vertical return Point(p1.x, line.getPointAt(p1.x)); - } + } else if (line.p1.x == line.p2.x) { // Line2 is vertical @@ -354,11 +354,11 @@ Point LineSegment::intersection(LineSegment line) { intersection_X = (c2 - c1) / (slope - line.slope); intersection_Y = slope * intersection_X + c1; - + } - + return Point(intersection_X, intersection_Y); - + } @@ -375,7 +375,7 @@ Point LineSegment::midpoint() float diff = p2.x - p1.x; float midX = ((float) p1.x) + (diff / 2); int midY = getPointAt(midX); - + return Point(midX, midY); } @@ -386,17 +386,12 @@ LineSegment LineSegment::getParallelLine(float distance) 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); - + LineSegment result(p1.x + offsetX, p1.y + offsetY, p2.x + offsetX, p2.y + offsetY); - + return result; } - - - - - diff --git a/src/openalpr/utility.h b/src/openalpr/utility.h index deb9266..64cafce 100644 --- a/src/openalpr/utility.h +++ b/src/openalpr/utility.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -38,9 +38,9 @@ #include "binarize_wolf.h" #include #include "config.h" - - + + /* struct LineSegment { @@ -50,70 +50,70 @@ struct LineSegment float y2; }; */ - - + + class LineSegment { - + public: Point p1, p2; float slope; float length; float angle; - + // LineSegment(Point point1, Point point2); LineSegment(); LineSegment(int x1, int y1, int x2, int y2); LineSegment(Point p1, Point p2); - + void init(int x1, int y1, int x2, int y2); - + bool isPointBelowLine(Point tp); - + float getPointAt(float x); - + Point closestPointOnSegmentTo(Point p); - + Point intersection(LineSegment line); - + LineSegment getParallelLine(float distance); - + Point midpoint(); - + inline std::string str() { std::stringstream ss; ss << "(" << p1.x << ", " << p1.y << ") : (" << p2.x << ", " << p2.y << ")"; return ss.str() ; } - - + + }; double median(int array[], int arraySize); vector produceThresholds(const Mat img_gray, Config* config); - + Mat drawImageDashboard(vector images, int imageType, int numColumns); - + void displayImage(Config* config, string windowName, cv::Mat frame); void drawAndWait(cv::Mat* frame); - + double distanceBetweenPoints(Point p1, Point p2); - + 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); - + float angleBetweenPoints(Point p1, Point p2); - + Size getSizeMaintainingAspect(Mat inputImg, int maxWidth, int maxHeight); - + Mat equalizeBrightness(Mat img); - + Rect expandRect(Rect original, int expandXPixels, int expandYPixels, int maxX, int maxY); - + Mat addLabel(Mat input, string label); - + #endif // UTILITY_H diff --git a/src/openalpr/verticalhistogram.cpp b/src/openalpr/verticalhistogram.cpp index cd1f913..ebe97b1 100644 --- a/src/openalpr/verticalhistogram.cpp +++ b/src/openalpr/verticalhistogram.cpp @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -22,9 +22,9 @@ VerticalHistogram::VerticalHistogram(Mat inputImage, Mat mask) { analyzeImage(inputImage, mask); - - - + + + } VerticalHistogram::~VerticalHistogram() @@ -38,44 +38,44 @@ void VerticalHistogram::analyzeImage(Mat inputImage, Mat mask) { highestPeak = 0; lowestValley = inputImage.rows; - - + + histoImg = Mat::zeros(inputImage.size(), CV_8U); - + int columnCount; - + for (int col = 0; col < inputImage.cols; col++) { columnCount = 0; - + for (int row = 0; row < inputImage.rows; row++) { - + if (inputImage.at(row, col) > 0 && mask.at(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(inputImage.rows - columnCount, col) = 255; - + } - + } int VerticalHistogram::getLocalMinimum(int leftX, int rightX) { int minimum = histoImg.rows + 1; int lowestX = leftX; - + for (int i = leftX; i <= rightX; i++) { if (colHeights[i] < minimum) @@ -84,7 +84,7 @@ int VerticalHistogram::getLocalMinimum(int leftX, int rightX) minimum = colHeights[i]; } } - + return lowestX; } @@ -92,7 +92,7 @@ int VerticalHistogram::getLocalMaximum(int leftX, int rightX) { int maximum = -1; int highestX = leftX; - + for (int i = leftX; i <= rightX; i++) { if (colHeights[i] > maximum) @@ -101,8 +101,8 @@ int VerticalHistogram::getLocalMaximum(int leftX, int rightX) maximum = colHeights[i]; } } - - return highestX; + + return highestX; } int VerticalHistogram::getHeightAt(int x) @@ -113,78 +113,78 @@ int VerticalHistogram::getHeightAt(int x) void VerticalHistogram::findValleys() { int MINIMUM_PEAK_HEIGHT = (int) (((float) highestPeak) * 0.75); - + int totalWidth = colHeights.size(); - + int midpoint = ((highestPeak - lowestValley) / 2) + lowestValley; - + HistogramDirection prevDirection = FALLING; - + int relativePeakHeight = 0; int valleyStart = 0; - + for (int i = 0; i < totalWidth; i++) { bool aboveMidpoint = (colHeights[i] >= midpoint); - + if (aboveMidpoint) { if (colHeights[i] > relativePeakHeight) relativePeakHeight = colHeights[i]; - - + + prevDirection = FLAT; - + } else { relativePeakHeight = 0; - + HistogramDirection direction = getHistogramDirection(i); - + if ((prevDirection == FALLING || prevDirection == FLAT) && direction == RISING) { - + } else if ((prevDirection == FALLING || prevDirection == FLAT) && direction == RISING) { - + } } - + } } HistogramDirection VerticalHistogram::getHistogramDirection(int index) { int EXTRA_WIDTH_TO_AVERAGE = 2; - + float trailingAverage = 0; float forwardAverage = 0; - + int trailStartIndex = index - EXTRA_WIDTH_TO_AVERAGE; if (trailStartIndex < 0) trailStartIndex = 0; int forwardEndIndex = index + EXTRA_WIDTH_TO_AVERAGE; if (forwardEndIndex >= colHeights.size()) forwardEndIndex = colHeights.size() - 1; - + for (int i = index; i >= trailStartIndex; i--) { trailingAverage += colHeights[i]; } trailingAverage = trailingAverage / ((float) (1 + index - trailStartIndex)); - + for (int i = index; i <= forwardEndIndex; i++) { forwardAverage += colHeights[i]; } forwardAverage = forwardAverage / ((float) (1 + forwardEndIndex - index)); - - + + float diff = forwardAverage - trailingAverage; float minDiff = ((float) (highestPeak - lowestValley)) * 0.10; - + if (diff > minDiff) return RISING; else if (diff < minDiff) @@ -192,5 +192,3 @@ HistogramDirection VerticalHistogram::getHistogramDirection(int index) else return FLAT; } - - diff --git a/src/openalpr/verticalhistogram.h b/src/openalpr/verticalhistogram.h index 6a7b7db..c424b91 100644 --- a/src/openalpr/verticalhistogram.h +++ b/src/openalpr/verticalhistogram.h @@ -1,18 +1,18 @@ /* * Copyright (c) 2013 New Designs Unlimited, LLC * Opensource Automated License Plate Recognition [http://www.openalpr.com] - * + * * This file is part of OpenAlpr. - * + * * OpenAlpr is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License - * version 3 as published by the Free Software Foundation - * + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ @@ -45,24 +45,24 @@ class VerticalHistogram virtual ~VerticalHistogram(); Mat histoImg; - + // Returns the lowest X position between two points. int getLocalMinimum(int leftX, int rightX); // Returns the highest X position between two points. int getLocalMaximum(int leftX, int rightX); - + int getHeightAt(int x); - + private: vector colHeights; int highestPeak; int lowestValley; vector valleys; - + void analyzeImage(Mat inputImage, Mat mask); void findValleys(); - + HistogramDirection getHistogramDirection(int index); }; -#endif // VERTICALHISTOGRAM_H \ No newline at end of file +#endif // VERTICALHISTOGRAM_H diff --git a/src/tclap/Arg.h b/src/tclap/Arg.h index d653164..3945b19 100644 --- a/src/tclap/Arg.h +++ b/src/tclap/Arg.h @@ -689,4 +689,3 @@ inline void Arg::reset() } //namespace TCLAP #endif - diff --git a/src/tclap/ArgException.h b/src/tclap/ArgException.h index 3411aa9..e9f2059 100644 --- a/src/tclap/ArgException.h +++ b/src/tclap/ArgException.h @@ -1,24 +1,24 @@ // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- -/****************************************************************************** - * +/****************************************************************************** + * * file: ArgException.h - * + * * Copyright (c) 2003, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_ARG_EXCEPTION_H @@ -36,7 +36,7 @@ namespace TCLAP { class ArgException : public std::exception { public: - + /** * Constructor. * \param text - The text of the exception. @@ -44,15 +44,15 @@ class ArgException : public std::exception * \param td - Text describing the type of ArgException it is. * of the exception. */ - ArgException( const std::string& text = "undefined 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 ), + : std::exception(), + _errorText(text), + _argId( id ), _typeDescription(td) - { } - + { } + /** * Destructor. */ @@ -66,20 +66,20 @@ class ArgException : public std::exception /** * Returns the argument id. */ - std::string argId() const - { + std::string argId() const + { if ( _argId == "undefined" ) return " "; else - return ( "Argument: " + _argId ); + return ( "Argument: " + _argId ); } /** - * Returns the arg id and error text. + * Returns the arg id and error text. */ - const char* what() const throw() + const char* what() const throw() { - static std::string ex; + static std::string ex; ex = _argId + " -- " + _errorText; return ex.c_str(); } @@ -90,7 +90,7 @@ class ArgException : public std::exception */ std::string typeDescription() const { - return _typeDescription; + return _typeDescription; } @@ -119,19 +119,19 @@ class ArgException : public std::exception * parse the argument it has been passed. */ class ArgParseException : public ArgException -{ +{ public: /** * Constructor. * \param text - The text of the exception. - * \param id - The text identifying the argument source + * \param id - The text identifying the argument source * of the exception. */ - ArgParseException( const std::string& text = "undefined exception", + ArgParseException( const std::string& text = "undefined exception", const std::string& id = "undefined" ) - : ArgException( text, - id, - std::string( "Exception found while parsing " ) + + : ArgException( text, + id, + std::string( "Exception found while parsing " ) + std::string( "the value the Arg has been passed." )) { } }; @@ -146,12 +146,12 @@ class CmdLineParseException : public ArgException /** * Constructor. * \param text - The text of the exception. - * \param id - The text identifying the argument source + * \param id - The text identifying the argument source * of the exception. */ - CmdLineParseException( const std::string& text = "undefined exception", + CmdLineParseException( const std::string& text = "undefined exception", const std::string& id = "undefined" ) - : ArgException( text, + : ArgException( text, id, std::string( "Exception found when the values ") + std::string( "on the command line do not meet ") + @@ -161,7 +161,7 @@ class CmdLineParseException : public ArgException }; /** - * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. + * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. * same flag as another Arg, same name, etc. */ class SpecificationException : public ArgException @@ -170,16 +170,16 @@ class SpecificationException : public ArgException /** * Constructor. * \param text - The text of the exception. - * \param id - The text identifying the argument source + * \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, + : ArgException( text, id, std::string("Exception found when an Arg object ")+ std::string("is improperly defined by the ") + - std::string("developer." )) + std::string("developer." )) { } }; @@ -197,4 +197,3 @@ private: } // namespace TCLAP #endif - diff --git a/src/tclap/CmdLine.h b/src/tclap/CmdLine.h index 0e7dda3..7d7c14b 100644 --- a/src/tclap/CmdLine.h +++ b/src/tclap/CmdLine.h @@ -452,7 +452,7 @@ inline void CmdLine::parse(std::vector& args) int requiredCount = 0; - for (int i = 0; static_cast(i) < args.size(); i++) + for (int i = 0; static_cast(i) < args.size(); i++) { bool matched = false; for (ArgListIterator it = _argList.begin(); @@ -619,7 +619,7 @@ inline void CmdLine::reset() { for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ ) (*it)->reset(); - + _progName.clear(); } diff --git a/src/tclap/CmdLineInterface.h b/src/tclap/CmdLineInterface.h index 1b25e9b..7b0fd3e 100644 --- a/src/tclap/CmdLineInterface.h +++ b/src/tclap/CmdLineInterface.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: CmdLineInterface.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_COMMANDLINE_INTERFACE_H #define TCLAP_COMMANDLINE_INTERFACE_H @@ -31,7 +31,7 @@ namespace TCLAP { - + class Arg; class CmdLineOutput; class XorHandler; @@ -51,29 +51,29 @@ class CmdLineInterface /** * Adds an argument to the list of arguments to be parsed. - * \param a - Argument to be added. + * \param a - Argument to be added. */ virtual void add( Arg& a )=0; /** * An alternative add. Functionally identical. - * \param a - Argument to be added. + * \param a - Argument to be added. */ virtual void add( Arg* a )=0; /** - * Add two Args that will be xor'd. + * 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. + * \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 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. + * \param xors - List of Args to be added and xor'd. */ virtual void xorAdd( std::vector& xors )=0; @@ -86,7 +86,7 @@ class CmdLineInterface /** * Parses the command line. - * \param args - A vector of strings representing the args. + * \param args - A vector of strings representing the args. * args[0] is still the program name. */ void parse(std::vector& args); @@ -97,7 +97,7 @@ class CmdLineInterface virtual CmdLineOutput* getOutput()=0; /** - * \param co - CmdLineOutput object that we want to use instead. + * \param co - CmdLineOutput object that we want to use instead. */ virtual void setOutput(CmdLineOutput* co)=0; @@ -112,12 +112,12 @@ class CmdLineInterface virtual std::string& getProgramName()=0; /** - * Returns the argList. + * Returns the argList. */ virtual std::list& getArgList()=0; /** - * Returns the XorHandler. + * Returns the XorHandler. */ virtual XorHandler& getXorHandler()=0; @@ -137,9 +137,9 @@ class CmdLineInterface */ virtual bool hasHelpAndVersion()=0; - /** + /** * Resets the instance as if it had just been constructed so that the - * instance can be reused. + * instance can be reused. */ virtual void reset()=0; }; @@ -147,4 +147,4 @@ class CmdLineInterface } //namespace -#endif +#endif diff --git a/src/tclap/CmdLineOutput.h b/src/tclap/CmdLineOutput.h index 71ee5a3..993b1d9 100644 --- a/src/tclap/CmdLineOutput.h +++ b/src/tclap/CmdLineOutput.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: CmdLineOutput.h - * + * * Copyright (c) 2004, Michael E. Smoot * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_CMDLINEOUTPUT_H #define TCLAP_CMDLINEOUTPUT_H @@ -38,7 +38,7 @@ class ArgException; /** * The interface that any output object must implement. */ -class CmdLineOutput +class CmdLineOutput { public: @@ -49,26 +49,26 @@ class CmdLineOutput virtual ~CmdLineOutput() {} /** - * Generates some sort of output for the USAGE. - * \param c - The CmdLine object the output is generated for. + * 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. + * 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. + * 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, + virtual void failure( CmdLineInterface& c, ArgException& e )=0; }; } //namespace TCLAP -#endif +#endif diff --git a/src/tclap/DocBookOutput.h b/src/tclap/DocBookOutput.h index a42ca27..00ccc75 100644 --- a/src/tclap/DocBookOutput.h +++ b/src/tclap/DocBookOutput.h @@ -1,24 +1,24 @@ // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- -/****************************************************************************** - * +/****************************************************************************** + * * file: DocBookOutput.h - * + * * Copyright (c) 2004, Michael E. Smoot * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_DOCBOOKOUTPUT_H #define TCLAP_DOCBOOKOUTPUT_H @@ -37,7 +37,7 @@ namespace TCLAP { /** - * A class that generates DocBook output for usage() method for the + * A class that generates DocBook output for usage() method for the * given CmdLine and its Args. */ class DocBookOutput : public CmdLineOutput @@ -46,35 +46,35 @@ class DocBookOutput : public CmdLineOutput public: /** - * Prints the usage to stdout. Can be overridden to + * Prints the usage to stdout. Can be overridden to * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void usage(CmdLineInterface& c); /** - * Prints the version to stdout. Can be overridden + * Prints the version to stdout. Can be overridden * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void version(CmdLineInterface& c); /** - * Prints (to stderr) an error message, short usage + * 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. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. */ - virtual void failure(CmdLineInterface& c, + virtual void failure(CmdLineInterface& c, ArgException& e ); 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. + * \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); @@ -87,12 +87,12 @@ class DocBookOutput : public CmdLineOutput }; -inline void DocBookOutput::version(CmdLineInterface& _cmd) -{ +inline void DocBookOutput::version(CmdLineInterface& _cmd) +{ std::cout << _cmd.getVersion() << std::endl; } -inline void DocBookOutput::usage(CmdLineInterface& _cmd ) +inline void DocBookOutput::usage(CmdLineInterface& _cmd ) { std::list argList = _cmd.getArgList(); std::string progName = _cmd.getProgramName(); @@ -127,13 +127,13 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) for ( int i = 0; (unsigned int)i < xorList.size(); i++ ) { std::cout << "" << std::endl; - for ( ArgVectorIterator it = xorList[i].begin(); + for ( ArgVectorIterator it = xorList[i].begin(); it != xorList[i].end(); it++ ) printShortArg((*it)); std::cout << "" << std::endl; } - + // rest of args for (ArgListIterator it = argList.begin(); it != argList.end(); it++) if ( !xorHandler.contains( (*it) ) ) @@ -145,7 +145,7 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::cout << "" << std::endl; std::cout << "Description" << std::endl; std::cout << "" << std::endl; - std::cout << _cmd.getMessage() << std::endl; + std::cout << _cmd.getMessage() << std::endl; std::cout << "" << std::endl; std::cout << "" << std::endl; @@ -153,7 +153,7 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::cout << "Options" << std::endl; std::cout << "" << std::endl; - + for (ArgListIterator it = argList.begin(); it != argList.end(); it++) printLongArg((*it)); @@ -163,17 +163,17 @@ inline void DocBookOutput::usage(CmdLineInterface& _cmd ) std::cout << "" << std::endl; std::cout << "Version" << std::endl; std::cout << "" << std::endl; - std::cout << xversion << std::endl; + std::cout << xversion << std::endl; std::cout << "" << std::endl; std::cout << "" << std::endl; - + std::cout << "" << std::endl; } inline void DocBookOutput::failure( CmdLineInterface& _cmd, - ArgException& e ) -{ + ArgException& e ) +{ static_cast(_cmd); // unused std::cout << e.what() << std::endl; throw ExitException(1); @@ -211,15 +211,15 @@ inline void DocBookOutput::basename( std::string& s ) inline void DocBookOutput::printShortArg(Arg* a) { - std::string lt = "<"; - std::string gt = ">"; + std::string lt = "<"; + std::string 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"; @@ -251,8 +251,8 @@ inline void DocBookOutput::printShortArg(Arg* a) inline void DocBookOutput::printLongArg(Arg* a) { - std::string lt = "<"; - std::string gt = ">"; + std::string lt = "<"; + std::string gt = ">"; std::string desc = a->getDescription(); substituteSpecialChars(desc,'<',lt); @@ -296,4 +296,4 @@ inline void DocBookOutput::printLongArg(Arg* a) } } //namespace TCLAP -#endif +#endif diff --git a/src/tclap/HelpVisitor.h b/src/tclap/HelpVisitor.h index 076c640..fec4b1d 100644 --- a/src/tclap/HelpVisitor.h +++ b/src/tclap/HelpVisitor.h @@ -1,23 +1,23 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: HelpVisitor.h - * + * * Copyright (c) 2003, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_HELP_VISITOR_H #define TCLAP_HELP_VISITOR_H @@ -44,12 +44,12 @@ class HelpVisitor: public Visitor protected: /** - * The CmdLine the output will be generated for. + * The CmdLine the output will be generated for. */ CmdLineInterface* _cmd; /** - * The output object. + * The output object. */ CmdLineOutput** _out; @@ -58,17 +58,17 @@ class HelpVisitor: public Visitor /** * Constructor. * \param cmd - The CmdLine the output will be generated for. - * \param out - The type of output. + * \param out - The type of output. */ - HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) + HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) : Visitor(), _cmd( cmd ), _out( out ) { } /** - * Calls the usage method of the CmdLineOutput for the + * Calls the usage method of the CmdLineOutput for the * specified CmdLine. */ void visit() { (*_out)->usage(*_cmd); throw ExitException(0); } - + }; } diff --git a/src/tclap/IgnoreRestVisitor.h b/src/tclap/IgnoreRestVisitor.h index 09bdba7..4601013 100644 --- a/src/tclap/IgnoreRestVisitor.h +++ b/src/tclap/IgnoreRestVisitor.h @@ -1,23 +1,23 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: IgnoreRestVisitor.h - * + * * Copyright (c) 2003, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_IGNORE_REST_VISITOR_H diff --git a/src/tclap/MultiArg.h b/src/tclap/MultiArg.h index 63c88c7..8c36c7f 100644 --- a/src/tclap/MultiArg.h +++ b/src/tclap/MultiArg.h @@ -1,22 +1,22 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: MultiArg.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * *****************************************************************************/ @@ -39,7 +39,7 @@ template class MultiArg : public Arg { public: - typedef std::vector container_type; + typedef std::vector container_type; typedef typename container_type::iterator iterator; typedef typename container_type::const_iterator const_iterator; @@ -56,7 +56,7 @@ protected: std::string _typeDesc; /** - * A list of constraint on this Arg. + * A list of constraint on this Arg. */ Constraint* _constraint; @@ -117,7 +117,7 @@ public: * \param v - An optional visitor. You probably should not * use this unless you have a very good reason. */ - MultiArg( const std::string& flag, + MultiArg( const std::string& flag, const std::string& name, const std::string& desc, bool req, @@ -146,7 +146,7 @@ public: bool req, Constraint* constraint, Visitor* v = NULL ); - + /** * Constructor. * \param flag - The one character flag that identifies this @@ -163,14 +163,14 @@ public: * \param v - An optional visitor. You probably should not * use this unless you have a very good reason. */ - MultiArg( const std::string& flag, + MultiArg( const std::string& flag, const std::string& name, const std::string& desc, bool req, Constraint* constraint, CmdLineInterface& parser, Visitor* v = NULL ); - + /** * Handles the processing of the argument. * This re-implements the Arg version of this method to set the @@ -179,7 +179,7 @@ public: * \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& args); + virtual bool processArg(int* i, std::vector& args); /** * Returns a vector of type T containing the values parsed from @@ -200,13 +200,13 @@ public: const_iterator end() const { return _values.end(); } /** - * Returns the a short id string. Used in the usage. + * 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. + * 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; @@ -218,7 +218,7 @@ public: virtual bool isRequired() const; virtual bool allowMore(); - + virtual void reset(); private: @@ -231,7 +231,7 @@ private: }; template -MultiArg::MultiArg(const std::string& flag, +MultiArg::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, @@ -242,12 +242,12 @@ MultiArg::MultiArg(const std::string& flag, _typeDesc( typeDesc ), _constraint( NULL ), _allowMore(false) -{ +{ _acceptsMultipleValues = true; } template -MultiArg::MultiArg(const std::string& flag, +MultiArg::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, @@ -259,7 +259,7 @@ MultiArg::MultiArg(const std::string& flag, _typeDesc( typeDesc ), _constraint( NULL ), _allowMore(false) -{ +{ parser.add( this ); _acceptsMultipleValues = true; } @@ -268,7 +268,7 @@ MultiArg::MultiArg(const std::string& flag, * */ template -MultiArg::MultiArg(const std::string& flag, +MultiArg::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, @@ -279,12 +279,12 @@ MultiArg::MultiArg(const std::string& flag, _typeDesc( constraint->shortID() ), _constraint( constraint ), _allowMore(false) -{ +{ _acceptsMultipleValues = true; } template -MultiArg::MultiArg(const std::string& flag, +MultiArg::MultiArg(const std::string& flag, const std::string& name, const std::string& desc, bool req, @@ -296,7 +296,7 @@ MultiArg::MultiArg(const std::string& flag, _typeDesc( constraint->shortID() ), _constraint( constraint ), _allowMore(false) -{ +{ parser.add( this ); _acceptsMultipleValues = true; } @@ -305,7 +305,7 @@ template const std::vector& MultiArg::getValue() { return _values; } template -bool MultiArg::processArg(int *i, std::vector& args) +bool MultiArg::processArg(int *i, std::vector& args) { if ( _ignoreable && Arg::ignoreRest() ) return false; @@ -321,7 +321,7 @@ bool MultiArg::processArg(int *i, std::vector& args) if ( argMatches( flag ) ) { if ( Arg::delimiter() != ' ' && value == "" ) - throw( ArgParseException( + throw( ArgParseException( "Couldn't find delimiter for this argument!", toString() ) ); @@ -334,15 +334,15 @@ bool MultiArg::processArg(int *i, std::vector& args) 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 + // 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 ) + args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) _extractValue( args[++(*i)] ); */ @@ -395,7 +395,7 @@ bool MultiArg::isRequired() const } template -void MultiArg::_extractValue( const std::string& val ) +void MultiArg::_extractValue( const std::string& val ) { try { T tmp; @@ -409,10 +409,10 @@ void MultiArg::_extractValue( const std::string& val ) if ( ! _constraint->check( _values.back() ) ) throw( CmdLineParseException( "Value '" + val + "' does not meet constraint: " + - _constraint->description(), + _constraint->description(), toString() ) ); } - + template bool MultiArg::allowMore() { diff --git a/src/tclap/MultiSwitchArg.h b/src/tclap/MultiSwitchArg.h index 7661d85..af3192f 100644 --- a/src/tclap/MultiSwitchArg.h +++ b/src/tclap/MultiSwitchArg.h @@ -1,5 +1,5 @@ -/****************************************************************************** +/****************************************************************************** * * file: MultiSwitchArg.h * @@ -61,12 +61,12 @@ class MultiSwitchArg : public SwitchArg * 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. + * \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, + MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, int init = 0, @@ -82,12 +82,12 @@ class MultiSwitchArg : public SwitchArg * \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. + * \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, + MultiSwitchArg(const std::string& flag, const std::string& name, const std::string& desc, CmdLineInterface& parser, @@ -103,7 +103,7 @@ class MultiSwitchArg : public SwitchArg * \param args - Mutable list of strings. Passed * in from main(). */ - virtual bool processArg(int* i, std::vector& args); + virtual bool processArg(int* i, std::vector& args); /** * Returns int, the number of times the switch has been set. @@ -119,7 +119,7 @@ class MultiSwitchArg : public SwitchArg * Returns the longID for this Arg. */ std::string longID(const std::string& val) const; - + void reset(); }; @@ -138,15 +138,15 @@ _default( init ) { } inline MultiSwitchArg::MultiSwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, + 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 ); } @@ -178,7 +178,7 @@ inline bool MultiSwitchArg::processArg(int *i, std::vector& args) ++_value; // Check for more in argument and increment value. - while ( combinedSwitchesMatch( args[*i] ) ) + while ( combinedSwitchesMatch( args[*i] ) ) ++_value; _checkWithVisitor(); @@ -189,13 +189,13 @@ inline bool MultiSwitchArg::processArg(int *i, std::vector& args) return false; } -inline std::string +inline std::string MultiSwitchArg::shortID(const std::string& val) const { return Arg::shortID(val) + " ... "; } -inline std::string +inline std::string MultiSwitchArg::longID(const std::string& val) const { return Arg::longID(val) + " (accepted multiple times)"; diff --git a/src/tclap/OptionalUnlabeledTracker.h b/src/tclap/OptionalUnlabeledTracker.h index 8174c5f..f06be14 100644 --- a/src/tclap/OptionalUnlabeledTracker.h +++ b/src/tclap/OptionalUnlabeledTracker.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: OptionalUnlabeledTracker.h - * + * * Copyright (c) 2005, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H @@ -37,7 +37,7 @@ class OptionalUnlabeledTracker static void gotOptional() { alreadyOptionalRef() = true; } - static bool& alreadyOptional() { return alreadyOptionalRef(); } + static bool& alreadyOptional() { return alreadyOptionalRef(); } private: diff --git a/src/tclap/StandardTraits.h b/src/tclap/StandardTraits.h index 46d7f6f..9e678ba 100644 --- a/src/tclap/StandardTraits.h +++ b/src/tclap/StandardTraits.h @@ -30,7 +30,7 @@ #include // To check for long long #endif -// If Microsoft has already typedef'd wchar_t as an unsigned +// If Microsoft has already typedef'd wchar_t as an unsigned // short, then compiles will break because it's as if we're // creating ArgTraits twice for unsigned short. Thus... #ifdef _MSC_VER @@ -123,7 +123,7 @@ struct ArgTraits { typedef ValueLike ValueCategory; }; -// Microsoft implements size_t awkwardly. +// Microsoft implements size_t awkwardly. #if defined(_MSC_VER) && defined(_M_X64) /** * size_ts have value-like semantics. @@ -205,4 +205,3 @@ void SetString(T &dst, const std::string &src) } // namespace #endif - diff --git a/src/tclap/StdOutput.h b/src/tclap/StdOutput.h index ec1cb93..cc7260e 100644 --- a/src/tclap/StdOutput.h +++ b/src/tclap/StdOutput.h @@ -1,24 +1,24 @@ // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- -/****************************************************************************** - * +/****************************************************************************** + * * file: StdOutput.h - * + * * Copyright (c) 2004, Michael E. Smoot * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_STDCMDLINEOUTPUT_H #define TCLAP_STDCMDLINEOUTPUT_H @@ -46,77 +46,77 @@ class StdOutput : public CmdLineOutput public: /** - * Prints the usage to stdout. Can be overridden to + * Prints the usage to stdout. Can be overridden to * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void usage(CmdLineInterface& c); /** - * Prints the version to stdout. Can be overridden + * Prints the version to stdout. Can be overridden * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void version(CmdLineInterface& c); /** - * Prints (to stderr) an error message, short usage + * 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. + * \param c - The CmdLine object the output is generated for. + * \param e - The ArgException that caused the failure. */ - virtual void failure(CmdLineInterface& c, + virtual void failure(CmdLineInterface& c, ArgException& e ); protected: /** * Writes a brief usage message with short args. - * \param c - The CmdLine object the output is generated for. + * \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, + * 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 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, + * 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 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, + void spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, int secondLineOffset ) const; }; -inline void StdOutput::version(CmdLineInterface& _cmd) +inline void StdOutput::version(CmdLineInterface& _cmd) { std::string progName = _cmd.getProgramName(); std::string xversion = _cmd.getVersion(); - std::cout << std::endl << progName << " version: " + std::cout << std::endl << progName << " version: " << xversion << std::endl << std::endl; } -inline void StdOutput::usage(CmdLineInterface& _cmd ) +inline void StdOutput::usage(CmdLineInterface& _cmd ) { - std::cout << std::endl << "USAGE: " << std::endl << std::endl; + std::cout << std::endl << "USAGE: " << std::endl << std::endl; _shortUsage( _cmd, std::cout ); @@ -124,12 +124,12 @@ inline void StdOutput::usage(CmdLineInterface& _cmd ) _longUsage( _cmd, std::cout ); - std::cout << std::endl; + std::cout << std::endl; } inline void StdOutput::failure( CmdLineInterface& _cmd, - ArgException& e ) + ArgException& e ) { std::string progName = _cmd.getProgramName(); @@ -140,10 +140,10 @@ inline void StdOutput::failure( CmdLineInterface& _cmd, { std::cerr << "Brief USAGE: " << std::endl; - _shortUsage( _cmd, std::cerr ); + _shortUsage( _cmd, std::cerr ); - std::cerr << std::endl << "For complete USAGE and HELP type: " - << std::endl << " " << progName << " --help" + std::cerr << std::endl << "For complete USAGE and HELP type: " + << std::endl << " " << progName << " --help" << std::endl << std::endl; } else @@ -152,8 +152,8 @@ inline void StdOutput::failure( CmdLineInterface& _cmd, throw ExitException(1); } -inline void -StdOutput::_shortUsage( CmdLineInterface& _cmd, +inline void +StdOutput::_shortUsage( CmdLineInterface& _cmd, std::ostream& os ) const { std::list argList = _cmd.getArgList(); @@ -167,7 +167,7 @@ StdOutput::_shortUsage( CmdLineInterface& _cmd, for ( int i = 0; static_cast(i) < xorList.size(); i++ ) { s += " {"; - for ( ArgVectorIterator it = xorList[i].begin(); + for ( ArgVectorIterator it = xorList[i].begin(); it != xorList[i].end(); it++ ) s += (*it)->shortID() + "|"; @@ -179,7 +179,7 @@ StdOutput::_shortUsage( CmdLineInterface& _cmd, if ( !xorHandler.contains( (*it) ) ) s += " " + (*it)->shortID(); - // if the program name is too long, then adjust the second line offset + // if the program name is too long, then adjust the second line offset int secondLineOffset = static_cast(progName.length()) + 2; if ( secondLineOffset > 75/2 ) secondLineOffset = static_cast(75/2); @@ -187,8 +187,8 @@ StdOutput::_shortUsage( CmdLineInterface& _cmd, spacePrint( os, s, 75, 3, secondLineOffset ); } -inline void -StdOutput::_longUsage( CmdLineInterface& _cmd, +inline void +StdOutput::_longUsage( CmdLineInterface& _cmd, std::ostream& os ) const { std::list argList = _cmd.getArgList(); @@ -196,11 +196,11 @@ StdOutput::_longUsage( CmdLineInterface& _cmd, XorHandler xorHandler = _cmd.getXorHandler(); std::vector< std::vector > xorList = xorHandler.getXorList(); - // first the xor + // first the xor for ( int i = 0; static_cast(i) < xorList.size(); i++ ) { - for ( ArgVectorIterator it = xorList[i].begin(); - it != xorList[i].end(); + for ( ArgVectorIterator it = xorList[i].begin(); + it != xorList[i].end(); it++ ) { spacePrint( os, (*it)->longID(), 75, 3, 3 ); @@ -216,8 +216,8 @@ StdOutput::_longUsage( CmdLineInterface& _cmd, 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 ); + spacePrint( os, (*it)->longID(), 75, 3, 3 ); + spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); os << std::endl; } @@ -226,10 +226,10 @@ StdOutput::_longUsage( CmdLineInterface& _cmd, spacePrint( os, message, 75, 3, 0 ); } -inline void StdOutput::spacePrint( std::ostream& os, - const std::string& s, - int maxWidth, - int indentSpaces, +inline void StdOutput::spacePrint( std::ostream& os, + const std::string& s, + int maxWidth, + int indentSpaces, int secondLineOffset ) const { int len = static_cast(s.length()); @@ -242,19 +242,19 @@ inline void StdOutput::spacePrint( std::ostream& os, { // find the substring length // int stringLen = std::min( len - start, allowedLen ); - // doing it this way to support a VisualC++ 2005 bug - using namespace std; + // doing it this way to support a VisualC++ 2005 bug + using namespace std; int stringLen = min( 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] != ',' && - s[stringLen+start] != '|' ) + s[stringLen+start] != '|' ) stringLen--; - - // ok, the word is longer than the line, so just split + + // ok, the word is longer than the line, so just split // wherever the line ends if ( stringLen <= 0 ) stringLen = allowedLen; @@ -264,7 +264,7 @@ inline void StdOutput::spacePrint( std::ostream& os, if ( s[start+i] == '\n' ) stringLen = i+1; - // print the indent + // print the indent for ( int i = 0; i < indentSpaces; i++ ) os << " "; @@ -282,7 +282,7 @@ inline void StdOutput::spacePrint( std::ostream& os, // so we don't start a line with a space while ( s[stringLen+start] == ' ' && start < len ) start++; - + start += stringLen; } } @@ -295,4 +295,4 @@ inline void StdOutput::spacePrint( std::ostream& os, } } //namespace TCLAP -#endif +#endif diff --git a/src/tclap/SwitchArg.h b/src/tclap/SwitchArg.h index 3a93a93..74f4bf0 100644 --- a/src/tclap/SwitchArg.h +++ b/src/tclap/SwitchArg.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: SwitchArg.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_SWITCH_ARG_H @@ -61,17 +61,17 @@ class SwitchArg : public Arg * 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 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, + 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 @@ -85,14 +85,14 @@ class SwitchArg : public Arg * \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, + 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 @@ -101,7 +101,7 @@ class SwitchArg : public Arg * \param args - Mutable list of strings. Passed * in from main(). */ - virtual bool processArg(int* i, std::vector& args); + virtual bool processArg(int* i, std::vector& args); /** * Checks a string to see if any of the chars in the string @@ -113,7 +113,7 @@ class SwitchArg : public Arg * Returns bool, whether or not the switch has been set. */ bool getValue(); - + virtual void reset(); private: @@ -132,9 +132,9 @@ class SwitchArg : public Arg ////////////////////////////////////////////////////////////////////// //BEGIN SwitchArg.cpp ////////////////////////////////////////////////////////////////////// -inline SwitchArg::SwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, +inline SwitchArg::SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, bool default_val, Visitor* v ) : Arg(flag, name, desc, false, false, v), @@ -142,27 +142,27 @@ inline SwitchArg::SwitchArg(const std::string& flag, _default( default_val ) { } -inline SwitchArg::SwitchArg(const std::string& flag, - const std::string& name, - const std::string& desc, +inline SwitchArg::SwitchArg(const std::string& flag, + const std::string& name, + const std::string& desc, CmdLineInterface& parser, bool default_val, Visitor* v ) : Arg(flag, name, desc, false, false, v), _value( default_val ), _default(default_val) -{ +{ parser.add( this ); } inline bool SwitchArg::getValue() { return _value; } -inline bool SwitchArg::lastCombined(std::string& combinedSwitches ) +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; } @@ -173,32 +173,32 @@ inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches ) combinedSwitches[0] != Arg::flagStartString()[0] ) return false; - // make sure it isn't a long name - if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == + // 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 + // 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. + // a combined switch list. for ( unsigned int i = 1; i < combinedSwitches.length(); i++ ) - if ( _flag.length() > 0 && + if ( _flag.length() > 0 && combinedSwitches[i] == _flag[0] && - _flag[0] != Arg::flagStartString()[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(); + combinedSwitches[i] = Arg::blankChar(); return true; } - // none of the switches passed in the list match. - return false; + // none of the switches passed in the list match. + return false; } inline void SwitchArg::commonProcessing() @@ -207,7 +207,7 @@ inline void SwitchArg::commonProcessing() throw(CmdLineParseException( "Mutually exclusive argument already set!", toString())); - if ( _alreadySet ) + if ( _alreadySet ) throw(CmdLineParseException("Argument already set!", toString())); _alreadySet = true; @@ -235,16 +235,16 @@ inline bool SwitchArg::processArg(int *i, std::vector& args) // 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 + // check again to ensure we don't misinterpret + // this as a MultiSwitchArg if ( combinedSwitchesMatch( args[*i] ) ) - throw(CmdLineParseException("Argument already set!", + 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 + // 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] ); } @@ -255,7 +255,7 @@ inline bool SwitchArg::processArg(int *i, std::vector& args) inline void SwitchArg::reset() { Arg::reset(); - _value = _default; + _value = _default; } ////////////////////////////////////////////////////////////////////// //End SwitchArg.cpp diff --git a/src/tclap/UnlabeledMultiArg.h b/src/tclap/UnlabeledMultiArg.h index d38ce91..b0a3b73 100644 --- a/src/tclap/UnlabeledMultiArg.h +++ b/src/tclap/UnlabeledMultiArg.h @@ -1,23 +1,23 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: UnlabeledMultiArg.h - * + * * Copyright (c) 2003, Michael E. Smoot. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H @@ -33,7 +33,7 @@ namespace TCLAP { /** * Just like a MultiArg, except that the arguments are unlabeled. Basically, - * this Arg will slurp up everything that hasn't been matched to another + * this Arg will slurp up everything that hasn't been matched to another * Arg. */ template @@ -52,9 +52,9 @@ class UnlabeledMultiArg : public MultiArg using MultiArg::toString; public: - + /** - * Constructor. + * 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 @@ -77,7 +77,7 @@ class UnlabeledMultiArg : public MultiArg bool ignoreable = false, Visitor* v = NULL ); /** - * Constructor. + * 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 @@ -101,9 +101,9 @@ class UnlabeledMultiArg : public MultiArg CmdLineInterface& parser, bool ignoreable = false, Visitor* v = NULL ); - + /** - * Constructor. + * 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 @@ -125,7 +125,7 @@ class UnlabeledMultiArg : public MultiArg Visitor* v = NULL ); /** - * Constructor. + * 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 @@ -140,14 +140,14 @@ class UnlabeledMultiArg : public MultiArg * \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, + UnlabeledMultiArg( const std::string& name, + const std::string& desc, bool req, Constraint* 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 @@ -156,7 +156,7 @@ class UnlabeledMultiArg : public MultiArg * \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& args); + virtual bool processArg(int* i, std::vector& args); /** * Returns the a short id string. Used in the usage. @@ -184,28 +184,28 @@ class UnlabeledMultiArg : public MultiArg }; template -UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, bool req, const std::string& typeDesc, bool ignoreable, Visitor* v) : MultiArg("", name, desc, req, typeDesc, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(true, toString()); } template -UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, bool req, const std::string& typeDesc, CmdLineInterface& parser, bool ignoreable, Visitor* v) : MultiArg("", name, desc, req, typeDesc, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(true, toString()); parser.add( this ); @@ -213,28 +213,28 @@ UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, template -UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, bool req, Constraint* constraint, bool ignoreable, Visitor* v) : MultiArg("", name, desc, req, constraint, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(true, toString()); } template -UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, - const std::string& desc, +UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, + const std::string& desc, bool req, Constraint* constraint, CmdLineInterface& parser, bool ignoreable, Visitor* v) : MultiArg("", name, desc, req, constraint, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(true, toString()); parser.add( this ); @@ -242,7 +242,7 @@ UnlabeledMultiArg::UnlabeledMultiArg(const std::string& name, template -bool UnlabeledMultiArg::processArg(int *i, std::vector& args) +bool UnlabeledMultiArg::processArg(int *i, std::vector& args) { if ( _hasBlanks( args[*i] ) ) @@ -251,14 +251,14 @@ bool UnlabeledMultiArg::processArg(int *i, std::vector& args) // never ignore an unlabeled multi arg - // always take the first value, regardless of the start string + // 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 + // 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 ) + args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) _extractValue( args[++(*i)] ); */ diff --git a/src/tclap/UnlabeledValueArg.h b/src/tclap/UnlabeledValueArg.h index 8debba7..fcf6401 100644 --- a/src/tclap/UnlabeledValueArg.h +++ b/src/tclap/UnlabeledValueArg.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: UnlabeledValueArg.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H @@ -72,18 +72,18 @@ class UnlabeledValueArg : public ValueArg * 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 + * 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, + UnlabeledValueArg( const std::string& name, + const std::string& desc, bool req, T value, const std::string& typeDesc, bool ignoreable = false, - Visitor* v = NULL); + Visitor* v = NULL); /** * UnlabeledValueArg constructor. @@ -102,20 +102,20 @@ class UnlabeledValueArg : public ValueArg * \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 + * 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, + 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 ); - + Visitor* v = NULL ); + /** * UnlabeledValueArg constructor. * \param name - A one word name for the argument. Note that this is used for @@ -130,20 +130,20 @@ class UnlabeledValueArg : public ValueArg * 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 + * 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, + UnlabeledValueArg( const std::string& name, + const std::string& desc, bool req, T value, Constraint* constraint, bool ignoreable = false, - Visitor* v = NULL ); + Visitor* v = NULL ); + - /** * UnlabeledValueArg constructor. * \param name - A one word name for the argument. Note that this is used for @@ -159,29 +159,29 @@ class UnlabeledValueArg : public ValueArg * \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 + * 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, + UnlabeledValueArg( const std::string& name, + const std::string& desc, bool req, T value, Constraint* 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. + * \param args - Mutable list of strings. */ - virtual bool processArg(int* i, std::vector& args); + virtual bool processArg(int* i, std::vector& args); /** * Overrides shortID for specific behavior. @@ -210,15 +210,15 @@ class UnlabeledValueArg : public ValueArg * Constructor implemenation. */ template -UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, bool req, T val, const std::string& typeDesc, bool ignoreable, Visitor* v) : ValueArg("", name, desc, req, val, typeDesc, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(req, toString()); @@ -226,8 +226,8 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, } template -UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, bool req, T val, const std::string& typeDesc, @@ -235,7 +235,7 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, bool ignoreable, Visitor* v) : ValueArg("", name, desc, req, val, typeDesc, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(req, toString()); parser.add( this ); @@ -245,22 +245,22 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, * Constructor implemenation. */ template -UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, bool req, T val, Constraint* constraint, bool ignoreable, Visitor* v) : ValueArg("", name, desc, req, val, constraint, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(req, toString()); } template -UnlabeledValueArg::UnlabeledValueArg(const std::string& name, - const std::string& desc, +UnlabeledValueArg::UnlabeledValueArg(const std::string& name, + const std::string& desc, bool req, T val, Constraint* constraint, @@ -268,7 +268,7 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, bool ignoreable, Visitor* v) : ValueArg("", name, desc, req, val, constraint, v) -{ +{ _ignoreable = ignoreable; OptionalUnlabeledTracker::check(req, toString()); parser.add( this ); @@ -278,17 +278,17 @@ UnlabeledValueArg::UnlabeledValueArg(const std::string& name, * Implementation of processArg(). */ template -bool UnlabeledValueArg::processArg(int *i, std::vector& args) +bool UnlabeledValueArg::processArg(int *i, std::vector& args) { - + if ( _alreadySet ) return false; - + if ( _hasBlanks( args[*i] ) ) return false; // never ignore an unlabeled arg - + _extractValue( args[*i] ); _alreadySet = true; return true; @@ -313,8 +313,8 @@ std::string UnlabeledValueArg::longID(const std::string& val) const static_cast(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. + // 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 + ">"; } diff --git a/src/tclap/ValueArg.h b/src/tclap/ValueArg.h index 95f9bb7..bdf7f9c 100644 --- a/src/tclap/ValueArg.h +++ b/src/tclap/ValueArg.h @@ -1,23 +1,23 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: ValueArg.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_VALUE_ARGUMENT_H @@ -40,7 +40,7 @@ namespace TCLAP { * Instead use an UnlabeledValueArg. */ template -class ValueArg : public Arg +class ValueArg : public Arg { protected: @@ -67,7 +67,7 @@ class ValueArg : public Arg std::string _typeDesc; /** - * A Constraint this Arg must conform to. + * A Constraint this Arg must conform to. */ Constraint* _constraint; @@ -75,7 +75,7 @@ class ValueArg : public Arg * 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. + * \param val - value to be parsed. */ void _extractValue( const std::string& val ); @@ -83,9 +83,9 @@ class ValueArg : public Arg /** * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, + * 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, + * 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. @@ -104,20 +104,20 @@ class ValueArg : public 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, + 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, + * 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, + * 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. @@ -137,20 +137,20 @@ class ValueArg : public 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, + 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, + * 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, + * 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. @@ -168,20 +168,20 @@ class ValueArg : public 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, + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T value, Constraint* constraint, CmdLineInterface& parser, Visitor* v = NULL ); - + /** * Labeled ValueArg constructor. - * You could conceivably call this constructor with a blank flag, + * 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, + * 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. @@ -198,10 +198,10 @@ class ValueArg : public 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, + ValueArg( const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T value, Constraint* constraint, Visitor* v = NULL ); @@ -212,10 +212,10 @@ class ValueArg : public Arg * _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 + * \param args - Mutable list of strings. Passed * in from main(). */ - virtual bool processArg(int* i, std::vector& args); + virtual bool processArg(int* i, std::vector& args); /** * Returns the value of the argument. @@ -233,7 +233,7 @@ class ValueArg : public Arg * \param val - value to be used. */ virtual std::string longID(const std::string& val = "val") const; - + virtual void reset() ; private: @@ -249,10 +249,10 @@ private: * Constructor implementation. */ template -ValueArg::ValueArg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T val, const std::string& typeDesc, Visitor* v) @@ -264,10 +264,10 @@ ValueArg::ValueArg(const std::string& flag, { } template -ValueArg::ValueArg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T val, const std::string& typeDesc, CmdLineInterface& parser, @@ -277,15 +277,15 @@ ValueArg::ValueArg(const std::string& flag, _default( val ), _typeDesc( typeDesc ), _constraint( NULL ) -{ +{ parser.add( this ); } template -ValueArg::ValueArg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T val, Constraint* constraint, Visitor* v) @@ -297,10 +297,10 @@ ValueArg::ValueArg(const std::string& flag, { } template -ValueArg::ValueArg(const std::string& flag, - const std::string& name, - const std::string& desc, - bool req, +ValueArg::ValueArg(const std::string& flag, + const std::string& name, + const std::string& desc, + bool req, T val, Constraint* constraint, CmdLineInterface& parser, @@ -310,7 +310,7 @@ ValueArg::ValueArg(const std::string& flag, _default( val ), _typeDesc( constraint->shortID() ), _constraint( constraint ) -{ +{ parser.add( this ); } @@ -344,22 +344,22 @@ bool ValueArg::processArg(int *i, std::vector& args) { if ( _xorSet ) throw( CmdLineParseException( - "Mutually exclusive argument already set!", + "Mutually exclusive argument already set!", toString()) ); else - throw( CmdLineParseException("Argument already set!", + throw( CmdLineParseException("Argument already set!", toString()) ); } if ( Arg::delimiter() != ' ' && value == "" ) - throw( ArgParseException( + throw( ArgParseException( "Couldn't find delimiter for this argument!", toString() ) ); if ( value == "" ) { (*i)++; - if ( static_cast(*i) < args.size() ) + if ( static_cast(*i) < args.size() ) _extractValue( args[*i] ); else throw( ArgParseException("Missing a value for this argument!", @@ -367,11 +367,11 @@ bool ValueArg::processArg(int *i, std::vector& args) } else _extractValue( value ); - + _alreadySet = true; _checkWithVisitor(); return true; - } + } else return false; } @@ -383,7 +383,7 @@ template std::string ValueArg::shortID(const std::string& val) const { static_cast(val); // Ignore input, don't warn - return Arg::shortID( _typeDesc ); + return Arg::shortID( _typeDesc ); } /** @@ -393,22 +393,22 @@ template std::string ValueArg::longID(const std::string& val) const { static_cast(val); // Ignore input, don't warn - return Arg::longID( _typeDesc ); + return Arg::longID( _typeDesc ); } template -void ValueArg::_extractValue( const std::string& val ) +void ValueArg::_extractValue( const std::string& val ) { try { ExtractValue(_value, val, typename ArgTraits::ValueCategory()); } catch( ArgParseException &e) { throw ArgParseException(e.error(), toString()); } - + if ( _constraint != NULL ) if ( ! _constraint->check( _value ) ) - throw( CmdLineParseException( "Value '" + val + - + "' does not meet constraint: " + throw( CmdLineParseException( "Value '" + val + + + "' does not meet constraint: " + _constraint->description(), toString() ) ); } diff --git a/src/tclap/ValuesConstraint.h b/src/tclap/ValuesConstraint.h index 27d3a6d..835b7bf 100644 --- a/src/tclap/ValuesConstraint.h +++ b/src/tclap/ValuesConstraint.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: ValuesConstraint.h - * + * * Copyright (c) 2005, Michael E. Smoot * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_VALUESCONSTRAINT_H #define TCLAP_VALUESCONSTRAINT_H @@ -54,10 +54,10 @@ class ValuesConstraint : public Constraint public: /** - * Constructor. - * \param allowed - vector of allowed values. + * Constructor. + * \param allowed - vector of allowed values. */ - ValuesConstraint(std::vector& allowed); + ValuesConstraint(std::vector& allowed); /** * Virtual destructor. @@ -65,7 +65,7 @@ class ValuesConstraint : public Constraint virtual ~ValuesConstraint() {} /** - * Returns a description of the Constraint. + * Returns a description of the Constraint. */ virtual std::string description() const; @@ -77,14 +77,14 @@ class ValuesConstraint : public Constraint /** * The method used to verify that the value parsed from the command * line meets the constraint. - * \param value - The value that will be checked. + * \param value - The value that will be checked. */ virtual bool check(const T& value) const; - + protected: /** - * The list of valid values. + * The list of valid values. */ std::vector _allowed; @@ -99,7 +99,7 @@ template ValuesConstraint::ValuesConstraint(std::vector& allowed) : _allowed(allowed), _typeDesc("") -{ +{ for ( unsigned int i = 0; i < _allowed.size(); i++ ) { @@ -113,7 +113,7 @@ ValuesConstraint::ValuesConstraint(std::vector& allowed) os << _allowed[i]; - std::string temp( os.str() ); + std::string temp( os.str() ); if ( i > 0 ) _typeDesc += "|"; @@ -126,23 +126,22 @@ bool ValuesConstraint::check( const T& val ) const { if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() ) return false; - else + else return true; } template std::string ValuesConstraint::shortID() const { - return _typeDesc; + return _typeDesc; } template std::string ValuesConstraint::description() const { - return _typeDesc; + return _typeDesc; } } //namespace TCLAP -#endif - +#endif diff --git a/src/tclap/VersionVisitor.h b/src/tclap/VersionVisitor.h index d7e67d8..b7ab87d 100644 --- a/src/tclap/VersionVisitor.h +++ b/src/tclap/VersionVisitor.h @@ -1,24 +1,24 @@ // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- -/****************************************************************************** - * +/****************************************************************************** + * * file: VersionVisitor.h - * + * * Copyright (c) 2003, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_VERSION_VISITOR_H @@ -51,7 +51,7 @@ class VersionVisitor: public Visitor CmdLineInterface* _cmd; /** - * The output object. + * The output object. */ CmdLineOutput** _out; @@ -59,19 +59,19 @@ class VersionVisitor: public Visitor /** * Constructor. - * \param cmd - The CmdLine the output is generated for. - * \param out - The type of output. + * \param cmd - The CmdLine the output is generated for. + * \param out - The type of output. */ - VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) + 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); + void visit() { + (*_out)->version(*_cmd); + throw ExitException(0); } }; diff --git a/src/tclap/Visitor.h b/src/tclap/Visitor.h index 38ddcbd..2ef79f2 100644 --- a/src/tclap/Visitor.h +++ b/src/tclap/Visitor.h @@ -1,23 +1,23 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: Visitor.h - * + * * Copyright (c) 2003, Michael E. Smoot . * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_VISITOR_H diff --git a/src/tclap/XorHandler.h b/src/tclap/XorHandler.h index 13551fb..2727f27 100644 --- a/src/tclap/XorHandler.h +++ b/src/tclap/XorHandler.h @@ -1,24 +1,24 @@ -/****************************************************************************** - * +/****************************************************************************** + * * file: XorHandler.h - * + * * Copyright (c) 2003, Michael E. Smoot . * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno. * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + *****************************************************************************/ #ifndef TCLAP_XORHANDLER_H #define TCLAP_XORHANDLER_H @@ -56,12 +56,12 @@ class XorHandler * \param ors - list of Arg* that will be xor'd. */ void add( std::vector& 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. + * the Arg's in the list. You shouldn't use this. * \param a - The Arg to be checked. */ int check( const Arg* a ); @@ -84,7 +84,7 @@ class XorHandler */ bool contains( const Arg* a ); - std::vector< std::vector >& getXorList(); + std::vector< std::vector >& getXorList(); }; @@ -93,24 +93,24 @@ class XorHandler //BEGIN XOR.cpp ////////////////////////////////////////////////////////////////////// inline void XorHandler::add( std::vector& ors ) -{ +{ _orList.push_back( ors ); } -inline int XorHandler::check( const Arg* a ) +inline int XorHandler::check( const Arg* a ) { // iterate over each XOR list for ( int i = 0; static_cast(i) < _orList.size(); i++ ) { // if the XOR list contains the arg.. - ArgVectorIterator ait = std::find( _orList[i].begin(), + 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(); + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); it++ ) if ( a != (*it) && (*it)->isSet() ) throw(CmdLineParseException( @@ -118,8 +118,8 @@ inline int XorHandler::check( const Arg* a ) (*it)->toString())); // go through and set each arg that is not a - for ( ArgVectorIterator it = _orList[i].begin(); - it != _orList[i].end(); + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); it++ ) if ( a != (*it) ) (*it)->xorSet(); @@ -141,16 +141,16 @@ inline int XorHandler::check( const Arg* a ) inline bool XorHandler::contains( const Arg* a ) { for ( int i = 0; static_cast(i) < _orList.size(); i++ ) - for ( ArgVectorIterator it = _orList[i].begin(); - it != _orList[i].end(); - it++ ) + for ( ArgVectorIterator it = _orList[i].begin(); + it != _orList[i].end(); + it++ ) if ( a == (*it) ) return true; return false; } -inline std::vector< std::vector >& XorHandler::getXorList() +inline std::vector< std::vector >& XorHandler::getXorList() { return _orList; } @@ -163,4 +163,4 @@ inline std::vector< std::vector >& XorHandler::getXorList() } //namespace TCLAP -#endif +#endif diff --git a/src/tclap/ZshCompletionOutput.h b/src/tclap/ZshCompletionOutput.h index 0b37fc7..e2a36ca 100644 --- a/src/tclap/ZshCompletionOutput.h +++ b/src/tclap/ZshCompletionOutput.h @@ -1,24 +1,24 @@ // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*- -/****************************************************************************** - * +/****************************************************************************** + * * file: ZshCompletionOutput.h - * + * * Copyright (c) 2006, Oliver Kiddle * All rights reverved. - * + * * See the file COPYING in the top directory of this distribution for * more information. - * - * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * + * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ + * + *****************************************************************************/ #ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H #define TCLAP_ZSHCOMPLETIONOUTPUT_H @@ -48,24 +48,24 @@ class ZshCompletionOutput : public CmdLineOutput ZshCompletionOutput(); /** - * Prints the usage to stdout. Can be overridden to + * Prints the usage to stdout. Can be overridden to * produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void usage(CmdLineInterface& c); /** - * Prints the version to stdout. Can be overridden + * Prints the version to stdout. Can be overridden * to produce alternative behavior. - * \param c - The CmdLine object the output is generated for. + * \param c - The CmdLine object the output is generated for. */ virtual void version(CmdLineInterface& c); /** - * Prints (to stderr) an error message, short usage + * 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. + * \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 ); @@ -272,7 +272,7 @@ inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Ar { XorHandler xorHandler = _cmd.getXorHandler(); std::vector< std::vector > xorList = xorHandler.getXorList(); - + if (a->getName() == "help" || a->getName() == "version") { return "(-)"; @@ -309,13 +309,13 @@ inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Ar 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(); }