📄 marki.cpp
字号:
case 'R': // reject fLoad = fRejectCmd(); break; default: // unrecognized key, ignore it fLoad = false; }if (fLoad) { sLoadCurrentImage(MA_SHOW_ERR); InvalidateRect(hgMainWnd, NULL, false); // force repaint of entire window DisplayImageNbr(); // Because user may be holding the key down (auto-repeat) we need to force a // screen update -- else WM_PAINT gets queued behind WM_KEYDOWN and repaint // only gets done after all keypresses stop. Hence this call to WmPaint. WmPaint(hWnd); }}//-----------------------------------------------------------------------------static void WmMouseMove (LPARAM lParam){static int xOldMouse, yOldMouse;fgChug = false; // any mouse movement turns off chuggingSetCursor(LoadCursor (NULL, IDC_CROSS)); // this is needed, not sure whyint xMouse = LOWORD(lParam);int yMouse = HIWORD(lParam);// Windows feeds us repeated WM_MOUSE messages even// when the mouse hasn't moved. Hence the if below.if (xMouse != xOldMouse || yMouse != yOldMouse) { SetCursor(LoadCursor (NULL, IDC_CROSS)); xOldMouse = xMouse; yOldMouse = yMouse; }}//-----------------------------------------------------------------------------static void WmMouseRButtonDown (void){IdmNext();sLoadCurrentImage(MA_SHOW_ERR);InvalidateRect(hgMainWnd, NULL, false); // force repaint of entire window}//-----------------------------------------------------------------------------LRESULT CALLBACK WndProc (HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam){switch (iMsg) { case WM_CREATE: if (NULL == (hgDlgWnd = CreateDialog(hgAppInstance, sgDlg, hWnd, DlgProc))) SysErr("CreateDialog failed"); return 0; case WM_PAINT: WmPaint(hWnd); return 0; case WM_SIZE: WmSize(hWnd, iMsg, wParam, lParam); return 0; case WM_COMMAND: // toolbar buttons WmCommand(hWnd, iMsg, wParam, lParam); return 0; case WM_CLOSE: CheckSaveState(); SaveStateToRegistry(hgMainWnd, hgDlgWnd); break; // call default window close handler case WM_DESTROY: KillTimer(hgMainWnd, IdTimer_Chug); PostQuitMessage(0); return 0; case WM_LBUTTONDOWN: // put a mark this image Wm_LButtonDown(lParam); break; case WM_RBUTTONDOWN: // move to next image WmMouseRButtonDown(); break; case WM_MOUSEMOVE: // set cursor to cross WmMouseMove(lParam); break; case WM_KEYDOWN: // user hit a key WmKeydown(hWnd, wParam); return 0; case WM_TIMER: if (fgChug) WmTimer(); return 0; }return DefWindowProc(hWnd, iMsg, wParam, lParam);}//-----------------------------------------------------------------------------static char *sCreateToolbar (HWND hWnd) // return error msg, or null if no error{hgToolbarBmp = LoadBitmap(hgAppInstance, MAKEINTRESOURCE(IDR_MARKI_BUTTONS));if (!hgToolbarBmp) return "CreateToolbar";int nButtons;for (nButtons = 0; nButtons < 64; nButtons++) // calculate nButtons if (gToolbarButtons[nButtons].iBitmap < 0) break;hgToolbar = CreateToolbarEx( hWnd, // parent window WS_VISIBLE|TBSTYLE_FLAT|TBSTYLE_TOOLTIPS, 1, // child ID of the this toolbar child window 1, // nBitmaps NULL, // hBmInst (UINT)hgToolbarBmp, // wBMID gToolbarButtons, // lpButtons nButtons, // iNumButtons (must include Separators) 0, 0, 0, 0, // position etc. sizeof(TBBUTTON));if (!hgToolbar) return "CreateTooobar failed";return NULL;}//-----------------------------------------------------------------------------char *sInit (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int iCmdShow){WNDCLASSEX wndclass;hgAppInstance = hInstance;// pgLogFile is defined in common/util.cppif (NULL == (pgLogFile = fopen(sgMarkiLog, "wt"))) return "Can't open log file";gStartTime = clock();fprintf(pgLogFile, "%s %s\n", sgProgramName, sgVersion);wndclass.cbSize = sizeof(wndclass);wndclass.style = CS_HREDRAW | CS_VREDRAW;wndclass.lpfnWndProc = WndProc;wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0;wndclass.hInstance = hInstance;wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.lpszMenuName = NULL;wndclass.lpszClassName = sgClass;wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if (!RegisterClassEx(&wndclass)) return "RegisterClass failed";// Create the same window layout as last time by looking at registry.// If nothing in registry, then GetStateFromRegistry returns biggest possible main window.int xPos, yPos, xSize, ySize;GetStateFromRegistry(&xPos, &yPos, &xSize, &ySize, &igCrop, &fgAutoNext, &fgEqualize, &fgConnectDots, &xgDlg, &ygDlg);hgMainWnd = CreateWindow(sgProgramName, sgProgramName, // window caption WS_OVERLAPPEDWINDOW, // window style xPos, // x position yPos, // y position xSize, // x size ySize, // y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parametersif (!hgMainWnd) return "CreateWindowEx failed";if (char *sErrMsg = sCreateToolbar(hgMainWnd)) return sErrMsg;// tell buttons to display themeselves as depressed or notSendMessage(hgToolbar, TB_CHECKBUTTON, IDM_AutoNext, (LPARAM)MAKELONG(fgAutoNext, 0));SendMessage(hgToolbar, TB_CHECKBUTTON, IDM_Equalize, (LPARAM)MAKELONG(fgEqualize, 0));SendMessage(hgToolbar, TB_CHECKBUTTON, IDM_ConnectDots, (LPARAM)MAKELONG(fgConnectDots, 0));return NULL; // success}//-----------------------------------------------------------------------------// This should always be called before exiting the programstatic int __cdecl fShutdown (char *pArgs, ...) // always returns 0{va_list pArg;char sMsg[1000]; // big enough for my stringsif (!pgLogFile) pgLogFile = stdout;sMsg[0] = 0;if (pArgs) { va_start(pArg, pArgs); vsprintf(sMsg, pArgs, pArg); va_end(pArg); Err(sMsg); }if (sMsg && sMsg[0]) { fprintf(pgLogFile, "Msg %s\n", sMsg); CheckSaveState(); // give user chance to save if we have a fatal error }clock_t ElapsedTime = clock() - gStartTime;if (ElapsedTime/CLOCKS_PER_SEC > 5) // print time if we have been in this prog for more than 5 secs { FormatTime(sMsg, double(ElapsedTime)); lprintf("%s elapsed\n", sMsg); }if (hgAppInstance) { UnregisterClass(sgProgramName, hgAppInstance); hgAppInstance = NULL; }if (hgToolbar) { DestroyWindow(hgToolbar); hgToolbar = NULL; }if (hgToolbarBmp) { DeleteObject((HGDIOBJ)hgToolbarBmp); hgToolbarBmp = NULL; }return 0;}//-----------------------------------------------------------------------------static int __cdecl CompareOffsetFileNames (const void *pArg0, const void *pArg1) // for qsort{return _stricmp(&(*(char**)pArg0)[FNAME_OFFSET], &(*(char**)pArg1)[FNAME_OFFSET]);}//-----------------------------------------------------------------------------int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int iCmdShow){MSG msg;char *sErrMsg;//InitMallocDebug();// If this program is running already, ask the user if he or she really// wants to run it twice. (The log files will get mixed up). The old standard technique// of checking for multiple program instances using hPrevInstance is deprecated.hgProgramMutex = CreateMutex(NULL, true, sgProgramName);if (GetLastError() == ERROR_ALREADY_EXISTS && !fYesNoMsg(false, "%s is running already. Run it twice?", sgProgramName)) return fShutdown(NULL);#if USE_SHAPE_FILEif (char *sErrMsg = sParseCmdLine(pCmdLine)) { lprintf(sErrMsg); // print usage (but don't put up a window) return fShutdown(NULL); }#endifif (sErrMsg = sInit(hInstance, hPrevInstance, pCmdLine, iCmdShow)) return fShutdown(sErrMsg);#if USE_SHAPE_FILEReadShapeFile(&gShapesOrg, gTagStrings, sgImageDirs, sgTagRegExp, gAttrMask1, gAttrMask2, sgShapeFile, QUIET);if (fgErr) return fShutdown(NULL); // error message has already been issuedDiscardGlobalFaceDetectorShapes(&gShapesOrg, gTagStrings, AT_DISCARD_UNDERSCORES);ngImages = gShapesOrg.size();if (ngImages == 0) Err("No images");// Convert all shapes to have the same number of landmarks as the first shape// Unspecified landmarks are set to 0,0int nChanged = 0;ngPoints = iGetWantedPoints(gShapesOrg, gTagStrings, gAttrMask1, gAttrMask2);lprintf("\nConverting all shapes the same number of landmarks %d as the first shape\n", ngPoints);for (int iShape = 0; iShape < ngImages && !fgErr; iShape++) if (fConvertShapeToInternalFormat(gShapesOrg[iShape], ngPoints)) nChanged++;lprintf("Got %d shape%s, reference shape has %d landmarks\n", ngImages, ((ngImages==1)? "":"s"), ngPoints);if (nChanged) lprintf("Converted %d shape%s to %d points per shape, %d shape%s unchanged\n", nChanged, ((nChanged!=1)? "s":""), ngPoints, ngImages-nChanged, ((ngImages-nChanged!=1)? "s":""));if (ngPoints != CONF_nPointsXm2vts) // put warning in until I figure out exactly what to do here Warn("ngPoints %d != CONF_nPointsXm2vts %d", ngPoints, CONF_nPointsXm2vts);if (fgErr) return fShutdown(NULL); // error message has already been issuedgShapes = gShapesOrg; // vector copyif (igLandmark >= ngPoints) return fShutdown("Landmark -l %d: no such landmark (shapes in %s have only %d landmarks)", igLandmark, sgShapeFile, ngImages);#else // not USE_SHAPE_FILE// Put the filenames specified by sFileSpec into the gTagStrings array and update ngImages//// We prefix the strings with FNAME_OFFSET nbr of blanks for indexing compatibility// with strings returned by ReadShapeFile//// This code is a modified copy of misc.cpp:void GetFileNamesIntoGlobalFileArray(char sFileSpec[])// Use copy instead of original func because I want slightly different error handling// and I want to use gTagStrings instead of sgFilesgTagStrings.resize(CONF_nMaxMatArray);char sFileSpec[SLEN];strcpy(sgImageDirs, sgDefaultImageDir);sprintf(sFileSpec, "%s/*.bmp", sgImageDirs);char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];long hFile;struct _finddata_t FileData;// get directory prefix to sFileSpec if any, because findfirst drops it_splitpath(sFileSpec, drive, dir, fname, ext);// findnext returns files in random order. We want alphabetic so we// have to get all the files first and then sort them, and then use them.if ((hFile = _findfirst(sFileSpec, &FileData)) == -1L) { // try to give a helpful message here _splitpath(sFileSpec, drive, dir, fname, ext); return fShutdown("No match for \"%s\"", sFileSpec); }if (strlen(FileData.name) > sizeof(sgFiles[0]) - 3) // 3 may be over rigorous return fShutdown("File name %s is too long", FileData.name);//logprintf("File %s\n", FileData.name);// We prefix the strings with FNAME_OFFSET nbr of blanks for indexing compatibility// with strings returned by ReadShapeFilechar *sDummyPrefix = "_____________________";// TODO is the following correct now that gTagStrings is a StringVec?gTagStrings[ngImages] = (char *)malloc(strlen(FileData.name)+1+FNAME_OFFSET);gTagStrings[ngImages] = (char *)malloc(strlen(FileData.name)+1+FNAME_OFFSET);strncpy(gTagStrings[ngImages], sDummyPrefix, FNAME_OFFSET);strcpy(&gTagStrings[ngImages++][FNAME_OFFSET], FileData.name);while (_findnext(hFile, &FileData) == 0 && !fgUserInt) { gTagStrings[ngImages] = (char *)malloc(strlen(FileData.name)+1+FNAME_OFFSET); strncpy(gTagStrings[ngImages], sDummyPrefix, FNAME_OFFSET); strcpy(&gTagStrings[ngImages++][FNAME_OFFSET], FileData.name); if (ngImages == CONF_nMaxFiles) fShutdown("Too many files matching %s (max is %d)", sFileSpec, CONF_nMaxFiles); }_findclose(hFile);qsort((void *)gTagStrings, size_t(ngImages), sizeof(char *), CompareOffsetFileNames);#endif // not USE_SHAPE_FILEif (sErrMsg = sLoadCurrentImage(MA_NO_SHOW_ERR)) return fShutdown(sErrMsg);ShowWindow(hgMainWnd, SW_SHOW);UpdateWindow(hgMainWnd);while (GetMessage(&msg, NULL, 0, 0)) { if (fgErr) break; TranslateMessage(&msg); DispatchMessage(&msg); }if (fgErr) fShutdown("Early exit because of error");else fShutdown(NULL);return msg.wParam;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -