diff --git a/include/detection.hpp b/include/detection.hpp index 46930d3..a38fee0 100644 --- a/include/detection.hpp +++ b/include/detection.hpp @@ -3,7 +3,14 @@ #include #include -#include "opencv2/core/core.hpp" +#include +#include +#include +#include + +using namespace std; +using namespace cv; + class Detector { public: @@ -12,3 +19,14 @@ class Detector { virtual void Detect(const cv::Mat& frame, std::vector& objects, std::vector& scores) = 0; }; + +class CascadeDetector : public Detector { +public: + virtual bool Init(const std::string& model_file_path); + virtual void Detect(const cv::Mat& frame, std::vector& objects, + std::vector& scores); + +protected: + cv::CascadeClassifier detector; +}; + diff --git a/include/image_processing.hpp b/include/image_processing.hpp index ca1f116..f476261 100644 --- a/include/image_processing.hpp +++ b/include/image_processing.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "opencv2/core/core.hpp" @@ -15,4 +16,16 @@ class ImageProcessor { const int kernelSize) = 0; virtual cv::Mat Pixelize(const cv::Mat &src, const cv::Rect &roi, const int kDivs) = 0; +}; + +class ImageProcessorImpl : public ImageProcessor { +public: + cv::Mat CvtColor(const cv::Mat &src, const cv::Rect &roi) override; + + cv::Mat Filter(const cv::Mat &src, const cv::Rect &roi, const int kSize) override; + + cv::Mat + DetectEdges(const cv::Mat &src, const cv::Rect &roi, const int filterSize, const int lowThreshold, const int ratio, + const int kernelSize) override; + cv::Mat Pixelize(const cv::Mat &src, const cv::Rect &roi, const int kDivs) override; }; \ No newline at end of file diff --git a/logo_cascade/intel_HAAR.xml b/logo_cascade/intel_HAAR.xml new file mode 100644 index 0000000..975b99d --- /dev/null +++ b/logo_cascade/intel_HAAR.xml @@ -0,0 +1,203 @@ + + + + BOOST + HAAR + 32 + 32 + + GAB + 9.9500000476837158e-01 + 1.0000000149011612e-01 + 9.4999999999999996e-01 + 1 + 100 + + 0 + 1 + BASIC + 5 + + + <_> + 1 + 9.9700450897216797e-01 + + <_> + + 0 -1 9 2.6727295480668545e-03 + + -1. 9.9700450897216797e-01 + + <_> + 2 + 1.6233325004577637e-02 + + <_> + + 0 -1 8 -2.8224483132362366e-02 + + 9.7911489009857178e-01 -9.5910018682479858e-01 + <_> + + 0 -1 5 1.6519669443368912e-03 + + -9.4611197710037231e-01 9.7533351182937622e-01 + + <_> + 2 + -2.3966401815414429e-01 + + <_> + + 0 -1 2 -1.8159887194633484e-01 + + 8.1481480598449707e-01 -9.9596774578094482e-01 + <_> + + 0 -1 0 2.7227598428726196e-01 + + -9.9537020921707153e-01 7.5630372762680054e-01 + + <_> + 4 + -9.0893095731735229e-01 + + <_> + + 0 -1 7 5.1844924688339233e-02 + + -9.2384767532348633e-01 2.1568627655506134e-01 + <_> + + 0 -1 1 4.7272067517042160e-02 + + -8.6901932954788208e-01 5.2460169792175293e-01 + <_> + + 0 -1 4 -5.4597020149230957e-02 + + 4.5749512314796448e-01 -9.4674235582351685e-01 + <_> + + 0 -1 3 9.5191076397895813e-02 + + -9.6718007326126099e-01 4.7605302929878235e-01 + + <_> + 4 + -9.4207423925399780e-01 + + <_> + + 0 -1 10 -2.4780812673270702e-03 + + 1.2500000000000000e-01 -9.4238680601119995e-01 + <_> + + 0 -1 11 2.1410051733255386e-02 + + -9.3719536066055298e-01 3.8065698742866516e-01 + <_> + + 0 -1 6 -1.3540741056203842e-03 + + 5.3382533788681030e-01 -9.2854446172714233e-01 + <_> + + 0 -1 12 -1.2107914313673973e-02 + + 4.0368261933326721e-01 -9.4481426477432251e-01 + + <_> + + <_> + 1 0 30 18 -1. + <_> + 1 9 30 9 2. + 0 + <_> + + <_> + 3 0 2 30 -1. + <_> + 3 10 2 10 3. + 0 + <_> + + <_> + 4 16 21 16 -1. + <_> + 4 24 21 8 2. + 0 + <_> + + <_> + 10 1 12 14 -1. + <_> + 10 8 12 7 2. + 0 + <_> + + <_> + 11 18 7 12 -1. + <_> + 11 24 7 6 2. + 0 + <_> + + <_> + 12 15 2 2 -1. + <_> + 13 15 1 2 2. + 0 + <_> + + <_> + 13 16 2 1 -1. + <_> + 14 16 1 1 2. + 0 + <_> + + <_> + 14 1 6 10 -1. + <_> + 14 6 6 5 2. + 0 + <_> + + <_> + 14 10 6 12 -1. + <_> + 14 14 6 4 3. + 0 + <_> + + <_> + 15 14 2 3 -1. + <_> + 16 14 1 3 2. + 0 + <_> + + <_> + 15 17 2 3 -1. + <_> + 15 18 2 1 3. + 0 + <_> + + <_> + 23 9 9 16 -1. + <_> + 26 9 3 16 3. + 0 + <_> + + <_> + 26 1 6 21 -1. + <_> + 29 1 3 21 2. + 0 + diff --git a/logo_cascade/intel_LBP.xml b/logo_cascade/intel_LBP.xml new file mode 100644 index 0000000..4b03540 --- /dev/null +++ b/logo_cascade/intel_LBP.xml @@ -0,0 +1,118 @@ + + + + BOOST + LBP + 32 + 32 + + GAB + 9.9500000476837158e-01 + 1.0000000149011612e-01 + 9.4999999999999996e-01 + 1 + 100 + + 256 + 1 + 5 + + + <_> + 1 + 9.2307692766189575e-01 + + <_> + + 0 -1 2 -243210785 -787906557 -2147483628 -251559935 + -2004832114 -1744175104 -2139094902 -1710022005 + + -1. 9.2307692766189575e-01 + + <_> + 1 + 8.5185188055038452e-01 + + <_> + + 0 -1 5 -711997505 -685438579 -1589539441 -14554131 + -525422401 -1316317151 -775886449 -2561 + + -1. 8.5185188055038452e-01 + + <_> + 2 + -1.9843308627605438e-01 + + <_> + + 0 -1 3 -95423497 -546619001 336412677 -742678013 704878731 + -879050368 -721237617 -7360593 + + -9.8792755603790283e-01 7.7358490228652954e-01 + <_> + + 0 -1 1 -715796001 2035925121 809877593 -782286833 + -1868516725 -1738399606 -486027045 -1053973 + + -9.7201800346374512e-01 8.7086659669876099e-01 + + <_> + 2 + -2.9111653566360474e-01 + + <_> + + 0 -1 7 -687219745 -108445629 402928799 2009842059 + -2061381443 -88481708 1237551339 -1056853 + + -9.9594318866729736e-01 7.1929824352264404e-01 + <_> + + 0 -1 0 -41550371 -249867389 1152347 -680009681 -255277921 + -1437676915 -1056708165 -37750337 + + -9.8999285697937012e-01 7.0482665300369263e-01 + + <_> + 2 + -3.8104116916656494e-01 + + <_> + + 0 -1 6 -537920513 -1001164153 860206851 831950969 -519970677 + -207503230 -931091729 -1049861 + + -9.9590164422988892e-01 5.8064514398574829e-01 + <_> + + 0 -1 4 -237505057 1430488223 -725499767 -184036437 + -628901445 -107380601 -97681173 -72363589 + + -9.6168631315231323e-01 8.2039451599121094e-01 + + <_> + + 7 1 8 10 + <_> + + 9 3 5 8 + <_> + + 11 12 5 3 + <_> + + 12 14 1 1 + <_> + + 12 15 1 1 + <_> + + 15 14 1 1 + <_> + + 15 15 1 2 + <_> + + 15 16 1 2 + diff --git a/samples/detection_demo.cpp b/samples/detection_demo.cpp new file mode 100644 index 0000000..810d567 --- /dev/null +++ b/samples/detection_demo.cpp @@ -0,0 +1,115 @@ +#include +#include "detection.hpp" + +using namespace std; +using namespace cv; + +const char* kOptions = + "{ i image | | image to process }" + "{ v video | | video to process }" + "{ c camera | | camera to get video from }" + "{ m model | | path to detector file }" + "{ h ? help usage | | print help message }"; + +void detectOnVideo( VideoCapture& capture, shared_ptr detector){ + Mat frame; + vector objects; + vector scores; + while(true) { + capture >> frame; + try { + detector->Detect(frame, objects, scores); + } + catch (char* msg){ + throw msg; + } + for(const auto& rect : objects){ + rectangle(frame, rect, Scalar(250, 150, 10)); + } + imshow("capture", frame); + int c = waitKey(33); + if (c == 27) { + break; + } + objects.clear(); + scores.clear(); + } + +} + +int main(int argc, const char** argv) { + // Parse command line arguments. + CommandLineParser parser(argc, argv, kOptions); + + // If help option is given, print help message and exit. + if (parser.get("h")) { + parser.printMessage(); + return 0; + } + std::shared_ptr detector; + try { + detector = Detector::CreateDetector("cascade"); + } + catch (const std::exception& e){ + cout << e.what() << endl; + } + + std::vector objects; + std::vector scores; + + std::string filePath; + + if(parser.has("m")){ + std::string filePathDetector; + filePathDetector = parser.get("m"); + detector->Init(filePathDetector); + } + else{ + cerr << "Error load model"; + return -1; + } + + if(parser.has("i")){ + std::string filePath = parser.get("i");; + Mat input = imread(filePath); + try { + detector->Detect(input, objects, scores); + } + catch(char* msg){ + throw msg; + } + } + else if(parser.has("v")){ + std::string filePath = parser.get("v");; + cv::VideoCapture video(filePath); + try { + detectOnVideo(video, detector); + } + catch (char* msg){ + cout << msg; + video.release(); + } + video.release(); + } + else if(parser.has("c")){ + + VideoCapture cap(0); + if(!cap.isOpened()) + return -1; + try { + detectOnVideo(cap, detector); + } + catch (char* msg){ + cout << msg; + } + cap.release(); + } + + else{ + cerr << "no flag" << endl; + } + + return 0; +} + + diff --git a/samples/imgproc_demo.cpp b/samples/imgproc_demo.cpp new file mode 100644 index 0000000..4466d4c --- /dev/null +++ b/samples/imgproc_demo.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +using namespace std; +using namespace cv; + +const char* kOptions = + "{ @image | | image to process }" + "{ gray | | convert ROI to gray scale }" + "{ median | | apply median filter for ROI }" + "{ edges | | detect edges in ROI }" + "{ pix | | pixelize ROI }" + "{ h ? help usage | | print help message }"; +struct MouseCallbackState { + bool is_selection_started; + bool is_selection_finished; + Point point_first; + Point point_second; +} mouseCallbackState; +void onMouse(int event, int x, int y, int flag, void* param) +{ + if(event == cv::EVENT_LBUTTONDOWN) + { + mouseCallbackState.is_selection_started = true; + mouseCallbackState.is_selection_finished = false; + mouseCallbackState.point_first = cv::Point(x, y); + } + if(event == cv::EVENT_LBUTTONUP) + { + mouseCallbackState.is_selection_started = false; + mouseCallbackState.is_selection_finished = true; + mouseCallbackState.point_second = cv::Point(x, y); + } + if(event == cv::EVENT_MOUSEMOVE && !mouseCallbackState.is_selection_finished) + { + mouseCallbackState.point_second = cv::Point(x, y); + } +} + +int main(int argc, const char** argv) { + // Parse command line arguments. + CommandLineParser parser(argc, argv, kOptions); + + // If help option is given, print help message and exit. + if (parser.get("help")) { + parser.printMessage(); + return 0; + } + + + // Do something cool. + cv::namedWindow("input"); + cv::setMouseCallback("input", onMouse); + std::string filePath; + if (parser.has("image")){ + filePath = parser.get("image"); + } + cv::Mat input = cv::imread(filePath); + cv::Mat input_copy; + cv::Rect rect; + while(true) + { + input.copyTo(input_copy); + + if(mouseCallbackState.is_selection_started && !mouseCallbackState.is_selection_finished) { + rect = cv::Rect(mouseCallbackState.point_first.x, mouseCallbackState.point_first.y, + mouseCallbackState.point_second.x - mouseCallbackState.point_first.x, + mouseCallbackState.point_second.y - mouseCallbackState.point_first.y); + } + cv::rectangle(input_copy, rect, cv::Scalar(90, 108, 70)); + cv::imshow("input", input_copy); + char c = cv::waitKey(39); + if (c == 27) + break; + } + ImageProcessorImpl processor; + + if(parser.has("gray")){ + input = processor.CvtColor(input, rect); + } + else if(parser.has("pix")) { + input = processor.Pixelize(input, rect, 5); + } + else if(parser.has("edges")) { + input = processor.DetectEdges(input, rect, 5, 2, 3, 5); + } + else if(parser.has("median")) { + input = processor.Filter(input, rect, 5); + } + else{ + cerr << "no flag" << endl; + } + cv::imshow("input", input); + cv::waitKey(0); + + return 0; +} diff --git a/src/detection.cpp b/src/detection.cpp index 15e7fd1..2a0d008 100644 --- a/src/detection.cpp +++ b/src/detection.cpp @@ -1,13 +1,35 @@ -#include "detection.hpp" - #include +#include "detection.hpp" using std::string; using std::shared_ptr; +using std::invalid_argument; using namespace cv; shared_ptr Detector::CreateDetector(const string& name) { - std::cerr << "Failed to create detector with name '" << name << "'" - << std::endl; - return nullptr; + if (name == "cascade") { + return std::make_shared(); + } + else + throw invalid_argument("invalid name expected cascade"); + + + +} + + +bool CascadeDetector::Init(const std::string &model_file_path) { + detector.load(model_file_path); + return !detector.empty(); +} + +void CascadeDetector::Detect(const cv::Mat &frame, std::vector &objects, std::vector &scores) { + if (!detector.empty()) { + std::vector sc; + detector.detectMultiScale(frame, objects, sc); + scores.resize(sc.size()); + std::copy(sc.begin(), sc.end(), scores.begin()); + } + else + throw "detector is empty"; } diff --git a/src/image_processing.cpp b/src/image_processing.cpp new file mode 100644 index 0000000..8c8330e --- /dev/null +++ b/src/image_processing.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include +#include + +#include "image_processing.hpp" + + cv::Mat ImageProcessorImpl::CvtColor(const cv::Mat &src, const cv::Rect &roi) { + + cv::Mat src_copy; + src.copyTo(src_copy); + cv::Mat src_copy_roi = src_copy(roi); + cv::Mat dst_gray_roi; + cv::cvtColor(src_copy_roi, dst_gray_roi, CV_BGR2GRAY); + std::vector channels(3); + + std::fill(channels.begin(), channels.end(), dst_gray_roi); + cv::Mat dst_roi; + cv::merge(channels, dst_roi); + // cv::merge(dst_gray_roi, dst_gray_roi, dst_gray_roi, dst_roi); + dst_roi.copyTo(src_copy_roi); + return src_copy; + } + + cv::Mat ImageProcessorImpl::Filter(const cv::Mat &src, const cv::Rect &roi, const int kSize) { + cv::Mat src_copy; + src.copyTo(src_copy); + cv::Mat src_copy_roi = src_copy(roi); + cv::medianBlur(src_copy_roi, src_copy_roi, kSize); + return src_copy; + } + + cv::Mat ImageProcessorImpl:: + DetectEdges(const cv::Mat &src, const cv::Rect &roi, const int filterSize, const int lowThreshold, const int ratio, + const int kernelSize) { + cv::Mat src_copy; + src.copyTo(src_copy); + cv::Mat src_roi = src_copy(roi); + cv::Mat src_gray_roi; + cv::cvtColor(src_roi, src_gray_roi, CV_BGR2GRAY); + cv::Mat detected_edges; + cv::blur(src_gray_roi, src_gray_roi, cv::Size(filterSize, filterSize)); + cv::Canny(src_gray_roi, detected_edges, lowThreshold, lowThreshold + ratio, kernelSize); + cv::Mat dst; + src.copyTo(dst); + cv::Mat dst_roi = dst(roi); + dst_roi = cv::Scalar::all(0); + src_roi.copyTo(dst_roi, detected_edges); + return dst; + } + + cv::Mat ImageProcessorImpl::Pixelize(const cv::Mat &src, const cv::Rect &roi, const int kDivs) { + cv::Mat src_copy; + src.copyTo(src_copy); + cv::Mat src_copy_roi = src_copy(roi); + int block_size_x = roi.width / kDivs; + int block_size_y = roi.height / kDivs; + for (int i = 0; i < src_copy_roi.rows; i += block_size_y) + for (int j = 0; j < src_copy_roi.cols; j += block_size_x) { + cv::Mat src_roi_block = src_copy_roi(cv::Rect(j, i, + j + block_size_x <= src_copy_roi.cols ? + block_size_x : src_copy_roi.cols - j, + i + block_size_y <= src_copy_roi.rows ? + block_size_y : src_copy_roi.rows - i)); + + cv::blur(src_roi_block, src_roi_block, cv::Size(block_size_x, block_size_y)); + } + return src_copy; + } + + +