| // This may look like C code, but it is really -*- C++ -*- |
| // |
| // Copyright Dirk Lemstra 2014-2015 |
| // |
| // Implementation of channel moments. |
| // |
| |
| #define MAGICKCORE_IMPLEMENTATION 1 |
| #define MAGICK_PLUSPLUS_IMPLEMENTATION 1 |
| |
| #include "Magick++/Include.h" |
| #include "Magick++/Exception.h" |
| #include "Magick++/Statistic.h" |
| #include "Magick++/Image.h" |
| |
| using namespace std; |
| |
| Magick::ChannelMoments::ChannelMoments(void) |
| : _channel(SyncPixelChannel), |
| _huInvariants(8), |
| _centroidX(0.0), |
| _centroidY(0.0), |
| _ellipseAxisX(0.0), |
| _ellipseAxisY(0.0), |
| _ellipseAngle(0.0), |
| _ellipseEccentricity(0.0), |
| _ellipseIntensity(0.0) |
| { |
| } |
| |
| Magick::ChannelMoments::ChannelMoments(const ChannelMoments &channelMoments_) |
| : _channel(channelMoments_._channel), |
| _huInvariants(channelMoments_._huInvariants), |
| _centroidX(channelMoments_._centroidX), |
| _centroidY(channelMoments_._centroidY), |
| _ellipseAxisX(channelMoments_._ellipseAxisX), |
| _ellipseAxisY(channelMoments_._ellipseAxisY), |
| _ellipseAngle(channelMoments_._ellipseAngle), |
| _ellipseEccentricity(channelMoments_._ellipseEccentricity), |
| _ellipseIntensity(channelMoments_._ellipseIntensity) |
| { |
| } |
| |
| Magick::ChannelMoments::~ChannelMoments(void) |
| { |
| } |
| |
| double Magick::ChannelMoments::centroidX(void) const |
| { |
| return(_centroidX); |
| } |
| |
| double Magick::ChannelMoments::centroidY(void) const |
| { |
| return(_centroidY); |
| } |
| |
| Magick::PixelChannel Magick::ChannelMoments::channel(void) const |
| { |
| return(_channel); |
| } |
| |
| double Magick::ChannelMoments::ellipseAxisX(void) const |
| { |
| return(_ellipseAxisX); |
| } |
| |
| double Magick::ChannelMoments::ellipseAxisY(void) const |
| { |
| return(_ellipseAxisY); |
| } |
| |
| double Magick::ChannelMoments::ellipseAngle(void) const |
| { |
| return(_ellipseAngle); |
| } |
| |
| double Magick::ChannelMoments::ellipseEccentricity(void) const |
| { |
| return(_ellipseEccentricity); |
| } |
| |
| double Magick::ChannelMoments::ellipseIntensity(void) const |
| { |
| return(_ellipseIntensity); |
| } |
| |
| double Magick::ChannelMoments::huInvariants(const size_t index_) const |
| { |
| if (index_ > 7) |
| throw ErrorOption("Valid range for index is 0-7"); |
| |
| return(_huInvariants.at(index_)); |
| } |
| |
| bool Magick::ChannelMoments::isValid() const |
| { |
| return(_channel != SyncPixelChannel); |
| } |
| |
| Magick::ChannelMoments::ChannelMoments(const PixelChannel channel_, |
| const MagickCore::ChannelMoments *channelMoments_) |
| : _channel(channel_), |
| _huInvariants(), |
| _centroidX(channelMoments_->centroid.x), |
| _centroidY(channelMoments_->centroid.y), |
| _ellipseAxisX(channelMoments_->ellipse_axis.x), |
| _ellipseAxisY(channelMoments_->ellipse_axis.y), |
| _ellipseAngle(channelMoments_->ellipse_angle), |
| _ellipseEccentricity(channelMoments_->ellipse_eccentricity), |
| _ellipseIntensity(channelMoments_->ellipse_intensity) |
| { |
| register ssize_t |
| i; |
| |
| for (i=0; i<8; i++) |
| _huInvariants.push_back(channelMoments_->invariant[i]); |
| } |
| |
| Magick::ChannelPerceptualHash::ChannelPerceptualHash(void) |
| : _channel(SyncPixelChannel), |
| _srgbHuPhash(7), |
| _hclpHuPhash(7) |
| { |
| } |
| |
| Magick::ChannelPerceptualHash::ChannelPerceptualHash( |
| const ChannelPerceptualHash &channelPerceptualHash_) |
| : _channel(channelPerceptualHash_._channel), |
| _srgbHuPhash(channelPerceptualHash_._srgbHuPhash), |
| _hclpHuPhash(channelPerceptualHash_._hclpHuPhash) |
| { |
| } |
| |
| Magick::ChannelPerceptualHash::ChannelPerceptualHash( |
| const PixelChannel channel_,const std::string &hash_) |
| : _channel(channel_), |
| _srgbHuPhash(7), |
| _hclpHuPhash(7) |
| { |
| register ssize_t |
| i; |
| |
| if (hash_.length() != 70) |
| throw ErrorOption("Invalid hash length"); |
| |
| for (i=0; i<14; i++) |
| { |
| unsigned int |
| hex; |
| |
| double |
| value; |
| |
| if (sscanf(hash_.substr(i*5,5).c_str(),"%05x",&hex) != 1) |
| throw ErrorOption("Invalid hash value"); |
| |
| value=((unsigned short)hex) / pow(10.0, (double)(hex >> 17)); |
| if (hex & (1 << 16)) |
| value=-value; |
| if (i < 7) |
| _srgbHuPhash[i]=value; |
| else |
| _hclpHuPhash[i-7]=value; |
| } |
| } |
| |
| Magick::ChannelPerceptualHash::~ChannelPerceptualHash(void) |
| { |
| } |
| |
| Magick::ChannelPerceptualHash::operator std::string() const |
| { |
| std::string |
| hash; |
| |
| register ssize_t |
| i; |
| |
| if (!isValid()) |
| return(std::string()); |
| |
| for (i=0; i<14; i++) |
| { |
| char |
| buffer[6]; |
| |
| double |
| value; |
| |
| unsigned int |
| hex; |
| |
| if (i < 7) |
| value=_srgbHuPhash[i]; |
| else |
| value=_hclpHuPhash[i-7]; |
| |
| hex=0; |
| while(hex < 7 && fabs(value*10) < 65536) |
| { |
| value=value*10; |
| hex++; |
| } |
| |
| hex=(hex<<1); |
| if (value < 0.0) |
| hex|=1; |
| hex=(hex<<16)+(unsigned int)(value < 0.0 ? -(value - 0.5) : value + 0.5); |
| (void) FormatLocaleString(buffer,6,"%05x",hex); |
| hash+=std::string(buffer); |
| } |
| return(hash); |
| } |
| |
| Magick::PixelChannel Magick::ChannelPerceptualHash::channel() const |
| { |
| return(_channel); |
| } |
| |
| bool Magick::ChannelPerceptualHash::isValid() const |
| { |
| return(_channel != SyncPixelChannel); |
| } |
| |
| double Magick::ChannelPerceptualHash::sumSquaredDifferences( |
| const ChannelPerceptualHash &channelPerceptualHash_) |
| { |
| double |
| ssd; |
| |
| register ssize_t |
| i; |
| |
| ssd=0.0; |
| for (i=0; i<7; i++) |
| { |
| ssd+=((_srgbHuPhash[i]-channelPerceptualHash_._srgbHuPhash[i])* |
| (_srgbHuPhash[i]-channelPerceptualHash_._srgbHuPhash[i])); |
| ssd+=((_hclpHuPhash[i]-channelPerceptualHash_._hclpHuPhash[i])* |
| (_hclpHuPhash[i]-channelPerceptualHash_._hclpHuPhash[i])); |
| } |
| return(ssd); |
| } |
| |
| double Magick::ChannelPerceptualHash::srgbHuPhash(const size_t index_) const |
| { |
| if (index_ > 6) |
| throw ErrorOption("Valid range for index is 0-6"); |
| |
| return(_srgbHuPhash.at(index_)); |
| } |
| |
| double Magick::ChannelPerceptualHash::hclpHuPhash(const size_t index_) const |
| { |
| if (index_ > 6) |
| throw ErrorOption("Valid range for index is 0-6"); |
| |
| return(_hclpHuPhash.at(index_)); |
| } |
| |
| Magick::ChannelPerceptualHash::ChannelPerceptualHash( |
| const PixelChannel channel_, |
| const MagickCore::ChannelPerceptualHash *channelPerceptualHash_) |
| : _channel(channel_), |
| _srgbHuPhash(7), |
| _hclpHuPhash(7) |
| { |
| register ssize_t |
| i; |
| |
| for (i=0; i<7; i++) |
| { |
| _srgbHuPhash[i]=channelPerceptualHash_->phash[0][i]; |
| _hclpHuPhash[i]=channelPerceptualHash_->phash[1][i]; |
| } |
| } |
| |
| Magick::ChannelStatistics::ChannelStatistics(void) |
| : _channel(SyncPixelChannel), |
| _area(0.0), |
| _depth(0.0), |
| _entropy(0.0), |
| _kurtosis(0.0), |
| _maxima(0.0), |
| _mean(0.0), |
| _minima(0.0), |
| _skewness(0.0), |
| _standardDeviation(0.0), |
| _sum(0.0), |
| _sumCubed(0.0), |
| _sumFourthPower(0.0), |
| _sumSquared(0.0), |
| _variance(0.0) |
| { |
| } |
| |
| Magick::ChannelStatistics::ChannelStatistics( |
| const ChannelStatistics &channelStatistics_) |
| : _channel(channelStatistics_._channel), |
| _area(channelStatistics_._area), |
| _depth(channelStatistics_._depth), |
| _entropy(channelStatistics_._entropy), |
| _kurtosis(channelStatistics_._kurtosis), |
| _maxima(channelStatistics_._maxima), |
| _mean(channelStatistics_._mean), |
| _minima(channelStatistics_._minima), |
| _skewness(channelStatistics_._skewness), |
| _standardDeviation(channelStatistics_._standardDeviation), |
| _sum(channelStatistics_._sum), |
| _sumCubed(channelStatistics_._sumCubed), |
| _sumFourthPower(channelStatistics_._sumFourthPower), |
| _sumSquared(channelStatistics_._sumSquared), |
| _variance(channelStatistics_._variance) |
| { |
| } |
| |
| Magick::ChannelStatistics::~ChannelStatistics(void) |
| { |
| } |
| |
| double Magick::ChannelStatistics::area() const |
| { |
| return(_area); |
| } |
| |
| Magick::PixelChannel Magick::ChannelStatistics::channel() const |
| { |
| return(_channel); |
| } |
| |
| size_t Magick::ChannelStatistics::depth() const |
| { |
| return(_depth); |
| } |
| |
| double Magick::ChannelStatistics::entropy() const |
| { |
| return(_entropy); |
| } |
| |
| bool Magick::ChannelStatistics::isValid() const |
| { |
| return(_channel != SyncPixelChannel); |
| } |
| |
| double Magick::ChannelStatistics::kurtosis() const |
| { |
| return(_kurtosis); |
| } |
| |
| double Magick::ChannelStatistics::maxima() const |
| { |
| return(_maxima); |
| } |
| |
| double Magick::ChannelStatistics::mean() const |
| { |
| return(_mean); |
| } |
| |
| double Magick::ChannelStatistics::minima() const |
| { |
| return(_minima); |
| } |
| |
| double Magick::ChannelStatistics::skewness() const |
| { |
| return(_skewness); |
| } |
| |
| double Magick::ChannelStatistics::standardDeviation() const |
| { |
| return(_standardDeviation); |
| } |
| |
| double Magick::ChannelStatistics::sum() const |
| { |
| return(_sum); |
| } |
| |
| double Magick::ChannelStatistics::sumCubed() const |
| { |
| return(_sumCubed); |
| } |
| |
| double Magick::ChannelStatistics::sumFourthPower() const |
| { |
| return(_sumFourthPower); |
| } |
| |
| double Magick::ChannelStatistics::sumSquared() const |
| { |
| return(_sumSquared); |
| } |
| |
| double Magick::ChannelStatistics::variance() const |
| { |
| return(_variance); |
| } |
| |
| Magick::ChannelStatistics::ChannelStatistics(const PixelChannel channel_, |
| const MagickCore::ChannelStatistics *channelStatistics_) |
| : _channel(channel_), |
| _area(channelStatistics_->area), |
| _depth(channelStatistics_->depth), |
| _entropy(channelStatistics_->entropy), |
| _kurtosis(channelStatistics_->kurtosis), |
| _maxima(channelStatistics_->maxima), |
| _mean(channelStatistics_->mean), |
| _minima(channelStatistics_->minima), |
| _skewness(channelStatistics_->skewness), |
| _standardDeviation(channelStatistics_->standard_deviation), |
| _sum(channelStatistics_->sum), |
| _sumCubed(channelStatistics_->sum_cubed), |
| _sumFourthPower(channelStatistics_->sum_fourth_power), |
| _sumSquared(channelStatistics_->sum_squared), |
| _variance(channelStatistics_->variance) |
| { |
| } |
| |
| Magick::ImageMoments::ImageMoments(void) |
| : _channels() |
| { |
| } |
| |
| Magick::ImageMoments::ImageMoments(const ImageMoments &imageMoments_) |
| : _channels(imageMoments_._channels) |
| { |
| } |
| |
| Magick::ImageMoments::~ImageMoments(void) |
| { |
| } |
| |
| Magick::ChannelMoments Magick::ImageMoments::channel( |
| const PixelChannel channel_) const |
| { |
| for (std::vector<ChannelMoments>::const_iterator it = _channels.begin(); |
| it != _channels.end(); ++it) |
| { |
| if (it->channel() == channel_) |
| return(*it); |
| } |
| return(ChannelMoments()); |
| } |
| |
| Magick::ImageMoments::ImageMoments(const Image &image_) |
| : _channels() |
| { |
| MagickCore::ChannelMoments* |
| channel_moments; |
| |
| GetPPException; |
| channel_moments=GetImageMoments(image_.constImage(),exceptionInfo); |
| if (channel_moments != (MagickCore::ChannelMoments *) NULL) |
| { |
| register ssize_t |
| i; |
| |
| for (i=0; i < (ssize_t) GetPixelChannels(image_.constImage()); i++) |
| { |
| PixelChannel channel=GetPixelChannelChannel(image_.constImage(),i); |
| PixelTrait traits=GetPixelChannelTraits(image_.constImage(),channel); |
| if (traits == UndefinedPixelTrait) |
| continue; |
| if ((traits & UpdatePixelTrait) == 0) |
| continue; |
| _channels.push_back(Magick::ChannelMoments(channel, |
| &channel_moments[channel])); |
| } |
| _channels.push_back(Magick::ChannelMoments(CompositePixelChannel, |
| &channel_moments[CompositePixelChannel])); |
| channel_moments=(MagickCore::ChannelMoments *) RelinquishMagickMemory( |
| channel_moments); |
| } |
| ThrowPPException(image_.quiet()); |
| } |
| |
| Magick::ImagePerceptualHash::ImagePerceptualHash(void) |
| : _channels() |
| { |
| } |
| |
| Magick::ImagePerceptualHash::ImagePerceptualHash( |
| const ImagePerceptualHash &imagePerceptualHash_) |
| : _channels(imagePerceptualHash_._channels) |
| { |
| } |
| |
| Magick::ImagePerceptualHash::ImagePerceptualHash(const std::string &hash_) |
| : _channels() |
| { |
| if (hash_.length() != 210) |
| throw ErrorOption("Invalid hash length"); |
| |
| _channels.push_back(Magick::ChannelPerceptualHash(RedPixelChannel, |
| hash_.substr(0, 70))); |
| _channels.push_back(Magick::ChannelPerceptualHash(GreenPixelChannel, |
| hash_.substr(70, 70))); |
| _channels.push_back(Magick::ChannelPerceptualHash(BluePixelChannel, |
| hash_.substr(140, 70))); |
| } |
| |
| Magick::ImagePerceptualHash::~ImagePerceptualHash(void) |
| { |
| } |
| |
| Magick::ImagePerceptualHash::operator std::string() const |
| { |
| if (!isValid()) |
| return(std::string()); |
| |
| return static_cast<std::string>(_channels[0]) + |
| static_cast<std::string>(_channels[1]) + |
| static_cast<std::string>(_channels[2]); |
| } |
| |
| Magick::ChannelPerceptualHash Magick::ImagePerceptualHash::channel( |
| const PixelChannel channel_) const |
| { |
| for (std::vector<ChannelPerceptualHash>::const_iterator it = |
| _channels.begin(); it != _channels.end(); ++it) |
| { |
| if (it->channel() == channel_) |
| return(*it); |
| } |
| return(ChannelPerceptualHash()); |
| } |
| |
| bool Magick::ImagePerceptualHash::isValid() const |
| { |
| if (_channels.size() != 3) |
| return(false); |
| |
| if (_channels[0].channel() != RedPixelChannel) |
| return(false); |
| |
| if (_channels[1].channel() != GreenPixelChannel) |
| return(false); |
| |
| if (_channels[2].channel() != BluePixelChannel) |
| return(false); |
| |
| return(true); |
| } |
| |
| double Magick::ImagePerceptualHash::sumSquaredDifferences( |
| const ImagePerceptualHash &channelPerceptualHash_) |
| { |
| double |
| ssd; |
| |
| register ssize_t |
| i; |
| |
| if (!isValid()) |
| throw ErrorOption("instance is not valid"); |
| if (!channelPerceptualHash_.isValid()) |
| throw ErrorOption("channelPerceptualHash_ is not valid"); |
| |
| ssd=0.0; |
| for (i=0; i<3; i++) |
| { |
| ssd+=_channels[i].sumSquaredDifferences(_channels[i]); |
| } |
| return(ssd); |
| } |
| |
| Magick::ImagePerceptualHash::ImagePerceptualHash( |
| const Image &image_) |
| : _channels() |
| { |
| MagickCore::ChannelPerceptualHash* |
| channel_perceptual_hash; |
| |
| PixelTrait |
| traits; |
| |
| GetPPException; |
| channel_perceptual_hash=GetImagePerceptualHash(image_.constImage(), |
| exceptionInfo); |
| if (channel_perceptual_hash != (MagickCore::ChannelPerceptualHash *) NULL) |
| { |
| traits=GetPixelChannelTraits(image_.constImage(),RedPixelChannel); |
| if ((traits & UpdatePixelTrait) != 0) |
| _channels.push_back(Magick::ChannelPerceptualHash(RedPixelChannel, |
| &channel_perceptual_hash[RedPixelChannel])); |
| traits=GetPixelChannelTraits(image_.constImage(),GreenPixelChannel); |
| if ((traits & UpdatePixelTrait) != 0) |
| _channels.push_back(Magick::ChannelPerceptualHash(GreenPixelChannel, |
| &channel_perceptual_hash[GreenPixelChannel])); |
| traits=GetPixelChannelTraits(image_.constImage(),BluePixelChannel); |
| if ((traits & UpdatePixelTrait) != 0) |
| _channels.push_back(Magick::ChannelPerceptualHash(BluePixelChannel, |
| &channel_perceptual_hash[BluePixelChannel])); |
| channel_perceptual_hash=(MagickCore::ChannelPerceptualHash *) |
| RelinquishMagickMemory(channel_perceptual_hash); |
| } |
| ThrowPPException(image_.quiet()); |
| } |
| |
| Magick::ImageStatistics::ImageStatistics(void) |
| : _channels() |
| { |
| } |
| |
| Magick::ImageStatistics::ImageStatistics( |
| const ImageStatistics &imageStatistics_) |
| : _channels(imageStatistics_._channels) |
| { |
| } |
| |
| Magick::ImageStatistics::~ImageStatistics(void) |
| { |
| } |
| |
| Magick::ChannelStatistics Magick::ImageStatistics::channel( |
| const PixelChannel channel_) const |
| { |
| for (std::vector<ChannelStatistics>::const_iterator it = _channels.begin(); |
| it != _channels.end(); ++it) |
| { |
| if (it->channel() == channel_) |
| return(*it); |
| } |
| return(ChannelStatistics()); |
| } |
| |
| Magick::ImageStatistics::ImageStatistics(const Image &image_) |
| : _channels() |
| { |
| MagickCore::ChannelStatistics* |
| channel_statistics; |
| |
| GetPPException; |
| channel_statistics=GetImageStatistics(image_.constImage(),exceptionInfo); |
| if (channel_statistics != (MagickCore::ChannelStatistics *) NULL) |
| { |
| register ssize_t |
| i; |
| |
| for (i=0; i < (ssize_t) GetPixelChannels(image_.constImage()); i++) |
| { |
| PixelChannel channel=GetPixelChannelChannel(image_.constImage(),i); |
| PixelTrait traits=GetPixelChannelTraits(image_.constImage(),channel); |
| if (traits == UndefinedPixelTrait) |
| continue; |
| if ((traits & UpdatePixelTrait) == 0) |
| continue; |
| _channels.push_back(Magick::ChannelStatistics(channel, |
| &channel_statistics[channel])); |
| } |
| _channels.push_back(Magick::ChannelStatistics(CompositePixelChannel, |
| &channel_statistics[CompositePixelChannel])); |
| channel_statistics=(MagickCore::ChannelStatistics *) RelinquishMagickMemory( |
| channel_statistics); |
| } |
| ThrowPPException(image_.quiet()); |
| } |