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