영상처리
#include <windows.h>
#include"vfw.h"
#pragma comment(lib,"vfw32.lib")
#define ID_HISTOGRAM 101
#define ID_CAPTURE 102
#define ID_GRAY 103
#define ID_FIX 104
#define ID_BINARY 105
#define ID_SCROLL 106
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
LRESULT CALLBACK FramInfo(HWND,LPVIDEOHDR);
HINSTANCE g_hInst;
HWND hWndMain;
HWND hVFW;
HWND Hwndmain;
HBITMAP hBit;
BITMAPINFO Bm;
LPCTSTR IpszClass=TEXT("VFW");
int flag = 0; // 히스토그램 ON/OFF 제어 flag 변수
int flag_cap = 0; // 캡쳐 제어 flag 변수
int flag_mode = 0; // 화면 모드 flag 변수
int temp = 0; // 화면 모드 임시 저장 변수
int scrl = 128; // 스크롤바 수치 저장 변수
RECT rt = {650, 0, 1000, 300}; // 캡쳐 무효화 영역
HWND hHisto, hCap, hGray, hFix, hBin, hScrl; // 버튼 핸들 변수
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR IpszCmdParam,
int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst = hInstance;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon = LoadIcon(NULL,IDC_APPSTARTING);
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = (WNDPROC)WndProc;
WndClass.lpszClassName = IpszClass;
WndClass.lpszMenuName = NULL;
WndClass.style = CS_HREDRAW|CS_VREDRAW;
RegisterClass(&WndClass);
hWnd= CreateWindow(IpszClass,
IpszClass,
WS_OVERLAPPEDWINDOW| WS_VSCROLL,
CW_USEDEFAULT,
CW_USEDEFAULT,
1250,
650,
NULL,
(HMENU)NULL,
hInstance,
NULL);
ShowWindow(hWnd,nCmdShow);
hWndMain=hWnd;
while(GetMessage(&Message,0,0,0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return (int)Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC Hdc;
int TempPos;
switch(iMessage)
{
case WM_CREATE:
Hwndmain=hWnd;
Hdc=GetDC(hWnd);
// 컨트롤들을 각각 핸들에 저장
hHisto = CreateWindow(TEXT("button"), TEXT("Show Histogram"), WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, 20, 270, 120, 30, hWnd, (HMENU)ID_HISTOGRAM, g_hInst, NULL);
hCap = CreateWindow(TEXT("button"), TEXT("Capture CAM"), WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, 170, 270, 120, 30, hWnd, (HMENU)ID_CAPTURE, g_hInst, NULL);
hGray = CreateWindow(TEXT("button"), TEXT("Gray Mode"), WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, 20, 310, 120, 30, hWnd, (HMENU)ID_GRAY, g_hInst, NULL);
hFix = CreateWindow(TEXT("button"), TEXT("Blue -> White"), WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, 170, 310, 120, 30, hWnd, (HMENU)ID_FIX, g_hInst, NULL);
hBin = CreateWindow(TEXT("button"), TEXT("Binary Mode"), WS_CHILD | WS_VISIBLE |
BS_PUSHBUTTON, 20, 350, 120, 30, hWnd, (HMENU)ID_BINARY, g_hInst, NULL);
hScrl = CreateWindow(TEXT("scrollbar"), NULL, WS_CHILD | WS_VISIBLE |
SBS_HORZ, 0, 240, 320, 20, hWnd, (HMENU)ID_SCROLL, g_hInst, NULL);
SetScrollRange(hScrl, SB_CTL, 0, 255, TRUE); // 스크롤 범위(0 ~ 255) 지정
SetScrollPos(hScrl, SB_CTL, 128, TRUE); // 스크롤 위치 지정(128)
EnableWindow(hScrl, FALSE);
hVFW=capCreateCaptureWindow(TEXT("VFW"), // 캡쳐 윈도우 생성
WS_CHILD | WS_VISIBLE,
0,0,1,1,hWnd,0); // 원본 화면 위치
capDriverConnect(hVFW,0); // 캡쳐 드라이브와 캡쳐 윈도우 연결
capPreviewRate(hVFW,1);
capPreview(hVFW,TRUE); // 프리뷰를 시작하거나 중지
capGetVideoFormat(hVFW,&Bm,sizeof(Bm)); // 캡쳐되는 이미지의 정보를 얻어냄
hBit=CreateCompatibleBitmap(Hdc, // hBit에 비트맵의 핸들을 저장
Bm.bmiHeader.biWidth,
Bm.bmiHeader.biHeight);
if(capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)
{
return FALSE;
}
ReleaseDC(hWnd,Hdc);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_HISTOGRAM: // 히스토그램 ON/OFF
flag ^= 1;
if(flag == 1)
SetWindowText(hHisto, TEXT("Off Histogram")); // 버튼 컨트롤 텍스트 변경
else
SetWindowText(hHisto, TEXT("Show Histogram"));
break;
case ID_CAPTURE: // 캡쳐 ON/OFF
if(flag_cap == 0) // 캡쳐 OFF일때
{
SetWindowText(hCap, TEXT("Clear Capture"));
flag_cap = 1;
}
else if(flag_cap == 2) // 캡쳐 ON일때
{
SetWindowText(hCap, TEXT("Capture CAM"));
InvalidateRect(hWnd, &rt, TRUE);
flag_cap = 0;
}
break;
case ID_GRAY: // 그레이 모드 ON/OFF
if(flag_mode == 1) // 그레이 모드 ON일때
{
SetWindowText(hGray, TEXT("Gray Mode"));
flag_mode = 0;
}
else // 그레이 모드 OFF일때
{
SetWindowText(hGray, TEXT("Normal Mode"));
flag_mode = 1;
}
break;
case ID_FIX: // Blue -> White모드 ON/OFF
if(flag_mode == 2) // Blue -> White 모드 ON일때
{
SetWindowText(hFix, TEXT("Blue -> White"));
flag_mode = 0;
}
else // Blue -> White 모드 OFF일때
{
SetWindowText(hFix, TEXT("Return"));
flag_mode = 2;
}
break;
case ID_BINARY: // 2진화모드 ON/OFF
if(flag_mode == 3) // 2진화모드 ON일때
{
SetWindowText(hBin, TEXT("Binary Mode"));
EnableWindow(hScrl, FALSE);
flag_mode = 0;
}
else // 2진화모드 OFF일때
{
SetWindowText(hBin, TEXT("Return"));
EnableWindow(hScrl, TRUE);
flag_mode = 3;
}
break;
}
break;
case WM_HSCROLL: // 윈도우 스크롤바가 WM_HSCROLL 메시지 보낼때
if((HWND)lParam == hScrl) TempPos = scrl; // 스크롤바의 윈도우 핸들이 hScrl일때 TempPos에 scrl값 저장
switch(LOWORD(wParam)) // 스크롤바의 어디를 눌렀는지 정보를 나타냄
{
case SB_LINELEFT: // 이 값들은 책 참조^^
TempPos = max(0, TempPos - 1);
break;
case SB_LINERIGHT:
TempPos = min(255, TempPos + 1);
break;
case SB_PAGELEFT:
TempPos = max(0, TempPos - 10);
break;
case SB_PAGERIGHT:
TempPos = min(255, TempPos + 10);
break;
case SB_THUMBTRACK: // 드래그할때 값 저장
TempPos = HIWORD(wParam);
break;
}
if((HWND)lParam == hScrl) scrl = TempPos; // 변경된 스크롤바 값을 scrl에 저장
SetScrollPos((HWND)lParam, SB_CTL, TempPos, TRUE); // 현재 값에 맞게 스크롤바 위치 지정
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
LRESULT CALLBACK FramInfo(HWND hVFW,LPVIDEOHDR VideoHdr)
{
HDC Hdc;
HDC hMemDC;
HBITMAP OldBitmap;
int iCntX;
int iCntY;
int Jump;
int histo[256] = {0, };
int col = 0;
Hdc = GetDC(Hwndmain);
hMemDC = CreateCompatibleDC(Hdc);
OldBitmap = (HBITMAP)SelectObject(hMemDC,hBit);
Jump = 0;
for(iCntY = 0; iCntY<Bm.bmiHeader.biHeight; ++iCntY)
{
for(iCntX = 0; iCntX<Bm.bmiHeader.biWidth ; ++iCntX)
{
if(flag_mode == 0) // 평상시 캠영상
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(VideoHdr->lpData[Jump + 2],VideoHdr->lpData[Jump + 1],VideoHdr->lpData[Jump]));
}
else if(flag_mode == 1) // 그레이모드 캠영상
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(VideoHdr->lpData[Jump],VideoHdr->lpData[Jump],VideoHdr->lpData[Jump]));
}
else if(flag_mode == 2) // Blue to White 캠영상
{
if(VideoHdr->lpData[Jump+2] < 130 && VideoHdr->lpData[Jump+1] < 130 && VideoHdr->lpData[Jump] > 100)
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(255, 255, 255));
}
else
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(VideoHdr->lpData[Jump + 2],VideoHdr->lpData[Jump + 1],VideoHdr->lpData[Jump]));
}
}
else if(flag_mode == 3) // 이진화 캠영상
{
if(VideoHdr->lpData[Jump] < scrl) // 현재 스크롤바 값(scrl)과 비교하여 이진화 처리
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(0, 0, 0));
}
else
{
SetPixel(hMemDC,iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,
RGB(255, 255, 255));
}
}
histo[VideoHdr->lpData[Jump]]++; // 히스토그램 수치 저장 배열
Jump +=3;
}
}
TextOut(Hdc, 435, 270, TEXT("- HISTOGRAM -"), 14);
Rectangle(Hdc, 350, 0, 650, 251); // 그래프 영역 초기화를 위해 출력하기 전에 사각형을 그려줌
TextOut(Hdc, 350, 255, TEXT("0"), 1); // x축 수치 표현
TextOut(Hdc, 410, 255, TEXT("64"), 2);
TextOut(Hdc, 473, 255, TEXT("128"), 3);
TextOut(Hdc, 535, 255, TEXT("192"), 3);
TextOut(Hdc, 600, 255, TEXT("255"), 3);
TextOut(Hdc, 625, 255, TEXT("밝기"), 4);
TextOut(Hdc, 325, 200, TEXT("250"), 3); // y축 수치 표현
TextOut(Hdc, 325, 150, TEXT("500"), 3);
TextOut(Hdc, 325, 100, TEXT("750"), 3);
TextOut(Hdc, 318, 50, TEXT("1000"), 4);
TextOut(Hdc, 318, 0, TEXT("수치"), 4);
if(flag == 1) // 히스토그램 버튼
{
for(iCntX = 0; iCntX<256 ; ++iCntX)
{
MoveToEx(Hdc, 350 + 1 *iCntX, 250, NULL); // 해당 x축 위치로 이동
LineTo(Hdc, 350 + 1 * iCntX, 250 - histo[iCntX] / 5); // 해당 수치만큼 y축으로 선 긋기
}
}
if(flag_cap == 1) // 캡쳐 버튼
{
TextOut(Hdc, 780, 250, TEXT("- CAPTURE -"), 12);
BitBlt(Hdc,660,0,Bm.bmiHeader.biWidth,
Bm.bmiHeader.biHeight,
hMemDC,0,0,SRCCOPY);
flag_cap = 2;
}
BitBlt(Hdc,0,0,Bm.bmiHeader.biWidth,
Bm.bmiHeader.biHeight,
hMemDC,0,0,SRCCOPY);
SelectObject(hMemDC,OldBitmap);
DeleteDC(hMemDC);
ReleaseDC(Hwndmain,Hdc);
return 0;
}