diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a1949c..061049b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set(LIBRARY_DEPS ${OpenCV_LIBS}) # BUILD add_subdirectory(sample_template) # Add you directory here -# add_subdirectory(sample_YOUR_NAME) +add_subdirectory(sample_Shchedrin) # REPORT message( STATUS "") diff --git a/sample_Shchedrin/CMakeLists.txt b/sample_Shchedrin/CMakeLists.txt new file mode 100644 index 0000000..65c5916 --- /dev/null +++ b/sample_Shchedrin/CMakeLists.txt @@ -0,0 +1,7 @@ +set(target "sample_Shchedrin") + +file(GLOB hdrs "*.hpp") +file(GLOB srcs "*.cpp") + +add_executable(${target} ${srcs} ${hdrs}) +target_link_libraries(${target} ${LIBRARY_DEPS}) diff --git a/sample_Shchedrin/application.cpp b/sample_Shchedrin/application.cpp new file mode 100644 index 0000000..cf01078 --- /dev/null +++ b/sample_Shchedrin/application.cpp @@ -0,0 +1,230 @@ +#include "application.hpp" +#include "processing.hpp" + +#include +#include +#include +#include + +using namespace cv; + +int Application::parseArguments(int argc, const char **argv, + Application::Parameters ¶ms) +{ + if (argc < 2) + { + return 1; + } + params.imgFileName = std::string(argv[1]); + params.useCamera = false; + if(std::string(argv[1]) == "--camera"){ + params.useCamera = true; + } + return 0; +} + +int Application::getFrame(const std::string &fileName, Mat& src) +{ + src = imread(fileName); + if (src.empty()) + { + return 1; + } + return 0; +} + +int Application::processFrame(const Mat& src, Mat& dst, cv::Rect region) +{ + processor.applyEdges = guiState.edgesEnabled; + processor.applyPixel = guiState.pixelEnabled; + processor.applyGray = guiState.grayEnabled; + processor.applyMedian = guiState.medianEnabled; + processor.processFrame(src, dst, region); + if (dst.empty()) + { + return 1; + } + + return 0; +} + +int Application::drawButtons(Mat &display) +{ + guiState.onButtonPlace = Rect(20 + 140 * 0, display.rows - 60, 120, 40); + guiState.offButtonPlace = Rect(20 + 140 * 1, display.rows - 60, 120, 40); + guiState.saveButtonPlace = Rect(20 + 140 * 2, display.rows - 60, 120, 40); + guiState.grayscaleButtonPlace = Rect(20 + 140 * 3, display.rows - 60, 120, 40); + guiState.pixelButtonPlace = Rect(20 + 140 * 4, display.rows - 60, 120, 40); + guiState.edgesButtonPlace = Rect(20 + 140 * 5, display.rows - 60, 120, 40); + guiState.medianButtonPlace = Rect(20 + 140 * 6, display.rows - 60, 120, 40); + rectangle(display, guiState.onButtonPlace, + Scalar(128, 128, 128), CV_FILLED); + rectangle(display, guiState.offButtonPlace, + Scalar(128, 128, 128), CV_FILLED); + rectangle(display, guiState.saveButtonPlace, + Scalar(128, 128, 128), CV_FILLED); + + Scalar color(128,128,128); + if(guiState.grayEnabled){ + color = Scalar(128,200,128); + }else{ + color = Scalar(128,128,128); + } + rectangle(display, guiState.grayscaleButtonPlace, + color, CV_FILLED); + if(guiState.pixelEnabled){ + color = Scalar(128,200,128); + }else{ + color = Scalar(128,128,128); + } + rectangle(display, guiState.pixelButtonPlace, + color, CV_FILLED); + if(guiState.edgesEnabled){ + color = Scalar(128,200,128); + }else{ + color = Scalar(128,128,128); + } + rectangle(display, guiState.edgesButtonPlace, + color, CV_FILLED); + + if(guiState.medianEnabled){ + color = Scalar(128,200,128); + }else{ + color = Scalar(128,128,128); + } + rectangle(display, guiState.medianButtonPlace, + color, CV_FILLED); + + putText(display, "on", + Point(guiState.onButtonPlace.x + guiState.onButtonPlace.width / 2 - 15, + guiState.onButtonPlace.y + guiState.onButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "off", + Point(guiState.offButtonPlace.x + guiState.offButtonPlace.width / 2 - 20, + guiState.offButtonPlace.y + guiState.offButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "save", + Point(guiState.saveButtonPlace.x + guiState.saveButtonPlace.width / 2 - 35, + guiState.saveButtonPlace.y + guiState.saveButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "gray", + Point(guiState.grayscaleButtonPlace.x + guiState.grayscaleButtonPlace.width / 2 - 35, + guiState.grayscaleButtonPlace.y + guiState.grayscaleButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "pixel", + Point(guiState.pixelButtonPlace.x + guiState.pixelButtonPlace.width / 2 - 35, + guiState.pixelButtonPlace.y + guiState.pixelButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "edges", + Point(guiState.edgesButtonPlace.x + guiState.edgesButtonPlace.width / 2 - 35, + guiState.edgesButtonPlace.y + guiState.edgesButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + putText(display, "median", + Point(guiState.medianButtonPlace.x + + guiState.medianButtonPlace.width / 2 - 55, + guiState.medianButtonPlace.y + + guiState.medianButtonPlace.height / 2 + 10), + FONT_HERSHEY_SIMPLEX, 1.0, Scalar(0, 0, 0), 2); + + return 0; +} + +int Application::showFrame(const std::string &caption, + const Mat& src, Mat& dst, int shift) +{ + if (guiState.state == OffFilter) + { + src.copyTo(dst); + } + else if (guiState.state == OnFilter) + { + cv::Rect region(shift % (src.cols/2), src.cols/4, src.rows/2, src.cols/2); + processFrame(src, dst, region); + } + else + { + return 1; + } + + Mat display(src.rows, src.cols + dst.cols, src.type()); + Mat srcRoi = display(Rect(0, 0, src.cols, src.rows)); + src.copyTo(srcRoi); + Mat dstRoi = display(Rect(src.cols, 0, dst.cols, dst.rows)); + dst.copyTo(dstRoi); + if(guiState.saveImage){ + guiState.saveImage = false; + + time_t now = time(0); + struct tm tstruct; + char buf[80]; + char filename[100]; + tstruct = *localtime(&now); + strftime(buf, sizeof(buf), "%Y_%m_%d_%H_%M_%S", &tstruct); + sprintf (filename,"%s.png", buf); + imwrite(filename,display); + } + drawButtons(display); + + namedWindow(caption); + imshow(caption, display); + setMouseCallback(caption, onButtonsOnOffClick, &guiState); + char key = waitKey(1); + + return key; +} + +void onButtonsOnOffClick(int eventId, int x, int y, int flags, void *userData) +{ + if (eventId != EVENT_LBUTTONDOWN) + { + return; + } + Application::GUIElementsState *elems = + (Application::GUIElementsState *)userData; + if (onButtonClicked(elems->onButtonPlace, x, y)) + { + elems->state = Application::OnFilter; + return; + } + if (onButtonClicked(elems->offButtonPlace, x, y)) + { + elems->state = Application::OffFilter; + return; + } + if (onButtonClicked(elems->saveButtonPlace, x, y)) + { + elems->saveImage = true; + return; + } + if (onButtonClicked(elems->grayscaleButtonPlace, x, y)) + { + elems->grayEnabled = !elems->grayEnabled; + return; + } + if (onButtonClicked(elems->pixelButtonPlace, x, y)) + { + elems->pixelEnabled = !elems->pixelEnabled; + return; + } + if (onButtonClicked(elems->edgesButtonPlace, x, y)) + { + elems->edgesEnabled = !elems->edgesEnabled; + return; + } + if (onButtonClicked(elems->medianButtonPlace, x, y)) + { + elems->medianEnabled = !elems->medianEnabled; + return; + } +} + +bool onButtonClicked(cv::Rect buttonPlace, int x, int y) +{ + if (x < buttonPlace.x || x > buttonPlace.x + buttonPlace.width || + y < buttonPlace.y || y > buttonPlace.y + buttonPlace.height) + { + return false; + } + return true; +} + diff --git a/sample_Shchedrin/application.hpp b/sample_Shchedrin/application.hpp new file mode 100644 index 0000000..a5f1cf4 --- /dev/null +++ b/sample_Shchedrin/application.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +#include "processing.hpp" + +bool onButtonClicked(cv::Rect buttonPlace, int x, int y); +void onButtonsOnOffClick(int eventId, int x, int y, int flags, void *userData); + +class Application +{ + public: + enum WindowState + { + OnFilter, + OffFilter + }; + struct Parameters + { + std::string imgFileName; + bool useCamera; + }; + struct GUIElementsState + { + bool saveImage; + bool grayEnabled; + bool pixelEnabled; + bool edgesEnabled; + bool medianEnabled; + WindowState state; + cv::Rect onButtonPlace; + cv::Rect offButtonPlace; + cv::Rect saveButtonPlace; + cv::Rect grayscaleButtonPlace; + cv::Rect pixelButtonPlace; + cv::Rect edgesButtonPlace; + cv::Rect medianButtonPlace; + }; + int parseArguments(int argc, const char **argv, Parameters ¶ms); + int getFrame(const std::string &fileName, cv::Mat& src); + int processFrame(const cv::Mat& src, cv::Mat& dst, cv::Rect region); + int showFrame(const std::string &caption, + const cv::Mat& src, cv::Mat& dst, int shift); + friend void onButtonsOnOffClick(int eventId, int x, int y, + int flags, void *userData); + Application() + { + guiState.state = OnFilter; + guiState.saveImage = false; + guiState.grayEnabled = false; + guiState.pixelEnabled = false; + guiState.edgesEnabled = false; + }; + + private: + Processing processor; + GUIElementsState guiState; + + int drawButtons(cv::Mat &display); + + friend bool onButtonClicked(cv::Rect buttonPlace, int x, int y); +}; diff --git a/sample_Shchedrin/main.cpp b/sample_Shchedrin/main.cpp new file mode 100644 index 0000000..1ebacfb --- /dev/null +++ b/sample_Shchedrin/main.cpp @@ -0,0 +1,61 @@ +#include +#include "opencv2/opencv.hpp" +#include + +#include "application.hpp" + +using namespace std; +using namespace cv; + +enum ErrorCode { + OK, + WRONG_ARGUMENTS, + WRONG_INPUT, + CANT_PROCESS +}; + +int main(int argc, const char **argv) +{ + Application app; + Application::Parameters params; + + if (app.parseArguments(argc, argv, params) != 0) + { + cout << "sample_template " << endl; + cout << " - image name for filtering" << endl; + return WRONG_ARGUMENTS; + } + + Mat src; + VideoCapture cap(0); + if(!cap.isOpened()){ // check if we succeeded + cerr<<"Can not connect to camera."<>src; + if(src.empty()){ + cout<<"Unable to get frame"< +#include //TODO:delete + +using namespace cv; + +void Processing::processFrame(const cv::Mat& src, cv::Mat& dst, cv::Rect region) +{ + src.copyTo(dst); + + Mat roi = dst(region); + if(applyEdges){ + Mat buf; + cvtColor(roi, buf, CV_RGB2GRAY); + GaussianBlur(buf, buf, Size(3, 3), 1.6); + Canny(buf,buf,60,200); + vector rgb; + rgb.push_back(buf); + rgb.push_back(buf); + rgb.push_back(buf); + merge(rgb, roi); + } + if(applyPixel){ + int pixelSize = 10; + for(int i = 0; pixelSize * i < roi.rows; i++){ + for(int j = 0; pixelSize * j < roi.cols; j++){ + Rect square(j*pixelSize, i* pixelSize, pixelSize, pixelSize); + Mat squareMat = roi(square); + Scalar color = mean(roi(square)); + squareMat.setTo(Scalar(0,0,0)); + circle(squareMat, Point(pixelSize/2, pixelSize/2), pixelSize/2, color, -1); + } + } + } + if(applyGray){ + Mat buf; + cvtColor(roi, buf, CV_RGB2GRAY); + vector rgb; + rgb.push_back(buf); + rgb.push_back(buf); + rgb.push_back(buf); + merge(rgb, roi); + } + const int kSize = 11; + if(applyMedian){ + medianBlur(roi, roi, kSize); + } + + rectangle(dst, region, Scalar(255, 0, 0)); +} + +Processing::Processing(){ + applyEdges = false; + applyGray = false; + applyPixel = false; +} diff --git a/sample_Shchedrin/processing.hpp b/sample_Shchedrin/processing.hpp new file mode 100644 index 0000000..4a3efa3 --- /dev/null +++ b/sample_Shchedrin/processing.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +class Processing +{ + public: + bool applyGray, applyPixel, applyEdges, applyMedian; + void processFrame(const cv::Mat& src, cv::Mat& dst, cv::Rect region); + Processing(); +};