diff --git a/runtime_data/openalpr.conf b/runtime_data/openalpr.conf
index c88437e..38159ec 100644
--- a/runtime_data/openalpr.conf
+++ b/runtime_data/openalpr.conf
@@ -1,6 +1,5 @@
[common]
-
ocr_img_size_percent = 1.33333333
state_id_img_size_percent = 2.0
@@ -26,20 +25,18 @@ postprocess_min_characters = 4
postprocess_max_characters = 10
[debug]
-general = 0
-timing = 0
-state_id = 0
-plate_lines = 0
+general = 0
+timing = 0
+state_id = 0
+plate_lines = 0
plate_corners = 0
-char_regions = 0
-char_segment = 0
+char_regions = 0
+char_segment = 0
char_analysis = 0
-color_filter = 0
-ocr = 0
-postprocess = 0
-show_images = 0
-
-
+color_filter = 0
+ocr = 0
+postprocess = 0
+show_images = 0
;;; Country Specific variables ;;;;
@@ -70,7 +67,6 @@ template_max_height_px = 60
plateline_sensitivity_vertical = 25
plateline_sensitivity_horizontal = 45
-
; Regions smaller than this will be disqualified
min_plate_size_width_px = 70
min_plate_size_height_px = 35
@@ -85,7 +81,6 @@ char_analysis_height_range = 0.15
char_analysis_height_step_size = 0.10
char_analysis_height_num_steps = 5
-
segmentation_min_box_width_px = 8
segmentation_min_charheight_percent = 0.5;
segmentation_max_segment_width_percent_vs_average = 2.0;
diff --git a/src/main.cpp b/src/main.cpp
index e8a3505..c51cc32 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,90 +17,83 @@
* along with this program. If not, see .
*/
+#include
+#include
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
- #include
- #include
+#include "tclap/CmdLine.h"
+#include "support/filesystem.h"
+#include "support/timing.h"
+#include "alpr.h"
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
+const std::string MAIN_WINDOW_NAME = "ALPR main window";
+const bool SAVE_LAST_VIDEO_STILL = false;
+const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg";
- #include "tclap/CmdLine.h"
- #include "support/filesystem.h"
- #include "support/timing.h"
- #include "alpr.h"
+/** Function Headers */
+bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson);
+bool measureProcessingTime = false;
+int main( int argc, const char** argv )
+{
+ std::string filename;
+ std::string runtimePath = "";
+ bool outputJson = false;
+ int seektoms = 0;
+ bool detectRegion = false;
+ std::string templateRegion;
+ std::string country;
+ int topn;
- const std::string MAIN_WINDOW_NAME = "ALPR main window";
+ try
+ {
+ TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION);
- const bool SAVE_LAST_VIDEO_STILL = false;
- const std::string LAST_VIDEO_STILL_LOCATION = "/tmp/laststill.jpg";
+ TCLAP::UnlabeledValueArg 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");
- /** Function Headers */
- bool detectandshow(Alpr* alpr, cv::Mat frame, std::string region, bool writeJson);
+ TCLAP::SwitchArg jsonSwitch("j","json","Output recognition results in JSON format. Default=off", cmd, false);
+ TCLAP::SwitchArg detectRegionSwitch("d","detect_region","Attempt to detect the region of the plate image. Default=off", cmd, false);
+ TCLAP::SwitchArg clockSwitch("","clock","Measure/print the total time to process image and all plates. Default=off", cmd, false);
+ cmd.add( fileArg );
+ cmd.add( countryCodeArg );
+ cmd.add( seekToMsArg );
+ cmd.add( topNArg );
+ cmd.add( runtimeDirArg );
+ cmd.add( templateRegionArg );
- bool measureProcessingTime = false;
+ cmd.parse( argc, argv );
- int main( int argc, const char** argv )
- {
- std::string filename;
- std::string runtimePath = "";
- bool outputJson = false;
- int seektoms = 0;
- bool detectRegion = false;
- std::string templateRegion;
- std::string country;
- int topn;
+ filename = fileArg.getValue();
- try {
+ country = countryCodeArg.getValue();
+ seektoms = seekToMsArg.getValue();
+ outputJson = jsonSwitch.getValue();
+ runtimePath = runtimeDirArg.getValue();
+ detectRegion = detectRegionSwitch.getValue();
+ templateRegion = templateRegionArg.getValue();
+ topn = topNArg.getValue();
+ measureProcessingTime = clockSwitch.getValue();
- TCLAP::CmdLine cmd("OpenAlpr Command Line Utility", ' ', OPENALPR_VERSION);
-
- TCLAP::UnlabeledValueArg 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);
-
- cmd.add( fileArg );
- cmd.add( countryCodeArg );
- cmd.add( seekToMsArg );
- cmd.add( topNArg );
- cmd.add( runtimeDirArg );
- cmd.add( templateRegionArg );
-
- cmd.parse( argc, argv );
-
- filename = fileArg.getValue();
-
- country = countryCodeArg.getValue();
- seektoms = seekToMsArg.getValue();
- outputJson = jsonSwitch.getValue();
- runtimePath = runtimeDirArg.getValue();
- detectRegion = detectRegionSwitch.getValue();
- templateRegion = templateRegionArg.getValue();
- topn = topNArg.getValue();
- measureProcessingTime = clockSwitch.getValue();
-
- } catch (TCLAP::ArgException &e) // catch any exceptions
- {
- std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
- return 1;
- }
-
- cv::Mat frame;
+ }
+ catch (TCLAP::ArgException &e) // catch any exceptions
+ {
+ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
+ return 1;
+ }
+ cv::Mat frame;
Alpr alpr(country, runtimePath);
alpr.setTopN(topn);
@@ -125,15 +118,15 @@
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
- std::cout << "Error opening webcam" << std::endl;
- return 1;
+ std::cout << "Error opening webcam" << std::endl;
+ return 1;
}
while (cap.read(frame) == true)
{
- detectandshow(&alpr, frame, "", outputJson);
- cv::waitKey(1);
- framenum++;
+ detectandshow(&alpr, frame, "", outputJson);
+ cv::waitKey(1);
+ framenum++;
}
}
else if (hasEnding(filename, ".avi") || hasEnding(filename, ".mp4") || hasEnding(filename, ".webm") || hasEnding(filename, ".flv"))
@@ -148,16 +141,16 @@
while (cap.read(frame) == true)
{
- if (SAVE_LAST_VIDEO_STILL == true)
- {
- cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame);
- }
- std::cout << "Frame: " << framenum << std::endl;
+ if (SAVE_LAST_VIDEO_STILL == true)
+ {
+ cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame);
+ }
+ std::cout << "Frame: " << framenum << std::endl;
- detectandshow( &alpr, frame, "", outputJson);
- //create a 1ms delay
- cv::waitKey(1);
- framenum++;
+ detectandshow( &alpr, frame, "", outputJson);
+ //create a 1ms delay
+ cv::waitKey(1);
+ framenum++;
}
}
else
@@ -179,32 +172,31 @@
std::cerr << "Image file not found: " << filename << std::endl;
}
-
}
else if (DirectoryExists(filename.c_str()))
{
- std::vector files = getFilesInDir(filename.c_str());
+ std::vector files = getFilesInDir(filename.c_str());
- std::sort( files.begin(), files.end(), stringCompare );
+ std::sort( files.begin(), files.end(), stringCompare );
- for (int i = 0; i< files.size(); i++)
+ for (int i = 0; i< files.size(); i++)
+ {
+ if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png"))
{
- if (hasEnding(files[i], ".jpg") || hasEnding(files[i], ".png"))
- {
- std::string fullpath = filename + "/" + files[i];
- std::cout << fullpath << std::endl;
- frame = cv::imread( fullpath.c_str() );
- if (detectandshow( &alpr, frame, "", outputJson))
- {
- //while ((char) cv::waitKey(50) != 'c') { }
- }
- else
- {
- //cv::waitKey(50);
- }
- }
-
+ std::string fullpath = filename + "/" + files[i];
+ std::cout << fullpath << std::endl;
+ frame = cv::imread( fullpath.c_str() );
+ if (detectandshow( &alpr, frame, "", outputJson))
+ {
+ //while ((char) cv::waitKey(50) != 'c') { }
+ }
+ else
+ {
+ //cv::waitKey(50);
+ }
}
+
+ }
}
else
{
@@ -212,53 +204,45 @@
return 1;
}
-
-
return 0;
- }
+}
+bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson)
+{
- bool detectandshow( Alpr* alpr, cv::Mat frame, std::string region, bool writeJson)
- {
+ std::vector buffer;
+ cv::imencode(".bmp", frame, buffer );
+ timespec startTime;
+ getTime(&startTime);
- std::vector buffer;
- cv::imencode(".bmp", frame, buffer );
+ std::vector results = alpr->recognize(buffer);
-
- timespec startTime;
- getTime(&startTime);
-
-
- std::vector results = alpr->recognize(buffer);
-
-
- if (writeJson)
- {
+ if (writeJson)
+ {
std::cout << alpr->toJson(results) << std::endl;
- }
- else
- {
+ }
+ else
+ {
for (int i = 0; i < results.size(); i++)
{
std::cout << "plate" << i << ": " << results[i].result_count << " results -- Processing Time = " << results[i].processing_time_ms << "ms." << std::endl;
for (int k = 0; k < results[i].topNPlates.size(); k++)
{
- std::cout << " - " << results[i].topNPlates[k].characters << "\t confidence: " << results[i].topNPlates[k].overall_confidence << "\t template_match: " << results[i].topNPlates[k].matches_template << std::endl;
+ std::cout << " - " << results[i].topNPlates[k].characters << "\t confidence: " << results[i].topNPlates[k].overall_confidence << "\t template_match: " << results[i].topNPlates[k].matches_template << std::endl;
}
}
- }
+ }
- timespec endTime;
- getTime(&endTime);
- if (measureProcessingTime)
- std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl;
+ timespec endTime;
+ getTime(&endTime);
+ if (measureProcessingTime)
+ std::cout << "Total Time to process image: " << diffclock(startTime, endTime) << "ms." << std::endl;
+ if (results.size() > 0)
+ return true;
+ return false;
- if (results.size() > 0)
- return true;
- return false;
-
- }
+}
diff --git a/src/misc_utilities/benchmark.cpp b/src/misc_utilities/benchmark.cpp
index 909775b..bcfe1b9 100644
--- a/src/misc_utilities/benchmark.cpp
+++ b/src/misc_utilities/benchmark.cpp
@@ -17,12 +17,12 @@
* along with this program. If not, see .
*/
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
- #include
- #include
- #include
+#include
+#include
+#include
#include
#include // std::accumulate
@@ -34,8 +34,8 @@
//#include "utility.h"
#include "support/filesystem.h"
- using namespace std;
- using namespace cv;
+using namespace std;
+using namespace cv;
// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR
@@ -44,47 +44,44 @@ void outputStats(vector datapoints);
int main( int argc, const char** argv )
{
- string country;
- string benchmarkName;
- string inDir;
- string outDir;
- Mat frame;
-
+ string country;
+ string benchmarkName;
+ string inDir;
+ string outDir;
+ Mat frame;
//Check if user specify image to process
if(argc == 5)
{
- country = argv[1];
- benchmarkName = argv[2];
- inDir = argv[3];
- outDir = argv[4];
+ country = argv[1];
+ benchmarkName = argv[2];
+ inDir = argv[3];
+ outDir = argv[4];
-
- }else{
- printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]);
- printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]);
- printf("\n");
- printf("\ttest names are: speed, segocr, detection\n\n" );
- return 0;
}
-
+ else
+ {
+ printf("Use:\n\t%s [country] [benchmark name] [img input dir] [results output dir]\n",argv[0]);
+ printf("\tex: %s us speed ./speed/usimages ./speed\n",argv[0]);
+ printf("\n");
+ printf("\ttest names are: speed, segocr, detection\n\n" );
+ return 0;
+ }
if (DirectoryExists(inDir.c_str()) == false)
{
- printf("Input dir does not exist\n");
- return 0;
+ printf("Input dir does not exist\n");
+ return 0;
}
if (DirectoryExists(outDir.c_str()) == false)
{
- printf("Output dir does not exist\n");
- return 0;
+ printf("Output dir does not exist\n");
+ return 0;
}
-
vector files = getFilesInDir(inDir.c_str());
sort( files.begin(), files.end(), stringCompare );
-
if (benchmarkName.compare("segocr") == 0)
{
Config* config = new Config(country);
@@ -92,55 +89,50 @@ int main( int argc, const char** argv )
OCR* ocr = new OCR(config);
-
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
- string fullpath = inDir + "/" + files[i];
+ string fullpath = inDir + "/" + files[i];
- frame = imread( fullpath.c_str() );
- resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
+ frame = imread( fullpath.c_str() );
+ resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
- Rect plateCoords;
- plateCoords.x = 0;
- plateCoords.y = 0;
- plateCoords.width = frame.cols;
- plateCoords.height = frame.rows;
+ Rect plateCoords;
+ plateCoords.x = 0;
+ plateCoords.y = 0;
+ plateCoords.width = frame.cols;
+ plateCoords.height = frame.rows;
- char statecode[3];
- statecode[0] = files[i][0];
- statecode[1] = files[i][1];
- statecode[2] = '\0';
- string statecodestr(statecode);
+ char statecode[3];
+ statecode[0] = files[i][0];
+ statecode[1] = files[i][1];
+ statecode[2] = '\0';
+ string statecodestr(statecode);
- CharacterRegion charRegion(frame, config);
+ CharacterRegion charRegion(frame, config);
- if (abs(charRegion.getTopLine().angle) > 4)
- {
- // Rotate image:
- Mat rotated(frame.size(), frame.type());
- Mat rot_mat( 2, 3, CV_32FC1 );
- Point center = Point( frame.cols/2, frame.rows/2 );
+ if (abs(charRegion.getTopLine().angle) > 4)
+ {
+ // Rotate image:
+ Mat rotated(frame.size(), frame.type());
+ Mat rot_mat( 2, 3, CV_32FC1 );
+ Point center = Point( frame.cols/2, frame.rows/2 );
- rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 );
- warpAffine( frame, rotated, rot_mat, frame.size() );
+ rot_mat = getRotationMatrix2D( center, charRegion.getTopLine().angle, 1.0 );
+ warpAffine( frame, rotated, rot_mat, frame.size() );
- rotated.copyTo(frame);
- }
+ rotated.copyTo(frame);
+ }
+ CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config);
+ ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
+ ocr->postProcessor->analyze(statecode, 25);
+ cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl;
- CharacterSegmenter charSegmenter(frame, charRegion.thresholdsInverted(), config);
- ocr->performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
- ocr->postProcessor->analyze(statecode, 25);
-
- cout << files[i] << "," << statecode << "," << ocr->postProcessor->bestChars << endl;
-
-
- imshow("Current LP", frame);
- waitKey(5);
-
+ imshow("Current LP", frame);
+ waitKey(5);
}
@@ -158,14 +150,13 @@ int main( int argc, const char** argv )
{
if (hasEnding(files[i], ".png"))
{
- string fullpath = inDir + "/" + files[i];
- frame = imread( fullpath.c_str() );
+ string fullpath = inDir + "/" + files[i];
+ frame = imread( fullpath.c_str() );
- vector regions = plateDetector.detect(frame);
-
- imshow("Current LP", frame);
- waitKey(5);
+ vector regions = plateDetector.detect(frame);
+ imshow("Current LP", frame);
+ waitKey(5);
}
@@ -173,7 +164,7 @@ int main( int argc, const char** argv )
}
else if (benchmarkName.compare("speed") == 0)
{
- // Benchmarks speed of region detection, plate analysis, and OCR
+ // Benchmarks speed of region detection, plate analysis, and OCR
timespec startTime;
timespec endTime;
@@ -197,75 +188,72 @@ int main( int argc, const char** argv )
vector ocrTimes;
vector postProcessTimes;
-
for (int i = 0; i< files.size(); i++)
{
if (hasEnding(files[i], ".png"))
{
- cout << "Image: " << files[i] << endl;
+ cout << "Image: " << files[i] << endl;
- string fullpath = inDir + "/" + files[i];
- frame = imread( fullpath.c_str() );
+ string fullpath = inDir + "/" + files[i];
+ frame = imread( fullpath.c_str() );
+ getTime(&startTime);
+ alpr.recognize(frame);
+ getTime(&endTime);
+ double endToEndTime = diffclock(startTime, endTime);
+ cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl;
+ endToEndTimes.push_back(endToEndTime);
- getTime(&startTime);
- alpr.recognize(frame);
- getTime(&endTime);
- double endToEndTime = diffclock(startTime, endTime);
- cout << " -- End to End recognition time: " << endToEndTime << "ms." << endl;
- endToEndTimes.push_back(endToEndTime);
+ getTime(&startTime);
+ vector regions = plateDetector.detect(frame);
+ getTime(&endTime);
- 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);
- double regionDetectionTime = diffclock(startTime, endTime);
- cout << " -- Region detection time: " << regionDetectionTime << "ms." << endl;
- regionDetectionTimes.push_back(regionDetectionTime);
+ for (int z = 0; z < regions.size(); z++)
+ {
+ getTime(&startTime);
+ char temp[5];
+ stateIdentifier.recognize(frame, regions[z], temp);
+ getTime(&endTime);
+ double stateidTime = diffclock(startTime, endTime);
+ cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
+ stateIdTimes.push_back(stateidTime);
- for (int z = 0; z < regions.size(); z++)
- {
- getTime(&startTime);
- char temp[5];
- stateIdentifier.recognize(frame, regions[z], temp);
- getTime(&endTime);
- double stateidTime = diffclock(startTime, endTime);
- cout << "\tRegion " << z << ": State ID time: " << stateidTime << "ms." << endl;
- stateIdTimes.push_back(stateidTime);
+ getTime(&startTime);
+ LicensePlateCandidate lp(frame, regions[z], &config);
+ lp.recognize();
+ getTime(&endTime);
+ double analysisTime = diffclock(startTime, endTime);
+ cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;
- getTime(&startTime);
- LicensePlateCandidate lp(frame, regions[z], &config);
- lp.recognize();
- getTime(&endTime);
- double analysisTime = diffclock(startTime, endTime);
- cout << "\tRegion " << z << ": Analysis time: " << analysisTime << "ms." << endl;
+ if (lp.confidence > 10)
+ {
+ lpAnalysisPositiveTimes.push_back(analysisTime);
- if (lp.confidence > 10)
- {
- lpAnalysisPositiveTimes.push_back(analysisTime);
+ getTime(&startTime);
+ ocr.performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
+ getTime(&endTime);
+ double ocrTime = diffclock(startTime, endTime);
+ cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl;
+ ocrTimes.push_back(ocrTime);
+ getTime(&startTime);
+ ocr.postProcessor->analyze("", 25);
+ getTime(&endTime);
+ double postProcessTime = diffclock(startTime, endTime);
+ cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl;
+ postProcessTimes.push_back(postProcessTime);
+ }
+ else
+ {
+ lpAnalysisNegativeTimes.push_back(analysisTime);
+ }
+ }
- getTime(&startTime);
- ocr.performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
- getTime(&endTime);
- double ocrTime = diffclock(startTime, endTime);
- cout << "\tRegion " << z << ": OCR time: " << ocrTime << "ms." << endl;
- ocrTimes.push_back(ocrTime);
-
- getTime(&startTime);
- ocr.postProcessor->analyze("", 25);
- getTime(&endTime);
- double postProcessTime = diffclock(startTime, endTime);
- cout << "\tRegion " << z << ": PostProcess time: " << postProcessTime << "ms." << endl;
- postProcessTimes.push_back(postProcessTime);
- }
- else
- {
- lpAnalysisNegativeTimes.push_back(analysisTime);
- }
- }
-
- waitKey(5);
+ waitKey(5);
}
@@ -273,7 +261,6 @@ int main( int argc, const char** argv )
cout << endl << "---------------------" << endl;
-
cout << "End to End Time Statistics:" << endl;
outputStats(endToEndTimes);
cout << endl;
@@ -315,24 +302,23 @@ int main( int argc, const char** argv )
{
if (hasEnding(files[i], ".png"))
{
- string fullpath = inDir + "/" + files[i];
- frame = imread( fullpath.c_str() );
+ string fullpath = inDir + "/" + files[i];
+ frame = imread( fullpath.c_str() );
- vector buffer;
- imencode(".bmp", frame, buffer );
+ vector buffer;
+ imencode(".bmp", frame, buffer );
- vector results = alpr.recognize(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 << files[i] << ": ";
+ for (int z = 0; z < results.size(); z++)
+ {
+ outputdatafile << results[z].bestPlate.characters << ", ";
+ }
+ outputdatafile << endl;
+ imshow("Current LP", frame);
+ waitKey(5);
}
@@ -350,7 +336,7 @@ void outputStats(vector datapoints)
std::vector diff(datapoints.size());
std::transform(datapoints.begin(), datapoints.end(), diff.begin(),
- std::bind2nd(std::minus(), mean));
+ std::bind2nd(std::minus(), mean));
double sq_sum = std::inner_product(diff.begin(), diff.end(), diff.begin(), 0.0);
double stdev = std::sqrt(sq_sum / datapoints.size());
diff --git a/src/misc_utilities/classifychars.cpp b/src/misc_utilities/classifychars.cpp
index 47c200b..c8f2463 100644
--- a/src/misc_utilities/classifychars.cpp
+++ b/src/misc_utilities/classifychars.cpp
@@ -31,8 +31,8 @@
#include "support/filesystem.h"
#include "ocr.h"
- using namespace std;
- using namespace cv;
+using namespace std;
+using namespace cv;
// Given a directory full of lp images (named [statecode]#.png) crop out the alphanumeric characters.
// These will be used to train the OCR
@@ -61,36 +61,34 @@ const int DASHBOARD_COLUMNS = 3;
#endif
-
void showDashboard(vector 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;
-
+ string inDir;
+ string outDir;
+ Mat frame;
//Check if user specify image to process
if(argc == 3)
{
- inDir = argv[1];
- outDir = argv[2];
+ inDir = argv[1];
+ outDir = argv[2];
-
- }else{
- printf("Use:\n\t%s indirectory outdirectory\n",argv[0]);
- printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]);
- return 0;
}
-
+ else
+ {
+ printf("Use:\n\t%s indirectory outdirectory\n",argv[0]);
+ printf("Ex: \n\t%s ./pics/ ./out \n",argv[0]);
+ return 0;
+ }
if (DirectoryExists(outDir.c_str()) == false)
{
- printf("Output dir does not exist\n");
- return 0;
+ printf("Output dir does not exist\n");
+ return 0;
}
cout << "Usage: " << endl;
@@ -110,172 +108,166 @@ int main( int argc, const char** argv )
if (DirectoryExists(inDir.c_str()))
{
- vector files = getFilesInDir(inDir.c_str());
+ vector files = getFilesInDir(inDir.c_str());
- sort( files.begin(), files.end(), stringCompare );
+ sort( files.begin(), files.end(), stringCompare );
- for (int i = 0; i< files.size(); i++)
+ for (int i = 0; i< files.size(); i++)
+ {
+ if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
- if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
- {
- string fullpath = inDir + "/" + files[i];
- cout << fullpath << endl;
- frame = imread( fullpath.c_str() );
- resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
+ string fullpath = inDir + "/" + files[i];
+ cout << fullpath << endl;
+ frame = imread( fullpath.c_str() );
+ resize(frame, frame, Size(config->ocrImageWidthPx, config->ocrImageHeightPx));
- imshow ("Original", frame);
+ imshow ("Original", frame);
+ char statecode[3];
+ statecode[0] = files[i][0];
+ statecode[1] = files[i][1];
+ statecode[2] = '\0';
+ string statecodestr(statecode);
- char statecode[3];
- statecode[0] = files[i][0];
- statecode[1] = files[i][1];
- statecode[2] = '\0';
- string statecodestr(statecode);
+ CharacterRegion regionizer(frame, config);
- CharacterRegion regionizer(frame, config);
+ if (abs(regionizer.getTopLine().angle) > 4)
+ {
+ // Rotate image:
+ Mat rotated(frame.size(), frame.type());
+ Mat rot_mat( 2, 3, CV_32FC1 );
+ Point center = Point( frame.cols/2, frame.rows/2 );
- if (abs(regionizer.getTopLine().angle) > 4)
- {
- // Rotate image:
- Mat rotated(frame.size(), frame.type());
- Mat rot_mat( 2, 3, CV_32FC1 );
- Point center = Point( frame.cols/2, frame.rows/2 );
+ rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 );
+ warpAffine( frame, rotated, rot_mat, frame.size() );
- rot_mat = getRotationMatrix2D( center, regionizer.getTopLine().angle, 1.0 );
- warpAffine( frame, rotated, rot_mat, frame.size() );
+ rotated.copyTo(frame);
+ }
- rotated.copyTo(frame);
- }
+ CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config);
- CharacterSegmenter charSegmenter(frame, regionizer.thresholdsInverted(), config);
+ //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);
- //ocr.cleanCharRegions(charSegmenter.thresholds, charSegmenter.characters);
+ ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
+ ocr.postProcessor->analyze(statecodestr, 25);
+ cout << "OCR results: " << ocr.postProcessor->bestChars << endl;
- ocr.performOCR(charSegmenter.getThresholds(), charSegmenter.characters);
- ocr.postProcessor->analyze(statecodestr, 25);
- cout << "OCR results: " << ocr.postProcessor->bestChars << endl;
+ vector selectedBoxes(charSegmenter.getThresholds().size());
+ for (int z = 0; z < charSegmenter.getThresholds().size(); z++)
+ selectedBoxes[z] = false;
+ int curDashboardSelection = 0;
- vector selectedBoxes(charSegmenter.getThresholds().size());
- for (int z = 0; z < charSegmenter.getThresholds().size(); z++)
- selectedBoxes[z] = false;
+ vector humanInputs(charSegmenter.characters.size());
- int curDashboardSelection = 0;
+ for (int z = 0; z < charSegmenter.characters.size(); z++)
+ humanInputs[z] = ' ';
- vector humanInputs(charSegmenter.characters.size());
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0);
- for (int z = 0; z < charSegmenter.characters.size(); z++)
- humanInputs[z] = ' ';
+ char waitkey = (char) waitKey(50);
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, 0);
+ while (waitkey != 'n' && waitkey != 'p') // Next image
+ {
+ if (waitkey == LEFT_ARROW_KEY) // left arrow key
+ {
+ if (curDashboardSelection > 0)
+ curDashboardSelection--;
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
+ }
+ else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
+ {
+ if (curDashboardSelection < charSegmenter.getThresholds().size() - 1)
+ curDashboardSelection++;
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
+ }
+ else if (waitkey == DOWN_ARROW_KEY)
+ {
+ if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1)
+ curDashboardSelection += DASHBOARD_COLUMNS;
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
+ }
+ else if (waitkey == UP_ARROW_KEY)
+ {
+ if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
+ curDashboardSelection -= DASHBOARD_COLUMNS;
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
+ }
+ else if (waitkey == ENTER_KEY)
+ {
+ vector tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr);
+ for (int c = 0; c < charSegmenter.characters.size(); c++)
+ humanInputs[c] = tempdata[c];
+ }
+ else if (waitkey == SPACE_KEY)
+ {
+ selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
+ showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
+ }
+ else if (waitkey == 's' || waitkey == 'S')
+ {
+ bool somethingSelected = false;
+ bool chardataTagged = false;
+ for (int c = 0; c < charSegmenter.getThresholds().size(); c++)
+ {
+ if (selectedBoxes[c])
+ {
+ somethingSelected = true;
+ break;
+ }
+ }
+ for (int c = 0; c < charSegmenter.characters.size(); c++)
+ {
+ if (humanInputs[c] != ' ')
+ {
+ chardataTagged = true;
+ break;
+ }
+ }
+ // Save
+ if (somethingSelected && chardataTagged)
+ {
+ for (int c = 0; c < charSegmenter.characters.size(); c++)
+ {
+ if (humanInputs[c] == ' ')
+ continue;
+ for (int t = 0; t < charSegmenter.getThresholds().size(); t++)
+ {
+ if (selectedBoxes[t] == false)
+ continue;
- char waitkey = (char) waitKey(50);
+ stringstream filename;
+ Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]);
+ filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
+ imwrite(filename.str(), cropped);
+ cout << "Writing char image: " << filename.str() << endl;
+ }
+ }
+ }
+ else if (somethingSelected == false)
+ cout << "Did not select any boxes" << endl;
+ else if (chardataTagged == false)
+ cout << "You have not tagged any characters" << endl;
+ }
- while (waitkey != 'n' && waitkey != 'p') // Next image
- {
- if (waitkey == LEFT_ARROW_KEY) // left arrow key
- {
- if (curDashboardSelection > 0)
- curDashboardSelection--;
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
- }
- else if (waitkey == RIGHT_ARROW_KEY) // right arrow key
- {
- if (curDashboardSelection < charSegmenter.getThresholds().size() - 1)
- curDashboardSelection++;
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
- }
- else if (waitkey == DOWN_ARROW_KEY)
- {
- if (curDashboardSelection + DASHBOARD_COLUMNS <= charSegmenter.getThresholds().size() - 1)
- curDashboardSelection += DASHBOARD_COLUMNS;
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
- }
- else if (waitkey == UP_ARROW_KEY)
- {
- if (curDashboardSelection - DASHBOARD_COLUMNS >= 0)
- curDashboardSelection -= DASHBOARD_COLUMNS;
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
- }
- else if (waitkey == ENTER_KEY)
- {
- vector tempdata = showCharSelection(charSegmenter.getThresholds()[curDashboardSelection], charSegmenter.characters, statecodestr);
- for (int c = 0; c < charSegmenter.characters.size(); c++)
- humanInputs[c] = tempdata[c];
- }
- else if (waitkey == SPACE_KEY)
- {
- selectedBoxes[curDashboardSelection] = !selectedBoxes[curDashboardSelection];
- showDashboard(charSegmenter.getThresholds(), selectedBoxes, curDashboardSelection);
- }
- else if (waitkey == 's' || waitkey == 'S')
- {
- bool somethingSelected = false;
- bool chardataTagged = false;
- for (int c = 0; c < charSegmenter.getThresholds().size(); c++)
- {
- if (selectedBoxes[c])
- {
- somethingSelected = true;
- break;
- }
- }
- for (int c = 0; c < charSegmenter.characters.size(); c++)
- {
- if (humanInputs[c] != ' ')
- {
- chardataTagged = true;
- break;
- }
- }
- // Save
- if (somethingSelected && chardataTagged)
- {
+ waitkey = (char) waitKey(50);
- for (int c = 0; c < charSegmenter.characters.size(); c++)
- {
- if (humanInputs[c] == ' ')
- continue;
+ }
- for (int t = 0; t < charSegmenter.getThresholds().size(); t++)
- {
- if (selectedBoxes[t] == false)
- continue;
-
- stringstream filename;
- Mat cropped = charSegmenter.getThresholds()[t](charSegmenter.characters[c]);
- filename << outDir << "/" << humanInputs[c] << "-" << t << "-" << files[i];
- imwrite(filename.str(), cropped);
- cout << "Writing char image: " << filename.str() << endl;
- }
- }
- }
- else if (somethingSelected == false)
- cout << "Did not select any boxes" << endl;
- else if (chardataTagged == false)
- cout << "You have not tagged any characters" << endl;
- }
-
- waitkey = (char) waitKey(50);
-
- }
-
- if (waitkey == 'p')
- i = i - 2;
- if (i < -1)
- i = -1;
-
-
- }
+ if (waitkey == 'p')
+ i = i - 2;
+ if (i < -1)
+ i = -1;
}
+
+ }
}
}
-
void showDashboard(vector images, vector selectedImages, int selectedIndex)
{
vector vecCopy;
@@ -309,62 +301,60 @@ void showDashboard(vector images, vector selectedImages, int selected
vector showCharSelection(Mat image, vector charRegions, string state)
{
- int curCharIdx = 0;
+ int curCharIdx = 0;
- vector humanInputs(charRegions.size());
- for (int i = 0; i < charRegions.size(); i++)
- humanInputs[i] = (char) SPACE_KEY;
+ 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);
- char waitkey = (char) waitKey(50);
- while (waitkey != ENTER_KEY && waitkey != ESCAPE_KEY)
+ rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);
+
+ imshow("Character selector", imgCopy);
+
+ if (waitkey == LEFT_ARROW_KEY)
+ curCharIdx--;
+ else if (waitkey == RIGHT_ARROW_KEY )
+ curCharIdx++;
+ else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
{
- Mat imgCopy(image.size(), image.type());
- image.copyTo(imgCopy);
- cvtColor(imgCopy, imgCopy, CV_GRAY2BGR);
+ // Save the character to disk
+ humanInputs[curCharIdx] = toupper((char) waitkey);
+ curCharIdx++;
- rectangle(imgCopy, charRegions[curCharIdx], Scalar(0, 255, 0), 1);
-
- imshow("Character selector", imgCopy);
-
- if (waitkey == LEFT_ARROW_KEY)
- curCharIdx--;
- else if (waitkey == RIGHT_ARROW_KEY )
- curCharIdx++;
- else if ((waitkey >= '0' && waitkey <= '9') || (waitkey >= 'a' && waitkey <= 'z') || waitkey == SPACE_KEY)
- {
- // Save the character to disk
- humanInputs[curCharIdx] = toupper((char) waitkey);
- curCharIdx++;
-
- if (curCharIdx >= charRegions.size())
- {
- waitkey = (char) ENTER_KEY;
- break;
- }
- }
-
- if (curCharIdx < 0)
- curCharIdx = 0;
if (curCharIdx >= charRegions.size())
- curCharIdx = charRegions.size() -1;
-
- waitkey = (char) waitKey(50);
+ {
+ waitkey = (char) ENTER_KEY;
+ break;
+ }
}
- if (waitkey == ENTER_KEY)
+ if (curCharIdx < 0)
+ curCharIdx = 0;
+ if (curCharIdx >= charRegions.size())
+ curCharIdx = charRegions.size() -1;
+
+ waitkey = (char) waitKey(50);
+ }
+
+ if (waitkey == ENTER_KEY)
+ {
+ // Save all the inputs
+ for (int i = 0; i < charRegions.size(); i++)
{
- // Save all the inputs
- for (int i = 0; i < charRegions.size(); i++)
- {
- if (humanInputs[i] != (char) SPACE_KEY)
- cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
- }
-
+ if (humanInputs[i] != (char) SPACE_KEY)
+ cout << "Tagged " << state << " char code: '" << humanInputs[i] << "' at char position: " << i << endl;
}
- destroyWindow("Character selector");
+ }
+ destroyWindow("Character selector");
- return humanInputs;
+ return humanInputs;
}
diff --git a/src/misc_utilities/prepcharsfortraining.cpp b/src/misc_utilities/prepcharsfortraining.cpp
index 6f51ce1..b49ac33 100644
--- a/src/misc_utilities/prepcharsfortraining.cpp
+++ b/src/misc_utilities/prepcharsfortraining.cpp
@@ -17,49 +17,46 @@
* along with this program. If not, see .
*/
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
- #include
- #include
+#include
+#include
#include
#include
#include "support/filesystem.h"
- using namespace std;
- using namespace cv;
-
-
+using namespace std;
+using namespace cv;
// Takes a directory full of single char images, and plops them on a big tif files
// Also creates a box file so Tesseract can recognize it
int main( int argc, const char** argv )
{
- string inDir;
-
+ string inDir;
//Check if user specify image to process
if(argc == 2)
{
- inDir = argv[1];
+ inDir = argv[1];
- }else{
- printf("Use:\n\t%s input dir \n",argv[0]);
- return 0;
}
-
+ else
+ {
+ printf("Use:\n\t%s input dir \n",argv[0]);
+ return 0;
+ }
if (DirectoryExists(inDir.c_str()) == false)
{
- printf("Output dir does not exist\n");
- return 0;
+ printf("Output dir does not exist\n");
+ return 0;
}
cout << "Usage: " << endl;
cout << "\tinputdir -- input dir for benchmark data" << endl;
-
if (DirectoryExists(inDir.c_str()))
{
const int X_OFFSET = 10;
@@ -74,97 +71,92 @@ int main( int argc, const char** argv )
const int TILE_HEIGHT = 70;
const int CHAR_VERT_OFFSET = 48;
- vector files = getFilesInDir(inDir.c_str());
+ vector files = getFilesInDir(inDir.c_str());
- sort( files.begin(), files.end(), stringCompare );
+ sort( files.begin(), files.end(), stringCompare );
+ int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH);
+ int lines = files.size() / (tiles_per_row);
+ int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ;
+ cout << tiles_per_row << " : " << vertical_resolution << endl;
- int tiles_per_row = ((float) (HORIZONTAL_RESOLUTION - (PAGE_MARGIN_X * 2))) / ((float) TILE_WIDTH);
- int lines = files.size() / (tiles_per_row);
- int vertical_resolution = (lines * TILE_HEIGHT) + (PAGE_MARGIN_Y * 2) ;
- cout << tiles_per_row << " : " << vertical_resolution << endl;
+ Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U);
+ bitwise_not(bigTif, bigTif);
- Mat bigTif = Mat::zeros(Size(HORIZONTAL_RESOLUTION, vertical_resolution), CV_8U);
- bitwise_not(bigTif, bigTif);
+ stringstream boxFileOut;
- stringstream boxFileOut;
+ for (int i = 0; i< files.size(); i++)
+ {
+ int col = i % tiles_per_row;
+ int line = i / tiles_per_row;
- for (int i = 0; i< files.size(); i++)
+ int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X;
+ int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y;
+
+ if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
{
- int col = i % tiles_per_row;
- int line = i / tiles_per_row;
+ string fullpath = inDir + "/" + files[i];
- int xPos = (col * TILE_WIDTH) + PAGE_MARGIN_X;
- int yPos = (line * TILE_HEIGHT) + PAGE_MARGIN_Y;
+ cout << "Processing file: " << (i + 1) << " of " << files.size() << endl;
- if (hasEnding(files[i], ".png") || hasEnding(files[i], ".jpg"))
- {
- string fullpath = inDir + "/" + files[i];
+ char charcode = files[i][0];
- cout << "Processing file: " << (i + 1) << " of " << files.size() << endl;
+ Mat characterImg = imread(fullpath);
+ Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type());
+ bitwise_not(charImgCopy, charImgCopy);
- char charcode = files[i][0];
+ characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows)));
+ cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY);
+ bitwise_not(charImgCopy, charImgCopy);
- Mat characterImg = imread(fullpath);
- Mat charImgCopy = Mat::zeros(Size(150, 150), characterImg.type());
- bitwise_not(charImgCopy, charImgCopy);
+ vector > contours;
- characterImg.copyTo(charImgCopy(Rect(X_OFFSET, Y_OFFSET, characterImg.cols, characterImg.rows)));
- cvtColor(charImgCopy, charImgCopy, CV_BGR2GRAY);
- bitwise_not(charImgCopy, charImgCopy);
+ //imshow("copy", charImgCopy);
+ findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
- vector > contours;
+ Rect tallestRect(0, 0, 0, 0);
+ for (int c = 0; c < contours.size(); c++)
+ {
+ Rect tmpRect = boundingRect(contours[c]);
+ if (tmpRect.height > tallestRect.height)
+ tallestRect = tmpRect;
+ }
- //imshow("copy", charImgCopy);
- findContours(charImgCopy, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
+ //cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl;
- Rect tallestRect(0, 0, 0, 0);
- for (int c = 0; c < contours.size(); c++)
- {
- Rect tmpRect = boundingRect(contours[c]);
- if (tmpRect.height > tallestRect.height)
- tallestRect = tmpRect;
- }
+ Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height);
- //cout << tallestRect.x << ":" << tallestRect.y << " -- " << tallestRect.width << ":" << tallestRect.height << endl;
+ //cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl;
+ Mat cropped(characterImg, cropRect);
+ cvtColor(cropped, cropped, CV_BGR2GRAY);
- Rect cropRect(0, tallestRect.y - Y_OFFSET, tallestRect.width, tallestRect.height);
+ Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height);
+ //cout << "1" << endl;
- //cout << "Cropped: " << cropRect.x << ":" << cropRect.y << " -- " << cropRect.width << ":" << cropRect.height << endl;
- Mat cropped(characterImg, cropRect);
- cvtColor(cropped, cropped, CV_BGR2GRAY);
+ cropped.copyTo(bigTif(destinationRect));
- Rect destinationRect(xPos + (CHAR_HORIZ_OFFSET - tallestRect.width), yPos + (CHAR_VERT_OFFSET - tallestRect.height), tallestRect.width, tallestRect.height);
+ int x1= destinationRect.x - 2;
+ int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2;
+ int x2 = (destinationRect.x + destinationRect.width) + 2;
+ int y2 = (vertical_resolution - destinationRect.y) + 2;
+ //0 70 5602 85 5636 0
+ boxFileOut << charcode << " " << x1 << " " << y1 << " ";
+ boxFileOut << x2 << " " << y2 ;
+ boxFileOut << " 0" << endl;
- //cout << "1" << endl;
+ //rectangle(characterImg, tallestRect, Scalar(0, 255, 0));
+ //imshow("characterImg", cropped);
- cropped.copyTo(bigTif(destinationRect));
-
-
- int x1= destinationRect.x - 2;
- int y1 = (vertical_resolution - destinationRect.y - destinationRect.height) - 2;
- int x2 = (destinationRect.x + destinationRect.width) + 2;
- int y2 = (vertical_resolution - destinationRect.y) + 2;
- //0 70 5602 85 5636 0
- boxFileOut << charcode << " " << x1 << " " << y1 << " ";
- boxFileOut << x2 << " " << y2 ;
- boxFileOut << " 0" << endl;
-
- //rectangle(characterImg, tallestRect, Scalar(0, 255, 0));
- //imshow("characterImg", cropped);
-
- waitKey(2);
-
-
- }
+ waitKey(2);
}
+ }
- imwrite("combined.tif", bigTif);
- ofstream boxFile("combined.box", std::ios::out);
- boxFile << boxFileOut.str();
+ imwrite("combined.tif", bigTif);
+ ofstream boxFile("combined.box", std::ios::out);
+ boxFile << boxFileOut.str();
}
diff --git a/src/misc_utilities/sortstate.cpp b/src/misc_utilities/sortstate.cpp
index d43fbe9..36449dd 100644
--- a/src/misc_utilities/sortstate.cpp
+++ b/src/misc_utilities/sortstate.cpp
@@ -17,11 +17,11 @@
* along with this program. If not, see .
*/
- #include "opencv2/highgui/highgui.hpp"
- #include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
- #include
- #include
+#include
+#include
#include
#include "regiondetector.h"
@@ -30,34 +30,34 @@
#include "utility.h"
#include "support/filesystem.h"
- using namespace std;
- using namespace cv;
+using namespace std;
+using namespace cv;
// Given a directory full of pre-cropped images, identify the state that each image belongs to.
// This is used to sort our own positive image database as a first step before grabbing characters to use to train the OCR.
- bool detectPlate( StateIdentifier* identifier, Mat frame);
+bool detectPlate( StateIdentifier* identifier, Mat frame);
int main( int argc, const char** argv )
{
- string inDir;
- string outDir;
- Mat frame;
-
+ string inDir;
+ string outDir;
+ Mat frame;
//Check if user specify image to process
if(argc == 3 )
{
- inDir = argv[1];
- outDir = argv[2];
- outDir = outDir + "/";
+ inDir = argv[1];
+ outDir = argv[2];
+ outDir = outDir + "/";
-
- }else{
- printf("Use:\n\t%s directory \n",argv[0]);
- printf("Ex: \n\t%s ./pics/ \n",argv[0]);
- return 0;
+ }
+ else
+ {
+ printf("Use:\n\t%s directory \n",argv[0]);
+ printf("Ex: \n\t%s ./pics/ \n",argv[0]);
+ return 0;
}
Config config("us");
@@ -65,53 +65,52 @@ int main( int argc, const char** argv )
if (DirectoryExists(outDir.c_str()) == false)
{
- printf("Output dir does not exist\n");
- return 0;
+ printf("Output dir does not exist\n");
+ return 0;
}
if (DirectoryExists(inDir.c_str()))
{
- vector files = getFilesInDir(inDir.c_str());
+ vector files = getFilesInDir(inDir.c_str());
- for (int i = 0; i< files.size(); i++)
+ for (int i = 0; i< files.size(); i++)
+ {
+ if (hasEnding(files[i], ".png"))
{
- if (hasEnding(files[i], ".png"))
- {
- string fullpath = inDir + "/" + files[i];
- cout << fullpath << endl;
- frame = imread( fullpath.c_str() );
+ string fullpath = inDir + "/" + files[i];
+ cout << fullpath << endl;
+ frame = imread( fullpath.c_str() );
- char code[4];
- int confidence = identifier.recognize(frame, code);
+ char code[4];
+ int confidence = identifier.recognize(frame, code);
- if (confidence <= 20)
- {
- code[0] = 'z';
- code[1] = 'z';
- confidence = 100;
- }
+ if (confidence <= 20)
+ {
+ code[0] = 'z';
+ code[1] = 'z';
+ confidence = 100;
+ }
- //imshow("Plate", frame);
- if (confidence > 20)
- {
- cout << confidence << " : " << code;
+ //imshow("Plate", frame);
+ if (confidence > 20)
+ {
+ cout << confidence << " : " << code;
- ostringstream convert; // stream used for the conversion
- convert << i; // insert the textual representation of 'Number' in the characters in the stream
-
-
- string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png";
- system( copyCommand.c_str() );
- waitKey(50);
- //while ((char) waitKey(50) != 'c') { }
- }
- else
- waitKey(50);
- }
+ ostringstream convert; // stream used for the conversion
+ convert << i; // insert the textual representation of 'Number' in the characters in the stream
+ string copyCommand = "cp \"" + fullpath + "\" " + outDir + code + convert.str() + ".png";
+ system( copyCommand.c_str() );
+ waitKey(50);
+ //while ((char) waitKey(50) != 'c') { }
+ }
+ else
+ waitKey(50);
}
+
+ }
}
}
- bool detectPlate( StateIdentifier* identifier, Mat frame);
+bool detectPlate( StateIdentifier* identifier, Mat frame);
diff --git a/src/openalpr/TRexpp.h b/src/openalpr/TRexpp.h
index 430925b..29bdb3f 100644
--- a/src/openalpr/TRexpp.h
+++ b/src/openalpr/TRexpp.h
@@ -31,45 +31,67 @@ extern "C" {
#include "trex.h"
}
-struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;};
+struct TRexParseException
+{
+ TRexParseException(const TRexChar *c):desc(c) {} const TRexChar *desc;
+};
-class TRexpp {
-public:
- TRexpp() { _exp = (TRex *)0; }
- ~TRexpp() { CleanUp(); }
- // compiles a regular expression
- void Compile(const TRexChar *pattern) {
- const TRexChar *error;
- CleanUp();
- if(!(_exp = trex_compile(pattern,&error)))
- throw TRexParseException(error);
- }
- // return true if the given text match the expression
- bool Match(const TRexChar* text) {
- return _exp?(trex_match(_exp,text) != 0):false;
- }
- // Searches for the first match of the expression in a zero terminated string
- bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) {
- return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false;
- }
- // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
- bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) {
- return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false;
- }
- bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
- {
- TRexMatch match;
- TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False;
- if(res) {
- *out_begin = match.begin;
- *out_len = match.len;
- return true;
- }
- return false;
- }
- int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; }
-private:
- void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; }
- TRex *_exp;
+class TRexpp
+{
+ public:
+ TRexpp()
+ {
+ _exp = (TRex *)0;
+ }
+ ~TRexpp()
+ {
+ CleanUp();
+ }
+ // compiles a regular expression
+ void Compile(const TRexChar *pattern)
+ {
+ const TRexChar *error;
+ CleanUp();
+ if(!(_exp = trex_compile(pattern,&error)))
+ throw TRexParseException(error);
+ }
+ // return true if the given text match the expression
+ bool Match(const TRexChar* text)
+ {
+ return _exp?(trex_match(_exp,text) != 0):false;
+ }
+ // Searches for the first match of the expression in a zero terminated string
+ bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
+ {
+ return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false;
+ }
+ // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
+ bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
+ {
+ return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false;
+ }
+ bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
+ {
+ TRexMatch match;
+ TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False;
+ if(res)
+ {
+ *out_begin = match.begin;
+ *out_len = match.len;
+ return true;
+ }
+ return false;
+ }
+ int GetSubExpCount()
+ {
+ return _exp?trex_getsubexpcount(_exp):0;
+ }
+ private:
+ void CleanUp()
+ {
+ if(_exp) trex_free(_exp);
+ _exp = (TRex *)0;
+ }
+ TRex *_exp;
};
#endif //_TREXPP_H_
diff --git a/src/openalpr/alpr.cpp b/src/openalpr/alpr.cpp
index c5e2c9e..be03f49 100644
--- a/src/openalpr/alpr.cpp
+++ b/src/openalpr/alpr.cpp
@@ -20,9 +20,6 @@
#include "alpr.h"
#include "alpr_impl.h"
-
-
-
// ALPR code
Alpr::Alpr(const std::string country, const std::string runtimeDir)
@@ -40,22 +37,19 @@ std::vector Alpr::recognize(std::string filepath)
}
-
std::vector Alpr::recognize(std::vector imageBuffer)
{
- // Not sure if this actually works
+ // Not sure if this actually works
cv::Mat img = cv::imdecode(Mat(imageBuffer), 1);
return impl->recognize(img);
}
-
string Alpr::toJson(const vector< AlprResult > results)
{
return impl->toJson(results);
}
-
void Alpr::setDetectRegion(bool detectRegion)
{
impl->setDetectRegion(detectRegion);
@@ -74,11 +68,8 @@ bool Alpr::isLoaded()
return true;
}
-
-
// Results code
-
AlprResult::AlprResult()
{
diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h
index 69db91f..2e69292 100644
--- a/src/openalpr/alpr.h
+++ b/src/openalpr/alpr.h
@@ -37,8 +37,8 @@ struct AlprPlate
struct AlprCoordinate
{
- int x;
- int y;
+ int x;
+ int y;
};
class AlprResult
diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp
index 1bab02a..22178f0 100644
--- a/src/openalpr/alpr_impl.cpp
+++ b/src/openalpr/alpr_impl.cpp
@@ -19,7 +19,6 @@
#include "alpr_impl.h"
-
AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
{
config = new Config(country, runtimeDir);
@@ -39,7 +38,7 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir)
for (int i = 0; i < platinfo.size(); i++)
{
- std::cout << platinfo[i]->platformName << std::endl;
+ std::cout << platinfo[i]->platformName << std::endl;
}
cv::ocl::DevicesInfo devices;
@@ -68,7 +67,6 @@ AlprImpl::~AlprImpl()
delete ocr;
}
-
std::vector AlprImpl::recognize(cv::Mat img)
{
timespec startTime;
@@ -76,100 +74,95 @@ std::vector AlprImpl::recognize(cv::Mat img)
vector response;
-
vector plateRegions = plateDetector->detect(img);
-
// Recognize.
for (int i = 0; i < plateRegions.size(); i++)
{
- timespec platestarttime;
- getTime(&platestarttime);
+ timespec platestarttime;
+ getTime(&platestarttime);
- LicensePlateCandidate lp(img, plateRegions[i], config);
+ LicensePlateCandidate lp(img, plateRegions[i], config);
- lp.recognize();
+ lp.recognize();
+ if (lp.confidence > 10)
+ {
+ AlprResult plateResult;
+ plateResult.region = defaultRegion;
+ plateResult.regionConfidence = 0;
- if (lp.confidence > 10)
+ for (int pointidx = 0; pointidx < 4; pointidx++)
{
- AlprResult plateResult;
- plateResult.region = defaultRegion;
- plateResult.regionConfidence = 0;
-
- for (int pointidx = 0; pointidx < 4; pointidx++)
- {
- plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x;
- plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y;
- }
-
- if (detectRegion)
- {
- char statecode[4];
- plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode);
- if (plateResult.regionConfidence > 0)
- {
- plateResult.region = statecode;
- }
- }
-
-
- ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
-
- ocr->postProcessor->analyze(plateResult.region, topN);
-
- //plateResult.characters = ocr->postProcessor->bestChars;
- const vector ppResults = ocr->postProcessor->getResults();
-
- int bestPlateIndex = 0;
-
- for (int pp = 0; pp < ppResults.size(); pp++)
- {
- if (pp >= topN)
- break;
-
- // Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match
- if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate)
- bestPlateIndex = pp;
-
- if (ppResults[pp].letters.size() >= config->postProcessMinCharacters &&
- ppResults[pp].letters.size() <= config->postProcessMaxCharacters)
- {
- AlprPlate aplate;
- aplate.characters = ppResults[pp].letters;
- aplate.overall_confidence = ppResults[pp].totalscore;
- aplate.matches_template = ppResults[pp].matchesTemplate;
- plateResult.topNPlates.push_back(aplate);
- }
- }
- plateResult.result_count = plateResult.topNPlates.size();
-
- if (plateResult.topNPlates.size() > 0)
- plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex];
-
- timespec plateEndTime;
- getTime(&plateEndTime);
- plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime);
-
- if (plateResult.result_count > 0)
- response.push_back(plateResult);
-
- if (config->debugGeneral)
- {
- rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2);
- for (int z = 0; z < 4; z++)
- line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2);
- }
-
-
+ plateResult.plate_points[pointidx].x = (int) lp.plateCorners[pointidx].x;
+ plateResult.plate_points[pointidx].y = (int) lp.plateCorners[pointidx].y;
}
- else
+
+ if (detectRegion)
{
- if (config->debugGeneral)
- rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2);
+ char statecode[4];
+ plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegions[i], statecode);
+ if (plateResult.regionConfidence > 0)
+ {
+ plateResult.region = statecode;
+ }
}
+ ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters);
+
+ ocr->postProcessor->analyze(plateResult.region, topN);
+
+ //plateResult.characters = ocr->postProcessor->bestChars;
+ const vector ppResults = ocr->postProcessor->getResults();
+
+ int bestPlateIndex = 0;
+
+ for (int pp = 0; pp < ppResults.size(); pp++)
+ {
+ if (pp >= topN)
+ break;
+
+ // Set our "best plate" match to either the first entry, or the first entry with a postprocessor template match
+ if (bestPlateIndex == 0 && ppResults[pp].matchesTemplate)
+ bestPlateIndex = pp;
+
+ if (ppResults[pp].letters.size() >= config->postProcessMinCharacters &&
+ ppResults[pp].letters.size() <= config->postProcessMaxCharacters)
+ {
+ AlprPlate aplate;
+ aplate.characters = ppResults[pp].letters;
+ aplate.overall_confidence = ppResults[pp].totalscore;
+ aplate.matches_template = ppResults[pp].matchesTemplate;
+ plateResult.topNPlates.push_back(aplate);
+ }
+ }
+ plateResult.result_count = plateResult.topNPlates.size();
+
+ if (plateResult.topNPlates.size() > 0)
+ plateResult.bestPlate = plateResult.topNPlates[bestPlateIndex];
+
+ timespec plateEndTime;
+ getTime(&plateEndTime);
+ plateResult.processing_time_ms = diffclock(platestarttime, plateEndTime);
+
+ if (plateResult.result_count > 0)
+ response.push_back(plateResult);
+
+ if (config->debugGeneral)
+ {
+ rectangle(img, plateRegions[i], Scalar(0, 255, 0), 2);
+ for (int z = 0; z < 4; z++)
+ line(img, lp.plateCorners[z], lp.plateCorners[(z + 1) % 4], Scalar(255,0,255), 2);
+ }
+
+ }
+ else
+ {
+ if (config->debugGeneral)
+ rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2);
+ }
+
}
if (config->debugTiming)
@@ -210,8 +203,6 @@ string AlprImpl::toJson(const vector< AlprResult > results)
return response;
}
-
-
cJSON* AlprImpl::createJsonObj(const AlprResult* result)
{
cJSON *root, *coords, *candidates;
@@ -228,7 +219,7 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
cJSON_AddNumberToObject(root,"processing_time_ms", result->processing_time_ms);
cJSON_AddItemToObject(root, "coordinates", coords=cJSON_CreateArray());
- for (int i=0;i<4;i++)
+ for (int i=0; i<4; i++)
{
cJSON *coords_object;
coords_object = cJSON_CreateObject();
@@ -238,7 +229,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
cJSON_AddItemToArray(coords, coords_object);
}
-
cJSON_AddItemToObject(root, "candidates", candidates=cJSON_CreateArray());
for (int i = 0; i < result->topNPlates.size(); i++)
{
@@ -254,7 +244,6 @@ cJSON* AlprImpl::createJsonObj(const AlprResult* result)
return root;
}
-
void AlprImpl::setDetectRegion(bool detectRegion)
{
this->detectRegion = detectRegion;
diff --git a/src/openalpr/binarize_wolf.cpp b/src/openalpr/binarize_wolf.cpp
index a80fe7e..a8bf5bd 100644
--- a/src/openalpr/binarize_wolf.cpp
+++ b/src/openalpr/binarize_wolf.cpp
@@ -33,190 +33,192 @@
#include "binarize_wolf.h"
-
// *************************************************************
// glide a window across the image and
// create two maps: mean and standard deviation.
// *************************************************************
+float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy)
+{
-float calcLocalStats (Mat &im, Mat &map_m, Mat &map_s, int winx, int winy) {
+ float m,s,max_s;
+ long sum, sum_sq;
+ uchar foo;
+ int wxh = winx/2;
+ int wyh = winy/2;
+ int x_firstth= wxh;
+ int y_lastth = im.rows-wyh-1;
+ int y_firstth= wyh;
+ float winarea = winx*winy;
- float m,s,max_s;
- long sum, sum_sq;
- uchar foo;
- int wxh = winx/2;
- int wyh = winy/2;
- int x_firstth= wxh;
- int y_lastth = im.rows-wyh-1;
- int y_firstth= wyh;
- float winarea = winx*winy;
+ max_s = 0;
+ for (int j = y_firstth ; j<=y_lastth; j++)
+ {
+ // Calculate the initial window at the beginning of the line
+ sum = sum_sq = 0;
+ for (int wy=0 ; wy max_s)
+ max_s = s;
+ map_m.fset(x_firstth, j, m);
+ map_s.fset(x_firstth, j, s);
+ // Shift the window, add and remove new/old values to the histogram
+ for (int i=1 ; i <= im.cols-winx; i++)
+ {
- max_s = 0;
- for (int j = y_firstth ; j<=y_lastth; j++)
- {
- // Calculate the initial window at the beginning of the line
- sum = sum_sq = 0;
- for (int wy=0 ; wy max_s)
- max_s = s;
- map_m.fset(x_firstth, j, m);
- map_s.fset(x_firstth, j, s);
+ // Remove the left old column and add the right new column
+ for (int wy=0; wy max_s)
+ max_s = s;
+ map_m.fset(i+wxh, j, m);
+ map_s.fset(i+wxh, j, s);
+ }
+ }
- // Shift the window, add and remove new/old values to the histogram
- for (int i=1 ; i <= im.cols-winx; i++) {
-
- // Remove the left old column and add the right new column
- for (int wy=0; wy max_s)
- max_s = s;
- map_m.fset(i+wxh, j, m);
- map_s.fset(i+wxh, j, s);
- }
- }
-
- return max_s;
+ return max_s;
}
-
/**********************************************************
* The binarization routine
**********************************************************/
-
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
- int winx, int winy, float k) {
+ int winx, int winy, float k)
+{
- float dR = BINARIZEWOLF_DEFAULTDR;
+ float dR = BINARIZEWOLF_DEFAULTDR;
- float m, s, max_s;
- float th=0;
- double min_I, max_I;
- int wxh = winx/2;
- int wyh = winy/2;
- int x_firstth= wxh;
- int x_lastth = im.cols-wxh-1;
- int y_lastth = im.rows-wyh-1;
- int y_firstth= wyh;
- int mx, my;
+ float m, s, max_s;
+ float th=0;
+ double min_I, max_I;
+ int wxh = winx/2;
+ int wyh = winy/2;
+ int x_firstth= wxh;
+ int x_lastth = im.cols-wxh-1;
+ int y_lastth = im.rows-wyh-1;
+ int y_firstth= wyh;
+ int mx, my;
- // Create local statistics and store them in a float matrices
- Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F);
- Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F);
- max_s = calcLocalStats (im, map_m, map_s, winx, winy);
+ // Create local statistics and store them in a float matrices
+ Mat map_m = Mat::zeros (im.rows, im.cols, CV_32F);
+ Mat map_s = Mat::zeros (im.rows, im.cols, CV_32F);
+ max_s = calcLocalStats (im, map_m, map_s, winx, winy);
- minMaxLoc(im, &min_I, &max_I);
+ minMaxLoc(im, &min_I, &max_I);
- Mat thsurf (im.rows, im.cols, CV_32F);
+ Mat thsurf (im.rows, im.cols, CV_32F);
- // Create the threshold surface, including border processing
- // ----------------------------------------------------
+ // Create the threshold surface, including border processing
+ // ----------------------------------------------------
- for (int j = y_firstth ; j<=y_lastth; j++) {
+ for (int j = y_firstth ; j<=y_lastth; j++)
+ {
- // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
- for (int i=0 ; i <= im.cols-winx; i++) {
+ // NORMAL, NON-BORDER AREA IN THE MIDDLE OF THE WINDOW:
+ for (int i=0 ; i <= im.cols-winx; i++)
+ {
- m = map_m.fget(i+wxh, j);
- s = map_s.fget(i+wxh, j);
+ m = map_m.fget(i+wxh, j);
+ s = map_s.fget(i+wxh, j);
- // Calculate the threshold
- switch (version) {
+ // Calculate the threshold
+ switch (version)
+ {
- case NIBLACK:
- th = m + k*s;
- break;
+ case NIBLACK:
+ th = m + k*s;
+ break;
- case SAUVOLA:
- th = m * (1 + k*(s/dR-1));
- break;
+ case SAUVOLA:
+ th = m * (1 + k*(s/dR-1));
+ break;
- case WOLFJOLION:
- th = m + k * (s/max_s-1) * (m-min_I);
- break;
+ case WOLFJOLION:
+ th = m + k * (s/max_s-1) * (m-min_I);
+ break;
- default:
- cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
- exit (1);
- }
+ default:
+ cerr << "Unknown threshold type in ImageThresholder::surfaceNiblackImproved()\n";
+ exit (1);
+ }
- thsurf.fset(i+wxh,j,th);
+ thsurf.fset(i+wxh,j,th);
- if (i==0) {
- // LEFT BORDER
- for (int i=0; i<=x_firstth; ++i)
- thsurf.fset(i,j,th);
+ if (i==0)
+ {
+ // LEFT BORDER
+ for (int i=0; i<=x_firstth; ++i)
+ thsurf.fset(i,j,th);
- // LEFT-UPPER CORNER
- if (j==y_firstth)
- for (int u=0; u= thsurf.fget(x,y))
- {
- output.uset(x,y,255);
- }
- else
- {
- output.uset(x,y,0);
- }
+ for (int y=0; y= thsurf.fget(x,y))
+ {
+ output.uset(x,y,255);
+ }
+ else
+ {
+ output.uset(x,y,0);
+ }
}
}
diff --git a/src/openalpr/binarize_wolf.h b/src/openalpr/binarize_wolf.h
index fae86e0..6e85d70 100644
--- a/src/openalpr/binarize_wolf.h
+++ b/src/openalpr/binarize_wolf.h
@@ -32,9 +32,9 @@ using namespace cv;
enum NiblackVersion
{
- NIBLACK=0,
- SAUVOLA,
- WOLFJOLION,
+ NIBLACK=0,
+ SAUVOLA,
+ WOLFJOLION,
};
#define BINARIZEWOLF_VERSION "2.3 (February 26th, 2013)"
@@ -49,7 +49,7 @@ enum NiblackVersion
void NiblackSauvolaWolfJolion (Mat im, Mat output, NiblackVersion version,
- int winx, int winy, float k);
+ int winx, int winy, float k);
diff --git a/src/openalpr/characteranalysis.cpp b/src/openalpr/characteranalysis.cpp
index c15a112..b9b3c39 100644
--- a/src/openalpr/characteranalysis.cpp
+++ b/src/openalpr/characteranalysis.cpp
@@ -29,13 +29,12 @@ CharacterAnalysis::CharacterAnalysis(Mat img, Config* config)
if (this->config->debugCharAnalysis)
cout << "Starting CharacterAnalysis identification" << endl;
-
if (img.type() != CV_8U)
cvtColor( img, this->img_gray, CV_BGR2GRAY );
else
{
- img_gray = Mat(img.size(), img.type());
- img.copyTo(img_gray);
+ img_gray = Mat(img.size(), img.type());
+ img.copyTo(img_gray);
}
}
@@ -44,20 +43,16 @@ CharacterAnalysis::~CharacterAnalysis()
{
for (int i = 0; i < thresholds.size(); i++)
{
- thresholds[i].release();
+ thresholds[i].release();
}
thresholds.clear();
}
-
-
void CharacterAnalysis::analyze()
{
-
thresholds = produceThresholds(img_gray, config);
-
/*
// Morph Close the gray image to make it easier to detect blobs
int morph_elem = 1;
@@ -73,11 +68,9 @@ void CharacterAnalysis::analyze()
}
*/
-
timespec startTime;
getTime(&startTime);
-
for (int i = 0; i < thresholds.size(); i++)
{
vector > contours;
@@ -86,18 +79,15 @@ void CharacterAnalysis::analyze()
Mat tempThreshold(thresholds[i].size(), CV_8U);
thresholds[i].copyTo(tempThreshold);
findContours(tempThreshold,
- contours, // a vector of contours
- hierarchy,
- CV_RETR_TREE, // retrieve all contours
- CV_CHAIN_APPROX_SIMPLE ); // all pixels of each contours
+ contours, // a vector of contours
+ 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)
{
timespec endTime;
@@ -106,7 +96,6 @@ void CharacterAnalysis::analyze()
}
//Mat img_equalized = equalizeBrightness(img_gray);
-
getTime(&startTime);
for (int i = 0; i < thresholds.size(); i++)
@@ -125,8 +114,6 @@ void CharacterAnalysis::analyze()
cout << " -- Character Analysis Filter Time: " << diffclock(startTime, endTime) << "ms." << endl;
}
-
-
this->plateMask = findOuterBoxMask();
if (hasPlateMask)
@@ -138,7 +125,6 @@ void CharacterAnalysis::analyze()
}
}
-
int bestFitScore = -1;
int bestFitIndex = -1;
for (int i = 0; i < thresholds.size(); i++)
@@ -149,7 +135,6 @@ void CharacterAnalysis::analyze()
int segmentCount = getGoodIndicesCount(charSegments[i]);
-
if (segmentCount > bestFitScore)
{
bestFitScore = segmentCount;
@@ -165,11 +150,9 @@ void CharacterAnalysis::analyze()
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)
@@ -182,29 +165,25 @@ void CharacterAnalysis::analyze()
vector > allowedContours;
for (int i = 0; i < bestContours.size(); i++)
{
- if (bestCharSegments[i])
- allowedContours.push_back(bestContours[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
+ -1, // draw all contours
+ cv::Scalar(255,0,0), // in blue
+ 1); // with a thickness of 1
drawContours(img_contours, allowedContours,
- -1, // draw all contours
- cv::Scalar(0,255,0), // in green
- 1); // with a thickness of 1
-
+ -1, // draw all contours
+ cv::Scalar(0,255,0), // in green
+ 1); // with a thickness of 1
displayImage(config, "Matching Contours", img_contours);
}
-
//charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP));
-
-
this->linePolygon = getBestVotedLines(img_gray, bestContours, bestCharSegments);
if (this->linePolygon.size() > 0)
@@ -223,14 +202,11 @@ void CharacterAnalysis::analyze()
this->charBoxLeft = LineSegment(this->charArea[3].x, this->charArea[3].y, this->charArea[0].x, this->charArea[0].y);
this->charBoxRight = LineSegment(this->charArea[2].x, this->charArea[2].y, this->charArea[1].x, this->charArea[1].y);
-
}
}
this->thresholdsInverted = isPlateInverted();
-
-
}
int CharacterAnalysis::getGoodIndicesCount(vector goodIndices)
@@ -245,8 +221,6 @@ int CharacterAnalysis::getGoodIndicesCount(vector goodIndices)
return count;
}
-
-
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.
@@ -256,7 +230,6 @@ Mat CharacterAnalysis::findOuterBoxMask()
int bestCharCount = 0;
double lowestArea = 99999999999999;
-
if (this->config->debugCharAnalysis)
cout << "CharacterAnalysis::findOuterBoxMask" << endl;
@@ -272,8 +245,8 @@ Mat CharacterAnalysis::findOuterBoxMask()
if (charSegments[imgIndex][i]) charsRecognized++;
if (charSegments[imgIndex][i] && allHierarchy[imgIndex][i][3] != -1)
{
- parentId = allHierarchy[imgIndex][i][3];
- hasParent = true;
+ parentId = allHierarchy[imgIndex][i][3];
+ hasParent = true;
}
}
@@ -284,28 +257,24 @@ Mat CharacterAnalysis::findOuterBoxMask()
{
double boxArea = contourArea(allContours[imgIndex][parentId]);
if (boxArea < min_parent_area)
- continue;
+ continue;
if ((charsRecognized > bestCharCount) ||
- (charsRecognized == bestCharCount && boxArea < lowestArea))
- //(boxArea < lowestArea)
+ (charsRecognized == bestCharCount && boxArea < lowestArea))
+ //(boxArea < lowestArea)
{
- bestCharCount = charsRecognized;
- winningIndex = imgIndex;
- winningParentId = parentId;
- lowestArea = boxArea;
+ bestCharCount = charsRecognized;
+ winningIndex = imgIndex;
+ winningParentId = parentId;
+ lowestArea = boxArea;
}
}
-
}
if (this->config->debugCharAnalysis)
cout << "Winning image index is: " << winningIndex << endl;
-
-
-
if (winningIndex != -1 && bestCharCount >= 3)
{
int longestChildIndex = -1;
@@ -313,36 +282,31 @@ Mat CharacterAnalysis::findOuterBoxMask()
// Find the child with the longest permiter/arc length ( just for kicks)
for (int i = 0; i < allContours[winningIndex].size(); i++)
{
- for (int j = 0; j < allContours[winningIndex].size(); j++)
- {
- if (allHierarchy[winningIndex][j][3] == winningParentId)
- {
- double arclength = arcLength(allContours[winningIndex][j], false);
- if (arclength > longestChildLength)
- {
- longestChildIndex = j;
- longestChildLength = arclength;
- }
- }
- }
+ for (int j = 0; j < allContours[winningIndex].size(); j++)
+ {
+ if (allHierarchy[winningIndex][j][3] == winningParentId)
+ {
+ double arclength = arcLength(allContours[winningIndex][j], false);
+ if (arclength > longestChildLength)
+ {
+ longestChildIndex = j;
+ longestChildLength = arclength;
+ }
+ }
+ }
}
-
-
-
-
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,
- allHierarchy[winningIndex],
- 0
- );
-
+ winningParentId, // draw this contour
+ 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;
@@ -356,7 +320,6 @@ Mat CharacterAnalysis::findOuterBoxMask()
//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.
// We'll want to do the contour again and find the larges one so that we remove the clipped portion.
@@ -368,33 +331,31 @@ Mat CharacterAnalysis::findOuterBoxMask()
for (int c = 0; c < contoursSecondRound.size(); c++)
{
double area = contourArea(contoursSecondRound[c]);
- if (area > largestArea)
- {
- biggestContourIndex = c;
- largestArea = area;
- }
+ if (area > largestArea)
+ {
+ biggestContourIndex = c;
+ largestArea = area;
+ }
}
if (biggestContourIndex != -1)
{
- mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U);
+ mask = Mat::zeros(thresholds[winningIndex].size(), CV_8U);
- vector smoothedMaskPoints;
- approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true);
+ vector smoothedMaskPoints;
+ approxPolyDP(contoursSecondRound[biggestContourIndex], smoothedMaskPoints, 2, true);
- vector > tempvec;
- tempvec.push_back(smoothedMaskPoints);
- //fillPoly(mask, smoothedMaskPoints.data(), smoothedMaskPoints, Scalar(255,255,255));
+ 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,
- allHierarchy[winningIndex],
- 0
- );
-
-
+ 0, // draw this contour
+ cv::Scalar(255,255,255), // in
+ CV_FILLED,
+ 8,
+ allHierarchy[winningIndex],
+ 0
+ );
}
@@ -422,48 +383,41 @@ Mat CharacterAnalysis::findOuterBoxMask()
bitwise_not(fullMask, fullMask);
return fullMask;
-
-
}
-
Mat CharacterAnalysis::getCharacterMask()
{
- Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U);
+ Mat charMask = Mat::zeros(bestThreshold.size(), CV_8U);
- for (int i = 0; i < bestContours.size(); i++)
- {
- if (bestCharSegments[i] == false)
- continue;
+ 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,
+ bestHierarchy,
+ 1
+ );
- drawContours(charMask, bestContours,
- i, // draw this contour
- 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,
+ 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,
- bestHierarchy,
- 1
- );
- }
-
-
- return charMask;
+ return charMask;
}
-
-
// 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)
{
@@ -481,161 +435,150 @@ vector CharacterAnalysis::getBestVotedLines(Mat img, vector
charRegions.push_back(boundingRect(contours[i]));
}
-
- // Find the best fit line segment that is parallel with the most char segments
- if (charRegions.size() <= 1)
+ // Find the best fit line segment that is parallel with the most char segments
+ if (charRegions.size() <= 1)
+ {
+ // Maybe do something about this later, for now let's just ignore
+ }
+ else
+ {
+ vector topLines;
+ vector bottomLines;
+ // Iterate through each possible char and find all possible lines for the top and bottom of each char segment
+ for (int i = 0; i < charRegions.size() - 1; i++)
{
- // Maybe do something about this later, for now let's just ignore
- }
- else
- {
- vector topLines;
- vector bottomLines;
- // Iterate through each possible char and find all possible lines for the top and bottom of each char segment
- for (int i = 0; i < charRegions.size() - 1; i++)
+ for (int k = i+1; k < charRegions.size(); k++)
{
- for (int k = i+1; k < charRegions.size(); k++)
- {
- //Mat tempImg;
- //result.copyTo(tempImg);
+ //Mat tempImg;
+ //result.copyTo(tempImg);
+ Rect* leftRect;
+ Rect* rightRect;
+ if (charRegions[i].x < charRegions[k].x)
+ {
+ leftRect = &charRegions[i];
+ rightRect = &charRegions[k];
+ }
+ else
+ {
+ leftRect = &charRegions[k];
+ rightRect = &charRegions[i];
+ }
- Rect* leftRect;
- Rect* rightRect;
- if (charRegions[i].x < charRegions[k].x)
- {
- leftRect = &charRegions[i];
- rightRect = &charRegions[k];
- }
- else
- {
- leftRect = &charRegions[k];
- rightRect = &charRegions[i];
- }
+ //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2);
+ //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2);
- //rectangle(tempImg, *leftRect, Scalar(0, 255, 0), 2);
- //rectangle(tempImg, *rightRect, Scalar(255, 255, 255), 2);
+ int x1, y1, x2, y2;
- int x1, y1, x2, y2;
+ if (leftRect->y > rightRect->y) // Rising line, use the top left corner of the rect
+ {
+ x1 = leftRect->x;
+ x2 = rightRect->x;
+ }
+ else // falling line, use the top right corner of the rect
+ {
+ x1 = leftRect->x + leftRect->width;
+ x2 = rightRect->x + rightRect->width;
+ }
+ y1 = leftRect->y;
+ y2 = rightRect->y;
- if (leftRect->y > rightRect->y) // Rising line, use the top left corner of the rect
- {
- x1 = leftRect->x;
- x2 = rightRect->x;
- }
- else // falling line, use the top right corner of the rect
- {
- x1 = leftRect->x + leftRect->width;
- x2 = rightRect->x + rightRect->width;
- }
- 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));
- //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
+ {
+ x1 = leftRect->x + leftRect->width;
+ x2 = rightRect->x + rightRect->width;
+ }
+ else // falling line, use the bottom left corner of the rect
+ {
+ x1 = leftRect->x;
+ x2 = rightRect->x;
+ }
+ 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));
- if (leftRect->y > rightRect->y) // Rising line, use the bottom right corner of the rect
- {
- x1 = leftRect->x + leftRect->width;
- x2 = rightRect->x + rightRect->width;
- }
- else // falling line, use the bottom left corner of the rect
- {
- x1 = leftRect->x;
- x2 = rightRect->x;
- }
- 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);
- }
+ //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++)
- {
- 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;
- float maxBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MAX_THRESHOLD;
- if ( (topYPos >= minTop && topYPos <= maxTop) &&
- (botYPos >= minBot && botYPos <= maxBot))
- {
- curScore++;
- }
-
- //cout << "Slope: " << topslope << " yPos: " << topYPos << endl;
- //drawAndWait(&tempImg);
-
- }
-
-
- // Tie goes to the one with longer line segments
- if ((curScore > bestScore) ||
- (curScore == bestScore && topLines[i].length > bestScoreDistance))
- {
- bestScore = curScore;
- bestScoreIndex = i;
- // Just use x distance for now
- 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);
- //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);
-
-
}
+ int bestScoreIndex = 0;
+ int bestScore = -1;
+ int bestScoreDistance = -1; // Line segment distance is used as a tie breaker
- return bestStripe;
+ // Now, among all possible lines, find the one that is the best fit
+ 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;
+ float maxBot = (charRegions[charidx].y + charRegions[charidx].height) * SCORING_MAX_THRESHOLD;
+ if ( (topYPos >= minTop && topYPos <= maxTop) &&
+ (botYPos >= minBot && botYPos <= maxBot))
+ {
+ curScore++;
+ }
+
+ //cout << "Slope: " << topslope << " yPos: " << topYPos << endl;
+ //drawAndWait(&tempImg);
+
+ }
+
+ // Tie goes to the one with longer line segments
+ if ((curScore > bestScore) ||
+ (curScore == bestScore && topLines[i].length > bestScoreDistance))
+ {
+ bestScore = curScore;
+ bestScoreIndex = i;
+ // Just use x distance for now
+ 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);
+ //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;
}
-
-
vector CharacterAnalysis::filter(Mat img, vector > contours, vector hierarchy)
{
static int STARTING_MIN_HEIGHT = round (((float) img.rows) * config->charAnalysisMinPercent);
@@ -643,7 +586,6 @@ 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++)
@@ -655,7 +597,6 @@ vector CharacterAnalysis::filter(Mat img, vector > contours,
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;
@@ -668,7 +609,6 @@ 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)
@@ -678,227 +618,216 @@ vector CharacterAnalysis::filter(Mat img, vector > contours,
}
}
-
return charSegments;
}
-
// Goes through the contours for the plate and picks out possible char segments based on min/max height
vector CharacterAnalysis::filterByBoxSize(vector< vector< Point> > contours, vector goodIndices, int minHeightPx, int maxHeightPx)
{
- float idealAspect=config->charWidthMM / config->charHeightMM;
- float aspecttolerance=0.25;
+ 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);
- 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;
- for (int i = 0; i < contours.size(); i++)
+ //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)
{
- if (goodIndices[i] == false)
- continue;
- //Create bounding rect of object
- Rect mr= boundingRect(contours[i]);
+ float charAspect= (float)mr.width/(float)mr.height;
- 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)
- includedIndices[i] = true;
- }
+ if (abs(charAspect - idealAspect) < aspecttolerance)
+ includedIndices[i] = true;
}
+ }
- return includedIndices;
+ return includedIndices;
}
-
-
vector< bool > CharacterAnalysis::filterContourHoles(vector< vector< Point > > contours, vector< Vec4i > hierarchy, vector< bool > goodIndices)
{
- vector includedIndices(contours.size());
- for (int j = 0; j < contours.size(); j++)
- includedIndices.push_back(false);
+ vector includedIndices(contours.size());
+ for (int j = 0; j < contours.size(); j++)
+ includedIndices.push_back(false);
- for (int i = 0; i < contours.size(); i++)
+ for (int i = 0; i < contours.size(); i++)
+ {
+ if (goodIndices[i] == false)
+ continue;
+
+ int parentIndex = hierarchy[i][3];
+
+ if (parentIndex >= 0 && goodIndices[parentIndex] == true)
{
- 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;
- }
- }
- else
- {
- includedIndices[i] = true;
- }
+ // this contour is a child of an already identified contour. REMOVE it
+ if (this->config->debugCharAnalysis)
+ {
+ cout << "filterContourHoles: contour index: " << i << endl;
+ }
}
+ else
+ {
+ includedIndices[i] = true;
+ }
+ }
- return includedIndices;
+ return includedIndices;
}
-
// Goes through the contours for the plate and picks out possible char segments based on min/max height
// 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 includedIndices(contours.size());
+ for (int j = 0; j < contours.size(); j++)
+ includedIndices[j] = false;
- vector parentIDs;
- vector votes;
+ vector parentIDs;
+ vector votes;
- for (int i = 0; i < contours.size(); i++)
+ 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
+ for (int j = 0; j < parentIDs.size(); j++)
{
- if (goodIndices[i] == false)
- continue;
-
- int voteIndex = -1;
- int parentID = hierarchy[i][3];
- // check if parentID is already in the lsit
- for (int j = 0; j < parentIDs.size(); j++)
- {
- if (parentIDs[j] == parentID)
- {
- voteIndex = j;
- break;
- }
- }
- if (voteIndex == -1)
- {
- parentIDs.push_back(parentID);
- votes.push_back(1);
- }
- else
- {
- votes[voteIndex] = votes[voteIndex] + 1;
- }
-
- }
-
- // Tally up the votes, pick the winner
- int totalVotes = 0;
- int winningParentId = 0;
- int highestVotes = 0;
- for (int i = 0; i < parentIDs.size(); i++)
- {
- if (votes[i] > highestVotes)
+ if (parentIDs[j] == parentID)
{
- winningParentId = parentIDs[i];
- highestVotes = votes[i];
+ voteIndex = j;
+ break;
}
- 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 (voteIndex == -1)
{
- if (goodIndices[i] == false)
- continue;
-
- if (totalVotes <= 2)
- {
- includedIndices[i] = true;
- }
- else if (hierarchy[i][3] == winningParentId)
- {
- includedIndices[i] = true;
- }
+ parentIDs.push_back(parentID);
+ votes.push_back(1);
+ }
+ else
+ {
+ votes[voteIndex] = votes[voteIndex] + 1;
}
- return includedIndices;
-}
+ }
+ // Tally up the votes, pick the winner
+ int totalVotes = 0;
+ int winningParentId = 0;
+ int highestVotes = 0;
+ for (int i = 0; i < parentIDs.size(); i++)
+ {
+ if (votes[i] > highestVotes)
+ {
+ winningParentId = parentIDs[i];
+ highestVotes = votes[i];
+ }
+ 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;
+ }
+ else if (hierarchy[i][3] == winningParentId)
+ {
+ includedIndices[i] = true;
+ }
+ }
+
+ return includedIndices;
+}
vector CharacterAnalysis::filterBetweenLines(Mat img, vector > contours, vector hierarchy, vector outerPolygon, vector goodIndices)
{
- static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88;
+ static float MIN_AREA_PERCENT_WITHIN_LINES = 0.88;
- vector includedIndices(contours.size());
- for (int j = 0; j < contours.size(); j++)
- includedIndices[j] = false;
+ vector includedIndices(contours.size());
+ for (int j = 0; j < contours.size(); j++)
+ includedIndices[j] = false;
+ if (outerPolygon.size() == 0)
+ return includedIndices;
- if (outerPolygon.size() == 0)
- return includedIndices;
+ vector validPoints;
- 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);
- // 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);
+ float lineHeight = distanceBetweenPoints(midpoint, acrossFromMidpoint);
- float x = ((float) img.cols) / 2;
- Point midpoint = Point(x, bottomLine.getPointAt(x));
- Point acrossFromMidpoint = topLine.closestPointOnSegmentTo(midpoint);
- float lineHeight = distanceBetweenPoints(midpoint, acrossFromMidpoint);
+ // Create a white mask for the area inside the polygon
+ 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));
- // Create a white mask for the area inside the polygon
- 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,
+ hierarchy,
+ 0
+ );
- for (int i = 0; i < contours.size(); i++)
+ 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++)
{
- if (goodIndices[i] == false)
- continue;
+ areaBetweenLines += contourArea(tempContours[tempContourIdx]);
- // 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,
- 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;
+ if (areaBetweenLines / totalArea >= MIN_AREA_PERCENT_WITHIN_LINES)
+ {
+ includedIndices[i] = true;
+ }
+
+ innerArea.setTo(Scalar(0,0,0));
+ }
+
+ return includedIndices;
}
std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point > > contours, vector< Vec4i > hierarchy, std::vector< bool > goodIndices)
@@ -909,7 +838,6 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point >
if (hasPlateMask == false)
return goodIndices;
-
vector passingIndices;
for (int i = 0; i < goodIndices.size(); i++)
passingIndices.push_back(false);
@@ -935,8 +863,8 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point >
if (afterMaskWhiteness / beforeMaskWhiteness > MINIMUM_PERCENT_LEFT_AFTER_MASK)
{
- charsInsideMask++;
- passingIndices[i] = true;
+ charsInsideMask++;
+ passingIndices[i] = true;
}
}
@@ -952,8 +880,6 @@ std::vector< bool > CharacterAnalysis::filterByOuterMask(vector< vector< Point >
return passingIndices;
}
-
-
bool CharacterAnalysis::isPlateInverted()
{
@@ -964,42 +890,39 @@ bool CharacterAnalysis::isPlateInverted()
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;
}
-
bool CharacterAnalysis::verifySize(Mat r, float minHeightPx, float maxHeightPx)
{
- //Char sizes 45x90
- float aspect=config->charWidthMM / config->charHeightMM;
- float charAspect= (float)r.cols/(float)r.rows;
- float error=0.35;
- //float minHeight=TEMPLATE_PLATE_HEIGHT * .35;
- //float maxHeight=TEMPLATE_PLATE_HEIGHT * .65;
- //We have a different aspect ratio for number 1, and it can be ~0.2
- float minAspect=0.2;
- float maxAspect=aspect+aspect*error;
- //area of pixels
- float area=countNonZero(r);
- //bb area
- float bbArea=r.cols*r.rows;
- //% of pixel in area
- float percPixels=area/bbArea;
+ //Char sizes 45x90
+ float aspect=config->charWidthMM / config->charHeightMM;
+ float charAspect= (float)r.cols/(float)r.rows;
+ float error=0.35;
+ //float minHeight=TEMPLATE_PLATE_HEIGHT * .35;
+ //float maxHeight=TEMPLATE_PLATE_HEIGHT * .65;
+ //We have a different aspect ratio for number 1, and it can be ~0.2
+ float minAspect=0.2;
+ float maxAspect=aspect+aspect*error;
+ //area of pixels
+ float area=countNonZero(r);
+ //bb area
+ float bbArea=r.cols*r.rows;
+ //% of pixel in area
+ float percPixels=area/bbArea;
- //if(DEBUG)
- //cout << "Aspect: "<< aspect << " ["<< minAspect << "," << maxAspect << "] " << "Area "<< percPixels <<" Char aspect " << charAspect << " Height char "<< r.rows << "\n";
- if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeightPx && r.rows < maxHeightPx)
- return true;
- else
- return false;
+ //if(DEBUG)
+ //cout << "Aspect: "<< aspect << " ["<< minAspect << "," << maxAspect << "] " << "Area "<< percPixels <<" Char aspect " << charAspect << " Height char "<< r.rows << "\n";
+ if(percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeightPx && r.rows < maxHeightPx)
+ return true;
+ else
+ return false;
}
-
vector CharacterAnalysis::getCharArea()
{
const int MAX = 100000;
@@ -1010,16 +933,16 @@ vector CharacterAnalysis::getCharArea()
for (int i = 0; i < bestContours.size(); i++)
{
- if (bestCharSegments[i] == false)
- continue;
+ if (bestCharSegments[i] == false)
+ continue;
- for (int z = 0; z < bestContours[i].size(); z++)
- {
- if (bestContours[i][z].x < leftX)
- leftX = bestContours[i][z].x;
- if (bestContours[i][z].x > rightX)
- rightX = bestContours[i][z].x;
- }
+ for (int z = 0; z < bestContours[i].size(); z++)
+ {
+ if (bestContours[i][z].x < leftX)
+ leftX = bestContours[i][z].x;
+ if (bestContours[i][z].x > rightX)
+ rightX = bestContours[i][z].x;
+ }
}
vector charArea;
@@ -1029,10 +952,10 @@ vector CharacterAnalysis::getCharArea()
Point tr(rightX, topLine.getPointAt(rightX));
Point br(rightX, bottomLine.getPointAt(rightX));
Point bl(leftX, bottomLine.getPointAt(leftX));
- charArea.push_back(tl);
- charArea.push_back(tr);
- charArea.push_back(br);
- charArea.push_back(bl);
+ charArea.push_back(tl);
+ charArea.push_back(tr);
+ charArea.push_back(br);
+ charArea.push_back(bl);
}
return charArea;
diff --git a/src/openalpr/characterregion.cpp b/src/openalpr/characterregion.cpp
index 9660c73..5146d75 100644
--- a/src/openalpr/characterregion.cpp
+++ b/src/openalpr/characterregion.cpp
@@ -28,19 +28,15 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
this->confidence = 0;
-
-
if (this->debug)
cout << "Starting CharacterRegion identification" << endl;
timespec startTime;
getTime(&startTime);
-
charAnalysis = new CharacterAnalysis(img, config);
charAnalysis->analyze();
-
if (this->debug)
{
vector tempDash;
@@ -53,7 +49,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
tempDash.push_back(tmp);
}
-
Mat bestVal(charAnalysis->bestThreshold.size(), charAnalysis->bestThreshold.type());
charAnalysis->bestThreshold.copyTo(bestVal);
cvtColor(bestVal, bestVal, CV_GRAY2BGR);
@@ -62,18 +57,16 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
{
Scalar dcolor(255,0,0);
if (charAnalysis->bestCharSegments[z])
- dcolor = Scalar(0,255,0);
+ dcolor = Scalar(0,255,0);
drawContours(bestVal, charAnalysis->bestContours, z, dcolor, 1);
}
tempDash.push_back(bestVal);
displayImage(config, "Character Region Step 1 Thresholds", drawImageDashboard(tempDash, bestVal.type(), 3));
}
-
-
if (this->debug)
{
- /*
+ /*
Mat img_contours(img_threshold.size(), CV_8U);
img_threshold.copyTo(img_contours);
cvtColor(img_contours, img_contours, CV_GRAY2RGB);
@@ -81,29 +74,26 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
vector > allowedContours;
for (int i = 0; i < contours.size(); i++)
{
- if (charSegments[i])
- allowedContours.push_back(contours[i]);
+ if (charSegments[i])
+ allowedContours.push_back(contours[i]);
}
drawContours(img_contours, contours,
- -1, // draw all contours
- cv::Scalar(255,0,0), // in blue
- 1); // with a thickness of 1
+ -1, // draw all contours
+ cv::Scalar(255,0,0), // in blue
+ 1); // with a thickness of 1
drawContours(img_contours, allowedContours,
- -1, // draw all contours
- cv::Scalar(0,255,0), // in green
- 1); // with a thickness of 1
-
+ -1, // draw all contours
+ cv::Scalar(0,255,0), // in green
+ 1); // with a thickness of 1
displayImage(config, "Matching Contours", img_contours);
*/
}
-
//charsegments = this->getPossibleCharRegions(img_threshold, allContours, allHierarchy, STARTING_MIN_HEIGHT + (bestFitIndex * HEIGHT_STEP), STARTING_MAX_HEIGHT + (bestFitIndex * HEIGHT_STEP));
-
if (charAnalysis->linePolygon.size() > 0)
{
@@ -120,7 +110,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
else if (absangle > 1)
confidenceDrainers += (10 - absangle) * 5;
-
if (confidenceDrainers >= 100)
this->confidence=1;
else
@@ -128,8 +117,6 @@ CharacterRegion::CharacterRegion(Mat img, Config* config)
}
-
-
if (config->debugTiming)
{
timespec endTime;
@@ -144,49 +131,47 @@ CharacterRegion::~CharacterRegion()
delete(charAnalysis);
}
-
-
Mat CharacterRegion::getPlateMask()
{
- return charAnalysis->plateMask;
+ return charAnalysis->plateMask;
}
LineSegment CharacterRegion::getTopLine()
{
- return charAnalysis->topLine;
+ return charAnalysis->topLine;
}
LineSegment CharacterRegion::getBottomLine()
{
- return charAnalysis->bottomLine;
+ return charAnalysis->bottomLine;
}
vector 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/charactersegmenter.cpp b/src/openalpr/charactersegmenter.cpp
index 81777eb..3eef1de 100644
--- a/src/openalpr/charactersegmenter.cpp
+++ b/src/openalpr/charactersegmenter.cpp
@@ -34,7 +34,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
timespec startTime;
getTime(&startTime);
-
Mat img_gray(img.size(), CV_8U);
cvtColor( img, img_gray, CV_BGR2GRAY );
@@ -43,22 +42,14 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
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));
+ displayImage(config, "CharacterSegmenter Thresholds", drawImageDashboard(charAnalysis->thresholds, CV_8U, 3));
}
-
-
-
-
-
if (this->config->debugCharSegmenter)
{
@@ -69,19 +60,19 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
vector > allowedContours;
for (int i = 0; i < charAnalysis->bestContours.size(); i++)
{
- if (charAnalysis->bestCharSegments[i])
- allowedContours.push_back(charAnalysis->bestContours[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
+ -1, // draw all contours
+ cv::Scalar(255,0,0), // in blue
+ 1); // with a thickness of 1
drawContours(img_contours, allowedContours,
- -1, // draw all contours
- cv::Scalar(0,255,0), // in green
- 1); // with a thickness of 1
+ -1, // draw all contours
+ cv::Scalar(0,255,0), // in green
+ 1); // with a thickness of 1
if (charAnalysis->linePolygon.size() > 0)
{
@@ -93,8 +84,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
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);
@@ -105,14 +94,13 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
for (int i = 0; i < charAnalysis->bestContours.size(); i++)
{
- if (charAnalysis->bestCharSegments[i] == false)
- continue;
+ if (charAnalysis->bestCharSegments[i] == false)
+ continue;
+ Rect mr = boundingRect(charAnalysis->bestContours[i]);
- Rect mr = boundingRect(charAnalysis->bestContours[i]);
-
- charWidths.push_back(mr.width);
- charHeights.push_back(mr.height);
+ charWidths.push_back(mr.width);
+ charHeights.push_back(mr.height);
}
float avgCharWidth = median(charWidths.data(), charWidths.size());
@@ -122,56 +110,49 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
// 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++)
{
-
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)
{
- Mat histoCopy(vertHistogram.histoImg.size(), vertHistogram.histoImg.type());
- //vertHistogram.copyTo(histoCopy);
- cvtColor(vertHistogram.histoImg, histoCopy, CV_GRAY2RGB);
- allHistograms.push_back(histoCopy);
+ Mat histoCopy(vertHistogram.histoImg.size(), vertHistogram.histoImg.type());
+ //vertHistogram.copyTo(histoCopy);
+ cvtColor(vertHistogram.histoImg, histoCopy, CV_GRAY2RGB);
+ allHistograms.push_back(histoCopy);
}
//
float score = 0;
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));
- }
+ 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);
+ 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]);
+ allBoxes.push_back(charBoxes[z]);
//drawAndWait(&histogramMask);
}
-
float medianCharWidth = avgCharWidth;
vector widthValues;
// Compute largest char width
@@ -182,7 +163,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
medianCharWidth = median(widthValues.data(), widthValues.size());
-
if (config->debugTiming)
{
timespec endTime;
@@ -193,25 +173,23 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
//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
+ // Setup the dashboard images to show the cleaning filters
for (int i = 0; i < charAnalysis->thresholds.size(); i++)
{
- Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type());
- Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes);
- charAnalysis->thresholds[i].copyTo(cleanImg);
- bitwise_and(cleanImg, boxMask, cleanImg);
- cvtColor(cleanImg, cleanImg, CV_GRAY2BGR);
+ Mat cleanImg = Mat::zeros(charAnalysis->thresholds[i].size(), charAnalysis->thresholds[i].type());
+ Mat boxMask = getCharBoxMask(charAnalysis->thresholds[i], candidateBoxes);
+ 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);
+ 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);
@@ -238,7 +216,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
if (this->config->debugCharSegmenter)
{
-
Mat imgDash = drawImageDashboard(charAnalysis->thresholds, CV_8U, 3);
displayImage(config, "Segmentation after cleaning", imgDash);
@@ -250,11 +227,6 @@ CharacterSegmenter::CharacterSegmenter(Mat img, bool invertedColors, Config* con
}
}
-
-
-
-
-
if (config->debugTiming)
{
timespec endTime;
@@ -268,11 +240,6 @@ CharacterSegmenter::~CharacterSegmenter()
delete charAnalysis;
}
-
-
-
-
-
// Given a histogram and the horizontal line boundaries, respond with an array of boxes where the characters are
// Scores the histogram quality as well based on num chars, char volume, and even separation
vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram, float avgCharWidth, float avgCharHeight, float* score)
@@ -298,8 +265,8 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram,
}
else if (allBoxes[i].width > avgCharWidth * 2 && allBoxes[i].width < MAX_SEGMENT_WIDTH * 2 && allBoxes[i].height > MIN_HISTOGRAM_HEIGHT)
{
- // rectangle(histogram.histoImg, allBoxes[i], Scalar(255, 0, 0) );
- // drawAndWait(&histogram.histoImg);
+ // rectangle(histogram.histoImg, allBoxes[i], Scalar(255, 0, 0) );
+ // drawAndWait(&histogram.histoImg);
// 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);
@@ -314,29 +281,26 @@ vector CharacterSegmenter::getHistogramBoxes(VerticalHistogram histogram,
if (maxHeightChar1 > MIN_HISTOGRAM_HEIGHT && minHeight < (0.25 * ((float) maxHeightChar1)))
{
- // Add a box for Char1
- Point botRight = Point(minX - 1, allBoxes[i].y + allBoxes[i].height);
- charBoxes.push_back(Rect(allBoxes[i].tl(), botRight) );
+ // Add a box for Char1
+ Point botRight = Point(minX - 1, allBoxes[i].y + allBoxes[i].height);
+ charBoxes.push_back(Rect(allBoxes[i].tl(), botRight) );
}
if (maxHeightChar2 > MIN_HISTOGRAM_HEIGHT && minHeight < (0.25 * ((float) maxHeightChar2)))
{
- // Add a box for Char2
- Point topLeft = Point(minX + 1, allBoxes[i].y);
- charBoxes.push_back(Rect(topLeft, allBoxes[i].br()) );
+ // Add a box for Char2
+ Point topLeft = Point(minX + 1, allBoxes[i].y);
+ 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
@@ -344,7 +308,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
Mat histoImg = Mat::zeros(Size(img.cols, img.rows), CV_8U);
-
int columnCount;
for (int col = 0; col < img.cols; col++)
@@ -354,7 +317,7 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
for (int i = 0; i < charBoxes.size(); i++)
{
if (col >= charBoxes[i].x && col < (charBoxes[i].x + charBoxes[i].width))
- columnCount++;
+ columnCount++;
}
// Fill the line of the histogram
@@ -370,7 +333,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
float bestRowScore = 0;
vector bestBoxes;
-
for (int row = 0; row < histoImg.rows; row++)
{
vector validBoxes;
@@ -387,48 +349,46 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
for (int boxidx = 0; boxidx < allBoxes.size(); boxidx++)
{
int w = allBoxes[boxidx].width;
- if (w >= config->segmentationMinBoxWidthPx && w <= MAX_SEGMENT_WIDTH)
- {
- float widthDiffPixels = abs(w - avgCharWidth);
- float widthDiffPercent = widthDiffPixels / avgCharWidth;
- rowScore += 10 * (1 - widthDiffPercent);
+ if (w >= config->segmentationMinBoxWidthPx && w <= MAX_SEGMENT_WIDTH)
+ {
+ float widthDiffPixels = abs(w - avgCharWidth);
+ float widthDiffPercent = widthDiffPixels / avgCharWidth;
+ rowScore += 10 * (1 - widthDiffPercent);
- if (widthDiffPercent < 0.25) // Bonus points when it's close to the average character width
- rowScore += 8;
+ 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 )
- {
- // 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);
+ validBoxes.push_back(allBoxes[boxidx]);
+ }
+ else if (w > avgCharWidth * 2 && w <= MAX_SEGMENT_WIDTH * 2 )
+ {
+ // 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 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);
+ int maxHeightChar1 = histogram.getHeightAt(maxXChar1);
+ int maxHeightChar2 = histogram.getHeightAt(maxXChar2);
- if ( minHeight < (0.25 * ((float) maxHeightChar1)))
- {
- // Add a box for Char1
- Point botRight = Point(minX - 1, allBoxes[boxidx].y + allBoxes[boxidx].height);
- validBoxes.push_back(Rect(allBoxes[boxidx].tl(), botRight) );
- }
- if ( minHeight < (0.25 * ((float) maxHeightChar2)))
- {
- // Add a box for Char2
- Point topLeft = Point(minX + 1, allBoxes[boxidx].y);
- validBoxes.push_back(Rect(topLeft, allBoxes[boxidx].br()) );
- }
- }
+ if ( minHeight < (0.25 * ((float) maxHeightChar1)))
+ {
+ // Add a box for Char1
+ Point botRight = Point(minX - 1, allBoxes[boxidx].y + allBoxes[boxidx].height);
+ validBoxes.push_back(Rect(allBoxes[boxidx].tl(), botRight) );
+ }
+ if ( minHeight < (0.25 * ((float) maxHeightChar2)))
+ {
+ // Add a box for Char2
+ Point topLeft = Point(minX + 1, allBoxes[boxidx].y);
+ validBoxes.push_back(Rect(topLeft, allBoxes[boxidx].br()) );
+ }
+ }
}
-
-
if (rowScore > bestRowScore)
{
bestRowScore = rowScore;
@@ -437,8 +397,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
}
}
-
-
if (this->config->debugCharSegmenter)
{
cvtColor(histoImg, histoImg, CV_GRAY2BGR);
@@ -455,7 +413,6 @@ vector CharacterSegmenter::getBestCharBoxes(Mat img, vector charBoxe
}
-
return bestBoxes;
}
@@ -476,7 +433,7 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset)
}
if ((isOn == false && onSegment == true) ||
- (col == img.cols - 1 && onSegment == true))
+ (col == img.cols - 1 && onSegment == true))
{
// A segment just ended or we're at the very end of the row and we're on a segment
Point topLeft = Point(col - curSegmentLength, top.getPointAt(col - curSegmentLength) - 1);
@@ -489,11 +446,9 @@ vector CharacterSegmenter::get1DHits(Mat img, int yOffset)
}
-
return hits;
}
-
void CharacterSegmenter::removeSmallContours(vector thresholds, vector > > allContours, float avgCharWidth, float avgCharHeight)
{
//const float MIN_CHAR_AREA = 0.02 * avgCharWidth * avgCharHeight; // To clear out the tiny specks
@@ -505,14 +460,14 @@ void CharacterSegmenter::removeSmallContours(vector thresholds, vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa
{
if (i == charBoxes.size() - 1)
{
- newCharBoxes.push_back(charBoxes[i]);
- break;
+ newCharBoxes.push_back(charBoxes[i]);
+ break;
}
float bigWidth = (charBoxes[i + 1].x + charBoxes[i + 1].width - charBoxes[i].x);
@@ -543,24 +498,22 @@ vector CharacterSegmenter::combineCloseBoxes( vector charBoxes, floa
newCharBoxes.push_back(bigRect);
if (this->config->debugCharSegmenter)
{
- for (int z = 0; z < charAnalysis->thresholds.size(); z++)
- {
- Point center(bigRect.x + bigRect.width / 2, bigRect.y + bigRect.height / 2);
- RotatedRect rrect(center, Size2f(bigRect.width, bigRect.height + (bigRect.height / 2)), 0);
- ellipse(imgDbgCleanStages[z], rrect, Scalar(0,255,0), 1);
- }
- cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl;
+ for (int z = 0; z < charAnalysis->thresholds.size(); z++)
+ {
+ Point center(bigRect.x + bigRect.width / 2, bigRect.y + bigRect.height / 2);
+ RotatedRect rrect(center, Size2f(bigRect.width, bigRect.height + (bigRect.height / 2)), 0);
+ ellipse(imgDbgCleanStages[z], rrect, Scalar(0,255,0), 1);
+ }
+ cout << "Merging 2 boxes -- " << i << " and " << i + 1 << endl;
}
i++;
}
else
{
- newCharBoxes.push_back(charBoxes[i]);
+ newCharBoxes.push_back(charBoxes[i]);
}
-
-
}
return newCharBoxes;
@@ -575,7 +528,6 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c
Mat mask = getCharBoxMask(thresholds[0], charRegions);
-
for (int i = 0; i < thresholds.size(); i++)
{
bitwise_and(thresholds[i], mask, thresholds[i]);
@@ -598,82 +550,74 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c
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++)
{
- if (contours[c].size() == 0)
- continue;
- if (charRegions[j].contains(contours[c][0]) == false)
- continue;
+ if (contours[c].size() == 0)
+ 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);
- Rect r = boundingRect(contours[c]);
+ if (this->config->debugCharSegmenter)
+ {
+ drawContours(imgDbgCleanStages[i], contours, c, COLOR_DEBUG_SPECKLES, CV_FILLED);
+ }
+ }
+ else
+ {
+ if (r.height > tallestContourHeight)
+ tallestContourHeight = r.height;
- 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);
+ totalArea += contourArea(contours[c]);
- if (this->config->debugCharSegmenter)
- {
- drawContours(imgDbgCleanStages[i], contours, c, COLOR_DEBUG_SPECKLES, CV_FILLED);
- }
- }
- else
- {
- if (r.height > tallestContourHeight)
- tallestContourHeight = r.height;
-
- totalArea += contourArea(contours[c]);
-
-
- }
- //else if (r.height > tallestContourHeight)
- //{
- // tallestContourIndex = c;
- // tallestContourHeight = h;
- //}
+ }
+ //else if (r.height > tallestContourHeight)
+ //{
+ // tallestContourIndex = c;
+ // tallestContourHeight = h;
+ //}
}
-
-
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;
+ // 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);
- }
+ 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);
+ rectangle(thresholds[i], charRegions[j], Scalar(0, 0, 0), -1);
}
else if (tallestContourHeight < ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT))
{
- // This character is too short. Black the whole thing out
- 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;
+ // This character is too short. Black the whole thing out
+ 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);
+ 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 ) );
+ Size( 2 + 1, 2+1 ),
+ Point( 1, 1 ) );
//morphologyEx(thresholds[i], thresholds[i], MORPH_OPEN, element);
@@ -685,14 +629,13 @@ void CharacterSegmenter::cleanCharRegions(vector thresholds, vector c
// Lastly, draw a clipping line between each character boxes
for (int j = 0; j < charRegions.size(); j++)
{
- line(thresholds[i], Point(charRegions[j].x - 1, charRegions[j].y), Point(charRegions[j].x - 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0));
- 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));
+ line(thresholds[i], Point(charRegions[j].x - 1, charRegions[j].y), Point(charRegions[j].x - 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0));
+ line(thresholds[i], Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y), Point(charRegions[j].x + charRegions[j].width + 1, charRegions[j].y + charRegions[j].height), Scalar(0, 0, 0));
}
}
}
-
void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask, vector charRegions)
{
// If I knock out x% of the contour area from this thing (after applying the color filter)
@@ -702,79 +645,75 @@ void CharacterSegmenter::cleanBasedOnColor(vector thresholds, Mat colorMask
for (int i = 0; i < thresholds.size(); i++)
{
- for (int j = 0; j < charRegions.size(); j++)
+ 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);
- 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;
- //Mat thresholdCopy2 = Mat::zeros(thresholds[i].size(), CV_8U);
- //rectangle(thresholdCopy2, charRegions[j], Scalar(255,255,255), CV_FILLED);
- //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask"));
- //bitwise_and(thresholds[i], thresholdCopy2, thresholdCopy2);
- //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh"));
- //bitwise_and(colorMask, thresholdCopy2, thresholdCopy2);
- //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh + Color"));
+ if (this->config->debugCharSegmenter)
+ {
+ //vector tmpDebug;
+ //Mat thresholdCopy2 = Mat::zeros(thresholds[i].size(), CV_8U);
+ //rectangle(thresholdCopy2, charRegions[j], Scalar(255,255,255), CV_FILLED);
+ //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask"));
+ //bitwise_and(thresholds[i], thresholdCopy2, thresholdCopy2);
+ //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh"));
+ //bitwise_and(colorMask, thresholdCopy2, thresholdCopy2);
+ //tmpDebug.push_back(addLabel(thresholdCopy2, "box Mask + Thresh + Color"));
//
// Mat tmpytmp = addLabel(thresholdCopy2, "box Mask + Thresh + Color");
// Mat tmpx = drawImageDashboard(tmpDebug, tmpytmp.type(), 1);
- //drawAndWait( &tmpx );
+ //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;
- 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);
- }
- }
+ Point topLeft(charRegions[j].x, charRegions[j].y);
+ circle(imgDbgCleanStages[i], topLeft, 5, COLOR_DEBUG_COLORFILTER, CV_FILLED);
+ }
}
+ }
}
}
-
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);
+ 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++)
+ for (int j = 0; j < thresholds.size(); j++)
+ {
+ if (mean(thresholds[j], mask)[0] > MAX_FILLED)
{
- if (mean(thresholds[j], mask)[0] > MAX_FILLED)
- {
- // Empty the rect
- rectangle(thresholds[j], charRegions[i], Scalar(0,0,0), -1);
+ // 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);
- rectangle(imgDbgCleanStages[j], inset, COLOR_DEBUG_FULLBOX, 1);
- }
- }
+ if (this->config->debugCharSegmenter)
+ {
+ Rect inset(charRegions[i].x + 2, charRegions[i].y - 2, charRegions[i].width - 4, charRegions[i].height - 4);
+ rectangle(imgDbgCleanStages[j], inset, COLOR_DEBUG_FULLBOX, 1);
+ }
}
+ }
}
}
vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds, const vector charRegions)
@@ -811,31 +750,29 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds,
vector allPointsInBox;
for (int c = 0; c < contours.size(); c++)
{
- if (contours[c].size() == 0)
- continue;
+ if (contours[c].size() == 0)
+ continue;
- for (int z = 0; z < contours[c].size(); z++)
- allPointsInBox.push_back(contours[c][z]);
+ for (int z = 0; z < contours[c].size(); z++)
+ allPointsInBox.push_back(contours[c][z]);
}
float height = 0;
if (allPointsInBox.size() > 0)
{
- height = boundingRect(allPointsInBox).height;
+ height = boundingRect(allPointsInBox).height;
}
-
if (height >= ((float) charRegions[j].height * MIN_CONTOUR_HEIGHT_PERCENT))
{
- boxScores[j] = boxScores[j] + 1;
+ boxScores[j] = boxScores[j] + 1;
}
else if (this->config->debugCharSegmenter)
{
- drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3);
+ drawX(imgDbgCleanStages[i], charRegions[j], COLOR_DEBUG_EMPTYFILTER, 3);
}
-
}
}
@@ -862,16 +799,16 @@ vector CharacterSegmenter::filterMostlyEmptyBoxes(vector thresholds,
// Erase the box from the Mat... mainly for debug purposes
if (this->config->debugCharSegmenter)
{
- cout << "Mostly Empty Filter: box index: " << i;
- cout << " this box had a score of : " << boxScores[i];;
- cout << " MIN_FULL_BOXES: " << MIN_FULL_BOXES << endl;;
+ 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);
+ 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);
- }
+ drawX(imgDbgCleanStages[z], charRegions[i], COLOR_DEBUG_EMPTYFILTER, 1);
+ }
}
}
@@ -902,7 +839,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector 0 && charBoxes[0].width < MIN_SEGMENT_WIDTH_EDGES)
// charBoxes.erase(charBoxes.begin() + 0);
-
// TECHNIQUE #1
// Check for long vertical lines. Once the line is too long, mask the whole region
@@ -934,7 +870,7 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector MIN_CONNECTED_EDGE_PIXELS)
{
- leftEdgeX = col;
- break;
+ leftEdgeX = col;
+ break;
}
col--;
@@ -963,13 +899,12 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector MIN_CONNECTED_EDGE_PIXELS)
{
- rightEdgeX = col;
- break;
+ rightEdgeX = col;
+ break;
}
col++;
}
-
if (leftEdgeX != 0)
leftEdges.push_back(leftEdgeX);
if (rightEdgeX != thresholds[i].cols)
@@ -1007,7 +942,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector MAX_COVERAGE_PERCENT) ||
- (charRegions[0].width - leftCoveragePx < config->segmentationMinBoxWidthPx))
+ (charRegions[0].width - leftCoveragePx < config->segmentationMinBoxWidthPx))
{
rectangle(mask, charRegions[0], Scalar(0,0,0), -1); // Mask the whole region
if (this->config->debugCharSegmenter)
- cout << "Edge Filter: Entire left region is erased" << endl;
+ cout << "Edge Filter: Entire left region is erased" << endl;
}
if ((rightCoveragePercent > MAX_COVERAGE_PERCENT) ||
- (charRegions[charRegions.size() -1].width - rightCoveragePx < config->segmentationMinBoxWidthPx))
+ (charRegions[charRegions.size() -1].width - rightCoveragePx < config->segmentationMinBoxWidthPx))
{
rectangle(mask, charRegions[charRegions.size() -1], Scalar(0,0,0), -1);
if (this->config->debugCharSegmenter)
- cout << "Edge Filter: Entire right region is erased" << endl;
+ cout << "Edge Filter: Entire right region is erased" << endl;
}
for (int i = 0; i < thresholds.size(); i++)
@@ -1034,7 +968,6 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vectorconfig->debugCharSegmenter)
{
cout << "Edge Filter: left=" << leftEdge << " right=" << rightEdge << endl;
@@ -1044,7 +977,7 @@ void CharacterSegmenter::filterEdgeBoxes(vector thresholds, const vector thresholds, const vector > contours;
- Mat mask = Mat::zeros(thresholds[i].size(),CV_8U);
- rectangle(mask, charRegions[boxidx], Scalar(255,255,255), CV_FILLED);
+ 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);
- float tallestContourHeight = 0;
- float fattestContourWidth = 0;
- float biggestContourArea = 0;
- for (int c = 0; c < contours.size(); c++)
- {
- Rect r = boundingRect(contours[c]);
- if (r.height > tallestContourHeight)
- tallestContourHeight = r.height;
- if (r.width > fattestContourWidth)
- fattestContourWidth = r.width;
- float a = r.area();
- if (a > biggestContourArea)
- biggestContourArea = a;
- }
+ 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);
+ float tallestContourHeight = 0;
+ float fattestContourWidth = 0;
+ float biggestContourArea = 0;
+ for (int c = 0; c < contours.size(); c++)
+ {
+ Rect r = boundingRect(contours[c]);
+ if (r.height > tallestContourHeight)
+ tallestContourHeight = r.height;
+ if (r.width > fattestContourWidth)
+ fattestContourWidth = r.width;
+ float a = r.area();
+ if (a > biggestContourArea)
+ biggestContourArea = a;
+ }
- float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT;
- if ((fattestContourWidth < MIN_BOX_WIDTH_PX) ||
- (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) ||
- (biggestContourArea < minArea)
- )
- {
- // Find a good place to MASK this contour.
- // for now, just mask the whole thing
- if (this->debug)
- {
+ float minArea = charRegions[boxidx].area() * MIN_EDGE_CONTOUR_AREA_PCT;
+ if ((fattestContourWidth < MIN_BOX_WIDTH_PX) ||
+ (tallestContourHeight < MIN_EDGE_CONTOUR_HEIGHT) ||
+ (biggestContourArea < minArea)
+ )
+ {
+ // Find a good place to MASK this contour.
+ // for now, just mask the whole thing
+ if (this->debug)
+ {
- rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2);
- cout << "Edge Filter: threshold " << i << " box " << boxidx << endl;
- }
- rectangle(thresholds[i], charRegions[boxidx], Scalar(0,0,0), -1);
- }
- else
- {
- filteredCharRegions.push_back(charRegions[boxidx]);
- }
+ rectangle(imgDbgCleanStages[i], charRegions[boxidx], COLOR_DEBUG_EDGE, 2);
+ cout << "Edge Filter: threshold " << i << " box " << boxidx << endl;
+ }
+ rectangle(thresholds[i], charRegions[boxidx], Scalar(0,0,0), -1);
+ }
+ else
+ {
+ filteredCharRegions.push_back(charRegions[boxidx]);
+ }
}
}
*/
@@ -1140,7 +1073,7 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
// Add a little extra to the score if this is outside of the lines
if (!isbetweenLines)
- incrementBy = 1.1;
+ incrementBy = 1.1;
onSegment = true;
curSegmentLength += incrementBy;
@@ -1151,10 +1084,10 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
}
if ((isOn == false && onSegment == true) ||
- (row == img.rows - 1 && onSegment == true))
+ (row == img.rows - 1 && onSegment == true))
{
if (wasbetweenLines && curSegmentLength > longestBlobLength)
- longestBlobLength = curSegmentLength;
+ longestBlobLength = curSegmentLength;
onSegment = false;
isbetweenLines = false;
@@ -1163,7 +1096,6 @@ int CharacterSegmenter::getLongestBlobLengthBetweenLines(Mat img, int col)
}
-
return longestBlobLength;
}
@@ -1183,7 +1115,6 @@ int CharacterSegmenter::isSkinnyLineInsideBox(Mat threshold, Rect box, vector tallestContourHeight)
{
- tallestContourIdx = s;
- tallestContourHeight = r.height;
- tallestContourWidth = r.width;
- tallestContourArea = contourArea(subContours[s]);
+ tallestContourIdx = s;
+ tallestContourHeight = r.height;
+ tallestContourWidth = r.width;
+ tallestContourArea = contourArea(subContours[s]);
}
}
if (tallestContourIdx != -1)
{
-
//cout << "Edge Filter: " << tallestContourHeight << " -- " << avgCharHeight << endl;
if (tallestContourHeight >= avgCharHeight * 0.9 &&
- ((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1)))
+ ((tallestContourWidth < config->segmentationMinBoxWidthPx) || (tallestContourArea < avgCharWidth * avgCharHeight * 0.1)))
{
- cout << "Edge Filter: Avg contour width: " << avgCharWidth << " This guy is: " << tallestContourWidth << endl;
- cout << "Edge Filter: tallestContourArea: " << tallestContourArea << " Minimum: " << avgCharWidth * avgCharHeight * 0.1 << endl;
- return i;
+ cout << "Edge Filter: Avg contour width: " << avgCharWidth << " This guy is: " << tallestContourWidth << endl;
+ cout << "Edge Filter: tallestContourArea: " << tallestContourArea << " Minimum: " << avgCharWidth * avgCharHeight * 0.1 << endl;
+ return i;
}
}
}
@@ -1230,14 +1160,12 @@ 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);
+ rectangle(mask, charBoxes[i], Scalar(255, 255, 255), -1);
return mask;
}
diff --git a/src/openalpr/cjson.h b/src/openalpr/cjson.h
index 9bfc54f..4703a6d 100644
--- a/src/openalpr/cjson.h
+++ b/src/openalpr/cjson.h
@@ -24,8 +24,7 @@
#define cJSON__h
#ifdef __cplusplus
-extern "C"
-{
+extern "C" {
#endif
/* cJSON Types: */
@@ -40,22 +39,24 @@ extern "C"
#define cJSON_IsReference 256
/* The cJSON structure: */
-typedef struct cJSON {
- struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
- struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+typedef struct cJSON
+{
+ struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
- int type; /* The type of the item, as above. */
+ int type; /* The type of the item, as above. */
- char *valuestring; /* The item's string, if type==cJSON_String */
- int valueint; /* The item's number, if type==cJSON_Number */
- double valuedouble; /* The item's number, if type==cJSON_Number */
+ char *valuestring; /* The item's string, if type==cJSON_String */
+ int valueint; /* The item's number, if type==cJSON_Number */
+ double valuedouble; /* The item's number, if type==cJSON_Number */
- char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+ char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
-typedef struct cJSON_Hooks {
- void *(*malloc_fn)(size_t sz);
- void (*free_fn)(void *ptr);
+typedef struct cJSON_Hooks
+{
+ void *(*malloc_fn)(size_t sz);
+ void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
diff --git a/src/openalpr/colorfilter.cpp b/src/openalpr/colorfilter.cpp
index cc20bfa..5be932e 100644
--- a/src/openalpr/colorfilter.cpp
+++ b/src/openalpr/colorfilter.cpp
@@ -17,11 +17,8 @@
* along with this program. If not, see .
*/
-
#include "colorfilter.h"
-
-
ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
{
@@ -32,7 +29,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
this->debug = config->debugColorFiler;
-
this->grayscale = imageIsGrayscale(image);
if (this->debug)
@@ -48,7 +44,6 @@ ColorFilter::ColorFilter(Mat image, Mat characterMask, Config* config)
findCharColors();
-
if (config->debugTiming)
{
timespec endTime;
@@ -75,12 +70,12 @@ bool ColorFilter::imageIsGrayscale(Mat image)
if (r == g == b)
{
- // So far so good
+ // So far so good
}
else
{
- // Image is color.
- return false;
+ // Image is color.
+ return false;
}
}
}
@@ -112,16 +107,14 @@ void ColorFilter::findCharColors()
Mat erodedCharMask(charMask.size(), CV_8U);
Mat element = getStructuringElement( 1,
- Size( 2 + 1, 2+1 ),
- Point( 1, 1 ) );
+ Size( 2 + 1, 2+1 ),
+ Point( 1, 1 ) );
erode(charMask, erodedCharMask, element);
vector > contours;
vector hierarchy;
findContours(erodedCharMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
-
-
vector hMeans, sMeans, vMeans;
vector hStdDevs, sStdDevs, vStdDevs;
@@ -130,50 +123,46 @@ void ColorFilter::findCharColors()
if (hierarchy[i][3] != -1)
continue;
- Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U);
+ Mat singleCharMask = Mat::zeros(hsv.size(), CV_8U);
- drawContours(singleCharMask, contours,
- i, // draw this contour
- cv::Scalar(255,255,255), // in
- CV_FILLED,
- 8,
- hierarchy
- );
+ drawContours(singleCharMask, contours,
+ i, // draw this contour
+ cv::Scalar(255,255,255), // in
+ CV_FILLED,
+ 8,
+ hierarchy
+ );
- // get rid of the outline by drawing a 1 pixel width black line
- drawContours(singleCharMask, contours,
- i, // draw this contour
- cv::Scalar(0,0,0), // in
- 1,
- 8,
- hierarchy
- );
+ // get rid of the outline by drawing a 1 pixel width black line
+ drawContours(singleCharMask, contours,
+ i, // draw this contour
+ cv::Scalar(0,0,0), // in
+ 1,
+ 8,
+ hierarchy
+ );
+ //drawAndWait(&singleCharMask);
+ Scalar mean;
+ Scalar stddev;
+ meanStdDev(hsv, mean, stddev, singleCharMask);
+ if (this->debug)
+ {
+ cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <debug)
- {
- cout << "ColorFilter " << setw(3) << i << ". Mean: h: " << setw(7) << mean[0] << " s: " << setw(7) <getMajorityOpinion(sMeans, .65, 35);
int bestValIndex = this->getMajorityOpinion(vMeans, .65, 30);
-
if (sMeans[bestSatIndex] < MINIMUM_SATURATION)
return;
-
bool doHueFilter = false, doSatFilter = false, doValFilter = false;
float hueMin, hueMax;
float satMin, satMax;
@@ -259,8 +246,6 @@ void ColorFilter::findCharColors()
cout << "ColorFilter Val: " << bestValIndex << " : " << setw(7) << vMeans[bestValIndex] << " -- " << valMin << "-" << valMax << endl;
}
-
-
Mat imgDebugHueOnly = Mat::zeros(hsv.size(), hsv.type());
Mat imgDebug = Mat::zeros(hsv.size(), hsv.type());
Mat imgDistanceFromCenter = Mat::zeros(hsv.size(), CV_8U);
@@ -291,19 +276,19 @@ void ColorFilter::findCharColors()
if (doHueFilter && (h < hueMin || h > hueMax))
{
- hPasses = false;
- imgDebug.at(row, col)[0] = 0;
- debugMask.at(row, col) = 0;
+ hPasses = false;
+ imgDebug.at(row, col)[0] = 0;
+ debugMask.at(row, col) = 0;
}
if (doSatFilter && (s < satMin || s > satMax))
{
- sPasses = false;
- imgDebug.at(row, col)[1] = 0;
+ sPasses = false;
+ imgDebug.at(row, col)[1] = 0;
}
if (doValFilter && (v < valMin || v > valMax))
{
- vPasses = false;
- imgDebug.at(row, col)[2] = 0;
+ vPasses = false;
+ imgDebug.at(row, col)[2] = 0;
}
//if (pixelPasses)
@@ -314,27 +299,24 @@ void ColorFilter::findCharColors()
//imgDebug.at(row, col)[2] = vPasses & 255;
if ((hPasses) || (hPasses && sPasses))//(hPasses && vPasses) || (sPasses && vPasses) ||
- this->colorMask.at(row, col) = 255;
+ this->colorMask.at(row, col) = 255;
else
- this->colorMask.at(row, col) = 0;
-
+ this->colorMask.at