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 변수에 저장합니다.




직접 설정하면 번거롭기 때문에 기존 값에서 필요한 값만 수정합니다.




수정된 값을 반영합니다.




미리보기를 할 수 있게 해줍니다.





설정

트랙백

댓글

20140930 (C++ 함수 오버로딩, 평활화 최종)

149일차












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

C++

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






------- 오버로딩

함수의 반환값, 이름은 같은데 인자만 다른 것



예)

함수                        타입

int test(int );             int (*)(int);

int test(int, int);         int (*)(int, int);


-> C에서는 불가능 하지만 C++에서는 가능하다

     이것이 함수 오버로딩



함수                        타입

int test(int );             int (*)(int);            -> O

int test(int, int);         int (*)(int, int);      -> O

char test(int );          char (*)(int);         -> X

int test(char);           int (*)(char);         -> O


-> 3번째 같은 경우 반환값이 다르기 때문에 오버로딩이 불가능하다.

    함수 타입, 이름이 같으면 오버로딩이 된다.












------- 이전에 C와 asm을 함께 섞어 사용하였는데,

C++도 섞어 사용할 수 있다. 먼저 .asm 파일을 확인해야한다.



소스)

#include <iostream>


void swap(int *, int *);

void swap(float *, float *);

void test();


int main()

{

int iA = 100;

int iB = 200;

float fA = 100.1;

float fB = 200.2;


std::cout << "iA : " << iA << std::endl;

std::cout << "iB : " << iB << std::endl;


swap(&iA, &iB);


std::cout << "iA : " << iA << std::endl;

std::cout << "iB : " << iB << std::endl << std::endl;


std::cout << "fA : " << fA << std::endl;

std::cout << "fB : " << fB << std::endl;


swap(&fA, &fB);


std::cout << "fA : " << fA << std::endl;

std::cout << "fB : " << fB << std::endl;


test();


return 0;

}


void swap(int * a, int * b)

{

int temp;


temp = *a;

*a = *b;

*b = temp;

}


void swap(float * a, float * b)

{

float temp;


temp = *a;

*a = *b;

*b = temp;

}







위와 같이 컴파일 하고, asm 파일을 확인하면


- main.cpp

...

17 swap(&iA, &iB);

...

25 swap(&fA, &fB);

...

30 test();

...


- main.asm

; Line 17

lea edx, DWORD PTR _iB$[ebp]

push edx

lea eax, DWORD PTR _iA$[ebp]

push eax

call ?swap@@YAXPAH0@Z ; swap

add esp, 8

...

; Line 25

...

call ?swap@@YAXPAM0@Z ; swap

...

; Line 30

call ?test@@YAXXZ ; test


swap 함수와 test 함수의 이름이 이상하게 선언되어 있다.

보안코드와 디버깅 코드가 더 추가되어서 그렇다고 한다.


17 line의 swap과 25 line의 swap의 이름이 서로 다르다.

C++에서는 함수 오버로딩으로 같은 이름을 사용하지만,

결국 asm 에서 다른 이름을 사용한다.





------- C로 마지막에 호출한 test() 함수를 구현하는데,

main.cpp에서 구현한 swap() 함수를 사용하여 구현한다.


소스)

#include <stdio.h>


void test()

{

int iA = 50;

int iB = 25;


swap(&iA, &iB);


printf("iA = %d, iB = %d\n", iA, iB);

}




편의를 위해 ms cl을 사용한다.

cl /Fa test.c 이렇게 컴파일 후 asm파일을 확인




- main.cpp

...

PUBLIC _test

...

8 swap(&iA, &iB);

...


- main.asm

; Line 8

lea eax, DWORD PTR _iB$[ebp]

push eax

lea ecx, DWORD PTR _iA$[ebp]

push ecx

call _swap

add esp, 8



여기 test.c에서 test 함수 이름과 사용할 swap 함수의 이름이 main.cpp에서 함수의 이름이 다르다.

    C                    C++

_test        !=     ?test@@YAXXZ

_swap     !=     ?swap@@YAXPAH0@Z


이것을 통일 시켜줘야 서로 통용이 가능하다.

그렇게 하기 위해서 main.cpp 소스를 다음과 같이 수정한다.


소스)

- main.cpp

....

extern "C" void swap(int *, int *);

void swap(float *, float *);

extern "C" void test();

....



함수 선언부에서 외부 함수를 사용한다는 기호?를 선언해 주는데,

"C"를 붙였다. "C"는 C와 통용 가능한 함수 이름으로 선언해 준다는 뜻인 것 같다.


그리고 컴파일 하고 (cl /Fa main.cpp), .asm 파일을 확인해 본 결과...


- main.cpp

...

17 swap(&iA, &iB);

...

30 test();

...


- main.asm

...

; Line 17

lea edx, DWORD PTR _iB$[ebp]

push edx

lea eax, DWORD PTR _iA$[ebp]

push eax

call _swap

add esp, 8

...

; Line 30

call _test



이렇게 C와 통용이 가능한 이름으로 바뀌었다.



둘이 함께 .obj 파일을 합쳐 컴파일(cl main.obj test.obj) 후, 실행 결과.




이렇게 함께 사용하여 컴파일이 가능하다.












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

평활화

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


소스)

aaa.txt


관련 자료)

히스토그램을 이용한 화소 점 처리.pptx



- 다음과 같이 3단계를 통해 평활화가 이루어진다.




단계별 소스)


- 1단계

명암 값의 빈도 수를 계산해 입력 영상의 히스토그램 생성


ucpPixel = BMbuf + stpBFH->bfOffBits;

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

{

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

{

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

}



- 2단계

각 명암 값 x에서 0 ~ x까지의 누적 빈도 수(누적합)를 계산


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]);

}



- 3단계

2단계에서 구한 누적 빈도 수를 정규화(정규화 누적합, 공식 = 누적값 * 최대밝기 / 총픽셀수)


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

}





결과)












설정

트랙백

댓글

20140929 (C++ cout, cin, winapi로 영상 평활화 처리)

148일차














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

C++

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



우선 .cpp 소스 파일을 생성합니다.


1.



2.



3.



4.











화면에 글자를 출력해 보는 기본 소스부터 시작합니다.


소스)


#include <iostream>  // stdio.h -> iostream으로 바뀜


int main()

{

    std::cout << "Hello\n";  // printf -> std::cout 으로 바뀜, std::cout 은 객체입니다.


    return 0;

}








--- C++.....


- C++은 C를 포함하기 때문에 C 문법, 함수를 다 사용할 수 있습니다.

- 소스 중간에 변수를 선언하여 사용할 수 있다. (단, 중간에 선언한 변수는 그 위에서 사용 불가)

- std::cout은 객체입니다. (console out)



소스)


#include <iostream>


int main()

{

    std::cout << "hello\n";


    printf("C 문법\n");  // C 함수 사용 가능


    int iA = 100;  // 소스 중간에 변수 선언 가능


    std::cout << iA;  // %d등 서식 문자를 사용하지 않고 숫자를 간단히 출력

    std::cout << "\n";


    std::cout << iA << "\n";  // 뒤에 엔터 서식 문자를 넣을 수도 있다.

    std::cout << iA << std::endl;  // "\n" 대신 std::endl 이라는 것도 있다. 개인의 취향


    return 0;

}







linux에서도 실습해 보았습니다.






(g++이 설치되어 있지 않을 시 "sudo apt-get install g++" 치면 자동으로 설치, 설정이 된다.)






- MS Visual Studio는 확장자로 .c는 C,  .cpp는 C++로 사용하는데,

Linux, Unix에서는 .cpp, .c++, .cc등 으로 사용한다고 합니다.


- MS Visual Studio는 확장자로( .c,  .cpp ) 소스 파일을 구분하여 컴파일 하는 반면,

Linux, Unix 에서는 확장자로 소스 파일을 구분하지 않고, C는 gcc로,  C++은 g++로 컴파일 합니다.









--- C++...


- "std::cin >> 변수"   입력을 받아 변수에 넣습니다. std::cout << 이랑 삿갓이 반대 모양입니다.



소스)

#include <iostream>


int main()

{

    int dan;

    int su;


    std::cout << "단을 입력하세요 : ";

    std::cin >> dan;


    for(; 10 > dan; ++dan)

    {

        for(su = 1; 10 > su; ++su)

        {

            std::cout << dan << " * " << su << " = " << dan * su << std::endl;  // 입력 받은 단부터 구구단 출력

        }

        std::cout << std::endl;

    }


    char buf[128];

    int number;


    std::cout << "문자열, 숫자 입력 : ";

    std::cin >> buf >> number;  // 입력을 연속해서 받을 수 있다.


    std::cout << "문자열 : " << buf << std::endl;

    std::cout << "숫자 : " << number << std::endl;

    std::cout << "문자열 + 1: " << buf + 1 << std::endl;  // 문자열 변수에 +1을 하면 주소가 +1 되어 출력된다.


    return 0;

}















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

평활화

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



- 어둡게 촬영된 영상의 히스토그램을 조절하여 명암 분포가 빈약한 영상을 균일하게 만드는 기법


- 히스토그램 평활화 3단계

1. 명암값의 빈도수 수치 계산

(uiRcnt[], uiGcnt[], uiBcnt[] 이 배열들이 명암값 빈수도 계산된 값이다.)


2. 각 명암값 누적수 계산



3. 총 화소와 최대 명도값으로 계산

n[i] = sum[i] * ( 1 / (총화소) ) * (최대 밝기)





추가된 소스)


...

//전역 변수 선언

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

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

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

...




...

//히스토그램 세로축 수치 값을 조정하는 소스 밑에 추가


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

{

if(uiXcount != 0)

{

uiRhisto[uiXcount] = ((uiRhisto[uiXcount-1] + uiRcnt[uiXcount]) * 255) / (uiX*uiY);

}

else

{

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

}

}









설정

트랙백

댓글

20140925

146일차



#include <windows.h>


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

#define XOFFSET 280

#define X_WIDTH_SIZE 150


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,

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;

}


unsigned char * BMbuf;

HBITMAP Screen;


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;

RECT rt;

switch (iMessage)

{

case WM_CREATE:

hFile = CreateFile(TEXT("image.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,

20, 20, 90, 20, hWnd, (HMENU)-1, g_hInst, NULL);

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

110, 20, 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,

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

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

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


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

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

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

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

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

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

uiPad = uiX%4;


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

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

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

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

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

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


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

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

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

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

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

hdc = GetDC(hWnd);

MemDC = CreateCompatibleDC(hdc);

GetClientRect(hWnd, &rt);

Screen = CreateCompatibleBitmap(hdc, rt.right, rt.bottom);

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

ucpPixel = BMbuf + stpBFH->bfOffBits;

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

{

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

{

SetPixel(MemDC, uiXcount + XOFFSET, uiYcount-1, RGB(*(ucpPixel+2), *(ucpPixel+1), *ucpPixel));

ucpPixel = ucpPixel + 3;

}

ucpPixel = ucpPixel + uiPad;

}

SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

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


GetClientRect(hWnd, &rt);

BitBlt(hdc, 0, 0, rt.right, rt.bottom, MemDC, 0, 0, SRCCOPY);


SelectObject(MemDC, OldBitmap);

DeleteDC(MemDC);

EndPaint(hWnd, &ps);

return 0;

case WM_DESTROY:

DeleteObject(Screen);

PostQuitMessage(0);

return 0;

}

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

}



설정

트랙백

댓글

20140924 (비트맵 파일 구조)

145일차





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

비트맵 파일 구조

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











1. 파일 헤더

typedef struct tagBITMAPFILEHEADER

{

    WORD    bfType;    // "BM"이라고  bitmap을 나타내는 값 저장됨

    DWORD    bfSize;    // 바이트 단위로 전체 파일 크기

    WORD    bfReserved1;    // 예약된 변수

    WORD    bfReserved2;    // 예약된 변수

    DWORD    bfOffBits;    // 실제 데이터 위치까지의 거리

}BITMAPFILEHEADER;



WORD (unsigned short) 2byte, DWORD (unsigned long) 4byte.




2. 이미지 헤더

typedef struct tagBITMAPINFOHEADER

{

    DWORD    biSize;    // 이 구조체의 크기

    LONG    biWidth;    // 픽셀 단위 이미지 폭

    LONG    biHeight;    // 이미지 높이

    WORD    biPlanes;    // 비트 플레인 수 (항상 1, 움직이는 그림은 다른수라 하던데..?)

    WORD    biBitCount;    // 픽셀당 비트 수 (컬러, 흑백 구별)

    DWORD    biCompression;    // 압축유무

    DWORD    biSizeImage;    // 이미지 크기 (바이트 단위)

    LONG    biXPelsPermeter;    // 가로 해상도

    LONG    biYPelsPermeter;    // 세로 해상도

    DWORD    biClrUsed;    // 실제 사용 색상 수

    DWORD    biClrImportant;    // 중요한 색상 인덱스

}BITMAPINFOHEADER;



설정

트랙백

댓글

20140827 (메시지 맵, strrev, strupr, toupper, strlwr, tolower, strchr, strstr, strtol, strtoul, strod)

128일차








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

작성 중인 프로그램 작성 완료

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



--- 메세지 맵


메시지 맵 매크로, 메시지 맵 알고르즘이라고 불리는데,

ms사에 windows의 메시지를 받고 처리하는 방식을

이 방식으로 하였다.


간략하게 설명하자면 새로운 함수를 추가할 때마다

main함수의 소스를 수정해야 하는데,

메시지 맵. 이 방식을 사용하면 추가 함수와 배열만 건드리면 된다.


ex)


#include <stdio.h>

void Func1();
void Func2();
void Func3();
void Func4();
void Func5();

int main()
{
    int a;

    printf("1 ~ 5 중 입력 : ");
    scanf("%d"&a);

    if(a == 1)
    {
        Func1();
    }
    else if(a == 2)
    {
        Func2();
    }
    else if(a == 3)
    {
        Func3();
    }
    else if(a == 4)
    {
        Func4();
    }
    else if(a == 5)
    {
        Func5();
    }

    return 0;
}

void Func1()
{
    printf("Number 1.\n");
}

void Func2()
{
    printf("Number 2.\n");
}

void Func3()
{
    printf("Number 3.\n");
}

void Func4()
{
    printf("Number 4.\n");
}

void Func5()
{
    printf("Number 5.\n");
}



이런 소스가 있는데

만약 10까지 더 추가하게 되면

새로운 함수도 추가하고 main도 손봐야 한다.


메시지 맵 알고리즘을 사용하면


#include <stdio.h>

void Func1();
void Func2();
void Func3();
void Func4();
void Func5();

typedef struct _MSG_FUNC
{
    int FuncNum;
    void (*Func)();
}MSG_FUNC;

int main()
{
    int a;
    MSG_FUNC * FuncPoint;
    MSG_FUNC FuncArray[] = {
        {1, Func1},
        {2, Func2},
        {3, Func3},
        {4, Func4},
        {5, Func5},
        {00}
      };

    printf("1 ~ 5 중 입력 : ");
    scanf("%d"&a);

    for(FuncPoint = FuncArray; FuncPoint->FuncNum != 0; ++FuncPoint)
    {
        if(a == FuncPoint->FuncNum)
        {
            (FuncPoint->Func)();
            break;
        }
    }

    return 0;
}

void Func1()
{
    printf("Number 1.\n");
}

void Func2()
{
    printf("Number 2.\n");
}

void Func3()
{
    printf("Number 3.\n");
}

void Func4()
{
    printf("Number 4.\n");
}

void Func5()
{
    printf("Number 5.\n");
}




코드량도 줄고

배열에 멤버만 추가하면 같은 형태의 함수를

훨씬 쉽게 관리할 수 있다.







------- 문자, 문자열 함수


--- strrev

문자열 역순으로 변환


#include <string.h>


char * strrev(char *str);


str에 문자열을 역순으로 바꾸고 str에 다시 저장.


리턴값

역순으로 바뀐 문자열의 번지를 리턴




--- strupr

대문자로 변환


#include <string.h>


char * strupr(char * str);

int toupper(int ch);


strupr : str에 문자열을 변환하고 str에 다시 저장.


리턴값

strupr : 바뀐 문자열 번지 리턴

toupper : 대문자




--- strlwr

소문자로 변환


#include <string.h>


char * strlwr(char * str);

int tolower(int ch);


strlwr : str에 문자열을 변환하고 str에 다시 저장.


리턴값

strlwr : 바뀐 문자열 번지 리턴

tolower : 소문자





--- strchr

문자열에서 임의이 문자 시작하는 위치 찾기


#include <string.h>


char * strchr(const char * str, int chr);


str : 검색 대상 문자열

chr : 찾는 문자


리턴값

성공 : 찾고자 하는 문자가 발견된 위치 포인터를 반환

실패 : NULL



--- strstr

문자열에서 임의의 문자열이 시작하는 위치 찾기


#include <string.h>


char * strstr(const char * str1 , const char * str2);


str1 : 검색 대상 문자열

str2 : 찾고자 하는 문자열


리턴값

성공 : 찾고자 하는 문자열이 발견된 위치 포인터 반환

실패 : NULL




--- strtol, strtoul

문자열을 변환할 진법의 수로 변환


#include <stdlib.h>


long int strtol (const char* str, char** endptr, int base);

unsigned long int strtoul (const char* str, char** endptr, int base);


str : 변환시킬 문자열 주소

endptr : 변환된 숫자 다음 위치를 저장할 포인터. 사용하지 않을 시 NULL.

base : 변환할 진법


리턴값

성공 : 변환된 수

실패 : 0





--- strtod

문자열을 double형 수로 변환


double strtod (const char* str, char** endptr);


str : 변환시킬 문자열 주소

endptr : 변환된 숫자 다음 위치를 저장할 포인터. 사용하지 않을 시 NULL.


리턴값

성공 : 변환된 수

실패 : 0.0 반환

설정

트랙백

댓글