diff --git a/src/openalpr/detection/detector.cpp b/src/openalpr/detection/detector.cpp index 05599a0..42a4c62 100644 --- a/src/openalpr/detection/detector.cpp +++ b/src/openalpr/detection/detector.cpp @@ -25,7 +25,7 @@ using namespace std; namespace alpr { - Detector::Detector(Config* config) + Detector::Detector(Config* config, PreWarp* prewarp) : detector_mask(config, prewarp) { this->config = config; diff --git a/src/openalpr/detection/detector.h b/src/openalpr/detection/detector.h index b0e9b64..d20bfc3 100644 --- a/src/openalpr/detection/detector.h +++ b/src/openalpr/detection/detector.h @@ -49,6 +49,8 @@ namespace alpr Config* config; bool loaded; + + DetectorMask detector_mask; std::string get_detector_file(); diff --git a/src/openalpr/detection/detectorcpu.cpp b/src/openalpr/detection/detectorcpu.cpp index e3d9db7..04693e1 100644 --- a/src/openalpr/detection/detectorcpu.cpp +++ b/src/openalpr/detection/detectorcpu.cpp @@ -28,6 +28,7 @@ namespace alpr DetectorCPU::DetectorCPU(Config* config) : Detector(config) { + DetectorCPU::DetectorCPU(Config* config, PreWarp* prewarp) : Detector(config, prewarp) { if( this->plate_cascade.load( get_detector_file() ) ) diff --git a/src/openalpr/detection/detectorcpu.h b/src/openalpr/detection/detectorcpu.h index ef5662c..25fdd85 100644 --- a/src/openalpr/detection/detectorcpu.h +++ b/src/openalpr/detection/detectorcpu.h @@ -36,7 +36,7 @@ namespace alpr class DetectorCPU : public Detector { public: - DetectorCPU(Config* config); + DetectorCPU(Config* config, PreWarp* prewarp); virtual ~DetectorCPU(); std::vector detect(cv::Mat frame, std::vector regionsOfInterest); diff --git a/src/openalpr/detection/detectorcuda.cpp b/src/openalpr/detection/detectorcuda.cpp index e14cdd2..e6fd704 100644 --- a/src/openalpr/detection/detectorcuda.cpp +++ b/src/openalpr/detection/detectorcuda.cpp @@ -29,7 +29,7 @@ using namespace std; namespace alpr { - DetectorCUDA::DetectorCUDA(Config* config) : Detector(config) { + DetectorCUDA::DetectorCUDA(Config* config, PreWarp* prewarp) : Detector(config, prewarp) { diff --git a/src/openalpr/detection/detectorcuda.h b/src/openalpr/detection/detectorcuda.h index 5c75230..f422821 100644 --- a/src/openalpr/detection/detectorcuda.h +++ b/src/openalpr/detection/detectorcuda.h @@ -43,7 +43,7 @@ namespace alpr class DetectorCUDA : public Detector { public: - DetectorCUDA(Config* config); + DetectorCUDA(Config* config, PreWarp* prewarp); virtual ~DetectorCUDA(); std::vector detect(cv::Mat frame, std::vector regionsOfInterest); diff --git a/src/openalpr/detection/detectorfactory.cpp b/src/openalpr/detection/detectorfactory.cpp index 59ac3d2..0823614 100644 --- a/src/openalpr/detection/detectorfactory.cpp +++ b/src/openalpr/detection/detectorfactory.cpp @@ -4,12 +4,12 @@ namespace alpr { - Detector* createDetector(Config* config) + Detector* createDetector(Config* config, PreWarp* prewarp) { if (config->detector == DETECTOR_LBP_CPU) { // CPU mode - return new DetectorCPU(config); + return new DetectorCPU(config, prewarp); } else if (config->detector == DETECTOR_LBP_GPU) { @@ -19,13 +19,13 @@ namespace alpr std::cerr << "Error: GPU detector requested, but GPU extensions are not compiled. " << "Add COMPILE_GPU=1 to the compiler definitions to enable GPU compilation." << std::endl; - return new DetectorCPU(config); + return new DetectorCPU(config, prewarp); #endif } else if (config->detector == DETECTOR_LBP_OPENCL) { #if OPENCV_MAJOR_VERSION == 3 - return new DetectorOCL(config); + return new DetectorOCL(config, prewarp); #else std::cerr << "Error: OpenCL acceleration requires OpenCV 3.0. " << std::endl; return new DetectorCPU(config); @@ -33,12 +33,12 @@ namespace alpr } else if (config->detector == DETECTOR_MORPH_CPU) { - return new DetectorMorph(config); + return new DetectorMorph(config, prewarp); } else { std::cerr << "Unknown detector requested. Using LBP CPU" << std::endl; - return new DetectorCPU(config); + return new DetectorCPU(config, prewarp); } } diff --git a/src/openalpr/detection/detectorfactory.h b/src/openalpr/detection/detectorfactory.h index 8aa3d83..b2b8a48 100644 --- a/src/openalpr/detection/detectorfactory.h +++ b/src/openalpr/detection/detectorfactory.h @@ -27,7 +27,7 @@ namespace alpr { - Detector* createDetector(Config* config); + Detector* createDetector(Config* config, PreWarp* prewarp); } #endif /* OPENALPR_DETECTORFACTORY_H */ diff --git a/src/openalpr/detection/detectormask.cpp b/src/openalpr/detection/detectormask.cpp new file mode 100644 index 0000000..0f3e50d --- /dev/null +++ b/src/openalpr/detection/detectormask.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015 OpenALPR Technology, Inc. + * Open source 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 "detectormask.h" +#include "prewarp.h" + +using namespace cv; +using namespace std; + +namespace alpr +{ + + + DetectorMask::DetectorMask(Config* config, PreWarp* prewarp) { + mask_loaded = false; + resized_mask_loaded = false; + this->config = config; + this->prewarp = prewarp; + last_prewarp_hash = ""; + } + + DetectorMask::~DetectorMask() { + } + + void DetectorMask::setMask(Mat orig_mask) { + this->mask = orig_mask; + if (orig_mask.channels() > 2) + cvtColor( orig_mask, this->mask, CV_BGR2GRAY ); + else + this->mask = orig_mask; + + // Threshold the mask so that the values are either 0 or 255 (no shades of gray)) + threshold(this->mask, this->mask, 1, 255, cv::THRESH_BINARY); + + + // Calculate the biggest rectangle that covers all the whitespace + // Rather than using contours, go row by row, column by column until you hit + // a white pixel and stop. Should be faster and a little simpler + unsigned int top_bound = 0, bottom_bound = 0, left_bound = 0, right_bound = 0; + + cout << mask.col(20).cols << " - " << mask.col(20).rows << endl; + for (top_bound = 0; top_bound < mask.rows; top_bound++) + if (countNonZero(mask.row(top_bound)) > 0) break; + for (bottom_bound = mask.rows - 1; bottom_bound >= 0; bottom_bound--) + if (countNonZero(mask.row(bottom_bound)) > 0) break; + + for (left_bound = 0; left_bound < mask.cols; left_bound++) + if (countNonZero(mask.col(left_bound)) > 0) break; + for (right_bound = mask.rows - 1; right_bound >= 0; right_bound--) + if (countNonZero(mask.col(right_bound)) > 0) break; + + if (left_bound >= right_bound || top_bound >= bottom_bound) + { + cerr << "Invalid mask" << endl; + return; + } + + scan_area.x = left_bound; + scan_area.y = top_bound; + scan_area.width = right_bound - left_bound; + scan_area.height = bottom_bound - top_bound; + +// Mat debug(this->mask.size(), mask.type()); +// this->mask.copyTo(debug); +// cvtColor(debug, debug, CV_GRAY2BGR); +// rectangle(debug, scan_area, Scalar(0,255,0), 2); +// drawAndWait(debug); + mask_loaded = true; + } + + cv::Size DetectorMask::mask_size() { + return mask.size(); + } + + // Provided a region of interest, truncate it if the mask cuts off a portion of it. + // No reason to analyze extra content + cv::Rect DetectorMask::getRoiInsideMask(cv::Rect roi) { + + if (prewarp->valid) + { + cv::Rect warped_scan_area = prewarp->projectRect(scan_area, mask.cols, mask.rows, false); + + Rect roi_intersection = roi & scan_area; + return roi_intersection; + + } + else + { + Rect roi_intersection = roi & scan_area; + return roi_intersection; + } + } + + + // Checks if the provided region is partially covered by the mask + // If so, it is disqualified + bool DetectorMask::region_is_masked(cv::Rect region) { + int MIN_WHITENESS = 253; + + // If the mean pixel value over the crop is very white (e.g., > 253 out of 255) + // then this is in the white area of the mask and we'll use it + Mat mask_crop = mask(region); + double mean_value = mean(mask_crop)[0]; + + return mean_value >= MIN_WHITENESS; + } + + Mat DetectorMask::apply_mask(Mat image) { + if (!mask_loaded) + return image; + + if (!resized_mask_loaded || last_prewarp_hash != prewarp->toString()) + { + resize(mask, resized_mask, image.size()); + + if (prewarp->valid) + { + resized_mask = prewarp->warpImage(resized_mask); + } + + last_prewarp_hash = prewarp->toString(); + + resized_mask_loaded = true; + } + + if (image.size() != resized_mask.size()) + { + return image; + } + + Mat response(image.size(), image.type()); + image.copyTo(response, resized_mask); + + return response; + } + +} \ No newline at end of file diff --git a/src/openalpr/detection/detectormask.h b/src/openalpr/detection/detectormask.h new file mode 100644 index 0000000..9c68746 --- /dev/null +++ b/src/openalpr/detection/detectormask.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015 OpenALPR Technology, Inc. + * Open source 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_DETECTORMASK_H +#define OPENALPR_DETECTORMASK_H + +#include +#include "opencv2/imgproc/imgproc.hpp" +#include "config.h" +#include "prewarp.h" + +namespace alpr +{ + + class DetectorMask { + public: + + DetectorMask(Config* config, PreWarp* prewarp); + virtual ~DetectorMask(); + + void setMask(cv::Mat mask); + + cv::Rect getRoiInsideMask(cv::Rect roi); + + cv::Size mask_size(); + + bool region_is_masked(cv::Rect region); + + cv::Mat apply_mask(cv::Mat image); + + bool mask_loaded; + + private: + + PreWarp* prewarp; + std::string last_prewarp_hash; + + cv::Mat mask; + + cv::Mat resized_mask; + bool resized_mask_loaded; + + Config* config; + cv::Rect scan_area; + + }; + +} +#endif /* DETECTORMASK_H */ + diff --git a/src/openalpr/detection/detectormorph.cpp b/src/openalpr/detection/detectormorph.cpp index 5e99495..a6aa9b8 100644 --- a/src/openalpr/detection/detectormorph.cpp +++ b/src/openalpr/detection/detectormorph.cpp @@ -24,7 +24,7 @@ using namespace std; namespace alpr { - DetectorMorph::DetectorMorph(Config* config) : Detector(config) { + DetectorMorph::DetectorMorph(Config* config, PreWarp* prewarp) : Detector(config, prewarp) { this->loaded = true; } diff --git a/src/openalpr/detection/detectormorph.h b/src/openalpr/detection/detectormorph.h index 364b16d..c19af95 100644 --- a/src/openalpr/detection/detectormorph.h +++ b/src/openalpr/detection/detectormorph.h @@ -35,7 +35,7 @@ namespace alpr { class DetectorMorph : public Detector { public: - DetectorMorph(Config* config); + DetectorMorph(Config* config, PreWarp* prewarp); virtual ~DetectorMorph(); std::vector detect(cv::Mat frame, std::vector regionsOfInterest); diff --git a/src/openalpr/detection/detectorocl.cpp b/src/openalpr/detection/detectorocl.cpp index 525a3fb..016385d 100644 --- a/src/openalpr/detection/detectorocl.cpp +++ b/src/openalpr/detection/detectorocl.cpp @@ -32,7 +32,7 @@ namespace alpr { - DetectorOCL::DetectorOCL(Config* config) : Detector(config) { + DetectorOCL::DetectorOCL(Config* config, PreWarp* prewarp) : Detector(config, prewarp) { tthread::lock_guard guard(ocl_detector_mutex_m); diff --git a/src/openalpr/detection/detectorocl.h b/src/openalpr/detection/detectorocl.h index 5daf784..aded432 100644 --- a/src/openalpr/detection/detectorocl.h +++ b/src/openalpr/detection/detectorocl.h @@ -39,7 +39,7 @@ namespace alpr class DetectorOCL : public Detector { public: - DetectorOCL(Config* config); + DetectorOCL(Config* config, PreWarp* prewarp); virtual ~DetectorOCL(); std::vector detect(cv::Mat frame, std::vector regionsOfInterest);