blob: 0814e6b5e0efce55962a102caee8c4b3ea2c08fc [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% GGGG EEEEE M M %
7% G E MM MM %
8% G GG EEE M M M %
9% G G E M M %
10% GGGG EEEEE M M %
11% %
12% %
13% Graphic Gems - Graphic Support Methods %
14% %
15% Software Design %
16% John Cristy %
17% August 1996 %
18% %
19% %
20% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/color-private.h"
45#include "magick/draw.h"
46#include "magick/gem.h"
47#include "magick/image.h"
48#include "magick/image-private.h"
49#include "magick/log.h"
50#include "magick/memory_.h"
51#include "magick/pixel-private.h"
52#include "magick/quantum.h"
53#include "magick/random_.h"
54#include "magick/resize.h"
55#include "magick/transform.h"
56#include "magick/signature-private.h"
57
58/*
59%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60% %
61% %
62% %
63% C o n v e r t H S B T o R G B %
64% %
65% %
66% %
67%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68%
69% ConvertHSBToRGB() transforms a (hue, saturation, brightness) to a (red,
70% green, blue) triple.
71%
72% The format of the ConvertHSBToRGBImage method is:
73%
74% void ConvertHSBToRGB(const double hue,const double saturation,
75% const double brightness,Quantum *red,Quantum *green,Quantum *blue)
76%
77% A description of each parameter follows:
78%
79% o hue, saturation, brightness: A double value representing a
80% component of the HSB color space.
81%
82% o red, green, blue: A pointer to a pixel component of type Quantum.
83%
84*/
85MagickExport void ConvertHSBToRGB(const double hue,const double saturation,
86 const double brightness,Quantum *red,Quantum *green,Quantum *blue)
87{
88 MagickRealType
89 f,
90 h,
91 p,
92 q,
93 t;
94
95 /*
96 Convert HSB to RGB colorspace.
97 */
98 assert(red != (Quantum *) NULL);
99 assert(green != (Quantum *) NULL);
100 assert(blue != (Quantum *) NULL);
101 if (saturation == 0.0)
102 {
103 *red=RoundToQuantum((MagickRealType) QuantumRange*brightness);
104 *green=(*red);
105 *blue=(*red);
106 return;
107 }
108 h=6.0*(hue-floor(hue));
109 f=h-floor((double) h);
110 p=brightness*(1.0-saturation);
111 q=brightness*(1.0-saturation*f);
112 t=brightness*(1.0-(saturation*(1.0-f)));
113 switch ((int) h)
114 {
115 case 0:
116 default:
117 {
118 *red=RoundToQuantum((MagickRealType) QuantumRange*brightness);
119 *green=RoundToQuantum((MagickRealType) QuantumRange*t);
120 *blue=RoundToQuantum((MagickRealType) QuantumRange*p);
121 break;
122 }
123 case 1:
124 {
125 *red=RoundToQuantum((MagickRealType) QuantumRange*q);
126 *green=RoundToQuantum((MagickRealType) QuantumRange*brightness);
127 *blue=RoundToQuantum((MagickRealType) QuantumRange*p);
128 break;
129 }
130 case 2:
131 {
132 *red=RoundToQuantum((MagickRealType) QuantumRange*p);
133 *green=RoundToQuantum((MagickRealType) QuantumRange*brightness);
134 *blue=RoundToQuantum((MagickRealType) QuantumRange*t);
135 break;
136 }
137 case 3:
138 {
139 *red=RoundToQuantum((MagickRealType) QuantumRange*p);
140 *green=RoundToQuantum((MagickRealType) QuantumRange*q);
141 *blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
142 break;
143 }
144 case 4:
145 {
146 *red=RoundToQuantum((MagickRealType) QuantumRange*t);
147 *green=RoundToQuantum((MagickRealType) QuantumRange*p);
148 *blue=RoundToQuantum((MagickRealType) QuantumRange*brightness);
149 break;
150 }
151 case 5:
152 {
153 *red=RoundToQuantum((MagickRealType) QuantumRange*brightness);
154 *green=RoundToQuantum((MagickRealType) QuantumRange*p);
155 *blue=RoundToQuantum((MagickRealType) QuantumRange*q);
156 break;
157 }
158 }
159}
160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166% C o n v e r t H S L T o R G B %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% ConvertHSLToRGB() transforms a (hue, saturation, lightness) to a (red,
173% green, blue) triple.
174%
175% The format of the ConvertHSLToRGBImage method is:
176%
177% void ConvertHSLToRGB(const double hue,const double saturation,
178% const double lightness,Quantum *red,Quantum *green,Quantum *blue)
179%
180% A description of each parameter follows:
181%
182% o hue, saturation, lightness: A double value representing a
183% component of the HSL color space.
184%
185% o red, green, blue: A pointer to a pixel component of type Quantum.
186%
187*/
188
189static inline MagickRealType ConvertHueToRGB(MagickRealType m1,
190 MagickRealType m2,MagickRealType hue)
191{
192 if (hue < 0.0)
193 hue+=1.0;
194 if (hue > 1.0)
195 hue-=1.0;
196 if ((6.0*hue) < 1.0)
197 return(m1+6.0*(m2-m1)*hue);
198 if ((2.0*hue) < 1.0)
199 return(m2);
200 if ((3.0*hue) < 2.0)
201 return(m1+6.0*(m2-m1)*(2.0/3.0-hue));
202 return(m1);
203}
204
205MagickExport void ConvertHSLToRGB(const double hue,const double saturation,
206 const double lightness,Quantum *red,Quantum *green,Quantum *blue)
207{
208 MagickRealType
209 b,
210 g,
211 r,
212 m1,
213 m2;
214
215 /*
216 Convert HSL to RGB colorspace.
217 */
218 assert(red != (Quantum *) NULL);
219 assert(green != (Quantum *) NULL);
220 assert(blue != (Quantum *) NULL);
221 if (saturation == 0)
222 {
223 *red=RoundToQuantum((MagickRealType) QuantumRange*lightness);
224 *green=(*red);
225 *blue=(*red);
226 return;
227 }
228 if (lightness <= 0.5)
229 m2=lightness*(saturation+1.0);
230 else
231 m2=(lightness+saturation)-(lightness*saturation);
232 m1=2.0*lightness-m2;
233 r=ConvertHueToRGB(m1,m2,hue+1.0/3.0);
234 g=ConvertHueToRGB(m1,m2,hue);
235 b=ConvertHueToRGB(m1,m2,hue-1.0/3.0);
236 *red=RoundToQuantum((MagickRealType) QuantumRange*r);
237 *green=RoundToQuantum((MagickRealType) QuantumRange*g);
238 *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
239}
240
241/*
242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243% %
244% %
245% %
246% C o n v e r t H W B T o R G B %
247% %
248% %
249% %
250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251%
252% ConvertHWBToRGB() transforms a (hue, whiteness, blackness) to a (red, green,
253% blue) triple.
254%
255% The format of the ConvertHWBToRGBImage method is:
256%
257% void ConvertHWBToRGB(const double hue,const double whiteness,
258% const double blackness,Quantum *red,Quantum *green,Quantum *blue)
259%
260% A description of each parameter follows:
261%
262% o hue, whiteness, blackness: A double value representing a
263% component of the HWB color space.
264%
265% o red, green, blue: A pointer to a pixel component of type Quantum.
266%
267*/
268MagickExport void ConvertHWBToRGB(const double hue,const double whiteness,
269 const double blackness,Quantum *red,Quantum *green,Quantum *blue)
270{
271 MagickRealType
272 b,
273 f,
274 g,
275 n,
276 r,
277 v;
278
279 register long
280 i;
281
282 /*
283 Convert HWB to RGB colorspace.
284 */
285 assert(red != (Quantum *) NULL);
286 assert(green != (Quantum *) NULL);
287 assert(blue != (Quantum *) NULL);
288 v=1.0-blackness;
289 if (hue == 0.0)
290 {
291 *red=RoundToQuantum((MagickRealType) QuantumRange*v);
292 *green=RoundToQuantum((MagickRealType) QuantumRange*v);
293 *blue=RoundToQuantum((MagickRealType) QuantumRange*v);
294 return;
295 }
296 i=(long) floor(6.0*hue);
297 f=6.0*hue-i;
298 if ((i & 0x01) != 0)
299 f=1.0-f;
300 n=whiteness+f*(v-whiteness); /* linear interpolation */
301 switch (i)
302 {
303 default:
304 case 6:
305 case 0: r=v; g=n; b=whiteness; break;
306 case 1: r=n; g=v; b=whiteness; break;
307 case 2: r=whiteness; g=v; b=n; break;
308 case 3: r=whiteness; g=n; b=v; break;
309 case 4: r=n; g=whiteness; b=v; break;
310 case 5: r=v; g=whiteness; b=n; break;
311 }
312 *red=RoundToQuantum((MagickRealType) QuantumRange*r);
313 *green=RoundToQuantum((MagickRealType) QuantumRange*g);
314 *blue=RoundToQuantum((MagickRealType) QuantumRange*b);
315}
316
317/*
318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319% %
320% %
321% %
322% C o n v e r t R G B T o H S B %
323% %
324% %
325% %
326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327%
328% ConvertRGBToHSB() transforms a (red, green, blue) to a (hue, saturation,
329% brightness) triple.
330%
331% The format of the ConvertRGBToHSB method is:
332%
333% void ConvertRGBToHSB(const Quantum red,const Quantum green,
334% const Quantum blue,double *hue,double *saturation,double *brightness)
335%
336% A description of each parameter follows:
337%
338% o red, green, blue: A Quantum value representing the red, green, and
339% blue component of a pixel..
340%
341% o hue, saturation, brightness: A pointer to a double value representing a
342% component of the HSB color space.
343%
344*/
345MagickExport void ConvertRGBToHSB(const Quantum red,const Quantum green,
346 const Quantum blue,double *hue,double *saturation,double *brightness)
347{
348 MagickRealType
349 delta,
350 max,
351 min;
352
353 /*
354 Convert RGB to HSB colorspace.
355 */
356 assert(hue != (double *) NULL);
357 assert(saturation != (double *) NULL);
358 assert(brightness != (double *) NULL);
359 *hue=0.0;
360 *saturation=0.0;
361 *brightness=0.0;
362 min=(MagickRealType) (red < green ? red : green);
363 if ((MagickRealType) blue < min)
364 min=(MagickRealType) blue;
365 max=(MagickRealType) (red > green ? red : green);
366 if ((MagickRealType) blue > max)
367 max=(MagickRealType) blue;
368 if (max == 0.0)
369 return;
370 delta=max-min;
371 *saturation=(double) (delta/max);
372 *brightness=(double) (QuantumScale*max);
373 if (delta == 0.0)
374 return;
cristy18b17442009-10-25 18:36:48 +0000375 if ((MagickRealType) red == max)
376 *hue=(double) ((green-(MagickRealType) blue)/delta);
cristy3ed852e2009-09-05 21:47:34 +0000377 else
cristy18b17442009-10-25 18:36:48 +0000378 if ((MagickRealType) green == max)
379 *hue=(double) (2.0+(blue-(MagickRealType) red)/delta);
cristy3ed852e2009-09-05 21:47:34 +0000380 else
cristy18b17442009-10-25 18:36:48 +0000381 *hue=(double) (4.0+(red-(MagickRealType) green)/delta);
382 *hue/=6.0;
cristy3ed852e2009-09-05 21:47:34 +0000383 if (*hue < 0.0)
384 *hue+=1.0;
385}
386
387/*
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389% %
390% %
391% %
392% C o n v e r t R G B T o H S L %
393% %
394% %
395% %
396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397%
398% ConvertRGBToHSL() transforms a (red, green, blue) to a (hue, saturation,
399% lightness) triple.
400%
401% The format of the ConvertRGBToHSL method is:
402%
403% void ConvertRGBToHSL(const Quantum red,const Quantum green,
404% const Quantum blue,double *hue,double *saturation,double *lightness)
405%
406% A description of each parameter follows:
407%
408% o red, green, blue: A Quantum value representing the red, green, and
409% blue component of a pixel..
410%
411% o hue, saturation, lightness: A pointer to a double value representing a
412% component of the HSL color space.
413%
414*/
415
416static inline double MagickMax(const double x,const double y)
417{
418 if (x > y)
419 return(x);
420 return(y);
421}
422
423static inline double MagickMin(const double x,const double y)
424{
425 if (x < y)
426 return(x);
427 return(y);
428}
429
430MagickExport void ConvertRGBToHSL(const Quantum red,const Quantum green,
431 const Quantum blue,double *hue,double *saturation,double *lightness)
432{
433 MagickRealType
434 b,
435 delta,
436 g,
437 max,
438 min,
439 r;
440
441 /*
442 Convert RGB to HSL colorspace.
443 */
444 assert(hue != (double *) NULL);
445 assert(saturation != (double *) NULL);
446 assert(lightness != (double *) NULL);
447 r=QuantumScale*red;
448 g=QuantumScale*green;
449 b=QuantumScale*blue;
450 max=MagickMax(r,MagickMax(g,b));
451 min=MagickMin(r,MagickMin(g,b));
452 *lightness=(double) ((min+max)/2.0);
453 delta=max-min;
454 if (delta == 0.0)
455 {
456 *hue=0.0;
457 *saturation=0.0;
458 return;
459 }
460 if (*lightness < 0.5)
461 *saturation=(double) (delta/(min+max));
462 else
463 *saturation=(double) (delta/(2.0-max-min));
464 if (r == max)
465 *hue=((((max-b)/6.0)+(delta/2.0))-(((max-g)/6.0)+(delta/2.0)))/delta;
466 else
467 if (g == max)
468 *hue=(1.0/3.0)+((((max-r)/6.0)+(delta/2.0))-(((max-b)/6.0)+(delta/2.0)))/
469 delta;
470 else
471 if (b == max)
472 *hue=(2.0/3.0)+((((max-g)/6.0)+(delta/2.0))-(((max-r)/6.0)+
473 (delta/2.0)))/delta;
474 if (*hue < 0.0)
475 *hue+=1.0;
476 if (*hue > 1.0)
477 *hue-=1.0;
478}
479
480/*
481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482% %
483% %
484% %
485% C o n v e r t R G B T o H W B %
486% %
487% %
488% %
489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490%
491% ConvertRGBToHWB() transforms a (red, green, blue) to a (hue, whiteness,
492% blackness) triple.
493%
494% The format of the ConvertRGBToHWB method is:
495%
496% void ConvertRGBToHWB(const Quantum red,const Quantum green,
497% const Quantum blue,double *hue,double *whiteness,double *blackness)
498%
499% A description of each parameter follows:
500%
501% o red, green, blue: A Quantum value representing the red, green, and
502% blue component of a pixel.
503%
504% o hue, whiteness, blackness: A pointer to a double value representing a
505% component of the HWB color space.
506%
507*/
508MagickExport void ConvertRGBToHWB(const Quantum red,const Quantum green,
509 const Quantum blue,double *hue,double *whiteness,double *blackness)
510{
511 MagickRealType
512 f,
513 v,
514 w;
515
516 register long
517 i;
518
519 /*
520 Convert RGB to HWB colorspace.
521 */
522 assert(hue != (double *) NULL);
523 assert(whiteness != (double *) NULL);
524 assert(blackness != (double *) NULL);
525 w=(MagickRealType) MagickMin((double) red,MagickMin((double) green,(double)
526 blue));
527 v=(MagickRealType) MagickMax((double) red,MagickMax((double) green,(double)
528 blue));
529 *blackness=1.0-QuantumScale*v;
530 *whiteness=QuantumScale*w;
531 if (v == w)
532 {
533 *hue=0.0;
534 return;
535 }
536 f=((MagickRealType) red == w) ? green-(MagickRealType) blue :
537 (((MagickRealType) green == w) ? blue-(MagickRealType) red : red-
538 (MagickRealType) green);
539 i=((MagickRealType) red == w) ? 3 : (((MagickRealType) green == w) ? 5 : 1);
540 *hue=((double) i-f/(v-1.0*w))/6.0;
541}
542
543/*
544%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
545% %
546% %
547% %
548% E x p a n d A f f i n e %
549% %
550% %
551% %
552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553%
554% ExpandAffine() computes the affine's expansion factor, i.e. the square root
555% of the factor by which the affine transform affects area. In an affine
556% transform composed of scaling, rotation, shearing, and translation, returns
557% the amount of scaling.
558%
559% The format of the ExpandAffine method is:
560%
561% double ExpandAffine(const AffineMatrix *affine)
562%
563% A description of each parameter follows:
564%
565% o expansion: Method ExpandAffine returns the affine's expansion factor.
566%
567% o affine: A pointer the affine transform of type AffineMatrix.
568%
569*/
570MagickExport double ExpandAffine(const AffineMatrix *affine)
571{
572 assert(affine != (const AffineMatrix *) NULL);
573 return(sqrt(fabs(affine->sx*affine->sy-affine->rx*affine->ry)));
574}
575
576/*
577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578% %
579% %
580% %
581% 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 %
582% %
583% %
584% %
585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586%
cristy82b15832009-10-06 19:17:37 +0000587% GenerateDifferentialNoise() generates differentual noise.
cristy3ed852e2009-09-05 21:47:34 +0000588%
589% The format of the GenerateDifferentialNoise method is:
590%
591% double GenerateDifferentialNoise(RandomInfo *random_info,
592% const Quantum pixel,const NoiseType noise_type,
593% const MagickRealType attenuate)
594%
595% A description of each parameter follows:
596%
597% o random_info: the random info.
598%
599% o pixel: noise is relative to this pixel value.
600%
601% o noise_type: the type of noise.
602%
603% o attenuate: attenuate the noise.
604%
605*/
606MagickExport double GenerateDifferentialNoise(RandomInfo *random_info,
607 const Quantum pixel,const NoiseType noise_type,const MagickRealType attenuate)
608{
609#define NoiseEpsilon (attenuate*1.0e-5)
cristy20a777c2009-10-23 13:03:15 +0000610#define SigmaUniform (attenuate*4.0)
611#define SigmaGaussian (attenuate*4.0)
cristy3ed852e2009-09-05 21:47:34 +0000612#define SigmaImpulse (attenuate*0.10)
cristy20a777c2009-10-23 13:03:15 +0000613#define SigmaLaplacian (attenuate*10.0)
614#define SigmaMultiplicativeGaussian (attenuate*1.0)
cristy3ed852e2009-09-05 21:47:34 +0000615#define SigmaPoisson (attenuate*0.05)
cristy20a777c2009-10-23 13:03:15 +0000616#define TauGaussian (attenuate*20.0)
cristy3ed852e2009-09-05 21:47:34 +0000617
cristyadb41ca2009-10-22 15:02:28 +0000618 double
cristy3ed852e2009-09-05 21:47:34 +0000619 alpha,
620 beta,
621 noise,
622 sigma;
623
624 alpha=GetPseudoRandomValue(random_info);
cristy3ed852e2009-09-05 21:47:34 +0000625 switch (noise_type)
626 {
627 case UniformNoise:
628 default:
629 {
cristy20a777c2009-10-23 13:03:15 +0000630 noise=(double) pixel+ScaleCharToQuantum((unsigned char)
631 (SigmaUniform*(alpha)));
cristy3ed852e2009-09-05 21:47:34 +0000632 break;
633 }
634 case GaussianNoise:
635 {
cristyadb41ca2009-10-22 15:02:28 +0000636 double
cristy3ed852e2009-09-05 21:47:34 +0000637 tau;
638
cristyadb41ca2009-10-22 15:02:28 +0000639 if (alpha == 0.0)
640 alpha=1.0;
cristy3ed852e2009-09-05 21:47:34 +0000641 beta=GetPseudoRandomValue(random_info);
cristyadb41ca2009-10-22 15:02:28 +0000642 sigma=sqrt(-2.0*log(alpha))*cos(2.0*MagickPI*beta);
643 tau=sqrt(-2.0*log(alpha))*sin(2.0*MagickPI*beta);
cristy20a777c2009-10-23 13:03:15 +0000644 noise=(double) pixel+sqrt((double) pixel)*SigmaGaussian*sigma+
cristy3ed852e2009-09-05 21:47:34 +0000645 TauGaussian*tau;
646 break;
647 }
648 case MultiplicativeGaussianNoise:
649 {
650 if (alpha <= NoiseEpsilon)
cristyadb41ca2009-10-22 15:02:28 +0000651 sigma=(double) QuantumRange;
cristy3ed852e2009-09-05 21:47:34 +0000652 else
cristyadb41ca2009-10-22 15:02:28 +0000653 sigma=sqrt(-2.0*log(alpha));
cristy3ed852e2009-09-05 21:47:34 +0000654 beta=GetPseudoRandomValue(random_info);
cristyadb41ca2009-10-22 15:02:28 +0000655 noise=(double) pixel+pixel*SigmaMultiplicativeGaussian*sigma/2.0*
656 cos((2.0*MagickPI*beta));
cristy3ed852e2009-09-05 21:47:34 +0000657 break;
658 }
659 case ImpulseNoise:
660 {
661 if (alpha < (SigmaImpulse/2.0))
662 noise=0.0;
663 else
664 if (alpha >= (1.0-(SigmaImpulse/2.0)))
cristyadb41ca2009-10-22 15:02:28 +0000665 noise=(double) QuantumRange;
cristy3ed852e2009-09-05 21:47:34 +0000666 else
cristyadb41ca2009-10-22 15:02:28 +0000667 noise=(double) pixel;
cristy3ed852e2009-09-05 21:47:34 +0000668 break;
669 }
670 case LaplacianNoise:
671 {
672 if (alpha <= 0.5)
673 {
674 if (alpha <= NoiseEpsilon)
cristyadb41ca2009-10-22 15:02:28 +0000675 noise=(double) pixel-(double) QuantumRange;
cristy3ed852e2009-09-05 21:47:34 +0000676 else
cristyadb41ca2009-10-22 15:02:28 +0000677 noise=(double) pixel+ScaleCharToQuantum((unsigned char)
678 (SigmaLaplacian*log((2.0*alpha))+0.5));
cristy3ed852e2009-09-05 21:47:34 +0000679 break;
680 }
681 beta=1.0-alpha;
682 if (beta <= (0.5*NoiseEpsilon))
cristyadb41ca2009-10-22 15:02:28 +0000683 noise=(double) (pixel+QuantumRange);
cristy3ed852e2009-09-05 21:47:34 +0000684 else
cristyadb41ca2009-10-22 15:02:28 +0000685 noise=(double) pixel-ScaleCharToQuantum((unsigned char)
686 (SigmaLaplacian*log((2.0*beta))+0.5));
cristy3ed852e2009-09-05 21:47:34 +0000687 break;
688 }
689 case PoissonNoise:
690 {
cristyadb41ca2009-10-22 15:02:28 +0000691 double
cristy3ed852e2009-09-05 21:47:34 +0000692 poisson;
693
694 register long
695 i;
696
cristyadb41ca2009-10-22 15:02:28 +0000697 poisson=exp(-SigmaPoisson*ScaleQuantumToChar(pixel));
cristy3ed852e2009-09-05 21:47:34 +0000698 for (i=0; alpha > poisson; i++)
699 {
700 beta=GetPseudoRandomValue(random_info);
701 alpha*=beta;
702 }
cristyadb41ca2009-10-22 15:02:28 +0000703 noise=(double) ScaleCharToQuantum((unsigned char) (i/SigmaPoisson));
cristy3ed852e2009-09-05 21:47:34 +0000704 break;
705 }
706 case RandomNoise:
707 {
cristyadb41ca2009-10-22 15:02:28 +0000708 noise=(double) QuantumRange*GetPseudoRandomValue(random_info);
cristy3ed852e2009-09-05 21:47:34 +0000709 break;
710 }
711 }
712 return(noise);
713}
714
715/*
716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717% %
718% %
719% %
720% G e t O p t i m a l K e r n e l W i d t h %
721% %
722% %
723% %
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725%
726% GetOptimalKernelWidth() computes the optimal kernel radius for a convolution
727% filter. Start with the minimum value of 3 pixels and walk out until we drop
728% below the threshold of one pixel numerical accuracy.
729%
730% The format of the GetOptimalKernelWidth method is:
731%
732% unsigned long GetOptimalKernelWidth(const double radius,
733% const double sigma)
734%
735% A description of each parameter follows:
736%
737% o width: Method GetOptimalKernelWidth returns the optimal width of
738% a convolution kernel.
739%
740% o radius: the radius of the Gaussian, in pixels, not counting the center
741% pixel.
742%
743% o sigma: the standard deviation of the Gaussian, in pixels.
744%
745*/
746MagickExport unsigned long GetOptimalKernelWidth1D(const double radius,
747 const double sigma)
748{
749 long
750 width;
751
752 MagickRealType
753 normalize,
754 value;
755
756 register long
757 u;
758
759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
760 if (radius > 0.0)
761 return((unsigned long) (2.0*ceil(radius)+1.0));
762 if (fabs(sigma) <= MagickEpsilon)
cristy20908da2009-12-02 14:34:11 +0000763 return(1UL);
cristy3ed852e2009-09-05 21:47:34 +0000764 for (width=5; ; )
765 {
766 normalize=0.0;
767 for (u=(-width/2); u <= (width/2); u++)
768 normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma);
769 u=width/2;
770 value=exp(-((double) u*u)/(2.0*sigma*sigma))/(MagickSQ2PI*sigma)/normalize;
cristy20908da2009-12-02 14:34:11 +0000771 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +0000772 break;
773 width+=2;
774 }
775 return((unsigned long) (width-2));
776}
777
778MagickExport unsigned long GetOptimalKernelWidth2D(const double radius,
779 const double sigma)
780{
781
782 long
783 width;
784
785 MagickRealType
786 alpha,
787 normalize,
788 value;
789
790 register long
791 u,
792 v;
793
794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
795 if (radius > 0.0)
796 return((unsigned long) (2.0*ceil(radius)+1.0));
797 if (fabs(sigma) <= MagickEpsilon)
cristy20908da2009-12-02 14:34:11 +0000798 return(1UL);
cristy3ed852e2009-09-05 21:47:34 +0000799 for (width=5; ; )
800 {
801 normalize=0.0;
802 for (v=(-width/2); v <= (width/2); v++)
803 {
804 for (u=(-width/2); u <= (width/2); u++)
805 {
806 alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
807 normalize+=alpha/(2.0*MagickPI*sigma*sigma);
808 }
809 }
810 v=width/2;
811 value=exp(-((double) v*v)/(2.0*sigma*sigma))/normalize;
cristy20908da2009-12-02 14:34:11 +0000812 if ((value < QuantumScale) || (value < MagickEpsilon))
cristy3ed852e2009-09-05 21:47:34 +0000813 break;
814 width+=2;
815 }
816 return((unsigned long) (width-2));
817}
818
819MagickExport unsigned long GetOptimalKernelWidth(const double radius,
820 const double sigma)
821{
822 return(GetOptimalKernelWidth1D(radius,sigma));
823}