From 3e57fbb9d2983f4f9f8026d367796cdc097f6fa3 Mon Sep 17 00:00:00 2001 From: Victor Date: Fri, 6 Apr 2012 01:17:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=B5=D1=82=D0=B5=D0=BA=D1=82=D0=BE=D1=80=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D0=BD=D0=B5=D0=B9.=20=D0=A3=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B0=20=D1=83=D1=82=D0=B5=D1=87?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=B0=D0=BC=D1=8F=D1=82=D0=B8.=20=D0=9E?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=BD=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D0=B2?= =?UTF-8?q?=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=BC=20=D0=BF=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5.=20=D0=9F=D1=83=D0=BD=D0=BA=D1=82=20"=D0=A3=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=B0"=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D1=91=D0=BD=20=D0=BD=D0=B0=20"=D0=9F?= =?UTF-8?q?=D0=B0=D1=83=D0=B7=D0=B0".=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=B4=D0=B8=D0=B0=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B5=20=D0=BE=D0=BA=D0=BD=D0=BE=20"=D0=9E?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B5".?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AbstractOperator.cpp | 21 +++++++++----- src/AbstractOperator.h | 11 +++++--- src/DonNUEdgeDetector.rc | 58 +++++++++++++++++++++++++++++++++++---- src/EdgeDetector.cpp | 14 +++++++--- src/Main.cpp | 51 ++++++++++++++++++++++++++++++++-- src/PrewittOperator.h | 12 ++++---- src/RobertsOperator.h | 12 ++++---- src/SobelOperator.h | 12 ++++---- src/WindowClass.cpp | 1 - src/WindowClass.h | 2 +- src/resource.h | Bin 2258 -> 1345 bytes 11 files changed, 152 insertions(+), 42 deletions(-) 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 10c454ef52e7d6c240922e1bcb1a26773ad184f3..ee18b5c8e2d57ad07df80500e29d3caee5eb4a53 100644 GIT binary patch literal 1345 zcmaKsPj90z5XJA6`W-CwSgC=wyV^ZE_9SZ+Y-F2ka~h?IsaQoIC1n4o>UUoQyA336 zxgg*-k2jAQCX<&JsgOekl7nOd%2TNi*|Jg_H@ok50r99)l)&^%fsx(ns>1n-;$tHi{X|4Sa+T zLR4A*O$-`K^|^nq9!Dc}m7!Ks(AETA5yUeM--SKb?vjZ|vw~jTc=aTp-Q$B~j^6$7 z2MSs<0~}^EVD`O6d-X4)R$+!pi@A_A;HOnT!{?eV4Wr3<{4M_VR9(mg=-{{V`0XI~ z|K7umcHUdOTV&~eH^i^%>acCd&(-$e_N1tHq;kJV{q)1{^uFV~nX>R4@uO>VE);q@ z>H&E7pc*~VK)I6163sH5s>B={L0^p$9xZAxD%T8fL6iI~fH?Xbf|*KFD*2dgH|1`y jv`1~f=2olZ1ouljnEWH{O~R>k`}1f=%~hMSIG+Ck@QgVz literal 2258 zcmbW3TW{Jx5QXP8mGU1f^|4ZDE)VS^wP{)v48n#cPgVn=qKZHYp%+#C>rKD2%Z3)& z##F1tyX*DYGiPRJc>LY6mi?rq*0;hE>)3#vx>0Jey=Ru$FWRv^V{gkM>)G5Uc5h2t z(P#F++L*PKt?iTDF^la5EwaycYYX~4>kmAqtj$@Ouxriimidg8J4PpeoiGB+@4m4g z>`6Fh0jm*grVcgXy$~n-F2O&cPo5CO^|`|rx)?-QlGqR%d)8*0@|2w;-ZX2c_R>z> z3Hy-S*dK%5r4KnRN84e|DMCJT$W^=xe2{`P;Q0=;yasL8nhVg?s<{{Nyh4*hP{Sz! z-SaO~rhxYwIFJ4VKcJsi>h5E940|aaST%bF^ovUE`|dVueV7qH8FsYsXKqJN%_GT= z)gBa9!FPSsP+a679m2B-`T*RHeRRHT>dnBtEY{R|VkhiQ0=;iTIrmxRFhbdEi zdph=()*(8icfI#s)p$=h1@;fo_L8pK*i46@z<%^g(A#zm&)A_iiRXa+dM|fz9=piP z_&r45vx>Oh)z*7%dn=AM-VfhzD@aO4{_g6AYQT)@u%-s6j(l|$WXzYUo2|A(QRt8yN`BV zJfrxzrgA8sbs3l4cI7*rUGR!h2)c<$>2MT2m AjQ{`u