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