mirror of
https://github.com/kerberos-io/openalpr-base.git
synced 2025-10-06 08:56:55 +08:00
Adding hierarchical plate regions. The goal is to minimize unnecessary processing of regions within regions
This commit is contained in:
@@ -150,7 +150,7 @@ int main( int argc, const char** argv )
|
||||
string fullpath = inDir + "/" + files[i];
|
||||
frame = imread( fullpath.c_str() );
|
||||
|
||||
vector<Rect> regions = plateDetector.detect(frame);
|
||||
vector<PlateRegion> regions = plateDetector.detect(frame);
|
||||
|
||||
imshow("Current LP", frame);
|
||||
waitKey(5);
|
||||
@@ -200,7 +200,7 @@ int main( int argc, const char** argv )
|
||||
endToEndTimes.push_back(endToEndTime);
|
||||
|
||||
getTime(&startTime);
|
||||
vector<Rect> regions = plateDetector.detect(frame);
|
||||
vector<PlateRegion> regions = plateDetector.detect(frame);
|
||||
getTime(&endTime);
|
||||
|
||||
double regionDetectionTime = diffclock(startTime, endTime);
|
||||
@@ -211,14 +211,14 @@ int main( int argc, const char** argv )
|
||||
{
|
||||
getTime(&startTime);
|
||||
char temp[5];
|
||||
stateIdentifier.recognize(frame, regions[z], temp);
|
||||
stateIdentifier.recognize(frame, regions[z].rect, 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);
|
||||
LicensePlateCandidate lp(frame, regions[z].rect, &config);
|
||||
lp.recognize();
|
||||
getTime(&endTime);
|
||||
double analysisTime = diffclock(startTime, endTime);
|
||||
|
@@ -79,7 +79,7 @@ std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
|
||||
|
||||
|
||||
// Find all the candidate regions
|
||||
vector<Rect> plateRegions = plateDetector->detect(img);
|
||||
vector<PlateRegion> 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;
|
||||
@@ -120,7 +120,7 @@ std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
|
||||
{
|
||||
for (int i = 0; i < plateRegions.size(); i++)
|
||||
{
|
||||
rectangle(img, plateRegions[i], Scalar(0, 0, 255), 2);
|
||||
rectangle(img, plateRegions[i].rect, Scalar(0, 0, 255), 2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < dispatcher.getRecognitionResults().size(); i++)
|
||||
@@ -137,8 +137,9 @@ std::vector<AlprResult> AlprImpl::recognize(cv::Mat img)
|
||||
|
||||
displayImage(config, "Main Image", img);
|
||||
// Pause indefinitely until they press a key
|
||||
while ((char) cv::waitKey(50) == -1)
|
||||
{}
|
||||
cv::waitKey(1);
|
||||
//while ((char) cv::waitKey(50) == -1)
|
||||
// {}
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +164,7 @@ void plateAnalysisThread(void* arg)
|
||||
cout << "Thread: " << tthread::this_thread::get_id() << " loop " << ++loop_count << endl;
|
||||
|
||||
// Get a single plate region from the queue
|
||||
Rect plateRegion = dispatcher->nextPlate();
|
||||
PlateRegion plateRegion = dispatcher->nextPlate();
|
||||
|
||||
Mat img = dispatcher->getImageCopy();
|
||||
|
||||
@@ -172,7 +173,7 @@ void plateAnalysisThread(void* arg)
|
||||
timespec platestarttime;
|
||||
getTime(&platestarttime);
|
||||
|
||||
LicensePlateCandidate lp(img, plateRegion, dispatcher->config);
|
||||
LicensePlateCandidate lp(img, plateRegion.rect, dispatcher->config);
|
||||
|
||||
lp.recognize();
|
||||
|
||||
@@ -192,7 +193,7 @@ void plateAnalysisThread(void* arg)
|
||||
if (dispatcher->detectRegion)
|
||||
{
|
||||
char statecode[4];
|
||||
plateResult.regionConfidence = dispatcher->stateIdentifier->recognize(img, plateRegion, statecode);
|
||||
plateResult.regionConfidence = dispatcher->stateIdentifier->recognize(img, plateRegion.rect, statecode);
|
||||
if (plateResult.regionConfidence > 0)
|
||||
{
|
||||
plateResult.region = statecode;
|
||||
|
@@ -78,7 +78,7 @@ class AlprImpl
|
||||
class PlateDispatcher
|
||||
{
|
||||
public:
|
||||
PlateDispatcher(vector<Rect> plateRegions, cv::Mat* image,
|
||||
PlateDispatcher(vector<PlateRegion> plateRegions, cv::Mat* image,
|
||||
Config* config,
|
||||
StateIdentifier* stateIdentifier,
|
||||
OCR* ocr,
|
||||
@@ -113,11 +113,11 @@ class PlateDispatcher
|
||||
mMutex.unlock();
|
||||
return plateAvailable;
|
||||
}
|
||||
Rect nextPlate()
|
||||
PlateRegion nextPlate()
|
||||
{
|
||||
tthread::lock_guard<tthread::mutex> guard(mMutex);
|
||||
|
||||
Rect plateRegion = plateRegions[plateRegions.size() - 1];
|
||||
PlateRegion plateRegion = plateRegions[plateRegions.size() - 1];
|
||||
plateRegions.pop_back();
|
||||
|
||||
return plateRegion;
|
||||
@@ -147,7 +147,7 @@ class PlateDispatcher
|
||||
|
||||
tthread::mutex mMutex;
|
||||
cv::Mat* frame;
|
||||
vector<Rect> plateRegions;
|
||||
vector<PlateRegion> plateRegions;
|
||||
vector<AlprResult> recognitionResults;
|
||||
|
||||
};
|
||||
|
@@ -57,19 +57,19 @@ bool RegionDetector::isLoaded()
|
||||
return this->loaded;
|
||||
}
|
||||
|
||||
vector<Rect> RegionDetector::detect(Mat frame)
|
||||
vector<PlateRegion> RegionDetector::detect(Mat frame)
|
||||
{
|
||||
|
||||
Mat frame_gray;
|
||||
cvtColor( frame, frame_gray, CV_BGR2GRAY );
|
||||
|
||||
vector<Rect> regionsOfInterest = doCascade(frame_gray);
|
||||
vector<PlateRegion> regionsOfInterest = doCascade(frame_gray);
|
||||
|
||||
return regionsOfInterest;
|
||||
}
|
||||
|
||||
/** @function detectAndDisplay */
|
||||
vector<Rect> RegionDetector::doCascade(Mat frame)
|
||||
vector<PlateRegion> RegionDetector::doCascade(Mat frame)
|
||||
{
|
||||
//float scale_factor = 1;
|
||||
int w = frame.size().width;
|
||||
@@ -116,6 +116,28 @@ vector<Rect> RegionDetector::doCascade(Mat frame)
|
||||
plates[i].height = plates[i].height / scale_factor;
|
||||
}
|
||||
|
||||
return plates;
|
||||
vector<PlateRegion> orderedRegions = aggregateRegions(plates);
|
||||
|
||||
return orderedRegions;
|
||||
|
||||
}
|
||||
|
||||
vector<PlateRegion> RegionDetector::aggregateRegions(vector<Rect> regions)
|
||||
{
|
||||
// Combines overlapping regions into a parent->child order.
|
||||
// The largest regions will be parents, and they will have children if they are within them.
|
||||
// This way, when processing regions later, we can process the parents first, and only delve into the children
|
||||
// If there was no plate match. Otherwise, we would process everything and that would be wasteful.
|
||||
|
||||
vector<PlateRegion> orderedRegions;
|
||||
|
||||
// For now, just return a full list with no children, so I can get the plumbing sorted.
|
||||
for (int i = 0; i < regions.size(); i++)
|
||||
{
|
||||
PlateRegion newRegion;
|
||||
newRegion.rect = regions[i];
|
||||
orderedRegions.push_back(newRegion);
|
||||
}
|
||||
|
||||
return orderedRegions;
|
||||
}
|
||||
|
@@ -33,6 +33,12 @@
|
||||
#include "support/timing.h"
|
||||
#include "constants.h"
|
||||
|
||||
struct PlateRegion
|
||||
{
|
||||
Rect rect;
|
||||
vector<PlateRegion> children;
|
||||
};
|
||||
|
||||
class RegionDetector
|
||||
{
|
||||
|
||||
@@ -41,7 +47,7 @@ class RegionDetector
|
||||
virtual ~RegionDetector();
|
||||
|
||||
bool isLoaded();
|
||||
vector<Rect> detect(Mat frame);
|
||||
vector<PlateRegion> detect(Mat frame);
|
||||
|
||||
private:
|
||||
Config* config;
|
||||
@@ -51,8 +57,9 @@ class RegionDetector
|
||||
|
||||
bool loaded;
|
||||
|
||||
vector<Rect> doCascade(Mat frame);
|
||||
vector<PlateRegion> doCascade(Mat frame);
|
||||
|
||||
vector<PlateRegion> aggregateRegions(vector<Rect> regions);
|
||||
};
|
||||
|
||||
#endif // REGIONDETECTOR_H
|
||||
|
Reference in New Issue
Block a user