From 742556cc3710dcd5cba5dea57a606b511c6017df Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Mon, 17 Feb 2014 13:21:47 -0700 Subject: [PATCH 1/5] Fixed clock timing on Windows. Previously, clock timing was mocked out to 0. This fixes it and gives correct timings in ms for plate recognitions --- src/openalpr/support/timing.cpp | 88 +++++++++++++++++++++++++++++---- src/openalpr/support/timing.h | 11 ++++- 2 files changed, 87 insertions(+), 12 deletions(-) diff --git a/src/openalpr/support/timing.cpp b/src/openalpr/support/timing.cpp index 0b66891..5b259f8 100644 --- a/src/openalpr/support/timing.cpp +++ b/src/openalpr/support/timing.cpp @@ -1,35 +1,103 @@ #include "timing.h" -#ifdef __MACH__ -#include -#include -#endif #ifdef WINDOWS timespec diff(timespec start, timespec end); + +// Windows timing code +LARGE_INTEGER getFILETIMEoffset() +{ + SYSTEMTIME s; + FILETIME f; + LARGE_INTEGER t; + + s.wYear = 1970; + s.wMonth = 1; + s.wDay = 1; + s.wHour = 0; + s.wMinute = 0; + s.wSecond = 0; + s.wMilliseconds = 0; + SystemTimeToFileTime(&s, &f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + return (t); +} + +int clock_gettime(int X, timespec *tv) +{ + LARGE_INTEGER t; + FILETIME f; + double microseconds; + static LARGE_INTEGER offset; + static double frequencyToMicroseconds; + static int initialized = 0; + static BOOL usePerformanceCounter = 0; + + if (!initialized) { + LARGE_INTEGER performanceFrequency; + initialized = 1; + usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); + if (usePerformanceCounter) { + QueryPerformanceCounter(&offset); + frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; + } else { + offset = getFILETIMEoffset(); + frequencyToMicroseconds = 10.; + } + } + if (usePerformanceCounter) QueryPerformanceCounter(&t); + else { + GetSystemTimeAsFileTime(&f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + } + + t.QuadPart -= offset.QuadPart; + microseconds = (double)t.QuadPart / frequencyToMicroseconds; + t.QuadPart = microseconds; + tv->tv_sec = t.QuadPart / 1000000; + tv->tv_usec = t.QuadPart % 1000000; + return (0); +} + + + void getTime(timespec* time) { - // Do nothing on Windows + clock_gettime(0, time); + } double diffclock(timespec time1,timespec time2) { - // Mock this out for Windows - return 0; + timespec delta = diff(time1,time2); + double milliseconds = (delta.tv_sec * 1000) + (((double) delta.tv_usec) / 1000.0); + + + return milliseconds; } timespec diff(timespec start, timespec end) { - // Mock this out for Windows - return 0; + timespec temp; + if ((end.tv_usec-start.tv_usec)<0) { + temp.tv_sec = end.tv_sec-start.tv_sec-1; + temp.tv_usec = 1000000+end.tv_usec-start.tv_usec; + } else { + temp.tv_sec = end.tv_sec-start.tv_sec; + temp.tv_usec = end.tv_usec-start.tv_usec; + } + return temp; } #else -timespec diff(timespec start, timespec end); void getTime(timespec* time) { diff --git a/src/openalpr/support/timing.h b/src/openalpr/support/timing.h index e7cabb3..66763f7 100644 --- a/src/openalpr/support/timing.h +++ b/src/openalpr/support/timing.h @@ -3,10 +3,17 @@ #include +// Support for OS X +#ifdef __MACH__ +#include +#include +#endif +// Support for Windows #ifdef WINDOWS - // Mock this out for Windows - #define timespec int + #include + + #define timespec timeval #endif void getTime(timespec* time); From 3bc2d43929c36a239332e13061a20f4a009d41fa Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Mon, 17 Feb 2014 14:55:41 -0600 Subject: [PATCH 2/5] Moved timing prototype definition out of Windows only code block --- src/openalpr/support/timing.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/openalpr/support/timing.cpp b/src/openalpr/support/timing.cpp index 5b259f8..7e31290 100644 --- a/src/openalpr/support/timing.cpp +++ b/src/openalpr/support/timing.cpp @@ -1,12 +1,11 @@ #include "timing.h" -#ifdef WINDOWS - - timespec diff(timespec start, timespec end); +#ifdef WINDOWS + // Windows timing code LARGE_INTEGER getFILETIMEoffset() { From a07991adb62238090bb7ccee1252274c5562fd12 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Mon, 17 Feb 2014 14:57:14 -0600 Subject: [PATCH 3/5] Added error message when input image/video file is not found --- src/main.cpp | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0386964..8375f26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -139,32 +140,46 @@ } else if (hasEnding(filename, ".avi") || hasEnding(filename, ".mp4") || hasEnding(filename, ".webm") || hasEnding(filename, ".flv")) { - int framenum = 0; - - cv::VideoCapture cap=cv::VideoCapture(); - cap.open(filename); - cap.set(CV_CAP_PROP_POS_MSEC, seektoms); - - while (cap.read(frame) == true) + if (fileExists(filename.c_str())) { - if (SAVE_LAST_VIDEO_STILL == true) - { - cv::imwrite(LAST_VIDEO_STILL_LOCATION, frame); - } - std::cout << "Frame: " << framenum << std::endl; + int framenum = 0; - detectandshow( &alpr, frame, "", outputJson); - //create a 1ms delay - cv::waitKey(1); - framenum++; + cv::VideoCapture cap=cv::VideoCapture(); + cap.open(filename); + cap.set(CV_CAP_PROP_POS_MSEC, seektoms); + + while (cap.read(frame) == true) + { + 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++; + } + } + else + { + std::cerr << "Video file not found: " << filename << std::endl; } } else if (hasEnding(filename, ".png") || hasEnding(filename, ".jpg") || hasEnding(filename, ".gif")) { - frame = cv::imread( filename ); + if (fileExists(filename.c_str())) + { + frame = cv::imread( filename ); detectandshow( &alpr, frame, "", outputJson); + } + else + { + std::cerr << "Image file not found: " << filename << std::endl; + } } From 646c2d66608e9ff8a45dc01dc307a165a3bfdd2b Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Tue, 18 Feb 2014 22:19:20 -0600 Subject: [PATCH 4/5] Fixed segfault when calculating median against empty array --- src/openalpr/utility.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openalpr/utility.cpp b/src/openalpr/utility.cpp index 4953e2c..06fd044 100644 --- a/src/openalpr/utility.cpp +++ b/src/openalpr/utility.cpp @@ -177,6 +177,12 @@ vector produceThresholds(const Mat img_gray, Config* config) double median(int array[], int arraySize) { + if (arraySize == 0) + { + //std::cerr << "Median calculation requested on empty array" << endl; + return 0; + } + std::sort(&array[0], &array[arraySize]); return arraySize % 2 ? array[arraySize / 2] : (array[arraySize / 2 - 1] + array[arraySize / 2]) / 2; } From bcdb010cc5fb469b593150979a020af4cda3698a Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Tue, 18 Feb 2014 22:49:25 -0600 Subject: [PATCH 5/5] Increased recognition speed for plate region analysis by 2.5x. Reduced number of thresholded images from 10 to 4. Accuracy (based on current benchmarks) is about the same, but recognition speed for a single plate region goes from ~88ms to ~40ms. --- src/openalpr/utility.cpp | 63 ++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/src/openalpr/utility.cpp b/src/openalpr/utility.cpp index 06fd044..8b30359 100644 --- a/src/openalpr/utility.cpp +++ b/src/openalpr/utility.cpp @@ -112,7 +112,7 @@ void displayImage(Config* config, string windowName, cv::Mat frame) vector produceThresholds(const Mat img_gray, Config* config) { - const int THRESHOLD_COUNT = 10; + const int THRESHOLD_COUNT = 4; //Mat img_equalized = equalizeBrightness(img_gray); timespec startTime; @@ -120,44 +120,37 @@ vector produceThresholds(const Mat img_gray, Config* config) vector thresholds; - //#pragma omp parallel for for (int i = 0; i < THRESHOLD_COUNT; i++) thresholds.push_back(Mat(img_gray.size(), CV_8U)); + int i = 0; - for (int i = 0; i < THRESHOLD_COUNT; i++) - { - - - if (i <= 2) //0-2 - { - int k = ((i%3) * 5) + 7; // 7, 12, 17 - if (k==12) k = 13; // change 12 to 13 - //#pragma omp ordered - adaptiveThreshold(img_gray, thresholds[i], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , k, 3); - } - else if (i <= 6) //3-6 - { - int k = i%2; // 0 or 1 - int win = 18 + (k * 4); // 18 or 22 - //#pragma omp ordered - NiblackSauvolaWolfJolion (img_gray, thresholds[i], WOLFJOLION, win, win, 0.05 + (k * 0.35)); - bitwise_not(thresholds[i], thresholds[i]); - - } - else if (i <= 9) //7-9 - { - int k = (i%3) + 1; // 1,2,3 - //#pragma omp ordered - NiblackSauvolaWolfJolion (img_gray, thresholds[i], SAUVOLA, 12, 12, 0.18 * k); - bitwise_not(thresholds[i], thresholds[i]); - - } - - - - - } + // Adaptive + //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 7, 3); + //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 13, 3); + //adaptiveThreshold(img_gray, thresholds[i++], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV , 17, 3); + + // Wolf + int k = 0, win=18; + //NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); + //bitwise_not(thresholds[i-1], thresholds[i-1]); + NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); + bitwise_not(thresholds[i-1], thresholds[i-1]); + + k = 1; win = 22; + NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); + bitwise_not(thresholds[i-1], thresholds[i-1]); + //NiblackSauvolaWolfJolion (img_gray, thresholds[i++], WOLFJOLION, win, win, 0.05 + (k * 0.35)); + //bitwise_not(thresholds[i-1], thresholds[i-1]); + + // Sauvola + k = 1; + NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k); + bitwise_not(thresholds[i-1], thresholds[i-1]); + k=2; + NiblackSauvolaWolfJolion (img_gray, thresholds[i++], SAUVOLA, 12, 12, 0.18 * k); + bitwise_not(thresholds[i-1], thresholds[i-1]); +