diff --git a/src/AbstractOperator.cpp b/src/AbstractOperator.cpp index 2049972..041301d 100644 --- a/src/AbstractOperator.cpp +++ b/src/AbstractOperator.cpp @@ -5,17 +5,23 @@ */ IplImage* AbstractOperator::applyOperator(IplImage* sourceImage) { IplImage* horizontalEdges = cvCloneImage(sourceImage); - CvMat* horizontalMatrix = getHorizontalKernelMatrix(); cvFilter2D(sourceImage, horizontalEdges, horizontalMatrix, cvPoint(-1,-1)); - cvReleaseMat(&horizontalMatrix); IplImage* verticalEdges = cvCloneImage(sourceImage); - CvMat* verticalMatrix = getVerticalKernelMatrix(); cvFilter2D(sourceImage, verticalEdges, verticalMatrix, cvPoint(-1,-1)); - cvReleaseMat(&verticalMatrix); - sourceImage = applyGradient(horizontalEdges, verticalEdges); - return sourceImage; + horizontalEdges = applyGradient(horizontalEdges, verticalEdges); + cvReleaseImage(&sourceImage); + cvReleaseImage(&verticalEdges); + return horizontalEdges; +} + +/** + * Создать матрицы свертки. + **/ +void AbstractOperator::createMatrix() { + createHorizontalKernelMatrix(); + createVerticalKernelMatrix(); } /** @@ -25,7 +31,7 @@ CvMat* AbstractOperator::setupKernelMatrixFromArray(CvMat* kernel, float* matrix int w = kernel->width; for (int y = 0; y < kernel->height; y++) { for (int x = 0; x < w; x++) { - cvSet2D(kernel, 0, 0, cvRealScalar(matrix[y*w+x])); + cvSet2D(kernel, y, x, cvRealScalar(matrix[y*w+x])); } } return kernel; @@ -40,6 +46,7 @@ IplImage* AbstractOperator::applyGradient(IplImage* horiz, IplImage* vert) { // Вычисляем значения для каждого канала for (int i = 0; i < ch; i++) { pHor[ch*x+i] = calculateGradient(pHor[ch*x+i], pVert[ch*x+i]); + if (pHor[ch*x+i] > 255) pHor[ch*x+i] = 255; } } } diff --git a/src/AbstractOperator.h b/src/AbstractOperator.h index 4a4dd27..2a93eb2 100644 --- a/src/AbstractOperator.h +++ b/src/AbstractOperator.h @@ -8,16 +8,19 @@ class AbstractOperator { public: IplImage* applyOperator(IplImage* sourceImage); + void createMatrix(); protected: - virtual CvMat* getHorizontalKernelMatrix() = 0; - virtual CvMat* getVerticalKernelMatrix() = 0; + virtual void createHorizontalKernelMatrix() = 0; + virtual void createVerticalKernelMatrix() = 0; CvMat* setupKernelMatrixFromArray(CvMat* sourceMatrix, float* matrix); +protected: + CvMat* horizontalMatrix; + CvMat* verticalMatrix; + private: IplImage* applyGradient(IplImage* horizontalEdges, IplImage* verticalEdges); uchar calculateGradient(uchar pix1, uchar pix2); - - int numberOfChannels; }; diff --git a/src/DonNUEdgeDetector.rc b/src/DonNUEdgeDetector.rc index 94cc145..9f9b6d1 100644 --- a/src/DonNUEdgeDetector.rc +++ b/src/DonNUEdgeDetector.rc @@ -17,6 +17,7 @@ #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -54,7 +55,7 @@ BEGIN POPUP "&Камера" BEGIN MENUITEM "&Захват кадра\tF9", ID_SNAPSHOT - MENUITEM "У&стройство", ID_DEVICE + MENUITEM "&Пауза\tCtrl+P", ID_PAUSE MENUITEM SEPARATOR MENUITEM "Вы&ход\tAlt+F4", ID_EXIT END @@ -82,16 +83,63 @@ END IDR_MAINACCELERATOR ACCELERATORS BEGIN - "1", ID_OP_ROBERTS, VIRTKEY, NOINVERT - "2", ID_OP_PREWITT, VIRTKEY, NOINVERT - "3", ID_OP_SOBEL, VIRTKEY, NOINVERT "G", ID_EF_GRAYSCALE, VIRTKEY, CONTROL, NOINVERT "I", ID_EF_INVERSE, VIRTKEY, CONTROL, NOINVERT "O", ID_EF_ORIGINAL, VIRTKEY, CONTROL, NOINVERT - VK_F9, ID_SNAPSHOT, VIRTKEY, NOINVERT VK_F4, ID_EXIT, VIRTKEY, ALT, NOINVERT + "2", ID_OP_PREWITT, VIRTKEY, NOINVERT + "1", ID_OP_ROBERTS, VIRTKEY, NOINVERT + "3", ID_OP_SOBEL, VIRTKEY, NOINVERT + VK_F9, ID_SNAPSHOT, VIRTKEY, NOINVERT + "P", ID_PAUSE, VIRTKEY, CONTROL, NOINVERT END + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT_DIALOG DIALOGEX 0, 0, 203, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "О программе" +FONT 8, "Tahoma", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDC_OK,73,65,61,14,BS_CENTER + LTEXT "Автор: Виктор aNNiMON Мельник",-1,43,20,113,8,NOT WS_GROUP + LTEXT "DonNUEdgeDetector 1.0",-1,55,7,82,9,NOT WS_GROUP + LTEXT "Исходный код открыт и располагается на:",-1,29,33,149,9,NOT WS_GROUP + PUSHBUTTON "github.com/aNNiMON/DonNUEdgeDetector",IDC_GO_TO_GIT,22,45,163,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 9 + RIGHTMARGIN, 197 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON "icon.ico" #endif // Русский (Россия) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/EdgeDetector.cpp b/src/EdgeDetector.cpp index 9220a4c..8507346 100644 --- a/src/EdgeDetector.cpp +++ b/src/EdgeDetector.cpp @@ -8,6 +8,7 @@ EdgeDetector::EdgeDetector() {} */ EdgeDetector::~EdgeDetector() { cvReleaseCapture(&camera); + cvReleaseImage(&resultFrame); cvDestroyAllWindows(); delete edgeDetectOperator; } @@ -27,20 +28,25 @@ void EdgeDetector::init(int deviceNumber) { void EdgeDetector::update() { if (camera == NULL) return; + cvWaitKey(33); + cameraFrame = cvQueryFrame(camera); - resultFrame = cvCloneImage(cameraFrame); + cvReleaseImage(&resultFrame); if (isGrayScaleEffect) { - IplImage* tempFrame = cvCloneImage(resultFrame); + IplImage* tempFrame = cvCloneImage(cameraFrame); resultFrame = cvCreateImage(imageSize, cameraFrame->depth, CV_LOAD_IMAGE_GRAYSCALE); cvCvtColor(tempFrame, resultFrame, CV_BGR2GRAY); - } + cvReleaseImage(&tempFrame); + } else resultFrame = cvCloneImage(cameraFrame); + if (!isOriginalEffect) { resultFrame = edgeDetectOperator->applyOperator(resultFrame); } if (isInverseEffect) { IplImage* tempFrame = cvCloneImage(resultFrame); cvNot(tempFrame, resultFrame); + cvReleaseImage(&tempFrame); } cvShowImage(getWindowName(), resultFrame); @@ -86,11 +92,11 @@ void EdgeDetector::setOperator(UINT typeOperator) { edgeDetectOperator = new SobelOperator(); break; } + edgeDetectOperator->createMatrix(); } CvCapture* EdgeDetector::initCamera(int deviceNumber) { - //return cvCreateCameraCapture(deviceNumber); return cvCaptureFromCAM(deviceNumber); } diff --git a/src/Main.cpp b/src/Main.cpp index dc295e0..49f9833 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "EdgeDetector.h" #include "WindowClass.h" #include "Window.h" @@ -10,6 +11,7 @@ LRESULT CALLBACK mainWindowProcedure(HWND, UINT, UINT, LONG); void menuCommandSelected(HWND hWnd, UINT wParam); +void setPause(HWND hWnd, bool pause); void setOperatorType(HWND hWnd, UINT type); void setEffectTypes(HWND hWnd); @@ -18,6 +20,7 @@ bool effectsEnabled[EFFECTS_END - EFFECTS_START + 1]; /** Детектор границ */ EdgeDetector detector; +bool pause, runningThread; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { // Регистрация класса окна @@ -25,6 +28,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd wClass.setToDefault(); wClass.setInstance(hInstance); wClass.setClassName(L"DonNUEdgeDetector"); + wClass.setIconType(MAKEINTRESOURCE(IDI_ICON1)); wClass.setMenuName(MAKEINTRESOURCE(IDR_MAINMENU)); wClass.setWindowProcedure(mainWindowProcedure); if (!wClass.registerClass()) return 0; @@ -49,7 +53,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { - detector.update(); if(!TranslateAccelerator(wnd.getWindow(), hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -58,6 +61,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd return msg.wParam; } +VOID edgeDetectingThread (PVOID pvoid) { + while (runningThread) { + if (!pause) detector.update(); + } + _endthread(); +} + + /** * Оконная процедура. */ @@ -65,8 +76,11 @@ LRESULT CALLBACK mainWindowProcedure(HWND hWnd, UINT message, UINT wParam, LONG switch(message) { case WM_CREATE: + runningThread = true; + setPause(hWnd, false); setOperatorType(hWnd, ID_OP_ROBERTS); setEffectTypes(hWnd); + _beginthread(edgeDetectingThread, 0, NULL) ; break; case WM_COMMAND: @@ -74,6 +88,7 @@ LRESULT CALLBACK mainWindowProcedure(HWND hWnd, UINT message, UINT wParam, LONG break; case WM_DESTROY: + runningThread = false; PostQuitMessage(0); break; @@ -83,6 +98,27 @@ LRESULT CALLBACK mainWindowProcedure(HWND hWnd, UINT message, UINT wParam, LONG return 0; } +/** + * Обработка сообщений диалогового окна "О программе" + */ +BOOL CALLBACK AboutDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + switch(message) { + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDC_GO_TO_GIT: + ShellExecuteA(GetParent(hDlg), "open", "https://github.com/aNNiMON/DonNUEdgeDetector", NULL, NULL, SW_MAXIMIZE); + return TRUE; + case IDC_OK: + EndDialog(hDlg, 0); + return TRUE; + } + break; + } + + return FALSE; +} + /** * Обработка события выбранного пункта меню. */ @@ -94,7 +130,8 @@ void menuCommandSelected(HWND hWnd, UINT wParam) { detector.snapshot(); break; - case ID_DEVICE: + case ID_PAUSE: + setPause(hWnd, !pause); break; case ID_OP_ROBERTS: @@ -111,6 +148,7 @@ void menuCommandSelected(HWND hWnd, UINT wParam) { break; case ID_ABOUT: + DialogBox(NULL, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), hWnd, (DLGPROC)AboutDialogProc); break; case ID_EXIT: @@ -119,6 +157,15 @@ void menuCommandSelected(HWND hWnd, UINT wParam) { } } +/** + * Приостановить работу детектора граней. + */ +void setPause(HWND hWnd, bool _pause) { + pause = _pause; + HMENU cameraMenu = GetSubMenu(GetMenu(hWnd), 0); + ULONG check = pause ? MF_CHECKED : MF_UNCHECKED; + CheckMenuItem(cameraMenu, 1, check); +} /** * Установить тип оператора (ID_OP_ROBERTS, ID_OP_SOBEL, ID_OP_PREWITT); diff --git a/src/PrewittOperator.h b/src/PrewittOperator.h index b6b4378..9b9cf5d 100644 --- a/src/PrewittOperator.h +++ b/src/PrewittOperator.h @@ -4,20 +4,20 @@ class PrewittOperator : public AbstractOperator { public: - CvMat* getHorizontalKernelMatrix() { + void createHorizontalKernelMatrix() { float matrix[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1 }; - CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + horizontalMatrix = cvCreateMat(3, 3, CV_32FC1); + horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix); } - CvMat* getVerticalKernelMatrix() { + void createVerticalKernelMatrix() { float matrix[9] = {-1,-1,-1, 0, 0, 0, 1, 1, 1 }; - CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + verticalMatrix = cvCreateMat(3, 3, CV_32FC1); + verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix); } }; diff --git a/src/RobertsOperator.h b/src/RobertsOperator.h index 87b14a5..6a5a7f8 100644 --- a/src/RobertsOperator.h +++ b/src/RobertsOperator.h @@ -4,19 +4,19 @@ class RobertsOperator : public AbstractOperator { public: - CvMat* getHorizontalKernelMatrix() { + void createHorizontalKernelMatrix() { float matrix[9] = {0, 0, 0, 0, 1, 0, 0, 0,-1 }; - CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + horizontalMatrix = cvCreateMat(3, 3, CV_32FC1); + horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix); } - CvMat* getVerticalKernelMatrix() { + void createVerticalKernelMatrix() { float matrix[9] = {0, 0, 0, 0, 0, 1, 0,-1, 0 }; - CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + verticalMatrix = cvCreateMat(3, 3, CV_32FC1); + verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix); } }; \ No newline at end of file diff --git a/src/SobelOperator.h b/src/SobelOperator.h index c1b96fa..6a4ac73 100644 --- a/src/SobelOperator.h +++ b/src/SobelOperator.h @@ -4,19 +4,19 @@ class SobelOperator : public AbstractOperator { public: - CvMat* getHorizontalKernelMatrix() { + void createHorizontalKernelMatrix() { float matrix[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1 }; - CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + horizontalMatrix = cvCreateMat(3, 3, CV_32FC1); + horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix); } - CvMat* getVerticalKernelMatrix() { + void createVerticalKernelMatrix() { float matrix[9] = {-1,-2,-1, 0, 0, 0, 1, 2, 1 }; - CvMat* kernel = cvCreateMat(3, 3,CV_32FC1); - return setupKernelMatrixFromArray(kernel, matrix); + verticalMatrix = cvCreateMat(3, 3,CV_32FC1); + verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix); } }; \ No newline at end of file diff --git a/src/WindowClass.cpp b/src/WindowClass.cpp index 9a18430..476a425 100644 --- a/src/WindowClass.cpp +++ b/src/WindowClass.cpp @@ -27,7 +27,6 @@ bool WindowClass::registerClass() { */ void WindowClass::setToDefault() { setStyle( CS_HREDRAW | CS_VREDRAW ); - setIconType(IDI_APPLICATION); setCursorType(IDC_ARROW); setBackgroundBrushColor(WHITE_BRUSH); setMenuName(L"MainMenu"); diff --git a/src/WindowClass.h b/src/WindowClass.h index 648c25b..e4044b9 100644 --- a/src/WindowClass.h +++ b/src/WindowClass.h @@ -3,7 +3,7 @@ #include /** - * WNDCLASS + * Класс регистрации WNDCLASS * @author aNNiMON */ class WindowClass { diff --git a/src/resource.h b/src/resource.h index 10c454e..ee18b5c 100644 Binary files a/src/resource.h and b/src/resource.h differ