MagickCore  7.0.10
threshold.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % TTTTT H H RRRR EEEEE SSSSS H H OOO L DDDD %
7 % T H H R R E SS H H O O L D D %
8 % T HHHHH RRRR EEE SSS HHHHH O O L D D %
9 % T H H R R E SS H H O O L D D %
10 % T H H R R EEEEE SSSSS H H OOO LLLLL DDDD %
11 % %
12 % %
13 % MagickCore Image Threshold Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % October 1996 %
18 % %
19 % %
20 % Copyright 1999-2020 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"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
52 #include "MagickCore/configure.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/decorate.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/enhance.h"
57 #include "MagickCore/exception.h"
59 #include "MagickCore/effect.h"
60 #include "MagickCore/fx.h"
61 #include "MagickCore/gem.h"
62 #include "MagickCore/gem-private.h"
63 #include "MagickCore/geometry.h"
65 #include "MagickCore/list.h"
66 #include "MagickCore/log.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/monitor.h"
70 #include "MagickCore/montage.h"
71 #include "MagickCore/option.h"
74 #include "MagickCore/property.h"
75 #include "MagickCore/quantize.h"
76 #include "MagickCore/quantum.h"
78 #include "MagickCore/random_.h"
80 #include "MagickCore/resize.h"
81 #include "MagickCore/resource_.h"
82 #include "MagickCore/segment.h"
83 #include "MagickCore/shear.h"
85 #include "MagickCore/string_.h"
88 #include "MagickCore/threshold.h"
89 #include "MagickCore/token.h"
90 #include "MagickCore/transform.h"
91 #include "MagickCore/xml-tree.h"
93 
94 /*
95  Define declarations.
96 */
97 #define ThresholdsFilename "thresholds.xml"
98 
99 /*
100  Typedef declarations.
101 */
103 {
104  char
106  *description;
107 
108  size_t
110  height;
111 
112  ssize_t
114  *levels;
115 };
116 
117 /*
118  Static declarations.
119 */
120 #if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
121  #include "MagickCore/threshold-map.h"
122 #else
123 static const char *const
125  "<?xml version=\"1.0\"?>"
126  "<thresholds>"
127  " <threshold map=\"threshold\" alias=\"1x1\">"
128  " <description>Threshold 1x1 (non-dither)</description>"
129  " <levels width=\"1\" height=\"1\" divisor=\"2\">"
130  " 1"
131  " </levels>"
132  " </threshold>"
133  " <threshold map=\"checks\" alias=\"2x1\">"
134  " <description>Checkerboard 2x1 (dither)</description>"
135  " <levels width=\"2\" height=\"2\" divisor=\"3\">"
136  " 1 2"
137  " 2 1"
138  " </levels>"
139  " </threshold>"
140  "</thresholds>";
141 #endif
142 
143 /*
144  Forward declarations.
145 */
146 static ThresholdMap
147  *GetThresholdMapFile(const char *,const char *,const char *,ExceptionInfo *);
148 
149 /*
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151 % %
152 % %
153 % %
154 % A d a p t i v e T h r e s h o l d I m a g e %
155 % %
156 % %
157 % %
158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 %
160 % AdaptiveThresholdImage() selects an individual threshold for each pixel
161 % based on the range of intensity values in its local neighborhood. This
162 % allows for thresholding of an image whose global intensity histogram
163 % doesn't contain distinctive peaks.
164 %
165 % The format of the AdaptiveThresholdImage method is:
166 %
167 % Image *AdaptiveThresholdImage(const Image *image,const size_t width,
168 % const size_t height,const double bias,ExceptionInfo *exception)
169 %
170 % A description of each parameter follows:
171 %
172 % o image: the image.
173 %
174 % o width: the width of the local neighborhood.
175 %
176 % o height: the height of the local neighborhood.
177 %
178 % o bias: the mean bias.
179 %
180 % o exception: return any errors or warnings in this structure.
181 %
182 */
184  const size_t width,const size_t height,const double bias,
185  ExceptionInfo *exception)
186 {
187 #define AdaptiveThresholdImageTag "AdaptiveThreshold/Image"
188 
189  CacheView
190  *image_view,
191  *threshold_view;
192 
193  Image
194  *threshold_image;
195 
197  status;
198 
200  progress;
201 
203  number_pixels;
204 
205  ssize_t
206  y;
207 
208  /*
209  Initialize threshold image attributes.
210  */
211  assert(image != (Image *) NULL);
212  assert(image->signature == MagickCoreSignature);
213  if (image->debug != MagickFalse)
214  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
215  assert(exception != (ExceptionInfo *) NULL);
216  assert(exception->signature == MagickCoreSignature);
217  threshold_image=CloneImage(image,0,0,MagickTrue,exception);
218  if (threshold_image == (Image *) NULL)
219  return((Image *) NULL);
220  if ((width == 0) || (height == 0))
221  return(threshold_image);
222  status=SetImageStorageClass(threshold_image,DirectClass,exception);
223  if (status == MagickFalse)
224  {
225  threshold_image=DestroyImage(threshold_image);
226  return((Image *) NULL);
227  }
228  /*
229  Threshold image.
230  */
231  status=MagickTrue;
232  progress=0;
233  number_pixels=(MagickSizeType) width*height;
234  image_view=AcquireVirtualCacheView(image,exception);
235  threshold_view=AcquireAuthenticCacheView(threshold_image,exception);
236 #if defined(MAGICKCORE_OPENMP_SUPPORT)
237  #pragma omp parallel for schedule(static) shared(progress,status) \
238  magick_number_threads(image,threshold_image,image->rows,1)
239 #endif
240  for (y=0; y < (ssize_t) image->rows; y++)
241  {
242  double
243  channel_bias[MaxPixelChannels],
244  channel_sum[MaxPixelChannels];
245 
246  register const Quantum
247  *magick_restrict p,
248  *magick_restrict pixels;
249 
250  register Quantum
251  *magick_restrict q;
252 
253  register ssize_t
254  i,
255  x;
256 
257  ssize_t
258  center,
259  u,
260  v;
261 
262  if (status == MagickFalse)
263  continue;
264  p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
265  (height/2L),image->columns+width,height,exception);
266  q=QueueCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,
267  1,exception);
268  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
269  {
270  status=MagickFalse;
271  continue;
272  }
273  center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(height/2L)+
274  GetPixelChannels(image)*(width/2);
275  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
276  {
277  PixelChannel channel = GetPixelChannelChannel(image,i);
278  PixelTrait traits = GetPixelChannelTraits(image,channel);
279  PixelTrait threshold_traits=GetPixelChannelTraits(threshold_image,
280  channel);
281  if ((traits == UndefinedPixelTrait) ||
282  (threshold_traits == UndefinedPixelTrait))
283  continue;
284  if ((threshold_traits & CopyPixelTrait) != 0)
285  {
286  SetPixelChannel(threshold_image,channel,p[center+i],q);
287  continue;
288  }
289  pixels=p;
290  channel_bias[channel]=0.0;
291  channel_sum[channel]=0.0;
292  for (v=0; v < (ssize_t) height; v++)
293  {
294  for (u=0; u < (ssize_t) width; u++)
295  {
296  if (u == (ssize_t) (width-1))
297  channel_bias[channel]+=pixels[i];
298  channel_sum[channel]+=pixels[i];
299  pixels+=GetPixelChannels(image);
300  }
301  pixels+=GetPixelChannels(image)*image->columns;
302  }
303  }
304  for (x=0; x < (ssize_t) image->columns; x++)
305  {
306  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
307  {
308  double
309  mean;
310 
311  PixelChannel channel = GetPixelChannelChannel(image,i);
312  PixelTrait traits = GetPixelChannelTraits(image,channel);
313  PixelTrait threshold_traits=GetPixelChannelTraits(threshold_image,
314  channel);
315  if ((traits == UndefinedPixelTrait) ||
316  (threshold_traits == UndefinedPixelTrait))
317  continue;
318  if ((threshold_traits & CopyPixelTrait) != 0)
319  {
320  SetPixelChannel(threshold_image,channel,p[center+i],q);
321  continue;
322  }
323  channel_sum[channel]-=channel_bias[channel];
324  channel_bias[channel]=0.0;
325  pixels=p;
326  for (v=0; v < (ssize_t) height; v++)
327  {
328  channel_bias[channel]+=pixels[i];
329  pixels+=(width-1)*GetPixelChannels(image);
330  channel_sum[channel]+=pixels[i];
331  pixels+=GetPixelChannels(image)*(image->columns+1);
332  }
333  mean=(double) (channel_sum[channel]/number_pixels+bias);
334  SetPixelChannel(threshold_image,channel,(Quantum) ((double)
335  p[center+i] <= mean ? 0 : QuantumRange),q);
336  }
337  p+=GetPixelChannels(image);
338  q+=GetPixelChannels(threshold_image);
339  }
340  if (SyncCacheViewAuthenticPixels(threshold_view,exception) == MagickFalse)
341  status=MagickFalse;
342  if (image->progress_monitor != (MagickProgressMonitor) NULL)
343  {
345  proceed;
346 
347 #if defined(MAGICKCORE_OPENMP_SUPPORT)
348  #pragma omp atomic
349 #endif
350  progress++;
351  proceed=SetImageProgress(image,AdaptiveThresholdImageTag,progress,
352  image->rows);
353  if (proceed == MagickFalse)
354  status=MagickFalse;
355  }
356  }
357  threshold_image->type=image->type;
358  threshold_view=DestroyCacheView(threshold_view);
359  image_view=DestroyCacheView(image_view);
360  if (status == MagickFalse)
361  threshold_image=DestroyImage(threshold_image);
362  return(threshold_image);
363 }
364 
365 /*
366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 % %
368 % %
369 % %
370 % A u t o T h r e s h o l d I m a g e %
371 % %
372 % %
373 % %
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 %
376 % AutoThresholdImage() automatically performs image thresholding
377 % dependent on which method you specify.
378 %
379 % The format of the AutoThresholdImage method is:
380 %
381 % MagickBooleanType AutoThresholdImage(Image *image,
382 % const AutoThresholdMethod method,ExceptionInfo *exception)
383 %
384 % A description of each parameter follows:
385 %
386 % o image: The image to auto-threshold.
387 %
388 % o method: choose from Kapur, OTSU, or Triangle.
389 %
390 % o exception: return any errors or warnings in this structure.
391 %
392 */
393 
394 static double KapurThreshold(const Image *image,const double *histogram,
395  ExceptionInfo *exception)
396 {
397 #define MaxIntensity 255
398 
399  double
400  *black_entropy,
401  *cumulative_histogram,
402  entropy,
403  epsilon,
404  maximum_entropy,
405  *white_entropy;
406 
407  register ssize_t
408  i,
409  j;
410 
411  size_t
412  threshold;
413 
414  /*
415  Compute optimal threshold from the entopy of the histogram.
416  */
417  cumulative_histogram=(double *) AcquireQuantumMemory(MaxIntensity+1UL,
418  sizeof(*cumulative_histogram));
419  black_entropy=(double *) AcquireQuantumMemory(MaxIntensity+1UL,
420  sizeof(*black_entropy));
421  white_entropy=(double *) AcquireQuantumMemory(MaxIntensity+1UL,
422  sizeof(*white_entropy));
423  if ((cumulative_histogram == (double *) NULL) ||
424  (black_entropy == (double *) NULL) || (white_entropy == (double *) NULL))
425  {
426  if (white_entropy != (double *) NULL)
427  white_entropy=(double *) RelinquishMagickMemory(white_entropy);
428  if (black_entropy != (double *) NULL)
429  black_entropy=(double *) RelinquishMagickMemory(black_entropy);
430  if (cumulative_histogram != (double *) NULL)
431  cumulative_histogram=(double *)
432  RelinquishMagickMemory(cumulative_histogram);
433  (void) ThrowMagickException(exception,GetMagickModule(),
434  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
435  return(-1.0);
436  }
437  /*
438  Entropy for black and white parts of the histogram.
439  */
440  cumulative_histogram[0]=histogram[0];
441  for (i=1; i <= MaxIntensity; i++)
442  cumulative_histogram[i]=cumulative_histogram[i-1]+histogram[i];
443  epsilon=MagickMinimumValue;
444  for (j=0; j <= MaxIntensity; j++)
445  {
446  /*
447  Black entropy.
448  */
449  black_entropy[j]=0.0;
450  if (cumulative_histogram[j] > epsilon)
451  {
452  entropy=0.0;
453  for (i=0; i <= j; i++)
454  if (histogram[i] > epsilon)
455  entropy-=histogram[i]/cumulative_histogram[j]*
456  log(histogram[i]/cumulative_histogram[j]);
457  black_entropy[j]=entropy;
458  }
459  /*
460  White entropy.
461  */
462  white_entropy[j]=0.0;
463  if ((1.0-cumulative_histogram[j]) > epsilon)
464  {
465  entropy=0.0;
466  for (i=j+1; i <= MaxIntensity; i++)
467  if (histogram[i] > epsilon)
468  entropy-=histogram[i]/(1.0-cumulative_histogram[j])*
469  log(histogram[i]/(1.0-cumulative_histogram[j]));
470  white_entropy[j]=entropy;
471  }
472  }
473  /*
474  Find histogram bin with maximum entropy.
475  */
476  maximum_entropy=black_entropy[0]+white_entropy[0];
477  threshold=0;
478  for (j=1; j <= MaxIntensity; j++)
479  if ((black_entropy[j]+white_entropy[j]) > maximum_entropy)
480  {
481  maximum_entropy=black_entropy[j]+white_entropy[j];
482  threshold=(size_t) j;
483  }
484  /*
485  Free resources.
486  */
487  white_entropy=(double *) RelinquishMagickMemory(white_entropy);
488  black_entropy=(double *) RelinquishMagickMemory(black_entropy);
489  cumulative_histogram=(double *) RelinquishMagickMemory(cumulative_histogram);
490  return(100.0*threshold/MaxIntensity);
491 }
492 
493 static double OTSUThreshold(const Image *image,const double *histogram,
494  ExceptionInfo *exception)
495 {
496  double
497  max_sigma,
498  *myu,
499  *omega,
500  *probability,
501  *sigma,
502  threshold;
503 
504  register ssize_t
505  i;
506 
507  /*
508  Compute optimal threshold from maximization of inter-class variance.
509  */
510  myu=(double *) AcquireQuantumMemory(MaxIntensity+1UL,sizeof(*myu));
511  omega=(double *) AcquireQuantumMemory(MaxIntensity+1UL,sizeof(*omega));
512  probability=(double *) AcquireQuantumMemory(MaxIntensity+1UL,
513  sizeof(*probability));
514  sigma=(double *) AcquireQuantumMemory(MaxIntensity+1UL,sizeof(*sigma));
515  if ((myu == (double *) NULL) || (omega == (double *) NULL) ||
516  (probability == (double *) NULL) || (sigma == (double *) NULL))
517  {
518  if (sigma != (double *) NULL)
519  sigma=(double *) RelinquishMagickMemory(sigma);
520  if (probability != (double *) NULL)
521  probability=(double *) RelinquishMagickMemory(probability);
522  if (omega != (double *) NULL)
523  omega=(double *) RelinquishMagickMemory(omega);
524  if (myu != (double *) NULL)
525  myu=(double *) RelinquishMagickMemory(myu);
526  (void) ThrowMagickException(exception,GetMagickModule(),
527  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
528  return(-1.0);
529  }
530  /*
531  Calculate probability density.
532  */
533  for (i=0; i <= (ssize_t) MaxIntensity; i++)
534  probability[i]=histogram[i];
535  /*
536  Generate probability of graylevels and mean value for separation.
537  */
538  omega[0]=probability[0];
539  myu[0]=0.0;
540  for (i=1; i <= (ssize_t) MaxIntensity; i++)
541  {
542  omega[i]=omega[i-1]+probability[i];
543  myu[i]=myu[i-1]+i*probability[i];
544  }
545  /*
546  Sigma maximization: inter-class variance and compute optimal threshold.
547  */
548  threshold=0;
549  max_sigma=0.0;
550  for (i=0; i < (ssize_t) MaxIntensity; i++)
551  {
552  sigma[i]=0.0;
553  if ((omega[i] != 0.0) && (omega[i] != 1.0))
554  sigma[i]=pow(myu[MaxIntensity]*omega[i]-myu[i],2.0)/(omega[i]*(1.0-
555  omega[i]));
556  if (sigma[i] > max_sigma)
557  {
558  max_sigma=sigma[i];
559  threshold=(double) i;
560  }
561  }
562  /*
563  Free resources.
564  */
565  myu=(double *) RelinquishMagickMemory(myu);
566  omega=(double *) RelinquishMagickMemory(omega);
567  probability=(double *) RelinquishMagickMemory(probability);
568  sigma=(double *) RelinquishMagickMemory(sigma);
569  return(100.0*threshold/MaxIntensity);
570 }
571 
572 static double TriangleThreshold(const double *histogram)
573 {
574  double
575  a,
576  b,
577  c,
578  count,
579  distance,
580  inverse_ratio,
581  max_distance,
582  segment,
583  x1,
584  x2,
585  y1,
586  y2;
587 
588  register ssize_t
589  i;
590 
591  ssize_t
592  end,
593  max,
594  start,
595  threshold;
596 
597  /*
598  Compute optimal threshold with triangle algorithm.
599  */
600  start=0; /* find start bin, first bin not zero count */
601  for (i=0; i <= (ssize_t) MaxIntensity; i++)
602  if (histogram[i] > 0.0)
603  {
604  start=i;
605  break;
606  }
607  end=0; /* find end bin, last bin not zero count */
608  for (i=(ssize_t) MaxIntensity; i >= 0; i--)
609  if (histogram[i] > 0.0)
610  {
611  end=i;
612  break;
613  }
614  max=0; /* find max bin, bin with largest count */
615  count=0.0;
616  for (i=0; i <= (ssize_t) MaxIntensity; i++)
617  if (histogram[i] > count)
618  {
619  max=i;
620  count=histogram[i];
621  }
622  /*
623  Compute threshold at split point.
624  */
625  x1=(double) max;
626  y1=histogram[max];
627  x2=(double) end;
628  if ((max-start) >= (end-max))
629  x2=(double) start;
630  y2=0.0;
631  a=y1-y2;
632  b=x2-x1;
633  c=(-1.0)*(a*x1+b*y1);
634  inverse_ratio=1.0/sqrt(a*a+b*b+c*c);
635  threshold=0;
636  max_distance=0.0;
637  if (x2 == (double) start)
638  for (i=start; i < max; i++)
639  {
640  segment=inverse_ratio*(a*i+b*histogram[i]+c);
641  distance=sqrt(segment*segment);
642  if ((distance > max_distance) && (segment > 0.0))
643  {
644  threshold=i;
645  max_distance=distance;
646  }
647  }
648  else
649  for (i=end; i > max; i--)
650  {
651  segment=inverse_ratio*(a*i+b*histogram[i]+c);
652  distance=sqrt(segment*segment);
653  if ((distance > max_distance) && (segment < 0.0))
654  {
655  threshold=i;
656  max_distance=distance;
657  }
658  }
659  return(100.0*threshold/MaxIntensity);
660 }
661 
663  const AutoThresholdMethod method,ExceptionInfo *exception)
664 {
665  CacheView
666  *image_view;
667 
668  char
669  property[MagickPathExtent];
670 
671  double
672  gamma,
673  *histogram,
674  sum,
675  threshold;
676 
678  status;
679 
680  register ssize_t
681  i;
682 
683  ssize_t
684  y;
685 
686  /*
687  Form histogram.
688  */
689  assert(image != (Image *) NULL);
690  assert(image->signature == MagickCoreSignature);
691  if (image->debug != MagickFalse)
692  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
693  histogram=(double *) AcquireQuantumMemory(MaxIntensity+1UL,
694  sizeof(*histogram));
695  if (histogram == (double *) NULL)
696  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
697  image->filename);
698  status=MagickTrue;
699  (void) memset(histogram,0,(MaxIntensity+1UL)*sizeof(*histogram));
700  image_view=AcquireVirtualCacheView(image,exception);
701  for (y=0; y < (ssize_t) image->rows; y++)
702  {
703  register const Quantum
704  *magick_restrict p;
705 
706  register ssize_t
707  x;
708 
709  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
710  if (p == (const Quantum *) NULL)
711  break;
712  for (x=0; x < (ssize_t) image->columns; x++)
713  {
714  double intensity = GetPixelIntensity(image,p);
715  histogram[ScaleQuantumToChar(ClampToQuantum(intensity))]++;
716  p+=GetPixelChannels(image);
717  }
718  }
719  image_view=DestroyCacheView(image_view);
720  /*
721  Normalize histogram.
722  */
723  sum=0.0;
724  for (i=0; i <= (ssize_t) MaxIntensity; i++)
725  sum+=histogram[i];
726  gamma=PerceptibleReciprocal(sum);
727  for (i=0; i <= (ssize_t) MaxIntensity; i++)
728  histogram[i]=gamma*histogram[i];
729  /*
730  Discover threshold from histogram.
731  */
732  switch (method)
733  {
735  {
736  threshold=KapurThreshold(image,histogram,exception);
737  break;
738  }
739  case OTSUThresholdMethod:
740  default:
741  {
742  threshold=OTSUThreshold(image,histogram,exception);
743  break;
744  }
746  {
747  threshold=TriangleThreshold(histogram);
748  break;
749  }
750  }
751  histogram=(double *) RelinquishMagickMemory(histogram);
752  if (threshold < 0.0)
753  status=MagickFalse;
754  if (status == MagickFalse)
755  return(MagickFalse);
756  /*
757  Threshold image.
758  */
759  (void) FormatLocaleString(property,MagickPathExtent,"%g%%",threshold);
760  (void) SetImageProperty(image,"auto-threshold:threshold",property,exception);
761  if (IsStringTrue(GetImageArtifact(image,"auto-threshold:verbose")) != MagickFalse)
762  (void) FormatLocaleFile(stdout,"%.*g%%\n",GetMagickPrecision(),threshold);
763  return(BilevelImage(image,QuantumRange*threshold/100.0,exception));
764 }
765 
766 /*
767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
768 % %
769 % %
770 % %
771 % B i l e v e l I m a g e %
772 % %
773 % %
774 % %
775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 %
777 % BilevelImage() changes the value of individual pixels based on the
778 % intensity of each pixel channel. The result is a high-contrast image.
779 %
780 % More precisely each channel value of the image is 'thresholded' so that if
781 % it is equal to or less than the given value it is set to zero, while any
782 % value greater than that give is set to it maximum or QuantumRange.
783 %
784 % This function is what is used to implement the "-threshold" operator for
785 % the command line API.
786 %
787 % If the default channel setting is given the image is thresholded using just
788 % the gray 'intensity' of the image, rather than the individual channels.
789 %
790 % The format of the BilevelImage method is:
791 %
792 % MagickBooleanType BilevelImage(Image *image,const double threshold,
793 % ExceptionInfo *exception)
794 %
795 % A description of each parameter follows:
796 %
797 % o image: the image.
798 %
799 % o threshold: define the threshold values.
800 %
801 % o exception: return any errors or warnings in this structure.
802 %
803 % Aside: You can get the same results as operator using LevelImages()
804 % with the 'threshold' value for both the black_point and the white_point.
805 %
806 */
807 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold,
808  ExceptionInfo *exception)
809 {
810 #define ThresholdImageTag "Threshold/Image"
811 
812  CacheView
813  *image_view;
814 
816  status;
817 
819  progress;
820 
821  ssize_t
822  y;
823 
824  assert(image != (Image *) NULL);
825  assert(image->signature == MagickCoreSignature);
826  if (image->debug != MagickFalse)
827  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
828  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
829  return(MagickFalse);
830  if (IsGrayColorspace(image->colorspace) == MagickFalse)
831  (void) SetImageColorspace(image,sRGBColorspace,exception);
832  /*
833  Bilevel threshold image.
834  */
835  status=MagickTrue;
836  progress=0;
837  image_view=AcquireAuthenticCacheView(image,exception);
838 #if defined(MAGICKCORE_OPENMP_SUPPORT)
839  #pragma omp parallel for schedule(static) shared(progress,status) \
840  magick_number_threads(image,image,image->rows,1)
841 #endif
842  for (y=0; y < (ssize_t) image->rows; y++)
843  {
844  register ssize_t
845  x;
846 
847  register Quantum
848  *magick_restrict q;
849 
850  if (status == MagickFalse)
851  continue;
852  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
853  if (q == (Quantum *) NULL)
854  {
855  status=MagickFalse;
856  continue;
857  }
858  for (x=0; x < (ssize_t) image->columns; x++)
859  {
860  double
861  pixel;
862 
863  register ssize_t
864  i;
865 
866  pixel=GetPixelIntensity(image,q);
867  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
868  {
869  PixelChannel channel = GetPixelChannelChannel(image,i);
870  PixelTrait traits = GetPixelChannelTraits(image,channel);
871  if ((traits & UpdatePixelTrait) == 0)
872  continue;
873  if (image->channel_mask != DefaultChannels)
874  pixel=(double) q[i];
875  q[i]=(Quantum) (pixel <= threshold ? 0 : QuantumRange);
876  }
877  q+=GetPixelChannels(image);
878  }
879  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
880  status=MagickFalse;
881  if (image->progress_monitor != (MagickProgressMonitor) NULL)
882  {
884  proceed;
885 
886 #if defined(MAGICKCORE_OPENMP_SUPPORT)
887  #pragma omp atomic
888 #endif
889  progress++;
890  proceed=SetImageProgress(image,ThresholdImageTag,progress++,
891  image->rows);
892  if (proceed == MagickFalse)
893  status=MagickFalse;
894  }
895  }
896  image_view=DestroyCacheView(image_view);
897  return(status);
898 }
899 
900 /*
901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % %
903 % %
904 % %
905 % B l a c k T h r e s h o l d I m a g e %
906 % %
907 % %
908 % %
909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910 %
911 % BlackThresholdImage() is like ThresholdImage() but forces all pixels below
912 % the threshold into black while leaving all pixels at or above the threshold
913 % unchanged.
914 %
915 % The format of the BlackThresholdImage method is:
916 %
917 % MagickBooleanType BlackThresholdImage(Image *image,
918 % const char *threshold,ExceptionInfo *exception)
919 %
920 % A description of each parameter follows:
921 %
922 % o image: the image.
923 %
924 % o threshold: define the threshold value.
925 %
926 % o exception: return any errors or warnings in this structure.
927 %
928 */
930  const char *thresholds,ExceptionInfo *exception)
931 {
932 #define ThresholdImageTag "Threshold/Image"
933 
934  CacheView
935  *image_view;
936 
938  geometry_info;
939 
941  status;
942 
944  progress;
945 
946  PixelInfo
947  threshold;
948 
950  flags;
951 
952  ssize_t
953  y;
954 
955  assert(image != (Image *) NULL);
956  assert(image->signature == MagickCoreSignature);
957  if (image->debug != MagickFalse)
958  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
959  if (thresholds == (const char *) NULL)
960  return(MagickTrue);
961  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
962  return(MagickFalse);
963  if (IsGrayColorspace(image->colorspace) != MagickFalse)
964  (void) SetImageColorspace(image,sRGBColorspace,exception);
965  GetPixelInfo(image,&threshold);
966  flags=ParseGeometry(thresholds,&geometry_info);
967  threshold.red=geometry_info.rho;
968  threshold.green=geometry_info.rho;
969  threshold.blue=geometry_info.rho;
970  threshold.black=geometry_info.rho;
971  threshold.alpha=100.0;
972  if ((flags & SigmaValue) != 0)
973  threshold.green=geometry_info.sigma;
974  if ((flags & XiValue) != 0)
975  threshold.blue=geometry_info.xi;
976  if ((flags & PsiValue) != 0)
977  threshold.alpha=geometry_info.psi;
978  if (threshold.colorspace == CMYKColorspace)
979  {
980  if ((flags & PsiValue) != 0)
981  threshold.black=geometry_info.psi;
982  if ((flags & ChiValue) != 0)
983  threshold.alpha=geometry_info.chi;
984  }
985  if ((flags & PercentValue) != 0)
986  {
987  threshold.red*=(MagickRealType) (QuantumRange/100.0);
988  threshold.green*=(MagickRealType) (QuantumRange/100.0);
989  threshold.blue*=(MagickRealType) (QuantumRange/100.0);
990  threshold.black*=(MagickRealType) (QuantumRange/100.0);
991  threshold.alpha*=(MagickRealType) (QuantumRange/100.0);
992  }
993  /*
994  White threshold image.
995  */
996  status=MagickTrue;
997  progress=0;
998  image_view=AcquireAuthenticCacheView(image,exception);
999 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1000  #pragma omp parallel for schedule(static) shared(progress,status) \
1001  magick_number_threads(image,image,image->rows,1)
1002 #endif
1003  for (y=0; y < (ssize_t) image->rows; y++)
1004  {
1005  register ssize_t
1006  x;
1007 
1008  register Quantum
1009  *magick_restrict q;
1010 
1011  if (status == MagickFalse)
1012  continue;
1013  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1014  if (q == (Quantum *) NULL)
1015  {
1016  status=MagickFalse;
1017  continue;
1018  }
1019  for (x=0; x < (ssize_t) image->columns; x++)
1020  {
1021  double
1022  pixel;
1023 
1024  register ssize_t
1025  i;
1026 
1027  pixel=GetPixelIntensity(image,q);
1028  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1029  {
1030  PixelChannel channel = GetPixelChannelChannel(image,i);
1031  PixelTrait traits = GetPixelChannelTraits(image,channel);
1032  if ((traits & UpdatePixelTrait) == 0)
1033  continue;
1034  if (image->channel_mask != DefaultChannels)
1035  pixel=(double) q[i];
1036  if (pixel < GetPixelInfoChannel(&threshold,channel))
1037  q[i]=(Quantum) 0;
1038  }
1039  q+=GetPixelChannels(image);
1040  }
1041  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1042  status=MagickFalse;
1043  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1044  {
1046  proceed;
1047 
1048 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1049  #pragma omp atomic
1050 #endif
1051  progress++;
1052  proceed=SetImageProgress(image,ThresholdImageTag,progress,
1053  image->rows);
1054  if (proceed == MagickFalse)
1055  status=MagickFalse;
1056  }
1057  }
1058  image_view=DestroyCacheView(image_view);
1059  return(status);
1060 }
1061 
1062 /*
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064 % %
1065 % %
1066 % %
1067 % C l a m p I m a g e %
1068 % %
1069 % %
1070 % %
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 %
1073 % ClampImage() set each pixel whose value is below zero to zero and any the
1074 % pixel whose value is above the quantum range to the quantum range (e.g.
1075 % 65535) otherwise the pixel value remains unchanged.
1076 %
1077 % The format of the ClampImage method is:
1078 %
1079 % MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
1080 %
1081 % A description of each parameter follows:
1082 %
1083 % o image: the image.
1084 %
1085 % o exception: return any errors or warnings in this structure.
1086 %
1087 */
1088 
1090 {
1091 #define ClampImageTag "Clamp/Image"
1092 
1093  CacheView
1094  *image_view;
1095 
1097  status;
1098 
1100  progress;
1101 
1102  ssize_t
1103  y;
1104 
1105  assert(image != (Image *) NULL);
1106  assert(image->signature == MagickCoreSignature);
1107  if (image->debug != MagickFalse)
1108  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1109  if (image->storage_class == PseudoClass)
1110  {
1111  register ssize_t
1112  i;
1113 
1114  register PixelInfo
1115  *magick_restrict q;
1116 
1117  q=image->colormap;
1118  for (i=0; i < (ssize_t) image->colors; i++)
1119  {
1120  q->red=(double) ClampPixel(q->red);
1121  q->green=(double) ClampPixel(q->green);
1122  q->blue=(double) ClampPixel(q->blue);
1123  q->alpha=(double) ClampPixel(q->alpha);
1124  q++;
1125  }
1126  return(SyncImage(image,exception));
1127  }
1128  /*
1129  Clamp image.
1130  */
1131  status=MagickTrue;
1132  progress=0;
1133  image_view=AcquireAuthenticCacheView(image,exception);
1134 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1135  #pragma omp parallel for schedule(static) shared(progress,status) \
1136  magick_number_threads(image,image,image->rows,1)
1137 #endif
1138  for (y=0; y < (ssize_t) image->rows; y++)
1139  {
1140  register ssize_t
1141  x;
1142 
1143  register Quantum
1144  *magick_restrict q;
1145 
1146  if (status == MagickFalse)
1147  continue;
1148  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1149  if (q == (Quantum *) NULL)
1150  {
1151  status=MagickFalse;
1152  continue;
1153  }
1154  for (x=0; x < (ssize_t) image->columns; x++)
1155  {
1156  register ssize_t
1157  i;
1158 
1159  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1160  {
1161  PixelChannel channel = GetPixelChannelChannel(image,i);
1162  PixelTrait traits = GetPixelChannelTraits(image,channel);
1163  if ((traits & UpdatePixelTrait) == 0)
1164  continue;
1165  q[i]=ClampPixel((MagickRealType) q[i]);
1166  }
1167  q+=GetPixelChannels(image);
1168  }
1169  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1170  status=MagickFalse;
1171  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1172  {
1174  proceed;
1175 
1176 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1177  #pragma omp atomic
1178 #endif
1179  progress++;
1180  proceed=SetImageProgress(image,ClampImageTag,progress,image->rows);
1181  if (proceed == MagickFalse)
1182  status=MagickFalse;
1183  }
1184  }
1185  image_view=DestroyCacheView(image_view);
1186  return(status);
1187 }
1188 
1189 /*
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 % %
1192 % %
1193 % %
1194 % C o l o r T h r e s h o l d I m a g e %
1195 % %
1196 % %
1197 % %
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 %
1200 % ColorThresholdImage() forces all pixels in the color range to white
1201 % otherwise black.
1202 %
1203 % The format of the ColorThresholdImage method is:
1204 %
1205 % MagickBooleanType ColorThresholdImage(Image *image,
1206 % const PixelInfo *start_color,const PixelInfo *stop_color,
1207 % ExceptionInfo *exception)
1208 %
1209 % A description of each parameter follows:
1210 %
1211 % o image: the image.
1212 %
1213 % o start_color, stop_color: define the start and stop color range. Any
1214 % pixel within the range returns white otherwise black.
1215 %
1216 % o exception: return any errors or warnings in this structure.
1217 %
1218 */
1220  const PixelInfo *start_color,const PixelInfo *stop_color,
1221  ExceptionInfo *exception)
1222 {
1223 #define ThresholdImageTag "Threshold/Image"
1224 
1225  CacheView
1226  *image_view;
1227 
1229  status;
1230 
1232  progress;
1233 
1234  PixelInfo
1235  start,
1236  stop;
1237 
1238  ssize_t
1239  y;
1240 
1241  /*
1242  Color threshold image.
1243  */
1244  assert(image != (Image *) NULL);
1245  assert(image->signature == MagickCoreSignature);
1246  if (image->debug != MagickFalse)
1247  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1248  status=AcquireImageColormap(image,2,exception);
1249  if (status == MagickFalse)
1250  return(status);
1251  start=(*start_color);
1252  stop=(*stop_color);
1253  switch (image->colorspace)
1254  {
1255  case HCLColorspace:
1256  {
1257  ConvertRGBToHCL(start_color->red,start_color->green,start_color->blue,
1258  &start.red,&start.green,&start.blue);
1259  ConvertRGBToHCL(stop_color->red,stop_color->green,stop_color->blue,
1260  &stop.red,&stop.green,&stop.blue);
1261  break;
1262  }
1263  case HSBColorspace:
1264  {
1265  ConvertRGBToHSB(start_color->red,start_color->green,start_color->blue,
1266  &start.red,&start.green,&start.blue);
1267  ConvertRGBToHSB(stop_color->red,stop_color->green,stop_color->blue,
1268  &stop.red,&stop.green,&stop.blue);
1269  break;
1270  }
1271  case HSLColorspace:
1272  {
1273  ConvertRGBToHSL(start_color->red,start_color->green,start_color->blue,
1274  &start.red,&start.green,&start.blue);
1275  ConvertRGBToHSL(stop_color->red,stop_color->green,stop_color->blue,
1276  &stop.red,&stop.green,&stop.blue);
1277  break;
1278  }
1279  case HSVColorspace:
1280  {
1281  ConvertRGBToHSV(start_color->red,start_color->green,start_color->blue,
1282  &start.red,&start.green,&start.blue);
1283  ConvertRGBToHSV(stop_color->red,stop_color->green,stop_color->blue,
1284  &stop.red,&stop.green,&stop.blue);
1285  break;
1286  }
1287  case HWBColorspace:
1288  {
1289  ConvertRGBToHWB(start_color->red,start_color->green,start_color->blue,
1290  &start.red,&start.green,&start.blue);
1291  ConvertRGBToHWB(stop_color->red,stop_color->green,stop_color->blue,
1292  &stop.red,&stop.green,&stop.blue);
1293  break;
1294  }
1295  case LabColorspace:
1296  {
1297  ConvertRGBToLab(start_color->red,start_color->green,start_color->blue,
1298  &start.red,&start.green,&start.blue);
1299  ConvertRGBToLab(stop_color->red,stop_color->green,stop_color->blue,
1300  &stop.red,&stop.green,&stop.blue);
1301  break;
1302  }
1303  default:
1304  {
1305  start.red*=QuantumScale;
1306  start.green*=QuantumScale;
1307  start.blue*=QuantumScale;
1308  stop.red*=QuantumScale;
1309  stop.green*=QuantumScale;
1310  stop.blue*=QuantumScale;
1311  break;
1312  }
1313  }
1314  start.red*=QuantumRange;
1315  start.green*=QuantumRange;
1316  start.blue*=QuantumRange;
1317  stop.red*=QuantumRange;
1318  stop.green*=QuantumRange;
1319  stop.blue*=QuantumRange;
1320  progress=0;
1321  image_view=AcquireAuthenticCacheView(image,exception);
1322 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1323  #pragma omp parallel for schedule(static) shared(progress,status) \
1324  magick_number_threads(image,image,image->rows,1)
1325 #endif
1326  for (y=0; y < (ssize_t) image->rows; y++)
1327  {
1328  register ssize_t
1329  x;
1330 
1331  register Quantum
1332  *magick_restrict q;
1333 
1334  if (status == MagickFalse)
1335  continue;
1336  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1337  if (q == (Quantum *) NULL)
1338  {
1339  status=MagickFalse;
1340  continue;
1341  }
1342  for (x=0; x < (ssize_t) image->columns; x++)
1343  {
1345  foreground = MagickTrue;
1346 
1347  register ssize_t
1348  i;
1349 
1350  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1351  {
1352  PixelChannel channel = GetPixelChannelChannel(image,i);
1353  PixelTrait traits = GetPixelChannelTraits(image,channel);
1354  if ((traits & UpdatePixelTrait) == 0)
1355  continue;
1356  if ((q[i] < GetPixelInfoChannel(&start,channel)) ||
1357  (q[i] > GetPixelInfoChannel(&stop,channel)))
1358  foreground=MagickFalse;
1359  }
1360  SetPixelIndex(image,(Quantum) (foreground != MagickFalse ? 1 : 0),q);
1361  q+=GetPixelChannels(image);
1362  }
1363  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1364  status=MagickFalse;
1365  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1366  {
1368  proceed;
1369 
1370 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1371  #pragma omp atomic
1372 #endif
1373  progress++;
1374  proceed=SetImageProgress(image,ThresholdImageTag,progress,
1375  image->rows);
1376  if (proceed == MagickFalse)
1377  status=MagickFalse;
1378  }
1379  }
1380  image_view=DestroyCacheView(image_view);
1381  image->colorspace=sRGBColorspace;
1382  return(SyncImage(image,exception));
1383 }
1384 
1385 /*
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % %
1388 % %
1389 % %
1390 % D e s t r o y T h r e s h o l d M a p %
1391 % %
1392 % %
1393 % %
1394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1395 %
1396 % DestroyThresholdMap() de-allocate the given ThresholdMap
1397 %
1398 % The format of the ListThresholdMaps method is:
1399 %
1400 % ThresholdMap *DestroyThresholdMap(Threshold *map)
1401 %
1402 % A description of each parameter follows.
1403 %
1404 % o map: Pointer to the Threshold map to destroy
1405 %
1406 */
1408 {
1409  assert(map != (ThresholdMap *) NULL);
1410  if (map->map_id != (char *) NULL)
1411  map->map_id=DestroyString(map->map_id);
1412  if (map->description != (char *) NULL)
1414  if (map->levels != (ssize_t *) NULL)
1415  map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
1416  map=(ThresholdMap *) RelinquishMagickMemory(map);
1417  return(map);
1418 }
1419 
1420 /*
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 % %
1423 % %
1424 % %
1425 % G e t T h r e s h o l d M a p %
1426 % %
1427 % %
1428 % %
1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430 %
1431 % GetThresholdMap() loads and searches one or more threshold map files for the
1432 % map matching the given name or alias.
1433 %
1434 % The format of the GetThresholdMap method is:
1435 %
1436 % ThresholdMap *GetThresholdMap(const char *map_id,
1437 % ExceptionInfo *exception)
1438 %
1439 % A description of each parameter follows.
1440 %
1441 % o map_id: ID of the map to look for.
1442 %
1443 % o exception: return any errors or warnings in this structure.
1444 %
1445 */
1447  ExceptionInfo *exception)
1448 {
1449  ThresholdMap
1450  *map;
1451 
1452  map=GetThresholdMapFile(BuiltinMap,"built-in",map_id,exception);
1453  if (map != (ThresholdMap *) NULL)
1454  return(map);
1455 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1456  {
1457  const StringInfo
1458  *option;
1459 
1461  *options;
1462 
1463  options=GetConfigureOptions(ThresholdsFilename,exception);
1464  option=(const StringInfo *) GetNextValueInLinkedList(options);
1465  while (option != (const StringInfo *) NULL)
1466  {
1467  map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
1468  GetStringInfoPath(option),map_id,exception);
1469  if (map != (ThresholdMap *) NULL)
1470  break;
1471  option=(const StringInfo *) GetNextValueInLinkedList(options);
1472  }
1473  options=DestroyConfigureOptions(options);
1474  }
1475 #endif
1476  return(map);
1477 }
1478 
1479 /*
1480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481 % %
1482 % %
1483 % %
1484 + G e t T h r e s h o l d M a p F i l e %
1485 % %
1486 % %
1487 % %
1488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489 %
1490 % GetThresholdMapFile() look for a given threshold map name or alias in the
1491 % given XML file data, and return the allocated the map when found.
1492 %
1493 % The format of the ListThresholdMaps method is:
1494 %
1495 % ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
1496 % const char *map_id,ExceptionInfo *exception)
1497 %
1498 % A description of each parameter follows.
1499 %
1500 % o xml: The threshold map list in XML format.
1501 %
1502 % o filename: The threshold map XML filename.
1503 %
1504 % o map_id: ID of the map to look for in XML list.
1505 %
1506 % o exception: return any errors or warnings in this structure.
1507 %
1508 */
1509 static ThresholdMap *GetThresholdMapFile(const char *xml,const char *filename,
1510  const char *map_id,ExceptionInfo *exception)
1511 {
1512  char
1513  *p;
1514 
1515  const char
1516  *attribute,
1517  *content;
1518 
1519  double
1520  value;
1521 
1522  register ssize_t
1523  i;
1524 
1525  ThresholdMap
1526  *map;
1527 
1528  XMLTreeInfo
1529  *description,
1530  *levels,
1531  *threshold,
1532  *thresholds;
1533 
1535  "Loading threshold map file \"%s\" ...",filename);
1536  map=(ThresholdMap *) NULL;
1537  thresholds=NewXMLTree(xml,exception);
1538  if (thresholds == (XMLTreeInfo *) NULL)
1539  return(map);
1540  for (threshold=GetXMLTreeChild(thresholds,"threshold");
1541  threshold != (XMLTreeInfo *) NULL;
1542  threshold=GetNextXMLTreeTag(threshold))
1543  {
1544  attribute=GetXMLTreeAttribute(threshold,"map");
1545  if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
1546  break;
1547  attribute=GetXMLTreeAttribute(threshold,"alias");
1548  if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
1549  break;
1550  }
1551  if (threshold == (XMLTreeInfo *) NULL)
1552  {
1553  thresholds=DestroyXMLTree(thresholds);
1554  return(map);
1555  }
1556  description=GetXMLTreeChild(threshold,"description");
1557  if (description == (XMLTreeInfo *) NULL)
1558  {
1560  "XmlMissingElement", "<description>, map \"%s\"",map_id);
1561  thresholds=DestroyXMLTree(thresholds);
1562  return(map);
1563  }
1564  levels=GetXMLTreeChild(threshold,"levels");
1565  if (levels == (XMLTreeInfo *) NULL)
1566  {
1568  "XmlMissingElement", "<levels>, map \"%s\"", map_id);
1569  thresholds=DestroyXMLTree(thresholds);
1570  return(map);
1571  }
1572  map=(ThresholdMap *) AcquireCriticalMemory(sizeof(*map));
1573  map->map_id=(char *) NULL;
1574  map->description=(char *) NULL;
1575  map->levels=(ssize_t *) NULL;
1576  attribute=GetXMLTreeAttribute(threshold,"map");
1577  if (attribute != (char *) NULL)
1578  map->map_id=ConstantString(attribute);
1579  content=GetXMLTreeContent(description);
1580  if (content != (char *) NULL)
1581  map->description=ConstantString(content);
1582  attribute=GetXMLTreeAttribute(levels,"width");
1583  if (attribute == (char *) NULL)
1584  {
1586  "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id);
1587  thresholds=DestroyXMLTree(thresholds);
1588  map=DestroyThresholdMap(map);
1589  return(map);
1590  }
1591  map->width=StringToUnsignedLong(attribute);
1592  if (map->width == 0)
1593  {
1595  "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id);
1596  thresholds=DestroyXMLTree(thresholds);
1597  map=DestroyThresholdMap(map);
1598  return(map);
1599  }
1600  attribute=GetXMLTreeAttribute(levels,"height");
1601  if (attribute == (char *) NULL)
1602  {
1604  "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id);
1605  thresholds=DestroyXMLTree(thresholds);
1606  map=DestroyThresholdMap(map);
1607  return(map);
1608  }
1609  map->height=StringToUnsignedLong(attribute);
1610  if (map->height == 0)
1611  {
1613  "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id);
1614  thresholds=DestroyXMLTree(thresholds);
1615  map=DestroyThresholdMap(map);
1616  return(map);
1617  }
1618  attribute=GetXMLTreeAttribute(levels,"divisor");
1619  if (attribute == (char *) NULL)
1620  {
1622  "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id);
1623  thresholds=DestroyXMLTree(thresholds);
1624  map=DestroyThresholdMap(map);
1625  return(map);
1626  }
1627  map->divisor=(ssize_t) StringToLong(attribute);
1628  if (map->divisor < 2)
1629  {
1631  "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id);
1632  thresholds=DestroyXMLTree(thresholds);
1633  map=DestroyThresholdMap(map);
1634  return(map);
1635  }
1636  content=GetXMLTreeContent(levels);
1637  if (content == (char *) NULL)
1638  {
1640  "XmlMissingContent", "<levels>, map \"%s\"",map_id);
1641  thresholds=DestroyXMLTree(thresholds);
1642  map=DestroyThresholdMap(map);
1643  return(map);
1644  }
1645  map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
1646  sizeof(*map->levels));
1647  if (map->levels == (ssize_t *) NULL)
1648  ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
1649  for (i=0; i < (ssize_t) (map->width*map->height); i++)
1650  {
1651  map->levels[i]=(ssize_t) strtol(content,&p,10);
1652  if (p == content)
1653  {
1655  "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id);
1656  thresholds=DestroyXMLTree(thresholds);
1657  map=DestroyThresholdMap(map);
1658  return(map);
1659  }
1660  if ((map->levels[i] < 0) || (map->levels[i] > map->divisor))
1661  {
1663  "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
1664  (double) map->levels[i],map_id);
1665  thresholds=DestroyXMLTree(thresholds);
1666  map=DestroyThresholdMap(map);
1667  return(map);
1668  }
1669  content=p;
1670  }
1671  value=(double) strtol(content,&p,10);
1672  (void) value;
1673  if (p != content)
1674  {
1676  "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id);
1677  thresholds=DestroyXMLTree(thresholds);
1678  map=DestroyThresholdMap(map);
1679  return(map);
1680  }
1681  thresholds=DestroyXMLTree(thresholds);
1682  return(map);
1683 }
1684 
1685 /*
1686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 % %
1688 % %
1689 % %
1690 + L i s t T h r e s h o l d M a p F i l e %
1691 % %
1692 % %
1693 % %
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1695 %
1696 % ListThresholdMapFile() lists the threshold maps and their descriptions
1697 % in the given XML file data.
1698 %
1699 % The format of the ListThresholdMaps method is:
1700 %
1701 % MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
1702 % const char *filename,ExceptionInfo *exception)
1703 %
1704 % A description of each parameter follows.
1705 %
1706 % o file: An pointer to the output FILE.
1707 %
1708 % o xml: The threshold map list in XML format.
1709 %
1710 % o filename: The threshold map XML filename.
1711 %
1712 % o exception: return any errors or warnings in this structure.
1713 %
1714 */
1715 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
1716  const char *filename,ExceptionInfo *exception)
1717 {
1718  const char
1719  *alias,
1720  *content,
1721  *map;
1722 
1723  XMLTreeInfo
1724  *description,
1725  *threshold,
1726  *thresholds;
1727 
1728  assert( xml != (char *) NULL );
1729  assert( file != (FILE *) NULL );
1731  "Loading threshold map file \"%s\" ...",filename);
1732  thresholds=NewXMLTree(xml,exception);
1733  if ( thresholds == (XMLTreeInfo *) NULL )
1734  return(MagickFalse);
1735  (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
1736  (void) FormatLocaleFile(file,
1737  "----------------------------------------------------\n");
1738  threshold=GetXMLTreeChild(thresholds,"threshold");
1739  for ( ; threshold != (XMLTreeInfo *) NULL;
1740  threshold=GetNextXMLTreeTag(threshold))
1741  {
1742  map=GetXMLTreeAttribute(threshold,"map");
1743  if (map == (char *) NULL)
1744  {
1746  "XmlMissingAttribute", "<map>");
1747  thresholds=DestroyXMLTree(thresholds);
1748  return(MagickFalse);
1749  }
1750  alias=GetXMLTreeAttribute(threshold,"alias");
1751  description=GetXMLTreeChild(threshold,"description");
1752  if (description == (XMLTreeInfo *) NULL)
1753  {
1755  "XmlMissingElement", "<description>, map \"%s\"",map);
1756  thresholds=DestroyXMLTree(thresholds);
1757  return(MagickFalse);
1758  }
1759  content=GetXMLTreeContent(description);
1760  if (content == (char *) NULL)
1761  {
1763  "XmlMissingContent", "<description>, map \"%s\"", map);
1764  thresholds=DestroyXMLTree(thresholds);
1765  return(MagickFalse);
1766  }
1767  (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
1768  content);
1769  }
1770  thresholds=DestroyXMLTree(thresholds);
1771  return(MagickTrue);
1772 }
1773 
1774 /*
1775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1776 % %
1777 % %
1778 % %
1779 % L i s t T h r e s h o l d M a p s %
1780 % %
1781 % %
1782 % %
1783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 %
1785 % ListThresholdMaps() lists the threshold maps and their descriptions
1786 % as defined by "threshold.xml" to a file.
1787 %
1788 % The format of the ListThresholdMaps method is:
1789 %
1790 % MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
1791 %
1792 % A description of each parameter follows.
1793 %
1794 % o file: An pointer to the output FILE.
1795 %
1796 % o exception: return any errors or warnings in this structure.
1797 %
1798 */
1800  ExceptionInfo *exception)
1801 {
1802  const StringInfo
1803  *option;
1804 
1806  *options;
1807 
1809  status;
1810 
1811  status=MagickTrue;
1812  if (file == (FILE *) NULL)
1813  file=stdout;
1814  options=GetConfigureOptions(ThresholdsFilename,exception);
1815  (void) FormatLocaleFile(file,
1816  "\n Threshold Maps for Ordered Dither Operations\n");
1817  option=(const StringInfo *) GetNextValueInLinkedList(options);
1818  while (option != (const StringInfo *) NULL)
1819  {
1820  (void) FormatLocaleFile(file,"\nPath: %s\n\n",GetStringInfoPath(option));
1821  status&=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
1822  GetStringInfoPath(option),exception);
1823  option=(const StringInfo *) GetNextValueInLinkedList(options);
1824  }
1825  options=DestroyConfigureOptions(options);
1826  return(status != 0 ? MagickTrue : MagickFalse);
1827 }
1828 
1829 /*
1830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1831 % %
1832 % %
1833 % %
1834 % O r d e r e d D i t h e r I m a g e %
1835 % %
1836 % %
1837 % %
1838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1839 %
1840 % OrderedDitherImage() will perform a ordered dither based on a number
1841 % of pre-defined dithering threshold maps, but over multiple intensity
1842 % levels, which can be different for different channels, according to the
1843 % input argument.
1844 %
1845 % The format of the OrderedDitherImage method is:
1846 %
1847 % MagickBooleanType OrderedDitherImage(Image *image,
1848 % const char *threshold_map,ExceptionInfo *exception)
1849 %
1850 % A description of each parameter follows:
1851 %
1852 % o image: the image.
1853 %
1854 % o threshold_map: A string containing the name of the threshold dither
1855 % map to use, followed by zero or more numbers representing the number
1856 % of color levels to dither between.
1857 %
1858 % Any level number less than 2 will be equivalent to 2, and means only
1859 % binary dithering will be applied to each color channel.
1860 %
1861 % No numbers also means a 2 level (bitmap) dither will be applied to all
1862 % channels, while a single number is the number of levels applied to each
1863 % channel in sequence. More numbers will be applied in turn to each of
1864 % the color channels.
1865 %
1866 % For example: "o3x3,6" will generate a 6 level posterization of the
1867 % image with an ordered 3x3 diffused pixel dither being applied between
1868 % each level. While checker,8,8,4 will produce a 332 colormaped image
1869 % with only a single checkerboard hash pattern (50% grey) between each
1870 % color level, to basically double the number of color levels with
1871 % a bare minimim of dithering.
1872 %
1873 % o exception: return any errors or warnings in this structure.
1874 %
1875 */
1877  const char *threshold_map,ExceptionInfo *exception)
1878 {
1879 #define DitherImageTag "Dither/Image"
1880 
1881  CacheView
1882  *image_view;
1883 
1884  char
1885  token[MagickPathExtent];
1886 
1887  const char
1888  *p;
1889 
1890  double
1891  levels[CompositePixelChannel];
1892 
1894  status;
1895 
1897  progress;
1898 
1899  register ssize_t
1900  i;
1901 
1902  ssize_t
1903  y;
1904 
1905  ThresholdMap
1906  *map;
1907 
1908  assert(image != (Image *) NULL);
1909  assert(image->signature == MagickCoreSignature);
1910  if (image->debug != MagickFalse)
1911  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1912  assert(exception != (ExceptionInfo *) NULL);
1913  assert(exception->signature == MagickCoreSignature);
1914  if (threshold_map == (const char *) NULL)
1915  return(MagickTrue);
1916  p=(char *) threshold_map;
1917  while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
1918  (*p != '\0'))
1919  p++;
1920  threshold_map=p;
1921  while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
1922  (*p != '\0'))
1923  {
1924  if ((p-threshold_map) >= (MagickPathExtent-1))
1925  break;
1926  token[p-threshold_map]=(*p);
1927  p++;
1928  }
1929  token[p-threshold_map]='\0';
1930  map=GetThresholdMap(token,exception);
1931  if (map == (ThresholdMap *) NULL)
1932  {
1934  "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
1935  return(MagickFalse);
1936  }
1937  for (i=0; i < MaxPixelChannels; i++)
1938  levels[i]=2.0;
1939  p=strchr((char *) threshold_map,',');
1940  if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0))
1941  {
1942  (void) GetNextToken(p,&p,MagickPathExtent,token);
1943  for (i=0; (i < MaxPixelChannels); i++)
1944  levels[i]=StringToDouble(token,(char **) NULL);
1945  for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++)
1946  {
1947  (void) GetNextToken(p,&p,MagickPathExtent,token);
1948  if (*token == ',')
1949  (void) GetNextToken(p,&p,MagickPathExtent,token);
1950  levels[i]=StringToDouble(token,(char **) NULL);
1951  }
1952  }
1953  for (i=0; i < MaxPixelChannels; i++)
1954  if (fabs(levels[i]) >= 1)
1955  levels[i]-=1.0;
1956  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1957  return(MagickFalse);
1958  status=MagickTrue;
1959  progress=0;
1960  image_view=AcquireAuthenticCacheView(image,exception);
1961 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1962  #pragma omp parallel for schedule(static) shared(progress,status) \
1963  magick_number_threads(image,image,image->rows,1)
1964 #endif
1965  for (y=0; y < (ssize_t) image->rows; y++)
1966  {
1967  register ssize_t
1968  x;
1969 
1970  register Quantum
1971  *magick_restrict q;
1972 
1973  if (status == MagickFalse)
1974  continue;
1975  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1976  if (q == (Quantum *) NULL)
1977  {
1978  status=MagickFalse;
1979  continue;
1980  }
1981  for (x=0; x < (ssize_t) image->columns; x++)
1982  {
1983  register ssize_t
1984  i;
1985 
1986  ssize_t
1987  n;
1988 
1989  n=0;
1990  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1991  {
1992  ssize_t
1993  level,
1994  threshold;
1995 
1996  PixelChannel channel = GetPixelChannelChannel(image,i);
1997  PixelTrait traits = GetPixelChannelTraits(image,channel);
1998  if ((traits & UpdatePixelTrait) == 0)
1999  continue;
2000  if (fabs(levels[n]) < MagickEpsilon)
2001  {
2002  n++;
2003  continue;
2004  }
2005  threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1));
2006  level=threshold/(map->divisor-1);
2007  threshold-=level*(map->divisor-1);
2008  q[i]=ClampToQuantum((double) (level+(threshold >=
2009  map->levels[(x % map->width)+map->width*(y % map->height)]))*
2010  QuantumRange/levels[n]);
2011  n++;
2012  }
2013  q+=GetPixelChannels(image);
2014  }
2015  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2016  status=MagickFalse;
2017  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2018  {
2020  proceed;
2021 
2022 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2023  #pragma omp atomic
2024 #endif
2025  progress++;
2026  proceed=SetImageProgress(image,DitherImageTag,progress,image->rows);
2027  if (proceed == MagickFalse)
2028  status=MagickFalse;
2029  }
2030  }
2031  image_view=DestroyCacheView(image_view);
2032  map=DestroyThresholdMap(map);
2033  return(MagickTrue);
2034 }
2035 
2036 /*
2037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2038 % %
2039 % %
2040 % %
2041 % P e r c e p t i b l e I m a g e %
2042 % %
2043 % %
2044 % %
2045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2046 %
2047 % PerceptibleImage() set each pixel whose value is less than |epsilon| to
2048 % epsilon or -epsilon (whichever is closer) otherwise the pixel value remains
2049 % unchanged.
2050 %
2051 % The format of the PerceptibleImage method is:
2052 %
2053 % MagickBooleanType PerceptibleImage(Image *image,const double epsilon,
2054 % ExceptionInfo *exception)
2055 %
2056 % A description of each parameter follows:
2057 %
2058 % o image: the image.
2059 %
2060 % o epsilon: the epsilon threshold (e.g. 1.0e-9).
2061 %
2062 % o exception: return any errors or warnings in this structure.
2063 %
2064 */
2065 
2066 static inline Quantum PerceptibleThreshold(const Quantum quantum,
2067  const double epsilon)
2068 {
2069  double
2070  sign;
2071 
2072  sign=(double) quantum < 0.0 ? -1.0 : 1.0;
2073  if ((sign*quantum) >= epsilon)
2074  return(quantum);
2075  return((Quantum) (sign*epsilon));
2076 }
2077 
2079  const double epsilon,ExceptionInfo *exception)
2080 {
2081 #define PerceptibleImageTag "Perceptible/Image"
2082 
2083  CacheView
2084  *image_view;
2085 
2087  status;
2088 
2090  progress;
2091 
2092  ssize_t
2093  y;
2094 
2095  assert(image != (Image *) NULL);
2096  assert(image->signature == MagickCoreSignature);
2097  if (image->debug != MagickFalse)
2098  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2099  if (image->storage_class == PseudoClass)
2100  {
2101  register ssize_t
2102  i;
2103 
2104  register PixelInfo
2105  *magick_restrict q;
2106 
2107  q=image->colormap;
2108  for (i=0; i < (ssize_t) image->colors; i++)
2109  {
2110  q->red=(double) PerceptibleThreshold(ClampToQuantum(q->red),
2111  epsilon);
2112  q->green=(double) PerceptibleThreshold(ClampToQuantum(q->green),
2113  epsilon);
2114  q->blue=(double) PerceptibleThreshold(ClampToQuantum(q->blue),
2115  epsilon);
2116  q->alpha=(double) PerceptibleThreshold(ClampToQuantum(q->alpha),
2117  epsilon);
2118  q++;
2119  }
2120  return(SyncImage(image,exception));
2121  }
2122  /*
2123  Perceptible image.
2124  */
2125  status=MagickTrue;
2126  progress=0;
2127  image_view=AcquireAuthenticCacheView(image,exception);
2128 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2129  #pragma omp parallel for schedule(static) shared(progress,status) \
2130  magick_number_threads(image,image,image->rows,1)
2131 #endif
2132  for (y=0; y < (ssize_t) image->rows; y++)
2133  {
2134  register ssize_t
2135  x;
2136 
2137  register Quantum
2138  *magick_restrict q;
2139 
2140  if (status == MagickFalse)
2141  continue;
2142  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2143  if (q == (Quantum *) NULL)
2144  {
2145  status=MagickFalse;
2146  continue;
2147  }
2148  for (x=0; x < (ssize_t) image->columns; x++)
2149  {
2150  register ssize_t
2151  i;
2152 
2153  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2154  {
2155  PixelChannel channel = GetPixelChannelChannel(image,i);
2156  PixelTrait traits = GetPixelChannelTraits(image,channel);
2157  if (traits == UndefinedPixelTrait)
2158  continue;
2159  q[i]=PerceptibleThreshold(q[i],epsilon);
2160  }
2161  q+=GetPixelChannels(image);
2162  }
2163  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2164  status=MagickFalse;
2165  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2166  {
2168  proceed;
2169 
2170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2171  #pragma omp atomic
2172 #endif
2173  progress++;
2174  proceed=SetImageProgress(image,PerceptibleImageTag,progress,
2175  image->rows);
2176  if (proceed == MagickFalse)
2177  status=MagickFalse;
2178  }
2179  }
2180  image_view=DestroyCacheView(image_view);
2181  return(status);
2182 }
2183 
2184 /*
2185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2186 % %
2187 % %
2188 % %
2189 % R a n d o m T h r e s h o l d I m a g e %
2190 % %
2191 % %
2192 % %
2193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194 %
2195 % RandomThresholdImage() changes the value of individual pixels based on the
2196 % intensity of each pixel compared to a random threshold. The result is a
2197 % low-contrast, two color image.
2198 %
2199 % The format of the RandomThresholdImage method is:
2200 %
2201 % MagickBooleanType RandomThresholdImage(Image *image,
2202 % const char *thresholds,ExceptionInfo *exception)
2203 %
2204 % A description of each parameter follows:
2205 %
2206 % o image: the image.
2207 %
2208 % o low,high: Specify the high and low thresholds. These values range from
2209 % 0 to QuantumRange.
2210 %
2211 % o exception: return any errors or warnings in this structure.
2212 %
2213 */
2215  const double min_threshold, const double max_threshold,ExceptionInfo *exception)
2216 {
2217 #define ThresholdImageTag "Threshold/Image"
2218 
2219  CacheView
2220  *image_view;
2221 
2223  status;
2224 
2226  progress;
2227 
2228  PixelInfo
2229  threshold;
2230 
2231  RandomInfo
2233 
2234  ssize_t
2235  y;
2236 
2237 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2238  unsigned long
2239  key;
2240 #endif
2241 
2242  assert(image != (Image *) NULL);
2243  assert(image->signature == MagickCoreSignature);
2244  if (image->debug != MagickFalse)
2245  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2246  assert(exception != (ExceptionInfo *) NULL);
2247  assert(exception->signature == MagickCoreSignature);
2248  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2249  return(MagickFalse);
2250  GetPixelInfo(image,&threshold);
2251  /*
2252  Random threshold image.
2253  */
2254  status=MagickTrue;
2255  progress=0;
2257  image_view=AcquireAuthenticCacheView(image,exception);
2258 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2260  #pragma omp parallel for schedule(static) shared(progress,status) \
2261  magick_number_threads(image,image,image->rows,key == ~0UL)
2262 #endif
2263  for (y=0; y < (ssize_t) image->rows; y++)
2264  {
2265  const int
2266  id = GetOpenMPThreadId();
2267 
2268  register Quantum
2269  *magick_restrict q;
2270 
2271  register ssize_t
2272  x;
2273 
2274  if (status == MagickFalse)
2275  continue;
2276  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2277  if (q == (Quantum *) NULL)
2278  {
2279  status=MagickFalse;
2280  continue;
2281  }
2282  for (x=0; x < (ssize_t) image->columns; x++)
2283  {
2284  register ssize_t
2285  i;
2286 
2287  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2288  {
2289  double
2290  threshold;
2291 
2292  PixelChannel channel = GetPixelChannelChannel(image,i);
2293  PixelTrait traits = GetPixelChannelTraits(image,channel);
2294  if ((traits & UpdatePixelTrait) == 0)
2295  continue;
2296  if ((double) q[i] < min_threshold)
2297  threshold=min_threshold;
2298  else
2299  if ((double) q[i] > max_threshold)
2300  threshold=max_threshold;
2301  else
2302  threshold=(double) (QuantumRange*
2304  q[i]=(double) q[i] <= threshold ? 0 : QuantumRange;
2305  }
2306  q+=GetPixelChannels(image);
2307  }
2308  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2309  status=MagickFalse;
2310  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2311  {
2313  proceed;
2314 
2315 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2316  #pragma omp atomic
2317 #endif
2318  progress++;
2319  proceed=SetImageProgress(image,ThresholdImageTag,progress,
2320  image->rows);
2321  if (proceed == MagickFalse)
2322  status=MagickFalse;
2323  }
2324  }
2325  image_view=DestroyCacheView(image_view);
2327  return(status);
2328 }
2329 
2330 /*
2331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2332 % %
2333 % %
2334 % %
2335 % R a n g e T h r e s h o l d I m a g e %
2336 % %
2337 % %
2338 % %
2339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2340 %
2341 % RangeThresholdImage() applies soft and hard thresholding.
2342 %
2343 % The format of the RangeThresholdImage method is:
2344 %
2345 % MagickBooleanType RangeThresholdImage(Image *image,
2346 % const double low_black,const double low_white,const double high_white,
2347 % const double high_black,ExceptionInfo *exception)
2348 %
2349 % A description of each parameter follows:
2350 %
2351 % o image: the image.
2352 %
2353 % o low_black: Define the minimum black threshold value.
2354 %
2355 % o low_white: Define the minimum white threshold value.
2356 %
2357 % o high_white: Define the maximum white threshold value.
2358 %
2359 % o high_black: Define the maximum black threshold value.
2360 %
2361 % o exception: return any errors or warnings in this structure.
2362 %
2363 */
2365  const double low_black,const double low_white,const double high_white,
2366  const double high_black,ExceptionInfo *exception)
2367 {
2368 #define ThresholdImageTag "Threshold/Image"
2369 
2370  CacheView
2371  *image_view;
2372 
2374  status;
2375 
2377  progress;
2378 
2379  ssize_t
2380  y;
2381 
2382  assert(image != (Image *) NULL);
2383  assert(image->signature == MagickCoreSignature);
2384  if (image->debug != MagickFalse)
2385  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2386  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2387  return(MagickFalse);
2388  if (IsGrayColorspace(image->colorspace) != MagickFalse)
2389  (void) TransformImageColorspace(image,sRGBColorspace,exception);
2390  /*
2391  Range threshold image.
2392  */
2393  status=MagickTrue;
2394  progress=0;
2395  image_view=AcquireAuthenticCacheView(image,exception);
2396 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2397  #pragma omp parallel for schedule(static) shared(progress,status) \
2398  magick_number_threads(image,image,image->rows,1)
2399 #endif
2400  for (y=0; y < (ssize_t) image->rows; y++)
2401  {
2402  register ssize_t
2403  x;
2404 
2405  register Quantum
2406  *magick_restrict q;
2407 
2408  if (status == MagickFalse)
2409  continue;
2410  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2411  if (q == (Quantum *) NULL)
2412  {
2413  status=MagickFalse;
2414  continue;
2415  }
2416  for (x=0; x < (ssize_t) image->columns; x++)
2417  {
2418  double
2419  pixel;
2420 
2421  register ssize_t
2422  i;
2423 
2424  pixel=GetPixelIntensity(image,q);
2425  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2426  {
2427  PixelChannel channel = GetPixelChannelChannel(image,i);
2428  PixelTrait traits = GetPixelChannelTraits(image,channel);
2429  if ((traits & UpdatePixelTrait) == 0)
2430  continue;
2431  if (image->channel_mask != DefaultChannels)
2432  pixel=(double) q[i];
2433  if (pixel < low_black)
2434  q[i]=(Quantum) 0;
2435  else
2436  if ((pixel >= low_black) && (pixel < low_white))
2438  PerceptibleReciprocal(low_white-low_black)*(pixel-low_black));
2439  else
2440  if ((pixel >= low_white) && (pixel <= high_white))
2441  q[i]=QuantumRange;
2442  else
2443  if ((pixel > high_white) && (pixel <= high_black))
2445  high_black-high_white)*(high_black-pixel));
2446  else
2447  if (pixel > high_black)
2448  q[i]=(Quantum) 0;
2449  else
2450  q[i]=(Quantum) 0;
2451  }
2452  q+=GetPixelChannels(image);
2453  }
2454  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2455  status=MagickFalse;
2456  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2457  {
2459  proceed;
2460 
2461 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2462  #pragma omp atomic
2463 #endif
2464  progress++;
2465  proceed=SetImageProgress(image,ThresholdImageTag,progress,
2466  image->rows);
2467  if (proceed == MagickFalse)
2468  status=MagickFalse;
2469  }
2470  }
2471  image_view=DestroyCacheView(image_view);
2472  return(status);
2473 }
2474 
2475 /*
2476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477 % %
2478 % %
2479 % %
2480 % W h i t e T h r e s h o l d I m a g e %
2481 % %
2482 % %
2483 % %
2484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485 %
2486 % WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
2487 % the threshold into white while leaving all pixels at or below the threshold
2488 % unchanged.
2489 %
2490 % The format of the WhiteThresholdImage method is:
2491 %
2492 % MagickBooleanType WhiteThresholdImage(Image *image,
2493 % const char *threshold,ExceptionInfo *exception)
2494 %
2495 % A description of each parameter follows:
2496 %
2497 % o image: the image.
2498 %
2499 % o threshold: Define the threshold value.
2500 %
2501 % o exception: return any errors or warnings in this structure.
2502 %
2503 */
2505  const char *thresholds,ExceptionInfo *exception)
2506 {
2507 #define ThresholdImageTag "Threshold/Image"
2508 
2509  CacheView
2510  *image_view;
2511 
2512  GeometryInfo
2513  geometry_info;
2514 
2516  status;
2517 
2519  progress;
2520 
2521  PixelInfo
2522  threshold;
2523 
2525  flags;
2526 
2527  ssize_t
2528  y;
2529 
2530  assert(image != (Image *) NULL);
2531  assert(image->signature == MagickCoreSignature);
2532  if (image->debug != MagickFalse)
2533  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2534  if (thresholds == (const char *) NULL)
2535  return(MagickTrue);
2536  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2537  return(MagickFalse);
2538  if (IsGrayColorspace(image->colorspace) != MagickFalse)
2539  (void) TransformImageColorspace(image,sRGBColorspace,exception);
2540  GetPixelInfo(image,&threshold);
2541  flags=ParseGeometry(thresholds,&geometry_info);
2542  threshold.red=geometry_info.rho;
2543  threshold.green=geometry_info.rho;
2544  threshold.blue=geometry_info.rho;
2545  threshold.black=geometry_info.rho;
2546  threshold.alpha=100.0;
2547  if ((flags & SigmaValue) != 0)
2548  threshold.green=geometry_info.sigma;
2549  if ((flags & XiValue) != 0)
2550  threshold.blue=geometry_info.xi;
2551  if ((flags & PsiValue) != 0)
2552  threshold.alpha=geometry_info.psi;
2553  if (threshold.colorspace == CMYKColorspace)
2554  {
2555  if ((flags & PsiValue) != 0)
2556  threshold.black=geometry_info.psi;
2557  if ((flags & ChiValue) != 0)
2558  threshold.alpha=geometry_info.chi;
2559  }
2560  if ((flags & PercentValue) != 0)
2561  {
2562  threshold.red*=(MagickRealType) (QuantumRange/100.0);
2563  threshold.green*=(MagickRealType) (QuantumRange/100.0);
2564  threshold.blue*=(MagickRealType) (QuantumRange/100.0);
2565  threshold.black*=(MagickRealType) (QuantumRange/100.0);
2566  threshold.alpha*=(MagickRealType) (QuantumRange/100.0);
2567  }
2568  /*
2569  White threshold image.
2570  */
2571  status=MagickTrue;
2572  progress=0;
2573  image_view=AcquireAuthenticCacheView(image,exception);
2574 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2575  #pragma omp parallel for schedule(static) shared(progress,status) \
2576  magick_number_threads(image,image,image->rows,1)
2577 #endif
2578  for (y=0; y < (ssize_t) image->rows; y++)
2579  {
2580  register ssize_t
2581  x;
2582 
2583  register Quantum
2584  *magick_restrict q;
2585 
2586  if (status == MagickFalse)
2587  continue;
2588  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2589  if (q == (Quantum *) NULL)
2590  {
2591  status=MagickFalse;
2592  continue;
2593  }
2594  for (x=0; x < (ssize_t) image->columns; x++)
2595  {
2596  double
2597  pixel;
2598 
2599  register ssize_t
2600  i;
2601 
2602  pixel=GetPixelIntensity(image,q);
2603  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2604  {
2605  PixelChannel channel = GetPixelChannelChannel(image,i);
2606  PixelTrait traits = GetPixelChannelTraits(image,channel);
2607  if ((traits & UpdatePixelTrait) == 0)
2608  continue;
2609  if (image->channel_mask != DefaultChannels)
2610  pixel=(double) q[i];
2611  if (pixel > GetPixelInfoChannel(&threshold,channel))
2612  q[i]=QuantumRange;
2613  }
2614  q+=GetPixelChannels(image);
2615  }
2616  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2617  status=MagickFalse;
2618  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2619  {
2621  proceed;
2622 
2623 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2624  #pragma omp atomic
2625 #endif
2626  progress++;
2627  proceed=SetImageProgress(image,ThresholdImageTag,progress,image->rows);
2628  if (proceed == MagickFalse)
2629  status=MagickFalse;
2630  }
2631  }
2632  image_view=DestroyCacheView(image_view);
2633  return(status);
2634 }
#define DitherImageTag
double psi
Definition: geometry.h:106
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport MagickBooleanType BlackThresholdImage(Image *image, const char *thresholds, ExceptionInfo *exception)
Definition: threshold.c:929
MagickExport MagickBooleanType RangeThresholdImage(Image *image, const double low_black, const double low_white, const double high_white, const double high_black, ExceptionInfo *exception)
Definition: threshold.c:2364
MagickDoubleType MagickRealType
Definition: magick-type.h:124
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
PixelInfo * colormap
Definition: image.h:179
MagickExport void ConvertRGBToHSL(const double red, const double green, const double blue, double *hue, double *saturation, double *lightness)
Definition: gem.c:1099
MagickExport XMLTreeInfo * DestroyXMLTree(XMLTreeInfo *xml_info)
Definition: xml-tree.c:558
MagickProgressMonitor progress_monitor
Definition: image.h:303
ImageType type
Definition: image.h:264
MagickExport MagickBooleanType SyncImage(Image *image, ExceptionInfo *exception)
Definition: image.c:3870
MagickExport MagickBooleanType TransformImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1503
static unsigned long StringToUnsignedLong(const char *magick_restrict value)
static const char *const BuiltinMap
Definition: threshold.c:124
#define ThrowFatalException(severity, tag)
MagickExport XMLTreeInfo * GetNextXMLTreeTag(XMLTreeInfo *xml_info)
Definition: xml-tree.c:744
size_t signature
Definition: exception.h:123
size_t width
Definition: threshold.c:109
double rho
Definition: geometry.h:106
MagickExport MagickBooleanType ListThresholdMaps(FILE *file, ExceptionInfo *exception)
Definition: threshold.c:1799
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:193
static RandomInfo ** DestroyRandomInfoThreadSet(RandomInfo **random_info)
static double StringToDouble(const char *magick_restrict string, char **magick_restrict sentinal)
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
MagickExport Image * AdaptiveThresholdImage(const Image *image, const size_t width, const size_t height, const double bias, ExceptionInfo *exception)
Definition: threshold.c:183
#define ThresholdsFilename
Definition: threshold.c:97
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:499
static MagickBooleanType IsGrayColorspace(const ColorspaceType colorspace)
char * map_id
Definition: threshold.c:105
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)
static long StringToLong(const char *magick_restrict value)
MagickRealType alpha
Definition: pixel.h:193
#define MagickEpsilon
Definition: magick-type.h:114
MagickExport XMLTreeInfo * GetXMLTreeChild(XMLTreeInfo *xml_info, const char *tag)
Definition: xml-tree.c:896
double sigma
Definition: geometry.h:106
MagickExport MagickBooleanType PerceptibleImage(Image *image, const double epsilon, ExceptionInfo *exception)
Definition: threshold.c:2078
ClassType storage_class
Definition: image.h:154
#define ThrowBinaryException(severity, tag, context)
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:133
MagickExport unsigned long GetRandomSecretKey(const RandomInfo *random_info)
Definition: random.c:741
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
MagickBooleanType ListThresholdMapFile(FILE *file, const char *xml, const char *filename, ExceptionInfo *exception)
Definition: threshold.c:1715
#define PerceptibleImageTag
Definition: image.h:151
MagickPrivate void ConvertRGBToHSB(const double, const double, const double, double *, double *, double *)
char * description
Definition: threshold.c:105
MagickExport void * GetNextValueInLinkedList(LinkedListInfo *list_info)
Definition: linked-list.c:305
#define MagickMinimumValue
Definition: magick-type.h:116
#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
static Quantum ClampPixel(const MagickRealType pixel)
MagickExport unsigned char * GetStringInfoDatum(const StringInfo *string_info)
Definition: string.c:1205
MagickExport LinkedListInfo * GetConfigureOptions(const char *filename, ExceptionInfo *exception)
Definition: configure.c:642
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:404
MagickBooleanType
Definition: magick-type.h:169
unsigned int MagickStatusType
Definition: magick-type.h:125
static double PerceptibleReciprocal(const double x)
MagickExport void * AcquireCriticalMemory(const size_t size)
Definition: memory.c:595
#define ThresholdImageTag
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:634
#define MaxIntensity
MagickExport magick_hot_spot size_t GetNextToken(const char *magick_restrict start, const char **magick_restrict end, const size_t extent, char *magick_restrict token)
Definition: token.c:174
static int GetOpenMPThreadId(void)
size_t height
Definition: threshold.c:109
ChannelType channel_mask
Definition: image.h:288
MagickExport MagickBooleanType SetImageProperty(Image *image, const char *property, const char *value, ExceptionInfo *exception)
Definition: property.c:4205
MagickExport const char * GetXMLTreeContent(XMLTreeInfo *xml_info)
Definition: xml-tree.c:936
ssize_t divisor
Definition: threshold.c:113
size_t MagickSizeType
Definition: magick-type.h:134
#define MagickPathExtent
MagickExport MagickBooleanType IsStringTrue(const char *value)
Definition: string.c:1415
static double OTSUThreshold(const Image *image, const double *histogram, ExceptionInfo *exception)
Definition: threshold.c:493
MagickExport ThresholdMap * GetThresholdMap(const char *map_id, ExceptionInfo *exception)
Definition: threshold.c:1446
MagickExport int GetMagickPrecision(void)
Definition: magick.c:942
#define ClampImageTag
MagickPrivate void ConvertRGBToHSV(const double, const double, const double, double *, double *, double *)
MagickRealType blue
Definition: pixel.h:193
MagickExport MagickBooleanType ColorThresholdImage(Image *image, const PixelInfo *start_color, const PixelInfo *stop_color, ExceptionInfo *exception)
Definition: threshold.c:1219
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
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
size_t signature
Definition: image.h:354
#define QuantumScale
Definition: magick-type.h:119
size_t columns
Definition: image.h:172
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
#define AdaptiveThresholdImageTag
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2595
PixelChannel
Definition: pixel.h:70
size_t colors
Definition: image.h:172
static double TriangleThreshold(const double *histogram)
Definition: threshold.c:572
static size_t GetPixelChannels(const Image *magick_restrict image)
MagickExport MagickBooleanType AcquireImageColormap(Image *image, const size_t colors, ExceptionInfo *exception)
Definition: colormap.c:104
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1435
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
double chi
Definition: geometry.h:106
MagickExport const char * GetStringInfoPath(const StringInfo *string_info)
Definition: string.c:1292
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
static MagickRealType GetPixelInfoChannel(const PixelInfo *magick_restrict pixel_info, const PixelChannel channel)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
AutoThresholdMethod
Definition: threshold.h:25
MagickExport const char * GetXMLTreeAttribute(XMLTreeInfo *xml_info, const char *tag)
Definition: xml-tree.c:779
MagickExport MagickBooleanType RandomThresholdImage(Image *image, const double min_threshold, const double max_threshold, ExceptionInfo *exception)
Definition: threshold.c:2214
unsigned short Quantum
Definition: magick-type.h:86
double xi
Definition: geometry.h:106
MagickExport MagickBooleanType SetImageColorspace(Image *image, const ColorspaceType colorspace, ExceptionInfo *exception)
Definition: colorspace.c:1312
MagickRealType black
Definition: pixel.h:193
MagickExport char * DestroyString(char *string)
Definition: string.c:813
MagickPrivate void ConvertRGBToLab(const double, const double, const double, double *, double *, double *)
MagickExport double GetPseudoRandomValue(RandomInfo *magick_restrict random_info)
Definition: random.c:610
static void SetPixelIndex(const Image *magick_restrict image, const Quantum index, Quantum *magick_restrict pixel)
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:853
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
MagickExport ThresholdMap * DestroyThresholdMap(ThresholdMap *map)
Definition: threshold.c:1407
static ThresholdMap * GetThresholdMapFile(const char *, const char *, const char *, ExceptionInfo *)
Definition: threshold.c:1509
MagickExport MagickBooleanType BilevelImage(Image *image, const double threshold, ExceptionInfo *exception)
Definition: threshold.c:807
MagickPrivate void ConvertRGBToHWB(const double, const double, const double, double *, double *, double *)
static RandomInfo * random_info
Definition: resource.c:113
static Quantum PerceptibleThreshold(const Quantum quantum, const double epsilon)
Definition: threshold.c:2066
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1122
#define MaxPixelChannels
Definition: pixel.h:27
MagickExport MagickBooleanType WhiteThresholdImage(Image *image, const char *thresholds, ExceptionInfo *exception)
Definition: threshold.c:2504
MagickExport MagickBooleanType ClampImage(Image *image, ExceptionInfo *exception)
Definition: threshold.c:1089
MagickRealType green
Definition: pixel.h:193
static double KapurThreshold(const Image *image, const double *histogram, ExceptionInfo *exception)
Definition: threshold.c:394
#define MagickExport
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
ColorspaceType colorspace
Definition: pixel.h:178
MagickExport MagickBooleanType OrderedDitherImage(Image *image, const char *threshold_map, ExceptionInfo *exception)
Definition: threshold.c:1876
MagickPrivate void ConvertRGBToHCL(const double, const double, const double, double *, double *, double *)
PixelTrait
Definition: pixel.h:137
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport LinkedListInfo * DestroyConfigureOptions(LinkedListInfo *options)
Definition: configure.c:314
MagickExport MagickBooleanType AutoThresholdImage(Image *image, const AutoThresholdMethod method, ExceptionInfo *exception)
Definition: threshold.c:662
ssize_t * levels
Definition: threshold.c:113
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1160
MagickExport char * ConstantString(const char *source)
Definition: string.c:702
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:775
ColorspaceType colorspace
Definition: image.h:157
MagickExport XMLTreeInfo * NewXMLTree(const char *xml, ExceptionInfo *exception)
Definition: xml-tree.c:1956
#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
MagickBooleanType debug
Definition: image.h:334