영상처리

영상처리

빛나는 미래 2010. 1. 5. 19:06


#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;
}