YUV to RGB ...

Program Visual C++ 2011. 8. 10. 16:34 Posted by HisPark
// 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;