영상 처리 - 복제 화면 띄우기, RGB값 변화에 따른 화면 출력
내장형 하드웨어/WINAPI / 2011. 11. 23. 16:07
→ 영상 처리 예제 소스
→ 아래 함수를 이용하여 캠에서 들어오는 영상을 복제해서 뿌린다.
→ 위 함수는 화면에 점을 출력하는 함수로 for문을 돌려 영상을 출력(원본 영상의 복사)한다.
→ 출력은 원본을 제외한 3가지로 BLUE, GREEN, RED 의 색상만을 각각 출력해 본다.
→ 위의 실행 결과는 왼쪽 처음부터 오른쪽으로 각각
→ 원본영상, 복사 영상
→ BMP출력, 영상+BMP
→ 영상-BMP, 영상*BMP
→ 6가지의 출력을 나타낸 것이다.
#include<windows.h>
#include<vfw.h>
HBITMAP hBm;
BITMAPINFO BInfo;
HWND hWnd;
HWND hVfw;
HDC hdc;
// 라이브러리를 추가하는 것을 comment - 수동식
// project setting을 변화시키면 project를 통채로 복사해야 하지만
// #pragama comment를 사용하면 소스만 복사해도 동작한다.
#pragma comment (lib, "vfw32.lib")
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp);
/* 고정 형식 */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 메세지 처리 함수
HINSTANCE g_hInst; // instance 전역 변수 선언
LPCTSTR lpszClass = TEXT("VFW32"); // 윈도 클래스 이름 정의
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
MSG Message; // MSG 구조체 사용
WNDCLASS WndClass; // WndClass 구조체 사용
g_hInst = hInstance; // 윈도우 클래스를 등록하는 프로그램의 번호이며 WinMain의 인수로 전달된 hInstance값을 그대로 대입
/* 윈도우 클래스 정의 */
WndClass.cbClsExtra = 0; // 예약 영역, 사용하지 않을 경우는 0
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // HBRUSH 타입으로 형변환
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // 윈도우가 사용할 마우스 커서지정
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 윈도우가 사용할 아이콘 지정
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc; // 윈도우의 메시지 처리 함수를 지정
WndClass.lpszClassName = lpszClass; // 윈도우 클래스의 이름을 문자열로 정의 - 여기서는 First라는 문자열을 보내준다.
WndClass.lpszMenuName = NULL; // 프로그램이 사용할 메뉴를 지정
WndClass.style = CS_HREDRAW|CS_VREDRAW; // 윈도우가 어떤 형태를 가질 것인가-윈도우의크기가 변할 경우 윈도우를 다시 그린다.
/* 윈도우 클래스 등록 */
RegisterClass(&WndClass); // WndClass 구조체의 번지를 전달
// 메모리 상에 윈도우 생성
hWnd=CreateWindow(lpszClass, TEXT("Video for Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);
/* 인자의 의미 -> (윈도우 클래스 이름, 타이틀바에 나타날 문자열-윈도우 네임(클래스 이름과 같게 하려면 lpszClass),
윈도우의 형태 지정, 윈도우의 크기와 위치(픽셀단위)-x, y, nWidth, nHeight,
부모 윈도우가 있을 경우 부모윈도우의 핸들-hWndParent, 윈도우에서 사용할 메뉴의 핸들-hmenu,
프로그램의 핸들 지정-hinst(프로그램이 종료될 때 파괴되지 않은 윈도우를 자동으로 파괴),
여러개의 윈도우를 만들때 각 윈도우에 고유의 파라미터를 전달하는 특수 목적에 사용-lpvParam)
*/
/* 화면에 윈도우 표시 */
ShowWindow(hWnd, nCmdShow); // CreateWindow 함수가 리턴한 핸들을 이용하여 출력
/* 사용자로부터의 메시지 처리*/
while(GetMessage(&Message, NULL, 0, 0)) // 메시지 큐에서 메시지 읽어옴,
// WN_QUIT이면 False 리턴 후 while문을 빠져나간다.
{
TranslateMessage(&Message); // 키보드 입력 처리
// 만약 A키를 누르면 A문자가 입력되었다는 메시지를 만들어 낸다.
DispatchMessage(&Message); // 큐에서 꺼낸 메시지를 WndProc 함수의 iMAssage로 전달
}
return (int)Message.wParam; // 메시지 루프 종료 후 이 프로그램을 실행시킨 OS로 리턴
}
// 사용자와 시스템이 보내오는 메시지를 처리
// 운영체제가 호출하는 함수는 CALLBACK 표시, LRESULT = 4byte long
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage) // 운영체제로부터 들어온 메시지에 대한 처리
{
/* 고정 형식 */
case WM_CREATE:
hdc = GetDC(hWnd);
// 320x240으로 캡쳐, 부모 윈도우(hWnd),
// 창이 만들어 진다. - 실제 생성되지는 않는다.
hVfw = capCreateCaptureWindow(TEXT("Video for Window"), WS_CHILD|WS_VISIBLE, 10, 10, 320, 240, hWnd, 0);
// usb를 통해 연결된 카메라 장치를 찾아 연결해 준다.
capDriverConnect(hVfw, 0);
// hVfw, 1ms - 화면에 보이는 속도(Rate)
capPreviewRate(hVfw, 1);
// Video 포멧을 확인하고 정보를 넣는다.
capGetVideoFormat(hVfw, &BInfo, sizeof(BITMAPINFO));
BInfo.bmiHeader.biWidth = 320;
BInfo.bmiHeader.biHeight = 240;
capSetVideoFormat(hVfw, &BInfo, sizeof(BITMAPINFO));
// 자동으로 라이브러리에서 Emb_Draw()를 호출해 준다.
capSetCallbackOnFrame(hVfw, Emb_Draw);
// 화면에 띄운다.(TRUE)
capPreview(hVfw, TRUE);
return 0;
case WM_LBUTTONDOWN:
return 0;
case WM_DESTROY: // 운영체제로부터 들어온 메시지에 대한 처리 - 여기서는 윈도우가 파괴되었음을 알린다.
ReleaseDC(hWnd, hdc);
PostQuitMessage(0); // WM_QUIT 메시지를 보냄
return 0;
}
// switch 문에서 처리하지 않은 메시지를 처리
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
// HWND, long *
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
SetPixel(hdc, xPos+420, yPos+10, RGB(0, 0, lp->lpData[iCnt])); // 블루
SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
return 0;
}
→ 실행 결과#include<vfw.h>
HBITMAP hBm;
BITMAPINFO BInfo;
HWND hWnd;
HWND hVfw;
HDC hdc;
// 라이브러리를 추가하는 것을 comment - 수동식
// project setting을 변화시키면 project를 통채로 복사해야 하지만
// #pragama comment를 사용하면 소스만 복사해도 동작한다.
#pragma comment (lib, "vfw32.lib")
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp);
/* 고정 형식 */
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 메세지 처리 함수
HINSTANCE g_hInst; // instance 전역 변수 선언
LPCTSTR lpszClass = TEXT("VFW32"); // 윈도 클래스 이름 정의
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
MSG Message; // MSG 구조체 사용
WNDCLASS WndClass; // WndClass 구조체 사용
g_hInst = hInstance; // 윈도우 클래스를 등록하는 프로그램의 번호이며 WinMain의 인수로 전달된 hInstance값을 그대로 대입
/* 윈도우 클래스 정의 */
WndClass.cbClsExtra = 0; // 예약 영역, 사용하지 않을 경우는 0
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // HBRUSH 타입으로 형변환
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // 윈도우가 사용할 마우스 커서지정
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 윈도우가 사용할 아이콘 지정
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = WndProc; // 윈도우의 메시지 처리 함수를 지정
WndClass.lpszClassName = lpszClass; // 윈도우 클래스의 이름을 문자열로 정의 - 여기서는 First라는 문자열을 보내준다.
WndClass.lpszMenuName = NULL; // 프로그램이 사용할 메뉴를 지정
WndClass.style = CS_HREDRAW|CS_VREDRAW; // 윈도우가 어떤 형태를 가질 것인가-윈도우의크기가 변할 경우 윈도우를 다시 그린다.
/* 윈도우 클래스 등록 */
RegisterClass(&WndClass); // WndClass 구조체의 번지를 전달
// 메모리 상에 윈도우 생성
hWnd=CreateWindow(lpszClass, TEXT("Video for Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU)NULL, hInstance, NULL);
/* 인자의 의미 -> (윈도우 클래스 이름, 타이틀바에 나타날 문자열-윈도우 네임(클래스 이름과 같게 하려면 lpszClass),
윈도우의 형태 지정, 윈도우의 크기와 위치(픽셀단위)-x, y, nWidth, nHeight,
부모 윈도우가 있을 경우 부모윈도우의 핸들-hWndParent, 윈도우에서 사용할 메뉴의 핸들-hmenu,
프로그램의 핸들 지정-hinst(프로그램이 종료될 때 파괴되지 않은 윈도우를 자동으로 파괴),
여러개의 윈도우를 만들때 각 윈도우에 고유의 파라미터를 전달하는 특수 목적에 사용-lpvParam)
*/
/* 화면에 윈도우 표시 */
ShowWindow(hWnd, nCmdShow); // CreateWindow 함수가 리턴한 핸들을 이용하여 출력
/* 사용자로부터의 메시지 처리*/
while(GetMessage(&Message, NULL, 0, 0)) // 메시지 큐에서 메시지 읽어옴,
// WN_QUIT이면 False 리턴 후 while문을 빠져나간다.
{
TranslateMessage(&Message); // 키보드 입력 처리
// 만약 A키를 누르면 A문자가 입력되었다는 메시지를 만들어 낸다.
DispatchMessage(&Message); // 큐에서 꺼낸 메시지를 WndProc 함수의 iMAssage로 전달
}
return (int)Message.wParam; // 메시지 루프 종료 후 이 프로그램을 실행시킨 OS로 리턴
}
// 사용자와 시스템이 보내오는 메시지를 처리
// 운영체제가 호출하는 함수는 CALLBACK 표시, LRESULT = 4byte long
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage) // 운영체제로부터 들어온 메시지에 대한 처리
{
/* 고정 형식 */
case WM_CREATE:
hdc = GetDC(hWnd);
// 320x240으로 캡쳐, 부모 윈도우(hWnd),
// 창이 만들어 진다. - 실제 생성되지는 않는다.
hVfw = capCreateCaptureWindow(TEXT("Video for Window"), WS_CHILD|WS_VISIBLE, 10, 10, 320, 240, hWnd, 0);
// usb를 통해 연결된 카메라 장치를 찾아 연결해 준다.
capDriverConnect(hVfw, 0);
// hVfw, 1ms - 화면에 보이는 속도(Rate)
capPreviewRate(hVfw, 1);
// Video 포멧을 확인하고 정보를 넣는다.
capGetVideoFormat(hVfw, &BInfo, sizeof(BITMAPINFO));
BInfo.bmiHeader.biWidth = 320;
BInfo.bmiHeader.biHeight = 240;
capSetVideoFormat(hVfw, &BInfo, sizeof(BITMAPINFO));
// 자동으로 라이브러리에서 Emb_Draw()를 호출해 준다.
capSetCallbackOnFrame(hVfw, Emb_Draw);
// 화면에 띄운다.(TRUE)
capPreview(hVfw, TRUE);
return 0;
case WM_LBUTTONDOWN:
return 0;
case WM_DESTROY: // 운영체제로부터 들어온 메시지에 대한 처리 - 여기서는 윈도우가 파괴되었음을 알린다.
ReleaseDC(hWnd, hdc);
PostQuitMessage(0); // WM_QUIT 메시지를 보냄
return 0;
}
// switch 문에서 처리하지 않은 메시지를 처리
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
// HWND, long *
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
SetPixel(hdc, xPos+420, yPos+10, RGB(0, 0, lp->lpData[iCnt])); // 블루
SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
return 0;
}
→ 아래 함수를 이용하여 캠에서 들어오는 영상을 복제해서 뿌린다.
// HWND, long *
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
SetPixel(hdc, xPos+420, yPos+10, RGB(0, 0, lp->lpData[iCnt])); // 블루
SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
→ COLORREF SetPixel(hdc, nXPos, nYPos, clrref)LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
SetPixel(hdc, xPos+420, yPos+10, RGB(0, 0, lp->lpData[iCnt])); // 블루
SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
→ 위 함수는 화면에 점을 출력하는 함수로 for문을 돌려 영상을 출력(원본 영상의 복사)한다.
→ 출력은 원본을 제외한 3가지로 BLUE, GREEN, RED 의 색상만을 각각 출력해 본다.
// HWND, long *
LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
DWORD dwRead;
hFile = CreateFile("116.bmp", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(hFile, buf, sizeof(buf), &dwRead, NULL);
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
// 영상
SetPixel(hdc, xPos+420, yPos+10, RGB(lp->lpData[iCnt+2], lp->lpData[iCnt+1], lp->lpData[iCnt]));
// BMP
SetPixel(hdc, xPos+10, yPos+250, RGB(buf[(iCnt+54)+2], buf[(iCnt+54)+1], buf[(iCnt+54)]));
// BMP + 영상
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2]+buf[(iCnt+54)+2], lp->lpData[iCnt+1]+buf[(iCnt+54)+1], lp->lpData[iCnt]+buf[(iCnt+54)]));
// BMP - 영상
SetPixel(hdc, xPos+10, yPos+490, RGB(lp->lpData[iCnt+2]-buf[(iCnt+54)+2], lp->lpData[iCnt+1]-buf[(iCnt+54)+1], lp->lpData[iCnt]-buf[(iCnt+54)]));
// BMP * 영상
SetPixel(hdc, xPos+420, yPos+490, RGB(lp->lpData[iCnt+2]*buf[(iCnt+54)+2], lp->lpData[iCnt+1]*buf[(iCnt+54)+1], lp->lpData[iCnt]*buf[(iCnt+54)]));
//SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
//SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
return 0;
}
→ 실행파일LRESULT CALLBACK Emb_Draw(HWND hWnd, LPVIDEOHDR lp)
{
int xPos;
int yPos;
int iCnt=0;
DWORD dwRead;
hFile = CreateFile("116.bmp", GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(hFile, buf, sizeof(buf), &dwRead, NULL);
for(yPos=240;0<yPos;--yPos)
{
for(xPos=0;320>xPos;++xPos)
{
//lp->lpData[iCnt+0]=255;
// 영상
SetPixel(hdc, xPos+420, yPos+10, RGB(lp->lpData[iCnt+2], lp->lpData[iCnt+1], lp->lpData[iCnt]));
// BMP
SetPixel(hdc, xPos+10, yPos+250, RGB(buf[(iCnt+54)+2], buf[(iCnt+54)+1], buf[(iCnt+54)]));
// BMP + 영상
SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2]+buf[(iCnt+54)+2], lp->lpData[iCnt+1]+buf[(iCnt+54)+1], lp->lpData[iCnt]+buf[(iCnt+54)]));
// BMP - 영상
SetPixel(hdc, xPos+10, yPos+490, RGB(lp->lpData[iCnt+2]-buf[(iCnt+54)+2], lp->lpData[iCnt+1]-buf[(iCnt+54)+1], lp->lpData[iCnt]-buf[(iCnt+54)]));
// BMP * 영상
SetPixel(hdc, xPos+420, yPos+490, RGB(lp->lpData[iCnt+2]*buf[(iCnt+54)+2], lp->lpData[iCnt+1]*buf[(iCnt+54)+1], lp->lpData[iCnt]*buf[(iCnt+54)]));
//SetPixel(hdc, xPos+10, yPos+250, RGB(0, lp->lpData[iCnt+1], 0)); // 그린
//SetPixel(hdc, xPos+420, yPos+250, RGB(lp->lpData[iCnt+2], 0, 0)); // 레드
iCnt = iCnt +3;
}
}
return 0;
}
→ 위의 실행 결과는 왼쪽 처음부터 오른쪽으로 각각
→ 원본영상, 복사 영상
→ BMP출력, 영상+BMP
→ 영상-BMP, 영상*BMP
→ 6가지의 출력을 나타낸 것이다.
'내장형 하드웨어 > WINAPI' 카테고리의 다른 글
영상처리 - 영상에 이미지 파일 고정 출력 및 위치변환 (0) | 2011.11.24 |
---|---|
WINAPI - sokoban (0) | 2011.10.10 |
WINAPI - 모델리스형 대화상자 (0) | 2011.10.06 |
WINAPI - DlgCheck (0) | 2011.09.29 |
WINAPI - 컨트롤과의 통신 (0) | 2011.09.28 |