Исправлена работа детекторов граней. Устранена утечка памяти. Обработка выполняется в новом потоке. Пункт "Устройства" изменён на "Пауза". Добавлено диалоговое окно "О программе".

This commit is contained in:
Victor 2012-04-06 01:17:36 +03:00
parent 5634f98ec3
commit 3e57fbb9d2
11 changed files with 152 additions and 42 deletions

View File

@ -5,17 +5,23 @@
*/ */
IplImage* AbstractOperator::applyOperator(IplImage* sourceImage) { IplImage* AbstractOperator::applyOperator(IplImage* sourceImage) {
IplImage* horizontalEdges = cvCloneImage(sourceImage); IplImage* horizontalEdges = cvCloneImage(sourceImage);
CvMat* horizontalMatrix = getHorizontalKernelMatrix();
cvFilter2D(sourceImage, horizontalEdges, horizontalMatrix, cvPoint(-1,-1)); cvFilter2D(sourceImage, horizontalEdges, horizontalMatrix, cvPoint(-1,-1));
cvReleaseMat(&horizontalMatrix);
IplImage* verticalEdges = cvCloneImage(sourceImage); IplImage* verticalEdges = cvCloneImage(sourceImage);
CvMat* verticalMatrix = getVerticalKernelMatrix();
cvFilter2D(sourceImage, verticalEdges, verticalMatrix, cvPoint(-1,-1)); cvFilter2D(sourceImage, verticalEdges, verticalMatrix, cvPoint(-1,-1));
cvReleaseMat(&verticalMatrix);
sourceImage = applyGradient(horizontalEdges, verticalEdges); horizontalEdges = applyGradient(horizontalEdges, verticalEdges);
return sourceImage; 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; int w = kernel->width;
for (int y = 0; y < kernel->height; y++) { for (int y = 0; y < kernel->height; y++) {
for (int x = 0; x < w; x++) { 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; return kernel;
@ -40,6 +46,7 @@ IplImage* AbstractOperator::applyGradient(IplImage* horiz, IplImage* vert) {
// Вычисляем значения для каждого канала // Вычисляем значения для каждого канала
for (int i = 0; i < ch; i++) { for (int i = 0; i < ch; i++) {
pHor[ch*x+i] = calculateGradient(pHor[ch*x+i], pVert[ch*x+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;
} }
} }
} }

View File

@ -8,16 +8,19 @@
class AbstractOperator { class AbstractOperator {
public: public:
IplImage* applyOperator(IplImage* sourceImage); IplImage* applyOperator(IplImage* sourceImage);
void createMatrix();
protected: protected:
virtual CvMat* getHorizontalKernelMatrix() = 0; virtual void createHorizontalKernelMatrix() = 0;
virtual CvMat* getVerticalKernelMatrix() = 0; virtual void createVerticalKernelMatrix() = 0;
CvMat* setupKernelMatrixFromArray(CvMat* sourceMatrix, float* matrix); CvMat* setupKernelMatrixFromArray(CvMat* sourceMatrix, float* matrix);
protected:
CvMat* horizontalMatrix;
CvMat* verticalMatrix;
private: private:
IplImage* applyGradient(IplImage* horizontalEdges, IplImage* verticalEdges); IplImage* applyGradient(IplImage* horizontalEdges, IplImage* verticalEdges);
uchar calculateGradient(uchar pix1, uchar pix2); uchar calculateGradient(uchar pix1, uchar pix2);
int numberOfChannels;
}; };

View File

@ -17,6 +17,7 @@
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -54,7 +55,7 @@ BEGIN
POPUP "&Камера" POPUP "&Камера"
BEGIN BEGIN
MENUITEM "&Захват кадра\tF9", ID_SNAPSHOT MENUITEM "&Захват кадра\tF9", ID_SNAPSHOT
MENUITEM "У&стройство", ID_DEVICE MENUITEM "&Пауза\tCtrl+P", ID_PAUSE
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "Вы&ход\tAlt+F4", ID_EXIT MENUITEM "Вы&ход\tAlt+F4", ID_EXIT
END END
@ -82,16 +83,63 @@ END
IDR_MAINACCELERATOR ACCELERATORS IDR_MAINACCELERATOR ACCELERATORS
BEGIN 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 "G", ID_EF_GRAYSCALE, VIRTKEY, CONTROL, NOINVERT
"I", ID_EF_INVERSE, VIRTKEY, CONTROL, NOINVERT "I", ID_EF_INVERSE, VIRTKEY, CONTROL, NOINVERT
"O", ID_EF_ORIGINAL, VIRTKEY, CONTROL, NOINVERT "O", ID_EF_ORIGINAL, VIRTKEY, CONTROL, NOINVERT
VK_F9, ID_SNAPSHOT, VIRTKEY, NOINVERT
VK_F4, ID_EXIT, VIRTKEY, ALT, 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 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 #endif // Русский (Россия) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -8,6 +8,7 @@ EdgeDetector::EdgeDetector() {}
*/ */
EdgeDetector::~EdgeDetector() { EdgeDetector::~EdgeDetector() {
cvReleaseCapture(&camera); cvReleaseCapture(&camera);
cvReleaseImage(&resultFrame);
cvDestroyAllWindows(); cvDestroyAllWindows();
delete edgeDetectOperator; delete edgeDetectOperator;
} }
@ -27,20 +28,25 @@ void EdgeDetector::init(int deviceNumber) {
void EdgeDetector::update() { void EdgeDetector::update() {
if (camera == NULL) return; if (camera == NULL) return;
cvWaitKey(33);
cameraFrame = cvQueryFrame(camera); cameraFrame = cvQueryFrame(camera);
resultFrame = cvCloneImage(cameraFrame); cvReleaseImage(&resultFrame);
if (isGrayScaleEffect) { if (isGrayScaleEffect) {
IplImage* tempFrame = cvCloneImage(resultFrame); IplImage* tempFrame = cvCloneImage(cameraFrame);
resultFrame = cvCreateImage(imageSize, cameraFrame->depth, CV_LOAD_IMAGE_GRAYSCALE); resultFrame = cvCreateImage(imageSize, cameraFrame->depth, CV_LOAD_IMAGE_GRAYSCALE);
cvCvtColor(tempFrame, resultFrame, CV_BGR2GRAY); cvCvtColor(tempFrame, resultFrame, CV_BGR2GRAY);
} cvReleaseImage(&tempFrame);
} else resultFrame = cvCloneImage(cameraFrame);
if (!isOriginalEffect) { if (!isOriginalEffect) {
resultFrame = edgeDetectOperator->applyOperator(resultFrame); resultFrame = edgeDetectOperator->applyOperator(resultFrame);
} }
if (isInverseEffect) { if (isInverseEffect) {
IplImage* tempFrame = cvCloneImage(resultFrame); IplImage* tempFrame = cvCloneImage(resultFrame);
cvNot(tempFrame, resultFrame); cvNot(tempFrame, resultFrame);
cvReleaseImage(&tempFrame);
} }
cvShowImage(getWindowName(), resultFrame); cvShowImage(getWindowName(), resultFrame);
@ -86,11 +92,11 @@ void EdgeDetector::setOperator(UINT typeOperator) {
edgeDetectOperator = new SobelOperator(); edgeDetectOperator = new SobelOperator();
break; break;
} }
edgeDetectOperator->createMatrix();
} }
CvCapture* EdgeDetector::initCamera(int deviceNumber) { CvCapture* EdgeDetector::initCamera(int deviceNumber) {
//return cvCreateCameraCapture(deviceNumber);
return cvCaptureFromCAM(deviceNumber); return cvCaptureFromCAM(deviceNumber);
} }

View File

@ -1,6 +1,7 @@
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <commctrl.h> #include <commctrl.h>
#include <process.h>
#include "EdgeDetector.h" #include "EdgeDetector.h"
#include "WindowClass.h" #include "WindowClass.h"
#include "Window.h" #include "Window.h"
@ -10,6 +11,7 @@
LRESULT CALLBACK mainWindowProcedure(HWND, UINT, UINT, LONG); LRESULT CALLBACK mainWindowProcedure(HWND, UINT, UINT, LONG);
void menuCommandSelected(HWND hWnd, UINT wParam); void menuCommandSelected(HWND hWnd, UINT wParam);
void setPause(HWND hWnd, bool pause);
void setOperatorType(HWND hWnd, UINT type); void setOperatorType(HWND hWnd, UINT type);
void setEffectTypes(HWND hWnd); void setEffectTypes(HWND hWnd);
@ -18,6 +20,7 @@ bool effectsEnabled[EFFECTS_END - EFFECTS_START + 1];
/** Детектор границ */ /** Детектор границ */
EdgeDetector detector; EdgeDetector detector;
bool pause, runningThread;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { 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.setToDefault();
wClass.setInstance(hInstance); wClass.setInstance(hInstance);
wClass.setClassName(L"DonNUEdgeDetector"); wClass.setClassName(L"DonNUEdgeDetector");
wClass.setIconType(MAKEINTRESOURCE(IDI_ICON1));
wClass.setMenuName(MAKEINTRESOURCE(IDR_MAINMENU)); wClass.setMenuName(MAKEINTRESOURCE(IDR_MAINMENU));
wClass.setWindowProcedure(mainWindowProcedure); wClass.setWindowProcedure(mainWindowProcedure);
if (!wClass.registerClass()) return 0; if (!wClass.registerClass()) return 0;
@ -49,7 +53,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd
MSG msg; MSG msg;
while(GetMessage(&msg, NULL, 0, 0)) { while(GetMessage(&msg, NULL, 0, 0)) {
detector.update();
if(!TranslateAccelerator(wnd.getWindow(), hAccel, &msg)) { if(!TranslateAccelerator(wnd.getWindow(), hAccel, &msg)) {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
@ -58,6 +61,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd
return msg.wParam; 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) { switch(message) {
case WM_CREATE: case WM_CREATE:
runningThread = true;
setPause(hWnd, false);
setOperatorType(hWnd, ID_OP_ROBERTS); setOperatorType(hWnd, ID_OP_ROBERTS);
setEffectTypes(hWnd); setEffectTypes(hWnd);
_beginthread(edgeDetectingThread, 0, NULL) ;
break; break;
case WM_COMMAND: case WM_COMMAND:
@ -74,6 +88,7 @@ LRESULT CALLBACK mainWindowProcedure(HWND hWnd, UINT message, UINT wParam, LONG
break; break;
case WM_DESTROY: case WM_DESTROY:
runningThread = false;
PostQuitMessage(0); PostQuitMessage(0);
break; break;
@ -83,6 +98,27 @@ LRESULT CALLBACK mainWindowProcedure(HWND hWnd, UINT message, UINT wParam, LONG
return 0; 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(); detector.snapshot();
break; break;
case ID_DEVICE: case ID_PAUSE:
setPause(hWnd, !pause);
break; break;
case ID_OP_ROBERTS: case ID_OP_ROBERTS:
@ -111,6 +148,7 @@ void menuCommandSelected(HWND hWnd, UINT wParam) {
break; break;
case ID_ABOUT: case ID_ABOUT:
DialogBox(NULL, MAKEINTRESOURCE(IDD_ABOUT_DIALOG), hWnd, (DLGPROC)AboutDialogProc);
break; break;
case ID_EXIT: 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); * Установить тип оператора (ID_OP_ROBERTS, ID_OP_SOBEL, ID_OP_PREWITT);

View File

@ -4,20 +4,20 @@
class PrewittOperator : public AbstractOperator { class PrewittOperator : public AbstractOperator {
public: public:
CvMat* getHorizontalKernelMatrix() { void createHorizontalKernelMatrix() {
float matrix[9] = {-1, 0, 1, float matrix[9] = {-1, 0, 1,
-1, 0, 1, -1, 0, 1,
-1, 0, 1 }; -1, 0, 1 };
CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); horizontalMatrix = cvCreateMat(3, 3, CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix);
} }
CvMat* getVerticalKernelMatrix() { void createVerticalKernelMatrix() {
float matrix[9] = {-1,-1,-1, float matrix[9] = {-1,-1,-1,
0, 0, 0, 0, 0, 0,
1, 1, 1 }; 1, 1, 1 };
CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); verticalMatrix = cvCreateMat(3, 3, CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix);
} }
}; };

View File

@ -4,19 +4,19 @@
class RobertsOperator : public AbstractOperator { class RobertsOperator : public AbstractOperator {
public: public:
CvMat* getHorizontalKernelMatrix() { void createHorizontalKernelMatrix() {
float matrix[9] = {0, 0, 0, float matrix[9] = {0, 0, 0,
0, 1, 0, 0, 1, 0,
0, 0,-1 }; 0, 0,-1 };
CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); horizontalMatrix = cvCreateMat(3, 3, CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix);
} }
CvMat* getVerticalKernelMatrix() { void createVerticalKernelMatrix() {
float matrix[9] = {0, 0, 0, float matrix[9] = {0, 0, 0,
0, 0, 1, 0, 0, 1,
0,-1, 0 }; 0,-1, 0 };
CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); verticalMatrix = cvCreateMat(3, 3, CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix);
} }
}; };

View File

@ -4,19 +4,19 @@
class SobelOperator : public AbstractOperator { class SobelOperator : public AbstractOperator {
public: public:
CvMat* getHorizontalKernelMatrix() { void createHorizontalKernelMatrix() {
float matrix[9] = {-1, 0, 1, float matrix[9] = {-1, 0, 1,
-2, 0, 2, -2, 0, 2,
-1, 0, 1 }; -1, 0, 1 };
CvMat* kernel = cvCreateMat(3, 3, CV_32FC1); horizontalMatrix = cvCreateMat(3, 3, CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); horizontalMatrix = setupKernelMatrixFromArray(horizontalMatrix, matrix);
} }
CvMat* getVerticalKernelMatrix() { void createVerticalKernelMatrix() {
float matrix[9] = {-1,-2,-1, float matrix[9] = {-1,-2,-1,
0, 0, 0, 0, 0, 0,
1, 2, 1 }; 1, 2, 1 };
CvMat* kernel = cvCreateMat(3, 3,CV_32FC1); verticalMatrix = cvCreateMat(3, 3,CV_32FC1);
return setupKernelMatrixFromArray(kernel, matrix); verticalMatrix = setupKernelMatrixFromArray(verticalMatrix, matrix);
} }
}; };

View File

@ -27,7 +27,6 @@ bool WindowClass::registerClass() {
*/ */
void WindowClass::setToDefault() { void WindowClass::setToDefault() {
setStyle( CS_HREDRAW | CS_VREDRAW ); setStyle( CS_HREDRAW | CS_VREDRAW );
setIconType(IDI_APPLICATION);
setCursorType(IDC_ARROW); setCursorType(IDC_ARROW);
setBackgroundBrushColor(WHITE_BRUSH); setBackgroundBrushColor(WHITE_BRUSH);
setMenuName(L"MainMenu"); setMenuName(L"MainMenu");

View File

@ -3,7 +3,7 @@
#include <windows.h> #include <windows.h>
/** /**
* Класс регистрации WNDCLASS * Класс регистрации WNDCLASS
* @author aNNiMON * @author aNNiMON
*/ */
class WindowClass { class WindowClass {

Binary file not shown.