diff --git a/config/openalpr.conf b/config/openalpr.conf index 17b6af9..bc374b7 100644 --- a/config/openalpr.conf +++ b/config/openalpr.conf @@ -31,8 +31,6 @@ detection_strictness = 3 max_detection_input_width = 1280 max_detection_input_height = 720 -multithreading_cores = 1 - max_plate_angle_degrees = 15 diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index a95d7e7..fce858a 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -102,34 +102,107 @@ AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img, std::vectordetect(img, regionsOfInterest); - // Get the number of threads specified and make sure the value is sane (cannot be greater than CPU cores or less than 1) - uint numThreads = config->multithreading_cores; - if (numThreads > tthread::thread::hardware_concurrency()) - numThreads = tthread::thread::hardware_concurrency(); - if (numThreads <= 0) - numThreads = 1; - - - PlateDispatcher dispatcher(response.plateRegions, &img, - config, stateIdentifier, ocr, - topN, detectRegion, defaultRegion); - - // Spawn n threads to process all of the candidate regions and recognize - list threads; - for (uint i = 0; i < numThreads; i++) - { - tthread::thread * t = new tthread::thread(plateAnalysisThread, (void *) &dispatcher); - threads.push_back(t); - } + queue plateQueue; + for (uint i = 0; i < response.plateRegions.size(); i++) + plateQueue.push(response.plateRegions[i]); - // Wait for all threads to finish - for(list::iterator i = threads.begin(); i != threads.end(); ++ i) + while(!plateQueue.empty()) { - tthread::thread* t = *i; - t->join(); - delete t; + PlateRegion plateRegion = plateQueue.front(); + plateQueue.pop(); + + PipelineData pipeline_data(img, plateRegion.rect, config); + + timespec platestarttime; + getTime(&platestarttime); + + LicensePlateCandidate lp(&pipeline_data); + + lp.recognize(); + + bool plateDetected = false; + if (pipeline_data.plate_area_confidence > 10) + { + AlprResult plateResult; + plateResult.region = defaultRegion; + plateResult.regionConfidence = 0; + + for (int pointidx = 0; pointidx < 4; pointidx++) + { + plateResult.plate_points[pointidx].x = (int) pipeline_data.plate_corners[pointidx].x; + plateResult.plate_points[pointidx].y = (int) pipeline_data.plate_corners[pointidx].y; + } + + if (detectRegion) + { + char statecode[4]; + plateResult.regionConfidence = stateIdentifier->recognize(&pipeline_data); + if (plateResult.regionConfidence > 0) + { + plateResult.region = statecode; + } + } + + + + ocr->performOCR(&pipeline_data); + ocr->postProcessor->analyze(plateResult.region, topN); + const vector ppResults = ocr->postProcessor->getResults(); + + + int bestPlateIndex = 0; + + for (uint 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) + { + plateDetected = true; + response.results.push_back(plateResult); + } + } + + if (!plateDetected) + { + // Not a valid plate + // Check if this plate has any children, if so, send them back up for processing + for (uint childidx = 0; childidx < plateRegion.children.size(); childidx++) + { + plateQueue.push(plateRegion.children[childidx]); + } + } + + + + } + if (config->debugTiming) { timespec endTime; @@ -144,11 +217,11 @@ AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img, std::vectordebugPauseOnFrame) { // Pause indefinitely until they press a key @@ -197,126 +268,7 @@ std::vector AlprImpl::recognize(cv::Mat img, std::vector r AlprFullDetails fullDetails = recognizeFullDetails(img, regionsOfInterest); return fullDetails.results; } -void plateAnalysisThread(void* arg) -{ - PlateDispatcher* dispatcher = (PlateDispatcher*) arg; - - if (dispatcher->config->debugGeneral) - cout << "Thread: " << tthread::this_thread::get_id() << " Initialized" << endl; - - int loop_count = 0; - while (true) - { - PlateRegion plateRegion; - if (dispatcher->nextPlate(&plateRegion) == false) - break; - - if (dispatcher->config->debugGeneral) - cout << "Thread: " << tthread::this_thread::get_id() << " loop " << ++loop_count << endl; - - PipelineData pipeline_data(dispatcher->getImageCopy(), plateRegion.rect, dispatcher->config); - - timespec platestarttime; - getTime(&platestarttime); - - LicensePlateCandidate lp(&pipeline_data); - - lp.recognize(); - - if (pipeline_data.plate_area_confidence <= 10) - { - // Not a valid plate - // Check if this plate has any children, if so, send them back up to the dispatcher for processing - for (uint childidx = 0; childidx < plateRegion.children.size(); childidx++) - { - dispatcher->appendPlate(plateRegion.children[childidx]); - } - } - else - { - AlprResult plateResult; - plateResult.region = dispatcher->defaultRegion; - plateResult.regionConfidence = 0; - - for (int pointidx = 0; pointidx < 4; pointidx++) - { - plateResult.plate_points[pointidx].x = (int) pipeline_data.plate_corners[pointidx].x; - plateResult.plate_points[pointidx].y = (int) pipeline_data.plate_corners[pointidx].y; - } - - if (dispatcher->detectRegion) - { - char statecode[4]; - plateResult.regionConfidence = dispatcher->stateIdentifier->recognize(&pipeline_data); - if (plateResult.regionConfidence > 0) - { - plateResult.region = statecode; - } - } - - - // Tesseract OCR does not appear to be threadsafe - dispatcher->ocrMutex.lock(); - dispatcher->ocr->performOCR(&pipeline_data); - dispatcher->ocr->postProcessor->analyze(plateResult.region, dispatcher->topN); - const vector ppResults = dispatcher->ocr->postProcessor->getResults(); - dispatcher->ocrMutex.unlock(); - - int bestPlateIndex = 0; - - for (uint pp = 0; pp < ppResults.size(); pp++) - { - if (pp >= dispatcher->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() >= dispatcher->config->postProcessMinCharacters && - ppResults[pp].letters.size() <= dispatcher->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) - { - // Synchronized section - dispatcher->addResult(plateResult); - - } - - } - - - - if (dispatcher->config->debugTiming) - { - timespec plateEndTime; - getTime(&plateEndTime); - cout << "Thread: " << tthread::this_thread::get_id() << " Finished loop " << loop_count << " in " << diffclock(platestarttime, plateEndTime) << "ms." << endl; - } - - - } - - if (dispatcher->config->debugGeneral) - cout << "Thread: " << tthread::this_thread::get_id() << " Complete" << endl; -} std::vector AlprImpl::convertRects(std::vector regionsOfInterest) { diff --git a/src/openalpr/alpr_impl.h b/src/openalpr/alpr_impl.h index 4c72162..2b518be 100644 --- a/src/openalpr/alpr_impl.h +++ b/src/openalpr/alpr_impl.h @@ -23,6 +23,8 @@ #include #include +#include +#include #include "alpr.h" #include "config.h" @@ -43,8 +45,6 @@ #include - -#include "support/tinythread.h" #include "support/platform.h" #define DEFAULT_TOPN 25 @@ -101,86 +101,6 @@ class AlprImpl cJSON* createJsonObj(const AlprResult* result); }; -class PlateDispatcher -{ - public: - PlateDispatcher(std::vector plateRegions, cv::Mat* image, - Config* config, - StateIdentifier* stateIdentifier, - OCR* ocr, - int topN, bool detectRegion, std::string defaultRegion) - { - this->plateRegions = plateRegions; - this->frame = image; - - this->config = config; - this->stateIdentifier = stateIdentifier; - this->ocr = ocr; - this->topN = topN; - this->detectRegion = detectRegion; - this->defaultRegion = defaultRegion; - } - cv::Mat getImageCopy() - { - tthread::lock_guard guard(mMutex); - - cv::Mat img(this->frame->size(), this->frame->type()); - this->frame->copyTo(img); - - return img; - } - - - bool nextPlate(PlateRegion* plateRegion) - { - tthread::lock_guard guard(mMutex); - - if (plateRegions.size() == 0) - return false; - - *plateRegion = plateRegions[plateRegions.size() - 1]; - plateRegions.pop_back(); - - return true; - } - - void appendPlate(PlateRegion plate) - { - tthread::lock_guard guard(mMutex); - - plateRegions.push_back(plate); - } - - void addResult(AlprResult recognitionResult) - { - tthread::lock_guard guard(mMutex); - recognitionResults.push_back(recognitionResult); - } - - std::vector getRecognitionResults() - { - return recognitionResults; - } - - StateIdentifier* stateIdentifier; - OCR* ocr; - Config* config; - - uint topN; - bool detectRegion; - std::string defaultRegion; - - tthread::mutex ocrMutex; - - private: - - tthread::mutex mMutex; - - cv::Mat* frame; - std::vector plateRegions; - std::vector recognitionResults; - -}; #endif // OPENALPR_ALPRIMPL_H \ No newline at end of file diff --git a/src/openalpr/config.cpp b/src/openalpr/config.cpp index 5ade5d2..58e5433 100644 --- a/src/openalpr/config.cpp +++ b/src/openalpr/config.cpp @@ -127,8 +127,6 @@ void Config::loadValues(string country) runtimeBaseDir = getString("common", "runtime_dir", "/usr/share/openalpr/runtime_data"); - multithreading_cores = getInt("common", "multithreading_cores", 1); - detection_iteration_increase = getFloat("common", "detection_iteration_increase", 1.1); detectionStrictness = getInt("common", "detection_strictness", 3); maxPlateWidthPercent = getFloat("common", "max_plate_width_percent", 100); diff --git a/src/openalpr/config.h b/src/openalpr/config.h index 3e0057e..402f5e6 100644 --- a/src/openalpr/config.h +++ b/src/openalpr/config.h @@ -45,8 +45,6 @@ class Config std::string country; - int multithreading_cores; - float detection_iteration_increase; int detectionStrictness; float maxPlateWidthPercent;