해당 포스트는 "열혈강의 영상처리 프로그래밍" 책의 내용을 요약한 것이다.



※ 다중 문서 응용 프로그램(MDI)에서 화면 출력

(github => https://github.com/fbf7290/ImageProcessing/tree/MDIViewer)

 

 

//위 그림에서 보이는 화면 출력 메뉴에 대한 이벤트 처리기
void CMDIViewerDoc::OnMenuView()
{
	// TODO: 여기에 명령 처리기 코드를 추가합니다.
	m_image = LoadImageFromDialog(); //탐색기를 선택한 비트맵 파일 반환
	if (!m_image.IsEmpty())          //영상이 제대로 읽어졌는 지 판단
	{
       //View 클래스에 화면을 갱신하라고 메시지를 보냄 => OnDraw()함수가 호출됨
		UpdateAllViews(NULL);       
	}
}

- LoadImageFromDialog() 함수

: CFileDialog를 통해 탐색기 안에 있는 비트맵 파일을 불러오는 기능을 한다.

#include "../stdafx.h"
#include "LoadImageFileDialog.h"
CByteImage LoadImageFromDialog()
{
	CByteImage image;	// 반환할 영상
	// 파일 대화상자에서 BMP 형식의 파일만 보이도록 하는 필터의 정의
	TCHAR szFilter[] = _T("BMP File (*.BMP) | *.BMP; | All Files(*.*)|*.*||");

	// 입력 영상 읽기
	CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter);
	if (IDOK != dlg.DoModal()) // 대화 상자 열기
	{
		return image;
	}

	char * strPathName = _strdup(CT2A(dlg.GetPathName())); // 영상 파일 경로 획득
	image.LoadImage(strPathName); // 영상 읽기

	return image;
}

 

 

- onDraw()

: 첫 번째 코드에서 메뉴 클릭 이벤트 함수 내에 UpdateAllViews(NULL); 함수가 호출되면 위 함수가 호출된다. onDraw()함수는 View 클래스 화면을 갱신하는 역할을 한다.

void CMDIViewerView::OnDraw(CDC* pDC)
{
	CMDIViewerDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 여기에 원시 데이터에 대한 그리기 코드를 추가합니다.
	CByteImage& m_image = pDoc->m_image;
	if (m_image.IsEmpty()) return;

   //화면에 영상을 출력하기 위한 함수
	_DrawImage(pDC->m_hDC, m_image,
		0, 0, m_image.GetWidth(), m_image.GetHeight(),
		0, 0, m_image.GetWidth(), m_image.GetHeight());
}

-_DrawImage() 함수

: image 객체 비트밉의 (nSrcX, nSrcY)좌표를 시작으로 너비 nSrcW, 높이 nSrcH 만큼의 비트맵을 메인 프로그램의 (nDstX, nDstY) 좌표에 너비 nDstW, 높이 nDstH 크기로 출력하는 함수이다. 이 함수 안에는 StretchDIBits라는 MFC에서 제공하는 함수를 사용한다. 먼저 StretchDIBits 함수를 알아보자.

StretchDIBits() 함수는 비트맵 형식 영상 정보 헤더와 함게 전달된 영상을 디바이스 컨텍스트를 이용하여 화면에 출력하는 함수로 wingdi.h에 선언되어 있다. 입력 영상에서 출력을 원하는 영역을 설정할 수 있고, 이 영역이 화면에서 출력되는 영역도 설정할 수 있다. 화면이 성공적으로 출력되면 출력된 영상의 행 수를 반환하고 출력이 정상적으로 이루어 지지 않았다면 0을 반환한다. 이 함수가 실제로 수행하는 것은 매개변수로 받은 비트맵 형식의 입력 영상을 디바이스 컨텍스트의 메모리로 복사하는 작업이다.

 

- 위 함수 매개변수인 BITMAPINFO 구조체는 비트맵 파일의 영상 정보 헤더인 BITMAPINFOHEADER 구조체와 팔레트 정보를 담은 RGBQUAD 구조체의 포인터를 모아 놓은 것이다.

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO

- 매개변수 iUsage : BITMAPINFO 구조체를 통하여 넘겨진 팔레트의 사용 방법을 결정한다. 보통 팔레트에 저장한 값을 실제 RGB 색상 값으로 사용하는 방법인 DIB_RGB_COLORS를 사용한다.

 

- 매개 변수 rop : 입력 영상의 픽셀 값으로부터 출력 화면의 픽셀 값을 구하는 방법을 결정하는 것으로 그대로 복사하는 방법(SRCCOPY), 반전하여 복사하는 방법(NOTCOPY), 현재 화면의 픽셀 값과 OR 연산을 하는 방법(SRCPAINT), 현재 화면의 픽셀 값과 AND 연산을 하는 방법(SRCAND) 등이 있다.

 

 

 

bool _DrawImage(HDC hdc, const CByteImage& image,
	int nSrcX, int nSrcY, int nSrcW, int nSrcH,
	int nDstX, int nDstY, int nDstW, int nDstH)
{
	if (image.IsEmpty()) return false; // 빈 영상이면 바로 종료

	int nWidth = image.GetWStep() / image.GetChannel();
	int nHeight = image.GetHeight();
	int nBPP = image.GetChannel() * 8;

	// 256색 회색조 또는 트루 컬러 영상만 출력 가능
	ASSERT(nWidth > 0 && nHeight > 0 && (nBPP == 8 || nBPP == 24));

	BITMAPINFOHEADER *bmih = &(((BITMAPINFO*)bmiBuf)->bmiHeader); //bmiBuf는 밑에 설명
	memset(bmih, 0, sizeof(*bmih));
	bmih->biSize = sizeof(BITMAPINFOHEADER);
	bmih->biWidth = nWidth;
	bmih->biHeight = -nHeight;	// 실제 비트맵 파일이 저장될 때는 상하가 반대로 저장 되므로 위에서 아래로 출력. 
	bmih->biPlanes = 1;         //무조건 1이어야함
	bmih->biBitCount = nBPP;
	bmih->biCompression = BI_RGB; // 압축 사용 안함

	if (nBPP == 8)   //회색조 영상일 경우 팔레트 저장. GrayPalette는 밑에서 설명
		memcpy(((BITMAPINFO*)bmiBuf)->bmiColors, GrayPalette, 256 * sizeof(RGBQUAD));

	SetStretchBltMode(hdc, COLORONCOLOR); //StretchDIBits로 비트맵을 축소 시 화면이 깨지는 거 방지
	::StretchDIBits(
		hdc,
		nDstX, nDstY, nDstW, nDstH,
		nSrcX, nSrcY, nSrcW, nSrcH,
		image.GetPtr(),
		(LPBITMAPINFO) &(((BITMAPINFO*)bmiBuf)->bmiHeader),
		DIB_RGB_COLORS,
		SRCCOPY);

	return true;
}

 

 

static BYTE bmiBuf[sizeof(BITMAPINFOHEADER) + 1024];
static const RGBQUAD GrayPalette[256] =
{
	{ 0,   0,   0,  0 },{ 1,   1,   1,  0 },{ 2,   2,   2,  0 },{ 3,   3,   3,  0 },{ 4,   4,   4,  0 },{ 5,   5,   5,  0 },{ 6,   6,   6,  0 },{ 7,   7,   7,  0 },{ 8,   8,   8,  0 },{ 9,   9,   9,  0 },
	{ 10,  10,  10,  0 },{ 11,  11,  11,  0 },{ 12,  12,  12,  0 },{ 13,  13,  13,  0 },{ 14,  14,  14,  0 },{ 15,  15,  15,  0 },{ 16,  16,  16,  0 },{ 17,  17,  17,  0 },{ 18,  18,  18,  0 },{ 19,  19,  19,  0 },
	{ 20,  20,  20,  0 },{ 21,  21,  21,  0 },{ 22,  22,  22,  0 },{ 23,  23,  23,  0 },{ 24,  24,  24,  0 },{ 25,  25,  25,  0 },{ 26,  26,  26,  0 },{ 27,  27,  27,  0 },{ 28,  28,  28,  0 },{ 29,  29,  29,  0 },
	{ 30,  30,  30,  0 },{ 31,  31,  31,  0 },{ 32,  32,  32,  0 },{ 33,  33,  33,  0 },{ 34,  34,  34,  0 },{ 35,  35,  35,  0 },{ 36,  36,  36,  0 },{ 37,  37,  37,  0 },{ 38,  38,  38,  0 },{ 39,  39,  39,  0 },
	{ 40,  40,  40,  0 },{ 41,  41,  41,  0 },{ 42,  42,  42,  0 },{ 43,  43,  43,  0 },{ 44,  44,  44,  0 },{ 45,  45,  45,  0 },{ 46,  46,  46,  0 },{ 47,  47,  47,  0 },{ 48,  48,  48,  0 },{ 49,  49,  49,  0 },
	{ 50,  50,  50,  0 },{ 51,  51,  51,  0 },{ 52,  52,  52,  0 },{ 53,  53,  53,  0 },{ 54,  54,  54,  0 },{ 55,  55,  55,  0 },{ 56,  56,  56,  0 },{ 57,  57,  57,  0 },{ 58,  58,  58,  0 },{ 59,  59,  59,  0 },
	{ 60,  60,  60,  0 },{ 61,  61,  61,  0 },{ 62,  62,  62,  0 },{ 63,  63,  63,  0 },{ 64,  64,  64,  0 },{ 65,  65,  65,  0 },{ 66,  66,  66,  0 },{ 67,  67,  67,  0 },{ 68,  68,  68,  0 },{ 69,  69,  69,  0 },
	{ 70,  70,  70,  0 },{ 71,  71,  71,  0 },{ 72,  72,  72,  0 },{ 73,  73,  73,  0 },{ 74,  74,  74,  0 },{ 75,  75,  75,  0 },{ 76,  76,  76,  0 },{ 77,  77,  77,  0 },{ 78,  78,  78,  0 },{ 79,  79,  79,  0 },
	{ 80,  80,  80,  0 },{ 81,  81,  81,  0 },{ 82,  82,  82,  0 },{ 83,  83,  83,  0 },{ 84,  84,  84,  0 },{ 85,  85,  85,  0 },{ 86,  86,  86,  0 },{ 87,  87,  87,  0 },{ 88,  88,  88,  0 },{ 89,  89,  89,  0 },
	{ 90,  90,  90,  0 },{ 91,  91,  91,  0 },{ 92,  92,  92,  0 },{ 93,  93,  93,  0 },{ 94,  94,  94,  0 },{ 95,  95,  95,  0 },{ 96,  96,  96,  0 },{ 97,  97,  97,  0 },{ 98,  98,  98,  0 },{ 99,  99,  99,  0 },
	{ 100, 100, 100,  0 },{ 101, 101, 101,  0 },{ 102, 102, 102,  0 },{ 103, 103, 103,  0 },{ 104, 104, 104,  0 },{ 105, 105, 105,  0 },{ 106, 106, 106,  0 },{ 107, 107, 107,  0 },{ 108, 108, 108,  0 },{ 109, 109, 109,  0 },
	{ 110, 110, 110,  0 },{ 111, 111, 111,  0 },{ 112, 112, 112,  0 },{ 113, 113, 113,  0 },{ 114, 114, 114,  0 },{ 115, 115, 115,  0 },{ 116, 116, 116,  0 },{ 117, 117, 117,  0 },{ 118, 118, 118,  0 },{ 119, 119, 119,  0 },
	{ 120, 120, 120,  0 },{ 121, 121, 121,  0 },{ 122, 122, 122,  0 },{ 123, 123, 123,  0 },{ 124, 124, 124,  0 },{ 125, 125, 125,  0 },{ 126, 126, 126,  0 },{ 127, 127, 127,  0 },{ 128, 128, 128,  0 },{ 129, 129, 129,  0 },
	{ 130, 130, 130,  0 },{ 131, 131, 131,  0 },{ 132, 132, 132,  0 },{ 133, 133, 133,  0 },{ 134, 134, 134,  0 },{ 135, 135, 135,  0 },{ 136, 136, 136,  0 },{ 137, 137, 137,  0 },{ 138, 138, 138,  0 },{ 139, 139, 139,  0 },
	{ 140, 140, 140,  0 },{ 141, 141, 141,  0 },{ 142, 142, 142,  0 },{ 143, 143, 143,  0 },{ 144, 144, 144,  0 },{ 145, 145, 145,  0 },{ 146, 146, 146,  0 },{ 147, 147, 147,  0 },{ 148, 148, 148,  0 },{ 149, 149, 149,  0 },
	{ 150, 150, 150,  0 },{ 151, 151, 151,  0 },{ 152, 152, 152,  0 },{ 153, 153, 153,  0 },{ 154, 154, 154,  0 },{ 155, 155, 155,  0 },{ 156, 156, 156,  0 },{ 157, 157, 157,  0 },{ 158, 158, 158,  0 },{ 159, 159, 159,  0 },
	{ 160, 160, 160,  0 },{ 161, 161, 161,  0 },{ 162, 162, 162,  0 },{ 163, 163, 163,  0 },{ 164, 164, 164,  0 },{ 165, 165, 165,  0 },{ 166, 166, 166,  0 },{ 167, 167, 167,  0 },{ 168, 168, 168,  0 },{ 169, 169, 169,  0 },
	{ 170, 170, 170,  0 },{ 171, 171, 171,  0 },{ 172, 172, 172,  0 },{ 173, 173, 173,  0 },{ 174, 174, 174,  0 },{ 175, 175, 175,  0 },{ 176, 176, 176,  0 },{ 177, 177, 177,{ 208, 208, 208,  0 },{ 209, 209, 209,  0 },
	{ 210, 210, 210,  0 },{ 211, 211, 211,  0 },{ 212, 212, 212,  0 },{ 213, 213, 213,  0 },{ 214, 214, 214,  0 },{ 215, 215, 215,  0 },{ 216, 216, 216,  0 },{ 217, 217, 217,  0 },{ 218, 218, 218,  0 },{ 219, 219, 219,  0 },
	{ 220, 220, 220,  0 },{ 221, 221, 221,  0 },{ 222, 222, 222,  0 },{ 223, 223, 223,  0 },{ 224, 224, 224,  0 },{ 225, 225, 225,  0 },{ 226, 226, 226,  0 },{ 227, 227, 227,  0 },{ 228, 228, 228,  0 },{ 229, 229, 229,  0 },
	{ 230, 230, 230,  0 },{ 231, 231, 231,  0 },{ 232, 232, 232,  0 },{ 233, 233, 233,  0 },{ 234, 234, 234,  0 },{ 235, 235, 235,  0 },{ 236, 236, 236,  0 },{ 237, 237, 237,  0 },{ 238, 238, 238,  0 },{ 239, 239, 239,  0 },
	{ 240, 240, 240,  0 },{ 241, 241, 241,  0 },{ 242, 242, 242,  0 },{ 243, 243, 243,  0 },{ 244, 244, 244,  0 },{ 245, 245, 245,  0 },{ 246, 246, 246,  0 },{ 247, 247, 247,  0 },{ 248, 248, 248,  0 },{ 249, 249, 249,  0 },
	{ 250, 250, 250,  0 },{ 251, 251, 251,  0 },{ 252, 252, 252,  0 },{ 253, 253, 253,  0 },{ 254, 254, 254,  0 },{ 255, 255, 255,  0 }
};

bmiBuf의 크기에 1024를 더해준 이유는 팔레트의 최대 크기가 1024byte이기 때문이다. RGBQUAD 구조체는 BYTE형 변수 4개가 모인 것이이고 팔레트의 최대 갯수가 256개이므로 최대 크기가 1024이다(위의 GrayPalette변수가 그렇다). 또한 GrayPalette 변수는 회색조 영상의 팔레트로 사용할 RGBQUAD 구조체의 배열로서 {0,0,0,0}에서 {255,255,255,255}의 정적 변수로 선언해 두고 사용한다.

+ Recent posts