www.pudn.com > wavecode.rar > image.c
#define AVE_DEL_YUV // turn U&V to (U+V) , (U-V) /** works dandy; it visually works at compactifying magnitudes : U & V are very similar * also compactifies noise into the third band * <> needs more testing to make sure this isn't image-anomalous **/ #include#include #include #include #include #include "image.h" #include "quantim.h" #include "haar.h" #include "dwt.h" #include "dct.h" #include "spt.h" #include "cdf22.h" #include "cdf24.h" #include "bcw3.h" #include "d4.h" #include "f97.h" #include "b97.h" #include "l97.h" #if 1 // words are Intel #define fgetuw fgetuwi #define fputuw fputuwi #endif // intel words image * newImage(int width, int height,int planes) { int p,y; image * im; int **rows; if ( (im = new(image)) == NULL ) return NULL; im->width = width; im->height = height; im->planes = planes; im->plane_size = width*height; im->plane_bytes = (im->plane_size)*sizeof(int); im->tot_bytes = im->plane_bytes * planes; im->tot_size = im->plane_size * planes; if ( (im->data = newarray(int **,planes)) == NULL ) { freeImage(im); return NULL; } for(p=0;p data[p] = newarray(int *,height+1)) == NULL ) { freeImage(im); return NULL; } rows = im->data[p]; if ( (rows[0] = malloc(im->plane_bytes + height)) == NULL ) { freeImage(im); return NULL; } for (y = 1; y <= height; y++) rows[y] = rows[y-1] + width; } return im; } imageFloat * newImageFloat(int width, int height,int planes) { int p,y; imageFloat * im; double **rows; if ( (im = new(image)) == NULL ) return NULL; im->width = width; im->height = height; im->planes = planes; im->plane_size = width*height; im->plane_bytes = (im->plane_size)*sizeof(double); im->tot_bytes = im->plane_bytes * planes; im->tot_size = im->plane_size * planes; if ( (im->data = newarray(double **,planes)) == NULL ) { freeImageFloat(im); return NULL; } for(p=0;p data[p] = newarray(double *,height+1)) == NULL ) { freeImageFloat(im); return NULL; } rows = im->data[p]; if ( (rows[0] = malloc(im->plane_bytes + height)) == NULL ) { freeImageFloat(im); return NULL; } for (y = 1; y <= height; y++) rows[y] = rows[y-1] + width; } return im; } image * copyImage(image *im) { image *new; int p; if ( (new = newImage(im->width,im->height,im->planes)) == NULL ) return NULL; for(p=0;p planes;p++) { memcpy(new->data[p][0],im->data[p][0],im->plane_bytes); } return new; } image * newImageFromFloat(imageFloat *im) { image *new; if ( (new = newImage(im->width,im->height,im->planes)) == NULL ) return NULL; return new; } imageFloat * newImageFloatFromFloat(imageFloat *im) { imageFloat *new; if ( (new = newImageFloat(im->width,im->height,im->planes)) == NULL ) return NULL; return new; } image * newImageFrom(image *im) { image *new; if ( (new = newImage(im->width,im->height,im->planes)) == NULL ) return NULL; return new; } imageFloat * newImageFloatFrom(image *im) { imageFloat *new; if ( (new = newImageFloat(im->width,im->height,im->planes)) == NULL ) return NULL; return new; } void freeImage(image *im) { if (im ) { if ( im->data ) { int p; for(p=0;p planes;p++) { if ( im->data[p] ) { if (im->data[p][0] ) free(im->data[p][0]); free(im->data[p]); } } free(im->data); } free(im); } } void freeImageFloat(imageFloat *im) { if (im ) { if ( im->data ) { int p; for(p=0;p planes;p++) { if ( im->data[p] ) { if (im->data[p][0] ) free(im->data[p][0]); free(im->data[p]); } } free(im->data); } free(im); } } void capBandByte(int *band,int width,int height,int fullw,int cap) { int x,y,v,minv,maxv; int *dp; int rowPad = fullw - width; double scale; minv = 999; maxv = -999; dp = band; for(y=height;y--;) { for(x=width;x--;) { v = *dp++; if ( v < minv ) minv = v; if ( v > maxv ) maxv = v; } dp += rowPad; } maxv = abs(maxv); if ( abs(minv) > abs(maxv) ) maxv = abs(minv); if ( maxv < cap ) return; scale = (double)cap/maxv; dp = band; for(y=height;y--;) { for(x=width;x--;) { *dp = (*dp)*scale; dp++; } dp += rowPad; } } void capImageBands(image *im,int levels,int cap) { int p,l,sizeX,sizeY; int **rows; for(p=0;p planes;p++) { rows = im->data[p]; for (l = levels; l > 0; l--) { sizeX = im->width >> l; sizeY = im->height >> l; if (l == levels) capBandByte(rows[0], sizeX, sizeY, im->width,cap); capBandByte(rows[0] + sizeX, sizeX, sizeY, im->width,cap); capBandByte(rows[sizeY], sizeX, sizeY, im->width,cap); capBandByte(rows[sizeY]+sizeX, sizeX, sizeY, im->width,cap); } } } void subtractImage(image *im,image *by) { int p,r; int *ptr,*bptr; for(p=0;p planes;p++) { ptr = im->data[p][0]; bptr =by->data[p][0]; for(r=im->plane_size;r--;) { *ptr++ -= *bptr++; } } } void addImage(image *im,image *by) { int p,r; int *ptr,*bptr; for(p=0;p planes;p++) { ptr = im->data[p][0]; bptr =by->data[p][0]; for(r=im->plane_size;r--;) { *ptr++ += *bptr++; } } } void zeroImage(image *im) { int p; for(p=0;p planes;p++) memclear(im->data[p][0],im->plane_bytes); } void patchImage(image *fm,image *to,int fmx,int fmy,int w,int h,int tox,int toy) { int x,y,p; int **fmrows,**torows; int *fmrow,*torow; for(p=0;p planes;p++) { fmrows = fm->data[p]; torows = to->data[p]; for(y=0;y planes;p++) { fptr = fm->data[p][0]; rptr = to->data[p][0]; for(r=to->plane_size;r--;) *rptr++ = *fptr++; } } void patchImageFloatFrom(image *fm,imageFloat *to) { int p,r; int *rptr; double *fptr; for(p=0;p planes;p++) { fptr = to->data[p][0]; rptr = fm->data[p][0]; for(r=to->plane_size;r--;) *fptr++ = *rptr++; } } void transposeLHs(image *im,int levels) { int p,x,y,l,w,h; int **rows,z; /*** * * This is a beautiful free compression win! * * <> the SPT and DWT do a transpose right before this * instead of two transposes, do zero * this should be absorbed into each transform in any case * ***/ assert( im->width == im->height ); for(p=0;p planes;p++) { for(l=1;l<=levels;l++) { w = (im->width) >> l; h = (im->height) >> l; rows = &(im->data[p][h]); for(y=0;y width != imf->width || im->height != imf->height ) return; for(p=0;p planes;p++) waveletTransform2D(im->data[p],imf->data[p],im->width,im->height,levels,inverse); } void cdf22ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) cdf22_2D(im->data[p],im->width,im->height,levels,inverse); } void cdf22Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); cdf22ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void f97ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) f97_2D(im->data[p],im->width,im->height,levels,inverse); } void f97Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); f97ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void b97ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) b97_2D(im->data[p],im->width,im->height,levels,inverse); } void b97Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); b97ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void l97ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) l97_2D(im->data[p],im->width,im->height,levels,inverse); } void l97Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); l97ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void cdf24ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) cdf24_2D(im->data[p],im->width,im->height,levels,inverse); } void cdf24Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); cdf24ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void bcw3ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) bcw3_2D(im->data[p],im->width,im->height,levels,inverse); } void bcw3Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); bcw3ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void d4ImageInt(image *im,int levels,bool inverse) { int p; for(p=0;p planes;p++) d4_2D(im->data[p],im->width,im->height,levels,inverse); } void d4Image(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); d4ImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void sptImageInt(image *im,int levels,bool inverse) { int p; /** special-case for the situation where quantizer == 1 instead of : spt -> float -> quantized ints we do : spt -> ints ***/ for(p=0;p planes;p++) sp_Transform2D(im->data[p],im->width,im->height,levels,inverse); } void sptImage(image *im,imageFloat *imF,int levels,bool inverse) { /** it's unnatural to copy the results of the spt into * a float buffer, but we do it for similarity to the * other transforms **/ if ( inverse ) patchImageFromFloat(imF,im); sptImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void dctImage(image *im,imageFloat * imf,bool inverse) { int p,x,y,i; int block[64],*bptr,*line; double blockf[64],*fptr,*fline; if ( inverse ) { idct_init(); /** imf -> im **/ for(p=0;p planes;p++) { for(y=0;y height;y+=8) { for(x=0;x width;x+=8) { fptr = blockf; for(i=0;i<8;i++) { fline = imf->data[p][y+i] + x; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; *fptr++ = *fline++; } idct(blockf,block); bptr = block; for(i=0;i<8;i++) { line = im->data[p][y+i] + x; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; *line++ = *bptr++; } } } } } else { dct_init(); /** im -> imf **/ for(p=0;p planes;p++) { for(y=0;y height;y+=8) { for(x=0;x width;x+=8) { bptr = block; for(i=0;i<8;i++) { line = im->data[p][y+i] + x; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; *bptr++ = *line++; } dct(block,blockf); fptr = blockf; for(i=0;i<8;i++) { fline = imf->data[p][y+i] + x; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; *fline++ = *fptr++; } } } } } } void haarImageInt(image *im,int levels,bool inverse) { int p; /** <> * by far the slowest part of the Haar transform is * the copy & shuffle. This could be eliminated entirely * if we adapted our coders to work on the tree-type data **/ if ( inverse ) { image * temp; temp = copyImage(im); deshuffleImage(im,temp,levels); freeImage(temp); } for(p=0;p planes;p++) { haar_Transform2D(im->data[p],im->width,im->height,levels,inverse); } if ( !inverse ) { image * temp; temp = copyImage(im); shuffleImage(temp,im,levels); freeImage(temp); } } void haarImage(image *im,imageFloat *imF,int levels,bool inverse) { if ( inverse ) patchImageFromFloat(imF,im); haarImageInt(im,levels,inverse); if (!inverse ) patchImageFloatFrom(im,imF); } void transformImage(image *raw,imageFloat *trans,int levels,bool inverse,int transformN) { switch(transformN) { case TRANS_SPT : sptImage(raw,trans,levels,inverse); break; case TRANS_HAAR : haarImage(raw,trans,levels,inverse); break; case TRANS_DWT : dwtImage(raw,trans,levels,inverse); break; case TRANS_DCT : assert( levels == 3 ); dctImage(raw,trans,inverse); break; case TRANS_CDF22 : cdf22Image(raw,trans,levels,inverse); break; case TRANS_CDF24 : cdf24Image(raw,trans,levels,inverse); break; case TRANS_BCW3 : bcw3Image(raw,trans,levels,inverse); break; case TRANS_D4 : d4Image(raw,trans,levels,inverse); break; case TRANS_F97 : f97Image(raw,trans,levels,inverse); break; case TRANS_B97 : b97Image(raw,trans,levels,inverse); break; case TRANS_L97 : l97Image(raw,trans,levels,inverse); break; default: errexit("tried to do invalid transform number"); break; } } void transformImageInt(image *im,int levels,bool inverse,int transformN) { switch(transformN) { case TRANS_SPT : sptImageInt(im,levels,inverse); break; case TRANS_HAAR : haarImageInt(im,levels,inverse); break; case TRANS_CDF22 : cdf22ImageInt(im,levels,inverse); break; case TRANS_CDF24: cdf24ImageInt(im,levels,inverse); break; case TRANS_BCW3: bcw3ImageInt(im,levels,inverse); break; case TRANS_D4: d4ImageInt(im,levels,inverse); break; case TRANS_F97: f97ImageInt(im,levels,inverse); break; case TRANS_B97: b97ImageInt(im,levels,inverse); break; case TRANS_L97: l97ImageInt(im,levels,inverse); break; default: errexit("tried to do invalid transformInt number"); break; } } void transQuad(int *band,int w,int h,int fullw,bool inverse,int transformN) { switch(transformN) { case TRANS_SPT : spQuad(band,w,h,fullw,inverse); break; case TRANS_CDF22 : cdfQuad(band,w,h,fullw,inverse); break; case TRANS_BCW3 : bcwQuad(band,w,h,fullw,inverse); break; case TRANS_D4 : d4Quad(band,w,h,fullw,inverse); break; case TRANS_F97 : f97Quad(band,w,h,fullw,inverse); break; case TRANS_B97 : b97Quad(band,w,h,fullw,inverse); break; case TRANS_L97 : l97Quad(band,w,h,fullw,inverse); break; default: errexit("tried to do invalid transQuad number"); break; } } /** * shuffle takes dct-style locally treed data * turns into subbands * this "shuffle" basically scales up each 8x8 block to * take up the full image, then bumps them so they * all lock together. * this is *not* quite the right shuffle to tree-structure dct. * we need to keep plaquettes within a dct-block together spatially * (use the -w option to see what I mean) **/ void shuffleImageBad(image *im,image *subb,int levels) { int p,x,y,tox,toy,a,b,xsize,ysize; int **fmr,**tor; xsize = im->width>>levels; ysize = im->height>>levels; for(p=0;p planes;p++) { fmr = im->data[p]; tor = subb->data[p]; for(y=0;y height;y++) { a = y>>levels; b = y - (a< width;x++) { a = x>>levels; b = x - (a< width>>levels; ysize = im->height>>levels; for(p=0;p planes;p++) { fmr = im->data[p]; tor = subb->data[p]; for(y=0;y height;y++) { a = y>>levels; b = y - (a< width;x++) { a = x>>levels; b = x - (a< width; h = im->height; block = 1< planes;p++) { dctr = im->data[p]; subr = subb->data[p]; for(by=0;by >levels][bx>>levels] = dctr[by][bx]; for(l=0;l< levels;l++) { sw = w>>(levels-l); sh = h>>(levels-l); //subband sizes offx = bx>>(levels-l); offy = by>>(levels-l); //offsets in the subband dsize = 1< width; h = im->height; block = 1< planes;p++) { dctr = im->data[p]; subr = subb->data[p]; for(by=0;by >levels][bx>>levels]; for(l=0;l >(levels-l); sh = h>>(levels-l); //subband sizes offx = bx>>(levels-l); offy = by>>(levels-l); //offsets in the subband dsize = 1< width; h = dctim->height; for(p=0;p planes;p++) { dctr = dctim->data[p]; subr = subb->data[p]; for(by=0;by >3][bx>>3] = dctr[by][bx]; for(l=0;l<=2;l++) { sw = w>>(3-l); sh = h>>(3-l); //subband sizes offx = bx>>(3-l); offy = by>>(3-l); //offsets in the subband dsize = 1< width; h = dctim->height; for(p=0;p planes;p++) { dctr = dctim->data[p]; subr = subb->data[p]; for(by=0;by >3][bx>>3]; for(l=0;l<=2;l++) { sw = w>>(3-l); sh = h>>(3-l); //subband sizes offx = bx>>(3-l); offy = by>>(3-l); //offsets in the subband dsize = 1< planes);pnum++) { int *rptr,*vptr; rptr = src->data[pnum][0]; vptr = comp->data[pnum][0]; for(i=(src->plane_size);i--;) { diff = *rptr++ - *vptr++; if ( diff < 0 ) diff = -diff; if ( diff > MAX_DIFF ) diff = MAX_DIFF; diffs[diff] ++; } } totsq = 0; for(i=1;i<=MAX_DIFF;i++) { if ( diffs[i] > 0 ) { totsq += i*i * diffs[i]; } } mse = (float)totsq/(src->tot_size); if ( mse < 0.0001 ) psnr = 999.0; else psnr = (PSNR_MAX - 10*log10(mse)); return psnr; } void imageCompare(image *src,image *comp,FILE *out) { long diffs[MAX_DIFF+1]; int diff,i,tot,totsq,max,pnum; float mse,me,rmse,psnr; if ( (src->tot_bytes != comp->tot_bytes) ) { fprintf(out,"Images are not of same size! cannot compare.\n"); return; } MemClearLongs(diffs,MAX_DIFF+1); for(pnum=0;pnum<(src->planes);pnum++) { int *rptr,*vptr; rptr = src->data[pnum][0]; vptr = comp->data[pnum][0]; for(i=(src->plane_size);i--;) { diff = *rptr++ - *vptr++; if ( diff < 0 ) diff = -diff; if ( diff > MAX_DIFF ) diff = MAX_DIFF; diffs[diff] ++; } } tot = totsq = max = 0; for(i=1;i<=MAX_DIFF;i++) { if ( diffs[i] > 0 ) { max = i; tot += i * diffs[i]; totsq += i*i * diffs[i]; } } if ( tot == 0 ) return; me = (float)tot/(src->tot_size); mse = (float)totsq/(src->tot_size); rmse = sqrt(mse); if ( mse < 0.0001 ) psnr = 999.0; else psnr = (PSNR_MAX - 10*log10(mse)); fprintf(out,"error: av= %.2f,max= %d,mse= %.3f,rmse= %.2f,psnr= %.2f\n",me,max,mse,rmse,psnr); } int imageAverage(image *im) { int p,r; int *dp; int tot=0; for(p=0;p planes;p++) { dp = im->data[p][0]; for(r=im->plane_size;r--;) { tot += *dp++; } } return ( tot / im->tot_size); } #define databyte_max 0xFF #define databyte_min 0 #define databyte_mid 0x80 // pointless? //#define databyte_mid 0 #define dataword_max 0xFFFF #define dataword_min 0 #define dataword_mid 0x8080 // pointless? bool readImageFileBytes(char *name,image *im,bool interleaved) { int p, r; FILE *inFile; if ((inFile = fopen(name, "rb")) == NULL) return false; if ( interleaved && im->planes > 1 ) { for(r=0;r<(im->plane_size);r++) { for(p=0;p<(im->planes);p++) { im->data[p][0][r] = (int)(fgetub(inFile) - databyte_mid); } } } else { int *plane; for(p=0;p<(im->planes);p++) { plane = im->data[p][0]; for(r=(im->plane_size);r--;) { *plane++ = (int)(fgetub(inFile) - databyte_mid); } } } fclose(inFile); return true; } bool writeImageFileBytes(char *name,image *im,bool interleaved) { int p, r, ch; int *plane; FILE *outFile; if ((outFile = fopen(name, "wb")) == NULL) return false; if ( interleaved && im->planes > 1 ) { for(r=0;r<(im->plane_size);r++) { for(p=0;p planes;p++) { ch = im->data[p][0][r] + databyte_mid; putminmax(ch,databyte_min,databyte_max); fputub(ch,outFile); } } } else { for(p=0;p planes;p++) { plane = im->data[p][0]; for(r=im->plane_size;r--;) { ch = *plane++ + databyte_mid; putminmax(ch,databyte_min,databyte_max); fputub(ch,outFile); } } } fclose(outFile); return true; } bool readImageFileWords(char *name,image *im,bool interleaved) { int p, r, ch; int *plane; FILE *inFile; if ((inFile = fopen(name, "rb")) == NULL) return false; if ( interleaved && im->planes > 1 ) { for(r=0;r<(im->plane_size);r++) { for(p=0;p<(im->planes);p++) { im->data[p][0][r] = (int)(fgetuw(inFile) - databyte_mid); } } } else { int *plane; for(p=0;p<(im->planes);p++) { plane = im->data[p][0]; for(r=(im->plane_size);r--;) { *plane++ = (int)(fgetuw(inFile) - databyte_mid); } } } fclose(inFile); return true; } bool writeImageFileWords(char *name,image *im,bool interleaved) { int p, r, ch; FILE *outFile; if ((outFile = fopen(name, "wb")) == NULL) return false; if ( interleaved && im->planes > 1 ) { for(r=0;r<(im->plane_size);r++) { for(p=0;p planes;p++) { ch = im->data[p][0][r] + databyte_mid; putminmax(ch,databyte_min,databyte_max); fputuw(ch,outFile); } } } else { int *plane; for(p=0;p planes;p++) { plane = im->data[p][0]; for(r=im->plane_size;r--;) { ch = *plane++ + databyte_mid; putminmax(ch,databyte_min,databyte_max); fputuw(ch,outFile); } } } fclose(outFile); return true; } void RGBtoYUV(image *im) { int i; int *p0,*p1,*p2; int A; if ( im->planes < 3 ) return; p0 = im->data[0][0]; p1 = im->data[1][0]; p2 = im->data[2][0]; for(i=im->plane_size;i--;) { RGB_to_YUV(*p0,*p1,*p2,p0,p1,p2); #ifdef AVE_DEL_YUV A = ((*p1 + *p2)>>1); *p2 -= *p1; *p1 = A; #endif p0++; p1++; p2++; } } void YUVtoRGB(image *im) { int i; int *p0,*p1,*p2; if ( im->planes < 3 ) return; p0 = im->data[0][0]; p1 = im->data[1][0]; p2 = im->data[2][0]; for(i=im->plane_size;i--;) { #ifdef AVE_DEL_YUV *p1 = *p1 - ((*p2 +1)>>1); *p2 += *p1; #endif YUV_to_RGB(*p0,*p1,*p2,p0,p1,p2); p0++; p1++; p2++; } }