Blender V2.61 - r43446

imageprocess.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  * This file was moved here from the src/ directory. It is meant to
00027  * deal with endianness. It resided in a general blending lib. The
00028  * other functions were only used during rendering. This single
00029  * function remained. It should probably move to imbuf/intern/util.c,
00030  * but we'll keep it here for the time being. (nzc)*/
00031 
00037 /*  imageprocess.c        MIXED MODEL
00038  * 
00039  *  april 95
00040  * 
00041  */
00042 
00043 #include <stdlib.h>
00044 
00045 #include "IMB_imbuf_types.h"
00046 #include "IMB_imbuf.h"
00047 #include "math.h"
00048 
00049 /* This define should be relocated to a global header some where  Kent Mein 
00050 I stole it from util.h in the plugins api */
00051 #define MAX2(x,y)                ( (x)>(y) ? (x) : (y) )
00052 
00053 /* Only this one is used liberally here, and in imbuf */
00054 void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
00055 {
00056     int size;
00057     unsigned char rt, *cp = (unsigned char *)ibuf->rect;
00058     float rtf, *cpf = ibuf->rect_float;
00059 
00060     if (ibuf->rect) {
00061         size = ibuf->x * ibuf->y;
00062 
00063         while(size-- > 0) {
00064             rt= cp[0];
00065             cp[0]= cp[3];
00066             cp[3]= rt;
00067             rt= cp[1];
00068             cp[1]= cp[2];
00069             cp[2]= rt;
00070             cp+= 4;
00071         }
00072     }
00073 
00074     if (ibuf->rect_float) {
00075         size = ibuf->x * ibuf->y;
00076 
00077         while(size-- > 0) {
00078             rtf= cpf[0];
00079             cpf[0]= cpf[3];
00080             cpf[3]= rtf;
00081             rtf= cpf[1];
00082             cpf[1]= cpf[2];
00083             cpf[2]= rtf;
00084             cpf+= 4;
00085         }
00086     }
00087 }
00088 static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float **outF, int x, int y)
00089 
00090 {
00091     int offset = ibuf->x * y * 4 + 4*x;
00092     
00093     if (ibuf->rect)
00094         *outI= (unsigned char *)ibuf->rect + offset;
00095     
00096     if (ibuf->rect_float)
00097         *outF= (float *)ibuf->rect_float + offset;
00098 }
00099 
00100 /**************************************************************************
00101 *                            INTERPOLATIONS 
00102 *
00103 * Reference and docs:
00104 * http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms
00105 ***************************************************************************/
00106 
00107 /* BICUBIC Interpolation functions */
00108 /*  More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation
00109 */
00110 /* function assumes out to be zero'ed, only does RGBA */
00111 
00112 static float P(float k)
00113 {
00114     float p1, p2, p3, p4;
00115     p1 = MAX2(k+2.0f,0);
00116     p2 = MAX2(k+1.0f,0);
00117     p3 = MAX2(k,0);
00118     p4 = MAX2(k-1.0f,0);
00119     return (float)(1.0f/6.0f)*( p1*p1*p1 - 4.0f * p2*p2*p2 + 6.0f * p3*p3*p3 - 4.0f * p4*p4*p4);
00120 }
00121 
00122 
00123 #if 0
00124 /* older, slower function, works the same as above */
00125 static float P(float k)
00126 {
00127     return (float)(1.0f/6.0f)*( pow( MAX2(k+2.0f,0) , 3.0f ) - 4.0f * pow( MAX2(k+1.0f,0) , 3.0f ) + 6.0f * pow( MAX2(k,0) , 3.0f ) - 4.0f * pow( MAX2(k-1.0f,0) , 3.0f));
00128 }
00129 #endif
00130 
00131 void bicubic_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v)
00132 {
00133     int i,j,n,m,x1,y1;
00134     unsigned char *dataI;
00135     float a,b,w,wx,wy[4], outR,outG,outB,outA,*dataF;
00136 
00137     /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
00138 
00139     i= (int)floor(u);
00140     j= (int)floor(v);
00141     a= u - i;
00142     b= v - j;
00143 
00144     outR = outG = outB = outA = 0.0f;
00145     
00146 /* Optimized and not so easy to read */
00147     
00148     /* avoid calling multiple times */
00149     wy[0] = P(b-(-1));
00150     wy[1] = P(b-  0);
00151     wy[2] = P(b-  1);
00152     wy[3] = P(b-  2);
00153     
00154     for(n= -1; n<= 2; n++){
00155         x1= i+n;
00156         if (x1>0 && x1 < in->x) {
00157             wx = P(n-a);
00158             for(m= -1; m<= 2; m++){
00159                 y1= j+m;
00160                 if (y1>0 && y1<in->y) {
00161                     /* normally we could do this */
00162                     /* w = P(n-a) * P(b-m); */
00163                     /* except that would call P() 16 times per pixel therefor pow() 64 times, better precalc these */
00164                     w = wx * wy[m+1];
00165                     
00166                     if (outF) {
00167                         dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
00168                         outR+= dataF[0] * w;
00169                         outG+= dataF[1] * w;
00170                         outB+= dataF[2] * w;
00171                         outA+= dataF[3] * w;
00172                     }
00173                     if (outI) {
00174                         dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1;
00175                         outR+= dataI[0] * w;
00176                         outG+= dataI[1] * w;
00177                         outB+= dataI[2] * w;
00178                         outA+= dataI[3] * w;
00179                     }
00180                 }
00181             }
00182         }
00183     }
00184 
00185 /* Done with optimized part */
00186     
00187 #if 0 
00188     /* older, slower function, works the same as above */
00189     for(n= -1; n<= 2; n++){
00190         for(m= -1; m<= 2; m++){
00191             x1= i+n;
00192             y1= j+m;
00193             if (x1>0 && x1 < in->x && y1>0 && y1<in->y) {
00194                 if (do_float) {
00195                     dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
00196                     outR+= dataF[0] * P(n-a) * P(b-m);
00197                     outG+= dataF[1] * P(n-a) * P(b-m);
00198                     outB+= dataF[2] * P(n-a) * P(b-m);
00199                     outA+= dataF[3] * P(n-a) * P(b-m);
00200                 }
00201                 if (do_rect) {
00202                     dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1;
00203                     outR+= dataI[0] * P(n-a) * P(b-m);
00204                     outG+= dataI[1] * P(n-a) * P(b-m);
00205                     outB+= dataI[2] * P(n-a) * P(b-m);
00206                     outA+= dataI[3] * P(n-a) * P(b-m);
00207                 }
00208             }
00209         }
00210     }
00211 #endif
00212     
00213     if (outI) {
00214         outI[0]= (int)outR;
00215         outI[1]= (int)outG;
00216         outI[2]= (int)outB;
00217         outI[3]= (int)outA;
00218     }
00219     if (outF) {
00220         outF[0]= outR;
00221         outF[1]= outG;
00222         outF[2]= outB;
00223         outF[3]= outA;
00224     }
00225 }
00226 
00227 
00228 void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
00229 {
00230     
00231     unsigned char *outI = NULL;
00232     float *outF = NULL;
00233     
00234     if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return;
00235     
00236     pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
00237     
00238     bicubic_interpolation_color(in, outI, outF, u, v);
00239 }
00240 
00241 /* function assumes out to be zero'ed, only does RGBA */
00242 /* BILINEAR INTERPOLATION */
00243 void bilinear_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v)
00244 {
00245     float *row1, *row2, *row3, *row4, a, b;
00246     unsigned char *row1I, *row2I, *row3I, *row4I;
00247     float a_b, ma_b, a_mb, ma_mb;
00248     float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f};
00249     unsigned char emptyI[4]= {0, 0, 0, 0};
00250     int y1, y2, x1, x2;
00251     
00252     
00253     /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
00254 
00255     x1= (int)floor(u);
00256     x2= (int)ceil(u);
00257     y1= (int)floor(v);
00258     y2= (int)ceil(v);
00259 
00260     // sample area entirely outside image? 
00261     if (x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) return;
00262 
00263     if (outF) {
00264         // sample including outside of edges of image 
00265         if (x1<0 || y1<0) row1= empty;
00266         else row1= (float *)in->rect_float + in->x * y1 * 4 + 4*x1;
00267         
00268         if (x1<0 || y2>in->y-1) row2= empty;
00269         else row2= (float *)in->rect_float + in->x * y2 * 4 + 4*x1;
00270         
00271         if (x2>in->x-1 || y1<0) row3= empty;
00272         else row3= (float *)in->rect_float + in->x * y1 * 4 + 4*x2;
00273         
00274         if (x2>in->x-1 || y2>in->y-1) row4= empty;
00275         else row4= (float *)in->rect_float + in->x * y2 * 4 + 4*x2;
00276         
00277         a= u-floorf(u);
00278         b= v-floorf(v);
00279         a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
00280         
00281         outF[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0];
00282         outF[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1];
00283         outF[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2];
00284         outF[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3];
00285     }
00286     if (outI) {
00287         // sample including outside of edges of image 
00288         if (x1<0 || y1<0) row1I= emptyI;
00289         else row1I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1;
00290         
00291         if (x1<0 || y2>in->y-1) row2I= emptyI;
00292         else row2I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x1;
00293         
00294         if (x2>in->x-1 || y1<0) row3I= emptyI;
00295         else row3I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x2;
00296         
00297         if (x2>in->x-1 || y2>in->y-1) row4I= emptyI;
00298         else row4I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x2;
00299         
00300         a= u-floorf(u);
00301         b= v-floorf(v);
00302         a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
00303         
00304         /* need to add 0.5 to avoid rounding down (causes darken with the smear brush)
00305          * tested with white images and this should not wrap back to zero */
00306         outI[0]= (ma_mb*row1I[0] + a_mb*row3I[0] + ma_b*row2I[0]+ a_b*row4I[0]) + 0.5f;
00307         outI[1]= (ma_mb*row1I[1] + a_mb*row3I[1] + ma_b*row2I[1]+ a_b*row4I[1]) + 0.5f;
00308         outI[2]= (ma_mb*row1I[2] + a_mb*row3I[2] + ma_b*row2I[2]+ a_b*row4I[2]) + 0.5f;
00309         outI[3]= (ma_mb*row1I[3] + a_mb*row3I[3] + ma_b*row2I[3]+ a_b*row4I[3]) + 0.5f;
00310     }
00311 }
00312 
00313 /* function assumes out to be zero'ed, only does RGBA */
00314 /* BILINEAR INTERPOLATION */
00315 
00316 /* Note about wrapping, the u/v still needs to be within the image bounds,
00317  * just the interpolation is wrapped.
00318  * This the same as bilinear_interpolation_color except it wraps rather than using empty and emptyI */
00319 void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v)
00320 {
00321     float *row1, *row2, *row3, *row4, a, b;
00322     unsigned char *row1I, *row2I, *row3I, *row4I;
00323     float a_b, ma_b, a_mb, ma_mb;
00324     int y1, y2, x1, x2;
00325     
00326     
00327     /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
00328 
00329     x1= (int)floor(u);
00330     x2= (int)ceil(u);
00331     y1= (int)floor(v);
00332     y2= (int)ceil(v);
00333 
00334     // sample area entirely outside image? 
00335     if (x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) return;
00336     
00337     /* wrap interpolation pixels - main difference from bilinear_interpolation_color  */
00338     if(x1<0)x1= in->x+x1;
00339     if(y1<0)y1= in->y+y1;
00340     
00341     if(x2>=in->x)x2= x2-in->x;
00342     if(y2>=in->y)y2= y2-in->y;
00343 
00344     if (outF) {
00345         // sample including outside of edges of image 
00346         row1= (float *)in->rect_float + in->x * y1 * 4 + 4*x1;
00347         row2= (float *)in->rect_float + in->x * y2 * 4 + 4*x1;
00348         row3= (float *)in->rect_float + in->x * y1 * 4 + 4*x2;
00349         row4= (float *)in->rect_float + in->x * y2 * 4 + 4*x2;
00350         
00351         a= u-floorf(u);
00352         b= v-floorf(v);
00353         a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
00354         
00355         outF[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0];
00356         outF[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1];
00357         outF[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2];
00358         outF[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3];
00359     }
00360     if (outI) {
00361         // sample including outside of edges of image 
00362         row1I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1;
00363         row2I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x1;
00364         row3I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x2;
00365         row4I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x2;
00366         
00367         a= u-floorf(u);
00368         b= v-floorf(v);
00369         a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
00370         
00371         /* need to add 0.5 to avoid rounding down (causes darken with the smear brush)
00372          * tested with white images and this should not wrap back to zero */
00373         outI[0]= (ma_mb*row1I[0] + a_mb*row3I[0] + ma_b*row2I[0]+ a_b*row4I[0]) + 0.5f;
00374         outI[1]= (ma_mb*row1I[1] + a_mb*row3I[1] + ma_b*row2I[1]+ a_b*row4I[1]) + 0.5f;
00375         outI[2]= (ma_mb*row1I[2] + a_mb*row3I[2] + ma_b*row2I[2]+ a_b*row4I[2]) + 0.5f;
00376         outI[3]= (ma_mb*row1I[3] + a_mb*row3I[3] + ma_b*row2I[3]+ a_b*row4I[3]) + 0.5f;
00377     }
00378 }
00379 
00380 void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
00381 {
00382     
00383     unsigned char *outI = NULL;
00384     float *outF = NULL;
00385     
00386     if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return;
00387     
00388     pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
00389     
00390     bilinear_interpolation_color(in, outI, outF, u, v);
00391 }
00392 
00393 /* function assumes out to be zero'ed, only does RGBA */
00394 /* NEAREST INTERPOLATION */
00395 void neareast_interpolation_color(struct ImBuf *in, unsigned char *outI, float *outF, float u, float v)
00396 {
00397     float *dataF;
00398     unsigned char *dataI;
00399     int y1, x1;
00400 
00401     /* ImBuf in must have a valid rect or rect_float, assume this is already checked */
00402     
00403     x1= (int)(u);
00404     y1= (int)(v);
00405 
00406     // sample area entirely outside image? 
00407     if (x1<0 || x1>in->x-1 || y1<0 || y1>in->y-1) return;
00408     
00409     // sample including outside of edges of image 
00410     if (x1<0 || y1<0) {
00411         if (outI) {
00412             outI[0]= 0;
00413             outI[1]= 0;
00414             outI[2]= 0;
00415             outI[3]= 0;
00416         }
00417         if (outF) {
00418             outF[0]= 0.0f;
00419             outF[1]= 0.0f;
00420             outF[2]= 0.0f;
00421             outF[3]= 0.0f;
00422         }
00423     } else {
00424         dataI= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1;
00425         if (outI) {
00426             outI[0]= dataI[0];
00427             outI[1]= dataI[1];
00428             outI[2]= dataI[2];
00429             outI[3]= dataI[3];
00430         }
00431         dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
00432         if (outF) {
00433             outF[0]= dataF[0];
00434             outF[1]= dataF[1];
00435             outF[2]= dataF[2];
00436             outF[3]= dataF[3];
00437         }
00438     }   
00439 }
00440 
00441 void neareast_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout)
00442 {
00443     
00444     unsigned char *outI = NULL;
00445     float *outF = NULL;
00446 
00447     if (in == NULL || (in->rect == NULL && in->rect_float == NULL)) return;
00448     
00449     pixel_from_buffer(out, &outI, &outF, xout, yout); /* gcc warns these could be uninitialized, but its ok */
00450     
00451     neareast_interpolation_color(in, outI, outF, x, y);
00452 }