diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index 5c405a7..51d5dfa 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -26,8 +26,17 @@ AlprImpl::AlprImpl(const std::string country, const std::string runtimeDir) { config = new Config(country, runtimeDir); plateDetector = new RegionDetector(config); - stateIdentifier = new StateIdentifier(config); - ocr = new OCR(config); + + int numThreads = getNumThreads(); + + for (int i = 0; i < numThreads; i++) + { + StateIdentifier* stateIdentifier = new StateIdentifier(config); + OCR* ocr = new OCR(config); + + stateIdentifiers.push_back(stateIdentifier); + ocrs.push_back(ocr); + } setNumThreads(0); @@ -68,10 +77,28 @@ AlprImpl::~AlprImpl() { delete config; delete plateDetector; - delete stateIdentifier; - delete ocr; + + for (int i = 0; i < stateIdentifiers.size(); i++) + { + delete stateIdentifiers[i]; + delete ocrs[i]; + } + + stateIdentifiers.clear(); + ocrs.clear(); } +int AlprImpl::getNumThreads() +{ + // Get the number of threads specified and make sure the value is sane (cannot be greater than CPU cores or less than 1) + int numThreads = config->multithreading_cores; + if (numThreads > tthread::thread::hardware_concurrency()) + numThreads = tthread::thread::hardware_concurrency(); + if (numThreads <= 0) + numThreads = 1; + + return numThreads; +} std::vector AlprImpl::recognize(cv::Mat img) { @@ -83,15 +110,11 @@ std::vector AlprImpl::recognize(cv::Mat img) vector plateRegions = plateDetector->detect(img); // Get the number of threads specified and make sure the value is sane (cannot be greater than CPU cores or less than 1) - int numThreads = config->multithreading_cores; - if (numThreads > tthread::thread::hardware_concurrency()) - numThreads = tthread::thread::hardware_concurrency(); - if (numThreads <= 0) - numThreads = 1; + int numThreads = getNumThreads(); PlateDispatcher dispatcher(plateRegions, &img, - config, stateIdentifier, ocr, + config, stateIdentifiers, ocrs, topN, detectRegion, defaultRegion); // Spawn n threads to process all of the candidate regions and recognize @@ -141,13 +164,28 @@ std::vector AlprImpl::recognize(cv::Mat img) void plateAnalysisThread(void* arg) { PlateDispatcher* dispatcher = (PlateDispatcher*) arg; + + timespec syncstarttime; + getTime(&syncstarttime); + + int threadID = dispatcher->getUniqueThreadId(); + Mat img = dispatcher->getImageCopy(); + if (dispatcher->config->debugGeneral) cout << "Thread: " << tthread::this_thread::get_id() << " Initialized" << endl; + + if (dispatcher->config->debugTiming) + { + timespec syncendtime; + getTime(&syncendtime); + cout << "Thread: " << tthread::this_thread::get_id() << " Synchronized initialization time in " << diffclock(syncstarttime, syncendtime) << "ms." << endl; + } int loop_count = 0; while (true) { + if (dispatcher->hasPlate() == false) break; @@ -158,7 +196,7 @@ void plateAnalysisThread(void* arg) // Get a single plate region from the queue Rect plateRegion = dispatcher->nextPlate(); - Mat img = dispatcher->getImageCopy(); + // Parallel section @@ -166,6 +204,9 @@ void plateAnalysisThread(void* arg) timespec platestarttime; getTime(&platestarttime); + StateIdentifier* stateIdentifier = dispatcher->stateIdentifiers[threadID]; + OCR* ocr = dispatcher->ocrs[threadID]; + LicensePlateCandidate lp(img, plateRegion, dispatcher->config); lp.recognize(); @@ -186,7 +227,7 @@ void plateAnalysisThread(void* arg) if (dispatcher->detectRegion) { char statecode[4]; - plateResult.regionConfidence = dispatcher->stateIdentifier->recognize(img, plateRegion, statecode); + plateResult.regionConfidence = stateIdentifier->recognize(img, plateRegion, statecode); if (plateResult.regionConfidence > 0) { plateResult.region = statecode; @@ -194,12 +235,12 @@ void plateAnalysisThread(void* arg) } - dispatcher->ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); + ocr->performOCR(lp.charSegmenter->getThresholds(), lp.charSegmenter->characters); - dispatcher->ocr->postProcessor->analyze(plateResult.region, dispatcher->topN); + ocr->postProcessor->analyze(plateResult.region, dispatcher->topN); //plateResult.characters = ocr->postProcessor->bestChars; - const vector ppResults = dispatcher->ocr->postProcessor->getResults(); + const vector ppResults = ocr->postProcessor->getResults(); int bestPlateIndex = 0; diff --git a/src/openalpr/alpr_impl.h b/src/openalpr/alpr_impl.h index 8fed548..5915736 100644 --- a/src/openalpr/alpr_impl.h +++ b/src/openalpr/alpr_impl.h @@ -63,15 +63,17 @@ class AlprImpl private: + int getNumThreads(); + cJSON* createJsonObj(const AlprResult* result); + RegionDetector* plateDetector; - StateIdentifier* stateIdentifier; - OCR* ocr; + vector stateIdentifiers; + vector ocrs; int topN; bool detectRegion; std::string defaultRegion; - cJSON* createJsonObj(const AlprResult* result); }; @@ -81,19 +83,21 @@ class PlateDispatcher public: PlateDispatcher(vector plateRegions, cv::Mat* image, Config* config, - StateIdentifier* stateIdentifier, - OCR* ocr, + vector stateIdentifiers, + vector ocrs, int topN, bool detectRegion, std::string defaultRegion) { this->plateRegions = plateRegions; this->frame = image; this->config = config; - this->stateIdentifier = stateIdentifier; - this->ocr = ocr; + this->stateIdentifiers = stateIdentifiers; + this->ocrs = ocrs; this->topN = topN; this->detectRegion = detectRegion; this->defaultRegion = defaultRegion; + + this->threadCounter = 0; } cv::Mat getImageCopy() @@ -105,6 +109,13 @@ class PlateDispatcher return img; } + + int getUniqueThreadId() + { + tthread::lock_guard guard(mMutex); + + return threadCounter++; + } bool hasPlate() { @@ -136,8 +147,8 @@ class PlateDispatcher } - StateIdentifier* stateIdentifier; - OCR* ocr; + vector stateIdentifiers; + vector ocrs; Config* config; int topN; @@ -146,6 +157,7 @@ class PlateDispatcher private: + int threadCounter; tthread::mutex mMutex; cv::Mat* frame; vector plateRegions;