MagickCore  6.7.5
gem.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                              GGGG  EEEEE  M   M                             %
00007 %                             G      E      MM MM                             %
00008 %                             G GG   EEE    M M M                             %
00009 %                             G   G  E      M   M                             %
00010 %                              GGGG  EEEEE  M   M                             %
00011 %                                                                             %
00012 %                                                                             %
00013 %                    Graphic Gems - Graphic Support Methods                   %
00014 %                                                                             %
00015 %                               Software Design                               %
00016 %                                 John Cristy                                 %
00017 %                                 August 1996                                 %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/color-private.h"
00045 #include "MagickCore/draw.h"
00046 #include "MagickCore/gem.h"
00047 #include "MagickCore/gem-private.h"
00048 #include "MagickCore/image.h"
00049 #include "MagickCore/image-private.h"
00050 #include "MagickCore/log.h"
00051 #include "MagickCore/memory_.h"
00052 #include "MagickCore/pixel-accessor.h"
00053 #include "MagickCore/quantum.h"
00054 #include "MagickCore/quantum-private.h"
00055 #include "MagickCore/random_.h"
00056 #include "MagickCore/resize.h"
00057 #include "MagickCore/transform.h"
00058 #include "MagickCore/signature-private.h"
00059 
00060 /*
00061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00062 %                                                                             %
00063 %                                                                             %
00064 %                                                                             %
00065 %   C o n v e r t H S B T o R G B                                             %
00066 %                                                                             %
00067 %                                                                             %
00068 %                                                                             %
00069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00070 %
00071 %  ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
00072 %  green, blue) triple.
00073 %
00074 %  The format of the ConvertHSBToRGBImage method is:
00075 %
00076 %      void ConvertHSBToRGB(const double hue,const double saturation,
00077 %        const double brightness,double *red,double *green,double *blue)
00078 %
00079 %  A description of each parameter follows:
00080 %
00081 %    o hue, saturation, brightness: A double value representing a
00082 %      component of the HSB color space.
00083 %
00084 %    o red, green, blue: A pointer to a pixel component of type Quantum.
00085 %
00086 */
00087 MagickPrivate void ConvertHSBToRGB(const double hue,const double saturation,
00088   const double brightness,double *red,double *green,double *blue)
00089 {
00090   MagickRealType
00091     f,
00092     h,
00093     p,
00094     q,
00095     t;
00096 
00097   /*
00098     Convert HSB to RGB colorspace.
00099   */
00100   assert(red != (double *) NULL);
00101   assert(green != (double *) NULL);
00102   assert(blue != (double *) NULL);
00103   if (saturation == 0.0)
00104     {
00105       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00106       *green=(*red);
00107       *blue=(*red);
00108       return;
00109     }
00110   h=6.0*(hue-floor(hue));
00111   f=h-floor((double) h);
00112   p=brightness*(1.0-saturation);
00113   q=brightness*(1.0-saturation*f);
00114   t=brightness*(1.0-(saturation*(1.0-f)));
00115   switch ((int) h)
00116   {
00117     case 0:
00118     default:
00119     {
00120       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00121       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*t);
00122       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00123       break;
00124     }
00125     case 1:
00126     {
00127       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*q);
00128       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00129       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00130       break;
00131     }
00132     case 2:
00133     {
00134       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00135       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00136       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*t);
00137       break;
00138     }
00139     case 3:
00140     {
00141       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00142       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*q);
00143       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00144       break;
00145     }
00146     case 4:
00147     {
00148       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*t);
00149       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00150       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00151       break;
00152     }
00153     case 5:
00154     {
00155       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*brightness);
00156       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*p);
00157       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*q);
00158       break;
00159     }
00160   }
00161 }
00162 
00163 /*
00164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00165 %                                                                             %
00166 %                                                                             %
00167 %                                                                             %
00168 %   C o n v e r t H S L T o R G B                                             %
00169 %                                                                             %
00170 %                                                                             %
00171 %                                                                             %
00172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00173 %
00174 %  ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
00175 %  green, blue) triple.
00176 %
00177 %  The format of the ConvertHSLToRGBImage method is:
00178 %
00179 %      void ConvertHSLToRGB(const double hue,const double saturation,
00180 %        const double lightness,double *red,double *green,double *blue)
00181 %
00182 %  A description of each parameter follows:
00183 %
00184 %    o hue, saturation, lightness: A double value representing a
00185 %      component of the HSL color space.
00186 %
00187 %    o red, green, blue: A pointer to a pixel component of type Quantum.
00188 %
00189 */
00190 
00191 static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
00192   MagickRealType m2,MagickRealType hue)
00193 {
00194   if (hue < 0.0)
00195     hue+=1.0;
00196   if (hue > 1.0)
00197     hue-=1.0;
00198   if ((6.0*hue) < 1.0)
00199     return(m1+6.0*(m2-m1)*hue);
00200   if ((2.0*hue) < 1.0)
00201     return(m2);
00202   if ((3.0*hue) < 2.0)
00203     return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
00204   return(m1);
00205 }
00206 
00207 MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
00208   const double lightness,double *red,double *green,double *blue)
00209 {
00210   MagickRealType
00211     b,
00212     g,
00213     r,
00214     m1,
00215     m2;
00216 
00217   /*
00218     Convert HSL to RGB colorspace.
00219   */
00220   assert(red != (double *) NULL);
00221   assert(green != (double *) NULL);
00222   assert(blue != (double *) NULL);
00223   if (saturation == 0)
00224     {
00225       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*lightness);
00226       *green=(*red);
00227       *blue=(*red);
00228       return;
00229     }
00230   if (lightness < 0.5)
00231     m2=lightness*(saturation+1.0);
00232   else
00233     m2=(lightness+saturation)-(lightness*saturation);
00234   m1=2.0*lightness-m2;
00235   r=ConvertHueToRGB(m1,m2,hue+1.0/3.0);
00236   g=ConvertHueToRGB(m1,m2,hue);
00237   b=ConvertHueToRGB(m1,m2,hue-1.0/3.0);
00238   *red=(double) ClampToQuantum((MagickRealType) QuantumRange*r);
00239   *green=(double) ClampToQuantum((MagickRealType) QuantumRange*g);
00240   *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*b);
00241 }
00242 
00243 /*
00244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00245 %                                                                             %
00246 %                                                                             %
00247 %                                                                             %
00248 %   C o n v e r t H W B T o R G B                                             %
00249 %                                                                             %
00250 %                                                                             %
00251 %                                                                             %
00252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00253 %
00254 %  ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
00255 %  blue) triple.
00256 %
00257 %  The format of the ConvertHWBToRGBImage method is:
00258 %
00259 %      void ConvertHWBToRGB(const double hue,const double whiteness,
00260 %        const double blackness,double *red,double *green,double *blue)
00261 %
00262 %  A description of each parameter follows:
00263 %
00264 %    o hue, whiteness, blackness: A double value representing a
00265 %      component of the HWB color space.
00266 %
00267 %    o red, green, blue: A pointer to a pixel component of type Quantum.
00268 %
00269 */
00270 MagickPrivate void ConvertHWBToRGB(const double hue,const double whiteness,
00271   const double blackness,double *red,double *green,double *blue)
00272 {
00273   MagickRealType
00274     b,
00275     f,
00276     g,
00277     n,
00278     r,
00279     v;
00280 
00281   register ssize_t
00282     i;
00283 
00284   /*
00285     Convert HWB to RGB colorspace.
00286   */
00287   assert(red != (double *) NULL);
00288   assert(green != (double *) NULL);
00289   assert(blue != (double *) NULL);
00290   v=1.0-blackness;
00291   if (hue == 0.0)
00292     {
00293       *red=(double) ClampToQuantum((MagickRealType) QuantumRange*v);
00294       *green=(double) ClampToQuantum((MagickRealType) QuantumRange*v);
00295       *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*v);
00296       return;
00297     }
00298   i=(ssize_t) floor(6.0*hue);
00299   f=6.0*hue-i;
00300   if ((i & 0x01) != 0)
00301     f=1.0-f;
00302   n=whiteness+f*(v-whiteness);  /* linear interpolation */
00303   switch (i)
00304   {
00305     default:
00306     case 6:
00307     case 0: r=v; g=n; b=whiteness; break;
00308     case 1: r=n; g=v; b=whiteness; break;
00309     case 2: r=whiteness; g=v; b=n; break;
00310     case 3: r=whiteness; g=n; b=v; break;
00311     case 4: r=n; g=whiteness; b=v; break;
00312     case 5: r=v; g=whiteness; b=n; break;
00313   }
00314   *red=(double) ClampToQuantum((MagickRealType) QuantumRange*r);
00315   *green=(double) ClampToQuantum((MagickRealType) QuantumRange*g);
00316   *blue=(double) ClampToQuantum((MagickRealType) QuantumRange*b);
00317 }
00318 
00319 /*
00320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00321 %                                                                             %
00322 %                                                                             %
00323 %                                                                             %
00324 %   C o n v e r t R G B T o H S B                                             %
00325 %                                                                             %
00326 %                                                                             %
00327 %                                                                             %
00328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00329 %
00330 %  ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
00331 %  brightness) triple.
00332 %
00333 %  The format of the ConvertRGBToHSB method is:
00334 %
00335 %      void ConvertRGBToHSB(const double red,const double green,
00336 %        const double blue,double *hue,double *saturation,double *brightness)
00337 %
00338 %  A description of each parameter follows:
00339 %
00340 %    o red, green, blue: A Quantum value representing the red, green, and
00341 %      blue component of a pixel..
00342 %
00343 %    o hue, saturation, brightness: A pointer to a double value representing a
00344 %      component of the HSB color space.
00345 %
00346 */
00347 MagickPrivate void ConvertRGBToHSB(const double red,const double green,
00348   const double blue,double *hue,double *saturation,double *brightness)
00349 {
00350   MagickRealType
00351     delta,
00352     max,
00353     min;
00354 
00355   /*
00356     Convert RGB to HSB colorspace.
00357   */
00358   assert(hue != (double *) NULL);
00359   assert(saturation != (double *) NULL);
00360   assert(brightness != (double *) NULL);
00361   *hue=0.0;
00362   *saturation=0.0;
00363   *brightness=0.0;
00364   min=(MagickRealType) (red < green ? red : green);
00365   if ((MagickRealType) blue < min)
00366     min=(MagickRealType) blue;
00367   max=(MagickRealType) (red > green ? red : green);
00368   if ((MagickRealType) blue > max)
00369     max=(MagickRealType) blue;
00370   if (max == 0.0)
00371     return;
00372   delta=max-min;
00373   *saturation=(double) (delta/max);
00374   *brightness=(double) (QuantumScale*max);
00375   if (delta == 0.0)
00376     return;
00377   if ((MagickRealType) red == max)
00378     *hue=(double) ((green-(MagickRealType) blue)/delta);
00379   else
00380     if ((MagickRealType) green == max)
00381       *hue=(double) (2.0+(blue-(MagickRealType) red)/delta);
00382     else
00383       *hue=(double) (4.0+(red-(MagickRealType) green)/delta);
00384   *hue/=6.0;
00385   if (*hue < 0.0)
00386     *hue+=1.0;
00387 }
00388 
00389 /*
00390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00391 %                                                                             %
00392 %                                                                             %
00393 %                                                                             %
00394 %   C o n v e r t R G B T o H S L                                             %
00395 %                                                                             %
00396 %                                                                             %
00397 %                                                                             %
00398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00399 %
00400 %  ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
00401 %  lightness) triple.
00402 %
00403 %  The format of the ConvertRGBToHSL method is:
00404 %
00405 %      void ConvertRGBToHSL(const double red,const double green,
00406 %        const double blue,double *hue,double *saturation,double *lightness)
00407 %
00408 %  A description of each parameter follows:
00409 %
00410 %    o red, green, blue: A Quantum value representing the red, green, and
00411 %      blue component of a pixel..
00412 %
00413 %    o hue, saturation, lightness: A pointer to a double value representing a
00414 %      component of the HSL color space.
00415 %
00416 */
00417 
00418 static inline double MagickMax(const double x,const double y)
00419 {
00420   if (x > y)
00421     return(x);
00422   return(y);
00423 }
00424 
00425 static inline double MagickMin(const double x,const double y)
00426 {
00427   if (x < y)
00428     return(x);
00429   return(y);
00430 }
00431 
00432 MagickExport void ConvertRGBToHSL(const double red,const double green,
00433   const double blue,double *hue,double *saturation,double *lightness)
00434 {
00435   MagickRealType
00436     b,
00437     delta,
00438     g,
00439     max,
00440     min,
00441     r;
00442 
00443   /*
00444     Convert RGB to HSL colorspace.
00445   */
00446   assert(hue != (double *) NULL);
00447   assert(saturation != (double *) NULL);
00448   assert(lightness != (double *) NULL);
00449   r=QuantumScale*red;
00450   g=QuantumScale*green;
00451   b=QuantumScale*blue;
00452   max=MagickMax(r,MagickMax(g,b));
00453   min=MagickMin(r,MagickMin(g,b));
00454   *lightness=(double) ((min+max)/2.0);
00455   delta=max-min;
00456   if (delta == 0.0)
00457     {
00458       *hue=0.0;
00459       *saturation=0.0;
00460       return;
00461     }
00462   if (*lightness < 0.5)
00463     *saturation=(double) (delta/(min+max));
00464   else
00465     *saturation=(double) (delta/(2.0-max-min));
00466   if (r == max)
00467     *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta;
00468   else
00469     if (g == max)
00470       *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/
00471         delta;
00472     else
00473       if (b == max)
00474         *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+
00475           (delta/2.0)))/delta;
00476   if (*hue < 0.0)
00477     *hue+=1.0;
00478   if (*hue > 1.0)
00479     *hue-=1.0;
00480 }
00481 
00482 /*
00483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00484 %                                                                             %
00485 %                                                                             %
00486 %                                                                             %
00487 %   C o n v e r t R G B T o H W B                                             %
00488 %                                                                             %
00489 %                                                                             %
00490 %                                                                             %
00491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00492 %
00493 %  ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
00494 %  blackness) triple.
00495 %
00496 %  The format of the ConvertRGBToHWB method is:
00497 %
00498 %      void ConvertRGBToHWB(const double red,const double green,
00499 %        const double blue,double *hue,double *whiteness,double *blackness)
00500 %
00501 %  A description of each parameter follows:
00502 %
00503 %    o red, green, blue: A Quantum value representing the red, green, and
00504 %      blue component of a pixel.
00505 %
00506 %    o hue, whiteness, blackness: A pointer to a double value representing a
00507 %      component of the HWB color space.
00508 %
00509 */
00510 MagickPrivate void ConvertRGBToHWB(const double red,const double green,
00511   const double blue,double *hue,double *whiteness,double *blackness)
00512 {
00513   long
00514     i;
00515 
00516   MagickRealType
00517     f,
00518     v,
00519     w;
00520 
00521   /*
00522     Convert RGB to HWB colorspace.
00523   */
00524   assert(hue != (double *) NULL);
00525   assert(whiteness != (double *) NULL);
00526   assert(blackness != (double *) NULL);
00527   w=(MagickRealType) MagickMin((double) red,MagickMin((double) green,(double)
00528     blue));
00529   v=(MagickRealType) MagickMax((double) red,MagickMax((double) green,(double)
00530     blue));
00531   *blackness=1.0-QuantumScale*v;
00532   *whiteness=QuantumScale*w;
00533   if (v == w)
00534     {
00535       *hue=0.0;
00536       return;
00537     }
00538   f=((MagickRealType) red == w) ? green-(MagickRealType) blue :
00539     (((MagickRealType) green == w) ? blue-(MagickRealType) red : red-
00540     (MagickRealType) green);
00541   i=((MagickRealType) red == w) ? 3 : (((MagickRealType) green == w) ? 5 : 1);
00542   *hue=((double) i-f/(v-1.0*w))/6.0;
00543 }
00544 
00545 /*
00546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00547 %                                                                             %
00548 %                                                                             %
00549 %                                                                             %
00550 %   E x p a n d A f f i n e                                                   %
00551 %                                                                             %
00552 %                                                                             %
00553 %                                                                             %
00554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00555 %
00556 %  ExpandAffine() computes the affine's expansion factor, i.e. the square root
00557 %  of the factor by which the affine transform affects area. In an affine
00558 %  transform composed of scaling, rotation, shearing, and translation, returns
00559 %  the amount of scaling.
00560 %
00561 %  The format of the ExpandAffine method is:
00562 %
00563 %      double ExpandAffine(const AffineMatrix *affine)
00564 %
00565 %  A description of each parameter follows:
00566 %
00567 %    o expansion: Method ExpandAffine returns the affine's expansion factor.
00568 %
00569 %    o affine: A pointer the affine transform of type AffineMatrix.
00570 %
00571 */
00572 MagickExport double ExpandAffine(const AffineMatrix *affine)
00573 {
00574   assert(affine != (const AffineMatrix *) NULL);
00575   return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
00576 }
00577 
00578 /*
00579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00580 %                                                                             %
00581 %                                                                             %
00582 %                                                                             %
00583 %   G e n e r a t e D i f f e r e n t i a l N o i s e                         %
00584 %                                                                             %
00585 %                                                                             %
00586 %                                                                             %
00587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00588 %
00589 %  GenerateDifferentialNoise() generates differentual noise.
00590 %
00591 %  The format of the GenerateDifferentialNoise method is:
00592 %
00593 %      double GenerateDifferentialNoise(RandomInfo *random_info,
00594 %        const Quantum pixel,const NoiseType noise_type,const double attenuate)
00595 %
00596 %  A description of each parameter follows:
00597 %
00598 %    o random_info: the random info.
00599 %
00600 %    o pixel: noise is relative to this pixel value.
00601 %
00602 %    o noise_type: the type of noise.
00603 %
00604 %    o attenuate:  attenuate the noise.
00605 %
00606 */
00607 MagickPrivate double GenerateDifferentialNoise(RandomInfo *random_info,
00608   const Quantum pixel,const NoiseType noise_type,const double attenuate)
00609 {
00610 #define SigmaUniform  (attenuate*0.015625)
00611 #define SigmaGaussian  (attenuate*0.015625)
00612 #define SigmaImpulse  (attenuate*0.1)
00613 #define SigmaLaplacian (attenuate*0.0390625)
00614 #define SigmaMultiplicativeGaussian  (attenuate*0.5)
00615 #define SigmaPoisson  (attenuate*12.5)
00616 #define TauGaussian  (attenuate*0.078125)
00617 
00618   double
00619     alpha,
00620     beta,
00621     noise,
00622     sigma;
00623 
00624   alpha=GetPseudoRandomValue(random_info);
00625   switch (noise_type)
00626   {
00627     case UniformNoise:
00628     default:
00629     {
00630       noise=(double) (pixel+QuantumRange*SigmaUniform*(alpha-0.5));
00631       break;
00632     }
00633     case GaussianNoise:
00634     {
00635       double
00636         gamma,
00637         tau;
00638 
00639       if (alpha == 0.0)
00640         alpha=1.0;
00641       beta=GetPseudoRandomValue(random_info);
00642       gamma=sqrt(-2.0*log(alpha));
00643       sigma=gamma*cos((double) (2.0*MagickPI*beta));
00644       tau=gamma*sin((double) (2.0*MagickPI*beta));
00645       noise=(double) (pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
00646         QuantumRange*TauGaussian*tau);
00647       break;
00648     }
00649     case ImpulseNoise:
00650     {
00651       if (alpha < (SigmaImpulse/2.0))
00652         noise=0.0;
00653       else
00654         if (alpha >= (1.0-(SigmaImpulse/2.0)))
00655           noise=(double) QuantumRange;
00656         else
00657           noise=(double) pixel;
00658       break;
00659     }
00660     case LaplacianNoise:
00661     {
00662       if (alpha <= 0.5)
00663         {
00664           if (alpha <= MagickEpsilon)
00665             noise=(double) (pixel-QuantumRange);
00666           else
00667             noise=(double) (pixel+QuantumRange*SigmaLaplacian*
00668               log(2.0*alpha)+0.5);
00669           break;
00670         }
00671       beta=1.0-alpha;
00672       if (beta <= (0.5*MagickEpsilon))
00673         noise=(double) (pixel+QuantumRange);
00674       else
00675         noise=(double) (pixel-QuantumRange*SigmaLaplacian*log(2.0*beta)+0.5);
00676       break;
00677     }
00678     case MultiplicativeGaussianNoise:
00679     {
00680       sigma=1.0;
00681       if (alpha > MagickEpsilon)
00682         sigma=sqrt(-2.0*log(alpha));
00683       beta=GetPseudoRandomValue(random_info);
00684       noise=(double) (pixel+pixel*SigmaMultiplicativeGaussian*sigma*
00685         cos((double) (2.0*MagickPI*beta))/2.0);
00686       break;
00687     }
00688     case PoissonNoise:
00689     {
00690       double
00691         poisson;
00692 
00693       register ssize_t
00694         i;
00695 
00696       poisson=exp(-SigmaPoisson*QuantumScale*pixel);
00697       for (i=0; alpha > poisson; i++)
00698       {
00699         beta=GetPseudoRandomValue(random_info);
00700         alpha*=beta;
00701       }
00702       noise=(double) (QuantumRange*i/SigmaPoisson);
00703       break;
00704     }
00705     case RandomNoise:
00706     {
00707       noise=(double) (QuantumRange*alpha);
00708       break;
00709     }
00710   }
00711   return(noise);
00712 }
00713 
00714 /*
00715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00716 %                                                                             %
00717 %                                                                             %
00718 %                                                                             %
00719 %   G e t O p t i m a l K e r n e l W i d t h                                 %
00720 %                                                                             %
00721 %                                                                             %
00722 %                                                                             %
00723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00724 %
00725 %  GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
00726 %  filter.  Start with the minimum value of 3 pixels and walk out until we drop
00727 %  below the threshold of one pixel numerical accuracy.
00728 %
00729 %  The format of the GetOptimalKernelWidth method is:
00730 %
00731 %      size_t GetOptimalKernelWidth(const double radius,
00732 %        const double sigma)
00733 %
00734 %  A description of each parameter follows:
00735 %
00736 %    o width: Method GetOptimalKernelWidth returns the optimal width of
00737 %      a convolution kernel.
00738 %
00739 %    o radius: the radius of the Gaussian, in pixels, not counting the center
00740 %      pixel.
00741 %
00742 %    o sigma: the standard deviation of the Gaussian, in pixels.
00743 %
00744 */
00745 MagickPrivate size_t GetOptimalKernelWidth1D(const double radius,
00746   const double sigma)
00747 {
00748   double
00749     alpha,
00750     beta,
00751     gamma,
00752     normalize,
00753     value;
00754 
00755   register ssize_t
00756     i;
00757 
00758   size_t
00759     width;
00760 
00761   ssize_t
00762     j;
00763 
00764   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00765   if (radius > MagickEpsilon)
00766     return((size_t) (2.0*ceil(radius)+1.0));
00767   gamma=fabs(sigma);
00768   if (gamma <= MagickEpsilon)
00769     return(3UL);
00770   alpha=1.0/(2.0*gamma*gamma);
00771   beta=(double) (1.0/(MagickSQ2PI*gamma));
00772   for (width=5; ; )
00773   {
00774     normalize=0.0;
00775     j=(ssize_t) width/2;
00776     for (i=(-j); i <= j; i++)
00777       normalize+=exp(-((double) (i*i))*alpha)*beta;
00778     value=exp(-((double) (j*j))*alpha)*beta/normalize;
00779     if ((value < QuantumScale) || (value < MagickEpsilon))
00780       break;
00781     width+=2;
00782   }
00783   return((size_t) (width-2));
00784 }
00785 
00786 MagickPrivate size_t GetOptimalKernelWidth2D(const double radius,
00787   const double sigma)
00788 {
00789   double
00790     alpha,
00791     beta,
00792     gamma,
00793     normalize,
00794     value;
00795 
00796   size_t
00797     width;
00798 
00799   ssize_t
00800     j,
00801     u,
00802     v;
00803 
00804   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00805   if (radius > MagickEpsilon)
00806     return((size_t) (2.0*ceil(radius)+1.0));
00807   gamma=fabs(sigma);
00808   if (gamma <= MagickEpsilon)
00809     return(3UL);
00810   alpha=1.0/(2.0*gamma*gamma);
00811   beta=(double) (1.0/(Magick2PI*gamma*gamma));
00812   for (width=5; ; )
00813   {
00814     normalize=0.0;
00815     j=(ssize_t) width/2;
00816     for (v=(-j); v <= j; v++)
00817       for (u=(-j); u <= j; u++)
00818         normalize+=exp(-((double) (u*u+v*v))*alpha)*beta;
00819     value=exp(-((double) (j*j))*alpha)*beta/normalize;
00820     if ((value < QuantumScale) || (value < MagickEpsilon))
00821       break;
00822     width+=2;
00823   }
00824   return((size_t) (width-2));
00825 }
00826 
00827 MagickPrivate size_t  GetOptimalKernelWidth(const double radius,
00828   const double sigma)
00829 {
00830   return(GetOptimalKernelWidth1D(radius,sigma));
00831 }