Home | History | Annotate | Download | only in lib
      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 
     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 
     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 
     44 Magick::ChannelMoments::~ChannelMoments(void)
     45 {
     46 }
     47 
     48 double Magick::ChannelMoments::centroidX(void) const
     49 {
     50   return(_centroidX);
     51 }
     52 
     53 double Magick::ChannelMoments::centroidY(void) const
     54 {
     55   return(_centroidY);
     56 }
     57 
     58 Magick::PixelChannel Magick::ChannelMoments::channel(void) const
     59 {
     60   return(_channel);
     61 }
     62 
     63 double Magick::ChannelMoments::ellipseAxisX(void) const
     64 {
     65   return(_ellipseAxisX);
     66 }
     67 
     68 double Magick::ChannelMoments::ellipseAxisY(void) const
     69 {
     70   return(_ellipseAxisY);
     71 }
     72 
     73 double Magick::ChannelMoments::ellipseAngle(void) const
     74 {
     75   return(_ellipseAngle);
     76 }
     77 
     78 double Magick::ChannelMoments::ellipseEccentricity(void) const
     79 {
     80   return(_ellipseEccentricity);
     81 }
     82 
     83 double Magick::ChannelMoments::ellipseIntensity(void) const
     84 {
     85   return(_ellipseIntensity);
     86 }
     87 
     88 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 
     96 bool Magick::ChannelMoments::isValid() const
     97 {
     98   return(_channel != SyncPixelChannel);
     99 }
    100 
    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   register ssize_t
    114     i;
    115 
    116   for (i=0; i<8; i++)
    117     _huInvariants.push_back(channelMoments_->invariant[i]);
    118 }
    119 
    120 Magick::ChannelPerceptualHash::ChannelPerceptualHash(void)
    121   : _channel(SyncPixelChannel),
    122     _srgbHuPhash(7),
    123     _hclpHuPhash(7)
    124 {
    125 }
    126 
    127 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
    128   const ChannelPerceptualHash &channelPerceptualHash_)
    129   : _channel(channelPerceptualHash_._channel),
    130     _srgbHuPhash(channelPerceptualHash_._srgbHuPhash),
    131     _hclpHuPhash(channelPerceptualHash_._hclpHuPhash)
    132 {
    133 }
    134 
    135 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
    136   const PixelChannel channel_,const std::string &hash_)
    137   : _channel(channel_),
    138     _srgbHuPhash(7),
    139     _hclpHuPhash(7)
    140 {
    141   register 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 
    168 Magick::ChannelPerceptualHash::~ChannelPerceptualHash(void)
    169 {
    170 }
    171 
    172 Magick::ChannelPerceptualHash::operator std::string() const
    173 {
    174   std::string
    175     hash;
    176 
    177   register 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 
    216 Magick::PixelChannel Magick::ChannelPerceptualHash::channel() const
    217 {
    218   return(_channel);
    219 }
    220 
    221 bool Magick::ChannelPerceptualHash::isValid() const
    222 {
    223   return(_channel != SyncPixelChannel);
    224 }
    225 
    226 double Magick::ChannelPerceptualHash::sumSquaredDifferences(
    227   const ChannelPerceptualHash &channelPerceptualHash_)
    228 {
    229   double
    230     ssd;
    231 
    232   register 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 
    246 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 
    254 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 
    262 Magick::ChannelPerceptualHash::ChannelPerceptualHash(
    263   const PixelChannel channel_,
    264   const MagickCore::ChannelPerceptualHash *channelPerceptualHash_)
    265   : _channel(channel_),
    266     _srgbHuPhash(7),
    267     _hclpHuPhash(7)
    268 {
    269   register ssize_t
    270     i;
    271 
    272   for (i=0; i<7; i++)
    273   {
    274     _srgbHuPhash[i]=channelPerceptualHash_->srgb_hu_phash[i];
    275     _hclpHuPhash[i]=channelPerceptualHash_->hclp_hu_phash[i];
    276   }
    277 }
    278 
    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 
    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 
    318 Magick::ChannelStatistics::~ChannelStatistics(void)
    319 {
    320 }
    321 
    322 double Magick::ChannelStatistics::area() const
    323 {
    324   return(_area);
    325 }
    326 
    327 Magick::PixelChannel Magick::ChannelStatistics::channel() const
    328 {
    329   return(_channel);
    330 }
    331 
    332 size_t Magick::ChannelStatistics::depth() const
    333 {
    334   return(_depth);
    335 }
    336 
    337 double Magick::ChannelStatistics::entropy() const
    338 {
    339   return(_entropy);
    340 }
    341 
    342 bool Magick::ChannelStatistics::isValid() const
    343 {
    344   return(_channel != SyncPixelChannel);
    345 }
    346 
    347 double Magick::ChannelStatistics::kurtosis() const
    348 {
    349   return(_kurtosis);
    350 }
    351 
    352 double Magick::ChannelStatistics::maxima() const
    353 {
    354   return(_maxima);
    355 }
    356 
    357 double Magick::ChannelStatistics::mean() const
    358 {
    359   return(_mean);
    360 }
    361 
    362 double Magick::ChannelStatistics::minima() const
    363 {
    364   return(_minima);
    365 }
    366 
    367 double Magick::ChannelStatistics::skewness() const
    368 {
    369   return(_skewness);
    370 }
    371 
    372 double Magick::ChannelStatistics::standardDeviation() const
    373 {
    374   return(_standardDeviation);
    375 }
    376 
    377 double Magick::ChannelStatistics::sum() const
    378 {
    379   return(_sum);
    380 }
    381 
    382 double Magick::ChannelStatistics::sumCubed() const
    383 {
    384   return(_sumCubed);
    385 }
    386 
    387 double Magick::ChannelStatistics::sumFourthPower() const
    388 {
    389   return(_sumFourthPower);
    390 }
    391 
    392 double Magick::ChannelStatistics::sumSquared() const
    393 {
    394   return(_sumSquared);
    395 }
    396 
    397 double Magick::ChannelStatistics::variance() const
    398 {
    399   return(_variance);
    400 }
    401 
    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 
    422 Magick::ImageMoments::ImageMoments(void)
    423   : _channels()
    424 {
    425 }
    426 
    427 Magick::ImageMoments::ImageMoments(const ImageMoments &imageMoments_)
    428   : _channels(imageMoments_._channels)
    429 {
    430 }
    431 
    432 Magick::ImageMoments::~ImageMoments(void)
    433 {
    434 }
    435 
    436 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 
    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       register 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 
    480 Magick::ImagePerceptualHash::ImagePerceptualHash(void)
    481   : _channels()
    482 {
    483 }
    484 
    485 Magick::ImagePerceptualHash::ImagePerceptualHash(
    486   const ImagePerceptualHash &imagePerceptualHash_)
    487   : _channels(imagePerceptualHash_._channels)
    488 {
    489 }
    490 
    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 
    505 Magick::ImagePerceptualHash::~ImagePerceptualHash(void)
    506 {
    507 }
    508 
    509 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 
    519 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 
    531 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 
    548 double Magick::ImagePerceptualHash::sumSquaredDifferences(
    549       const ImagePerceptualHash &channelPerceptualHash_)
    550 {
    551   double
    552     ssd;
    553 
    554   register 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 
    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 
    603 Magick::ImageStatistics::ImageStatistics(void)
    604   : _channels()
    605 {
    606 }
    607 
    608 Magick::ImageStatistics::ImageStatistics(
    609   const ImageStatistics &imageStatistics_)
    610   : _channels(imageStatistics_._channels)
    611 {
    612 }
    613 
    614 Magick::ImageStatistics::~ImageStatistics(void)
    615 {
    616 }
    617 
    618 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 
    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       register 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