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