JPEG압축과 PSNR추출하기

from MFC 2013. 10. 10. 13:28

JPEG양자화 과정 + 압축률 변경에 대한 예제는 다음과 같다.

일부분만 첨부할 것이고, 이해가 어렵다면 전체 코드를 첨부할테니 참고하도록 한다.


압축파일.002


압축파일.003


압축파일.004


압축파일.EXE


void CJpeg::DCT(short * pos, int bWidth, BOOL Flag)

{

// DCT 분만 아니라, DCT 후의 Zigzag 까지... 게다가 Quantization 까지!?//

BYTE Qtb0[64] ={16, 11, 12, 14, 12, 10, 16, 14, 

13, 14, 18, 17, 16, 19, 24, 40, 

26, 24, 22, 22, 24, 49, 36, 37, 

29, 40, 58, 51, 61, 60, 57, 51, 

56, 55, 64, 72, 92, 78, 64, 68, 

87, 69, 66, 57, 80, 109, 81, 87,

95, 98, 103, 104, 103, 62, 77, 113,

121, 112, 100, 120, 92, 101, 103, 99};

BYTE Qtb1[64] ={17, 18, 18, 24, 21, 24, 47, 26,

26, 47, 99, 66, 56, 66, 99, 99,

99 ,99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99 };



int i, j;

int x, y, u, v;

float Cu, Cv;

float Sum;

float dct_coeff[8][8] =

{

  +1.0f, +1.0f,    +1.0f, +1.0f,   +1.0f, +1.0f,   +1.0f, +1.0f, 

+0.9808f, +0.8315f, +0.5556f, +0.1951f, -0.1951f, -0.5556f, -0.8315f, -0.9808f,

+0.9239f, +0.3827f, -0.3827f, -0.9239f, -0.9239f, -0.3827f, +0.3827f, +0.9239f,

+0.8315f, -0.1951f, -0.9808f, -0.5556f, +0.5556f, +0.9808f, +0.1951f, -0.8315f,

+0.7071f, -0.7071f, -0.7071f, +0.7071f, +0.7071f, -0.7071f, -0.7071f, +0.7071f,

+0.5556f, -0.9808f, +0.1951f, +0.8315f, -0.8315f, -0.1951f, +0.9808f, -0.5556f,

+0.3827f, -0.9239f, +0.9239f, -0.3827f, -0.3827f, +0.9239f, -0.9239f, +0.3827f,

+0.1951f, -0.5556f, +0.8315f, -0.9808f, +0.9808f, -0.8315f, +0.5556f, -0.1951f

};


for(v=0; v<8; v++)

{

for(u=0; u<8; u++)

{

Sum = 0;


for(y=0; y<8; y++)

for(x=0; x<8; x++)

Sum = Sum + pos[(int)(y*bWidth+x)] * dct_coeff[u][x] * dct_coeff[v][y];

Cu = 1.; if(u == 0) Cu = 0.7071f;

Cv = 1.; if(v == 0) Cv = 0.7071f;

ZZ[(int)(v*8+u)] = (short)(Cu * Cv * Sum / 4.);

}

}

Zigzag2();


//m_nQfactor변수값을 이용하여 밝기Y와 색차신호(cb,cr) 양자화 테이블 값을 변경하고 있다.

if(Flag) // TRUE : Chrominance, FALSE : Luminance

for(i=0; i<64; i++)

ZZ[i] = ZZ[i] / (m_nQFactor * Qtb1[i]);

else

for(i=0; i<64; i++)

ZZ[i] = ZZ[i] / (m_nQFactor * Qtb0[i]);

for(i=0; i<8; i++)

for(j=0; j<8; j++)

//pos[i*bWidth+j] = (m_nQFactor * ZZ[i*8+j]);

pos[i*bWidth+j] = ZZ[i*8+j];

}


void CJpeg::Zigzag2()

{

int Index[64] = 

{0,  1,  5,  6,  14, 15, 27, 28,

2,  4,  7,  13, 16, 26, 29, 42, 

3,  8,  12, 17, 25, 30, 41, 43, 

9,  11, 18, 24, 31, 40, 44, 53, 

10, 19, 23, 32, 39, 45, 52, 54, 

20, 22, 33, 38, 46, 51, 55, 60,

21, 34, 37, 47, 50, 56, 59, 61,

35, 36, 48, 49, 57, 58, 62, 63};

short Temp[64];

memcpy(Temp, ZZ, 64 * sizeof(short));

int i, j, idx;

for(i=0; i<8; i++)

for(j=0; j<8; j++)

{

idx = (i<<3)+j;

ZZ[Index[idx]] = Temp[idx];

}


}

양자화율이 높을수록 (양자화 테이블값이 클수록) 압축률은 높지만 영상의 화질은 떨어지게 된다.


압축률 변경 실습

void CJpeg::PutDQT(HFILE hFile)

{

WORD Marker, SegSize;

BYTE c;

// Luminance Quantization Table //

BYTE Qtb0[64] = {16, 11, 12, 14, 12, 10, 16, 14,

13, 14, 18, 17, 16, 19, 24, 40,

26, 24, 22, 22, 24, 49, 36, 37,

29, 40, 58, 51, 61, 60, 57, 51,

56, 55, 64, 72, 92, 78, 64, 68,

87, 69, 66, 57, 80, 109, 81, 87,

95, 98, 103, 104, 103, 62, 77, 113,

121, 112, 100, 120, 92, 101, 103, 99};

// Chrominance Quantization Table //

BYTE Qtb1[64] = {17, 18, 18, 24, 21, 24, 47, 26,

26, 47, 99, 66, 56, 66, 99, 99,

99 ,99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99, 

99, 99, 99, 99, 99, 99, 99, 99 };

for(int i = 0 ; i < 64 ; i++)

{

Qtb0[i]=Qtb0[i]*m_nQFactor;

        Qtb1[i]=Qtb1[i]*m_nQFactor;

    }


Marker = (0xdb << 8) | 0xff;

_lwrite(hFile, (LPSTR)&Marker, 2); // Marker

SegSize = 67; SegSize = (SegSize << 8) | (SegSize >> 8);

_lwrite(hFile, (LPSTR)&SegSize, 2); // Segment Size

c = 0; _lwrite(hFile, (LPSTR)&c, 1); // PqTq = 0

_lwrite(hFile, (LPSTR)Qtb0, 64); // Q0 ~ Q63

Marker = (0xdb << 8) | 0xff;

_lwrite(hFile, (LPSTR)&Marker, 2); // Marker

SegSize = 67; SegSize = (SegSize << 8) | (SegSize >> 8);

_lwrite(hFile, (LPSTR)&SegSize, 2); // Segment Size

c = 1; _lwrite(hFile, (LPSTR)&c, 1); // PqTq = 1

_lwrite(hFile, (LPSTR)Qtb1, 64); // Q0 ~ Q63

}

밝기값과 색차신호를 위해 변경된 양자화 테이블을 Q_Factor에 반영하여 JPEG파일의 헤더부분에 저장한다.


다음은 화질을 평가하는 지표인 PSNR을 추출해보자.

double CJpeg::GetPSNR()

{


double MSE = 0.0, PSNR = 0.0;


if( m_pSrc == NULL || m_pTarget == NULL ){

        return PSNR;

    } 


int Height = GetHeight();

int Width = GetWidth();

int bWidth = Width;

int bHeight = Height;


if(Width % 8 != 0)

bWidth = (Width/8 + 1)*8;   // bWidth 는 8의 배수로 만든 넓이

if(Height % 8 != 0)

bHeight = (Height/8 + 1)*8; // bHeight 는 8의 배수로 만든 높이


int i,j;

int idxY, idxCb, idxCr;

for(i=0; i<Height; i++)

{

for(j=0; j<Width; j++)

{

idxY = i*(bWidth*3)+j*3; // Y

idxCb = idxY + 1; // Cb

idxCr = idxY + 2; // Cr


MSE += pow( m_pSrc[ idxY ] - m_pTarget[ idxY ], (double)2 );  //  Y에 대한 MSE 계산 

//MSE += pow( m_pSrc[ idxCb ] - m_pTarget[ idxCb ], 2 );  // Cb에 대한 MSE 계산 

//MSE += pow( m_pSrc[ idxCr ] - m_pTarget[ idxCr ], 2 );  // Cr에 대한 MSE 계산 

}

}


실행결과

양자화 테이블 값을 변경하여 JPEG로 압축하고 PSNR까지 표시해주는 프로그램을 작성했다.

Q_facter = 1인 경우

Q_factor = 15인 경우

'MFC' 카테고리의 다른 글

H.263  (0) 2013.10.17
통신에 대한 대략적인 개요  (0) 2013.10.10
웨이블릿 변환  (2) 2013.06.27
중간 시험 예상 문제  (0) 2013.06.05
데이터 메모리 영역, 허프만 트리..를 만들어야 하지만 리스트 만들기  (0) 2013.05.30
,