--- plugin_ssim.c 2006/10/30 11:21:42 1.5 +++ plugin_ssim.c 2007/07/26 14:30:31 1.9 @@ -23,7 +23,7 @@ * ****************************************************************************/ -#include +#include #include #include #include "../portab.h" @@ -37,6 +37,22 @@ typedef struct framestat_t framestat_t; +/*dev 1.0 gaussian weighting. the weight for the pixel x,y is w(x)*w(y)*/ +static float mask8[8] = { + 0.0069815, 0.1402264, 1.0361408, 2.8165226, + 2.8165226, 1.0361408, 0.1402264, 0.0069815 +}; + +/* integer version. Norm: coeffs sums up to 4096. + Define USE_INT_GAUSSIAN to use it as replacement to float version */ + +/* #define USE_INT_GAUSSIAN */ +static const uint16_t imask8[8] = { + 4, 72, 530, 1442, 1442, 530, 72, 4 +}; +#define GACCUM(X) ( ((X)+(1<<11)) >> 12 ) + + struct framestat_t{ int type; int quant; @@ -116,7 +132,7 @@ fprintf(out,"SSIM Error Metric\n"); fprintf(out,"quant avg min max\n"); while(tmp->next->next != NULL){ - fprintf(out,"%3d %1.4f %1.4f %1.4f\n",tmp->quant,tmp->ssim_avg,tmp->ssim_min,tmp->ssim_max); + fprintf(out,"%3d %1.3f %1.3f %1.3f\n",tmp->quant,tmp->ssim_avg,tmp->ssim_min,tmp->ssim_max); tmp = tmp->next; } fclose(out); @@ -221,6 +237,35 @@ return mean; } +int lum_8x8_gaussian(uint8_t* ptr, int stride){ + float mean=0,sum; + int i,j; + for(i=0;i<8;i++){ + sum = 0; + for(j=0;j<8;j++) + sum += ptr[i*stride + j]*mask8[j]; + + sum *=mask8[i]; + mean += sum; + } + return (int) mean + 0.5; +} + +int lum_8x8_gaussian_int(uint8_t* ptr, int stride){ + uint32_t mean; + int i,j; + mean = 0; + for(i=0;i<8;i++){ + uint32_t sum = 0; + for(j=0;j<8;j++) + sum += ptr[i*stride + j]*imask8[j]; + + sum = GACCUM(sum) * imask8[i]; + mean += sum; + } + return (int)GACCUM(mean); +} + /*calculate the difference between two blocks next to each other on a row*/ int lum_2x8_c(uint8_t* ptr, int stride){ int mean=0,i; @@ -234,6 +279,71 @@ } /*calculate contrast and correlation of the two blocks*/ +void consim_gaussian(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){ + unsigned int valo, valc,i,j,str; + float devo=0, devc=0, corr=0,sumo,sumc,sumcorr; + str = stride - 8; + for(i=0;i< 8;i++){ + sumo = 0; + sumc = 0; + sumcorr = 0; + for(j=0;j< 8;j++){ + valo = *ptro; + valc = *ptrc; + sumo += valo*valo*mask8[j]; + sumc += valc*valc*mask8[j]; + sumcorr += valo*valc*mask8[j]; + ptro++; + ptrc++; + } + + devo += sumo*mask8[i]; + devc += sumc*mask8[i]; + corr += sumcorr*mask8[i]; + ptro += str; + ptrc += str; + } + + *pdevo = (int) (devo - ((lumo*lumo + 32) >> 6)) + 0.5; + *pdevc = (int) (devc - ((lumc*lumc + 32) >> 6)) + 0.5; + *pcorr = (int) (corr - ((lumo*lumc + 32) >> 6)) + 0.5; +}; + +void consim_gaussian_int(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr) +{ + unsigned int valo, valc,i,j,str; + uint32_t devo=0, devc=0, corr=0; + str = stride - 8; + for(i=0;i< 8;i++){ + uint32_t sumo = 0; + uint32_t sumc = 0; + uint32_t sumcorr = 0; + for(j=0;j< 8;j++){ + valo = *ptro; + valc = *ptrc; + sumo += valo*valo*imask8[j]; + sumc += valc*valc*imask8[j]; + sumcorr += valo*valc*imask8[j]; + ptro++; + ptrc++; + } + + devo += GACCUM(sumo)*imask8[i]; + devc += GACCUM(sumc)*imask8[i]; + corr += GACCUM(sumcorr)*imask8[i]; + ptro += str; + ptrc += str; + } + + devo = GACCUM(devo); + devc = GACCUM(devc); + corr = GACCUM(corr); + *pdevo = (int) (devo - ((lumo*lumo + 32) >> 6)) + 0.5; + *pdevc = (int) (devc - ((lumc*lumc + 32) >> 6)) + 0.5; + *pcorr = (int) (corr - ((lumo*lumc + 32) >> 6)) + 0.5; +}; + +/*calculate contrast and correlation of the two blocks*/ void consim_c(uint8_t* ptro, uint8_t* ptrc, int stride, int lumo, int lumc, int* pdevo, int* pdevc, int* pcorr){ unsigned int valo, valc, devo=0, devc=0, corr=0,i,j,str; str = stride - 8; @@ -257,21 +367,15 @@ }; /*calculate the final ssim value*/ -static float calc_ssim(int meano, int meanc, int devo, int devc, int corr){ +static float calc_ssim(float meano, float meanc, float devo, float devc, float corr){ static const float c1 = (0.01*255)*(0.01*255); static const float c2 = (0.03*255)*(0.03*255); - float fmeano,fmeanc,fdevo,fdevc,fcorr; - fmeanc = (float) meanc; - fmeano = (float) meano; - fdevo = (float) devo; - fdevc = (float) devc; - fcorr = (float) corr; - /* printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",fmeano,fmeanc,fdevo,fdevc,fcorr); */ - return ((2.0*fmeano*fmeanc + c1)*(fcorr/32.0 + c2))/((fmeano*fmeano + fmeanc*fmeanc + c1)*(fdevc/64.0 + fdevo/64.0 + c2)); + /*printf("meano: %f meanc: %f devo: %f devc: %f corr: %f\n",meano,meanc,devo,devc,corr);*/ + return ((2.0*meano*meanc + c1)*(corr/32.0 + c2))/((meano*meano + meanc*meanc + c1)*(devc/64.0 + devo/64.0 + c2)); } static void ssim_after(xvid_plg_data_t* data, ssim_data_t* ssim){ - int i,j,c=0; + int i,j,c=0,opt; int width,height,str,ovr; unsigned char * ptr1,*ptr2; float isum=0, min=1.00,max=0.00, val; @@ -287,7 +391,7 @@ ptr1 = (unsigned char*) data->original.plane[0]; ptr2 = (unsigned char*) data->current.plane[0]; - + opt = ssim->grid == 1 && ssim->param->acc != 0; /*TODO: Thread*/ for(i=0;igrid){ @@ -298,7 +402,7 @@ ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); emms(); - val = calc_ssim(meano,meanc,devo,devc,corr); + val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr); isum += val; c++; /* for visualisation @@ -313,17 +417,17 @@ ptr2+=ssim->grid; /*rest of each row*/ for(j=ssim->grid;jgrid){ - if(ssim->grid == 1){ - meano += ssim->func2x8(ptr1,str); - meanc += ssim->func2x8(ptr2,str); - } else { - meano = ssim->func8x8(ptr1,str); - meanc = ssim->func8x8(ptr2,str); + if(opt){ + meano += ssim->func2x8(ptr1,str); + meanc += ssim->func2x8(ptr2,str); + } else { + meano = ssim->func8x8(ptr1,str); + meanc = ssim->func8x8(ptr2,str); } ssim->consim(ptr1,ptr2,str,meano,meanc,&devo,&devc,&corr); emms(); - val = calc_ssim(meano,meanc,devo,devc,corr); + val = calc_ssim((float) meano,(float) meanc,(float) devo,(float) devc,(float) corr); isum += val; c++; /* for visualisation @@ -354,7 +458,7 @@ } */ if(ssim->param->b_printstat){ - printf(" SSIM: avg: %f min: %f max: %f\n",isum,min,max); + printf(" SSIM: avg: %1.3f min: %1.3f max: %1.3f\n",isum,min,max); } } @@ -362,13 +466,10 @@ static int ssim_create(xvid_plg_create_t* create, void** handle){ ssim_data_t* ssim; plg_ssim_param_t* param; - int cpu_flags; param = (plg_ssim_param_t*) malloc(sizeof(plg_ssim_param_t)); *param = *((plg_ssim_param_t*) create->param); ssim = (ssim_data_t*) malloc(sizeof(ssim_data_t)); - cpu_flags = check_cpu_features(); - ssim->func8x8 = lum_8x8_c; ssim->func2x8 = lum_2x8_c; ssim->consim = consim_c; @@ -377,21 +478,36 @@ ssim->grid = param->acc; - /*gaussian weigthing not implemented*/ - if(ssim->grid == 0) ssim->grid = 1; - if(ssim->grid > 4) ssim->grid = 4; - - printf("Grid: %d\n",ssim->grid); - #if defined(ARCH_IS_IA32) - if((cpu_flags & XVID_CPU_MMX) && (param->acc > 0)){ - ssim->func8x8 = lum_8x8_mmx; - ssim->consim = consim_mmx; + { + int cpu_flags = check_cpu_features(); + if((cpu_flags & XVID_CPU_MMX) && (param->acc > 0)){ + ssim->func8x8 = lum_8x8_mmx; + ssim->consim = consim_mmx; + } + if((cpu_flags & XVID_CPU_SSE2) && (param->acc > 0)){ + ssim->consim = consim_sse2; + } } - if((cpu_flags & XVID_CPU_SSE2) && (param->acc > 0)){ - ssim->consim = consim_sse2; +#endif + + /*gaussian weigthing not implemented*/ +#if !defined(USE_INT_GAUSSIAN) + if(ssim->grid == 0){ + ssim->grid = 1; + ssim->func8x8 = lum_8x8_gaussian; + ssim->func2x8 = NULL; + ssim->consim = consim_gaussian; + } +#else + if(ssim->grid == 0){ + ssim->grid = 1; + ssim->func8x8 = lum_8x8_gaussian_int; + ssim->func2x8 = NULL; + ssim->consim = consim_gaussian_int; } #endif + if(ssim->grid > 4) ssim->grid = 4; ssim->ssim_sum = 0.0; ssim->frame_cnt = 0;