20141014 (C++ class내에 const, friend, static, 시리얼 통신 winapi)

157일차








-----------

C++

-----------



------- const

예제를 통하여 class 내에 const의 기능을 더 확인한다.


예제1)

#include <iostream>


using namespace std;


class SoSimple

{

private:

int num;

public:

SoSimple(int n) : num(n)

{

}


SoSimple & AddNum(int n)

{

num = num + n;

return *this;

}


void ShowData() const

{

cout << "num : " << num << endl;

}

};


int main()

{

const SoSimple obj(7);


// obj.AddNum(20); // error!

obj.ShowData(); // ok!


return 0;

}



obj 객체가 const 로 선언되었기 때문에, AddNum 함수가 const 함수가 아니라서

호출 자체가 에러인 것이다.




예제2)

#include <iostream>


using namespace std;


class SoSimple

{

private:

int num;

public:

SoSimple(int n) : num(n)

{

}


SoSimple & AddNum(int n)

{

num = num + n;

return *this;

}


void SimpleFunc()

{

cout << "SimpleFunc: " << num << endl;

}


void SimpleFunc() const

{

cout << "const SimpleFunc: " << num << endl;

}

};


void YourFunc(const SoSimple & obj) // 인자를 const로 받음

{

obj.SimpleFunc();

}


int main()

{

SoSimple obj1(2);

const SoSimple obj2(7);


obj1.SimpleFunc();

obj2.SimpleFunc();


YourFunc(obj1);

YourFunc(obj2);


return 0;

}


결과



YourFunc(const SoSimple & obj) 함수의 인수 자체가 const로 받았기 때문에

그 안에서 호출되는 객체는 모두 const로 호출된다.










------- friend

class 내에 friend를 선언하면 선언된 class에 private 멤버에 접근이 가능하다.


예제)

#include <iostream>

#include <cstring>


using namespace std;


class Girl; // class도 선언만 가능


class Boy

{

private:

int height;

friend class Girl; // friend 선언 위치는 class 내에 어느 곳이든 가능


public:

Boy(int len) : height(len)

{

}


void ShowYourFriendInfo(Girl & frn); // class 내에서 선언만 해두고 정의는 더 밑에 있다

};


class Girl

{

private:

char phNum[20];


public:

Girl(char * num)

{

strcpy(phNum, num);

}


void ShowYourFriendInfo(Boy & frn); // class 내에서 선언만 해두고 정의는 더 밑에 있다

friend class Boy; // friend 선언 위치는 class 내에 어느 곳이든 가능

};


// 정의가 여기 있는 이유는 Boy class에서 Girl class의 정의가

// 어떤지 모르니 Boy class 내에서 Girl class 에 대한 언급을 할 수가 없기에

// 밑에 다 정의를 해둔 것이다

void Boy::ShowYourFriendInfo(Girl & frn)

{

cout << "Her phone number: " << frn.phNum << endl; // private 멤버에 접근 가능

}


void Girl::ShowYourFriendInfo(Boy & frn)

{

cout << "His height: " << frn.height << endl; // private 멤버에 접근 가능

}


int main()

{

Boy boy(170);

Girl girl("010-1234-5678");


boy.ShowYourFriendInfo(girl);

girl.ShowYourFriendInfo(boy);


return 0;

}





여기서 함수의 접근도 설정할 수 있는데


int main()

{

Boy boy(170);

Girl girl("010-1234-5678");


boy.ShowYourFriendInfo(girl);

girl.ShowYourFriendInfo(boy);


boy.height = 180; // error!


return 0;

}



boy.height = 180; 코드는 에러인데


class Boy

{

private:

int height;

friend class Girl; // friend 선언 위치는 class 내에 어느 곳이든 가능

friend int main(); // 이렇게 main을 추가함


public:

...


위와 같은 방식으로 main()을 추가하면 main도 boy의 friend가 되었기 때문에

에러가 아니게 된다.










------- static 멤버 변수, 함수

class 내 변수에 static 을 붙이면 그 클래스에 그 변수 한 개만 할당되어

그 클래스의 객체들은 그 한 변수를 공유하게 된다.


class smart

{

public:

static int iNum;

};




또 함수에 static을 붙였을 시,

내부 함수나 변수는 static인 함수와 변수만 사용 가능하다.



예제)

#include <iostream>


using namespace std;


class smart

{

public:

static int iNum;

int iNum2;


public:

static void test()

{

cout << "test()" << endl;

iNum = iNum + 1;

// iNum2 = 0; // error! static 변수가 아니라서 사용 못함

}

};

int smart::iNum = 100;


int main()

{

cout << smart::iNum << endl;

smart::test();

cout << smart::iNum << endl;


return 0;

}



한 가지 흥미로운 것은 객체를 생성하지 않았는데 사용 가능하다는 것이다!!!











-------------------------

시리얼 통신 winapi

-------------------------



------- 어제 작성했던 시리얼 통신 DOS 모드로 작성했던 소스를

그래픽 모드로 재작성 하였다.



DOS 모드 소스)

#include <windows.h>

#include <stdio.h>


DWORD WINAPI Thread_Read(LPVOID);


HANDLE hComm;


int main()

{

u_char caString[10] = "하이~";

//char buf;

DWORD dwWritten;

DCB sPState;

COMMTIMEOUTS cTime;

DWORD ThreadID;

HANDLE hThread;


hComm = CreateFile("COM8", GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

printf("포트 열 수 없음\n");

return 0;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

printf("버퍼 설정 에러\n");

CloseHandle(hComm);

return 0;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

printf("버퍼 초기화 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

printf("시리얼 상태 읽기 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


cTime.ReadIntervalTimeout = MAXDWORD; // 시간 설정, 블록킹 됐을시 기다리는 시간

cTime.ReadTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.ReadTotalTimeoutConstant = 0;

cTime.WriteTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.WriteTotalTimeoutConstant = 0;


SetCommTimeouts(hComm, &cTime);


if(0 == SetCommState(hComm, &sPState))

{

printf("시리얼 상태 설정 에러\n");

CloseHandle(hComm);

return 0;

}


hThread = CreateThread(NULL, 0, Thread_Read, NULL, 0, &ThreadID);


while(1)

{

caString[0] = getch();

if(0 == WriteFile(hComm, caString, 1, &dwWritten, 0))

{

printf("쓰기 에러\n");

}

else

{

printf("쓰기 성공\n");

}

}


CloseHandle(hComm);


return 0;

}


DWORD WINAPI Thread_Read(LPVOID NotUse)

{

char buf = 0;

DWORD dwRead;


while(1)

{

Sleep(100);

ReadFile(hComm, &buf, 1, &dwRead, NULL);

if(0 != dwRead)

{

printf("[%c] ", buf);

}

}

}






그래픽 모드 소스)

#include <windows.h>

#include "resource.h"


#define ID_EDIT 100


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

void OpenSPort();

DWORD WINAPI Thread_Read(LPVOID NotUse);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("Serial");

HWND hMain;


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,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,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);


while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


HANDLE hComm;

HANDLE hThread;

BOOL bPortOnOff;

HWND hEdit;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

u_char caString[128] = "하이~";

DWORD dwWritten;


switch (iMessage)

{

case WM_CREATE:

hMain = hWnd;

hEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD | WS_VISIBLE

| WS_BORDER | ES_AUTOHSCROLL

, 10, 10, 100, 25, hWnd, (HMENU)ID_EDIT, g_hInst, NULL);

return 0;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_OPEN:

OpenSPort();

break;

case ID_CLOSE:

if(TRUE == bPortOnOff)

{

CloseHandle(hComm);

CloseHandle(hThread);

bPortOnOff = FALSE;

}

break;

case ID_EDIT:

switch(HIWORD(wParam))

{

}

break;

}

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}


void OpenSPort()

{

static DCB sPState;

static COMMTIMEOUTS cTime;

DWORD ThreadID;


if(TRUE == bPortOnOff)

{

CloseHandle(hComm);

CloseHandle(hThread);

// return 0;

bPortOnOff = FALSE;

}


hComm = CreateFile(TEXT("COM8"), GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

MessageBox(hMain, TEXT("포트 열 수 없음"), TEXT("알림"), MB_OK);

return ;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

MessageBox(hMain, TEXT("버퍼 설정 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

MessageBox(hMain, TEXT("버퍼 초기화 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

MessageBox(hMain, TEXT("시리얼 상태 읽기 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


cTime.ReadIntervalTimeout = MAXDWORD; // 시간 설정, 블록킹 됐을시 기다리는 시간

cTime.ReadTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.ReadTotalTimeoutConstant = 0;

cTime.WriteTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.WriteTotalTimeoutConstant = 0;


SetCommTimeouts(hComm, &cTime);


if(0 == SetCommState(hComm, &sPState))

{

MessageBox(hMain, TEXT("시리얼 상태 설정 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


hThread = CreateThread(NULL, 0, Thread_Read, NULL, 0, &ThreadID);


bPortOnOff = TRUE; // 포트 열기가 완료되었으므로 TRUE

}


DWORD WINAPI Thread_Read(LPVOID NotUse)

{

char tt;

static TCHAR buff[] = TEXT("0x00 ");

DWORD dwRead;


while(1)

{

Sleep(50);

ReadFile(hComm, &tt, 1, &dwRead, NULL);

wsprintf(buff, TEXT("0x%02X "), tt);

if(0 != dwRead)

{

SetWindowText(hEdit, buff);

}

}

}









설정

트랙백

댓글

20141013 (C++ 복사 생성자, 시리얼 통신 winapi)

156일차






-----------

C++

-----------



------- 복사 생성자

예제를 보자.


소스)

#include <iostream>

#include <cstring>


using namespace std;


class smart

{

public:

char * p;


public:

smart()

{

cout << "D생성자" << endl;

p = new char[3];

strcpy(p, "Hi");

}


smart(const smart & r) // 복사 생성자, 복사 받는 값은 변경하지 않으니

{ // 보통 앞에 const를 붙인다

p = new char[3];

strcpy(p, r.p);

cout << p << "복사 생성자" << endl;

}


~smart()

{

cout << "~소멸자" << endl;

delete []p;

}


smart test()

{

smart t;

*(t.p) = 'X';

return t;

}

};


int main()

{

smart obj1; // 디폴트 생성자 호출

smart obj2; // 디폴트 생성자 호출


// obj2 = obj1; // 대입 연산자 호출


*(obj2.p) = 'L';


smart obj3 = obj2; // 복사 생성자 호출

smart obj4(obj3); // 복사 생성자 호출


smart obj5 = obj4.test();


cout << "this is test" << endl;


return 0;

}


결과





위 처럼 생성자인데 바로 다른 값을 넣어주는 것을 복사 생성자라 한다.

이것을 선언해 주지 않을시 기본값으로 만들어져 있다.


만약 위 소스에서

smart(const smart & r) // 복사 생성자, 복사 받는 값은 변경하지 않으니

{ // 보통 앞에 const를 붙인다

// p = new char[3];

// strcpy(p, r.p);

cout << p << "복사 생성자" << endl;

}

해버리면 오류다ㅋ


http://wowcat.tistory.com/1946








------- explicit

복사 생성자를 사용할 때 묵시적 변환이 일어나서

복사 생성자가 호출되는 경우가 있는데, 무슨 말이냐 하면...


smart obj1 = obj2;      =>      smart obj1(obj2);


이렇게 묵시적으로 바뀐다.

여기서 smart obj1 = obj2; 형태가 맘에 들지 않으면 복사 생성자의 묵시적 호출을

허용하지 않을 수 있는데, 이때 사용하는 키워드가 explicit 이다.


예제)

class smart

{

public:

smart()

{

cout << "디폴트 생성자" << endl;

}

explicit smart(smart n)

{

cout << "복사 생성자" << endl;

}

};


int main()

{

smart obj1;


smart obj2(obj1);     // ok!

smart obj3 = obj1;    // error!


return 0;

}





------- 임시 객체

실제로 쓰지는 않고 임시 객체를 통해서

생성자와 소멸자가 사라지는 시간을 확인하는 소스이다.


예제)

#include <iostream>


using namespace std;


class Temporary

{

private:

int num;

public:

Temporary(int n) : num(n)

{

cout<<"create obj: "<<num<<endl;

}

~Temporary()

{

cout<<"destroy obj: "<<num<<endl;  

}

void ShowTempInfo()

{

cout<<"My num is "<<num<<endl;

}

};


int main(void)

{

Temporary(100);

cout<<"********** after make!"<<endl<<endl;


Temporary(200).ShowTempInfo();

cout<<"********** after make!"<<endl<<endl;


const Temporary &ref=Temporary(300);

cout<<"********** end of main!"<<endl<<endl;

return 0;

}


결과













---------------------

Winapi 시리얼 통신

---------------------



------- 시리얼 통신

소스를 짜기 앞서,


사용할 포트를 설정해 줘야한다. Virtual Serial Ports Driver라는 프로그램으로

8번과 9번을 연결해 놓았다.


하이퍼 터미널로 9번을 열었다면, 작성할 소스는 8번을 열어야 한다.


소스)

#include <windows.h>

#include <stdio.h>


int main()

{

u_char caString[10] = "하이~";

DWORD dwWritten;

DCB sPState;

HANDLE hComm = CreateFile("COM8", GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

printf("포트 열 수 없음\n");

return 0;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

printf("버퍼 설정 에러\n");

CloseHandle(hComm);

return 0;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

printf("버퍼 초기화 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

printf("시리얼 상태 읽기 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


if(0 == SetCommState(hComm, &sPState))

{

printf("시리얼 상태 설정 에러\n");

CloseHandle(hComm);

return 0;

}


if(0 == ReadFile(hComm, caString, sizeof(caString), &dwWritten, 0))

//if(0 == WriteFile(hComm, caString, sizeof(caString), &dwWritten, 0))

{

printf("쓰기 에러\n");

}

else

{

// printf("쓰기 성공\n");

printf("읽기 성공\n");

printf("[%s]\n", caString);

}


CloseHandle(hComm);


return 0;

}







------- 스레드 + 시리얼 통신

소스)

#include <windows.h>

#include <stdio.h>


DWORD WINAPI Thread_Read(LPVOID);


HANDLE hComm;


int main()

{

u_char caString[10] = "하이~";

//char buf;

DWORD dwWritten;

DCB sPState;

COMMTIMEOUTS cTime;

DWORD ThreadID;

HANDLE hThread;


hComm = CreateFile("COM8", GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

printf("포트 열 수 없음\n");

return 0;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

printf("버퍼 설정 에러\n");

CloseHandle(hComm);

return 0;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

printf("버퍼 초기화 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

printf("시리얼 상태 읽기 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


cTime.ReadIntervalTimeout = MAXDWORD; // 시간 설정, 블록킹 됐을시 기다리는 시간

cTime.ReadTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.ReadTotalTimeoutConstant = 0;

cTime.WriteTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.WriteTotalTimeoutConstant = 0;


SetCommTimeouts(hComm, &cTime);


if(0 == SetCommState(hComm, &sPState))

{

printf("시리얼 상태 설정 에러\n");

CloseHandle(hComm);

return 0;

}


hThread = CreateThread(NULL, 0, Thread_Read, NULL, 0, &ThreadID);


while(1)

{

caString[0] = getch();

if(0 == WriteFile(hComm, caString, 1, &dwWritten, 0))

{

printf("쓰기 에러\n");

}

else

{

printf("쓰기 성공\n");

}

}


CloseHandle(hComm);


return 0;

}


DWORD WINAPI Thread_Read(LPVOID NotUse)

{

char buf = 0;

DWORD dwRead;


while(1)

{

Sleep(100);

ReadFile(hComm, &buf, 1, &dwRead, NULL);

if(0 != dwRead)

{

printf("[%c] ", buf);

}

}

}







설정

트랙백

댓글

C++ Reference, Pointer

잡다 2014. 10. 13. 10:54

Reference와 Pointer의 역할이나 사용법이 거의 같은데,

어떻게 동작하나 궁금해서 Assembly로 확인해 보았다.


예제 소스)

- C++

#include <iostream>


void test(int &aaa)

{

7 aaa = 100;

}


void pointer(int * bbb)

{

12 *bbb = 200;

}


int main()

{

17 int number = 10;


19 test(number);

20 pointer(&number);


return 0;

}



- Assembly


_number$ = -4         ; size = 4

_main PROC

; Line 16

push ebp

mov ebp, esp

push ecx

; Line 17

mov DWORD PTR _number$[ebp], 10 ; 0000000aH

; Line 19

lea eax, DWORD PTR _number$[ebp] ; 주소 값 넘겨줌

push eax ; 주소 값을 인수로 저장

call ?test@@YAXAAH@Z ; test 함수 호출,  test(number);

add esp, 4

; Line 20

lea ecx, DWORD PTR _number$[ebp] ; 주소 값 넘겨줌

push ecx ; 주소 값을 인수로 저장

call ?pointer@@YAXPAH@Z ; pointer 함수 호출,  pointer(&number);

add esp, 4

; 두 함수 다 주소 값을 인자로 넘겨줌.

; Line 22

xor eax, eax

; Line 23

mov esp, ebp

pop ebp

ret 0

_main ENDP

_TEXT ENDS



_aaa$ = 8                 ; size = 4

?test@@YAXAAH@Z PROC ; test 함수 시작

; File d:\main.cpp

; Line 6

push ebp

mov ebp, esp

; Line 7

mov eax, DWORD PTR _aaa$[ebp] ; aaa가 가리키는 값(number주소)을 eax에 저장

mov DWORD PTR [eax], 100 ; 00000064H 값을 eax가 가리키는 값에 넣음

; Line 8

pop ebp

ret 0

?test@@YAXAAH@Z ENDP ; test 함수 끝

; 주소 값으로 값의 수정함



_bbb$ = 8                 ; size = 4

?pointer@@YAXPAH@Z PROC ; pointer 함수 시작

; Line 11

push ebp

mov ebp, esp

; Line 12

mov eax, DWORD PTR _bbb$[ebp] ; bbb가 가리키는 값(number주소)을 eax에 저장

mov DWORD PTR [eax], 200 ; 000000c8H 값을 eax가 가리키는 값에 넣음

; Line 13

pop ebp

ret 0

?pointer@@YAXPAH@Z ENDP ; pointer 함수 끝

; 주소 값으로 값의 수정함






또 다른 예제)


- C++

#include <iostream>


int main()

{

int number = 10;

int &aaa = number;

int *bbb = &number;


number = 20;

aaa = 100;

*bbb = 1000;


return 0;

}




- Assembly

_aaa$ = -12 ; size = 4

_number$ = -8 ; size = 4

_bbb$ = -4 ; size = 4

_main PROC

; File d:\main.cpp

; Line 6

push ebp

mov ebp, esp

sub esp, 12 ; 0000000cH

; Reference도 메모리를 할당 받는다

; Line 7

mov DWORD PTR _number$[ebp], 10 number = 0000000aH

; Line 8

lea eax, DWORD PTR _number$[ebp] ; number 주소를 eax에 저장

mov DWORD PTR _aaa$[ebp], eax ; aaa에 eax 값 넣음, &aaa = number

; Line 9

lea ecx, DWORD PTR _number$[ebp] number 주소를 ecx에 저장

mov DWORD PTR _bbb$[ebp], ecx ; bbb에 ecx 값 넣음, *bbb = &number

; Line 11

mov DWORD PTR _number$[ebp], 20 ; number = 00000014H

; Line 12

mov edx, DWORD PTR _aaa$[ebp] ; aaa 값을 edx에 저장

mov DWORD PTR [edx], 100 ; aaa가 가리키는 값에 00000064H을 넣음, aaa = 100;

; Line 13

mov eax, DWORD PTR _bbb$[ebp] ; bbb 값을 eax에 저장

mov DWORD PTR [eax], 1000 ; bbb가 가리키는 값에 000003e8H을 넣음, *bbb = 1000;

; Line 15

xor eax, eax

; Line 16

mov esp, ebp

pop ebp

ret 0

_main ENDP





결국 Pointer나 Reference나 Assembly로 동작 방식은 같다.

'잡다' 카테고리의 다른 글

stm32F10x Standard Peripherals Library  (0) 2015.01.12
PCB 설계/제작/조립 관련 사이트  (0) 2014.10.27
microangel 마우스 커서, 아이콘 제작 툴  (0) 2014.09.16
map  (0) 2014.09.13
우분투 리눅스 text 모드 부팅  (0) 2014.09.01

설정

트랙백

댓글

20141010 (C++ this)

155일차










-------------

C++

-------------


------- this

현재 객체를 가리킨다

(객체 주소)


예제)

#include <iostream>

#include <cstring>


using namespace std;


class SoSimple

{

public:

int num;


public:

SoSimple(int n)

: num(n)

{

cout << "num=" << num << ", ";

cout << "address=" << this << endl;

}


void ShowSimpleData()

{

cout << num << endl;

}


SoSimple * GetThisPointer()

{

return this;

}

};


int main()

{

SoSimple sim1(100);

SoSimple * ptr1 = sim1.GetThisPointer();


cout << ptr1 << ", ";

ptr1->ShowSimpleData();


SoSimple sim2(200);

SoSimple * ptr2 = sim2.GetThisPointer();


cout << ptr2 << ", ";

ptr2->ShowSimpleData();


return 0;

}



결과







다른 예제)

#include <iostream>


using namespace std;


class SelfRef

{

private:

int num;


public:

SelfRef(int n)

: num(n)

{

cout << "객체생성" << endl;

}


SelfRef & Adder(int n)

{

num = num + n;

return *this;

}


SelfRef & ShowTwoNumber()

{

cout << num << endl;

return *this;

}

};


int main()

{

SelfRef obj(3);

SelfRef & ref = obj.Adder(2);


obj.ShowTwoNumber();

ref.ShowTwoNumber();


ref.Adder(1).ShowTwoNumber().Adder(2).ShowTwoNumber();


return 0;

}



결과









--------------

RFID

--------------



beep.txt


ISO15693-HostCommand.pdf







설정

트랙백

댓글

영상처리 winapi 소스

프로그래밍 언어/WinApi 2014. 10. 10. 10:20


--------------------------

기상 방송 같은 효과

--------------------------


------- 기상 방송을 보면 아나운서가 파란 뒷 배경에서 설명하는데

방송에서는 아나운서 뒤에 기상 그림이 나온다.

이런 영상 효과를 내는 예제 소스이다. 웹캠이 연결되어 있어야하고

같은 디렉토리 내에 image.bmp 파일이 있어야한다.


#include <windows.h>

#include "vfw.h"

#pragma comment(lib, "vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND HWndMain;

LPCTSTR lpszClass=TEXT("WiseCat");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst = hInstance;


WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(  lpszClass

,lpszClass

,WS_OVERLAPPEDWINDOW

,CW_USEDEFAULT

,CW_USEDEFAULT

,CW_USEDEFAULT,CW_USEDEFAULT

,NULL

,(HMENU)NULL

,hInstance

,NULL);        

ShowWindow(hWnd,nCmdShow);


while(GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}


return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR);


HWND vfw;

BITMAPINFO Bm;

HDC hdc;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HANDLE hFile;

PAINTSTRUCT ps;

static unsigned int uiX;

static unsigned int uiY;

DWORD dwRead;


switch(iMessage)

{

case WM_CREATE:

HWndMain = hWnd;


// Bitmap 열고 처리 //시작---------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 열고 처리 //끝-----------------------------------------------


// 웹캠 설정 // 시작------------------------

vfw = capCreateCaptureWindow(  TEXT("CAM")

,WS_CHILD | WS_VISIBLE

,0

,0

,400

,300

,hWnd

,NULL);


capDriverConnect(vfw,0);

capGetVideoFormat(vfw,&Bm,sizeof(Bm));

Bm.bmiHeader.biWidth  = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(vfw,&Bm,sizeof(Bm));

//capDlgVideoFormat(m_capwnd); 

capSetCallbackOnFrame(vfw, FramInfo);

capPreviewRate(vfw, 1);

capPreview(vfw, FALSE);

// 웹캠 설정 // 끝--------------------------

return 0;


case WM_PAINT:

hdc = BeginPaint(hWnd,&ps);

EndPaint(hWnd,&ps);

return 0;


case WM_DESTROY:

free(BMbuf);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}


LRESULT CALLBACK FramInfo(HWND hWnd, LPVIDEOHDR lpData)

{

static int iCntX;

static int iCntY;

static int Jump;

unsigned char * ucpPixel;


// 원본 영상 그리기 // 시작-------------------------------

hdc = GetDC(HWndMain);

StretchDIBits(hdc  , 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 원본 영상 그리기 // 끝---------------------------------


// 영상 정보 편집 // 시작--------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits - 3;

Jump= 0;

for(iCntY = 0; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)  

{        

for(iCntX = 0; iCntX  < Bm.bmiHeader.biWidth  ; ++iCntX, Jump += 3)

{

ucpPixel = ucpPixel + 3;

if(lpData->lpData[Jump + 2] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 1] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 0] > 50)

{

lpData->lpData[Jump] = *(ucpPixel + 0);  // Blue

lpData->lpData[Jump + 2] = *(ucpPixel + 2);  // Red

lpData->lpData[Jump + 1] = *(ucpPixel + 1);  // Green

}

}

ucpPixel = ucpPixel + uiPad;

}

// 영상 정보 편집 // 끝----------------------------------------------


// 편집된 영상 그리기 // 시작----------------------------

StretchDIBits(hdc  , Bm.bmiHeader.biWidth +20

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 편집된 영상 그리기 // 끝------------------------------


ReleaseDC(HWndMain, hdc);


return 0;

}

/*

#include <windows.h>

#include <Vfw.h>

#pragma comment (lib,"vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("Class");

//WinMain 시작


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

//1. 윈도우 속성값 등록

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);  //주소에 Write


//2. 윈도우 생성

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL, (HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌


//3. 메시지 처리(무한 반복)

while (GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);

HBITMAP hBit;

BITMAPINFO Bm;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

HWND hVFW;

PAINTSTRUCT ps;

HANDLE hFile;

static unsigned int uiX;

static unsigned int uiY;

DWORD dwRead;


switch(iMessage)

{

case WM_CREATE:

hWndMain=hWnd;

hdc=GetDC(hWndMain);


// Bitmap 열기 //-------------------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 그리기 //끝-----------------------------------------------


hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,320,240,hWnd,0);

capDriverConnect(hVFW,0);

capPreviewRate(hVFW,10);

capGetVideoFormat(hVFW,&Bm, sizeof(Bm));

Bm.bmiHeader.biWidth = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(hVFW, &Bm, sizeof(Bm));

capPreview(hVFW,TRUE);


hBit = CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);


if (capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)

{

return FALSE;

}

ReleaseDC(hWndMain, hdc);

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

EndPaint(hWnd, &ps);

return 0;

case WM_DESTROY:

free(BMbuf);

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 avr;

unsigned char * ucpPixel;


hdc = GetDC(hWndMain);

hMemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


ucpPixel = BMbuf + stpBFH->bfOffBits;

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

//for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)

for (iCntX=Bm.bmiHeader.biWidth-1 ; 0 <= iCntX ; --iCntX)

{


// 특정 색 전환

if(VideoHdr->lpData[Jump+2] > 150)// && VideoHdr->lpData[Jump+2] > 40)

{

if(VideoHdr->lpData[Jump+1] > 150)// && VideoHdr->lpData[Jump+1] > 70)

{

if(VideoHdr->lpData[Jump+0] > 150)// && VideoHdr->lpData[Jump+0] > 70)

{

VideoHdr->lpData[Jump+2] = *(ucpPixel+2);

VideoHdr->lpData[Jump+1] = *(ucpPixel+1);

VideoHdr->lpData[Jump+0] = *(ucpPixel+0);

}

}

}


//원영상

SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));

//   SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(0xC3&(VideoHdr->lpData[Jump+2]), 0xC3&(VideoHdr->lpData[Jump+1]), 0xC3&(VideoHdr->lpData[Jump])));

// avr = (VideoHdr->lpData[Jump+2]+VideoHdr->lpData[Jump+1]+VideoHdr->lpData[Jump])/3;

// if(avr < 200)

// avr = 0;

// SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(avr, avr, avr));


Jump+=3;

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}


//------------------------------------------------------------------------------

BitBlt(hdc, 320,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);

SelectObject(hMemDC,OldBitmap);

ReleaseDC(hWndMain,hdc);

return 0;

}

*/


결과





왼쪽이 원본, 오른쪽이 특정 색은 다른 영상 이미지로 대체












-------------------------

웹캠 영상 처리

-------------------------


------- 웹캠으로 촬영된 영상을 스트레칭, 평활화등 영상 처리한 소스이다.



#include <windows.h>

#include <Vfw.h>

#pragma comment (lib,"vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("Class");

//WinMain 시작


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

//1. 윈도우 속성값 등록

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);  //주소에 Write


//2. 윈도우 생성

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL, (HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌


//3. 메시지 처리(무한 반복)

while (GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);

HBITMAP hBit;

BITMAPINFO Bm;

unsigned char * ucpPixel;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

HWND hVFW;

PAINTSTRUCT ps;

HANDLE hFile;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

DWORD dwRead;

HBITMAP OldBitmap;


switch(iMessage)

{

case WM_CREATE:

hWndMain=hWnd;

hdc=GetDC(hWndMain);


// Bitmap 열고 설정 //시작-----------------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 열고 설정 //끝-------------------------------------------------------


    // 웹캠 설정 // 시작----------------------------------------------------------------------

hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,320,240,hWnd,0);

capDriverConnect(hVFW,0);

capPreviewRate(hVFW,10);

capGetVideoFormat(hVFW,&Bm, sizeof(Bm));

Bm.bmiHeader.biWidth = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(hVFW, &Bm, sizeof(Bm));

capPreview(hVFW,TRUE);


hBit = CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);


if (capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)

{

return FALSE;

}

    // 웹캠 설정 // 끝------------------------------------------------------------------------


ReleaseDC(hWndMain, hdc);

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

EndPaint(hWnd, &ps);

return 0;

case WM_DESTROY:

free(BMbuf);

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 avr;

int Rhigh, Ghigh, Bhigh;

int Rlow, Glow, Blow;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRhisto[256];  // 평활화로 사용할 변수

unsigned int uiGhisto[256];  // 평활화로 사용할 변수

unsigned int uiBhisto[256];  // 평활화로 사용할 변수


hdc = GetDC(hWndMain);

hMemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


// 원본 영상 그리기 // 시작------------------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

//for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)    // 좌우 반전

for (iCntX=Bm.bmiHeader.biWidth-1 ; 0 <= iCntX ; --iCntX)

{

// 영상 정보 수집 // 시작-------------

++uiRcnt[VideoHdr->lpData[Jump+2]];

++uiGcnt[VideoHdr->lpData[Jump+1]];

++uiBcnt[VideoHdr->lpData[Jump+0]];

// 영상 정보 수집 // 끝---------------


// 영상 출력

SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));


// 영상 흑백으로 전환 // 시작----------------------------------------------------------------

// avr = (VideoHdr->lpData[Jump+2]+VideoHdr->lpData[Jump+1]+VideoHdr->lpData[Jump])/3;

// if(avr < 200)

// avr = 0;

// SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1, RGB(avr, avr, avr));

// 영상 흑백으로 전환 // 끝------------------------------------------------------------------


Jump+=3;    // 다음 픽셀

ucpPixel = ucpPixel + 3;    // 다음 픽셀

}

ucpPixel = ucpPixel + uiPad;    // 패드만큼 다음 가리킴

}

// 원본 영상 그리기 // 끝--------------------------------------------------------


// 영상 정보 처리 // 시작-----------------------------

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rlow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rhigh = uiXcount;

break;

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Glow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Ghigh = uiXcount;

break;

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Blow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Bhigh = uiXcount;

break;

}

}


// 누적

uiXcount = 0;

uiRhisto[uiXcount] = uiRcnt[uiXcount];

uiGhisto[uiXcount] = uiGcnt[uiXcount];

uiBhisto[uiXcount] = uiBcnt[uiXcount];

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount-1] + uiRcnt[uiXcount]);

uiGhisto[uiXcount] = (uiGhisto[uiXcount-1] + uiGcnt[uiXcount]);

uiBhisto[uiXcount] = (uiBhisto[uiXcount-1] + uiBcnt[uiXcount]);

}


// 계산

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

uiGhisto[uiXcount] = (uiGhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

uiBhisto[uiXcount] = (uiBhisto[uiXcount] * 255) / (Bm.bmiHeader.biHeight*Bm.bmiHeader.biWidth);

}

// 영상 정보 처리 // 끝-------------------------------


  // 편집된 영상 이미지 정보 수정 // 시작-------------------------------

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)

{

/*

//평활화 + 스트레칭

VideoHdr->lpData[Jump+2] = uiRhisto[(((VideoHdr->lpData[Jump+2])-Rlow) * 255) / (Rhigh - Rlow)];

VideoHdr->lpData[Jump+1] = uiGhisto[(((VideoHdr->lpData[Jump+1])-Glow) * 255) / (Ghigh - Glow)];

VideoHdr->lpData[Jump] = uiBhisto[(((VideoHdr->lpData[Jump+1])-Blow) * 255) / (Bhigh - Blow)];

*/


//스트레칭

VideoHdr->lpData[Jump+2] = (((VideoHdr->lpData[Jump+2])-Rlow) * 255) / (Rhigh - Rlow);

VideoHdr->lpData[Jump+1] = (((VideoHdr->lpData[Jump+1])-Glow) * 255) / (Ghigh - Glow);

VideoHdr->lpData[Jump] = (((VideoHdr->lpData[Jump+1])-Blow) * 255) / (Bhigh - Blow);


/*

//평활화

VideoHdr->lpData[Jump+2] = uiRhisto[VideoHdr->lpData[Jump+2]];

VideoHdr->lpData[Jump+1] = uiGhisto[VideoHdr->lpData[Jump+1]];

VideoHdr->lpData[Jump] = uiBhisto[VideoHdr->lpData[Jump+1]];

*/

//원영상

//   SetPixel(hMemDC, iCntX,(Bm.bmiHeader.biHeight - iCntY)-1,

// RGB(VideoHdr->lpData[Jump+2], VideoHdr->lpData[Jump+1], VideoHdr->lpData[Jump]));

Jump+=3;

}

}

// 편집된 영상 이미지 정보 수정 // 시작-------------------------------


BitBlt(hdc, 320,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);

SelectObject(hMemDC,OldBitmap);

ReleaseDC(hWndMain,hdc);

// Sleep(100);

return 0;

}



/*

// 선생님 소스

#include <windows.h>

#include "vfw.h"

#pragma comment(lib, "vfw32.lib")


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 lpszClass=TEXT("VFW");



LRESULT CALLBACK WndProc( HWND hWnd

, UINT iMessage

, WPARAM wParam

, LPARAM lParam)

{

HDC Hdc;


switch(iMessage)

{

case WM_CREATE:

Hwndmain = hWnd;

Hdc  = GetDC(hWnd);

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

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight);

if (capSetCallbackOnFrame(hVFW, FramInfo) == FALSE)

{

return FALSE;

}

ReleaseDC(hWnd, Hdc);

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;


Hdc = GetDC(Hwndmain);

hMemDC = CreateCompatibleDC(Hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);


BitBlt( Hdc

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, hMemDC

, 0

, 0

, SRCCOPY);

SelectObject(hMemDC,OldBitmap);

DeleteDC(hMemDC);

ReleaseDC(Hwndmain, Hdc);


return 0;

}

*/


결과




왼쪽이 원본 영상, 오른쪽이 평활화 & 스트레칭 처리된 영상이다.

원본의 왼쪽에 어두워 잘 안보이는데,

처리된 영상을 보면 어두운 부분이 보이게 처리된 것을 확인할 수 있다.











----------------

이미지 평활화

----------------


------- 비트맵 이미지를 평활화 처리하는 소스


#include <windows.h>


#define BITMAP_MAXSIZE (1024*768*3+10)

#define XOFFSET 280

#define X_WIDTH_SIZE 100

#define ALPA

#define SCREEN_Y_SIZE 270*2

#define SCROLL_SIZE 100*6


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("First");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

 ,LPSTR lpszCmdParam,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,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW | WS_VSCROLL,

100,40,800,660,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);

while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


unsigned char * BMbuf;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRcnt2[256];

unsigned int uiGcnt2[256];

unsigned int uiBcnt2[256];

unsigned int uiRhisto[256];  // 평활화로 사용할 변수

unsigned int uiGhisto[256];  // 평활화로 사용할 변수

unsigned int uiBhisto[256];  // 평활화로 사용할 변수

HBITMAP Screen;

HBITMAP Histo;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HDC hdc;

static HDC MemDC;

PAINTSTRUCT ps;

HANDLE hFile;

DWORD dwRead;

TCHAR str[1024];

static BITMAPFILEHEADER * stpBFH;

static BITMAPINFOHEADER * stpBIH;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned char * ucpPixel;

static unsigned int uiPad;

HBITMAP OldBitmap;

static int yPos;

int yInc;

int iBorW;

HPEN OldPen, MyPen;

switch (iMessage)

{

case WM_CREATE:

SetScrollRange(hWnd, SB_VERT, 0, SCROLL_SIZE, TRUE);

SetScrollPos(hWnd, SB_VERT, 0, TRUE);

hFile = CreateFile(TEXT("image4.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);


BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

if(0 == BMbuf)

{

MessageBox(hWnd, TEXT("동적할당을 받을 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

if(INVALID_HANDLE_VALUE != hFile)

{

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


// 정보 출력 //시작------------------------------------------------------

wsprintf(str, TEXT("[%c][%c]"), BMbuf[0], BMbuf[1]);

CreateWindow(TEXT("static"), TEXT("파일 타입 : "), WS_CHILD | WS_VISIBLE,

0, 0, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 0, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d byte]"), stpBFH->bfSize);

CreateWindow(TEXT("static"), TEXT("파일 크기 : "), WS_CHILD | WS_VISIBLE,

0, 20, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 20, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biWidth);

CreateWindow(TEXT("static"), TEXT("가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 40, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 40, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biHeight);

CreateWindow(TEXT("static"), TEXT("세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 60, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 60, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%08X]"), stpBFH->bfOffBits);

CreateWindow(TEXT("static"), TEXT("bfOffbits : "), WS_CHILD | WS_VISIBLE,

0, 80, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 80, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSize);

CreateWindow(TEXT("static"), TEXT("헤더 크기 : "), WS_CHILD | WS_VISIBLE,

0, 100, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 100, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSizeImage);

CreateWindow(TEXT("static"), TEXT("그림 크기 : "), WS_CHILD | WS_VISIBLE,

0, 120, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 120, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biXPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 140, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 140, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biYPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 160, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 160, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);

// 정보 출력 //끝-----------------------------------------------------------

uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);


hdc = GetDC(hWnd);

MemDC = CreateCompatibleDC(hdc);


Screen = CreateCompatibleBitmap(hdc, uiX, uiY * 2);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);

// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY; 0 < uiYcount; --uiYcount)

{

for(uiXcount = uiX; 0 < uiXcount; --uiXcount)

{

// 흑백 처리 // 시작--------------------------------------

iBorW = ((*(ucpPixel+2)) + (*(ucpPixel+1)) + (*ucpPixel))/3;

*(ucpPixel+2)= iBorW;

*(ucpPixel+1)= iBorW;

*(ucpPixel+0)= iBorW;

// 흑백 처리 // 끝----------------------------------------

++uiRcnt[*(ucpPixel+2)];

++uiGcnt[*(ucpPixel+1)];

++uiBcnt[*ucpPixel];


SetPixel(MemDC, uiXcount-1, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}



// Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt[uiXcount])

{

uiYcount = uiRcnt[uiXcount];

}

if(uiYcount < uiGcnt[uiXcount])

{

uiYcount = uiGcnt[uiXcount];

}

if(uiYcount < uiBcnt[uiXcount])

{

uiYcount = uiBcnt[uiXcount];

}

}


// 히스토그램 세로축 값 변환 //시작----------------------------------

// 평활화 누적값 // 시작--------------------------------------------


// 누적

uiXcount = 0;

uiRhisto[uiXcount] = uiRcnt[uiXcount];

uiGhisto[uiXcount] = uiGcnt[uiXcount];

uiBhisto[uiXcount] = uiBcnt[uiXcount];

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount-1] + uiRcnt[uiXcount]);

uiGhisto[uiXcount] = (uiGhisto[uiXcount-1] + uiGcnt[uiXcount]);

uiBhisto[uiXcount] = (uiBhisto[uiXcount-1] + uiBcnt[uiXcount]);

}

// 계산

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRhisto[uiXcount] = (uiRhisto[uiXcount] * 255) / (uiX*uiY);

uiGhisto[uiXcount] = (uiGhisto[uiXcount] * 255) / (uiX*uiY);

uiBhisto[uiXcount] = (uiBhisto[uiXcount] * 255) / (uiX*uiY);

}


//n[i]=sum[i]*(1/16)*7 


// 평활화 누적값 // 끝----------------------------------------------


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt[uiXcount] = (uiRcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt[uiXcount] = (uiGcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt[uiXcount] = (uiBcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}

// 히스토그램 세로축 값 변환 //끝------------------------------------


// 편집된 Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY*2; uiY < uiYcount; --uiYcount)

{

for(uiXcount = uiX; 0 < uiXcount; --uiXcount)

{

++uiRcnt2[uiRhisto[*(ucpPixel+2)]];

++uiGcnt2[uiGhisto[*(ucpPixel+1)]];

++uiBcnt2[uiBhisto[*ucpPixel]];


SetPixel(MemDC, uiXcount-1, uiYcount-1,

RGB(uiRhisto[*(ucpPixel+2)], uiGhisto[*(ucpPixel+1)], uiBhisto[*ucpPixel]));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}

// 편집된 Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt2[uiXcount])

{

uiYcount = uiRcnt2[uiXcount];

}

if(uiYcount < uiGcnt2[uiXcount])

{

uiYcount = uiGcnt2[uiXcount];

}

if(uiYcount < uiBcnt2[uiXcount])

{

uiYcount = uiBcnt2[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt2[uiXcount] = (uiRcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt2[uiXcount] = (uiGcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt2[uiXcount] = (uiBcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}


//히스토그램 그리기 //시작-------------------------------------------

Histo = CreateCompatibleBitmap(hdc, 260, SCREEN_Y_SIZE);

SelectObject(MemDC, Histo);

/*

SetBkColor(MemDC, RGB(100,100,100));

aaa = GetBkColor(MemDC);

wsprintf(str, TEXT("[%08X]"), aaa);

MessageBox(hWnd, str, TEXT("hi"), MB_OK);

*/

// SCREEN 바탕 흰색으로 그리기// 시작--------------------------------

for(uiYcount = 0; SCREEN_Y_SIZE > uiYcount; ++uiYcount)

{

for(uiXcount = 0; 260 > uiXcount; ++uiXcount)

{

SetPixel(MemDC, uiXcount, uiYcount, RGB(255, 255, 255));

}

}

// SCREEN 바탕 흰색으로 그리기// 끝----------------------------------


MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

OldPen = (HPEN)SelectObject(MemDC, MyPen);

MoveToEx(MemDC, 0, 0, NULL);

LineTo(MemDC, 0, 256);

LineTo(MemDC, 259, 256);


MoveToEx(MemDC, 0, 270, NULL);

LineTo(MemDC, 0, 270+256);

LineTo(MemDC, 259, 270+256);

// 빨강색 그래프

MoveToEx(MemDC, 3, 256-uiRcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiRcnt[uiXcount]);

}


// 초록색 그래프

MoveToEx(MemDC, 3, 256-uiGcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiGcnt[uiXcount]);

}


// 파랑색 그래프

MoveToEx(MemDC, 3, 256-uiBcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiBcnt[uiXcount]);

}




MoveToEx(MemDC, 3, 270+256-uiRcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiRcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiGcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiGcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiBcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiBcnt2[uiXcount]);

}

//히스토그램 그리기 //끝---------------------------------------------


SelectObject(hdc, OldPen);

SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

DeleteObject(MyPen);

ReleaseDC(hWnd, hdc);

free(BMbuf);

}

else

{

MessageBox(hWnd, TEXT("파일을 열 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

MemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);


BitBlt(hdc, XOFFSET, -yPos, uiX, uiY*2, MemDC, 0, 0, SRCCOPY);


(HBITMAP)SelectObject(MemDC, Histo);


BitBlt(hdc, 5, 180-yPos, 260, SCREEN_Y_SIZE, MemDC, 0, 0, SRCCOPY);


SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

EndPaint(hWnd, &ps);

return 0;

case WM_VSCROLL:

yInc = 0;

switch(LOWORD(wParam))

{

case SB_LINEUP:

yInc = -40;

break;

case SB_LINEDOWN:

yInc = 40;

break;

case SB_PAGEUP:

yInc = -200;

break;

case SB_PAGEDOWN:

yInc = 200;

break;

case SB_THUMBTRACK:

yInc = HIWORD(wParam)-yPos;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_KEYDOWN:

yInc = 0;

switch(wParam)

{

case VK_UP:

yInc = -40;

break;

case VK_DOWN:

yInc = 40;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_DESTROY:

DeleteObject(Screen);

DeleteObject(Histo);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}




결과


흑백이미지일 경우,

위에 그림이 원본, 밑에 그림이 평활화된 이미지.





색깔이미지일 경우,

위에 그림이 원본, 밑에 그림이 평활화된 이미지.












--------------------

이미지 스트레칭

--------------------


------- 비트맵 이미지를 스트레칭 처리하는 소스



#include <windows.h>


#define BITMAP_MAXSIZE (1024*768*3+10)

#define XOFFSET 280

#define X_WIDTH_SIZE 100

#define ALPA

#define SCREEN_Y_SIZE 270*2

#define SCROLL_SIZE 100*6


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("First");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

 ,LPSTR lpszCmdParam,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,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW | WS_VSCROLL,

100,40,800,660,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);

while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


unsigned char * BMbuf;

unsigned int uiRcnt[256];

unsigned int uiGcnt[256];

unsigned int uiBcnt[256];

unsigned int uiRcnt2[256];

unsigned int uiGcnt2[256];

unsigned int uiBcnt2[256];

unsigned int uiRStretch[256];  // 스트레칭으로 사용할 변수

unsigned int uiGStretch[256];  // 스트레칭으로 사용할 변수

unsigned int uiBStretch[256];  // 스트레칭으로 사용할 변수

HBITMAP Screen;

HBITMAP Stretch;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HDC hdc;

static HDC MemDC;

PAINTSTRUCT ps;

HANDLE hFile;

DWORD dwRead;

TCHAR str[1024];

static BITMAPFILEHEADER * stpBFH;

static BITMAPINFOHEADER * stpBIH;

static unsigned int uiX;

static unsigned int uiY;

unsigned int uiXcount;

unsigned int uiYcount;

unsigned char * ucpPixel;

static unsigned int uiPad;

HBITMAP OldBitmap;

static int yPos;

int yInc;

int iBorW;

HPEN OldPen, MyPen;

int Rhigh, Ghigh, Bhigh;

int Rlow, Glow, Blow;

switch (iMessage)

{

case WM_CREATE:

SetScrollRange(hWnd, SB_VERT, 0, SCROLL_SIZE, TRUE);

SetScrollPos(hWnd, SB_VERT, 0, TRUE);

hFile = CreateFile(TEXT("image6.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);


BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

if(0 == BMbuf)

{

MessageBox(hWnd, TEXT("동적할당을 받을 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

if(INVALID_HANDLE_VALUE != hFile)

{

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


// 정보 출력 //시작------------------------------------------------------

wsprintf(str, TEXT("[%c][%c]"), BMbuf[0], BMbuf[1]);

CreateWindow(TEXT("static"), TEXT("파일 타입 : "), WS_CHILD | WS_VISIBLE,

0, 0, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 0, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d byte]"), stpBFH->bfSize);

CreateWindow(TEXT("static"), TEXT("파일 크기 : "), WS_CHILD | WS_VISIBLE,

0, 20, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 20, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biWidth);

CreateWindow(TEXT("static"), TEXT("가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 40, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 40, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%u]"), stpBIH->biHeight);

CreateWindow(TEXT("static"), TEXT("세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 60, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 60, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%08X]"), stpBFH->bfOffBits);

CreateWindow(TEXT("static"), TEXT("bfOffbits : "), WS_CHILD | WS_VISIBLE,

0, 80, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 80, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSize);

CreateWindow(TEXT("static"), TEXT("헤더 크기 : "), WS_CHILD | WS_VISIBLE,

0, 100, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 100, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d bytes]"), stpBIH->biSizeImage);

CreateWindow(TEXT("static"), TEXT("그림 크기 : "), WS_CHILD | WS_VISIBLE,

0, 120, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 120, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biXPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 가로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 140, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 140, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);


wsprintf(str, TEXT("[%d pixel]"), stpBIH->biYPelsPerMeter);

CreateWindow(TEXT("static"), TEXT("이미지 세로 크기 : "), WS_CHILD | WS_VISIBLE,

0, 160, 130, 20, hWnd, (HMENU)-1, g_hInst, NULL);

CreateWindow(TEXT("static"), str, WS_CHILD | WS_VISIBLE,

130, 160, X_WIDTH_SIZE, 20, hWnd, (HMENU)-1, g_hInst, NULL);

// 정보 출력 //끝-----------------------------------------------------------

uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);


hdc = GetDC(hWnd);

MemDC = CreateCompatibleDC(hdc);


Screen = CreateCompatibleBitmap(hdc, uiX, uiY * 2);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);

// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY; 0 < uiYcount; --uiYcount)

{

for(uiXcount = 0; uiX > uiXcount; ++uiXcount)

{

/*iBorW = ((*(ucpPixel+2)) + (*(ucpPixel+1)) + (*ucpPixel))/3;

*(ucpPixel+2)= iBorW;

*(ucpPixel+1)= iBorW;

*(ucpPixel+0)= iBorW;*/

++uiRcnt[*(ucpPixel+2)];

++uiGcnt[*(ucpPixel+1)];

++uiBcnt[*ucpPixel];


SetPixel(MemDC, uiXcount, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}



// Bitmap 그리기 //끝-----------------------------------------------


// 히스토그램 세로축 값 변환 //시작----------------------------------



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rlow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiRcnt[uiXcount] != 0)

{

Rhigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Rhigh : %d, Rlow : %d"), Rhigh, Rlow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Glow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiGcnt[uiXcount] != 0)

{

Ghigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Ghigh : %d, Glow : %d"), Ghigh, Glow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);



for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Blow = uiXcount;

break;

}

}

for(uiXcount = 255; 0 <= uiXcount; --uiXcount)

{

if(uiBcnt[uiXcount] != 0)

{

Bhigh = uiXcount;

break;

}

}

// wsprintf(str, TEXT("Bhigh : %d, Blow : %d"), Bhigh, Blow);

// MessageBox(hWnd, str, TEXT("test"), MB_OK);


/*

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRStretch[uiXcount] = ((uiRcnt[uiXcount]-Rlow) * 255) / (Rhigh - Rlow);

uiGStretch[uiXcount] = ((uiGcnt[uiXcount]-Glow) * 255) / (Ghigh - Glow);

uiBStretch[uiXcount] = ((uiBcnt[uiXcount]-Blow) * 255) / (Bhigh - Blow);

}*/



uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt[uiXcount])

{

uiYcount = uiRcnt[uiXcount];

}

if(uiYcount < uiGcnt[uiXcount])

{

uiYcount = uiGcnt[uiXcount];

}

if(uiYcount < uiBcnt[uiXcount])

{

uiYcount = uiBcnt[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt[uiXcount] = (uiRcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt[uiXcount] = (uiGcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt[uiXcount] = (uiBcnt[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}

// 히스토그램 세로축 값 변환 //끝------------------------------------


// Bitmap 그리기 //시작---------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits;

for(uiYcount = uiY*2; uiY < uiYcount; --uiYcount)

{

for(uiXcount = 0; uiX > uiXcount; ++uiXcount)

{

*(ucpPixel+2) = (((*(ucpPixel+2))-Rlow) * 255) / (Rhigh - Rlow);

*(ucpPixel+1) = (((*(ucpPixel+1))-Glow) * 255) / (Ghigh - Glow);

*(ucpPixel+0) = (((*(ucpPixel+0))-Blow) * 255) / (Bhigh - Blow);


++uiRcnt2[*(ucpPixel+2)];

++uiGcnt2[*(ucpPixel+1)];

++uiBcnt2[*ucpPixel];


SetPixel(MemDC, uiXcount, uiYcount-1,

RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}

// Bitmap 그리기 //끝-----------------------------------------------


uiYcount = 0;

for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

if(uiYcount < uiRcnt2[uiXcount])

{

uiYcount = uiRcnt2[uiXcount];

}

if(uiYcount < uiGcnt2[uiXcount])

{

uiYcount = uiGcnt2[uiXcount];

}

if(uiYcount < uiBcnt2[uiXcount])

{

uiYcount = uiBcnt2[uiXcount];

}

}


for(uiXcount = 0; 256 > uiXcount; ++uiXcount)

{

uiRcnt2[uiXcount] = (uiRcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiGcnt2[uiXcount] = (uiGcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

uiBcnt2[uiXcount] = (uiBcnt2[uiXcount] * 255) / uiYcount;//(uiX*uiY);

}


//히스토그램 그리기 //시작-------------------------------------------

Stretch = CreateCompatibleBitmap(hdc, 260, SCREEN_Y_SIZE);

SelectObject(MemDC, Stretch);

/*

SetBkColor(MemDC, RGB(100,100,100));

aaa = GetBkColor(MemDC);

wsprintf(str, TEXT("[%08X]"), aaa);

MessageBox(hWnd, str, TEXT("hi"), MB_OK);

*/

// SCREEN 바탕 흰색으로 그리기// 시작--------------------------------

for(uiYcount = 0; SCREEN_Y_SIZE > uiYcount; ++uiYcount)

{

for(uiXcount = 0; 260 > uiXcount; ++uiXcount)

{

SetPixel(MemDC, uiXcount, uiYcount, RGB(255, 255, 255));

}

}

// SCREEN 바탕 흰색으로 그리기// 끝----------------------------------


MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

OldPen = (HPEN)SelectObject(MemDC, MyPen);

MoveToEx(MemDC, 0, 0, NULL);

LineTo(MemDC, 0, 256);

LineTo(MemDC, 259, 256);


MoveToEx(MemDC, 0, 270, NULL);

LineTo(MemDC, 0, 270+256);

LineTo(MemDC, 259, 270+256);

// 빨강색 그래프

MoveToEx(MemDC, 3, 256-uiRcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiRcnt[uiXcount]);

}


// 초록색 그래프

MoveToEx(MemDC, 3, 256-uiGcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiGcnt[uiXcount]);

}


// 파랑색 그래프

MoveToEx(MemDC, 3, 256-uiBcnt[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 256-uiBcnt[uiXcount]);

}



MoveToEx(MemDC, 3, 270+256-uiRcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiRcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiGcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiGcnt2[uiXcount]);

}


MoveToEx(MemDC, 3, 270+256-uiBcnt2[0], NULL);

for(uiXcount = 1; 256 > uiXcount; ++uiXcount)

{

MyPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));

SelectObject(MemDC, MyPen);

LineTo(MemDC, uiXcount+3, 270+256-uiBcnt2[uiXcount]);

}

//히스토그램 그리기 //끝---------------------------------------------


SelectObject(hdc, OldPen);

SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

DeleteObject(MyPen);

ReleaseDC(hWnd, hdc);

free(BMbuf);

}

else

{

MessageBox(hWnd, TEXT("파일을 열 수 없습니다."), TEXT("오류"), MB_OK);

DestroyWindow(hWnd);

}

return 0;

case WM_PAINT:

hdc = BeginPaint(hWnd, &ps);

MemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(MemDC, Screen);


BitBlt(hdc, XOFFSET, -yPos, uiX, uiY*2, MemDC, 0, 0, SRCCOPY);


(HBITMAP)SelectObject(MemDC, Stretch);


BitBlt(hdc, 5, 180-yPos, 260, SCREEN_Y_SIZE, MemDC, 0, 0, SRCCOPY);


SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

EndPaint(hWnd, &ps);

return 0;

case WM_VSCROLL:

yInc = 0;

switch(LOWORD(wParam))

{

case SB_LINEUP:

yInc = -40;

break;

case SB_LINEDOWN:

yInc = 40;

break;

case SB_PAGEUP:

yInc = -200;

break;

case SB_PAGEDOWN:

yInc = 200;

break;

case SB_THUMBTRACK:

yInc = HIWORD(wParam)-yPos;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_KEYDOWN:

yInc = 0;

switch(wParam)

{

case VK_UP:

yInc = -40;

break;

case VK_DOWN:

yInc = 40;

break;

}

if(yPos+yInc < 0)

yInc = -yPos;

if(yPos+yInc > SCROLL_SIZE)

yInc = SCROLL_SIZE - yPos;


yPos = yPos + yInc;

ScrollWindow(hWnd, 0, -yInc, NULL, NULL);

SetScrollPos(hWnd, SB_VERT, yPos, TRUE);

return 0;

case WM_DESTROY:

DeleteObject(Screen);

DeleteObject(Stretch);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}



결과



위에 이미지가 원본영상으로 전체적으로 어둡다.

밑에 이미지가 스트레칭 처리된 이미지로 밝아졌다.





전체적으로 밝기만 올렸을 경우,





설정

트랙백

댓글

20141008 (C++ 맴버 이니셜라이저)

154일차








----------

C++

----------





------- 맴버 이니셜라이저(Member Initializer)

우선 예제를 보자.


class Point

{

private:

int x;

int y;


public:

Point()

{

cout << "Point 디폴트 생성자 호출" << endl;

x = 0;

y = 0;

}


Point(int x, int y)

{

cout << "Point 생성자 호출" << endl;

Point::x = x;

Point::y = y;

}


~Point()

{

cout << "Point 소멸자 호출" << endl;

}


void Print()

{

cout << "[" << x << ", " << y << "]\n";

}

};


class Rectangle

{

public:

Point upLeft;

Point lowRight;


public:

Rectangle()

{

cout << "Rectangle 디폴트 생성자 호출" << endl;

}


Rectangle(int x1, int y1, int x2, int y2)

:upLeft(x1, y1), lowRight(x2, y2) // 함수의 코드를 실행전 이 코드를 먼저 수행

{

cout << "Rectangle 생성자 호출" << endl;

}


~Rectangle()

{

cout << "Rectangle 소멸자 호출" << endl;

}


void Print()

{

upLeft.Print();

lowRight.Print();

}

};


int main(void)

{

Rectangle obj1;

obj1.Print();


Rectangle obj2(1,2,3,4); // 요놈을 자세히 볼 것.

obj2.Print();


return 0;

}


결과



이렇듯 Rectangle 객체가 생성되기 전에 Point 객체가 먼저 생성되는데


Rectangle(int x1, int y1, int x2, int y2)

:upLeft(x1, y1), lowRight(x2, y2) // 함수의 코드를 실행전 이 코드를 먼저 수행

{

cout << "Rectangle 생성자 호출" << endl;

}


생성자와 중괄호 사이에 저렇게 넣으면 Point 객체가 생성되기 전에 빨강줄 코드부터 수행한다.

이것이 맴버 이니셜라이저이다.




또 이런 경우도 가능하다.

class Rectangle

{

public:

Point upLeft;

Point lowRight;

const int iNum; // const int iNum = 100;  //error


public:

Rectangle()

:iNum(100)

{

cout << "Rectangle 디폴트 생성자 호출" << endl;

// iNum = 100; // error;

}

};





--- C++에서는 변수 초기화에 괄호를 사용하여서도 가능하다.


예)

int iNum2(200);    // int iNum2 = 200;

cout << "iNum2 : " << iNum2 << endl;


int * ip(&iNum2);    // int * ip = &iNum2;

cout << "*ip : " << *ip << endl;


char buf[]("hihihi");    // char buf[] = "hihihi";

cout << "buf : " << buf << endl;


char * pbuf("this is test");    // char * pbuf = "this is rest";

cout << "*pbuf : " << pbuf << endl;


결과










--- 생성자, 소멸자 다른 예제


class Point

{

private:

int x;

int y;


public:

Point()

{

cout << "Point 디폴트 생성자 호출" << endl;

x = 0;

y = 0;

}

~Point()

{

cout << "Point 소멸자 호출" << endl;

}

};


void test(Point obj)

{

80: Point obj1;


82: obj1 = obj;

}


int main()

{

87: Point objA;


89: test(objA);


91: return 0;

}


결과



생성자가 두 번 호출되었고, 소멸자는 3번 호출되었다.

어셈블리로 확인해 본 결과.


_main PROC ; main 함수

; Line 87

lea ecx, DWORD PTR _objA$[ebp]

call ??0Point@@QAE@XZ         ; Point::Point 생성자 호출

mov DWORD PTR __$EHRec$[ebp+8], 0

; Line 89

mov eax, DWORD PTR _objA$[ebp+4]

push eax

mov ecx, DWORD PTR _objA$[ebp]

push ecx

call ?test@@YAXVPoint@@@Z ; test

add esp, 8

; Line 91

mov DWORD PTR $T30281[ebp], 0

mov DWORD PTR __$EHRec$[ebp+8], -1

lea ecx, DWORD PTR _objA$[ebp]

call ??1Point@@QAE@XZ         ; Point::~Point 소멸자 호출

mov eax, DWORD PTR $T30281[ebp]


?test@@YAXVPoint@@@Z PROC ; test 함수

; Line 80

lea ecx, DWORD PTR _obj1$[ebp]

call ??0Point@@QAE@XZ         ; Point::Point 생성자 호출

; Line 82

mov eax, DWORD PTR _obj$[ebp]

mov DWORD PTR _obj1$[ebp], eax

mov ecx, DWORD PTR _obj$[ebp+4]

mov DWORD PTR _obj1$[ebp+4], ecx

; Line 83

lea ecx, DWORD PTR _obj1$[ebp]

call ??1Point@@QAE@XZ         ; Point::~Point 소멸자 호출

mov DWORD PTR __$EHRec$[ebp+8], -1

lea ecx, DWORD PTR _obj$[ebp]

call ??1Point@@QAE@XZ         ; Point::~Point 소멸자 호출


어셈에서 이런 식으로 처리했다.


생성자가 main에서 Point objA를 선언하면서 한 번,

test에서 Point obj1을 선언하면서 한 번 호출하고,


소멸자는 main return 하면서 한 번,

test에서 return하면서 obj1, obj가 소멸되면서 두 번 호출하였다.








설정

트랙백

댓글

20141007 (C++ 정보은닉, 캡슐화, 생성자, 소멸자, 비디오처리)

153일차








-----------

C++

-----------




------- 정보은닉, 캡슐화


--- 정보은닉

정보은닉은 말 그대로 외부에 정보를 숨기는 역할이다.

class 내에 접근 지시자로 private와 const 함수가 이에 해당한다.


예제)


class Rectangle

{

private:

Point upLeft;

Point lowRight;


public:

bool InitMembers(const Point &ul, const Point &lr);

void ShowRectInfo() const;

};


클래스 내에 변수들은 private로 외부에서 접근 가능하지 못하고,
InitMembers라는 함수를 통해서만 수정이 가능하게 만들어 놓았다.

ShowRectInfo() 함수 선언 뒤에 const 가 선언되어 있는데,

이 함수는 내부 데이터를 읽기만 한다는 뜻이다.

만약 이 함수에서 데이터를 쓰는 코드가 들어 있을 시, 컴파일때 에러 처리가 된다.

또 const 함수 내에서 다른 함수를 호출시 그 함수도 const 옵션이 붙어 있어야만

호출이 가능하지, 붙지 않으면 이것 또한 컴파일시 에러 처리가 된다.




--- 캡슐화

예를 들어 함수 1, 2, 3 이 있는데 1 -> 2 -> 3 순으로 실행 되어야만 기능이 제대로 되는 함수라 하자.

그런데 프로그래머가 작성 중 이걸 잊어버리고 잘 못 코딩 할 경우 이것을 방지해 주는 역할이다.


예제)

#include <iostream>


using namespace std;


class SinivelCap

{

public:

void Take() const

{

cout << "콧물이 싹~ 납니다." << endl;

}

};


class SneezeCap

{

public:

void Take() const

{

cout << "재채기가 멎습니다." << endl;

}

};


class SnuffleCap

{

public:

void Take() const

{

cout << "코가 뻥 뚫립침니다." << endl;

}

};


class CONTAC600

{

private:

SinivelCap sin;

SneezeCap sne;

SnuffleCap snu;


public:

void Take() const

{

sin.Take();

sne.Take();

snu.Take();

}

};


class ColdPatient

{

public:

void TakeCONTAC600(const CONTAC600 &cap) const

{

cap.Take();

}

};


int main()

{

CONTAC600 cap;

ColdPatient sufferer;

sufferer.TakeCONTAC600(cap);


return 0;

}



위의 예제를 통해 보았듯이 이 클래스를 실행하면 항상

콧물 -> 재채기 -> 코 뻥.. 순으로 실행이 된다. 이런 것을 캡슐화라한다고 한다.




정보은닉이나 캡슐화나 프로그래머들이 소스 작성 시

에러를 줄여 안전성을 높이기 위한 기능이다.








------- 생성자, 소멸자

생성자는 클래스의 객체 생성시 실행시켜주는 함수?이다.


예제)


class smart

{

public:

int * ip;

};


int main()

{

smart obj1;

smart obj2;

smart obj3;


obj1.ip = 0;

obj2.ip = 0;

obj3.ip = 0;


return 0;

}


위의 예제에서 항상 smart 객체 생성시 ip 값에 0으로 초기화를 해줘야 하는데

매번 해 주기도 개체수가 많아진다면 엄청난 일이 되어 버린다.

그래서 다음과 같이 생성자를 만들어 준다.


class smart

{

public:

int * ip;


public:

smart()

{

ip = 0;

}

};


int main()

{

smart obj1;

smart obj2;

smart obj3;


return 0;

}


이렇게 하고나면 객체가 만들어 지는 즉시 smart()라는 생성자를 실행시켜

초기화를 해준다.

생성자는 클래스 이름과 같게 만들고 함수로 치자면 리턴 타입이 없다.



--- 소멸자

소멸자는 객체가 사라질때 호출되는 함수?이다.


예제)

#include <iostream>


using namespace std;


class smart

{

public:

int * ip;

int iNum;


public:

smart() // default 생성자라 부른다

{

iNum = 0;

cout << iNum << "Default 생성자 호출" << endl;

ip = new int;

}


smart(int iNum) // default 생성자가 아님

{

smart::iNum = iNum;

cout << iNum << "생성자 호출" << endl;

ip = new int;

}


~smart()  // 소멸자

{

cout << iNum << "소멸자 호출" << endl;

delete ip;

}

};


int main()

{

smart obj1(1);

smart obj2(2);

smart obj3(3);

smart obj4;

/*

obj1.ip = 0;

obj2.ip = 0;

obj3.ip = 0;

*/

/* obj1.iNum = 1;

obj2.iNum = 2;

obj3.iNum = 3;

*/

cout << "-----------------------------------------------" << endl;


return 0;

}


결과














--------------

영상 처리

--------------


#include <windows.h>

#include "vfw.h"

#pragma comment(lib, "vfw32.lib")


#define BITMAP_MAXSIZE (1024*768*3+10)


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND HWndMain;

LPCTSTR lpszClass=TEXT("WiseCat");


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst = hInstance;


WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(  lpszClass

,lpszClass

,WS_OVERLAPPEDWINDOW

,CW_USEDEFAULT

,CW_USEDEFAULT

,CW_USEDEFAULT,CW_USEDEFAULT

,NULL

,(HMENU)NULL

,hInstance

,NULL);        

ShowWindow(hWnd,nCmdShow);


while(GetMessage(&Message,NULL,0,0))

{

TranslateMessage(&Message);

DispatchMessage(&Message);

}


return (int)Message.wParam;

}


LRESULT CALLBACK FramInfo(HWND, LPVIDEOHDR);


HWND vfw;

BITMAPINFO Bm;

HDC hdc;

BITMAPFILEHEADER * stpBFH;

BITMAPINFOHEADER * stpBIH;

unsigned char * BMbuf;

unsigned int uiPad;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

HANDLE hFile;

PAINTSTRUCT ps;

static unsigned int uiX;

static unsigned int uiY;

DWORD dwRead;


switch(iMessage)

{

case WM_CREATE:

HWndMain = hWnd;


// Bitmap 열고 처리 //시작---------------------------------------------

hFile = CreateFile(TEXT("image.bmp"),

GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if(INVALID_HANDLE_VALUE != hFile)

{

BMbuf = (unsigned char *)malloc(BITMAP_MAXSIZE);

ReadFile(hFile, BMbuf, BITMAP_MAXSIZE, &dwRead, NULL);

CloseHandle(hFile);


stpBFH = (BITMAPFILEHEADER *)BMbuf;

stpBIH = (BITMAPINFOHEADER *)(BMbuf + sizeof(BITMAPFILEHEADER));


uiX = (unsigned int)(stpBIH->biWidth);

uiPad = uiX%4;

uiY = (unsigned int)(stpBIH->biHeight);

}

// Bitmap 열고 처리 //끝-----------------------------------------------


// 웹캠 설정 // 시작------------------------

vfw = capCreateCaptureWindow(  TEXT("CAM")

,WS_CHILD | WS_VISIBLE

,0

,0

,400

,300

,hWnd

,NULL);


capDriverConnect(vfw,0);

capGetVideoFormat(vfw,&Bm,sizeof(Bm));

Bm.bmiHeader.biWidth  = 320;

Bm.bmiHeader.biHeight = 240;

capSetVideoFormat(vfw,&Bm,sizeof(Bm));

//capDlgVideoFormat(m_capwnd); 

capSetCallbackOnFrame(vfw, FramInfo);

capPreviewRate(vfw, 1);

capPreview(vfw, FALSE);

// 웹캠 설정 // 끝--------------------------

return 0;


case WM_PAINT:

hdc = BeginPaint(hWnd,&ps);

EndPaint(hWnd,&ps);

return 0;


case WM_DESTROY:

free(BMbuf);

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}


LRESULT CALLBACK FramInfo(HWND hWnd, LPVIDEOHDR lpData)

{

static int iCntX;

static int iCntY;

static int Jump;

unsigned char * ucpPixel;


// 원본 영상 그리기 // 시작-------------------------------

hdc = GetDC(HWndMain);

StretchDIBits(hdc  , 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 원본 영상 그리기 // 끝---------------------------------


// 영상 정보 편집 // 시작--------------------------------------------

ucpPixel = BMbuf + stpBFH->bfOffBits - 3;

Jump= 0;

for(iCntY = 0; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)  

{        

for(iCntX = 0; iCntX  < Bm.bmiHeader.biWidth  ; ++iCntX, Jump += 3)

{

ucpPixel = ucpPixel + 3;

if(lpData->lpData[Jump + 2] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 1] > 100)

{

continue;

}

else if(lpData->lpData[Jump + 0] > 50)

{

lpData->lpData[Jump] = *(ucpPixel + 0);  // Blue

lpData->lpData[Jump + 2] = *(ucpPixel + 2);  // Red

lpData->lpData[Jump + 1] = *(ucpPixel + 1);  // Green

}

}

ucpPixel = ucpPixel + uiPad;

}

// 영상 정보 편집 // 끝----------------------------------------------


// 편집된 영상 그리기 // 시작----------------------------

StretchDIBits(hdc  , Bm.bmiHeader.biWidth +20

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, 0

, 0

, Bm.bmiHeader.biWidth

, Bm.bmiHeader.biHeight

, lpData->lpData

, &Bm

, DIB_RGB_COLORS

, SRCCOPY);

// 편집된 영상 그리기 // 끝------------------------------


ReleaseDC(HWndMain, hdc);


return 0;

}



설정

트랙백

댓글

20141006 (C++ struct, class)

152 일차







---------------

C++

---------------




------- struct


C++에서 구조체에 기능이 추가되었다.

- 구조체 선언시 struct 생략 가능

- 구조체 내에 함수 선언 가능



--- 구조체 선언시 struct 생략 가능


예제)

#include <iostream>


using namespace std;


struct smart

{

int iNum;

};


int main()

{

struct smart a;

a.iNum = 1;


cout << a.iNum << endl;


smart b;     // struct 생략 가능

b.iNum = 2;


cout << b.iNum << endl;


b.test();


return 0;

}






--- 구조체 내에 함수 선언 가능


예제)

#include <iostream>


using namespace std;


struct smart

{

int iNum;


void test()

{

cout << " test 함수 호출" << endl;

};

};


int main()

{

struct smart a;

a.iNum = 1;


a.test();    // 구조체 내에 함수 호출


return 0;

}






추가된 예제)

#include <iostream>


using namespace std;


void test()    // 전역? test 함수 선언

{

cout << "전역 test 함수" << endl;

}


struct smart

{

int iNum;


void test();    // 구조체 test 함수 선언

};


int iNum = 100;    // 전역 변수 iNum


void smart::test()    // 구조체 test 함수 정의.    이런식으로 전역에서 정의 가능.

{

int iNum = 50;


cout << ::iNum << smart::iNum << iNum << " test 함수 호출" << endl;

//                전역변수    구조체변수     지역변수

// 우선순위 :  전역변수 < 구조체변수 < 지역변수

::test();    // 전역 test 함수 호출

};


int main()

{

struct smart a;

a.iNum = 1;


cout << a.iNum << endl;


smart b;

b.iNum = 2;


cout << b.iNum << endl;


b.test();

a.test();


return 0;

}


결과










--- class & struct




구조체 선언부에서 struct 를 class로만 바꾸면 바로 클래스가 구현된 것이다.

struct + @ = class       (@ 에는 접근 속성, 상속 등등이 있다)


예제)

#include <iostream>


using namespace std;


//struct smart

class smart

{

public:    //  접근 속성으로 접근 제어 지시자라 불림

char caName[7];


void In();

void Out();

};


void smart::In()

{

cout << "이름을 입력하세요 : ";

cin >> caName;

}


void smart::Out()

{

cout << "나의 이름은 " << caName << " 입니다." << endl;

}


int main()

{

smart A;

smart B;


A.In();

B.In();


A.Out();

B.Out();


return 0;

}







--- 접근 제어 지시자는 3가지로

- public

- private

- protected

가 있다.


기본적으로 생략 시 private가 걸린다.


- public : 모두 접근 가능

- private : 클래스내에서만 접근 가능

- protected : 상속된 클래스에서 접근 가능 (상속은 추후에...)



예제)

#include <iostream>


using namespace std;


//struct smart

class smart

{

private:    // 외부 접근 불가능

char caName[7];


public:    // 아무나 사용 가능

void In();

void Out();

};


void smart::In()

{

cout << "이름을 입력하세요 : ";

cin >> caName;

}


void smart::Out()

{

cout << "나의 이름은 " << caName << " 입니다." << endl;

}


int main()

{

smart A;

smart B;


A.In();

B.In();


A.Out();

B.Out();


// B.caName[0] = 'a';    // error 접근 불가


return 0;

}














설정

트랙백

댓글

20141002 (C++ scope, namespace, bool, reference, new, delete, 비디오 처리 소스만)

151일차










---------

C++

---------




------- line

inline의 단점은 프로그램의 용량이 증가한다.

간단하고 자주 호출되는 함수에만 사용할 것.





------- scope 연산자

std::cout      여기서 :: 을 scope라고 부른다.


활용 예)


include <iostream>


int num = 100;


int main()

{

    int num = 200;


    std::cout << num << std::endl;

    std::cout << ::num << std::endl;


    return 0;

}


결과

  200  

  100  



변수 앞에 :: 을 붙이면 전역 변수에 접근할 수 있다.






------- namespace
지금까지 std::cout 앞에 std를 붙이는게 제법 귀찮다.

include 밑에 다음과 같은 명령을 추가한다.


using namespace std;


using : 사용하겠다

namespace : 이름 공간

std : std를


라는 뜻 정도로 보면 될 것 같다.

이 명령을 추가하고 나면 이제 cout과 cin,  endl 앞에는 std:: 이 생략 가능하다.


예)

include <iostream>


using namespace std;


int main()

{

    int num;


    cout << "숫자 입력 : ";

    cin >> num;


    cout << "입력 하신 숫자는 " << num << "입니다." << endl;


    return 0;

}






------- bool

C에서는 없던 bool 이라는 데이터형이 하나 추가되었다.

bool은 false, true 두 가지만 있다.

false  :  0

true   :  1

(winapi에서는 BOOL, TRUE, FALSE 대문자로 주의 할 것.)







------- Reference

C에서 변수 'A'를 가리킬 때 포인터를 사용하였다.


int a = 10;

int * p = &a;


C++에서는 reference가 추가 되었다.


int a = 10;

int & r = a;


포인터는 a(변수)의 주소를 가리킨 반면,

레퍼런스는 a(변수)의 또 다른 이름이다.


말 그대로 포인터는 4 byte형 메모리를 더 생성하였고,

레퍼런스는 a(변수)에 또 다른 이름만 붙었으니 메모리는 그대로다.





--- 특징

- 보통 함수 인자로 사용

- 변수 선언시 초기화를 해줘야만 사용 가능


--- 따라서 C++에서는 함수 호출 방식이 3가지다.

- Call by Value                   test(int);

- Call by Address               test(int *);

- Call by Reference             test(int &);







------- new, delete

C에서 malloc, free와 같은 기능


예제)

#include <iostream>

#include <string.h>

using namespace std;


char * MakeStrAdr(int len)

{

// char * str = (char*)malloc(sizeof(char)*len);

char * str = new char[len];

return str;

}


int main(void)

{

char * str = MakeStrAdr(20);

strcpy(str, "I am so happy~");

cout << str << endl;

// free(str);

delete []str;

return 0;

}



배열은 delete 할때, delete와 변수 사이에 배열이라는 표시로 []를 넣어 줘야한다.











----------------------

비디오 처리

----------------------




#include <windows.h>

#include <Vfw.h>

#pragma comment (lib,"vfw32.lib")


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

HINSTANCE g_hInst;

HWND hWndMain;

LPCTSTR lpszClass=TEXT("Class");

//WinMain 시작


//windows 그리기//시작----------------------------------------------------

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance

      ,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;

//1. 윈도우 속성값 등록

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL, IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=NULL;

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);  //주소에 Write

 

//2. 윈도우 생성

hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

 CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

 NULL, (HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow); //화면에 뿌려줌

 

//3. 메시지 처리(무한 반복)

while (GetMessage(&Message,NULL,0,0))

{

 TranslateMessage(&Message);

 DispatchMessage(&Message);

}

return (int)Message.wParam;

}

//windows 그리기//끝------------------------------------------------------


LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr);

HBITMAP hBit;

BITMAPINFO Bm;


//메시지 처리//시작--------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

HDC hdc;

HWND hVFW;

PAINTSTRUCT ps;


switch(iMessage)

{

case WM_CREATE:

 hWndMain=hWnd;

 hdc=GetDC(hWndMain);

 hVFW=capCreateCaptureWindow(TEXT("VFW"),WS_CHILD | WS_VISIBLE , 0,0,320,240,hWnd,0);

 capDriverConnect(hVFW,0);

 capPreviewRate(hVFW,10);

 capGetVideoFormat(hVFW,&Bm, sizeof(Bm));

 Bm.bmiHeader.biWidth = 320;

 Bm.bmiHeader.biHeight = 240;

 capSetVideoFormat(hVFW, &Bm, sizeof(Bm));

 capPreview(hVFW,TRUE);


 hBit = CreateCompatibleBitmap(hdc, Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight);


 if (capSetCallbackOnFrame(hVFW,FramInfo) == FALSE)  // FramInfo를 Callback 함수 등록

 {

return FALSE;

 }

 ReleaseDC(hWndMain, hdc);

 return 0;

case WM_PAINT:

 hdc = BeginPaint(hWnd, &ps);

 EndPaint(hWnd, &ps);

 return 0;

case WM_DESTROY:

 PostQuitMessage(0);

 return 0;

}

return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}

//메시지 처리//끝----------------------------------------------------------


//비디오 처리 callback 함수 //시작-------------------------------------------

LRESULT CALLBACK FramInfo(HWND hVFW, LPVIDEOHDR VideoHdr)

{

HDC hdc;

HDC hMemDC;

HBITMAP OldBitmap;

int iCntX;

int iCntY;

int Jump;

 

hdc = GetDC(hWndMain);

hMemDC = CreateCompatibleDC(hdc);

OldBitmap = (HBITMAP)SelectObject(hMemDC, hBit);

 

         // VideoHdr에 들어있는 영상 정보 출력 // 시작-----------------------------------------

Jump=0;

for (iCntY=0 ; iCntY < Bm.bmiHeader.biHeight ; ++iCntY)

{

 //for (iCntX=0 ; iCntX < Bm.bmiHeader.biWidth ; ++iCntX)

 for (iCntX=Bm.bmiHeader.biWidth-1 ; 0 <= iCntX ; --iCntX)

 {

// 특정 색 전환//시작----------------------------------------------------------------------

 if(VideoHdr->lpData[Jump+2] < 70 && VideoHdr->lpData[Jump+2] > 40)

 {

  if(VideoHdr->lpData[Jump+1] < 110 && VideoHdr->lpData[Jump+1] > 70)

  {

   if(VideoHdr->lpData[Jump+0] < 110 && VideoHdr->lpData[Jump+0] > 70)

{

VideoHdr->lpData[Jump+2] = 0;

VideoHdr->lpData[Jump+1] = 0;

VideoHdr->lpData[Jump] = 0;

}

  }

 }

// 특정 색 전환//끝------------------------------------------------------------------------


 Jump = Jump + 3;   // 다음 픽셀로

 }

}

         // VideoHdr에 들어있는 영상 정보 출력 // 끝-------------------------------------------


BitBlt(hdc, 320,0,Bm.bmiHeader.biWidth,Bm.bmiHeader.biHeight,hMemDC,0,0,SRCCOPY);

SelectObject(hMemDC,OldBitmap);

ReleaseDC(hWndMain,hdc);


return 0;

}

//비디오 처리 callback 함수 //끝---------------------------------------------










설정

트랙백

댓글

20141001 (C++ inline, 비디오 처리)

150일차









-----------

C++

-----------




------- inline

함수를 호출시 오버헤드가 적게 발생하게 하는 역할



--- 오버헤드

작업을 할 때 부수적으로 꼭 해야할 일

함수가 매크로보다 오버헤드가 많이 발생하기 때문에

예전 개발자들은 많은 함수를 매크로로 작성하여 사용했다고 한다.

C++에서는 이런 매크로를 최대 줄이려고 그와 비슷한 역할을 하는

inline이 있다.





- 참고로 최적화에 불합리한 코드가 있을 시, 최적화 하지 않는다.

- 분할 컴파일 시 헤더파일에 선언해 줄 것.






(공유 폴더 설정)






mount -t vboxsf (공유디렉토리이름) /mnt/(디렉토리)

ex) mount -t vboxsf linux_to_windows /mnt/windows


안되면 $sudo apt-get install virtualbox-* 하고 다시 시디에 내용 설치.














-------------

비디오 처리

-------------


http://zzoyu.tistory.com/51 에서 퍼옴



코딩하기

1. VFW 라이브러리 추가하기

 라이브러리를 추가하는 방법은 두가지입니다. 하나는 소스 상단에 #pragma comment( lib, "vfw32.lib" )를 추가해 주는 것이고, 다른 하나는 프로젝트 링커 옵션에 추가하는 것입니다. VS2010에서 pragma를 쓰지 않고 라이브러리를 추가하는 법은 아래와 같습니다. 영문판 VS2010이기 때문에 한글판과 이름 등에 차이가 있을 수 있습니다. 굳이 vfw가 아니더라도, 모든 라이브러리가 같은 방법을 사용하니 참고하시기 바랍니다.




우선 vfw.h를 인클루드합니다.




프로젝트폴더 위에서 오른쪽 마우스를 클릭해 메뉴를 연 뒤, Properties 메뉴를 엽니다.




Linker->Input을 선택합니다.




Additional Dependencies의 라이브러리 목록을 클릭하면 ▼버튼이 생기는데, 이를 클릭합니다.




vfw32.lib를 추가합니다.



이건 프로젝트에 설정하는 경우이므로 만약 소스만 사용할 경우

매번 추가해 줘야 하므로 소스에서 lib를 추가하는 방법.


#include  밑에 추가


//lib를 소스에서 직접 추가 소스

//windows에서만 가능

#pragma comment (lib, "Vfw32.lib")




빌드에 성공했습니다.



2. WM_CREATE에서 설정하기



우선 캡쳐 윈도우 핸들을 생성하여 저장합니다.




웹캠과 연결하는 함수를 호출합니다.




이미지를 갱신하는 속도를 지정합니다.




비디오 포맷에 대한 정보를 biVFW 변수에 저장합니다.




직접 설정하면 번거롭기 때문에 기존 값에서 필요한 값만 수정합니다.




수정된 값을 반영합니다.




미리보기를 할 수 있게 해줍니다.





설정

트랙백

댓글