WindowPrograms/MFC
8. 비트맵과 이미지처리
레이드리안
2011. 10. 24. 14:38
■전형적인 이미지 출력
- 윈도우 프로그래밍에서 비트맵 이미지를 출력하는 전형적인 방법은 리소스로 등록된 비트맵 이미지를 메모리 DC에 로드 하여
화면 DC로 출력(BitBlt())하는것입니다. 이과정을 요약하면, 이미지의 크기를 변경(StretchBlt())하거나 일부영역을 투명하게
처리(TransparentBlt())하거나 반투명하게 처리(AlphaBlend())하게 됩니다.
비트맵은 장치의존적인 비트맵(DDB, Device Dependent Bitmap)과 장치 독립적인 비트맵 (DIB, Device Indepent Bitmap)으로
나누어집니다. 장치 의존적이냐 장치 독립적이냐는 말은 장치의 영향을 받느냐 그렇지 않느냐의 의미로 해석 됩니다.
우리가 아는 비트맵파일은 모두 DIB라고 봐도 무방합니다. 비트맵을 우리눈으로 보려면 DDB로 변환해야합니다.
비트맵을 저장할 메모리 DC를 생성하되 출력할 화면 DC와 호환이 되도록합니다. 그리고 비트맵을 로드하고 메모리 DC의
비트맵으로 선택합니다. 최종적으로 BitBlt()함수를 호출하여 메모리 DC에 로드된 비트맵 이미지를 화면 DC로 전송합니다.
화면 DC로 비트맵을 전송하면 내부적으로 DIB가 DDB로 변환되어 모니터 화면에 출력하게됩니다.
CDC클래스의 CreateCompatibleDC() 메서드는 CDC클래스 객체의 주소를 인자로 받으며 전달받은 CDC클래스 객체와 호환되는
메모리 DC를 생성합니다. 메모리 DC는 출력할 비트맵 이미지를 저장하는 메모리 공간이라 할수있습니다.
CDC클래스의 BitBlt() 함수는 메모리 DC에서 화면 DC로 비트맵을 전송해 줍니다.
BitBlt()원형
BitBlt()함수는 메모리 DC에서 이미지의 일부 혹은 전체를 뗴어서 화면 DC로 전송합니다.
함수의 x,y인자는 화면 DC에서 출력을 시작하는 좌표.
nWidth,nHeight 인자가 각각 250,300 이되었는데, 화면DC에서 출력할 이미지의 크기를 말합니다.
xSrc,ySrc 인자는 출력할 원본이미지를 시작하는 좌표입니다.
원본이미지의 폭과 높이는 명시하지않았지만, 출력할 이미지와 같은 크기로 잘라냅니다.
BitBlt()함수의 마지막 인자에는 래스터 연산을 어떻게 할지 명시하는데,SRCCOPY는 메모리 DC의 내용에 변화를 주지 말고 그대로
화면DC에 복사 하라는 의미.
dwRop연산
StrechBlt()함수는 BitBlt()함수처럼 메모리 DC에 로드된 비트맵 이미지를 화면 DC에 출력하는 기능을 한다는 점에서는 같지만
원본 크기와 대상 크기를 달리하여 이미지를 확대 축소 출력한다는 점이 다름.
■고급 이미지 출력 함수
TransparentBlt()와 AlphaBlend() 두함수는 모두 예전에는 CDC클래스의 맴버가 아니였으나, MFC를 업그레이드 하면서 맴버로
추가되었습니다.
TransparentBlt()함수와 StretchBlt()함수 인자가 거의 비슷합니다.
StretchBlt()함수의 마지막 인자는 래스터 연산값이지만, TransparentBlt() 함수의 마지막 인자는 투명하게 출력할 RGB값입니다.
위의 소스에서 RGB값이(0,0,0)이므로 검정색이 됩니다. 따라서 메모리 DC에 로드된 비트맵의 색상중에 검정색은 투명하게 출력
될것입니다.
AlphaBelnd()함수는 전체이미지를 반투명하게 만듭니다.
AlphaBlend()함수의 마지막 인자 BLENDFUNCTION구조체는
BlendOp 맴버에는 원본이미지와 대상이미지를 섞는 연산을 명시합니다.
AC_SRC_OVER은 원본/대상 이미지를 서로 섞는다는 의미.
BlendFlags 맴버는 사용하지않으면 반드시 0이어야함.
SourceConstantAlpha 맴버는 원본이미지의 투명도를 결정하며 0~255범위값을 같습니다.
0이면 완전 투명(아무출력하지않음.) 255면 완전히 불투명해집니다.
BLENDFUNCTION 구조체의 마지막 맴버인 AlphaFormat에는 원본과 대상 비트맵 이미지를 해석하는 방법을 명시합니다.
이값은 0이나 AC_SRC_ALPHA가 되어야합니다.
AC_SRC_ALPHA가 되는 경우 원본 비트맵이 24비트 이하의 비트맵이 아니라 각 픽셀에 대한 알파 채널을 갖는 진정한 32비트
비트맵인경우에만 해당합니다.
■CImage 클래스의 활용
CImage 클래스는 MFC가 제공하는 ATL 클래중하나입니다. 그러므로 내부적으로는 COM객체로 구현되어 있습니다.
C++의 클래스가 논리적인 코드를 객체화한 개념이라면 COM은 실행 바이너리 파일 단위로 객체화한 것이라고 할수있다.
그러므로 메서드가 반환하는 값은HRESULT형이며, FAILED()매크로나 SUCCEEDED()매크로를 이용해 오류를 확인합니다.
CImage클래스의 Load() 메서드는 인자로 전달받은 경로의 이미지 파일을 로드하여 DIB이미지를 생성합니다.
유사 함수로 LoadFromResource()메서드가 있습니다. 이 함수는 CBitmap 클래스의 LoadBitmap() 메서드처럼 비트맵 리소스를
로드하여 비트맵 이미지를 만듭니다.사용하는 인자도 리소스 ID를 주어야한다는 점에서 같지만 첫번째 인자로 ::LoadImage() API
함수처럼 응용프로그램의 인스턴스 핸들을 주어야합니다.
메모리DC를 이용한 전형적인 이미지 출력보다 훨씬 코드가 간단해집니다.
CImage 클래스에는 GetDC()와 ReleaseDC()메서드가 있습니다.이들메서드는 CDC클래스의 GetDC()와 ReleaseDC()함수와 유사
합니다.다만, 생성한 비트맵 객체가 이미 있다는점에서 차이가 납니다.
구현방법은 화면 DC에 이미지를 출력한 다음에 추가로 문자열을 화면 DC에 출력하는 방법과 이미지DC에 문자열을 출력하고
변경한 이미지를 화면 DC에 출력하는 방법이있습니다. 별다를것없이 보이지만 화면의 깜빡임을 제거하는 코드를 만들려면
두방법은 극단적인 차이를 보입니다.
GetDC()메서드를 이용하면 DC의 핸들인 HDC데이터를 반환합니다. MFC의 CDC클래스는 내부적으로 m_hDC라는 핸들 맴버를
갖고있습니다. 이것은 CWnd클래스가 윈도우 핸들맴버로 갖는것과 비슷합니다. 그리고 CDC 클래스의 정적 맴버인 FromHandle()
함수를 명시적으로 호출하여 HDC에 대한 CDC클래스 객체의 포인터를 반환받습니다.
CDC클래스 객체는 CImage클래스 객체와 연결된 메모리DC가 되는데, 이것을 앞서배운 메모리DC와 구별하기위해 이미지DC라고
부릅니다. 이미지DC는 CImage 클래스 객체와 연결되어있으므로 나중에 CImage::ReleaseDC()메서드를 호출하여 리소스반환.
문자열의 배경을 투명하게 하고 TextOut() 함수를 이용하여 이미지 DC에 문자열을 출력하는 코드입니다.
함수의 원형| Bitblt()
■색상의 변환
윈도우 프로그래밍에서는 이미지를 처리할때 RGB방식을 사용합니다. 하지만, HSB/HSV색상, Saturation 명도, Brightness 밝기,
Value깊이 방식을 사용하여 색상을 표현하기도 합니다.
RGB컬러를 흑백으로 변환하는 방법은 매우간단하며 공식처럼 활용됩니다.
GetRValue(), GetGValue(), GetBValue() 함수는 COLORREF값에서 RGB값을 각각 추출하는 매크로입니다.
24비트 컬러에서 각각은 8비트이며, RGB각각에 대해 30,59,11을 곱한 값을 모두더해 다시 100으로 나누면 흑백에 해당하는
값을 구할수 있습니다.
CWnd 클래스의 GetDesktopWindow() 메서드는 바탕화면 윈도우 객체의 포인터를 반환합니다.
이렇게 해서 알아낸 바탕화면에 대한 DC를
로 생성합니다. 이때 CPaintDC클래스나 CClientDC클래스를 사용하지않고 CWindowDC클래스를 사용한것은.
CWindowDC클래스는 다른 형제 DC들과 달리 비클라이언트 영역을 포함한 윈도우 전체에 대한 DC입니다.
비트맵 파일이나 리소스를 로드하는것이 아니라 폭과 높이가 각각 300픽셀이고 바탕 화면 윈도우 DC의 픽셀당 비트수가 같은 비트맵
이미지를 생성합니다. CDC클래스의 GetDeviceCaps()메서드는 DC의 각종 정보를 추출합니다.인자로 전달받은 인덱스에따라
각각 다른 값을 int형 값으로 반환합니다.
일부이미지(200*200)을 흑백으로 변환(RGBtoGray)합니다. 이과정에서 CImage클래스의 GetPixel()과 SetPixel() 함수를
사용하였는데, 비트맵 이미지를 2차원 배열이라고 가정하고 원하는 특정 지점의 좌표를 이용하여 RGB값을 가져오거나 실행합니다.
같은 이름의 함수가 CDC클래스에도 있으며 기능도 같습니다. 이렇게 일부 영역의 이미지를 흑백이미지로 변환하여
화면에 출력하고 모든 처리를 종료합니다.
CImage클래스의 Create()메서드의 원형
마지막 인바의 기본값은 0입니다. 이인자에는 32비트 비트맵일경우 알파 채널을 명시합니다. 세번째인자(nBPP)가 반드시 32가 되어야 알파 채널을 명시할수 있습니다.
CDC클래스의 GetDeviceCaps()메서드는 인자로 전달받은 인덱스에 해당하는 DC정보를 반환해줍니다.
윈도우 탐색기는 윈도우 운영체제의 셀입니다. ::ShellExecute() API함수의 원형은 다음과 같습니다.
함수의원형 | ShellExecute()
hwnd 인자는 부모 윈도우의 핸들이며, 이값이 NULL이면 부모윈도우는 바탕화면이 됩니다.
lpOperation 인자에는 함수가 어떤 동작을 할것인지 명시합니다.
lpFile인자와 연결된 프로세스를 실행하라는 의미.
lpFarameters 인자에는 lpFile인자가 싱행 파일인 경우 실행할 파일의 실행인자를 명시합니다.
lpDirectory 인자에는 실행할 프로그램의 현재 폴더 경로를 명시합니다. 이값이 NULL이면 윈도우 기본 설정을 적용 합니다.
- 윈도우 프로그래밍에서 비트맵 이미지를 출력하는 전형적인 방법은 리소스로 등록된 비트맵 이미지를 메모리 DC에 로드 하여
화면 DC로 출력(BitBlt())하는것입니다. 이과정을 요약하면, 이미지의 크기를 변경(StretchBlt())하거나 일부영역을 투명하게
처리(TransparentBlt())하거나 반투명하게 처리(AlphaBlend())하게 됩니다.
비트맵은 장치의존적인 비트맵(DDB, Device Dependent Bitmap)과 장치 독립적인 비트맵 (DIB, Device Indepent Bitmap)으로
나누어집니다. 장치 의존적이냐 장치 독립적이냐는 말은 장치의 영향을 받느냐 그렇지 않느냐의 의미로 해석 됩니다.
우리가 아는 비트맵파일은 모두 DIB라고 봐도 무방합니다. 비트맵을 우리눈으로 보려면 DDB로 변환해야합니다.
비트맵을 저장할 메모리 DC를 생성하되 출력할 화면 DC와 호환이 되도록합니다. 그리고 비트맵을 로드하고 메모리 DC의
비트맵으로 선택합니다. 최종적으로 BitBlt()함수를 호출하여 메모리 DC에 로드된 비트맵 이미지를 화면 DC로 전송합니다.
화면 DC로 비트맵을 전송하면 내부적으로 DIB가 DDB로 변환되어 모니터 화면에 출력하게됩니다.
CDC클래스의 CreateCompatibleDC() 메서드는 CDC클래스 객체의 주소를 인자로 받으며 전달받은 CDC클래스 객체와 호환되는
메모리 DC를 생성합니다. 메모리 DC는 출력할 비트맵 이미지를 저장하는 메모리 공간이라 할수있습니다.
CDC클래스의 BitBlt() 함수는 메모리 DC에서 화면 DC로 비트맵을 전송해 줍니다.
BitBlt()원형
BitBlt()함수는 메모리 DC에서 이미지의 일부 혹은 전체를 뗴어서 화면 DC로 전송합니다.
함수의 x,y인자는 화면 DC에서 출력을 시작하는 좌표.
nWidth,nHeight 인자가 각각 250,300 이되었는데, 화면DC에서 출력할 이미지의 크기를 말합니다.
xSrc,ySrc 인자는 출력할 원본이미지를 시작하는 좌표입니다.
원본이미지의 폭과 높이는 명시하지않았지만, 출력할 이미지와 같은 크기로 잘라냅니다.
BitBlt()함수의 마지막 인자에는 래스터 연산을 어떻게 할지 명시하는데,SRCCOPY는 메모리 DC의 내용에 변화를 주지 말고 그대로
화면DC에 복사 하라는 의미.
dwRop연산
BLACKNESS | 검정색으로 채운다 |
WHITENESS | 흰색으로 채운다 |
DSTINVERT | 화면을 반전 |
MERGECOPY | 소스 비트맵과 바탕화면을 AND연산한다. |
MERGEPAINT | 소스 비트맵과 바탕화면을 OR연산한다. |
SRCCOPY | 소스영역을 대상 영역에 복사한다. |
SRCAND | 타겟과 AND연산. |
SRCINVERT | 타겟과 XOR연산 |
SRCPAINT | 타겟과 OR연산 |
SRCERASE | 타겟과 NOT소스를 AND |
※레스터 연산에서 래스터란 화면을 이루는 수평선을 의미.
가령 폭과 높이가 300*200인 비트맵 이미지가 있다면 200개의 수평선이 있는 이미지를 의미. 래스터 연산을 한다는것은
이미 화면에 출력된 래스터와 출력할 래스터를 어떻게 조합할것인지를 연산하는것입니다. 즉, 각각의 픽셀 하나하나에
대해 AND,OR,XOR과 같은 비트 연산을 하는 것입니다. 따라서 이값을 어떻게 조합하느냐에 따라 화면 이미지를 덮어쓰게
되기도 하고 일정 부분 섞여서 출력하기도 합니다.
가령 폭과 높이가 300*200인 비트맵 이미지가 있다면 200개의 수평선이 있는 이미지를 의미. 래스터 연산을 한다는것은
이미 화면에 출력된 래스터와 출력할 래스터를 어떻게 조합할것인지를 연산하는것입니다. 즉, 각각의 픽셀 하나하나에
대해 AND,OR,XOR과 같은 비트 연산을 하는 것입니다. 따라서 이값을 어떻게 조합하느냐에 따라 화면 이미지를 덮어쓰게
되기도 하고 일정 부분 섞여서 출력하기도 합니다.
StrechBlt()함수는 BitBlt()함수처럼 메모리 DC에 로드된 비트맵 이미지를 화면 DC에 출력하는 기능을 한다는 점에서는 같지만
원본 크기와 대상 크기를 달리하여 이미지를 확대 축소 출력한다는 점이 다름.
■고급 이미지 출력 함수
TransparentBlt()와 AlphaBlend() 두함수는 모두 예전에는 CDC클래스의 맴버가 아니였으나, MFC를 업그레이드 하면서 맴버로
추가되었습니다.
TransparentBlt()함수와 StretchBlt()함수 인자가 거의 비슷합니다.
StretchBlt()함수의 마지막 인자는 래스터 연산값이지만, TransparentBlt() 함수의 마지막 인자는 투명하게 출력할 RGB값입니다.
위의 소스에서 RGB값이(0,0,0)이므로 검정색이 됩니다. 따라서 메모리 DC에 로드된 비트맵의 색상중에 검정색은 투명하게 출력
될것입니다.
AlphaBelnd()함수는 전체이미지를 반투명하게 만듭니다.
AlphaBlend()함수의 마지막 인자 BLENDFUNCTION구조체는
BlendOp 맴버에는 원본이미지와 대상이미지를 섞는 연산을 명시합니다.
AC_SRC_OVER은 원본/대상 이미지를 서로 섞는다는 의미.
BlendFlags 맴버는 사용하지않으면 반드시 0이어야함.
SourceConstantAlpha 맴버는 원본이미지의 투명도를 결정하며 0~255범위값을 같습니다.
0이면 완전 투명(아무출력하지않음.) 255면 완전히 불투명해집니다.
BLENDFUNCTION 구조체의 마지막 맴버인 AlphaFormat에는 원본과 대상 비트맵 이미지를 해석하는 방법을 명시합니다.
이값은 0이나 AC_SRC_ALPHA가 되어야합니다.
AC_SRC_ALPHA가 되는 경우 원본 비트맵이 24비트 이하의 비트맵이 아니라 각 픽셀에 대한 알파 채널을 갖는 진정한 32비트
비트맵인경우에만 해당합니다.
■CImage 클래스의 활용
CImage 클래스는 MFC가 제공하는 ATL 클래중하나입니다. 그러므로 내부적으로는 COM객체로 구현되어 있습니다.
C++의 클래스가 논리적인 코드를 객체화한 개념이라면 COM은 실행 바이너리 파일 단위로 객체화한 것이라고 할수있다.
그러므로 메서드가 반환하는 값은HRESULT형이며, FAILED()매크로나 SUCCEEDED()매크로를 이용해 오류를 확인합니다.
CImage클래스의 Load() 메서드는 인자로 전달받은 경로의 이미지 파일을 로드하여 DIB이미지를 생성합니다.
유사 함수로 LoadFromResource()메서드가 있습니다. 이 함수는 CBitmap 클래스의 LoadBitmap() 메서드처럼 비트맵 리소스를
로드하여 비트맵 이미지를 만듭니다.사용하는 인자도 리소스 ID를 주어야한다는 점에서 같지만 첫번째 인자로 ::LoadImage() API
함수처럼 응용프로그램의 인스턴스 핸들을 주어야합니다.
메모리DC를 이용한 전형적인 이미지 출력보다 훨씬 코드가 간단해집니다.
CImage 클래스에는 GetDC()와 ReleaseDC()메서드가 있습니다.이들메서드는 CDC클래스의 GetDC()와 ReleaseDC()함수와 유사
합니다.다만, 생성한 비트맵 객체가 이미 있다는점에서 차이가 납니다.
구현방법은 화면 DC에 이미지를 출력한 다음에 추가로 문자열을 화면 DC에 출력하는 방법과 이미지DC에 문자열을 출력하고
변경한 이미지를 화면 DC에 출력하는 방법이있습니다. 별다를것없이 보이지만 화면의 깜빡임을 제거하는 코드를 만들려면
두방법은 극단적인 차이를 보입니다.
GetDC()메서드를 이용하면 DC의 핸들인 HDC데이터를 반환합니다. MFC의 CDC클래스는 내부적으로 m_hDC라는 핸들 맴버를
갖고있습니다. 이것은 CWnd클래스가 윈도우 핸들맴버로 갖는것과 비슷합니다. 그리고 CDC 클래스의 정적 맴버인 FromHandle()
함수를 명시적으로 호출하여 HDC에 대한 CDC클래스 객체의 포인터를 반환받습니다.
CDC클래스 객체는 CImage클래스 객체와 연결된 메모리DC가 되는데, 이것을 앞서배운 메모리DC와 구별하기위해 이미지DC라고
부릅니다. 이미지DC는 CImage 클래스 객체와 연결되어있으므로 나중에 CImage::ReleaseDC()메서드를 호출하여 리소스반환.
문자열의 배경을 투명하게 하고 TextOut() 함수를 이용하여 이미지 DC에 문자열을 출력하는 코드입니다.
함수의 원형| Bitblt()
■색상의 변환
윈도우 프로그래밍에서는 이미지를 처리할때 RGB방식을 사용합니다. 하지만, HSB/HSV색상, Saturation 명도, Brightness 밝기,
Value깊이 방식을 사용하여 색상을 표현하기도 합니다.
RGB컬러를 흑백으로 변환하는 방법은 매우간단하며 공식처럼 활용됩니다.
GetRValue(), GetGValue(), GetBValue() 함수는 COLORREF값에서 RGB값을 각각 추출하는 매크로입니다.
24비트 컬러에서 각각은 8비트이며, RGB각각에 대해 30,59,11을 곱한 값을 모두더해 다시 100으로 나누면 흑백에 해당하는
값을 구할수 있습니다.
CWnd 클래스의 GetDesktopWindow() 메서드는 바탕화면 윈도우 객체의 포인터를 반환합니다.
이렇게 해서 알아낸 바탕화면에 대한 DC를
로 생성합니다. 이때 CPaintDC클래스나 CClientDC클래스를 사용하지않고 CWindowDC클래스를 사용한것은.
CWindowDC클래스는 다른 형제 DC들과 달리 비클라이언트 영역을 포함한 윈도우 전체에 대한 DC입니다.
비트맵 파일이나 리소스를 로드하는것이 아니라 폭과 높이가 각각 300픽셀이고 바탕 화면 윈도우 DC의 픽셀당 비트수가 같은 비트맵
이미지를 생성합니다. CDC클래스의 GetDeviceCaps()메서드는 DC의 각종 정보를 추출합니다.인자로 전달받은 인덱스에따라
각각 다른 값을 int형 값으로 반환합니다.
일부이미지(200*200)을 흑백으로 변환(RGBtoGray)합니다. 이과정에서 CImage클래스의 GetPixel()과 SetPixel() 함수를
사용하였는데, 비트맵 이미지를 2차원 배열이라고 가정하고 원하는 특정 지점의 좌표를 이용하여 RGB값을 가져오거나 실행합니다.
같은 이름의 함수가 CDC클래스에도 있으며 기능도 같습니다. 이렇게 일부 영역의 이미지를 흑백이미지로 변환하여
화면에 출력하고 모든 처리를 종료합니다.
CImage클래스의 Create()메서드의 원형
마지막 인바의 기본값은 0입니다. 이인자에는 32비트 비트맵일경우 알파 채널을 명시합니다. 세번째인자(nBPP)가 반드시 32가 되어야 알파 채널을 명시할수 있습니다.
CDC클래스의 GetDeviceCaps()메서드는 인자로 전달받은 인덱스에 해당하는 DC정보를 반환해줍니다.
윈도우 탐색기는 윈도우 운영체제의 셀입니다. ::ShellExecute() API함수의 원형은 다음과 같습니다.
함수의원형 | ShellExecute()
hwnd 인자는 부모 윈도우의 핸들이며, 이값이 NULL이면 부모윈도우는 바탕화면이 됩니다.
lpOperation 인자에는 함수가 어떤 동작을 할것인지 명시합니다.
lpFile인자와 연결된 프로세스를 실행하라는 의미.
lpFarameters 인자에는 lpFile인자가 싱행 파일인 경우 실행할 파일의 실행인자를 명시합니다.
lpDirectory 인자에는 실행할 프로그램의 현재 폴더 경로를 명시합니다. 이값이 NULL이면 윈도우 기본 설정을 적용 합니다.