Magick++  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
Statistic.cpp
1 // This may look like C code, but it is really -*- C++ -*-
2 //
3 // Copyright @ 2014 ImageMagick Studio LLC, a non-profit organization
4 // dedicated to making software imaging solutions freely available.
5 //
6 // Implementation of channel moments.
7 //
8 
9 #define MAGICKCORE_IMPLEMENTATION 1
10 #define MAGICK_PLUSPLUS_IMPLEMENTATION 1
11 
12 #include "Magick++/Include.h"
13 #include "Magick++/Exception.h"
14 #include "Magick++/Statistic.h"
15 #include "Magick++/Image.h"
16 
17 using namespace std;
18 
19 Magick::ChannelMoments::ChannelMoments(void)
20  : _channel(SyncPixelChannel),
21  _huInvariants(8),
22  _centroidX(0.0),
23  _centroidY(0.0),
24  _ellipseAxisX(0.0),
25  _ellipseAxisY(0.0),
26  _ellipseAngle(0.0),
27  _ellipseEccentricity(0.0),
28  _ellipseIntensity(0.0)
29 {
30 }
31 
32 Magick::ChannelMoments::ChannelMoments(const ChannelMoments &channelMoments_)
33  : _channel(channelMoments_._channel),
34  _huInvariants(channelMoments_._huInvariants),
35  _centroidX(channelMoments_._centroidX),
36  _centroidY(channelMoments_._centroidY),
37  _ellipseAxisX(channelMoments_._ellipseAxisX),
38  _ellipseAxisY(channelMoments_._ellipseAxisY),
39  _ellipseAngle(channelMoments_._ellipseAngle),
40  _ellipseEccentricity(channelMoments_._ellipseEccentricity),
41  _ellipseIntensity(channelMoments_._ellipseIntensity)
42 {
43 }
44 
45 Magick::ChannelMoments::~ChannelMoments(void)
46 {
47 }
48 
49 double Magick::ChannelMoments::centroidX(void) const
50 {
51  return(_centroidX);
52 }
53 
54 double Magick::ChannelMoments::centroidY(void) const
55 {
56  return(_centroidY);
57 }
58 
59 Magick::PixelChannel Magick::ChannelMoments::channel(void) const
60 {
61  return(_channel);
62 }
63 
64 double Magick::ChannelMoments::ellipseAxisX(void) const
65 {
66  return(_ellipseAxisX);
67 }
68 
69 double Magick::ChannelMoments::ellipseAxisY(void) const
70 {
71  return(_ellipseAxisY);
72 }
73 
74 double Magick::ChannelMoments::ellipseAngle(void) const
75 {
76  return(_ellipseAngle);
77 }
78 
79 double Magick::ChannelMoments::ellipseEccentricity(void) const
80 {
81  return(_ellipseEccentricity);
82 }
83 
84 double Magick::ChannelMoments::ellipseIntensity(void) const
85 {
86  return(_ellipseIntensity);
87 }
88 
89 double Magick::ChannelMoments::huInvariants(const size_t index_) const
90 {
91  if (index_ > 7)
92  throw ErrorOption("Valid range for index is 0-7");
93 
94  return(_huInvariants.at(index_));
95 }
96 
97 bool Magick::ChannelMoments::isValid() const
98 {
99  return(_channel != SyncPixelChannel);
100 }
101 
102 Magick::ChannelMoments::ChannelMoments(const PixelChannel channel_,
103  const MagickCore::ChannelMoments *channelMoments_)
104  : _channel(channel_),
105  _huInvariants(),
106  _centroidX(channelMoments_->centroid.x),
107  _centroidY(channelMoments_->centroid.y),
108  _ellipseAxisX(channelMoments_->ellipse_axis.x),
109  _ellipseAxisY(channelMoments_->ellipse_axis.y),
110  _ellipseAngle(channelMoments_->ellipse_angle),
111  _ellipseEccentricity(channelMoments_->ellipse_eccentricity),
112  _ellipseIntensity(channelMoments_->ellipse_intensity)
113 {
114  ssize_t
115  i;
116 
117  for (i=0; i<8; i++)
118  _huInvariants.push_back(channelMoments_->invariant[i]);
119 }
120 
121 Magick::ChannelPerceptualHash::ChannelPerceptualHash(void)
122  : _channel(SyncPixelChannel),
123  _srgbHuPhash(7),
124  _hclpHuPhash(7)
125 {
126 }
127 
128 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
129  const ChannelPerceptualHash &channelPerceptualHash_)
130  : _channel(channelPerceptualHash_._channel),
131  _srgbHuPhash(channelPerceptualHash_._srgbHuPhash),
132  _hclpHuPhash(channelPerceptualHash_._hclpHuPhash)
133 {
134 }
135 
136 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
137  const PixelChannel channel_,const std::string &hash_)
138  : _channel(channel_),
139  _srgbHuPhash(7),
140  _hclpHuPhash(7)
141 {
142  size_t
143  i;
144 
145  if (hash_.length() != 70)
146  throw ErrorOption("Invalid hash length");
147 
148  for (i=0; i<14; i++)
149  {
150  unsigned int
151  hex;
152 
153  double
154  value;
155 
156 #if defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
157  if (sscanf_s(hash_.substr(i*5,5).c_str(),"%05x",&hex) != 1)
158 #else
159  if (sscanf(hash_.substr(i*5,5).c_str(),"%05x",&hex) != 1)
160 #endif
161  throw ErrorOption("Invalid hash value");
162 
163  value=((unsigned short)hex) / pow(10.0, (double)(hex >> 17));
164  if (hex & (1 << 16))
165  value=-value;
166  if (i < 7)
167  _srgbHuPhash[i]=value;
168  else
169  _hclpHuPhash[i-7]=value;
170  }
171 }
172 
173 Magick::ChannelPerceptualHash::~ChannelPerceptualHash(void)
174 {
175 }
176 
177 Magick::ChannelPerceptualHash::operator std::string() const
178 {
179  std::string
180  hash;
181 
182  size_t
183  i;
184 
185  if (!isValid())
186  return(std::string());
187 
188  for (i=0; i<14; i++)
189  {
190  char
191  buffer[6];
192 
193  double
194  value;
195 
196  unsigned int
197  hex;
198 
199  if (i < 7)
200  value=_srgbHuPhash[i];
201  else
202  value=_hclpHuPhash[i-7];
203 
204  hex=0;
205  while(hex < 7 && fabs(value*10) < 65536)
206  {
207  value=value*10;
208  hex++;
209  }
210 
211  hex=(hex<<1);
212  if (value < 0.0)
213  hex|=1;
214  hex=(hex<<16)+(unsigned int)(value < 0.0 ? -(value - 0.5) : value + 0.5);
215  (void) FormatLocaleString(buffer,6,"%05x",hex);
216  hash+=std::string(buffer);
217  }
218  return(hash);
219 }
220 
221 Magick::PixelChannel Magick::ChannelPerceptualHash::channel() const
222 {
223  return(_channel);
224 }
225 
226 bool Magick::ChannelPerceptualHash::isValid() const
227 {
228  return(_channel != SyncPixelChannel);
229 }
230 
231 double Magick::ChannelPerceptualHash::sumSquaredDifferences(
232  const ChannelPerceptualHash &channelPerceptualHash_)
233 {
234  double
235  ssd;
236 
237  size_t
238  i;
239 
240  ssd=0.0;
241  for (i=0; i<7; i++)
242  {
243  ssd+=((_srgbHuPhash[i]-channelPerceptualHash_._srgbHuPhash[i])*
244  (_srgbHuPhash[i]-channelPerceptualHash_._srgbHuPhash[i]));
245  ssd+=((_hclpHuPhash[i]-channelPerceptualHash_._hclpHuPhash[i])*
246  (_hclpHuPhash[i]-channelPerceptualHash_._hclpHuPhash[i]));
247  }
248  return(ssd);
249 }
250 
251 double Magick::ChannelPerceptualHash::srgbHuPhash(const size_t index_) const
252 {
253  if (index_ > 6)
254  throw ErrorOption("Valid range for index is 0-6");
255 
256  return(_srgbHuPhash.at(index_));
257 }
258 
259 double Magick::ChannelPerceptualHash::hclpHuPhash(const size_t index_) const
260 {
261  if (index_ > 6)
262  throw ErrorOption("Valid range for index is 0-6");
263 
264  return(_hclpHuPhash.at(index_));
265 }
266 
267 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
268  const PixelChannel channel_,
269  const MagickCore::ChannelPerceptualHash *channelPerceptualHash_)
270  : _channel(channel_),
271  _srgbHuPhash(7),
272  _hclpHuPhash(7)
273 {
274  size_t
275  i;
276 
277  for (i=0; i<7; i++)
278  {
279  _srgbHuPhash[i]=channelPerceptualHash_->phash[0][i];
280  _hclpHuPhash[i]=channelPerceptualHash_->phash[1][i];
281  }
282 }
283 
284 Magick::ChannelStatistics::ChannelStatistics(void)
285  : _channel(SyncPixelChannel),
286  _area(0.0),
287  _depth(0),
288  _entropy(0.0),
289  _kurtosis(0.0),
290  _maxima(0.0),
291  _mean(0.0),
292  _minima(0.0),
293  _skewness(0.0),
294  _standardDeviation(0.0),
295  _sum(0.0),
296  _sumCubed(0.0),
297  _sumFourthPower(0.0),
298  _sumSquared(0.0),
299  _variance(0.0)
300 {
301 }
302 
303 Magick::ChannelStatistics::ChannelStatistics(
304  const ChannelStatistics &channelStatistics_)
305  : _channel(channelStatistics_._channel),
306  _area(channelStatistics_._area),
307  _depth(channelStatistics_._depth),
308  _entropy(channelStatistics_._entropy),
309  _kurtosis(channelStatistics_._kurtosis),
310  _maxima(channelStatistics_._maxima),
311  _mean(channelStatistics_._mean),
312  _minima(channelStatistics_._minima),
313  _skewness(channelStatistics_._skewness),
314  _standardDeviation(channelStatistics_._standardDeviation),
315  _sum(channelStatistics_._sum),
316  _sumCubed(channelStatistics_._sumCubed),
317  _sumFourthPower(channelStatistics_._sumFourthPower),
318  _sumSquared(channelStatistics_._sumSquared),
319  _variance(channelStatistics_._variance)
320 {
321 }
322 
323 Magick::ChannelStatistics::~ChannelStatistics(void)
324 {
325 }
326 
327 double Magick::ChannelStatistics::area() const
328 {
329  return(_area);
330 }
331 
332 Magick::PixelChannel Magick::ChannelStatistics::channel() const
333 {
334  return(_channel);
335 }
336 
337 size_t Magick::ChannelStatistics::depth() const
338 {
339  return(_depth);
340 }
341 
342 double Magick::ChannelStatistics::entropy() const
343 {
344  return(_entropy);
345 }
346 
347 bool Magick::ChannelStatistics::isValid() const
348 {
349  return(_channel != SyncPixelChannel);
350 }
351 
352 double Magick::ChannelStatistics::kurtosis() const
353 {
354  return(_kurtosis);
355 }
356 
357 double Magick::ChannelStatistics::maxima() const
358 {
359  return(_maxima);
360 }
361 
362 double Magick::ChannelStatistics::mean() const
363 {
364  return(_mean);
365 }
366 
367 double Magick::ChannelStatistics::minima() const
368 {
369  return(_minima);
370 }
371 
372 double Magick::ChannelStatistics::skewness() const
373 {
374  return(_skewness);
375 }
376 
377 double Magick::ChannelStatistics::standardDeviation() const
378 {
379  return(_standardDeviation);
380 }
381 
382 double Magick::ChannelStatistics::sum() const
383 {
384  return(_sum);
385 }
386 
387 double Magick::ChannelStatistics::sumCubed() const
388 {
389  return(_sumCubed);
390 }
391 
392 double Magick::ChannelStatistics::sumFourthPower() const
393 {
394  return(_sumFourthPower);
395 }
396 
397 double Magick::ChannelStatistics::sumSquared() const
398 {
399  return(_sumSquared);
400 }
401 
402 double Magick::ChannelStatistics::variance() const
403 {
404  return(_variance);
405 }
406 
407 Magick::ChannelStatistics::ChannelStatistics(const PixelChannel channel_,
408  const MagickCore::ChannelStatistics *channelStatistics_)
409  : _channel(channel_),
410  _area(channelStatistics_->area),
411  _depth(channelStatistics_->depth),
412  _entropy(channelStatistics_->entropy),
413  _kurtosis(channelStatistics_->kurtosis),
414  _maxima(channelStatistics_->maxima),
415  _mean(channelStatistics_->mean),
416  _minima(channelStatistics_->minima),
417  _skewness(channelStatistics_->skewness),
418  _standardDeviation(channelStatistics_->standard_deviation),
419  _sum(channelStatistics_->sum),
420  _sumCubed(channelStatistics_->sum_cubed),
421  _sumFourthPower(channelStatistics_->sum_fourth_power),
422  _sumSquared(channelStatistics_->sum_squared),
423  _variance(channelStatistics_->variance)
424 {
425 }
426 
427 Magick::ImageMoments::ImageMoments(void)
428  : _channels()
429 {
430 }
431 
432 Magick::ImageMoments::ImageMoments(const ImageMoments &imageMoments_)
433  : _channels(imageMoments_._channels)
434 {
435 }
436 
437 Magick::ImageMoments::~ImageMoments(void)
438 {
439 }
440 
441 Magick::ChannelMoments Magick::ImageMoments::channel(
442  const PixelChannel channel_) const
443 {
444  for (std::vector<ChannelMoments>::const_iterator it = _channels.begin();
445  it != _channels.end(); ++it)
446  {
447  if (it->channel() == channel_)
448  return(*it);
449  }
450  return(ChannelMoments());
451 }
452 
453 Magick::ImageMoments::ImageMoments(const Image &image_)
454  : _channels()
455 {
456  MagickCore::ChannelMoments*
457  channel_moments;
458 
459  GetPPException;
460  channel_moments=GetImageMoments(image_.constImage(),exceptionInfo);
461  if (channel_moments != (MagickCore::ChannelMoments *) NULL)
462  {
463  ssize_t
464  i;
465 
466  for (i=0; i < (ssize_t) GetPixelChannels(image_.constImage()); i++)
467  {
468  PixelChannel channel=GetPixelChannelChannel(image_.constImage(),i);
469  PixelTrait traits=GetPixelChannelTraits(image_.constImage(),channel);
470  if (traits == UndefinedPixelTrait)
471  continue;
472  if ((traits & UpdatePixelTrait) == 0)
473  continue;
474  _channels.push_back(Magick::ChannelMoments(channel,
475  &channel_moments[channel]));
476  }
477  _channels.push_back(Magick::ChannelMoments(CompositePixelChannel,
478  &channel_moments[CompositePixelChannel]));
479  channel_moments=(MagickCore::ChannelMoments *) RelinquishMagickMemory(
480  channel_moments);
481  }
482  ThrowPPException(image_.quiet());
483 }
484 
485 Magick::ImagePerceptualHash::ImagePerceptualHash(void)
486  : _channels()
487 {
488 }
489 
490 Magick::ImagePerceptualHash::ImagePerceptualHash(
491  const ImagePerceptualHash &imagePerceptualHash_)
492  : _channels(imagePerceptualHash_._channels)
493 {
494 }
495 
496 Magick::ImagePerceptualHash::ImagePerceptualHash(const std::string &hash_)
497  : _channels()
498 {
499  if (hash_.length() != 210)
500  throw ErrorOption("Invalid hash length");
501 
502  _channels.push_back(Magick::ChannelPerceptualHash(RedPixelChannel,
503  hash_.substr(0, 70)));
504  _channels.push_back(Magick::ChannelPerceptualHash(GreenPixelChannel,
505  hash_.substr(70, 70)));
506  _channels.push_back(Magick::ChannelPerceptualHash(BluePixelChannel,
507  hash_.substr(140, 70)));
508 }
509 
510 Magick::ImagePerceptualHash::~ImagePerceptualHash(void)
511 {
512 }
513 
514 Magick::ImagePerceptualHash::operator std::string() const
515 {
516  if (!isValid())
517  return(std::string());
518 
519  return static_cast<std::string>(_channels[0]) +
520  static_cast<std::string>(_channels[1]) +
521  static_cast<std::string>(_channels[2]);
522 }
523 
524 Magick::ChannelPerceptualHash Magick::ImagePerceptualHash::channel(
525  const PixelChannel channel_) const
526 {
527  for (std::vector<ChannelPerceptualHash>::const_iterator it =
528  _channels.begin(); it != _channels.end(); ++it)
529  {
530  if (it->channel() == channel_)
531  return(*it);
532  }
533  return(ChannelPerceptualHash());
534 }
535 
536 bool Magick::ImagePerceptualHash::isValid() const
537 {
538  if (_channels.size() != 3)
539  return(false);
540 
541  if (_channels[0].channel() != RedPixelChannel)
542  return(false);
543 
544  if (_channels[1].channel() != GreenPixelChannel)
545  return(false);
546 
547  if (_channels[2].channel() != BluePixelChannel)
548  return(false);
549 
550  return(true);
551 }
552 
553 double Magick::ImagePerceptualHash::sumSquaredDifferences(
554  const ImagePerceptualHash &channelPerceptualHash_)
555 {
556  double
557  ssd;
558 
559  size_t
560  i;
561 
562  if (!isValid())
563  throw ErrorOption("instance is not valid");
564  if (!channelPerceptualHash_.isValid())
565  throw ErrorOption("channelPerceptualHash_ is not valid");
566 
567  ssd=0.0;
568  for (i=0; i<3; i++)
569  {
570  ssd+=_channels[i].sumSquaredDifferences(_channels[i]);
571  }
572  return(ssd);
573 }
574 
575 Magick::ImagePerceptualHash::ImagePerceptualHash(
576  const Image &image_)
577  : _channels()
578 {
579  MagickCore::ChannelPerceptualHash*
580  channel_perceptual_hash;
581 
582  PixelTrait
583  traits;
584 
585  GetPPException;
586  channel_perceptual_hash=GetImagePerceptualHash(image_.constImage(),
587  exceptionInfo);
588  if (channel_perceptual_hash != (MagickCore::ChannelPerceptualHash *) NULL)
589  {
590  traits=GetPixelChannelTraits(image_.constImage(),RedPixelChannel);
591  if ((traits & UpdatePixelTrait) != 0)
592  _channels.push_back(Magick::ChannelPerceptualHash(RedPixelChannel,
593  &channel_perceptual_hash[RedPixelChannel]));
594  traits=GetPixelChannelTraits(image_.constImage(),GreenPixelChannel);
595  if ((traits & UpdatePixelTrait) != 0)
596  _channels.push_back(Magick::ChannelPerceptualHash(GreenPixelChannel,
597  &channel_perceptual_hash[GreenPixelChannel]));
598  traits=GetPixelChannelTraits(image_.constImage(),BluePixelChannel);
599  if ((traits & UpdatePixelTrait) != 0)
600  _channels.push_back(Magick::ChannelPerceptualHash(BluePixelChannel,
601  &channel_perceptual_hash[BluePixelChannel]));
602  channel_perceptual_hash=(MagickCore::ChannelPerceptualHash *)
603  RelinquishMagickMemory(channel_perceptual_hash);
604  }
605  ThrowPPException(image_.quiet());
606 }
607 
608 Magick::ImageStatistics::ImageStatistics(void)
609  : _channels()
610 {
611 }
612 
613 Magick::ImageStatistics::ImageStatistics(
614  const ImageStatistics &imageStatistics_)
615  : _channels(imageStatistics_._channels)
616 {
617 }
618 
619 Magick::ImageStatistics::~ImageStatistics(void)
620 {
621 }
622 
623 Magick::ChannelStatistics Magick::ImageStatistics::channel(
624  const PixelChannel channel_) const
625 {
626  for (std::vector<ChannelStatistics>::const_iterator it = _channels.begin();
627  it != _channels.end(); ++it)
628  {
629  if (it->channel() == channel_)
630  return(*it);
631  }
632  return(ChannelStatistics());
633 }
634 
635 Magick::ImageStatistics::ImageStatistics(const Image &image_)
636  : _channels()
637 {
638  MagickCore::ChannelStatistics*
639  channel_statistics;
640 
641  GetPPException;
642  channel_statistics=GetImageStatistics(image_.constImage(),exceptionInfo);
643  if (channel_statistics != (MagickCore::ChannelStatistics *) NULL)
644  {
645  ssize_t
646  i;
647 
648  for (i=0; i < (ssize_t) GetPixelChannels(image_.constImage()); i++)
649  {
650  PixelChannel channel=GetPixelChannelChannel(image_.constImage(),i);
651  PixelTrait traits=GetPixelChannelTraits(image_.constImage(),channel);
652  if (traits == UndefinedPixelTrait)
653  continue;
654  if ((traits & UpdatePixelTrait) == 0)
655  continue;
656  _channels.push_back(Magick::ChannelStatistics(channel,
657  &channel_statistics[channel]));
658  }
659  _channels.push_back(Magick::ChannelStatistics(CompositePixelChannel,
660  &channel_statistics[CompositePixelChannel]));
661  channel_statistics=(MagickCore::ChannelStatistics *) RelinquishMagickMemory(
662  channel_statistics);
663  }
664  ThrowPPException(image_.quiet());
665 }