const MagickCore::ChannelMoments *channelMoments_);
private:
- std::vector<double> _huInvariants;
PixelChannel _channel;
+ std::vector<double> _huInvariants;
double _centroidX;
double _centroidY;
double _ellipseAxisX;
double _ellipseIntensity;
};
+ class MagickPPExport ChannelPerceptualHash
+ {
+ public:
+
+ // Default constructor
+ ChannelPerceptualHash(void);
+
+ // Copy constructor
+ ChannelPerceptualHash(const ChannelPerceptualHash &channelPerceptualHash_);
+
+ // Constructor using the specified hash string
+ ChannelPerceptualHash(const PixelChannel channel_,
+ const std::string &hash_);
+
+ // Destroy channel perceptual hash
+ ~ChannelPerceptualHash(void);
+
+ // Return hash string
+ operator std::string() const;
+
+ // The channel
+ PixelChannel channel(void) const;
+
+ // Does object contain valid channel perceptual hash?
+ bool isValid() const;
+
+ // Returns the sum squared difference between this hash and the other hash
+ double sumSquaredDifferences(
+ const ChannelPerceptualHash &channelPerceptualHash_);
+
+ // SRGB hu preceptual hash (valid range for index is 0-6)
+ double srgbHuPhash(const size_t index_) const;
+
+ // HCLp hu preceptual hash (valid range for index is 0-6)
+ double hclpHuPhash(const size_t index_) const;
+
+ //
+ // Implemementation methods
+ //
+
+ ChannelPerceptualHash(const PixelChannel channel_,
+ const MagickCore::ChannelPerceptualHash *channelPerceptualHash_);
+
+ private:
+ PixelChannel _channel;
+ std::vector<double> _srgbHuPhash;
+ std::vector<double> _hclpHuPhash;
+ };
+
// Obtain image statistics. Statistics are normalized to the range
// of 0.0 to 1.0 and are output to the specified ImageStatistics
// structure.
std::vector<ChannelMoments> _channels;
};
+ class MagickPPExport ImagePerceptualHash
+ {
+ public:
+
+ // Default constructor
+ ImagePerceptualHash(void);
+
+ // Copy constructor
+ ImagePerceptualHash(const ImagePerceptualHash &imagePerceptualHash_);
+
+ // Constructor using the specified hash string
+ ImagePerceptualHash(const std::string &hash_);
+
+ // Destroy image perceptual hash
+ ~ImagePerceptualHash(void);
+
+ // Return hash string
+ operator std::string() const;
+
+ // Returns the perceptual hash for the specified channel
+ ChannelPerceptualHash channel(const PixelChannel channel_) const;
+
+ // Does object contain valid perceptual hash?
+ bool isValid() const;
+
+ // Returns the sum squared difference between this hash and the other hash
+ double sumSquaredDifferences(
+ const ImagePerceptualHash &channelPerceptualHash_);
+
+ //
+ // Implemementation methods
+ //
+ ImagePerceptualHash(const MagickCore::Image *image_);
+
+ private:
+ std::vector<ChannelPerceptualHash> _channels;
+ };
+
class MagickPPExport ImageStatistics
{
public:
_ellipseEccentricity(channelMoments_->ellipse_eccentricity),
_ellipseIntensity(channelMoments_->ellipse_intensity)
{
- size_t
+ register ssize_t
i;
for (i=0; i<8; i++)
_huInvariants.push_back(channelMoments_->I[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 long
+ 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, (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 long
+ 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 long)(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_->srgb_hu_phash[i];
+ _hclpHuPhash[i]=channelPerceptualHash_->hclp_hu_phash[i];
+ }
+}
+
Magick::ChannelStatistics::ChannelStatistics(void)
: _channel(SyncPixelChannel),
_area(0.0),
ThrowPPException;
}
+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 MagickCore::Image *image)
+ : _channels()
+{
+ MagickCore::ChannelPerceptualHash*
+ channel_perceptual_hash;
+
+ PixelTrait
+ traits;
+
+ GetPPException;
+ channel_perceptual_hash=GetImagePerceptualHash(image,exceptionInfo);
+ if (channel_perceptual_hash != (MagickCore::ChannelPerceptualHash *) NULL)
+ {
+ traits=GetPixelChannelTraits(image,RedPixelChannel);
+ if ((traits & UpdatePixelTrait) != 0)
+ _channels.push_back(Magick::ChannelPerceptualHash(RedPixelChannel,
+ &channel_perceptual_hash[RedPixelChannel]));
+ traits=GetPixelChannelTraits(image,GreenPixelChannel);
+ if ((traits & UpdatePixelTrait) != 0)
+ _channels.push_back(Magick::ChannelPerceptualHash(GreenPixelChannel,
+ &channel_perceptual_hash[GreenPixelChannel]));
+ traits=GetPixelChannelTraits(image,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;
+}
+
Magick::ImageStatistics::ImageStatistics(void)
: _channels()
{