// YUV_B, YUV_R, YUV_G 배열은 사용하기 전에 YUV_lookup_table() 함수로 초기화해야 한다.
double YY[256], BU[256], GV[256], GU[256], RV[256];
unsigned char YUV_B[256][256];
unsigned char YUV_R[256][256];
unsigned char YUV_G[256][256][256];
void YUV_lookup_table()
{
int i, j, k;
double i_value;
for( i=255; i>=0; i-- )
{
YY[i] = (1.164*(i-16.0));
BU[i] = (2.018*(i-128.0));
GV[i] = (0.831*(i-128.0));
GU[i] = (0.391*(i-128.0));
RV[i] = (1.596*(i-128.0));
}
for( i=255; i>=0; i-- ){
for( j=255; j>=0; j-- )
{
i_value = YY[i] + BU[j];
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_B[i][j]=(int)i_value;
i_value = YY[i] + RV[j];
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_R[i][j]=(int)i_value;
for( k=0; k<256; k++ )
{
i_value = YY[i] - (GU[j] + GV[k]);
if ( i_value > 255 ) i_value=255;
else if ( i_value < 0 ) i_value=0;
YUV_G[i][j][k] =(int)i_value;
}
}
}
}
// YUV 영상을 RGB 영상으로 바꾸는 함수
void yuv420_to_rgb( unsigned char *in, unsigned char *out, int w, int h
)
{
int x,y;
double imgsize = w*h;
int w3 = w*3;
double uvsize = imgsize/4.0;
unsigned char *pY = in;
unsigned char *pV = in + (int)imgsize;
unsigned char *pU = in + (int)imgsize + (int)uvsize;
int y00, y01, y10, y11;
int u,v;
unsigned char *p;
// 윈도우에서는 영상의 상하가 거꾸로 저장되지 때문에 아래와 같이 코드 작성.
for( y=0; y<=h-2; y+=2 )
{
for( x=0; x<=w-2; x+=2 )
{
p = out + w3*(h-y-1) + x*3;
u = *pU;
v = *pV;
y00 = *pY;
y01 = *(pY+1);
y10 = *(pY+w);
y11 = *(pY+w+1);
*(p) = YUV_B[y00][u];
*(p+1) = YUV_G[y00][u][v];
*(p+2) = YUV_R[y00][v];
*(p+3) = YUV_B[y01][u];
*(p+3+1) = YUV_G[y01][u][v];
*(p+3+2) = YUV_R[y01][v];
*(p-w3) = YUV_B[y10][u];
*(p-w3+1) = YUV_G[y10][u][v];
*(p-w3+2) = YUV_R[y10][v];
*(p-w3+3) = YUV_B[y11][u];
*(p-w3+3+1) = YUV_G[y11][u][v];
*(p-w3+3+2) = YUV_R[y11][v];
pU++;
pV++;
pY = pY + 2;
}
pY = pY + w;
}
// 일반적인 경우 아래의 코드 사용함.
/*for( y=0; y<=h-2; y+=2 )
{
for( x=0; x<=w-2; x+=2 )
{
p = out + w3*y + x*3;
u = *pU;
v = *pV;
y00 = *pY;
y01 = *(pY+1);
y10 = *(pY+w);
y11 = *(pY+w+1);
*(p) = YUV_B[y00][u];
*(p+1) = YUV_G[y00][u][v];
*(p+2) = YUV_R[y00][v];
*(p+3) = YUV_B[y01][u];
*(p+3+1) = YUV_G[y01][u][v];
*(p+3+2) = YUV_R[y01][v];
*(p+w3) = YUV_B[y10][u];
*(p+w3+1) = YUV_G[y10][u][v];
*(p+w3+2) = YUV_R[y10][v];
*(p+w3+3) = YUV_B[y11][u];
*(p+w3+3+1) = YUV_G[y11][u][v];
*(p+w3+3+2) = YUV_R[y11][v];
pU++;
pV++;
pY = pY + 2;
}
pY = pY + w;
}*/
}
//////////////////////////////////////////////////////////////////////////////////////
// BMP 파일로 저장하기
int rgbSize = _imageSize.cx*_imageSize.cy*3;
BYTE* pRgb = new BYTE[rgbSize];
memset(pRgb, 0, rgbSize);
yuv420_to_rgb(_pImage, pRgb, _imageSize.cx, _imageSize.cy);
/*TCHAR curDirPath[512];
::GetModuleFileName(NULL, curDirPath, 512);
TCHAR* pExt = _tcsrchr(curDirPath, _T('\\'));
if(pExt) *pExt = 0;*/
TCHAR defExt[] = _T("bmp");
TCHAR filters[] = _T("bmp Files(*.bmp)|*.bmp|All
Files(*.*)|*.*||");
DWORD flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
TCHAR cd[_MAX_PATH];
GetCurrentDirectory(_MAX_PATH, cd);
CFileDialog dlg(FALSE, defExt, 0, flags, filters, this);
dlg.m_ofn.lpstrInitialDir = cd;
if(IDOK == dlg.DoModal()){
HANDLE hFile;
hFile = CreateFile(dlg.GetPathName(), GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE){
CString s; s.Format(_T("Could not create file : %s (error
%d)\n"), dlg.GetPathName(), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
return;
}
int headerSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD);
BITMAPFILEHEADER fileHeader = { ((WORD)('M'<<8)|'B'),
headerSize + rgbSize, 0, 0, headerSize};
BITMAPINFOHEADER infoHeader = { sizeof(BITMAPINFOHEADER),
_imageSize.cx, _imageSize.cy, 1, 24, BI_RGB, rgbSize, 0, 0, 0, 0 };
RGBQUAD rgbQuad = { 0, };
DWORD writtenLen = 0;
if(FALSE == WriteFile(hFile, &fileHeader,
sizeof(fileHeader), &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error
%d)\n"), _T("File Header"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
if(FALSE == WriteFile(hFile, &infoHeader,
sizeof(infoHeader), &writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error
%d)\n"), _T("Info Header"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
if(FALSE == WriteFile(hFile, &rgbQuad, sizeof(rgbQuad),
&writtenLen, 0)){
CString s; s.Format(_T("Could not write file : %s (error
%d)\n"), _T("RGB Quad"), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
if(FALSE == WriteFile(hFile, pRgb, rgbSize, &writtenLen,
0)){
CString s; s.Format(_T("Could not write file : %s (error
%d)\n"), dlg.GetPathName(), GetLastError());
AfxMessageBox(s, MB_ICONSTOP|MB_OK);
}
CloseHandle(hFile);
}
if(pRgb) delete [] pRgb;
[출처] YUV420을 RGB로 변환하기 (차니의 컴퓨터 마을) |작성자 newchany
'Program Visual C++' 카테고리의 다른 글
MFC 더블버퍼링 메모리 버퍼 이용 (0) | 2011.08.25 |
---|---|
RAW Data Draw (0) | 2011.08.11 |
쓰레드 사용 예제?? AfxBeginThread, CreateThread, _beginthreadex (0) | 2010.10.10 |
AfxBeginThread 사용법? (0) | 2009.05.05 |
Microsoft Platform SDK (0) | 2009.02.25 |