From 6033e357757500cd2dbadc90a593e98a6cdb84b5 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Sun, 8 Mar 2015 10:25:30 -0400 Subject: [PATCH] Added CUDA GPU support to detector --- src/openalpr/CMakeLists.txt | 1 + src/openalpr/config.cpp | 1 + src/openalpr/config.h | 10 ++ src/openalpr/detection/detectorcuda.cpp | 140 +++++++++++++++++++++ src/openalpr/detection/detectorcuda.h | 55 ++++++++ src/openalpr/detection/detectorfactory.cpp | 12 +- src/openalpr/detection/detectorfactory.h | 1 + 7 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 src/openalpr/detection/detectorcuda.cpp create mode 100644 src/openalpr/detection/detectorcuda.h diff --git a/src/openalpr/CMakeLists.txt b/src/openalpr/CMakeLists.txt index 787e336..d9f3f8c 100644 --- a/src/openalpr/CMakeLists.txt +++ b/src/openalpr/CMakeLists.txt @@ -7,6 +7,7 @@ set(lpr_source_files config.cpp detection/detector.cpp detection/detectorcpu.cpp + detection/detectorcuda.cpp detection/detectorfactory.cpp licenseplatecandidate.cpp utility.cpp diff --git a/src/openalpr/config.cpp b/src/openalpr/config.cpp index 23dabfb..62881a4 100644 --- a/src/openalpr/config.cpp +++ b/src/openalpr/config.cpp @@ -130,6 +130,7 @@ namespace alpr runtimeBaseDir = getString("common", "runtime_dir", "/usr/share/openalpr/runtime_data"); + gpu_mode = getInt("common", "gpu_mode", GPU_OFF); 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 e851f00..b388963 100644 --- a/src/openalpr/config.h +++ b/src/openalpr/config.h @@ -47,6 +47,8 @@ namespace alpr std::string country; + int gpu_mode; + float detection_iteration_increase; int detectionStrictness; float maxPlateWidthPercent; @@ -135,5 +137,13 @@ namespace alpr bool getBoolean(std::string section, std::string key, bool defaultValue); }; + + enum GPU_MODE + { + GPU_OFF=0, + GPU_CUDA=1, + GPU_OPENCL=2 + }; + } #endif // OPENALPR_CONFIG_H \ No newline at end of file diff --git a/src/openalpr/detection/detectorcuda.cpp b/src/openalpr/detection/detectorcuda.cpp new file mode 100644 index 0000000..64c9a7b --- /dev/null +++ b/src/openalpr/detection/detectorcuda.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2013 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] + * + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ + + +#include "detectorcuda.h" + + +using namespace cv; +using namespace std; + +namespace alpr +{ + + DetectorCUDA::DetectorCUDA(Config* config) : Detector(config) { + + + + if( this->cuda_cascade.load( config->getCascadeRuntimeDir() + config->country + ".xml" ) ) + { + this->loaded = true; + printf("--(!)Loaded CUDA classifier\n"); + } + else + { + this->loaded = false; + printf("--(!)Error loading CUDA classifier\n"); + } + } + + + DetectorCUDA::~DetectorCUDA() { + } + + vector DetectorCUDA::detect(Mat frame, std::vector regionsOfInterest) + { + + Mat frame_gray; + cvtColor( frame, frame_gray, CV_BGR2GRAY ); + + vector detectedRegions; + for (int i = 0; i < regionsOfInterest.size(); i++) + { + Mat cropped = frame_gray(regionsOfInterest[i]); + vector subRegions = doCascade(cropped, regionsOfInterest[i].x, regionsOfInterest[i].y); + + for (int j = 0; j < subRegions.size(); j++) + detectedRegions.push_back(subRegions[j]); + } + return detectedRegions; + } + + vector DetectorCUDA::doCascade(Mat frame, int offset_x, int offset_y) + { + + + if (frame.cols > config->maxDetectionInputWidth) + { + // The frame is too wide + this->scale_factor = ((float) config->maxDetectionInputWidth) / ((float) frame.cols); + + if (config->debugGeneral) + std::cout << "Input detection image is too wide. Resizing with scale: " << this->scale_factor << endl; + } + else if (frame.rows > config->maxDetectionInputHeight) + { + // The frame is too tall + this->scale_factor = ((float) config->maxDetectionInputHeight) / ((float) frame.rows); + + if (config->debugGeneral) + std::cout << "Input detection image is too tall. Resizing with scale: " << this->scale_factor << endl; + } + + int w = frame.size().width; + int h = frame.size().height; + + vector plates; + + equalizeHist( frame, frame ); + resize(frame, frame, Size(w * this->scale_factor, h * this->scale_factor)); + + //-- Detect plates + timespec startTime; + getTime(&startTime); + + float maxWidth = ((float) w) * (config->maxPlateWidthPercent / 100.0f) * this->scale_factor; + float maxHeight = ((float) h) * (config->maxPlateHeightPercent / 100.0f) * this->scale_factor; + Size minSize(config->minPlateSizeWidthPx * this->scale_factor, config->minPlateSizeHeightPx * this->scale_factor); + + gpu::GpuMat cudaFrame, plateregions_buffer; + Mat plateregions_downloaded; + + cudaFrame.upload(frame); + int numdetected = cuda_cascade.detectMultiScale(cudaFrame, plateregions_buffer, (double) config->detection_iteration_increase, config->detectionStrictness, minSize); + plateregions_buffer.colRange(0, numdetected).download(plateregions_downloaded); + + for (int i = 0; i < numdetected; ++i) + { + plates.push_back(plateregions_downloaded.ptr()[i]); + } + + + + if (config->debugTiming) + { + timespec endTime; + getTime(&endTime); + cout << "LBP Time: " << diffclock(startTime, endTime) << "ms." << endl; + } + + for( uint i = 0; i < plates.size(); i++ ) + { + plates[i].x = (plates[i].x / scale_factor) + offset_x; + plates[i].y = (plates[i].y / scale_factor) + offset_y; + plates[i].width = plates[i].width / scale_factor; + plates[i].height = plates[i].height / scale_factor; + } + + vector orderedRegions = aggregateRegions(plates); + + return orderedRegions; + + } + +} \ No newline at end of file diff --git a/src/openalpr/detection/detectorcuda.h b/src/openalpr/detection/detectorcuda.h new file mode 100644 index 0000000..927e046 --- /dev/null +++ b/src/openalpr/detection/detectorcuda.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013 New Designs Unlimited, LLC + * Opensource Automated License Plate Recognition [http://www.openalpr.com] + * + * This file is part of OpenAlpr. + * + * OpenAlpr is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License + * version 3 as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +*/ + +#ifndef OPENALPR_DETECTORCUDA_H +#define OPENALPR_DETECTORCUDA_H + +#include +#include +#include + +#include "opencv2/objdetect/objdetect.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/core/core.hpp" +#include "opencv2/ml/ml.hpp" +#include "opencv2/gpu/gpu.hpp" + +#include "detector.h" + +namespace alpr +{ + + class DetectorCUDA : public Detector { + public: + DetectorCUDA(Config* config); + virtual ~DetectorCUDA(); + + std::vector detect(cv::Mat frame, std::vector regionsOfInterest); + + private: + + cv::gpu::CascadeClassifier_GPU cuda_cascade; + + std::vector doCascade(cv::Mat frame, int offset_x, int offset_y); + }; + +} + +#endif /* OPENALPR_DETECTORCUDA_H */ + diff --git a/src/openalpr/detection/detectorfactory.cpp b/src/openalpr/detection/detectorfactory.cpp index cdc9617..07d7e94 100644 --- a/src/openalpr/detection/detectorfactory.cpp +++ b/src/openalpr/detection/detectorfactory.cpp @@ -2,10 +2,18 @@ namespace alpr { - Detector* createDetector(Config* config) { + if (config->gpu_mode == 0) + { + // CPU mode return new DetectorCPU(config); + } + else if (config->gpu_mode == 1) + { + return new DetectorCUDA(config); + } } -} \ No newline at end of file +} + diff --git a/src/openalpr/detection/detectorfactory.h b/src/openalpr/detection/detectorfactory.h index 8e3d926..8b50800 100644 --- a/src/openalpr/detection/detectorfactory.h +++ b/src/openalpr/detection/detectorfactory.h @@ -21,6 +21,7 @@ #define OPENALPR_DETECTORFACTORY_H #include "detectorcpu.h" +#include "detectorcuda.h" #include "config.h" namespace alpr