diff --git a/src/daemon.cpp b/src/daemon.cpp index 9256945..cd6e189 100644 --- a/src/daemon.cpp +++ b/src/daemon.cpp @@ -243,7 +243,8 @@ void streamRecognitionThread(void* arg) while (daemon_active) { - int response = videoBuffer.getLatestFrame(&latestFrame); + std::vector regionsOfInterest; + int response = videoBuffer.getLatestFrame(&latestFrame, regionsOfInterest); if (response != -1) { diff --git a/src/main.cpp b/src/main.cpp index 64d9d03..56dd67f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -170,7 +170,8 @@ int main( int argc, const char** argv ) while (program_active) { - int response = videoBuffer.getLatestFrame(&latestFrame); + std::vector regionsOfInterest; + int response = videoBuffer.getLatestFrame(&latestFrame, regionsOfInterest); if (response != -1) { diff --git a/src/openalpr/alpr.cpp b/src/openalpr/alpr.cpp index cc31091..03c8f09 100644 --- a/src/openalpr/alpr.cpp +++ b/src/openalpr/alpr.cpp @@ -34,16 +34,24 @@ Alpr::~Alpr() std::vector Alpr::recognize(std::string filepath) { - cv::Mat img = cv::imread(filepath, CV_LOAD_IMAGE_COLOR); - return impl->recognize(img); + std::vector regionsOfInterest; + return this->recognize(filepath, regionsOfInterest); +} + +std::vector Alpr::recognize(std::string filepath, std::vector regionsOfInterest) +{ + return impl->recognize(filepath, regionsOfInterest); } std::vector Alpr::recognize(std::vector imageBuffer) { - // Not sure if this actually works - cv::Mat img = cv::imdecode(cv::Mat(imageBuffer), 1); + std::vector regionsOfInterest; + return this->recognize(imageBuffer, regionsOfInterest); +} - return impl->recognize(img); +std::vector Alpr::recognize(std::vector imageBuffer, std::vector regionsOfInterest) +{ + return impl->recognize(imageBuffer, regionsOfInterest); } std::string Alpr::toJson(const std::vector< AlprResult > results, double processing_time_ms) diff --git a/src/openalpr/alpr.h b/src/openalpr/alpr.h index ef98290..a590644 100644 --- a/src/openalpr/alpr.h +++ b/src/openalpr/alpr.h @@ -39,6 +39,14 @@ struct AlprCoordinate int y; }; +struct AlprRegionOfInterest +{ + int x; + int y; + int width; + int height; +}; + class AlprResult { public: @@ -71,7 +79,9 @@ class Alpr void setDefaultRegion(std::string region); std::vector recognize(std::string filepath); + std::vector recognize(std::string filepath, std::vector regionsOfInterest); std::vector recognize(std::vector imageBuffer); + std::vector recognize(std::vector imageBuffer, std::vector regionsOfInterest); std::string toJson(const std::vector results, double processing_time_ms = -1); diff --git a/src/openalpr/alpr_impl.cpp b/src/openalpr/alpr_impl.cpp index e04b26f..1e5be05 100644 --- a/src/openalpr/alpr_impl.cpp +++ b/src/openalpr/alpr_impl.cpp @@ -67,10 +67,21 @@ bool AlprImpl::isLoaded() } AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img) +{ + std::vector regionsOfInterest; + regionsOfInterest.push_back(cv::Rect(0, 0, img.cols, img.rows)); + + return this->recognizeFullDetails(img, regionsOfInterest); +} + +AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img, std::vector regionsOfInterest) { timespec startTime; getTime(&startTime); + if (regionsOfInterest.size() == 0) + regionsOfInterest.push_back(cv::Rect(0, 0, img.cols, img.rows)); + AlprFullDetails response; if (!img.data) @@ -89,7 +100,7 @@ AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img) } // Find all the candidate regions - response.plateRegions = plateDetector->detect(img); + response.plateRegions = plateDetector->detect(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) int numThreads = config->multithreading_cores; @@ -165,12 +176,27 @@ AlprFullDetails AlprImpl::recognizeFullDetails(cv::Mat img) return response; } -std::vector AlprImpl::recognize(cv::Mat img) + +std::vector AlprImpl::recognize(std::string filepath, std::vector regionsOfInterest) { - AlprFullDetails fullDetails = recognizeFullDetails(img); - return fullDetails.results; + cv::Mat img = cv::imread(filepath, CV_LOAD_IMAGE_COLOR); + + return this->recognize(img, this->convertRects(regionsOfInterest)); } +std::vector AlprImpl::recognize(std::vector imageBuffer, std::vector regionsOfInterest) +{ + cv::Mat img = cv::imdecode(cv::Mat(imageBuffer), 1); + + return this->recognize(img, this->convertRects(regionsOfInterest)); +} + +std::vector AlprImpl::recognize(cv::Mat img, std::vector regionsOfInterest) +{ + + AlprFullDetails fullDetails = recognizeFullDetails(img, regionsOfInterest); + return fullDetails.results; +} void plateAnalysisThread(void* arg) { PlateDispatcher* dispatcher = (PlateDispatcher*) arg; @@ -292,6 +318,17 @@ void plateAnalysisThread(void* arg) cout << "Thread: " << tthread::this_thread::get_id() << " Complete" << endl; } + std::vector AlprImpl::convertRects(std::vector regionsOfInterest) + { + std::vector rectRegions; + for (int i = 0; i < regionsOfInterest.size(); i++) + { + rectRegions.push_back(cv::Rect(regionsOfInterest[i].x, regionsOfInterest[i].y, regionsOfInterest[i].width, regionsOfInterest[i].height)); + } + + return rectRegions; + } + string AlprImpl::toJson(const vector< AlprResult > results, double processing_time_ms) { cJSON *root, *jsonResults; diff --git a/src/openalpr/alpr_impl.h b/src/openalpr/alpr_impl.h index 7263812..78acf0a 100644 --- a/src/openalpr/alpr_impl.h +++ b/src/openalpr/alpr_impl.h @@ -64,7 +64,11 @@ class AlprImpl virtual ~AlprImpl(); AlprFullDetails recognizeFullDetails(cv::Mat img); - std::vector recognize(cv::Mat img); + AlprFullDetails recognizeFullDetails(cv::Mat img, std::vector regionsOfInterest); + + std::vector recognize(std::string filepath, std::vector regionsOfInterest); + std::vector recognize(std::vector imageBuffer, std::vector regionsOfInterest); + std::vector recognize(cv::Mat img, std::vector regionsOfInterest); void applyRegionTemplate(AlprResult* result, std::string region); @@ -89,6 +93,8 @@ class AlprImpl bool detectRegion; std::string defaultRegion; + std::vector convertRects(std::vector regionsOfInterest); + cJSON* createJsonObj(const AlprResult* result); }; diff --git a/src/openalpr/regiondetector.cpp b/src/openalpr/regiondetector.cpp index 4d63077..79e3de6 100644 --- a/src/openalpr/regiondetector.cpp +++ b/src/openalpr/regiondetector.cpp @@ -53,19 +53,18 @@ bool RegionDetector::isLoaded() return this->loaded; } -vector RegionDetector::detect(Mat frame) +vector RegionDetector::detect(Mat frame, std::vector regionsOfInterest) { Mat frame_gray; cvtColor( frame, frame_gray, CV_BGR2GRAY ); - vector regionsOfInterest = doCascade(frame_gray); + vector detectedRegions = doCascade(frame_gray, regionsOfInterest); - return regionsOfInterest; + return detectedRegions; } -/** @function detectAndDisplay */ -vector RegionDetector::doCascade(Mat frame) +vector RegionDetector::doCascade(Mat frame, std::vector regionsOfInterest) { diff --git a/src/openalpr/regiondetector.h b/src/openalpr/regiondetector.h index 4698738..d279295 100644 --- a/src/openalpr/regiondetector.h +++ b/src/openalpr/regiondetector.h @@ -46,7 +46,7 @@ class RegionDetector virtual ~RegionDetector(); bool isLoaded(); - std::vector detect(cv::Mat frame); + std::vector detect(cv::Mat frame, std::vector regionsOfInterest); private: Config* config; @@ -56,7 +56,7 @@ class RegionDetector bool loaded; - std::vector doCascade(cv::Mat frame); + std::vector doCascade(cv::Mat frame, std::vector regionsOfInterest); std::vector aggregateRegions(std::vector regions); }; diff --git a/src/video/videobuffer.cpp b/src/video/videobuffer.cpp index a1fa33c..8d7be24 100644 --- a/src/video/videobuffer.cpp +++ b/src/video/videobuffer.cpp @@ -72,12 +72,12 @@ void VideoBuffer::connect(std::string mjpeg_url, int fps) } -int VideoBuffer::getLatestFrame(cv::Mat* frame) +int VideoBuffer::getLatestFrame(cv::Mat* frame, std::vector& regionsOfInterest) { if (dispatcher == NULL) return -1; - return dispatcher->getLatestFrame(frame); + return dispatcher->getLatestFrame(frame, regionsOfInterest); } diff --git a/src/video/videobuffer.h b/src/video/videobuffer.h index 3959261..5a28581 100644 --- a/src/video/videobuffer.h +++ b/src/video/videobuffer.h @@ -25,7 +25,7 @@ class VideoDispatcher } - int getLatestFrame(cv::Mat* frame) + int getLatestFrame(cv::Mat* frame, std::vector& regionsOfInterest) { tthread::lock_guard guard(mMutex); @@ -37,6 +37,10 @@ class VideoDispatcher this->lastFrameRead = this->latestFrameNumber; + // Copy the regionsOfInterest array + for (int i = 0; i < this->latestRegionsOfInterest.size(); i++) + regionsOfInterest.push_back(this->latestRegionsOfInterest[i]); + return this->lastFrameRead; } @@ -44,6 +48,7 @@ class VideoDispatcher { //tthread::lock_guard guard(mMutex); this->latestFrame = frame; + this->latestRegionsOfInterest = calculateRegionsOfInterest(frame); this->latestFrameNumber++; } @@ -57,6 +62,16 @@ class VideoDispatcher std::cerr << error << std::endl; } + std::vector calculateRegionsOfInterest(cv::Mat* frame) + { + cv::Rect rect(0, 0, frame->cols, frame->rows); + + std::vector rois; + rois.push_back(rect); + + return rois; + } + bool active; int latestFrameNumber; @@ -68,7 +83,7 @@ class VideoDispatcher private: cv::Mat* latestFrame; - + std::vector latestRegionsOfInterest; }; class VideoBuffer @@ -83,7 +98,8 @@ class VideoBuffer // If a new frame is available, the function sets "frame" to it and returns the frame number // If no frames are available, or the latest has already been grabbed, returns -1. - int getLatestFrame(cv::Mat* frame); + // regionsOfInterest is set to a list of good regions to check for license plates. Default is one rectangle for the entire frame. + int getLatestFrame(cv::Mat* frame, std::vector& regionsOfInterest); void disconnect();