Исправлена работа детекторов граней. Устранена утечка памяти. Обработка выполняется в новом потоке. Пункт "Устройства" изменён на "Пауза". Добавлено диалоговое окно "О программе".
This commit is contained in:
parent
5634f98ec3
commit
3e57fbb9d2
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
51
src/Main.cpp
51
src/Main.cpp
@ -1,6 +1,7 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <commctrl.h>
|
||||
#include <process.h>
|
||||
#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);
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
@ -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);
|
||||
}
|
||||
};
|
@ -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");
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
/**
|
||||
* Класс регистрации WNDCLASS
|
||||
* Класс регистрации WNDCLASS
|
||||
* @author aNNiMON
|
||||
*/
|
||||
class WindowClass {
|
||||
|
BIN
src/resource.h
BIN
src/resource.h
Binary file not shown.
Loading…
Reference in New Issue
Block a user