MagickCore  7.1.0
effect.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % EEEEE FFFFF FFFFF EEEEE CCCC TTTTT %
7 % E F F E C T %
8 % EEE FFF FFF EEE C T %
9 % E F F E C T %
10 % EEEEE F F EEEEE CCCC T %
11 % %
12 % %
13 % MagickCore Image Effects Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % October 1996 %
18 % %
19 % %
20 % Copyright 1999-2021 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 % https://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 "MagickCore/studio.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/constitute.h"
51 #include "MagickCore/decorate.h"
52 #include "MagickCore/distort.h"
53 #include "MagickCore/draw.h"
54 #include "MagickCore/enhance.h"
55 #include "MagickCore/exception.h"
57 #include "MagickCore/effect.h"
58 #include "MagickCore/fx.h"
59 #include "MagickCore/gem.h"
60 #include "MagickCore/gem-private.h"
61 #include "MagickCore/geometry.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/matrix.h"
66 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
70 #include "MagickCore/montage.h"
71 #include "MagickCore/morphology.h"
73 #include "MagickCore/paint.h"
76 #include "MagickCore/property.h"
77 #include "MagickCore/quantize.h"
78 #include "MagickCore/quantum.h"
80 #include "MagickCore/random_.h"
82 #include "MagickCore/resample.h"
84 #include "MagickCore/resize.h"
85 #include "MagickCore/resource_.h"
86 #include "MagickCore/segment.h"
87 #include "MagickCore/shear.h"
89 #include "MagickCore/statistic.h"
90 #include "MagickCore/string_.h"
92 #include "MagickCore/transform.h"
93 #include "MagickCore/threshold.h"
94 
95 /*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 % %
98 % %
99 % %
100 % A d a p t i v e B l u r I m a g e %
101 % %
102 % %
103 % %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 % AdaptiveBlurImage() adaptively blurs the image by blurring less
107 % intensely near image edges and more intensely far from edges. We blur the
108 % image with a Gaussian operator of the given radius and standard deviation
109 % (sigma). For reasonable results, radius should be larger than sigma. Use a
110 % radius of 0 and AdaptiveBlurImage() selects a suitable radius for you.
111 %
112 % The format of the AdaptiveBlurImage method is:
113 %
114 % Image *AdaptiveBlurImage(const Image *image,const double radius,
115 % const double sigma,ExceptionInfo *exception)
116 %
117 % A description of each parameter follows:
118 %
119 % o image: the image.
120 %
121 % o radius: the radius of the Gaussian, in pixels, not counting the center
122 % pixel.
123 %
124 % o sigma: the standard deviation of the Laplacian, in pixels.
125 %
126 % o exception: return any errors or warnings in this structure.
127 %
128 */
129 MagickExport Image *AdaptiveBlurImage(const Image *image,const double radius,
130  const double sigma,ExceptionInfo *exception)
131 {
132 #define AdaptiveBlurImageTag "Convolve/Image"
133 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
134 
135  CacheView
136  *blur_view,
137  *edge_view,
138  *image_view;
139 
140  double
141  normalize,
142  **kernel;
143 
144  Image
145  *blur_image,
146  *edge_image,
147  *gaussian_image;
148 
150  status;
151 
153  progress;
154 
155  ssize_t
156  i;
157 
158  size_t
159  width;
160 
161  ssize_t
162  j,
163  k,
164  u,
165  v,
166  y;
167 
168  assert(image != (const Image *) NULL);
169  assert(image->signature == MagickCoreSignature);
170  if (image->debug != MagickFalse)
171  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
172  assert(exception != (ExceptionInfo *) NULL);
173  assert(exception->signature == MagickCoreSignature);
174  blur_image=CloneImage(image,0,0,MagickTrue,exception);
175  if (blur_image == (Image *) NULL)
176  return((Image *) NULL);
177  if (fabs(sigma) < MagickEpsilon)
178  return(blur_image);
179  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
180  {
181  blur_image=DestroyImage(blur_image);
182  return((Image *) NULL);
183  }
184  /*
185  Edge detect the image brightness channel, level, blur, and level again.
186  */
187  edge_image=EdgeImage(image,radius,exception);
188  if (edge_image == (Image *) NULL)
189  {
190  blur_image=DestroyImage(blur_image);
191  return((Image *) NULL);
192  }
193  (void) AutoLevelImage(edge_image,exception);
194  gaussian_image=BlurImage(edge_image,radius,sigma,exception);
195  if (gaussian_image != (Image *) NULL)
196  {
197  edge_image=DestroyImage(edge_image);
198  edge_image=gaussian_image;
199  }
200  (void) AutoLevelImage(edge_image,exception);
201  /*
202  Create a set of kernels from maximum (radius,sigma) to minimum.
203  */
204  width=GetOptimalKernelWidth2D(radius,sigma);
205  kernel=(double **) MagickAssumeAligned(AcquireAlignedMemory((size_t) width,
206  sizeof(*kernel)));
207  if (kernel == (double **) NULL)
208  {
209  edge_image=DestroyImage(edge_image);
210  blur_image=DestroyImage(blur_image);
211  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
212  }
213  (void) memset(kernel,0,(size_t) width*sizeof(*kernel));
214  for (i=0; i < (ssize_t) width; i+=2)
215  {
216  kernel[i]=(double *) MagickAssumeAligned(AcquireAlignedMemory(
217  (size_t) (width-i),(width-i)*sizeof(**kernel)));
218  if (kernel[i] == (double *) NULL)
219  break;
220  normalize=0.0;
221  j=(ssize_t) (width-i-1)/2;
222  k=0;
223  for (v=(-j); v <= j; v++)
224  {
225  for (u=(-j); u <= j; u++)
226  {
227  kernel[i][k]=(double) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
229  normalize+=kernel[i][k];
230  k++;
231  }
232  }
233  kernel[i][(k-1)/2]+=(double) (1.0-normalize);
234  if (sigma < MagickEpsilon)
235  kernel[i][(k-1)/2]=1.0;
236  }
237  if (i < (ssize_t) width)
238  {
239  for (i-=2; i >= 0; i-=2)
240  kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
241  kernel=(double **) RelinquishAlignedMemory(kernel);
242  edge_image=DestroyImage(edge_image);
243  blur_image=DestroyImage(blur_image);
244  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
245  }
246  /*
247  Adaptively blur image.
248  */
249  status=MagickTrue;
250  progress=0;
251  image_view=AcquireVirtualCacheView(image,exception);
252  edge_view=AcquireVirtualCacheView(edge_image,exception);
253  blur_view=AcquireAuthenticCacheView(blur_image,exception);
254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
255  #pragma omp parallel for schedule(static) shared(progress,status) \
256  magick_number_threads(image,blur_image,blur_image->rows,1)
257 #endif
258  for (y=0; y < (ssize_t) blur_image->rows; y++)
259  {
260  const Quantum
261  *magick_restrict r;
262 
263  Quantum
264  *magick_restrict q;
265 
266  ssize_t
267  x;
268 
269  if (status == MagickFalse)
270  continue;
271  r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
272  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
273  exception);
274  if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
275  {
276  status=MagickFalse;
277  continue;
278  }
279  for (x=0; x < (ssize_t) blur_image->columns; x++)
280  {
281  const Quantum
282  *magick_restrict p;
283 
284  ssize_t
285  i;
286 
287  ssize_t
288  center,
289  j;
290 
291  j=CastDoubleToLong(ceil((double) width*(1.0-QuantumScale*
292  GetPixelIntensity(edge_image,r))-0.5));
293  if (j < 0)
294  j=0;
295  else
296  if (j > (ssize_t) width)
297  j=(ssize_t) width;
298  if ((j & 0x01) != 0)
299  j--;
300  p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
301  (ssize_t) ((width-j)/2L),width-j,width-j,exception);
302  if (p == (const Quantum *) NULL)
303  break;
304  center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
305  GetPixelChannels(image)*((width-j)/2);
306  for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
307  {
308  double
309  alpha,
310  gamma,
311  pixel;
312 
314  channel;
315 
316  PixelTrait
317  blur_traits,
318  traits;
319 
320  const double
321  *magick_restrict k;
322 
323  const Quantum
324  *magick_restrict pixels;
325 
326  ssize_t
327  u;
328 
329  ssize_t
330  v;
331 
332  channel=GetPixelChannelChannel(image,i);
333  traits=GetPixelChannelTraits(image,channel);
334  blur_traits=GetPixelChannelTraits(blur_image,channel);
335  if ((traits == UndefinedPixelTrait) ||
336  (blur_traits == UndefinedPixelTrait))
337  continue;
338  if ((blur_traits & CopyPixelTrait) != 0)
339  {
340  SetPixelChannel(blur_image,channel,p[center+i],q);
341  continue;
342  }
343  k=kernel[j];
344  pixels=p;
345  pixel=0.0;
346  gamma=0.0;
347  if ((blur_traits & BlendPixelTrait) == 0)
348  {
349  /*
350  No alpha blending.
351  */
352  for (v=0; v < (ssize_t) (width-j); v++)
353  {
354  for (u=0; u < (ssize_t) (width-j); u++)
355  {
356  pixel+=(*k)*pixels[i];
357  gamma+=(*k);
358  k++;
359  pixels+=GetPixelChannels(image);
360  }
361  }
362  gamma=PerceptibleReciprocal(gamma);
363  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
364  continue;
365  }
366  /*
367  Alpha blending.
368  */
369  for (v=0; v < (ssize_t) (width-j); v++)
370  {
371  for (u=0; u < (ssize_t) (width-j); u++)
372  {
373  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
374  pixel+=(*k)*alpha*pixels[i];
375  gamma+=(*k)*alpha;
376  k++;
377  pixels+=GetPixelChannels(image);
378  }
379  }
380  gamma=PerceptibleReciprocal(gamma);
381  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
382  }
383  q+=GetPixelChannels(blur_image);
384  r+=GetPixelChannels(edge_image);
385  }
386  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
387  status=MagickFalse;
388  if (image->progress_monitor != (MagickProgressMonitor) NULL)
389  {
391  proceed;
392 
393 #if defined(MAGICKCORE_OPENMP_SUPPORT)
394  #pragma omp atomic
395 #endif
396  progress++;
397  proceed=SetImageProgress(image,AdaptiveBlurImageTag,progress,
398  image->rows);
399  if (proceed == MagickFalse)
400  status=MagickFalse;
401  }
402  }
403  blur_image->type=image->type;
404  blur_view=DestroyCacheView(blur_view);
405  edge_view=DestroyCacheView(edge_view);
406  image_view=DestroyCacheView(image_view);
407  edge_image=DestroyImage(edge_image);
408  for (i=0; i < (ssize_t) width; i+=2)
409  kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
410  kernel=(double **) RelinquishAlignedMemory(kernel);
411  if (status == MagickFalse)
412  blur_image=DestroyImage(blur_image);
413  return(blur_image);
414 }
415 
416 /*
417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 % %
419 % %
420 % %
421 % A d a p t i v e S h a r p e n I m a g e %
422 % %
423 % %
424 % %
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 %
427 % AdaptiveSharpenImage() adaptively sharpens the image by sharpening more
428 % intensely near image edges and less intensely far from edges. We sharpen the
429 % image with a Gaussian operator of the given radius and standard deviation
430 % (sigma). For reasonable results, radius should be larger than sigma. Use a
431 % radius of 0 and AdaptiveSharpenImage() selects a suitable radius for you.
432 %
433 % The format of the AdaptiveSharpenImage method is:
434 %
435 % Image *AdaptiveSharpenImage(const Image *image,const double radius,
436 % const double sigma,ExceptionInfo *exception)
437 %
438 % A description of each parameter follows:
439 %
440 % o image: the image.
441 %
442 % o radius: the radius of the Gaussian, in pixels, not counting the center
443 % pixel.
444 %
445 % o sigma: the standard deviation of the Laplacian, in pixels.
446 %
447 % o exception: return any errors or warnings in this structure.
448 %
449 */
450 MagickExport Image *AdaptiveSharpenImage(const Image *image,const double radius,
451  const double sigma,ExceptionInfo *exception)
452 {
453 #define AdaptiveSharpenImageTag "Convolve/Image"
454 #define MagickSigma (fabs(sigma) < MagickEpsilon ? MagickEpsilon : sigma)
455 
456  CacheView
457  *sharp_view,
458  *edge_view,
459  *image_view;
460 
461  double
462  normalize,
463  **kernel;
464 
465  Image
466  *sharp_image,
467  *edge_image,
468  *gaussian_image;
469 
471  status;
472 
474  progress;
475 
476  ssize_t
477  i;
478 
479  size_t
480  width;
481 
482  ssize_t
483  j,
484  k,
485  u,
486  v,
487  y;
488 
489  assert(image != (const Image *) NULL);
490  assert(image->signature == MagickCoreSignature);
491  if (image->debug != MagickFalse)
492  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
493  assert(exception != (ExceptionInfo *) NULL);
494  assert(exception->signature == MagickCoreSignature);
495  sharp_image=CloneImage(image,0,0,MagickTrue,exception);
496  if (sharp_image == (Image *) NULL)
497  return((Image *) NULL);
498  if (fabs(sigma) < MagickEpsilon)
499  return(sharp_image);
500  if (SetImageStorageClass(sharp_image,DirectClass,exception) == MagickFalse)
501  {
502  sharp_image=DestroyImage(sharp_image);
503  return((Image *) NULL);
504  }
505  /*
506  Edge detect the image brightness channel, level, sharp, and level again.
507  */
508  edge_image=EdgeImage(image,radius,exception);
509  if (edge_image == (Image *) NULL)
510  {
511  sharp_image=DestroyImage(sharp_image);
512  return((Image *) NULL);
513  }
514  (void) AutoLevelImage(edge_image,exception);
515  gaussian_image=BlurImage(edge_image,radius,sigma,exception);
516  if (gaussian_image != (Image *) NULL)
517  {
518  edge_image=DestroyImage(edge_image);
519  edge_image=gaussian_image;
520  }
521  (void) AutoLevelImage(edge_image,exception);
522  /*
523  Create a set of kernels from maximum (radius,sigma) to minimum.
524  */
525  width=GetOptimalKernelWidth2D(radius,sigma);
526  kernel=(double **) MagickAssumeAligned(AcquireAlignedMemory((size_t)
527  width,sizeof(*kernel)));
528  if (kernel == (double **) NULL)
529  {
530  edge_image=DestroyImage(edge_image);
531  sharp_image=DestroyImage(sharp_image);
532  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
533  }
534  (void) memset(kernel,0,(size_t) width*sizeof(*kernel));
535  for (i=0; i < (ssize_t) width; i+=2)
536  {
537  kernel[i]=(double *) MagickAssumeAligned(AcquireAlignedMemory((size_t)
538  (width-i),(width-i)*sizeof(**kernel)));
539  if (kernel[i] == (double *) NULL)
540  break;
541  normalize=0.0;
542  j=(ssize_t) (width-i-1)/2;
543  k=0;
544  for (v=(-j); v <= j; v++)
545  {
546  for (u=(-j); u <= j; u++)
547  {
548  kernel[i][k]=(double) (-exp(-((double) u*u+v*v)/(2.0*MagickSigma*
550  normalize+=kernel[i][k];
551  k++;
552  }
553  }
554  kernel[i][(k-1)/2]=(double) ((-2.0)*normalize);
555  if (sigma < MagickEpsilon)
556  kernel[i][(k-1)/2]=1.0;
557  }
558  if (i < (ssize_t) width)
559  {
560  for (i-=2; i >= 0; i-=2)
561  kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
562  kernel=(double **) RelinquishAlignedMemory(kernel);
563  edge_image=DestroyImage(edge_image);
564  sharp_image=DestroyImage(sharp_image);
565  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
566  }
567  /*
568  Adaptively sharpen image.
569  */
570  status=MagickTrue;
571  progress=0;
572  image_view=AcquireVirtualCacheView(image,exception);
573  edge_view=AcquireVirtualCacheView(edge_image,exception);
574  sharp_view=AcquireAuthenticCacheView(sharp_image,exception);
575 #if defined(MAGICKCORE_OPENMP_SUPPORT)
576  #pragma omp parallel for schedule(static) shared(progress,status) \
577  magick_number_threads(image,sharp_image,sharp_image->rows,1)
578 #endif
579  for (y=0; y < (ssize_t) sharp_image->rows; y++)
580  {
581  const Quantum
582  *magick_restrict r;
583 
584  Quantum
585  *magick_restrict q;
586 
587  ssize_t
588  x;
589 
590  if (status == MagickFalse)
591  continue;
592  r=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
593  q=QueueCacheViewAuthenticPixels(sharp_view,0,y,sharp_image->columns,1,
594  exception);
595  if ((r == (const Quantum *) NULL) || (q == (Quantum *) NULL))
596  {
597  status=MagickFalse;
598  continue;
599  }
600  for (x=0; x < (ssize_t) sharp_image->columns; x++)
601  {
602  const Quantum
603  *magick_restrict p;
604 
605  ssize_t
606  i;
607 
608  ssize_t
609  center,
610  j;
611 
612  j=CastDoubleToLong(ceil((double) width*(1.0-QuantumScale*
613  GetPixelIntensity(edge_image,r))-0.5));
614  if (j < 0)
615  j=0;
616  else
617  if (j > (ssize_t) width)
618  j=(ssize_t) width;
619  if ((j & 0x01) != 0)
620  j--;
621  p=GetCacheViewVirtualPixels(image_view,x-((ssize_t) (width-j)/2L),y-
622  (ssize_t) ((width-j)/2L),width-j,width-j,exception);
623  if (p == (const Quantum *) NULL)
624  break;
625  center=(ssize_t) GetPixelChannels(image)*(width-j)*((width-j)/2L)+
626  GetPixelChannels(image)*((width-j)/2);
627  for (i=0; i < (ssize_t) GetPixelChannels(sharp_image); i++)
628  {
629  double
630  alpha,
631  gamma,
632  pixel;
633 
635  channel;
636 
637  PixelTrait
638  sharp_traits,
639  traits;
640 
641  const double
642  *magick_restrict k;
643 
644  const Quantum
645  *magick_restrict pixels;
646 
647  ssize_t
648  u;
649 
650  ssize_t
651  v;
652 
653  channel=GetPixelChannelChannel(image,i);
654  traits=GetPixelChannelTraits(image,channel);
655  sharp_traits=GetPixelChannelTraits(sharp_image,channel);
656  if ((traits == UndefinedPixelTrait) ||
657  (sharp_traits == UndefinedPixelTrait))
658  continue;
659  if ((sharp_traits & CopyPixelTrait) != 0)
660  {
661  SetPixelChannel(sharp_image,channel,p[center+i],q);
662  continue;
663  }
664  k=kernel[j];
665  pixels=p;
666  pixel=0.0;
667  gamma=0.0;
668  if ((sharp_traits & BlendPixelTrait) == 0)
669  {
670  /*
671  No alpha blending.
672  */
673  for (v=0; v < (ssize_t) (width-j); v++)
674  {
675  for (u=0; u < (ssize_t) (width-j); u++)
676  {
677  pixel+=(*k)*pixels[i];
678  gamma+=(*k);
679  k++;
680  pixels+=GetPixelChannels(image);
681  }
682  }
683  gamma=PerceptibleReciprocal(gamma);
684  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
685  continue;
686  }
687  /*
688  Alpha blending.
689  */
690  for (v=0; v < (ssize_t) (width-j); v++)
691  {
692  for (u=0; u < (ssize_t) (width-j); u++)
693  {
694  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
695  pixel+=(*k)*alpha*pixels[i];
696  gamma+=(*k)*alpha;
697  k++;
698  pixels+=GetPixelChannels(image);
699  }
700  }
701  gamma=PerceptibleReciprocal(gamma);
702  SetPixelChannel(sharp_image,channel,ClampToQuantum(gamma*pixel),q);
703  }
704  q+=GetPixelChannels(sharp_image);
705  r+=GetPixelChannels(edge_image);
706  }
707  if (SyncCacheViewAuthenticPixels(sharp_view,exception) == MagickFalse)
708  status=MagickFalse;
709  if (image->progress_monitor != (MagickProgressMonitor) NULL)
710  {
712  proceed;
713 
714 #if defined(MAGICKCORE_OPENMP_SUPPORT)
715  #pragma omp atomic
716 #endif
717  progress++;
718  proceed=SetImageProgress(image,AdaptiveSharpenImageTag,progress,
719  image->rows);
720  if (proceed == MagickFalse)
721  status=MagickFalse;
722  }
723  }
724  sharp_image->type=image->type;
725  sharp_view=DestroyCacheView(sharp_view);
726  edge_view=DestroyCacheView(edge_view);
727  image_view=DestroyCacheView(image_view);
728  edge_image=DestroyImage(edge_image);
729  for (i=0; i < (ssize_t) width; i+=2)
730  kernel[i]=(double *) RelinquishAlignedMemory(kernel[i]);
731  kernel=(double **) RelinquishAlignedMemory(kernel);
732  if (status == MagickFalse)
733  sharp_image=DestroyImage(sharp_image);
734  return(sharp_image);
735 }
736 
737 /*
738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739 % %
740 % %
741 % %
742 % B l u r I m a g e %
743 % %
744 % %
745 % %
746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
747 %
748 % BlurImage() blurs an image. We convolve the image with a Gaussian operator
749 % of the given radius and standard deviation (sigma). For reasonable results,
750 % the radius should be larger than sigma. Use a radius of 0 and BlurImage()
751 % selects a suitable radius for you.
752 %
753 % The format of the BlurImage method is:
754 %
755 % Image *BlurImage(const Image *image,const double radius,
756 % const double sigma,ExceptionInfo *exception)
757 %
758 % A description of each parameter follows:
759 %
760 % o image: the image.
761 %
762 % o radius: the radius of the Gaussian, in pixels, not counting the center
763 % pixel.
764 %
765 % o sigma: the standard deviation of the Gaussian, in pixels.
766 %
767 % o exception: return any errors or warnings in this structure.
768 %
769 */
770 MagickExport Image *BlurImage(const Image *image,const double radius,
771  const double sigma,ExceptionInfo *exception)
772 {
773  char
774  geometry[MagickPathExtent];
775 
776  KernelInfo
777  *kernel_info;
778 
779  Image
780  *blur_image;
781 
782  assert(image != (const Image *) NULL);
783  assert(image->signature == MagickCoreSignature);
784  if (image->debug != MagickFalse)
785  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
786  assert(exception != (ExceptionInfo *) NULL);
787  assert(exception->signature == MagickCoreSignature);
788 #if defined(MAGICKCORE_OPENCL_SUPPORT)
789  blur_image=AccelerateBlurImage(image,radius,sigma,exception);
790  if (blur_image != (Image *) NULL)
791  return(blur_image);
792 #endif
793  (void) FormatLocaleString(geometry,MagickPathExtent,
794  "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
795  kernel_info=AcquireKernelInfo(geometry,exception);
796  if (kernel_info == (KernelInfo *) NULL)
797  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
798  blur_image=ConvolveImage(image,kernel_info,exception);
799  kernel_info=DestroyKernelInfo(kernel_info);
800  return(blur_image);
801 }
802 
803 /*
804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
805 % %
806 % %
807 % %
808 % B i l a t e r a l B l u r I m a g e %
809 % %
810 % %
811 % %
812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 %
814 % BilateralBlurImage() is a non-linear, edge-preserving, and noise-reducing
815 % smoothing filter for images. It replaces the intensity of each pixel with
816 % a weighted average of intensity values from nearby pixels. This weight is
817 % based on a Gaussian distribution. The weights depend not only on Euclidean
818 % distance of pixels, but also on the radiometric differences (e.g., range
819 % differences, such as color intensity, depth distance, etc.). This preserves
820 % sharp edges.
821 %
822 % The format of the BilateralBlurImage method is:
823 %
824 % Image *BilateralBlurImage(const Image *image,const size_t width,
825 % const size_t height,const double intensity_sigma,
826 % const double spatial_sigma,ExceptionInfo *exception)
827 %
828 % A description of each parameter follows:
829 %
830 % o image: the image.
831 %
832 % o width: the width of the neighborhood in pixels.
833 %
834 % o height: the height of the neighborhood in pixels.
835 %
836 % o intensity_sigma: sigma in the intensity space. A larger value means
837 % that farther colors within the pixel neighborhood (see spatial_sigma)
838 % will be mixed together, resulting in larger areas of semi-equal color.
839 %
840 % o spatial_sigma: sigma in the coordinate space. A larger value means that
841 % farther pixels influence each other as long as their colors are close
842 % enough (see intensity_sigma ). When the neigborhood diameter is greater
843 % than zero, it specifies the neighborhood size regardless of
844 % spatial_sigma. Otherwise, the neigborhood diameter is proportional to
845 % spatial_sigma.
846 %
847 % o exception: return any errors or warnings in this structure.
848 %
849 */
850 
851 static inline double BlurDistance(const ssize_t x,const ssize_t y,
852  const ssize_t u,const ssize_t v)
853 {
854  return(sqrt(((double) x-u)*((double) x-u)+((double) y-v)*((double) y-v)));
855 }
856 
857 static inline double BlurGaussian(const double x,const double sigma)
858 {
859  return(exp(-((double) x*x)*PerceptibleReciprocal(2.0*sigma*sigma))*
860  PerceptibleReciprocal(Magick2PI*sigma*sigma));
861 }
862 
863 static double **DestroyBilateralThreadSet(const ssize_t number_threads,
864  double **weights)
865 {
866  ssize_t
867  i;
868 
869  assert(weights != (double **) NULL);
870  for (i=0; i <= (ssize_t) number_threads; i++)
871  if (weights[i] != (double *) NULL)
872  weights[i]=(double *) RelinquishMagickMemory(weights[i]);
873  weights=(double **) RelinquishMagickMemory(weights);
874  return(weights);
875 }
876 
877 static double **AcquireBilateralThreadSet(const size_t number_threads,
878  const size_t width,const size_t height)
879 {
880  double
881  **weights;
882 
883  ssize_t
884  i;
885 
886  weights=(double **) AcquireQuantumMemory(number_threads+1,sizeof(*weights));
887  if (weights == (double **) NULL)
888  return((double **) NULL);
889  (void) memset(weights,0,number_threads*sizeof(*weights));
890  for (i=0; i <= (ssize_t) number_threads; i++)
891  {
892  weights[i]=(double *) AcquireQuantumMemory(width,height*sizeof(**weights));
893  if (weights[i] == (double *) NULL)
894  return(DestroyBilateralThreadSet(number_threads,weights));
895  }
896  return(weights);
897 }
898 
899 MagickExport Image *BilateralBlurImage(const Image *image,const size_t width,
900  const size_t height,const double intensity_sigma,const double spatial_sigma,
901  ExceptionInfo *exception)
902 {
903 #define MaxIntensity (255)
904 #define BilateralBlurImageTag "Blur/Image"
905 
906  CacheView
907  *blur_view,
908  *image_view;
909 
910  double
911  intensity_gaussian[2*(MaxIntensity+1)],
912  *spatial_gaussian,
913  **weights;
914 
915  Image
916  *blur_image;
917 
919  status;
920 
922  progress;
923 
924  OffsetInfo
925  mid;
926 
927  ssize_t
928  u;
929 
930  ssize_t
931  n,
932  number_threads,
933  v;
934 
935  ssize_t
936  i,
937  y;
938 
939  assert(image != (const Image *) NULL);
940  assert(image->signature == MagickCoreSignature);
941  if (image->debug != MagickFalse)
942  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
943  assert(exception != (ExceptionInfo *) NULL);
944  assert(exception->signature == MagickCoreSignature);
945  blur_image=CloneImage(image,0,0,MagickTrue,exception);
946  if (blur_image == (Image *) NULL)
947  return((Image *) NULL);
948  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
949  {
950  blur_image=DestroyImage(blur_image);
951  return((Image *) NULL);
952  }
953  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
954  weights=AcquireBilateralThreadSet(number_threads,width,height);
955  if (weights == (double **) NULL)
956  {
957  blur_image=DestroyImage(blur_image);
958  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
959  }
960  for (i=(-MaxIntensity); i < MaxIntensity; i++)
961  intensity_gaussian[i+MaxIntensity]=BlurGaussian((double) i,intensity_sigma);
962  spatial_gaussian=weights[number_threads];
963  n=0;
964  mid.x=(ssize_t) (width/2L);
965  mid.y=(ssize_t) (height/2L);
966  for (v=0; v < (ssize_t) height; v++)
967  for (u=0; u < (ssize_t) width; u++)
968  spatial_gaussian[n++]=BlurGaussian(BlurDistance(0,0,u-mid.x,v-mid.y),
969  spatial_sigma);
970  /*
971  Bilateral blur image.
972  */
973  status=MagickTrue;
974  progress=0;
975  image_view=AcquireVirtualCacheView(image,exception);
976  blur_view=AcquireAuthenticCacheView(blur_image,exception);
977 #if defined(MAGICKCORE_OPENMP_SUPPORT)
978  #pragma omp parallel for schedule(static) shared(progress,status) \
979  magick_number_threads(image,blur_image,blur_image->rows,1)
980 #endif
981  for (y=0; y < (ssize_t) blur_image->rows; y++)
982  {
983  const int
984  id = GetOpenMPThreadId();
985 
986  Quantum
987  *magick_restrict q;
988 
989  ssize_t
990  x;
991 
992  if (status == MagickFalse)
993  continue;
994  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
995  exception);
996  if (q == (Quantum *) NULL)
997  {
998  status=MagickFalse;
999  continue;
1000  }
1001  for (x=0; x < (ssize_t) blur_image->columns; x++)
1002  {
1003  double
1004  gamma,
1005  pixel;
1006 
1007  const Quantum
1008  *magick_restrict p,
1009  *magick_restrict r;
1010 
1011  ssize_t
1012  i,
1013  u;
1014 
1015  ssize_t
1016  n,
1017  v;
1018 
1019  /*
1020  Tonal weighting preserves edges while smoothing in the flat regions.
1021  */
1022  p=GetCacheViewVirtualPixels(image_view,x-mid.x,y-mid.y,width,height,
1023  exception);
1024  if (p == (const Quantum *) NULL)
1025  break;
1026  p+=(ssize_t) GetPixelChannels(image)*width*mid.y+GetPixelChannels(image)*
1027  mid.x;
1028  n=0;
1029  for (v=0; v < (ssize_t) height; v++)
1030  {
1031  for (u=0; u < (ssize_t) width; u++)
1032  {
1033  double
1034  intensity;
1035 
1036  r=p+(ssize_t) GetPixelChannels(image)*(ssize_t) width*(mid.y-v)+
1037  GetPixelChannels(image)*(mid.x-u);
1038  intensity=ScaleQuantumToChar(GetPixelIntensity(image,r))-
1039  (double) ScaleQuantumToChar(GetPixelIntensity(image,p));
1040  if ((intensity >= -MaxIntensity) && (intensity <= MaxIntensity))
1041  weights[id][n]=intensity_gaussian[(ssize_t) intensity+MaxIntensity]*
1042  spatial_gaussian[n];
1043  else
1044  weights[id][n]=BlurGaussian(intensity,intensity_sigma)*
1045  BlurGaussian(BlurDistance(x,y,x+u-mid.x,y+v-mid.y),spatial_sigma);
1046  n++;
1047  }
1048  }
1049  for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
1050  {
1051  PixelChannel
1052  channel;
1053 
1054  PixelTrait
1055  blur_traits,
1056  traits;
1057 
1058  channel=GetPixelChannelChannel(image,i);
1059  traits=GetPixelChannelTraits(image,channel);
1060  blur_traits=GetPixelChannelTraits(blur_image,channel);
1061  if ((traits == UndefinedPixelTrait) ||
1062  (blur_traits == UndefinedPixelTrait))
1063  continue;
1064  if ((blur_traits & CopyPixelTrait) != 0)
1065  {
1066  SetPixelChannel(blur_image,channel,p[i],q);
1067  continue;
1068  }
1069  pixel=0.0;
1070  gamma=0.0;
1071  n=0;
1072  if ((blur_traits & BlendPixelTrait) == 0)
1073  {
1074  /*
1075  No alpha blending.
1076  */
1077  for (v=0; v < (ssize_t) height; v++)
1078  {
1079  for (u=0; u < (ssize_t) width; u++)
1080  {
1081  r=p+(ssize_t) GetPixelChannels(image)*width*(mid.y-v)+
1082  GetPixelChannels(image)*(mid.x-u);
1083  pixel+=weights[id][n]*r[i];
1084  gamma+=weights[id][n];
1085  n++;
1086  }
1087  }
1088  SetPixelChannel(blur_image,channel,ClampToQuantum(
1089  PerceptibleReciprocal(gamma)*pixel),q);
1090  continue;
1091  }
1092  /*
1093  Alpha blending.
1094  */
1095  for (v=0; v < (ssize_t) height; v++)
1096  {
1097  for (u=0; u < (ssize_t) width; u++)
1098  {
1099  double
1100  alpha,
1101  beta;
1102 
1103  r=p+(ssize_t) GetPixelChannels(image)*width*(mid.y-v)+
1104  GetPixelChannels(image)*(mid.x-u);
1105  alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
1106  beta=(double) (QuantumScale*GetPixelAlpha(image,r));
1107  pixel+=weights[id][n]*r[i];
1108  gamma+=weights[id][n]*alpha*beta;
1109  n++;
1110  }
1111  }
1112  SetPixelChannel(blur_image,channel,ClampToQuantum(
1113  PerceptibleReciprocal(gamma)*pixel),q);
1114  }
1115  q+=GetPixelChannels(blur_image);
1116  }
1117  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
1118  status=MagickFalse;
1119  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1120  {
1122  proceed;
1123 
1124 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1125  #pragma omp atomic
1126 #endif
1127  progress++;
1128  proceed=SetImageProgress(image,BilateralBlurImageTag,progress,
1129  image->rows);
1130  if (proceed == MagickFalse)
1131  status=MagickFalse;
1132  }
1133  }
1134  blur_image->type=image->type;
1135  blur_view=DestroyCacheView(blur_view);
1136  image_view=DestroyCacheView(image_view);
1137  weights=DestroyBilateralThreadSet(number_threads,weights);
1138  if (status == MagickFalse)
1139  blur_image=DestroyImage(blur_image);
1140  return(blur_image);
1141 }
1142 
1143 /*
1144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1145 % %
1146 % %
1147 % %
1148 % C o n v o l v e I m a g e %
1149 % %
1150 % %
1151 % %
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153 %
1154 % ConvolveImage() applies a custom convolution kernel to the image.
1155 %
1156 % The format of the ConvolveImage method is:
1157 %
1158 % Image *ConvolveImage(const Image *image,const KernelInfo *kernel,
1159 % ExceptionInfo *exception)
1160 %
1161 % A description of each parameter follows:
1162 %
1163 % o image: the image.
1164 %
1165 % o kernel: the filtering kernel.
1166 %
1167 % o exception: return any errors or warnings in this structure.
1168 %
1169 */
1171  const KernelInfo *kernel_info,ExceptionInfo *exception)
1172 {
1173  Image
1174  *convolve_image;
1175 
1176 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1177  convolve_image=AccelerateConvolveImage(image,kernel_info,exception);
1178  if (convolve_image != (Image *) NULL)
1179  return(convolve_image);
1180 #endif
1181 
1182  convolve_image=MorphologyImage(image,ConvolveMorphology,1,kernel_info,
1183  exception);
1184  return(convolve_image);
1185 }
1186 
1187 /*
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 % %
1190 % %
1191 % %
1192 % D e s p e c k l e I m a g e %
1193 % %
1194 % %
1195 % %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 %
1198 % DespeckleImage() reduces the speckle noise in an image while perserving the
1199 % edges of the original image. A speckle removing filter uses a complementary
1200 % hulling technique (raising pixels that are darker than their surrounding
1201 % neighbors, then complementarily lowering pixels that are brighter than their
1202 % surrounding neighbors) to reduce the speckle index of that image (reference
1203 % Crimmins speckle removal).
1204 %
1205 % The format of the DespeckleImage method is:
1206 %
1207 % Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
1208 %
1209 % A description of each parameter follows:
1210 %
1211 % o image: the image.
1212 %
1213 % o exception: return any errors or warnings in this structure.
1214 %
1215 */
1216 
1217 static void Hull(const Image *image,const ssize_t x_offset,
1218  const ssize_t y_offset,const size_t columns,const size_t rows,
1219  const int polarity,Quantum *magick_restrict f,Quantum *magick_restrict g)
1220 {
1221  Quantum
1222  *p,
1223  *q,
1224  *r,
1225  *s;
1226 
1227  ssize_t
1228  y;
1229 
1230  assert(image != (const Image *) NULL);
1231  assert(image->signature == MagickCoreSignature);
1232  if (image->debug != MagickFalse)
1233  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1234  assert(f != (Quantum *) NULL);
1235  assert(g != (Quantum *) NULL);
1236  p=f+(columns+2);
1237  q=g+(columns+2);
1238  r=p+(y_offset*((ssize_t) columns+2)+x_offset);
1239 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1240  #pragma omp parallel for schedule(static) \
1241  magick_number_threads(image,image,rows,1)
1242 #endif
1243  for (y=0; y < (ssize_t) rows; y++)
1244  {
1246  v;
1247 
1248  ssize_t
1249  i,
1250  x;
1251 
1252  i=(2*y+1)+y*columns;
1253  if (polarity > 0)
1254  for (x=0; x < (ssize_t) columns; x++)
1255  {
1256  v=(MagickRealType) p[i];
1257  if ((MagickRealType) r[i] >= (v+ScaleCharToQuantum(2)))
1258  v+=ScaleCharToQuantum(1);
1259  q[i]=(Quantum) v;
1260  i++;
1261  }
1262  else
1263  for (x=0; x < (ssize_t) columns; x++)
1264  {
1265  v=(MagickRealType) p[i];
1266  if ((MagickRealType) r[i] <= (v-ScaleCharToQuantum(2)))
1267  v-=ScaleCharToQuantum(1);
1268  q[i]=(Quantum) v;
1269  i++;
1270  }
1271  }
1272  p=f+(columns+2);
1273  q=g+(columns+2);
1274  r=q+(y_offset*((ssize_t) columns+2)+x_offset);
1275  s=q-(y_offset*((ssize_t) columns+2)+x_offset);
1276 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1277  #pragma omp parallel for schedule(static) \
1278  magick_number_threads(image,image,rows,1)
1279 #endif
1280  for (y=0; y < (ssize_t) rows; y++)
1281  {
1282  ssize_t
1283  i,
1284  x;
1285 
1287  v;
1288 
1289  i=(2*y+1)+y*columns;
1290  if (polarity > 0)
1291  for (x=0; x < (ssize_t) columns; x++)
1292  {
1293  v=(MagickRealType) q[i];
1294  if (((MagickRealType) s[i] >= (v+ScaleCharToQuantum(2))) &&
1295  ((MagickRealType) r[i] > v))
1296  v+=ScaleCharToQuantum(1);
1297  p[i]=(Quantum) v;
1298  i++;
1299  }
1300  else
1301  for (x=0; x < (ssize_t) columns; x++)
1302  {
1303  v=(MagickRealType) q[i];
1304  if (((MagickRealType) s[i] <= (v-ScaleCharToQuantum(2))) &&
1305  ((MagickRealType) r[i] < v))
1306  v-=ScaleCharToQuantum(1);
1307  p[i]=(Quantum) v;
1308  i++;
1309  }
1310  }
1311 }
1312 
1314 {
1315 #define DespeckleImageTag "Despeckle/Image"
1316 
1317  CacheView
1318  *despeckle_view,
1319  *image_view;
1320 
1321  Image
1322  *despeckle_image;
1323 
1325  status;
1326 
1327  MemoryInfo
1328  *buffer_info,
1329  *pixel_info;
1330 
1331  Quantum
1332  *magick_restrict buffer,
1333  *magick_restrict pixels;
1334 
1335  ssize_t
1336  i;
1337 
1338  size_t
1339  length;
1340 
1341  static const ssize_t
1342  X[4] = {0, 1, 1,-1},
1343  Y[4] = {1, 0, 1, 1};
1344 
1345  /*
1346  Allocate despeckled image.
1347  */
1348  assert(image != (const Image *) NULL);
1349  assert(image->signature == MagickCoreSignature);
1350  if (image->debug != MagickFalse)
1351  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1352  assert(exception != (ExceptionInfo *) NULL);
1353  assert(exception->signature == MagickCoreSignature);
1354 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1355  despeckle_image=AccelerateDespeckleImage(image,exception);
1356  if (despeckle_image != (Image *) NULL)
1357  return(despeckle_image);
1358 #endif
1359  despeckle_image=CloneImage(image,0,0,MagickTrue,exception);
1360  if (despeckle_image == (Image *) NULL)
1361  return((Image *) NULL);
1362  status=SetImageStorageClass(despeckle_image,DirectClass,exception);
1363  if (status == MagickFalse)
1364  {
1365  despeckle_image=DestroyImage(despeckle_image);
1366  return((Image *) NULL);
1367  }
1368  /*
1369  Allocate image buffer.
1370  */
1371  length=(size_t) ((image->columns+2)*(image->rows+2));
1372  pixel_info=AcquireVirtualMemory(length,sizeof(*pixels));
1373  buffer_info=AcquireVirtualMemory(length,sizeof(*buffer));
1374  if ((pixel_info == (MemoryInfo *) NULL) ||
1375  (buffer_info == (MemoryInfo *) NULL))
1376  {
1377  if (buffer_info != (MemoryInfo *) NULL)
1378  buffer_info=RelinquishVirtualMemory(buffer_info);
1379  if (pixel_info != (MemoryInfo *) NULL)
1380  pixel_info=RelinquishVirtualMemory(pixel_info);
1381  despeckle_image=DestroyImage(despeckle_image);
1382  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1383  }
1384  pixels=(Quantum *) GetVirtualMemoryBlob(pixel_info);
1385  buffer=(Quantum *) GetVirtualMemoryBlob(buffer_info);
1386  /*
1387  Reduce speckle in the image.
1388  */
1389  status=MagickTrue;
1390  image_view=AcquireVirtualCacheView(image,exception);
1391  despeckle_view=AcquireAuthenticCacheView(despeckle_image,exception);
1392  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1393  {
1394  PixelChannel
1395  channel;
1396 
1397  PixelTrait
1398  despeckle_traits,
1399  traits;
1400 
1401  ssize_t
1402  k,
1403  x;
1404 
1405  ssize_t
1406  j,
1407  y;
1408 
1409  if (status == MagickFalse)
1410  continue;
1411  channel=GetPixelChannelChannel(image,i);
1412  traits=GetPixelChannelTraits(image,channel);
1413  despeckle_traits=GetPixelChannelTraits(despeckle_image,channel);
1414  if ((traits == UndefinedPixelTrait) ||
1415  (despeckle_traits == UndefinedPixelTrait))
1416  continue;
1417  if ((despeckle_traits & CopyPixelTrait) != 0)
1418  continue;
1419  (void) memset(pixels,0,length*sizeof(*pixels));
1420  j=(ssize_t) image->columns+2;
1421  for (y=0; y < (ssize_t) image->rows; y++)
1422  {
1423  const Quantum
1424  *magick_restrict p;
1425 
1426  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1427  if (p == (const Quantum *) NULL)
1428  {
1429  status=MagickFalse;
1430  continue;
1431  }
1432  j++;
1433  for (x=0; x < (ssize_t) image->columns; x++)
1434  {
1435  pixels[j++]=p[i];
1436  p+=GetPixelChannels(image);
1437  }
1438  j++;
1439  }
1440  (void) memset(buffer,0,length*sizeof(*buffer));
1441  for (k=0; k < 4; k++)
1442  {
1443  Hull(image,X[k],Y[k],image->columns,image->rows,1,pixels,buffer);
1444  Hull(image,-X[k],-Y[k],image->columns,image->rows,1,pixels,buffer);
1445  Hull(image,-X[k],-Y[k],image->columns,image->rows,-1,pixels,buffer);
1446  Hull(image,X[k],Y[k],image->columns,image->rows,-1,pixels,buffer);
1447  }
1448  j=(ssize_t) image->columns+2;
1449  for (y=0; y < (ssize_t) image->rows; y++)
1450  {
1452  sync;
1453 
1454  Quantum
1455  *magick_restrict q;
1456 
1457  q=GetCacheViewAuthenticPixels(despeckle_view,0,y,despeckle_image->columns,
1458  1,exception);
1459  if (q == (Quantum *) NULL)
1460  {
1461  status=MagickFalse;
1462  continue;
1463  }
1464  j++;
1465  for (x=0; x < (ssize_t) image->columns; x++)
1466  {
1467  SetPixelChannel(despeckle_image,channel,pixels[j++],q);
1468  q+=GetPixelChannels(despeckle_image);
1469  }
1470  sync=SyncCacheViewAuthenticPixels(despeckle_view,exception);
1471  if (sync == MagickFalse)
1472  status=MagickFalse;
1473  j++;
1474  }
1475  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1476  {
1478  proceed;
1479 
1481  GetPixelChannels(image));
1482  if (proceed == MagickFalse)
1483  status=MagickFalse;
1484  }
1485  }
1486  despeckle_view=DestroyCacheView(despeckle_view);
1487  image_view=DestroyCacheView(image_view);
1488  buffer_info=RelinquishVirtualMemory(buffer_info);
1489  pixel_info=RelinquishVirtualMemory(pixel_info);
1490  despeckle_image->type=image->type;
1491  if (status == MagickFalse)
1492  despeckle_image=DestroyImage(despeckle_image);
1493  return(despeckle_image);
1494 }
1495 
1496 /*
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1498 % %
1499 % %
1500 % %
1501 % E d g e I m a g e %
1502 % %
1503 % %
1504 % %
1505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 %
1507 % EdgeImage() finds edges in an image. Radius defines the radius of the
1508 % convolution filter. Use a radius of 0 and EdgeImage() selects a suitable
1509 % radius for you.
1510 %
1511 % The format of the EdgeImage method is:
1512 %
1513 % Image *EdgeImage(const Image *image,const double radius,
1514 % ExceptionInfo *exception)
1515 %
1516 % A description of each parameter follows:
1517 %
1518 % o image: the image.
1519 %
1520 % o radius: the radius of the pixel neighborhood.
1521 %
1522 % o exception: return any errors or warnings in this structure.
1523 %
1524 */
1525 MagickExport Image *EdgeImage(const Image *image,const double radius,
1526  ExceptionInfo *exception)
1527 {
1528  Image
1529  *edge_image;
1530 
1531  KernelInfo
1532  *kernel_info;
1533 
1534  ssize_t
1535  i;
1536 
1537  size_t
1538  width;
1539 
1540  assert(image != (const Image *) NULL);
1541  assert(image->signature == MagickCoreSignature);
1542  if (image->debug != MagickFalse)
1543  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1544  assert(exception != (ExceptionInfo *) NULL);
1545  assert(exception->signature == MagickCoreSignature);
1546  width=GetOptimalKernelWidth1D(radius,0.5);
1547  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
1548  if (kernel_info == (KernelInfo *) NULL)
1549  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1550  (void) memset(kernel_info,0,sizeof(*kernel_info));
1551  kernel_info->width=width;
1552  kernel_info->height=width;
1553  kernel_info->x=(ssize_t) (kernel_info->width-1)/2;
1554  kernel_info->y=(ssize_t) (kernel_info->height-1)/2;
1555  kernel_info->signature=MagickCoreSignature;
1556  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1557  AcquireAlignedMemory(kernel_info->width,kernel_info->height*
1558  sizeof(*kernel_info->values)));
1559  if (kernel_info->values == (MagickRealType *) NULL)
1560  {
1561  kernel_info=DestroyKernelInfo(kernel_info);
1562  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1563  }
1564  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1565  kernel_info->values[i]=(-1.0);
1566  kernel_info->values[i/2]=(double) kernel_info->width*kernel_info->height-1.0;
1567  edge_image=ConvolveImage(image,kernel_info,exception);
1568  kernel_info=DestroyKernelInfo(kernel_info);
1569  return(edge_image);
1570 }
1571 
1572 /*
1573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574 % %
1575 % %
1576 % %
1577 % E m b o s s I m a g e %
1578 % %
1579 % %
1580 % %
1581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582 %
1583 % EmbossImage() returns a grayscale image with a three-dimensional effect.
1584 % We convolve the image with a Gaussian operator of the given radius and
1585 % standard deviation (sigma). For reasonable results, radius should be
1586 % larger than sigma. Use a radius of 0 and Emboss() selects a suitable
1587 % radius for you.
1588 %
1589 % The format of the EmbossImage method is:
1590 %
1591 % Image *EmbossImage(const Image *image,const double radius,
1592 % const double sigma,ExceptionInfo *exception)
1593 %
1594 % A description of each parameter follows:
1595 %
1596 % o image: the image.
1597 %
1598 % o radius: the radius of the pixel neighborhood.
1599 %
1600 % o sigma: the standard deviation of the Gaussian, in pixels.
1601 %
1602 % o exception: return any errors or warnings in this structure.
1603 %
1604 */
1605 MagickExport Image *EmbossImage(const Image *image,const double radius,
1606  const double sigma,ExceptionInfo *exception)
1607 {
1608  double
1609  gamma,
1610  normalize;
1611 
1612  Image
1613  *emboss_image;
1614 
1615  KernelInfo
1616  *kernel_info;
1617 
1618  ssize_t
1619  i;
1620 
1621  size_t
1622  width;
1623 
1624  ssize_t
1625  j,
1626  k,
1627  u,
1628  v;
1629 
1630  assert(image != (const Image *) NULL);
1631  assert(image->signature == MagickCoreSignature);
1632  if (image->debug != MagickFalse)
1633  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1634  assert(exception != (ExceptionInfo *) NULL);
1635  assert(exception->signature == MagickCoreSignature);
1636  width=GetOptimalKernelWidth1D(radius,sigma);
1637  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
1638  if (kernel_info == (KernelInfo *) NULL)
1639  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1640  kernel_info->width=width;
1641  kernel_info->height=width;
1642  kernel_info->x=(ssize_t) (width-1)/2;
1643  kernel_info->y=(ssize_t) (width-1)/2;
1644  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
1645  AcquireAlignedMemory(kernel_info->width,kernel_info->width*
1646  sizeof(*kernel_info->values)));
1647  if (kernel_info->values == (MagickRealType *) NULL)
1648  {
1649  kernel_info=DestroyKernelInfo(kernel_info);
1650  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1651  }
1652  j=(ssize_t) (kernel_info->width-1)/2;
1653  k=j;
1654  i=0;
1655  for (v=(-j); v <= j; v++)
1656  {
1657  for (u=(-j); u <= j; u++)
1658  {
1659  kernel_info->values[i]=(MagickRealType) (((u < 0) || (v < 0) ? -8.0 :
1660  8.0)*exp(-((double) u*u+v*v)/(2.0*MagickSigma*MagickSigma))/
1662  if (u != k)
1663  kernel_info->values[i]=0.0;
1664  i++;
1665  }
1666  k--;
1667  }
1668  normalize=0.0;
1669  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1670  normalize+=kernel_info->values[i];
1671  gamma=PerceptibleReciprocal(normalize);
1672  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
1673  kernel_info->values[i]*=gamma;
1674  emboss_image=ConvolveImage(image,kernel_info,exception);
1675  kernel_info=DestroyKernelInfo(kernel_info);
1676  if (emboss_image != (Image *) NULL)
1677  (void) EqualizeImage(emboss_image,exception);
1678  return(emboss_image);
1679 }
1680 
1681 /*
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683 % %
1684 % %
1685 % %
1686 % G a u s s i a n B l u r I m a g e %
1687 % %
1688 % %
1689 % %
1690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691 %
1692 % GaussianBlurImage() blurs an image. We convolve the image with a
1693 % Gaussian operator of the given radius and standard deviation (sigma).
1694 % For reasonable results, the radius should be larger than sigma. Use a
1695 % radius of 0 and GaussianBlurImage() selects a suitable radius for you.
1696 %
1697 % The format of the GaussianBlurImage method is:
1698 %
1699 % Image *GaussianBlurImage(const Image *image,onst double radius,
1700 % const double sigma,ExceptionInfo *exception)
1701 %
1702 % A description of each parameter follows:
1703 %
1704 % o image: the image.
1705 %
1706 % o radius: the radius of the Gaussian, in pixels, not counting the center
1707 % pixel.
1708 %
1709 % o sigma: the standard deviation of the Gaussian, in pixels.
1710 %
1711 % o exception: return any errors or warnings in this structure.
1712 %
1713 */
1714 MagickExport Image *GaussianBlurImage(const Image *image,const double radius,
1715  const double sigma,ExceptionInfo *exception)
1716 {
1717  char
1718  geometry[MagickPathExtent];
1719 
1720  KernelInfo
1721  *kernel_info;
1722 
1723  Image
1724  *blur_image;
1725 
1726  assert(image != (const Image *) NULL);
1727  assert(image->signature == MagickCoreSignature);
1728  if (image->debug != MagickFalse)
1729  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1730  assert(exception != (ExceptionInfo *) NULL);
1731  assert(exception->signature == MagickCoreSignature);
1732  (void) FormatLocaleString(geometry,MagickPathExtent,"gaussian:%.20gx%.20g",
1733  radius,sigma);
1734  kernel_info=AcquireKernelInfo(geometry,exception);
1735  if (kernel_info == (KernelInfo *) NULL)
1736  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
1737  blur_image=ConvolveImage(image,kernel_info,exception);
1738  kernel_info=DestroyKernelInfo(kernel_info);
1739  return(blur_image);
1740 }
1741 
1742 /*
1743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744 % %
1745 % %
1746 % %
1747 % K u w a h a r a I m a g e %
1748 % %
1749 % %
1750 % %
1751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1752 %
1753 % KuwaharaImage() is an edge preserving noise reduction filter.
1754 %
1755 % The format of the KuwaharaImage method is:
1756 %
1757 % Image *KuwaharaImage(const Image *image,const double radius,
1758 % const double sigma,ExceptionInfo *exception)
1759 %
1760 % A description of each parameter follows:
1761 %
1762 % o image: the image.
1763 %
1764 % o radius: the square window radius.
1765 %
1766 % o sigma: the standard deviation of the Gaussian, in pixels.
1767 %
1768 % o exception: return any errors or warnings in this structure.
1769 %
1770 */
1771 
1773  const double *magick_restrict pixel)
1774 {
1775  return(0.212656f*pixel[image->channel_map[RedPixelChannel].offset]+
1776  0.715158f*pixel[image->channel_map[GreenPixelChannel].offset]+
1777  0.072186f*pixel[image->channel_map[BluePixelChannel].offset]); /* Rec709 */
1778 }
1779 
1780 MagickExport Image *KuwaharaImage(const Image *image,const double radius,
1781  const double sigma,ExceptionInfo *exception)
1782 {
1783 #define KuwaharaImageTag "Kuwahara/Image"
1784 
1785  CacheView
1786  *image_view,
1787  *kuwahara_view;
1788 
1789  Image
1790  *gaussian_image,
1791  *kuwahara_image;
1792 
1794  status;
1795 
1797  progress;
1798 
1799  size_t
1800  width;
1801 
1802  ssize_t
1803  y;
1804 
1805  /*
1806  Initialize Kuwahara image attributes.
1807  */
1808  assert(image != (Image *) NULL);
1809  assert(image->signature == MagickCoreSignature);
1810  if (image->debug != MagickFalse)
1811  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1812  assert(exception != (ExceptionInfo *) NULL);
1813  assert(exception->signature == MagickCoreSignature);
1814  width=(size_t) radius+1;
1815  gaussian_image=BlurImage(image,radius,sigma,exception);
1816  if (gaussian_image == (Image *) NULL)
1817  return((Image *) NULL);
1818  kuwahara_image=CloneImage(image,0,0,MagickTrue,exception);
1819  if (kuwahara_image == (Image *) NULL)
1820  {
1821  gaussian_image=DestroyImage(gaussian_image);
1822  return((Image *) NULL);
1823  }
1824  if (SetImageStorageClass(kuwahara_image,DirectClass,exception) == MagickFalse)
1825  {
1826  gaussian_image=DestroyImage(gaussian_image);
1827  kuwahara_image=DestroyImage(kuwahara_image);
1828  return((Image *) NULL);
1829  }
1830  /*
1831  Edge preserving noise reduction filter.
1832  */
1833  status=MagickTrue;
1834  progress=0;
1835  image_view=AcquireVirtualCacheView(gaussian_image,exception);
1836  kuwahara_view=AcquireAuthenticCacheView(kuwahara_image,exception);
1837 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1838  #pragma omp parallel for schedule(static) shared(progress,status) \
1839  magick_number_threads(image,kuwahara_image,gaussian_image->rows,1)
1840 #endif
1841  for (y=0; y < (ssize_t) gaussian_image->rows; y++)
1842  {
1843  Quantum
1844  *magick_restrict q;
1845 
1846  ssize_t
1847  x;
1848 
1849  if (status == MagickFalse)
1850  continue;
1851  q=QueueCacheViewAuthenticPixels(kuwahara_view,0,y,kuwahara_image->columns,1,
1852  exception);
1853  if (q == (Quantum *) NULL)
1854  {
1855  status=MagickFalse;
1856  continue;
1857  }
1858  for (x=0; x < (ssize_t) gaussian_image->columns; x++)
1859  {
1860  const Quantum
1861  *magick_restrict p;
1862 
1863  double
1864  min_variance;
1865 
1867  quadrant,
1868  target;
1869 
1870  size_t
1871  i;
1872 
1873  min_variance=MagickMaximumValue;
1874  SetGeometry(gaussian_image,&target);
1875  quadrant.width=width;
1876  quadrant.height=width;
1877  for (i=0; i < 4; i++)
1878  {
1879  const Quantum
1880  *magick_restrict k;
1881 
1882  double
1883  mean[MaxPixelChannels],
1884  variance;
1885 
1886  ssize_t
1887  n;
1888 
1889  ssize_t
1890  j;
1891 
1892  quadrant.x=x;
1893  quadrant.y=y;
1894  switch (i)
1895  {
1896  case 0:
1897  {
1898  quadrant.x=x-(ssize_t) (width-1);
1899  quadrant.y=y-(ssize_t) (width-1);
1900  break;
1901  }
1902  case 1:
1903  {
1904  quadrant.y=y-(ssize_t) (width-1);
1905  break;
1906  }
1907  case 2:
1908  {
1909  quadrant.x=x-(ssize_t) (width-1);
1910  break;
1911  }
1912  case 3:
1913  default:
1914  break;
1915  }
1916  p=GetCacheViewVirtualPixels(image_view,quadrant.x,quadrant.y,
1917  quadrant.width,quadrant.height,exception);
1918  if (p == (const Quantum *) NULL)
1919  break;
1920  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1921  mean[j]=0.0;
1922  k=p;
1923  for (n=0; n < (ssize_t) (width*width); n++)
1924  {
1925  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1926  mean[j]+=(double) k[j];
1927  k+=GetPixelChannels(gaussian_image);
1928  }
1929  for (j=0; j < (ssize_t) GetPixelChannels(gaussian_image); j++)
1930  mean[j]/=(double) (width*width);
1931  k=p;
1932  variance=0.0;
1933  for (n=0; n < (ssize_t) (width*width); n++)
1934  {
1935  double
1936  luma;
1937 
1938  luma=GetPixelLuma(gaussian_image,k);
1939  variance+=(luma-GetMeanLuma(gaussian_image,mean))*
1940  (luma-GetMeanLuma(gaussian_image,mean));
1941  k+=GetPixelChannels(gaussian_image);
1942  }
1943  if (variance < min_variance)
1944  {
1945  min_variance=variance;
1946  target=quadrant;
1947  }
1948  }
1949  if (i < 4)
1950  {
1951  status=MagickFalse;
1952  break;
1953  }
1954  status=InterpolatePixelChannels(gaussian_image,image_view,kuwahara_image,
1955  UndefinedInterpolatePixel,(double) target.x+target.width/2.0,(double)
1956  target.y+target.height/2.0,q,exception);
1957  if (status == MagickFalse)
1958  break;
1959  q+=GetPixelChannels(kuwahara_image);
1960  }
1961  if (SyncCacheViewAuthenticPixels(kuwahara_view,exception) == MagickFalse)
1962  status=MagickFalse;
1963  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1964  {
1966  proceed;
1967 
1968 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1969  #pragma omp atomic
1970 #endif
1971  progress++;
1972  proceed=SetImageProgress(image,KuwaharaImageTag,progress,image->rows);
1973  if (proceed == MagickFalse)
1974  status=MagickFalse;
1975  }
1976  }
1977  kuwahara_view=DestroyCacheView(kuwahara_view);
1978  image_view=DestroyCacheView(image_view);
1979  gaussian_image=DestroyImage(gaussian_image);
1980  if (status == MagickFalse)
1981  kuwahara_image=DestroyImage(kuwahara_image);
1982  return(kuwahara_image);
1983 }
1984 
1985 /*
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 % %
1988 % %
1989 % %
1990 % L o c a l C o n t r a s t I m a g e %
1991 % %
1992 % %
1993 % %
1994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 %
1996 % LocalContrastImage() attempts to increase the appearance of large-scale
1997 % light-dark transitions. Local contrast enhancement works similarly to
1998 % sharpening with an unsharp mask, however the mask is instead created using
1999 % an image with a greater blur distance.
2000 %
2001 % The format of the LocalContrastImage method is:
2002 %
2003 % Image *LocalContrastImage(const Image *image, const double radius,
2004 % const double strength,ExceptionInfo *exception)
2005 %
2006 % A description of each parameter follows:
2007 %
2008 % o image: the image.
2009 %
2010 % o radius: the radius of the Gaussian blur, in percentage with 100%
2011 % resulting in a blur radius of 20% of largest dimension.
2012 %
2013 % o strength: the strength of the blur mask in percentage.
2014 %
2015 % o exception: return any errors or warnings in this structure.
2016 %
2017 */
2018 MagickExport Image *LocalContrastImage(const Image *image,const double radius,
2019  const double strength,ExceptionInfo *exception)
2020 {
2021 #define LocalContrastImageTag "LocalContrast/Image"
2022 
2023  CacheView
2024  *image_view,
2025  *contrast_view;
2026 
2027  float
2028  *interImage,
2029  *scanline,
2030  totalWeight;
2031 
2032  Image
2033  *contrast_image;
2034 
2036  status;
2037 
2038  MemoryInfo
2039  *scanline_info,
2040  *interImage_info;
2041 
2042  ssize_t
2043  scanLineSize,
2044  width;
2045 
2046  /*
2047  Initialize contrast image attributes.
2048  */
2049  assert(image != (const Image *) NULL);
2050  assert(image->signature == MagickCoreSignature);
2051  if (image->debug != MagickFalse)
2052  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2053  assert(exception != (ExceptionInfo *) NULL);
2054  assert(exception->signature == MagickCoreSignature);
2055 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2056  contrast_image=AccelerateLocalContrastImage(image,radius,strength,exception);
2057  if (contrast_image != (Image *) NULL)
2058  return(contrast_image);
2059 #endif
2060  contrast_image=CloneImage(image,0,0,MagickTrue,exception);
2061  if (contrast_image == (Image *) NULL)
2062  return((Image *) NULL);
2063  if (SetImageStorageClass(contrast_image,DirectClass,exception) == MagickFalse)
2064  {
2065  contrast_image=DestroyImage(contrast_image);
2066  return((Image *) NULL);
2067  }
2068  image_view=AcquireVirtualCacheView(image,exception);
2069  contrast_view=AcquireAuthenticCacheView(contrast_image,exception);
2070  scanLineSize=(ssize_t) MagickMax(image->columns,image->rows);
2071  width=(ssize_t) scanLineSize*0.002f*fabs(radius);
2072  scanLineSize+=(2*width);
2073  scanline_info=AcquireVirtualMemory((size_t) GetOpenMPMaximumThreads()*
2074  scanLineSize,sizeof(*scanline));
2075  if (scanline_info == (MemoryInfo *) NULL)
2076  {
2077  contrast_view=DestroyCacheView(contrast_view);
2078  image_view=DestroyCacheView(image_view);
2079  contrast_image=DestroyImage(contrast_image);
2080  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2081  }
2082  scanline=(float *) GetVirtualMemoryBlob(scanline_info);
2083  /*
2084  Create intermediate buffer.
2085  */
2086  interImage_info=AcquireVirtualMemory(image->rows*(image->columns+(2*width)),
2087  sizeof(*interImage));
2088  if (interImage_info == (MemoryInfo *) NULL)
2089  {
2090  scanline_info=RelinquishVirtualMemory(scanline_info);
2091  contrast_view=DestroyCacheView(contrast_view);
2092  image_view=DestroyCacheView(image_view);
2093  contrast_image=DestroyImage(contrast_image);
2094  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2095  }
2096  interImage=(float *) GetVirtualMemoryBlob(interImage_info);
2097  totalWeight=(float) ((width+1)*(width+1));
2098  /*
2099  Vertical pass.
2100  */
2101  status=MagickTrue;
2102  {
2103  ssize_t
2104  x;
2105 
2106 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2107 #pragma omp parallel for schedule(static) \
2108  magick_number_threads(image,image,image->columns,1)
2109 #endif
2110  for (x=0; x < (ssize_t) image->columns; x++)
2111  {
2112  const int
2113  id = GetOpenMPThreadId();
2114 
2115  const Quantum
2116  *magick_restrict p;
2117 
2118  float
2119  *out,
2120  *pix,
2121  *pixels;
2122 
2123  ssize_t
2124  y;
2125 
2126  ssize_t
2127  i;
2128 
2129  if (status == MagickFalse)
2130  continue;
2131  pixels=scanline;
2132  pixels+=id*scanLineSize;
2133  pix=pixels;
2134  p=GetCacheViewVirtualPixels(image_view,x,-width,1,image->rows+(2*width),
2135  exception);
2136  if (p == (const Quantum *) NULL)
2137  {
2138  status=MagickFalse;
2139  continue;
2140  }
2141  for (y=0; y < (ssize_t) image->rows+(2*width); y++)
2142  {
2143  *pix++=(float)GetPixelLuma(image,p);
2144  p+=image->number_channels;
2145  }
2146  out=interImage+x+width;
2147  for (y=0; y < (ssize_t) image->rows; y++)
2148  {
2149  float
2150  sum,
2151  weight;
2152 
2153  weight=1.0f;
2154  sum=0;
2155  pix=pixels+y;
2156  for (i=0; i < width; i++)
2157  {
2158  sum+=weight*(*pix++);
2159  weight+=1.0f;
2160  }
2161  for (i=width+1; i < (2*width); i++)
2162  {
2163  sum+=weight*(*pix++);
2164  weight-=1.0f;
2165  }
2166  /* write to output */
2167  *out=sum/totalWeight;
2168  /* mirror into padding */
2169  if (x <= width && x != 0)
2170  *(out-(x*2))=*out;
2171  if ((x > (ssize_t) image->columns-width-2) &&
2172  (x != (ssize_t) image->columns-1))
2173  *(out+((image->columns-x-1)*2))=*out;
2174  out+=image->columns+(width*2);
2175  }
2176  }
2177  }
2178  /*
2179  Horizontal pass.
2180  */
2181  {
2182  ssize_t
2183  y;
2184 
2185 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2186 #pragma omp parallel for schedule(static) \
2187  magick_number_threads(image,image,image->rows,1)
2188 #endif
2189  for (y=0; y < (ssize_t) image->rows; y++)
2190  {
2191  const int
2192  id = GetOpenMPThreadId();
2193 
2194  const Quantum
2195  *magick_restrict p;
2196 
2197  float
2198  *pix,
2199  *pixels;
2200 
2201  Quantum
2202  *magick_restrict q;
2203 
2204  ssize_t
2205  x;
2206 
2207  ssize_t
2208  i;
2209 
2210  if (status == MagickFalse)
2211  continue;
2212  pixels=scanline;
2213  pixels+=id*scanLineSize;
2214  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2215  q=GetCacheViewAuthenticPixels(contrast_view,0,y,image->columns,1,
2216  exception);
2217  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2218  {
2219  status=MagickFalse;
2220  continue;
2221  }
2222  memcpy(pixels,interImage+(y*(image->columns+(2*width))),(image->columns+
2223  (2*width))*sizeof(float));
2224  for (x=0; x < (ssize_t) image->columns; x++)
2225  {
2226  float
2227  mult,
2228  srcVal,
2229  sum,
2230  weight;
2231 
2232  PixelTrait
2233  traits;
2234 
2235  weight=1.0f;
2236  sum=0;
2237  pix=pixels+x;
2238  for (i=0; i < width; i++)
2239  {
2240  sum+=weight*(*pix++);
2241  weight+=1.0f;
2242  }
2243  for (i=width+1; i < (2*width); i++)
2244  {
2245  sum+=weight*(*pix++);
2246  weight-=1.0f;
2247  }
2248  /* Apply and write */
2249  srcVal=(float) GetPixelLuma(image,p);
2250  mult=(srcVal-(sum/totalWeight))*(strength/100.0f);
2251  mult=(srcVal+mult)/srcVal;
2252  traits=GetPixelChannelTraits(image,RedPixelChannel);
2253  if ((traits & UpdatePixelTrait) != 0)
2254  SetPixelRed(contrast_image,ClampToQuantum((MagickRealType)
2255  GetPixelRed(image,p)*mult),q);
2257  if ((traits & UpdatePixelTrait) != 0)
2259  GetPixelGreen(image,p)*mult),q);
2261  if ((traits & UpdatePixelTrait) != 0)
2262  SetPixelBlue(contrast_image,ClampToQuantum((MagickRealType)
2263  GetPixelBlue(image,p)*mult),q);
2264  p+=image->number_channels;
2265  q+=contrast_image->number_channels;
2266  }
2267  if (SyncCacheViewAuthenticPixels(contrast_view,exception) == MagickFalse)
2268  status=MagickFalse;
2269  }
2270  }
2271  scanline_info=RelinquishVirtualMemory(scanline_info);
2272  interImage_info=RelinquishVirtualMemory(interImage_info);
2273  contrast_view=DestroyCacheView(contrast_view);
2274  image_view=DestroyCacheView(image_view);
2275  if (status == MagickFalse)
2276  contrast_image=DestroyImage(contrast_image);
2277  return(contrast_image);
2278 }
2279 
2280 /*
2281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282 % %
2283 % %
2284 % %
2285 % M o t i o n B l u r I m a g e %
2286 % %
2287 % %
2288 % %
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2290 %
2291 % MotionBlurImage() simulates motion blur. We convolve the image with a
2292 % Gaussian operator of the given radius and standard deviation (sigma).
2293 % For reasonable results, radius should be larger than sigma. Use a
2294 % radius of 0 and MotionBlurImage() selects a suitable radius for you.
2295 % Angle gives the angle of the blurring motion.
2296 %
2297 % Andrew Protano contributed this effect.
2298 %
2299 % The format of the MotionBlurImage method is:
2300 %
2301 % Image *MotionBlurImage(const Image *image,const double radius,
2302 % const double sigma,const double angle,ExceptionInfo *exception)
2303 %
2304 % A description of each parameter follows:
2305 %
2306 % o image: the image.
2307 %
2308 % o radius: the radius of the Gaussian, in pixels, not counting
2309 % the center pixel.
2310 %
2311 % o sigma: the standard deviation of the Gaussian, in pixels.
2312 %
2313 % o angle: Apply the effect along this angle.
2314 %
2315 % o exception: return any errors or warnings in this structure.
2316 %
2317 */
2318 
2319 static MagickRealType *GetMotionBlurKernel(const size_t width,
2320  const double sigma)
2321 {
2323  *kernel,
2324  normalize;
2325 
2326  ssize_t
2327  i;
2328 
2329  /*
2330  Generate a 1-D convolution kernel.
2331  */
2332  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2334  width,sizeof(*kernel)));
2335  if (kernel == (MagickRealType *) NULL)
2336  return(kernel);
2337  normalize=0.0;
2338  for (i=0; i < (ssize_t) width; i++)
2339  {
2340  kernel[i]=(MagickRealType) (exp((-((double) i*i)/(double) (2.0*MagickSigma*
2342  normalize+=kernel[i];
2343  }
2344  for (i=0; i < (ssize_t) width; i++)
2345  kernel[i]/=normalize;
2346  return(kernel);
2347 }
2348 
2349 MagickExport Image *MotionBlurImage(const Image *image,const double radius,
2350  const double sigma,const double angle,ExceptionInfo *exception)
2351 {
2352 #define BlurImageTag "Blur/Image"
2353 
2354  CacheView
2355  *blur_view,
2356  *image_view,
2357  *motion_view;
2358 
2359  Image
2360  *blur_image;
2361 
2363  status;
2364 
2366  progress;
2367 
2369  *kernel;
2370 
2371  OffsetInfo
2372  *offset;
2373 
2374  PointInfo
2375  point;
2376 
2377  ssize_t
2378  i;
2379 
2380  size_t
2381  width;
2382 
2383  ssize_t
2384  y;
2385 
2386  assert(image != (Image *) NULL);
2387  assert(image->signature == MagickCoreSignature);
2388  if (image->debug != MagickFalse)
2389  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2390  assert(exception != (ExceptionInfo *) NULL);
2391  width=GetOptimalKernelWidth1D(radius,sigma);
2392  kernel=GetMotionBlurKernel(width,sigma);
2393  if (kernel == (MagickRealType *) NULL)
2394  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2395  offset=(OffsetInfo *) AcquireQuantumMemory(width,sizeof(*offset));
2396  if (offset == (OffsetInfo *) NULL)
2397  {
2398  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2399  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
2400  }
2401  point.x=(double) width*sin(DegreesToRadians(angle));
2402  point.y=(double) width*cos(DegreesToRadians(angle));
2403  for (i=0; i < (ssize_t) width; i++)
2404  {
2405  offset[i].x=CastDoubleToLong(ceil((double) (i*point.y)/
2406  hypot(point.x,point.y)-0.5));
2407  offset[i].y=CastDoubleToLong(ceil((double) (i*point.x)/
2408  hypot(point.x,point.y)-0.5));
2409  }
2410  /*
2411  Motion blur image.
2412  */
2413 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2414  blur_image=AccelerateMotionBlurImage(image,kernel,width,offset,exception);
2415  if (blur_image != (Image *) NULL)
2416  {
2417  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2418  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2419  return(blur_image);
2420  }
2421 #endif
2422  blur_image=CloneImage(image,0,0,MagickTrue,exception);
2423  if (blur_image == (Image *) NULL)
2424  {
2425  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2426  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2427  return((Image *) NULL);
2428  }
2429  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
2430  {
2431  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2432  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2433  blur_image=DestroyImage(blur_image);
2434  return((Image *) NULL);
2435  }
2436  status=MagickTrue;
2437  progress=0;
2438  image_view=AcquireVirtualCacheView(image,exception);
2439  motion_view=AcquireVirtualCacheView(image,exception);
2440  blur_view=AcquireAuthenticCacheView(blur_image,exception);
2441 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2442  #pragma omp parallel for schedule(static) shared(progress,status) \
2443  magick_number_threads(image,blur_image,image->rows,1)
2444 #endif
2445  for (y=0; y < (ssize_t) image->rows; y++)
2446  {
2447  const Quantum
2448  *magick_restrict p;
2449 
2450  Quantum
2451  *magick_restrict q;
2452 
2453  ssize_t
2454  x;
2455 
2456  if (status == MagickFalse)
2457  continue;
2458  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2459  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
2460  exception);
2461  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2462  {
2463  status=MagickFalse;
2464  continue;
2465  }
2466  for (x=0; x < (ssize_t) image->columns; x++)
2467  {
2468  ssize_t
2469  i;
2470 
2471  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2472  {
2473  double
2474  alpha,
2475  gamma,
2476  pixel;
2477 
2478  PixelChannel
2479  channel;
2480 
2481  PixelTrait
2482  blur_traits,
2483  traits;
2484 
2485  const Quantum
2486  *magick_restrict r;
2487 
2489  *magick_restrict k;
2490 
2491  ssize_t
2492  j;
2493 
2494  channel=GetPixelChannelChannel(image,i);
2495  traits=GetPixelChannelTraits(image,channel);
2496  blur_traits=GetPixelChannelTraits(blur_image,channel);
2497  if ((traits == UndefinedPixelTrait) ||
2498  (blur_traits == UndefinedPixelTrait))
2499  continue;
2500  if ((blur_traits & CopyPixelTrait) != 0)
2501  {
2502  SetPixelChannel(blur_image,channel,p[i],q);
2503  continue;
2504  }
2505  k=kernel;
2506  pixel=0.0;
2507  if ((blur_traits & BlendPixelTrait) == 0)
2508  {
2509  for (j=0; j < (ssize_t) width; j++)
2510  {
2511  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+
2512  offset[j].y,1,1,exception);
2513  if (r == (const Quantum *) NULL)
2514  {
2515  status=MagickFalse;
2516  continue;
2517  }
2518  pixel+=(*k)*r[i];
2519  k++;
2520  }
2521  SetPixelChannel(blur_image,channel,ClampToQuantum(pixel),q);
2522  continue;
2523  }
2524  alpha=0.0;
2525  gamma=0.0;
2526  for (j=0; j < (ssize_t) width; j++)
2527  {
2528  r=GetCacheViewVirtualPixels(motion_view,x+offset[j].x,y+offset[j].y,1,
2529  1,exception);
2530  if (r == (const Quantum *) NULL)
2531  {
2532  status=MagickFalse;
2533  continue;
2534  }
2535  alpha=(double) (QuantumScale*GetPixelAlpha(image,r));
2536  pixel+=(*k)*alpha*r[i];
2537  gamma+=(*k)*alpha;
2538  k++;
2539  }
2540  gamma=PerceptibleReciprocal(gamma);
2541  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
2542  }
2543  p+=GetPixelChannels(image);
2544  q+=GetPixelChannels(blur_image);
2545  }
2546  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
2547  status=MagickFalse;
2548  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2549  {
2551  proceed;
2552 
2553 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2554  #pragma omp atomic
2555 #endif
2556  progress++;
2557  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
2558  if (proceed == MagickFalse)
2559  status=MagickFalse;
2560  }
2561  }
2562  blur_view=DestroyCacheView(blur_view);
2563  motion_view=DestroyCacheView(motion_view);
2564  image_view=DestroyCacheView(image_view);
2565  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
2566  offset=(OffsetInfo *) RelinquishMagickMemory(offset);
2567  if (status == MagickFalse)
2568  blur_image=DestroyImage(blur_image);
2569  return(blur_image);
2570 }
2571 
2572 /*
2573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2574 % %
2575 % %
2576 % %
2577 % P r e v i e w I m a g e %
2578 % %
2579 % %
2580 % %
2581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582 %
2583 % PreviewImage() tiles 9 thumbnails of the specified image with an image
2584 % processing operation applied with varying parameters. This may be helpful
2585 % pin-pointing an appropriate parameter for a particular image processing
2586 % operation.
2587 %
2588 % The format of the PreviewImages method is:
2589 %
2590 % Image *PreviewImages(const Image *image,const PreviewType preview,
2591 % ExceptionInfo *exception)
2592 %
2593 % A description of each parameter follows:
2594 %
2595 % o image: the image.
2596 %
2597 % o preview: the image processing operation.
2598 %
2599 % o exception: return any errors or warnings in this structure.
2600 %
2601 */
2602 MagickExport Image *PreviewImage(const Image *image,const PreviewType preview,
2603  ExceptionInfo *exception)
2604 {
2605 #define NumberTiles 9
2606 #define PreviewImageTag "Preview/Image"
2607 #define DefaultPreviewGeometry "204x204+10+10"
2608 
2609  char
2610  factor[MagickPathExtent],
2611  label[MagickPathExtent];
2612 
2613  double
2614  degrees,
2615  gamma,
2616  percentage,
2617  radius,
2618  sigma,
2619  threshold;
2620 
2621  Image
2622  *images,
2623  *montage_image,
2624  *preview_image,
2625  *thumbnail;
2626 
2627  ImageInfo
2628  *preview_info;
2629 
2631  proceed;
2632 
2633  MontageInfo
2634  *montage_info;
2635 
2636  QuantizeInfo
2637  quantize_info;
2638 
2640  geometry;
2641 
2642  ssize_t
2643  i,
2644  x;
2645 
2646  size_t
2647  colors;
2648 
2649  ssize_t
2650  y;
2651 
2652  /*
2653  Open output image file.
2654  */
2655  assert(image != (Image *) NULL);
2656  assert(image->signature == MagickCoreSignature);
2657  if (image->debug != MagickFalse)
2658  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2659  colors=2;
2660  degrees=0.0;
2661  gamma=(-0.2f);
2662  preview_info=AcquireImageInfo();
2663  SetGeometry(image,&geometry);
2664  (void) ParseMetaGeometry(DefaultPreviewGeometry,&geometry.x,&geometry.y,
2665  &geometry.width,&geometry.height);
2666  images=NewImageList();
2667  percentage=12.5;
2668  GetQuantizeInfo(&quantize_info);
2669  radius=0.0;
2670  sigma=1.0;
2671  threshold=0.0;
2672  x=0;
2673  y=0;
2674  for (i=0; i < NumberTiles; i++)
2675  {
2676  thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
2677  if (thumbnail == (Image *) NULL)
2678  break;
2679  (void) SetImageProgressMonitor(thumbnail,(MagickProgressMonitor) NULL,
2680  (void *) NULL);
2681  (void) SetImageProperty(thumbnail,"label",DefaultTileLabel,exception);
2682  if (i == (NumberTiles/2))
2683  {
2684  (void) QueryColorCompliance("#dfdfdf",AllCompliance,
2685  &thumbnail->matte_color,exception);
2686  AppendImageToList(&images,thumbnail);
2687  continue;
2688  }
2689  switch (preview)
2690  {
2691  case RotatePreview:
2692  {
2693  degrees+=45.0;
2694  preview_image=RotateImage(thumbnail,degrees,exception);
2695  (void) FormatLocaleString(label,MagickPathExtent,"rotate %g",degrees);
2696  break;
2697  }
2698  case ShearPreview:
2699  {
2700  degrees+=5.0;
2701  preview_image=ShearImage(thumbnail,degrees,degrees,exception);
2702  (void) FormatLocaleString(label,MagickPathExtent,"shear %gx%g",degrees,
2703  2.0*degrees);
2704  break;
2705  }
2706  case RollPreview:
2707  {
2708  x=(ssize_t) ((i+1)*thumbnail->columns)/NumberTiles;
2709  y=(ssize_t) ((i+1)*thumbnail->rows)/NumberTiles;
2710  preview_image=RollImage(thumbnail,x,y,exception);
2711  (void) FormatLocaleString(label,MagickPathExtent,"roll %+.20gx%+.20g",
2712  (double) x,(double) y);
2713  break;
2714  }
2715  case HuePreview:
2716  {
2717  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2718  if (preview_image == (Image *) NULL)
2719  break;
2720  (void) FormatLocaleString(factor,MagickPathExtent,"100,100,%g",2.0*
2721  percentage);
2722  (void) ModulateImage(preview_image,factor,exception);
2723  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2724  break;
2725  }
2726  case SaturationPreview:
2727  {
2728  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2729  if (preview_image == (Image *) NULL)
2730  break;
2731  (void) FormatLocaleString(factor,MagickPathExtent,"100,%g",2.0*
2732  percentage);
2733  (void) ModulateImage(preview_image,factor,exception);
2734  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2735  break;
2736  }
2737  case BrightnessPreview:
2738  {
2739  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2740  if (preview_image == (Image *) NULL)
2741  break;
2742  (void) FormatLocaleString(factor,MagickPathExtent,"%g",2.0*percentage);
2743  (void) ModulateImage(preview_image,factor,exception);
2744  (void) FormatLocaleString(label,MagickPathExtent,"modulate %s",factor);
2745  break;
2746  }
2747  case GammaPreview:
2748  default:
2749  {
2750  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2751  if (preview_image == (Image *) NULL)
2752  break;
2753  gamma+=0.4f;
2754  (void) GammaImage(preview_image,gamma,exception);
2755  (void) FormatLocaleString(label,MagickPathExtent,"gamma %g",gamma);
2756  break;
2757  }
2758  case SpiffPreview:
2759  {
2760  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2761  if (preview_image != (Image *) NULL)
2762  for (x=0; x < i; x++)
2763  (void) ContrastImage(preview_image,MagickTrue,exception);
2764  (void) FormatLocaleString(label,MagickPathExtent,"contrast (%.20g)",
2765  (double) i+1);
2766  break;
2767  }
2768  case DullPreview:
2769  {
2770  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2771  if (preview_image == (Image *) NULL)
2772  break;
2773  for (x=0; x < i; x++)
2774  (void) ContrastImage(preview_image,MagickFalse,exception);
2775  (void) FormatLocaleString(label,MagickPathExtent,"+contrast (%.20g)",
2776  (double) i+1);
2777  break;
2778  }
2779  case GrayscalePreview:
2780  {
2781  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2782  if (preview_image == (Image *) NULL)
2783  break;
2784  colors<<=1;
2785  quantize_info.number_colors=colors;
2786  quantize_info.colorspace=GRAYColorspace;
2787  (void) QuantizeImage(&quantize_info,preview_image,exception);
2788  (void) FormatLocaleString(label,MagickPathExtent,
2789  "-colorspace gray -colors %.20g",(double) colors);
2790  break;
2791  }
2792  case QuantizePreview:
2793  {
2794  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2795  if (preview_image == (Image *) NULL)
2796  break;
2797  colors<<=1;
2798  quantize_info.number_colors=colors;
2799  (void) QuantizeImage(&quantize_info,preview_image,exception);
2800  (void) FormatLocaleString(label,MagickPathExtent,"colors %.20g",
2801  (double) colors);
2802  break;
2803  }
2804  case DespecklePreview:
2805  {
2806  for (x=0; x < (i-1); x++)
2807  {
2808  preview_image=DespeckleImage(thumbnail,exception);
2809  if (preview_image == (Image *) NULL)
2810  break;
2811  thumbnail=DestroyImage(thumbnail);
2812  thumbnail=preview_image;
2813  }
2814  preview_image=DespeckleImage(thumbnail,exception);
2815  if (preview_image == (Image *) NULL)
2816  break;
2817  (void) FormatLocaleString(label,MagickPathExtent,"despeckle (%.20g)",
2818  (double) i+1);
2819  break;
2820  }
2821  case ReduceNoisePreview:
2822  {
2823  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t)
2824  radius,(size_t) radius,exception);
2825  (void) FormatLocaleString(label,MagickPathExtent,"noise %g",radius);
2826  break;
2827  }
2828  case AddNoisePreview:
2829  {
2830  switch ((int) i)
2831  {
2832  case 0:
2833  {
2834  (void) CopyMagickString(factor,"uniform",MagickPathExtent);
2835  break;
2836  }
2837  case 1:
2838  {
2839  (void) CopyMagickString(factor,"gaussian",MagickPathExtent);
2840  break;
2841  }
2842  case 2:
2843  {
2844  (void) CopyMagickString(factor,"multiplicative",MagickPathExtent);
2845  break;
2846  }
2847  case 3:
2848  {
2849  (void) CopyMagickString(factor,"impulse",MagickPathExtent);
2850  break;
2851  }
2852  case 5:
2853  {
2854  (void) CopyMagickString(factor,"laplacian",MagickPathExtent);
2855  break;
2856  }
2857  case 6:
2858  {
2859  (void) CopyMagickString(factor,"Poisson",MagickPathExtent);
2860  break;
2861  }
2862  default:
2863  {
2864  (void) CopyMagickString(thumbnail->magick,"NULL",MagickPathExtent);
2865  break;
2866  }
2867  }
2868  preview_image=StatisticImage(thumbnail,NonpeakStatistic,(size_t) i,
2869  (size_t) i,exception);
2870  (void) FormatLocaleString(label,MagickPathExtent,"+noise %s",factor);
2871  break;
2872  }
2873  case SharpenPreview:
2874  {
2875  preview_image=SharpenImage(thumbnail,radius,sigma,exception);
2876  (void) FormatLocaleString(label,MagickPathExtent,"sharpen %gx%g",
2877  radius,sigma);
2878  break;
2879  }
2880  case BlurPreview:
2881  {
2882  preview_image=BlurImage(thumbnail,radius,sigma,exception);
2883  (void) FormatLocaleString(label,MagickPathExtent,"blur %gx%g",radius,
2884  sigma);
2885  break;
2886  }
2887  case ThresholdPreview:
2888  {
2889  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2890  if (preview_image == (Image *) NULL)
2891  break;
2892  (void) BilevelImage(thumbnail,(double) (percentage*((double)
2893  QuantumRange+1.0))/100.0,exception);
2894  (void) FormatLocaleString(label,MagickPathExtent,"threshold %g",
2895  (double) (percentage*((double) QuantumRange+1.0))/100.0);
2896  break;
2897  }
2898  case EdgeDetectPreview:
2899  {
2900  preview_image=EdgeImage(thumbnail,radius,exception);
2901  (void) FormatLocaleString(label,MagickPathExtent,"edge %g",radius);
2902  break;
2903  }
2904  case SpreadPreview:
2905  {
2906  preview_image=SpreadImage(thumbnail,image->interpolate,radius,
2907  exception);
2908  (void) FormatLocaleString(label,MagickPathExtent,"spread %g",
2909  radius+0.5);
2910  break;
2911  }
2912  case SolarizePreview:
2913  {
2914  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2915  if (preview_image == (Image *) NULL)
2916  break;
2917  (void) SolarizeImage(preview_image,(double) QuantumRange*percentage/
2918  100.0,exception);
2919  (void) FormatLocaleString(label,MagickPathExtent,"solarize %g",
2920  (QuantumRange*percentage)/100.0);
2921  break;
2922  }
2923  case ShadePreview:
2924  {
2925  degrees+=10.0;
2926  preview_image=ShadeImage(thumbnail,MagickTrue,degrees,degrees,
2927  exception);
2928  (void) FormatLocaleString(label,MagickPathExtent,"shade %gx%g",degrees,
2929  degrees);
2930  break;
2931  }
2932  case RaisePreview:
2933  {
2935  raise;
2936 
2937  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2938  if (preview_image == (Image *) NULL)
2939  break;
2940  raise.width=(size_t) (2*i+2);
2941  raise.height=(size_t) (2*i+2);
2942  raise.x=(i-1)/2;
2943  raise.y=(i-1)/2;
2944  (void) RaiseImage(preview_image,&raise,MagickTrue,exception);
2945  (void) FormatLocaleString(label,MagickPathExtent,
2946  "raise %.20gx%.20g%+.20g%+.20g",(double) raise.width,(double)
2947  raise.height,(double) raise.x,(double) raise.y);
2948  break;
2949  }
2950  case SegmentPreview:
2951  {
2952  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
2953  if (preview_image == (Image *) NULL)
2954  break;
2955  threshold+=0.4f;
2956  (void) SegmentImage(preview_image,sRGBColorspace,MagickFalse,threshold,
2957  threshold,exception);
2958  (void) FormatLocaleString(label,MagickPathExtent,"segment %gx%g",
2959  threshold,threshold);
2960  break;
2961  }
2962  case SwirlPreview:
2963  {
2964  preview_image=SwirlImage(thumbnail,degrees,image->interpolate,
2965  exception);
2966  (void) FormatLocaleString(label,MagickPathExtent,"swirl %g",degrees);
2967  degrees+=45.0;
2968  break;
2969  }
2970  case ImplodePreview:
2971  {
2972  degrees+=0.1f;
2973  preview_image=ImplodeImage(thumbnail,degrees,image->interpolate,
2974  exception);
2975  (void) FormatLocaleString(label,MagickPathExtent,"implode %g",degrees);
2976  break;
2977  }
2978  case WavePreview:
2979  {
2980  degrees+=5.0f;
2981  preview_image=WaveImage(thumbnail,0.5*degrees,2.0*degrees,
2982  image->interpolate,exception);
2983  (void) FormatLocaleString(label,MagickPathExtent,"wave %gx%g",0.5*
2984  degrees,2.0*degrees);
2985  break;
2986  }
2987  case OilPaintPreview:
2988  {
2989  preview_image=OilPaintImage(thumbnail,(double) radius,(double) sigma,
2990  exception);
2991  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
2992  radius,sigma);
2993  break;
2994  }
2996  {
2997  preview_image=CharcoalImage(thumbnail,(double) radius,(double) sigma,
2998  exception);
2999  (void) FormatLocaleString(label,MagickPathExtent,"charcoal %gx%g",
3000  radius,sigma);
3001  break;
3002  }
3003  case JPEGPreview:
3004  {
3005  char
3006  filename[MagickPathExtent];
3007 
3008  int
3009  file;
3010 
3012  status;
3013 
3014  preview_image=CloneImage(thumbnail,0,0,MagickTrue,exception);
3015  if (preview_image == (Image *) NULL)
3016  break;
3017  preview_info->quality=(size_t) percentage;
3018  (void) FormatLocaleString(factor,MagickPathExtent,"%.20g",(double)
3019  preview_info->quality);
3020  file=AcquireUniqueFileResource(filename);
3021  if (file != -1)
3022  file=close(file)-1;
3023  (void) FormatLocaleString(preview_image->filename,MagickPathExtent,
3024  "jpeg:%s",filename);
3025  status=WriteImage(preview_info,preview_image,exception);
3026  if (status != MagickFalse)
3027  {
3028  Image
3029  *quality_image;
3030 
3031  (void) CopyMagickString(preview_info->filename,
3032  preview_image->filename,MagickPathExtent);
3033  quality_image=ReadImage(preview_info,exception);
3034  if (quality_image != (Image *) NULL)
3035  {
3036  preview_image=DestroyImage(preview_image);
3037  preview_image=quality_image;
3038  }
3039  }
3040  (void) RelinquishUniqueFileResource(preview_image->filename);
3041  if ((GetBlobSize(preview_image)/1024) >= 1024)
3042  (void) FormatLocaleString(label,MagickPathExtent,"quality %s\n%gmb ",
3043  factor,(double) ((MagickOffsetType) GetBlobSize(preview_image))/
3044  1024.0/1024.0);
3045  else
3046  if (GetBlobSize(preview_image) >= 1024)
3047  (void) FormatLocaleString(label,MagickPathExtent,
3048  "quality %s\n%gkb ",factor,(double) ((MagickOffsetType)
3049  GetBlobSize(preview_image))/1024.0);
3050  else
3051  (void) FormatLocaleString(label,MagickPathExtent,
3052  "quality %s\n%.20gb ",factor,(double) ((MagickOffsetType)
3053  GetBlobSize(thumbnail)));
3054  break;
3055  }
3056  }
3057  thumbnail=DestroyImage(thumbnail);
3058  percentage+=12.5;
3059  radius+=0.5;
3060  sigma+=0.25;
3061  if (preview_image == (Image *) NULL)
3062  break;
3063  preview_image->alpha_trait=UndefinedPixelTrait;
3064  (void) DeleteImageProperty(preview_image,"label");
3065  (void) SetImageProperty(preview_image,"label",label,exception);
3066  AppendImageToList(&images,preview_image);
3068  NumberTiles);
3069  if (proceed == MagickFalse)
3070  break;
3071  }
3072  if (images == (Image *) NULL)
3073  {
3074  preview_info=DestroyImageInfo(preview_info);
3075  return((Image *) NULL);
3076  }
3077  /*
3078  Create the montage.
3079  */
3080  montage_info=CloneMontageInfo(preview_info,(MontageInfo *) NULL);
3081  (void) CopyMagickString(montage_info->filename,image->filename,
3083  montage_info->shadow=MagickTrue;
3084  (void) CloneString(&montage_info->tile,"3x3");
3085  (void) CloneString(&montage_info->geometry,DefaultPreviewGeometry);
3086  (void) CloneString(&montage_info->frame,DefaultTileFrame);
3087  montage_image=MontageImages(images,montage_info,exception);
3088  montage_info=DestroyMontageInfo(montage_info);
3089  images=DestroyImageList(images);
3090  if (montage_image == (Image *) NULL)
3091  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3092  if (montage_image->montage != (char *) NULL)
3093  {
3094  /*
3095  Free image directory.
3096  */
3097  montage_image->montage=(char *) RelinquishMagickMemory(
3098  montage_image->montage);
3099  if (image->directory != (char *) NULL)
3100  montage_image->directory=(char *) RelinquishMagickMemory(
3101  montage_image->directory);
3102  }
3103  preview_info=DestroyImageInfo(preview_info);
3104  return(montage_image);
3105 }
3106 
3107 /*
3108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3109 % %
3110 % %
3111 % %
3112 % R o t a t i o n a l B l u r I m a g e %
3113 % %
3114 % %
3115 % %
3116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117 %
3118 % RotationalBlurImage() applies a radial blur to the image.
3119 %
3120 % Andrew Protano contributed this effect.
3121 %
3122 % The format of the RotationalBlurImage method is:
3123 %
3124 % Image *RotationalBlurImage(const Image *image,const double angle,
3125 % ExceptionInfo *exception)
3126 %
3127 % A description of each parameter follows:
3128 %
3129 % o image: the image.
3130 %
3131 % o angle: the angle of the radial blur.
3132 %
3133 % o blur: the blur.
3134 %
3135 % o exception: return any errors or warnings in this structure.
3136 %
3137 */
3138 MagickExport Image *RotationalBlurImage(const Image *image,const double angle,
3139  ExceptionInfo *exception)
3140 {
3141  CacheView
3142  *blur_view,
3143  *image_view,
3144  *radial_view;
3145 
3146  double
3147  blur_radius,
3148  *cos_theta,
3149  offset,
3150  *sin_theta,
3151  theta;
3152 
3153  Image
3154  *blur_image;
3155 
3157  status;
3158 
3160  progress;
3161 
3162  PointInfo
3163  blur_center;
3164 
3165  ssize_t
3166  i;
3167 
3168  size_t
3169  n;
3170 
3171  ssize_t
3172  y;
3173 
3174  /*
3175  Allocate blur image.
3176  */
3177  assert(image != (Image *) NULL);
3178  assert(image->signature == MagickCoreSignature);
3179  if (image->debug != MagickFalse)
3180  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3181  assert(exception != (ExceptionInfo *) NULL);
3182  assert(exception->signature == MagickCoreSignature);
3183 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3184  blur_image=AccelerateRotationalBlurImage(image,angle,exception);
3185  if (blur_image != (Image *) NULL)
3186  return(blur_image);
3187 #endif
3188  blur_image=CloneImage(image,0,0,MagickTrue,exception);
3189  if (blur_image == (Image *) NULL)
3190  return((Image *) NULL);
3191  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3192  {
3193  blur_image=DestroyImage(blur_image);
3194  return((Image *) NULL);
3195  }
3196  blur_center.x=(double) (image->columns-1)/2.0;
3197  blur_center.y=(double) (image->rows-1)/2.0;
3198  blur_radius=hypot(blur_center.x,blur_center.y);
3199  n=(size_t) fabs(4.0*DegreesToRadians(angle)*sqrt((double) blur_radius)+2UL);
3200  theta=DegreesToRadians(angle)/(double) (n-1);
3201  cos_theta=(double *) AcquireQuantumMemory((size_t) n,sizeof(*cos_theta));
3202  sin_theta=(double *) AcquireQuantumMemory((size_t) n,sizeof(*sin_theta));
3203  if ((cos_theta == (double *) NULL) || (sin_theta == (double *) NULL))
3204  {
3205  if (cos_theta != (double *) NULL)
3206  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
3207  if (sin_theta != (double *) NULL)
3208  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
3209  blur_image=DestroyImage(blur_image);
3210  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3211  }
3212  offset=theta*(double) (n-1)/2.0;
3213  for (i=0; i < (ssize_t) n; i++)
3214  {
3215  cos_theta[i]=cos((double) (theta*i-offset));
3216  sin_theta[i]=sin((double) (theta*i-offset));
3217  }
3218  /*
3219  Radial blur image.
3220  */
3221  status=MagickTrue;
3222  progress=0;
3223  image_view=AcquireVirtualCacheView(image,exception);
3224  radial_view=AcquireVirtualCacheView(image,exception);
3225  blur_view=AcquireAuthenticCacheView(blur_image,exception);
3226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3227  #pragma omp parallel for schedule(static) shared(progress,status) \
3228  magick_number_threads(image,blur_image,image->rows,1)
3229 #endif
3230  for (y=0; y < (ssize_t) image->rows; y++)
3231  {
3232  const Quantum
3233  *magick_restrict p;
3234 
3235  Quantum
3236  *magick_restrict q;
3237 
3238  ssize_t
3239  x;
3240 
3241  if (status == MagickFalse)
3242  continue;
3243  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3244  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3245  exception);
3246  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3247  {
3248  status=MagickFalse;
3249  continue;
3250  }
3251  for (x=0; x < (ssize_t) image->columns; x++)
3252  {
3253  double
3254  radius;
3255 
3256  PointInfo
3257  center;
3258 
3259  ssize_t
3260  i;
3261 
3262  size_t
3263  step;
3264 
3265  center.x=(double) x-blur_center.x;
3266  center.y=(double) y-blur_center.y;
3267  radius=hypot((double) center.x,center.y);
3268  if (radius == 0)
3269  step=1;
3270  else
3271  {
3272  step=(size_t) (blur_radius/radius);
3273  if (step == 0)
3274  step=1;
3275  else
3276  if (step >= n)
3277  step=n-1;
3278  }
3279  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3280  {
3281  double
3282  gamma,
3283  pixel;
3284 
3285  PixelChannel
3286  channel;
3287 
3288  PixelTrait
3289  blur_traits,
3290  traits;
3291 
3292  const Quantum
3293  *magick_restrict r;
3294 
3295  ssize_t
3296  j;
3297 
3298  channel=GetPixelChannelChannel(image,i);
3299  traits=GetPixelChannelTraits(image,channel);
3300  blur_traits=GetPixelChannelTraits(blur_image,channel);
3301  if ((traits == UndefinedPixelTrait) ||
3302  (blur_traits == UndefinedPixelTrait))
3303  continue;
3304  if ((blur_traits & CopyPixelTrait) != 0)
3305  {
3306  SetPixelChannel(blur_image,channel,p[i],q);
3307  continue;
3308  }
3309  gamma=0.0;
3310  pixel=0.0;
3312  (channel == AlphaPixelChannel))
3313  {
3314  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3315  {
3316  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3317  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3318  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3319  1,1,exception);
3320  if (r == (const Quantum *) NULL)
3321  {
3322  status=MagickFalse;
3323  continue;
3324  }
3325  pixel+=r[i];
3326  gamma++;
3327  }
3328  gamma=PerceptibleReciprocal(gamma);
3329  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3330  continue;
3331  }
3332  for (j=0; j < (ssize_t) n; j+=(ssize_t) step)
3333  {
3334  double
3335  alpha;
3336 
3337  r=GetCacheViewVirtualPixels(radial_view, (ssize_t) (blur_center.x+
3338  center.x*cos_theta[j]-center.y*sin_theta[j]+0.5),(ssize_t)
3339  (blur_center.y+center.x*sin_theta[j]+center.y*cos_theta[j]+0.5),
3340  1,1,exception);
3341  if (r == (const Quantum *) NULL)
3342  {
3343  status=MagickFalse;
3344  continue;
3345  }
3346  alpha=(double) QuantumScale*GetPixelAlpha(image,r);
3347  pixel+=alpha*r[i];
3348  gamma+=alpha;
3349  }
3350  gamma=PerceptibleReciprocal(gamma);
3351  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3352  }
3353  p+=GetPixelChannels(image);
3354  q+=GetPixelChannels(blur_image);
3355  }
3356  if (SyncCacheViewAuthenticPixels(blur_view,exception) == MagickFalse)
3357  status=MagickFalse;
3358  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3359  {
3361  proceed;
3362 
3363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3364  #pragma omp atomic
3365 #endif
3366  progress++;
3367  proceed=SetImageProgress(image,BlurImageTag,progress,image->rows);
3368  if (proceed == MagickFalse)
3369  status=MagickFalse;
3370  }
3371  }
3372  blur_view=DestroyCacheView(blur_view);
3373  radial_view=DestroyCacheView(radial_view);
3374  image_view=DestroyCacheView(image_view);
3375  cos_theta=(double *) RelinquishMagickMemory(cos_theta);
3376  sin_theta=(double *) RelinquishMagickMemory(sin_theta);
3377  if (status == MagickFalse)
3378  blur_image=DestroyImage(blur_image);
3379  return(blur_image);
3380 }
3381 
3382 /*
3383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 % %
3385 % %
3386 % %
3387 % S e l e c t i v e B l u r I m a g e %
3388 % %
3389 % %
3390 % %
3391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392 %
3393 % SelectiveBlurImage() selectively blur pixels within a contrast threshold.
3394 % It is similar to the unsharpen mask that sharpens everything with contrast
3395 % above a certain threshold.
3396 %
3397 % The format of the SelectiveBlurImage method is:
3398 %
3399 % Image *SelectiveBlurImage(const Image *image,const double radius,
3400 % const double sigma,const double threshold,ExceptionInfo *exception)
3401 %
3402 % A description of each parameter follows:
3403 %
3404 % o image: the image.
3405 %
3406 % o radius: the radius of the Gaussian, in pixels, not counting the center
3407 % pixel.
3408 %
3409 % o sigma: the standard deviation of the Gaussian, in pixels.
3410 %
3411 % o threshold: only pixels within this contrast threshold are included
3412 % in the blur operation.
3413 %
3414 % o exception: return any errors or warnings in this structure.
3415 %
3416 */
3417 MagickExport Image *SelectiveBlurImage(const Image *image,const double radius,
3418  const double sigma,const double threshold,ExceptionInfo *exception)
3419 {
3420 #define SelectiveBlurImageTag "SelectiveBlur/Image"
3421 
3422  CacheView
3423  *blur_view,
3424  *image_view,
3425  *luminance_view;
3426 
3427  Image
3428  *blur_image,
3429  *luminance_image;
3430 
3432  status;
3433 
3435  progress;
3436 
3438  *kernel;
3439 
3440  ssize_t
3441  i;
3442 
3443  size_t
3444  width;
3445 
3446  ssize_t
3447  center,
3448  j,
3449  u,
3450  v,
3451  y;
3452 
3453  /*
3454  Initialize blur image attributes.
3455  */
3456  assert(image != (Image *) NULL);
3457  assert(image->signature == MagickCoreSignature);
3458  if (image->debug != MagickFalse)
3459  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3460  assert(exception != (ExceptionInfo *) NULL);
3461  assert(exception->signature == MagickCoreSignature);
3462  width=GetOptimalKernelWidth1D(radius,sigma);
3464  width,width*sizeof(*kernel)));
3465  if (kernel == (MagickRealType *) NULL)
3466  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3467  j=(ssize_t) (width-1)/2;
3468  i=0;
3469  for (v=(-j); v <= j; v++)
3470  {
3471  for (u=(-j); u <= j; u++)
3472  kernel[i++]=(MagickRealType) (exp(-((double) u*u+v*v)/(2.0*MagickSigma*
3474  }
3475  if (image->debug != MagickFalse)
3476  {
3477  char
3478  format[MagickPathExtent],
3479  *message;
3480 
3481  const MagickRealType
3482  *k;
3483 
3484  ssize_t
3485  u,
3486  v;
3487 
3489  " SelectiveBlurImage with %.20gx%.20g kernel:",(double) width,(double)
3490  width);
3491  message=AcquireString("");
3492  k=kernel;
3493  for (v=0; v < (ssize_t) width; v++)
3494  {
3495  *message='\0';
3496  (void) FormatLocaleString(format,MagickPathExtent,"%.20g: ",(double) v);
3497  (void) ConcatenateString(&message,format);
3498  for (u=0; u < (ssize_t) width; u++)
3499  {
3500  (void) FormatLocaleString(format,MagickPathExtent,"%+f ",(double)
3501  *k++);
3502  (void) ConcatenateString(&message,format);
3503  }
3504  (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
3505  }
3506  message=DestroyString(message);
3507  }
3508  blur_image=CloneImage(image,0,0,MagickTrue,exception);
3509  if (blur_image == (Image *) NULL)
3510  return((Image *) NULL);
3511  if (SetImageStorageClass(blur_image,DirectClass,exception) == MagickFalse)
3512  {
3513  blur_image=DestroyImage(blur_image);
3514  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3515  return((Image *) NULL);
3516  }
3517  luminance_image=CloneImage(image,0,0,MagickTrue,exception);
3518  if (luminance_image == (Image *) NULL)
3519  {
3520  blur_image=DestroyImage(blur_image);
3521  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3522  return((Image *) NULL);
3523  }
3524  status=TransformImageColorspace(luminance_image,GRAYColorspace,exception);
3525  if (status == MagickFalse)
3526  {
3527  luminance_image=DestroyImage(luminance_image);
3528  blur_image=DestroyImage(blur_image);
3529  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3530  return((Image *) NULL);
3531  }
3532  /*
3533  Threshold blur image.
3534  */
3535  status=MagickTrue;
3536  progress=0;
3537  center=(ssize_t) (GetPixelChannels(image)*(image->columns+width)*
3538  ((width-1)/2L)+GetPixelChannels(image)*((width-1)/2L));
3539  image_view=AcquireVirtualCacheView(image,exception);
3540  luminance_view=AcquireVirtualCacheView(luminance_image,exception);
3541  blur_view=AcquireAuthenticCacheView(blur_image,exception);
3542 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3543  #pragma omp parallel for schedule(static) shared(progress,status) \
3544  magick_number_threads(image,blur_image,image->rows,1)
3545 #endif
3546  for (y=0; y < (ssize_t) image->rows; y++)
3547  {
3548  double
3549  contrast;
3550 
3552  sync;
3553 
3554  const Quantum
3555  *magick_restrict l,
3556  *magick_restrict p;
3557 
3558  Quantum
3559  *magick_restrict q;
3560 
3561  ssize_t
3562  x;
3563 
3564  if (status == MagickFalse)
3565  continue;
3566  p=GetCacheViewVirtualPixels(image_view,-((ssize_t) (width-1)/2L),y-(ssize_t)
3567  ((width-1)/2L),image->columns+width,width,exception);
3568  l=GetCacheViewVirtualPixels(luminance_view,-((ssize_t) (width-1)/2L),y-
3569  (ssize_t) ((width-1)/2L),luminance_image->columns+width,width,exception);
3570  q=QueueCacheViewAuthenticPixels(blur_view,0,y,blur_image->columns,1,
3571  exception);
3572  if ((p == (const Quantum *) NULL) || (l == (const Quantum *) NULL) ||
3573  (q == (Quantum *) NULL))
3574  {
3575  status=MagickFalse;
3576  continue;
3577  }
3578  for (x=0; x < (ssize_t) image->columns; x++)
3579  {
3580  double
3581  intensity;
3582 
3583  ssize_t
3584  i;
3585 
3586  intensity=GetPixelIntensity(image,p+center);
3587  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3588  {
3589  double
3590  alpha,
3591  gamma,
3592  pixel;
3593 
3594  PixelChannel
3595  channel;
3596 
3597  PixelTrait
3598  blur_traits,
3599  traits;
3600 
3601  const MagickRealType
3602  *magick_restrict k;
3603 
3604  const Quantum
3605  *magick_restrict luminance_pixels,
3606  *magick_restrict pixels;
3607 
3608  ssize_t
3609  u;
3610 
3611  ssize_t
3612  v;
3613 
3614  channel=GetPixelChannelChannel(image,i);
3615  traits=GetPixelChannelTraits(image,channel);
3616  blur_traits=GetPixelChannelTraits(blur_image,channel);
3617  if ((traits == UndefinedPixelTrait) ||
3618  (blur_traits == UndefinedPixelTrait))
3619  continue;
3620  if ((blur_traits & CopyPixelTrait) != 0)
3621  {
3622  SetPixelChannel(blur_image,channel,p[center+i],q);
3623  continue;
3624  }
3625  k=kernel;
3626  pixel=0.0;
3627  pixels=p;
3628  luminance_pixels=l;
3629  gamma=0.0;
3630  if ((blur_traits & BlendPixelTrait) == 0)
3631  {
3632  for (v=0; v < (ssize_t) width; v++)
3633  {
3634  for (u=0; u < (ssize_t) width; u++)
3635  {
3636  contrast=GetPixelIntensity(luminance_image,luminance_pixels)-
3637  intensity;
3638  if (fabs(contrast) < threshold)
3639  {
3640  pixel+=(*k)*pixels[i];
3641  gamma+=(*k);
3642  }
3643  k++;
3644  pixels+=GetPixelChannels(image);
3645  luminance_pixels+=GetPixelChannels(luminance_image);
3646  }
3647  pixels+=GetPixelChannels(image)*image->columns;
3648  luminance_pixels+=GetPixelChannels(luminance_image)*
3649  luminance_image->columns;
3650  }
3651  if (fabs((double) gamma) < MagickEpsilon)
3652  {
3653  SetPixelChannel(blur_image,channel,p[center+i],q);
3654  continue;
3655  }
3656  gamma=PerceptibleReciprocal(gamma);
3657  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3658  continue;
3659  }
3660  for (v=0; v < (ssize_t) width; v++)
3661  {
3662  for (u=0; u < (ssize_t) width; u++)
3663  {
3664  contrast=GetPixelIntensity(image,pixels)-intensity;
3665  if (fabs(contrast) < threshold)
3666  {
3667  alpha=(double) (QuantumScale*GetPixelAlpha(image,pixels));
3668  pixel+=(*k)*alpha*pixels[i];
3669  gamma+=(*k)*alpha;
3670  }
3671  k++;
3672  pixels+=GetPixelChannels(image);
3673  luminance_pixels+=GetPixelChannels(luminance_image);
3674  }
3675  pixels+=GetPixelChannels(image)*image->columns;
3676  luminance_pixels+=GetPixelChannels(luminance_image)*
3677  luminance_image->columns;
3678  }
3679  if (fabs((double) gamma) < MagickEpsilon)
3680  {
3681  SetPixelChannel(blur_image,channel,p[center+i],q);
3682  continue;
3683  }
3684  gamma=PerceptibleReciprocal(gamma);
3685  SetPixelChannel(blur_image,channel,ClampToQuantum(gamma*pixel),q);
3686  }
3687  p+=GetPixelChannels(image);
3688  l+=GetPixelChannels(luminance_image);
3689  q+=GetPixelChannels(blur_image);
3690  }
3691  sync=SyncCacheViewAuthenticPixels(blur_view,exception);
3692  if (sync == MagickFalse)
3693  status=MagickFalse;
3694  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3695  {
3697  proceed;
3698 
3699 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3700  #pragma omp atomic
3701 #endif
3702  progress++;
3703  proceed=SetImageProgress(image,SelectiveBlurImageTag,progress,
3704  image->rows);
3705  if (proceed == MagickFalse)
3706  status=MagickFalse;
3707  }
3708  }
3709  blur_image->type=image->type;
3710  blur_view=DestroyCacheView(blur_view);
3711  luminance_view=DestroyCacheView(luminance_view);
3712  image_view=DestroyCacheView(image_view);
3713  luminance_image=DestroyImage(luminance_image);
3714  kernel=(MagickRealType *) RelinquishAlignedMemory(kernel);
3715  if (status == MagickFalse)
3716  blur_image=DestroyImage(blur_image);
3717  return(blur_image);
3718 }
3719 
3720 /*
3721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722 % %
3723 % %
3724 % %
3725 % S h a d e I m a g e %
3726 % %
3727 % %
3728 % %
3729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730 %
3731 % ShadeImage() shines a distant light on an image to create a
3732 % three-dimensional effect. You control the positioning of the light with
3733 % azimuth and elevation; azimuth is measured in degrees off the x axis
3734 % and elevation is measured in pixels above the Z axis.
3735 %
3736 % The format of the ShadeImage method is:
3737 %
3738 % Image *ShadeImage(const Image *image,const MagickBooleanType gray,
3739 % const double azimuth,const double elevation,ExceptionInfo *exception)
3740 %
3741 % A description of each parameter follows:
3742 %
3743 % o image: the image.
3744 %
3745 % o gray: A value other than zero shades the intensity of each pixel.
3746 %
3747 % o azimuth, elevation: Define the light source direction.
3748 %
3749 % o exception: return any errors or warnings in this structure.
3750 %
3751 */
3753  const double azimuth,const double elevation,ExceptionInfo *exception)
3754 {
3755 #define GetShadeIntensity(image,pixel) \
3756  ClampPixel(GetPixelIntensity((image),(pixel)))
3757 #define ShadeImageTag "Shade/Image"
3758 
3759  CacheView
3760  *image_view,
3761  *shade_view;
3762 
3763  Image
3764  *linear_image,
3765  *shade_image;
3766 
3768  status;
3769 
3771  progress;
3772 
3773  PrimaryInfo
3774  light;
3775 
3776  ssize_t
3777  y;
3778 
3779  /*
3780  Initialize shaded image attributes.
3781  */
3782  assert(image != (const Image *) NULL);
3783  assert(image->signature == MagickCoreSignature);
3784  if (image->debug != MagickFalse)
3785  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3786  assert(exception != (ExceptionInfo *) NULL);
3787  assert(exception->signature == MagickCoreSignature);
3788  linear_image=CloneImage(image,0,0,MagickTrue,exception);
3789  shade_image=CloneImage(image,0,0,MagickTrue,exception);
3790  if ((linear_image == (Image *) NULL) || (shade_image == (Image *) NULL))
3791  {
3792  if (linear_image != (Image *) NULL)
3793  linear_image=DestroyImage(linear_image);
3794  if (shade_image != (Image *) NULL)
3795  shade_image=DestroyImage(shade_image);
3796  return((Image *) NULL);
3797  }
3798  if (SetImageStorageClass(shade_image,DirectClass,exception) == MagickFalse)
3799  {
3800  linear_image=DestroyImage(linear_image);
3801  shade_image=DestroyImage(shade_image);
3802  return((Image *) NULL);
3803  }
3804  /*
3805  Compute the light vector.
3806  */
3807  light.x=(double) QuantumRange*cos(DegreesToRadians(azimuth))*
3808  cos(DegreesToRadians(elevation));
3809  light.y=(double) QuantumRange*sin(DegreesToRadians(azimuth))*
3810  cos(DegreesToRadians(elevation));
3811  light.z=(double) QuantumRange*sin(DegreesToRadians(elevation));
3812  /*
3813  Shade image.
3814  */
3815  status=MagickTrue;
3816  progress=0;
3817  image_view=AcquireVirtualCacheView(linear_image,exception);
3818  shade_view=AcquireAuthenticCacheView(shade_image,exception);
3819 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3820  #pragma omp parallel for schedule(static) shared(progress,status) \
3821  magick_number_threads(linear_image,shade_image,linear_image->rows,1)
3822 #endif
3823  for (y=0; y < (ssize_t) linear_image->rows; y++)
3824  {
3825  double
3826  distance,
3827  normal_distance,
3828  shade;
3829 
3830  PrimaryInfo
3831  normal;
3832 
3833  const Quantum
3834  *magick_restrict center,
3835  *magick_restrict p,
3836  *magick_restrict post,
3837  *magick_restrict pre;
3838 
3839  Quantum
3840  *magick_restrict q;
3841 
3842  ssize_t
3843  x;
3844 
3845  if (status == MagickFalse)
3846  continue;
3847  p=GetCacheViewVirtualPixels(image_view,-1,y-1,linear_image->columns+2,3,
3848  exception);
3849  q=QueueCacheViewAuthenticPixels(shade_view,0,y,shade_image->columns,1,
3850  exception);
3851  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3852  {
3853  status=MagickFalse;
3854  continue;
3855  }
3856  /*
3857  Shade this row of pixels.
3858  */
3859  normal.z=2.0*(double) QuantumRange; /* constant Z of surface normal */
3860  for (x=0; x < (ssize_t) linear_image->columns; x++)
3861  {
3862  ssize_t
3863  i;
3864 
3865  /*
3866  Determine the surface normal and compute shading.
3867  */
3868  pre=p+GetPixelChannels(linear_image);
3869  center=pre+(linear_image->columns+2)*GetPixelChannels(linear_image);
3870  post=center+(linear_image->columns+2)*GetPixelChannels(linear_image);
3871  normal.x=(double) (
3872  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))+
3873  GetShadeIntensity(linear_image,center-GetPixelChannels(linear_image))+
3874  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))-
3875  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image))-
3876  GetShadeIntensity(linear_image,center+GetPixelChannels(linear_image))-
3877  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image)));
3878  normal.y=(double) (
3879  GetShadeIntensity(linear_image,post-GetPixelChannels(linear_image))+
3880  GetShadeIntensity(linear_image,post)+
3881  GetShadeIntensity(linear_image,post+GetPixelChannels(linear_image))-
3882  GetShadeIntensity(linear_image,pre-GetPixelChannels(linear_image))-
3883  GetShadeIntensity(linear_image,pre)-
3884  GetShadeIntensity(linear_image,pre+GetPixelChannels(linear_image)));
3885  if ((fabs(normal.x) <= MagickEpsilon) &&
3886  (fabs(normal.y) <= MagickEpsilon))
3887  shade=light.z;
3888  else
3889  {
3890  shade=0.0;
3891  distance=normal.x*light.x+normal.y*light.y+normal.z*light.z;
3892  if (distance > MagickEpsilon)
3893  {
3894  normal_distance=normal.x*normal.x+normal.y*normal.y+
3895  normal.z*normal.z;
3896  if (normal_distance > (MagickEpsilon*MagickEpsilon))
3897  shade=distance/sqrt((double) normal_distance);
3898  }
3899  }
3900  for (i=0; i < (ssize_t) GetPixelChannels(linear_image); i++)
3901  {
3902  PixelChannel
3903  channel;
3904 
3905  PixelTrait
3906  shade_traits,
3907  traits;
3908 
3909  channel=GetPixelChannelChannel(linear_image,i);
3910  traits=GetPixelChannelTraits(linear_image,channel);
3911  shade_traits=GetPixelChannelTraits(shade_image,channel);
3912  if ((traits == UndefinedPixelTrait) ||
3913  (shade_traits == UndefinedPixelTrait))
3914  continue;
3915  if ((shade_traits & CopyPixelTrait) != 0)
3916  {
3917  SetPixelChannel(shade_image,channel,center[i],q);
3918  continue;
3919  }
3920  if ((traits & UpdatePixelTrait) == 0)
3921  {
3922  SetPixelChannel(shade_image,channel,center[i],q);
3923  continue;
3924  }
3925  if (gray != MagickFalse)
3926  {
3927  SetPixelChannel(shade_image,channel,ClampToQuantum(shade),q);
3928  continue;
3929  }
3930  SetPixelChannel(shade_image,channel,ClampToQuantum(QuantumScale*shade*
3931  center[i]),q);
3932  }
3933  p+=GetPixelChannels(linear_image);
3934  q+=GetPixelChannels(shade_image);
3935  }
3936  if (SyncCacheViewAuthenticPixels(shade_view,exception) == MagickFalse)
3937  status=MagickFalse;
3938  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3939  {
3941  proceed;
3942 
3943 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3944  #pragma omp atomic
3945 #endif
3946  progress++;
3947  proceed=SetImageProgress(image,ShadeImageTag,progress,image->rows);
3948  if (proceed == MagickFalse)
3949  status=MagickFalse;
3950  }
3951  }
3952  shade_view=DestroyCacheView(shade_view);
3953  image_view=DestroyCacheView(image_view);
3954  linear_image=DestroyImage(linear_image);
3955  if (status == MagickFalse)
3956  shade_image=DestroyImage(shade_image);
3957  return(shade_image);
3958 }
3959 
3960 /*
3961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3962 % %
3963 % %
3964 % %
3965 % S h a r p e n I m a g e %
3966 % %
3967 % %
3968 % %
3969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3970 %
3971 % SharpenImage() sharpens the image. We convolve the image with a Gaussian
3972 % operator of the given radius and standard deviation (sigma). For
3973 % reasonable results, radius should be larger than sigma. Use a radius of 0
3974 % and SharpenImage() selects a suitable radius for you.
3975 %
3976 % Using a separable kernel would be faster, but the negative weights cancel
3977 % out on the corners of the kernel producing often undesirable ringing in the
3978 % filtered result; this can be avoided by using a 2D gaussian shaped image
3979 % sharpening kernel instead.
3980 %
3981 % The format of the SharpenImage method is:
3982 %
3983 % Image *SharpenImage(const Image *image,const double radius,
3984 % const double sigma,ExceptionInfo *exception)
3985 %
3986 % A description of each parameter follows:
3987 %
3988 % o image: the image.
3989 %
3990 % o radius: the radius of the Gaussian, in pixels, not counting the center
3991 % pixel.
3992 %
3993 % o sigma: the standard deviation of the Laplacian, in pixels.
3994 %
3995 % o exception: return any errors or warnings in this structure.
3996 %
3997 */
3998 MagickExport Image *SharpenImage(const Image *image,const double radius,
3999  const double sigma,ExceptionInfo *exception)
4000 {
4001  double
4002  gamma,
4003  normalize;
4004 
4005  Image
4006  *sharp_image;
4007 
4008  KernelInfo
4009  *kernel_info;
4010 
4011  ssize_t
4012  i;
4013 
4014  size_t
4015  width;
4016 
4017  ssize_t
4018  j,
4019  u,
4020  v;
4021 
4022  assert(image != (const Image *) NULL);
4023  assert(image->signature == MagickCoreSignature);
4024  if (image->debug != MagickFalse)
4025  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4026  assert(exception != (ExceptionInfo *) NULL);
4027  assert(exception->signature == MagickCoreSignature);
4028  width=GetOptimalKernelWidth2D(radius,sigma);
4029  kernel_info=AcquireKernelInfo((const char *) NULL,exception);
4030  if (kernel_info == (KernelInfo *) NULL)
4031  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
4032  (void) memset(kernel_info,0,sizeof(*kernel_info));
4033  kernel_info->width=width;
4034  kernel_info->height=width;
4035  kernel_info->x=(ssize_t) (width-1)/2;
4036  kernel_info->y=(ssize_t) (width-1)/2;
4037  kernel_info->signature=MagickCoreSignature;
4038  kernel_info->values=(MagickRealType *) MagickAssumeAligned(
4039  AcquireAlignedMemory(kernel_info->width,kernel_info->height*
4040  sizeof(*kernel_info->values)));
4041  if (kernel_info->values == (MagickRealType *) NULL)
4042  {
4043  kernel_info=DestroyKernelInfo(kernel_info);
4044  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
4045  }
4046  normalize=0.0;
4047  j=(ssize_t) (kernel_info->width-1)/2;
4048  i=0;
4049  for (v=(-j); v <= j; v++)
4050  {
4051  for (u=(-j); u <= j; u++)
4052  {
4053  kernel_info->values[i]=(MagickRealType) (-exp(-((double) u*u+v*v)/(2.0*
4055  normalize+=kernel_info->values[i];
4056  i++;
4057  }
4058  }
4059  kernel_info->values[i/2]=(double) ((-2.0)*normalize);
4060  normalize=0.0;
4061  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4062  normalize+=kernel_info->values[i];
4063  gamma=PerceptibleReciprocal(normalize);
4064  for (i=0; i < (ssize_t) (kernel_info->width*kernel_info->height); i++)
4065  kernel_info->values[i]*=gamma;
4066  sharp_image=ConvolveImage(image,kernel_info,exception);
4067  kernel_info=DestroyKernelInfo(kernel_info);
4068  return(sharp_image);
4069 }
4070 
4071 /*
4072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073 % %
4074 % %
4075 % %
4076 % S p r e a d I m a g e %
4077 % %
4078 % %
4079 % %
4080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4081 %
4082 % SpreadImage() is a special effects method that randomly displaces each
4083 % pixel in a square area defined by the radius parameter.
4084 %
4085 % The format of the SpreadImage method is:
4086 %
4087 % Image *SpreadImage(const Image *image,
4088 % const PixelInterpolateMethod method,const double radius,
4089 % ExceptionInfo *exception)
4090 %
4091 % A description of each parameter follows:
4092 %
4093 % o image: the image.
4094 %
4095 % o method: intepolation method.
4096 %
4097 % o radius: choose a random pixel in a neighborhood of this extent.
4098 %
4099 % o exception: return any errors or warnings in this structure.
4100 %
4101 */
4103  const PixelInterpolateMethod method,const double radius,
4104  ExceptionInfo *exception)
4105 {
4106 #define SpreadImageTag "Spread/Image"
4107 
4108  CacheView
4109  *image_view,
4110  *spread_view;
4111 
4112  Image
4113  *spread_image;
4114 
4116  status;
4117 
4119  progress;
4120 
4121  RandomInfo
4123 
4124  size_t
4125  width;
4126 
4127  ssize_t
4128  y;
4129 
4130 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4131  unsigned long
4132  key;
4133 #endif
4134 
4135  /*
4136  Initialize spread image attributes.
4137  */
4138  assert(image != (Image *) NULL);
4139  assert(image->signature == MagickCoreSignature);
4140  if (image->debug != MagickFalse)
4141  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4142  assert(exception != (ExceptionInfo *) NULL);
4143  assert(exception->signature == MagickCoreSignature);
4144  spread_image=CloneImage(image,0,0,MagickTrue,exception);
4145  if (spread_image == (Image *) NULL)
4146  return((Image *) NULL);
4147  if (SetImageStorageClass(spread_image,DirectClass,exception) == MagickFalse)
4148  {
4149  spread_image=DestroyImage(spread_image);
4150  return((Image *) NULL);
4151  }
4152  /*
4153  Spread image.
4154  */
4155  status=MagickTrue;
4156  progress=0;
4157  width=GetOptimalKernelWidth1D(radius,0.5);
4159  image_view=AcquireVirtualCacheView(image,exception);
4160  spread_view=AcquireAuthenticCacheView(spread_image,exception);
4161 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4163  #pragma omp parallel for schedule(static) shared(progress,status) \
4164  magick_number_threads(image,spread_image,image->rows,key == ~0UL)
4165 #endif
4166  for (y=0; y < (ssize_t) image->rows; y++)
4167  {
4168  const int
4169  id = GetOpenMPThreadId();
4170 
4171  Quantum
4172  *magick_restrict q;
4173 
4174  ssize_t
4175  x;
4176 
4177  if (status == MagickFalse)
4178  continue;
4179  q=QueueCacheViewAuthenticPixels(spread_view,0,y,spread_image->columns,1,
4180  exception);
4181  if (q == (Quantum *) NULL)
4182  {
4183  status=MagickFalse;
4184  continue;
4185  }
4186  for (x=0; x < (ssize_t) image->columns; x++)
4187  {
4188  PointInfo
4189  point;
4190 
4191  point.x=GetPseudoRandomValue(random_info[id]);
4192  point.y=GetPseudoRandomValue(random_info[id]);
4193  status=InterpolatePixelChannels(image,image_view,spread_image,method,
4194  (double) x+width*(point.x-0.5),(double) y+width*(point.y-0.5),q,
4195  exception);
4196  if (status == MagickFalse)
4197  break;
4198  q+=GetPixelChannels(spread_image);
4199  }
4200  if (SyncCacheViewAuthenticPixels(spread_view,exception) == MagickFalse)
4201  status=MagickFalse;
4202  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4203  {
4205  proceed;
4206 
4207 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4208  #pragma omp atomic
4209 #endif
4210  progress++;
4211  proceed=SetImageProgress(image,SpreadImageTag,progress,image->rows);
4212  if (proceed == MagickFalse)
4213  status=MagickFalse;
4214  }
4215  }
4216  spread_view=DestroyCacheView(spread_view);
4217  image_view=DestroyCacheView(image_view);
4219  if (status == MagickFalse)
4220  spread_image=DestroyImage(spread_image);
4221  return(spread_image);
4222 }
4223 
4224 /*
4225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4226 % %
4227 % %
4228 % %
4229 % U n s h a r p M a s k I m a g e %
4230 % %
4231 % %
4232 % %
4233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4234 %
4235 % UnsharpMaskImage() sharpens one or more image channels. We convolve the
4236 % image with a Gaussian operator of the given radius and standard deviation
4237 % (sigma). For reasonable results, radius should be larger than sigma. Use a
4238 % radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
4239 %
4240 % The format of the UnsharpMaskImage method is:
4241 %
4242 % Image *UnsharpMaskImage(const Image *image,const double radius,
4243 % const double sigma,const double amount,const double threshold,
4244 % ExceptionInfo *exception)
4245 %
4246 % A description of each parameter follows:
4247 %
4248 % o image: the image.
4249 %
4250 % o radius: the radius of the Gaussian, in pixels, not counting the center
4251 % pixel.
4252 %
4253 % o sigma: the standard deviation of the Gaussian, in pixels.
4254 %
4255 % o gain: the percentage of the difference between the original and the
4256 % blur image that is added back into the original.
4257 %
4258 % o threshold: the threshold in pixels needed to apply the diffence gain.
4259 %
4260 % o exception: return any errors or warnings in this structure.
4261 %
4262 */
4263 MagickExport Image *UnsharpMaskImage(const Image *image,const double radius,
4264  const double sigma,const double gain,const double threshold,
4265  ExceptionInfo *exception)
4266 {
4267 #define SharpenImageTag "Sharpen/Image"
4268 
4269  CacheView
4270  *image_view,
4271  *unsharp_view;
4272 
4273  Image
4274  *unsharp_image;
4275 
4277  status;
4278 
4280  progress;
4281 
4282  double
4283  quantum_threshold;
4284 
4285  ssize_t
4286  y;
4287 
4288  assert(image != (const Image *) NULL);
4289  assert(image->signature == MagickCoreSignature);
4290  if (image->debug != MagickFalse)
4291  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4292  assert(exception != (ExceptionInfo *) NULL);
4293 /* This kernel appears to be broken.
4294 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4295  unsharp_image=AccelerateUnsharpMaskImage(image,radius,sigma,gain,threshold,
4296  exception);
4297  if (unsharp_image != (Image *) NULL)
4298  return(unsharp_image);
4299 #endif
4300 */
4301  unsharp_image=BlurImage(image,radius,sigma,exception);
4302  if (unsharp_image == (Image *) NULL)
4303  return((Image *) NULL);
4304  quantum_threshold=(double) QuantumRange*threshold;
4305  /*
4306  Unsharp-mask image.
4307  */
4308  status=MagickTrue;
4309  progress=0;
4310  image_view=AcquireVirtualCacheView(image,exception);
4311  unsharp_view=AcquireAuthenticCacheView(unsharp_image,exception);
4312 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4313  #pragma omp parallel for schedule(static) shared(progress,status) \
4314  magick_number_threads(image,unsharp_image,image->rows,1)
4315 #endif
4316  for (y=0; y < (ssize_t) image->rows; y++)
4317  {
4318  const Quantum
4319  *magick_restrict p;
4320 
4321  Quantum
4322  *magick_restrict q;
4323 
4324  ssize_t
4325  x;
4326 
4327  if (status == MagickFalse)
4328  continue;
4329  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4330  q=QueueCacheViewAuthenticPixels(unsharp_view,0,y,unsharp_image->columns,1,
4331  exception);
4332  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4333  {
4334  status=MagickFalse;
4335  continue;
4336  }
4337  for (x=0; x < (ssize_t) image->columns; x++)
4338  {
4339  ssize_t
4340  i;
4341 
4342  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4343  {
4344  double
4345  pixel;
4346 
4347  PixelChannel
4348  channel;
4349 
4350  PixelTrait
4351  traits,
4352  unsharp_traits;
4353 
4354  channel=GetPixelChannelChannel(image,i);
4355  traits=GetPixelChannelTraits(image,channel);
4356  unsharp_traits=GetPixelChannelTraits(unsharp_image,channel);
4357  if ((traits == UndefinedPixelTrait) ||
4358  (unsharp_traits == UndefinedPixelTrait))
4359  continue;
4360  if ((unsharp_traits & CopyPixelTrait) != 0)
4361  {
4362  SetPixelChannel(unsharp_image,channel,p[i],q);
4363  continue;
4364  }
4365  pixel=p[i]-(double) GetPixelChannel(unsharp_image,channel,q);
4366  if (fabs(2.0*pixel) < quantum_threshold)
4367  pixel=(double) p[i];
4368  else
4369  pixel=(double) p[i]+gain*pixel;
4370  SetPixelChannel(unsharp_image,channel,ClampToQuantum(pixel),q);
4371  }
4372  p+=GetPixelChannels(image);
4373  q+=GetPixelChannels(unsharp_image);
4374  }
4375  if (SyncCacheViewAuthenticPixels(unsharp_view,exception) == MagickFalse)
4376  status=MagickFalse;
4377  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4378  {
4380  proceed;
4381 
4382 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4383  #pragma omp atomic
4384 #endif
4385  progress++;
4386  proceed=SetImageProgress(image,SharpenImageTag,progress,image->rows);
4387  if (proceed == MagickFalse)
4388  status=MagickFalse;
4389  }
4390  }
4391  unsharp_image->type=image->type;
4392  unsharp_view=DestroyCacheView(unsharp_view);
4393  image_view=DestroyCacheView(image_view);
4394  if (status == MagickFalse)
4395  unsharp_image=DestroyImage(unsharp_image);
4396  return(unsharp_image);
4397 }
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport Image * SelectiveBlurImage(const Image *image, const double radius, const double sigma, const double threshold, ExceptionInfo *exception)
Definition: effect.c:3417
MagickExport Image * BlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:770
PixelInfo matte_color
Definition: image.h:357
MagickDoubleType MagickRealType
Definition: magick-type.h:124
#define DefaultTileLabel
Definition: image-private.h:30
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
MagickExport Image * MotionBlurImage(const Image *image, const double radius, const double sigma, const double angle, ExceptionInfo *exception)
Definition: effect.c:2349
#define BlurImageTag
MagickExport MemoryInfo * RelinquishVirtualMemory(MemoryInfo *memory_info)
Definition: memory.c:1229
MagickExport ImageInfo * AcquireImageInfo(void)
Definition: image.c:327
#define PreviewImageTag
MagickExport Image * MontageImages(const Image *images, const MontageInfo *montage_info, ExceptionInfo *exception)
Definition: montage.c:306
MagickProgressMonitor progress_monitor
Definition: image.h:303
ImageType type
Definition: image.h:264
static Quantum GetPixelAlpha(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport MagickBooleanType TransformImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1609
#define MagickAssumeAligned(address)
ssize_t y
Definition: geometry.h:117
static MagickRealType GetMeanLuma(const Image *magick_restrict image, const double *magick_restrict pixel)
Definition: effect.c:1772
char * geometry
Definition: montage.h:36
static Quantum GetPixelRed(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
char * tile
Definition: montage.h:36
ColorspaceType colorspace
Definition: quantize.h:44
MagickExport Image * ShadeImage(const Image *image, const MagickBooleanType gray, const double azimuth, const double elevation, ExceptionInfo *exception)
Definition: effect.c:3752
MagickExport Image * UnsharpMaskImage(const Image *image, const double radius, const double sigma, const double gain, const double threshold, ExceptionInfo *exception)
Definition: effect.c:4263
MagickExport Image * BilateralBlurImage(const Image *image, const size_t width, const size_t height, const double intensity_sigma, const double spatial_sigma, ExceptionInfo *exception)
Definition: effect.c:899
size_t height
Definition: morphology.h:108
MagickExport MagickBooleanType RaiseImage(Image *image, const RectangleInfo *raise_info, const MagickBooleanType raise, ExceptionInfo *exception)
Definition: decorate.c:610
PixelInterpolateMethod
Definition: pixel.h:113
MagickExport KernelInfo * DestroyKernelInfo(KernelInfo *kernel)
Definition: morphology.c:2268
PixelInterpolateMethod interpolate
Definition: image.h:255
double x
Definition: image.h:99
MagickExport MemoryInfo * AcquireVirtualMemory(const size_t count, const size_t quantum)
Definition: memory.c:705
MagickExport Image * AdaptiveSharpenImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:450
size_t signature
Definition: exception.h:123
static size_t GetOpenMPMaximumThreads(void)
MagickExport Image * MorphologyImage(const Image *image, const MorphologyMethod method, const ssize_t iterations, const KernelInfo *kernel, ExceptionInfo *exception)
Definition: morphology.c:4136
MagickExport Image * PreviewImage(const Image *image, const PreviewType preview, ExceptionInfo *exception)
Definition: effect.c:2602
static Quantum GetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum *magick_restrict pixel)
static double ** AcquireBilateralThreadSet(const size_t number_threads, const size_t width, const size_t height)
Definition: effect.c:877
MagickExport MagickStatusType ParseMetaGeometry(const char *geometry, ssize_t *x, ssize_t *y, size_t *width, size_t *height)
Definition: geometry.c:1379
#define AdaptiveSharpenImageTag
MagickExport MagickBooleanType InterpolatePixelChannels(const Image *magick_restrict source, const CacheView_ *source_view, const Image *magick_restrict destination, const PixelInterpolateMethod method, const double x, const double y, Quantum *pixel, ExceptionInfo *exception)
Definition: pixel.c:4908
PreviewType
Definition: effect.h:27
double z
Definition: image.h:99
static RandomInfo ** DestroyRandomInfoThreadSet(RandomInfo **random_info)
ssize_t x
Definition: morphology.h:112
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
#define MagickPI
Definition: image-private.h:40
MagickExport MagickBooleanType EqualizeImage(Image *image, ExceptionInfo *exception)
Definition: enhance.c:2033
MagickExport Image * RotationalBlurImage(const Image *image, const double angle, ExceptionInfo *exception)
Definition: effect.c:3138
#define GetShadeIntensity(image, pixel)
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:463
MagickPrivate size_t GetOptimalKernelWidth1D(const double, const double)
MagickExport size_t CopyMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:731
char magick[MagickPathExtent]
Definition: image.h:319
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
static RandomInfo ** AcquireRandomInfoThreadSet(void)
size_t signature
Definition: morphology.h:129
#define SharpenImageTag
static MagickRealType GetPixelLuma(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
char * montage
Definition: image.h:201
#define MagickEpsilon
Definition: magick-type.h:114
size_t width
Definition: geometry.h:131
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:133
MagickExport Image * ThumbnailImage(const Image *image, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: resize.c:4523
MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info)
Definition: random.c:715
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
Definition: image.h:151
MagickExport Image * ImplodeImage(const Image *image, const double amount, const PixelInterpolateMethod method, ExceptionInfo *exception)
#define DespeckleImageTag
MagickExport MagickBooleanType ContrastImage(Image *image, const MagickBooleanType sharpen, ExceptionInfo *exception)
Definition: enhance.c:1399
char * frame
Definition: montage.h:36
double x
Definition: geometry.h:124
MagickExport KernelInfo * AcquireKernelInfo(const char *kernel_string, ExceptionInfo *exception)
Definition: morphology.c:486
#define MagickCoreSignature
MagickExport Quantum * GetCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:299
#define SpreadImageTag
MagickBooleanType
Definition: magick-type.h:165
MagickExport Image * NewImageList(void)
Definition: list.c:953
MagickExport char * AcquireString(const char *source)
Definition: string.c:94
static double PerceptibleReciprocal(const double x)
MagickExport int AcquireUniqueFileResource(char *path)
Definition: resource.c:551
MagickExport Image * LocalContrastImage(const Image *image, const double radius, const double strength, ExceptionInfo *exception)
Definition: effect.c:2018
MagickExport Image * SpreadImage(const Image *image, const PixelInterpolateMethod method, const double radius, ExceptionInfo *exception)
Definition: effect.c:4102
MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info, Image *image, ExceptionInfo *exception)
Definition: constitute.c:1083
#define BilateralBlurImageTag
#define Magick2PI
Definition: image-private.h:34
char filename[MagickPathExtent]
Definition: montage.h:63
MagickExport MagickBooleanType SegmentImage(Image *image, const ColorspaceType colorspace, const MagickBooleanType verbose, const double cluster_threshold, const double smooth_threshold, ExceptionInfo *exception)
Definition: segment.c:1794
#define DefaultTileFrame
Definition: image-private.h:28
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:665
char filename[MagickPathExtent]
Definition: image.h:480
MagickPrivate size_t GetOptimalKernelWidth2D(const double, const double)
Definition: gem.c:1685
static double DegreesToRadians(const double degrees)
Definition: image-private.h:64
double y
Definition: geometry.h:124
static int GetOpenMPThreadId(void)
MagickExport MagickBooleanType ModulateImage(Image *image, const char *modulate, ExceptionInfo *exception)
Definition: enhance.c:3625
#define MagickSQ2PI
Definition: image-private.h:43
MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
Definition: resource.c:1098
MagickExport Image * EmbossImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1605
MagickExport MagickBooleanType SetImageProperty(Image *image, const char *property, const char *value, ExceptionInfo *exception)
Definition: property.c:4235
size_t number_colors
Definition: quantize.h:38
#define MagickSigma
static MagickRealType * GetMotionBlurKernel(const size_t width, const double sigma)
Definition: effect.c:2319
MagickExport Image * RollImage(const Image *image, const ssize_t x_offset, const ssize_t y_offset, ExceptionInfo *exception)
Definition: transform.c:1532
#define MagickPathExtent
static Quantum GetPixelGreen(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
MagickExport void * RelinquishAlignedMemory(void *memory)
Definition: memory.c:1120
PixelTrait alpha_trait
Definition: image.h:280
MagickExport void GetQuantizeInfo(QuantizeInfo *quantize_info)
Definition: quantize.c:2311
#define MagickMaximumValue
Definition: magick-type.h:115
MagickExport Image * ReadImage(const ImageInfo *image_info, ExceptionInfo *exception)
Definition: constitute.c:429
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
#define NumberTiles
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
MagickExport MagickBooleanType QuantizeImage(const QuantizeInfo *quantize_info, Image *image, ExceptionInfo *exception)
Definition: quantize.c:3093
MagickExport Image * RotateImage(const Image *image, const double degrees, ExceptionInfo *exception)
Definition: distort.c:2949
size_t width
Definition: morphology.h:108
MagickExport Image * AdaptiveBlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:129
size_t signature
Definition: image.h:354
MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
Definition: resource.c:793
#define QuantumScale
Definition: magick-type.h:119
size_t columns
Definition: image.h:172
#define SelectiveBlurImageTag
ssize_t x
Definition: geometry.h:135
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
MagickExport Image * DespeckleImage(const Image *image, ExceptionInfo *exception)
Definition: effect.c:1313
size_t height
Definition: geometry.h:131
MagickExport Image * SwirlImage(const Image *image, double degrees, const PixelInterpolateMethod method, ExceptionInfo *exception)
MagickExport MontageInfo * DestroyMontageInfo(MontageInfo *montage_info)
Definition: montage.c:164
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2265
static void SetPixelBlue(const Image *magick_restrict image, const Quantum blue, Quantum *magick_restrict pixel)
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2614
MagickExport MagickProgressMonitor SetImageProgressMonitor(Image *image, const MagickProgressMonitor progress_monitor, void *client_data)
Definition: monitor.c:194
MagickExport Image * DestroyImageList(Image *images)
Definition: list.c:477
PixelChannel
Definition: pixel.h:70
MagickExport void * AcquireAlignedMemory(const size_t count, const size_t quantum)
Definition: memory.c:365
double y
Definition: image.h:99
#define MagickMax(x, y)
Definition: image-private.h:36
static size_t GetPixelChannels(const Image *magick_restrict image)
#define KuwaharaImageTag
static ssize_t CastDoubleToLong(const double value)
Definition: image-private.h:53
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
size_t quality
Definition: image.h:410
#define ThrowImageException(severity, tag)
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
MagickExport Image * ShearImage(const Image *image, const double x_shear, const double y_shear, ExceptionInfo *exception)
Definition: shear.c:1573
MagickExport MagickSizeType GetBlobSize(const Image *image)
Definition: blob.c:1844
MagickExport ImageInfo * DestroyImageInfo(ImageInfo *image_info)
Definition: image.c:1248
static void Hull(const Image *image, const ssize_t x_offset, const ssize_t y_offset, const size_t columns, const size_t rows, const int polarity, Quantum *magick_restrict f, Quantum *magick_restrict g)
Definition: effect.c:1217
unsigned short Quantum
Definition: magick-type.h:86
MagickExport Image * KuwaharaImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1780
MagickExport char * DestroyString(char *string)
Definition: string.c:788
MagickExport MagickBooleanType DeleteImageProperty(Image *image, const char *property)
Definition: property.c:279
MagickExport double GetPseudoRandomValue(RandomInfo *magick_restrict random_info)
Definition: random.c:584
#define MaxIntensity
size_t number_channels
Definition: image.h:283
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
char * directory
Definition: image.h:201
MagickExport void AppendImageToList(Image **images, const Image *append)
Definition: list.c:80
MagickExport Image * CharcoalImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
MagickExport Image * ConvolveImage(const Image *image, const KernelInfo *kernel_info, ExceptionInfo *exception)
Definition: effect.c:1170
MagickExport void SetGeometry(const Image *image, RectangleInfo *geometry)
Definition: geometry.c:1696
ssize_t x
Definition: geometry.h:117
MagickExport MagickBooleanType ConcatenateString(char **magick_restrict destination, const char *magick_restrict source)
Definition: string.c:458
MagickExport MagickBooleanType BilevelImage(Image *image, const double threshold, ExceptionInfo *exception)
Definition: threshold.c:807
static RandomInfo * random_info
Definition: resource.c:113
MagickExport Image * SharpenImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:3998
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1162
#define MaxPixelChannels
Definition: pixel.h:27
MagickBooleanType shadow
Definition: montage.h:50
MagickExport Image * WaveImage(const Image *image, const double amplitude, const double wave_length, const PixelInterpolateMethod method, ExceptionInfo *exception)
#define AdaptiveBlurImageTag
MagickExport MagickBooleanType GammaImage(Image *image, const double gamma, ExceptionInfo *exception)
Definition: enhance.c:2315
MagickExport char * CloneString(char **destination, const char *source)
Definition: string.c:250
static void SetPixelRed(const Image *magick_restrict image, const Quantum red, Quantum *magick_restrict pixel)
#define ShadeImageTag
MagickExport MagickBooleanType AutoLevelImage(Image *image, ExceptionInfo *exception)
Definition: enhance.c:185
static double ** DestroyBilateralThreadSet(const ssize_t number_threads, double **weights)
Definition: effect.c:863
static double BlurDistance(const ssize_t x, const ssize_t y, const ssize_t u, const ssize_t v)
Definition: effect.c:851
#define MagickExport
ssize_t y
Definition: morphology.h:112
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:135
MagickExport MagickBooleanType SolarizeImage(Image *image, const double threshold, ExceptionInfo *exception)
MagickExport Image * OilPaintImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: paint.c:690
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
MagickExport Image * EdgeImage(const Image *image, const double radius, ExceptionInfo *exception)
Definition: effect.c:1525
static Quantum GetPixelBlue(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
PixelTrait
Definition: pixel.h:137
MagickExport void * GetVirtualMemoryBlob(const MemoryInfo *memory_info)
Definition: memory.c:1090
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport MontageInfo * CloneMontageInfo(const ImageInfo *image_info, const MontageInfo *montage_info)
Definition: montage.c:104
#define DefaultPreviewGeometry
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1177
MagickExport Image * GaussianBlurImage(const Image *image, const double radius, const double sigma, ExceptionInfo *exception)
Definition: effect.c:1714
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:788
MagickExport Image * StatisticImage(const Image *image, const StatisticType type, const size_t width, const size_t height, ExceptionInfo *exception)
Definition: statistic.c:2898
#define QuantumRange
Definition: magick-type.h:87
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickRealType * values
Definition: morphology.h:116
MagickBooleanType debug
Definition: image.h:334
static void SetPixelGreen(const Image *magick_restrict image, const Quantum green, Quantum *magick_restrict pixel)
static double BlurGaussian(const double x, const double sigma)
Definition: effect.c:857