PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/MagickCore/segment.c

https://gitlab.com/ImageMagick/ImageMagick
C | 1950 lines | 1226 code | 77 blank | 647 comment | 277 complexity | b768d4b1afed39c347ead516fcbc9f1b MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % %
  4. % %
  5. % %
  6. % SSSSS EEEEE GGGG M M EEEEE N N TTTTT %
  7. % SS E G MM MM E NN N T %
  8. % SSS EEE G GGG M M M EEE N N N T %
  9. % SS E G G M M E N NN T %
  10. % SSSSS EEEEE GGGG M M EEEEE N N T %
  11. % %
  12. % %
  13. % MagickCore Methods to Segment an Image with Thresholding Fuzzy c-Means %
  14. % %
  15. % Software Design %
  16. % Cristy %
  17. % April 1993 %
  18. % %
  19. % %
  20. % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
  21. % dedicated to making software imaging solutions freely available. %
  22. % %
  23. % You may not use this file except in compliance with the License. You may %
  24. % obtain a copy of the License at %
  25. % %
  26. % https://imagemagick.org/script/license.php %
  27. % %
  28. % Unless required by applicable law or agreed to in writing, software %
  29. % distributed under the License is distributed on an "AS IS" BASIS, %
  30. % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
  31. % See the License for the specific language governing permissions and %
  32. % limitations under the License. %
  33. % %
  34. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  35. %
  36. % Segment segments an image by analyzing the histograms of the color
  37. % components and identifying units that are homogeneous with the fuzzy
  38. % c-means technique. The scale-space filter analyzes the histograms of
  39. % the three color components of the image and identifies a set of
  40. % classes. The extents of each class is used to coarsely segment the
  41. % image with thresholding. The color associated with each class is
  42. % determined by the mean color of all pixels within the extents of a
  43. % particular class. Finally, any unclassified pixels are assigned to
  44. % the closest class with the fuzzy c-means technique.
  45. %
  46. % The fuzzy c-Means algorithm can be summarized as follows:
  47. %
  48. % o Build a histogram, one for each color component of the image.
  49. %
  50. % o For each histogram, successively apply the scale-space filter and
  51. % build an interval tree of zero crossings in the second derivative
  52. % at each scale. Analyze this scale-space ''fingerprint'' to
  53. % determine which peaks and valleys in the histogram are most
  54. % predominant.
  55. %
  56. % o The fingerprint defines intervals on the axis of the histogram.
  57. % Each interval contains either a minima or a maxima in the original
  58. % signal. If each color component lies within the maxima interval,
  59. % that pixel is considered ''classified'' and is assigned an unique
  60. % class number.
  61. %
  62. % o Any pixel that fails to be classified in the above thresholding
  63. % pass is classified using the fuzzy c-Means technique. It is
  64. % assigned to one of the classes discovered in the histogram analysis
  65. % phase.
  66. %
  67. % The fuzzy c-Means technique attempts to cluster a pixel by finding
  68. % the local minima of the generalized within group sum of squared error
  69. % objective function. A pixel is assigned to the closest class of
  70. % which the fuzzy membership has a maximum value.
  71. %
  72. % Segment is strongly based on software written by Andy Gallo,
  73. % University of Delaware.
  74. %
  75. % The following reference was used in creating this program:
  76. %
  77. % Young Won Lim, Sang Uk Lee, "On The Color Image Segmentation
  78. % Algorithm Based on the Thresholding and the Fuzzy c-Means
  79. % Techniques", Pattern Recognition, Volume 23, Number 9, pages
  80. % 935-952, 1990.
  81. %
  82. %
  83. */
  84. #include "MagickCore/studio.h"
  85. #include "MagickCore/cache.h"
  86. #include "MagickCore/color.h"
  87. #include "MagickCore/colormap.h"
  88. #include "MagickCore/colorspace.h"
  89. #include "MagickCore/colorspace-private.h"
  90. #include "MagickCore/exception.h"
  91. #include "MagickCore/exception-private.h"
  92. #include "MagickCore/image.h"
  93. #include "MagickCore/image-private.h"
  94. #include "MagickCore/memory_.h"
  95. #include "MagickCore/memory-private.h"
  96. #include "MagickCore/monitor.h"
  97. #include "MagickCore/monitor-private.h"
  98. #include "MagickCore/pixel-accessor.h"
  99. #include "MagickCore/pixel-private.h"
  100. #include "MagickCore/quantize.h"
  101. #include "MagickCore/quantum.h"
  102. #include "MagickCore/quantum-private.h"
  103. #include "MagickCore/resource_.h"
  104. #include "MagickCore/segment.h"
  105. #include "MagickCore/string_.h"
  106. #include "MagickCore/thread-private.h"
  107. /*
  108. Define declarations.
  109. */
  110. #define MaxDimension 3
  111. #define DeltaTau 0.5f
  112. #if defined(FastClassify)
  113. #define WeightingExponent 2.0
  114. #define SegmentPower(ratio) (ratio)
  115. #else
  116. #define WeightingExponent 2.5
  117. #define SegmentPower(ratio) pow(ratio,(double) (1.0/(weighting_exponent-1.0)));
  118. #endif
  119. #define Tau 5.2f
  120. /*
  121. Typedef declarations.
  122. */
  123. typedef struct _ExtentPacket
  124. {
  125. double
  126. center;
  127. ssize_t
  128. index,
  129. left,
  130. right;
  131. } ExtentPacket;
  132. typedef struct _Cluster
  133. {
  134. struct _Cluster
  135. *next;
  136. ExtentPacket
  137. red,
  138. green,
  139. blue;
  140. ssize_t
  141. count,
  142. id;
  143. } Cluster;
  144. typedef struct _IntervalTree
  145. {
  146. double
  147. tau;
  148. ssize_t
  149. left,
  150. right;
  151. double
  152. mean_stability,
  153. stability;
  154. struct _IntervalTree
  155. *sibling,
  156. *child;
  157. } IntervalTree;
  158. typedef struct _ZeroCrossing
  159. {
  160. double
  161. tau,
  162. histogram[256];
  163. short
  164. crossings[256];
  165. } ZeroCrossing;
  166. /*
  167. Constant declarations.
  168. */
  169. static const int
  170. Blue = 2,
  171. Green = 1,
  172. Red = 0,
  173. SafeMargin = 3,
  174. TreeLength = 600;
  175. /*
  176. Method prototypes.
  177. */
  178. static double
  179. OptimalTau(const ssize_t *,const double,const double,const double,
  180. const double,short *);
  181. static ssize_t
  182. DefineRegion(const short *,ExtentPacket *);
  183. static void
  184. FreeNodes(IntervalTree *),
  185. InitializeHistogram(const Image *,ssize_t **,ExceptionInfo *),
  186. ScaleSpace(const ssize_t *,const double,double *),
  187. ZeroCrossHistogram(double *,const double,short *);
  188. /*
  189. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  190. % %
  191. % %
  192. % %
  193. + C l a s s i f y %
  194. % %
  195. % %
  196. % %
  197. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  198. %
  199. % Classify() defines one or more classes. Each pixel is thresholded to
  200. % determine which class it belongs to. If the class is not identified it is
  201. % assigned to the closest class based on the fuzzy c-Means technique.
  202. %
  203. % The format of the Classify method is:
  204. %
  205. % MagickBooleanType Classify(Image *image,short **extrema,
  206. % const double cluster_threshold,
  207. % const double weighting_exponent,
  208. % const MagickBooleanType verbose,ExceptionInfo *exception)
  209. %
  210. % A description of each parameter follows.
  211. %
  212. % o image: the image.
  213. %
  214. % o extrema: Specifies a pointer to an array of integers. They
  215. % represent the peaks and valleys of the histogram for each color
  216. % component.
  217. %
  218. % o cluster_threshold: This double represents the minimum number of
  219. % pixels contained in a hexahedra before it can be considered valid
  220. % (expressed as a percentage).
  221. %
  222. % o weighting_exponent: Specifies the membership weighting exponent.
  223. %
  224. % o verbose: A value greater than zero prints detailed information about
  225. % the identified classes.
  226. %
  227. % o exception: return any errors or warnings in this structure.
  228. %
  229. */
  230. static MagickBooleanType Classify(Image *image,short **extrema,
  231. const double cluster_threshold,
  232. const double weighting_exponent,const MagickBooleanType verbose,
  233. ExceptionInfo *exception)
  234. {
  235. #define SegmentImageTag "Segment/Image"
  236. #define ThrowClassifyException(severity,tag,label) \
  237. {\
  238. for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster) \
  239. { \
  240. next_cluster=cluster->next; \
  241. cluster=(Cluster *) RelinquishMagickMemory(cluster); \
  242. } \
  243. if (squares != (double *) NULL) \
  244. { \
  245. squares-=255; \
  246. free_squares=squares; \
  247. free_squares=(double *) RelinquishMagickMemory(free_squares); \
  248. } \
  249. ThrowBinaryException(severity,tag,label); \
  250. }
  251. CacheView
  252. *image_view;
  253. Cluster
  254. *cluster,
  255. *head,
  256. *last_cluster,
  257. *next_cluster;
  258. ExtentPacket
  259. blue,
  260. green,
  261. red;
  262. MagickOffsetType
  263. progress;
  264. double
  265. *free_squares;
  266. MagickStatusType
  267. status;
  268. register ssize_t
  269. i;
  270. register double
  271. *squares;
  272. size_t
  273. number_clusters;
  274. ssize_t
  275. count,
  276. y;
  277. /*
  278. Form clusters.
  279. */
  280. cluster=(Cluster *) NULL;
  281. head=(Cluster *) NULL;
  282. squares=(double *) NULL;
  283. (void) memset(&red,0,sizeof(red));
  284. (void) memset(&green,0,sizeof(green));
  285. (void) memset(&blue,0,sizeof(blue));
  286. while (DefineRegion(extrema[Red],&red) != 0)
  287. {
  288. green.index=0;
  289. while (DefineRegion(extrema[Green],&green) != 0)
  290. {
  291. blue.index=0;
  292. while (DefineRegion(extrema[Blue],&blue) != 0)
  293. {
  294. /*
  295. Allocate a new class.
  296. */
  297. if (head != (Cluster *) NULL)
  298. {
  299. cluster->next=(Cluster *) AcquireMagickMemory(
  300. sizeof(*cluster->next));
  301. cluster=cluster->next;
  302. }
  303. else
  304. {
  305. cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
  306. head=cluster;
  307. }
  308. if (cluster == (Cluster *) NULL)
  309. ThrowClassifyException(ResourceLimitError,"MemoryAllocationFailed",
  310. image->filename);
  311. /*
  312. Initialize a new class.
  313. */
  314. cluster->count=0;
  315. cluster->red=red;
  316. cluster->green=green;
  317. cluster->blue=blue;
  318. cluster->next=(Cluster *) NULL;
  319. }
  320. }
  321. }
  322. if (head == (Cluster *) NULL)
  323. {
  324. /*
  325. No classes were identified-- create one.
  326. */
  327. cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
  328. if (cluster == (Cluster *) NULL)
  329. ThrowClassifyException(ResourceLimitError,"MemoryAllocationFailed",
  330. image->filename);
  331. /*
  332. Initialize a new class.
  333. */
  334. cluster->count=0;
  335. cluster->red=red;
  336. cluster->green=green;
  337. cluster->blue=blue;
  338. cluster->next=(Cluster *) NULL;
  339. head=cluster;
  340. }
  341. /*
  342. Count the pixels for each cluster.
  343. */
  344. status=MagickTrue;
  345. count=0;
  346. progress=0;
  347. image_view=AcquireVirtualCacheView(image,exception);
  348. for (y=0; y < (ssize_t) image->rows; y++)
  349. {
  350. register const Quantum
  351. *p;
  352. register ssize_t
  353. x;
  354. p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
  355. if (p == (const Quantum *) NULL)
  356. break;
  357. for (x=0; x < (ssize_t) image->columns; x++)
  358. {
  359. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  360. if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
  361. (cluster->red.left-SafeMargin)) &&
  362. ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
  363. (cluster->red.right+SafeMargin)) &&
  364. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
  365. (cluster->green.left-SafeMargin)) &&
  366. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
  367. (cluster->green.right+SafeMargin)) &&
  368. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
  369. (cluster->blue.left-SafeMargin)) &&
  370. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
  371. (cluster->blue.right+SafeMargin)))
  372. {
  373. /*
  374. Count this pixel.
  375. */
  376. count++;
  377. cluster->red.center+=(double) ScaleQuantumToChar(
  378. GetPixelRed(image,p));
  379. cluster->green.center+=(double) ScaleQuantumToChar(
  380. GetPixelGreen(image,p));
  381. cluster->blue.center+=(double) ScaleQuantumToChar(
  382. GetPixelBlue(image,p));
  383. cluster->count++;
  384. break;
  385. }
  386. p+=GetPixelChannels(image);
  387. }
  388. if (image->progress_monitor != (MagickProgressMonitor) NULL)
  389. {
  390. MagickBooleanType
  391. proceed;
  392. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  393. #pragma omp atomic
  394. #endif
  395. progress++;
  396. proceed=SetImageProgress(image,SegmentImageTag,progress,2*image->rows);
  397. if (proceed == MagickFalse)
  398. status=MagickFalse;
  399. }
  400. }
  401. image_view=DestroyCacheView(image_view);
  402. /*
  403. Remove clusters that do not meet minimum cluster threshold.
  404. */
  405. count=0;
  406. last_cluster=head;
  407. next_cluster=head;
  408. for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
  409. {
  410. next_cluster=cluster->next;
  411. if ((cluster->count > 0) &&
  412. (cluster->count >= (count*cluster_threshold/100.0)))
  413. {
  414. /*
  415. Initialize cluster.
  416. */
  417. cluster->id=count;
  418. cluster->red.center/=cluster->count;
  419. cluster->green.center/=cluster->count;
  420. cluster->blue.center/=cluster->count;
  421. count++;
  422. last_cluster=cluster;
  423. continue;
  424. }
  425. /*
  426. Delete cluster.
  427. */
  428. if (cluster == head)
  429. head=next_cluster;
  430. else
  431. last_cluster->next=next_cluster;
  432. cluster=(Cluster *) RelinquishMagickMemory(cluster);
  433. }
  434. number_clusters=(size_t) count;
  435. if (verbose != MagickFalse)
  436. {
  437. /*
  438. Print cluster statistics.
  439. */
  440. (void) FormatLocaleFile(stdout,"Fuzzy C-means Statistics\n");
  441. (void) FormatLocaleFile(stdout,"===================\n\n");
  442. (void) FormatLocaleFile(stdout,"\tCluster Threshold = %g\n",(double)
  443. cluster_threshold);
  444. (void) FormatLocaleFile(stdout,"\tWeighting Exponent = %g\n",(double)
  445. weighting_exponent);
  446. (void) FormatLocaleFile(stdout,"\tTotal Number of Clusters = %.20g\n\n",
  447. (double) number_clusters);
  448. /*
  449. Print the total number of points per cluster.
  450. */
  451. (void) FormatLocaleFile(stdout,"\n\nNumber of Vectors Per Cluster\n");
  452. (void) FormatLocaleFile(stdout,"=============================\n\n");
  453. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  454. (void) FormatLocaleFile(stdout,"Cluster #%.20g = %.20g\n",(double)
  455. cluster->id,(double) cluster->count);
  456. /*
  457. Print the cluster extents.
  458. */
  459. (void) FormatLocaleFile(stdout,
  460. "\n\n\nCluster Extents: (Vector Size: %d)\n",MaxDimension);
  461. (void) FormatLocaleFile(stdout,"================");
  462. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  463. {
  464. (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
  465. cluster->id);
  466. (void) FormatLocaleFile(stdout,
  467. "%.20g-%.20g %.20g-%.20g %.20g-%.20g\n",(double)
  468. cluster->red.left,(double) cluster->red.right,(double)
  469. cluster->green.left,(double) cluster->green.right,(double)
  470. cluster->blue.left,(double) cluster->blue.right);
  471. }
  472. /*
  473. Print the cluster center values.
  474. */
  475. (void) FormatLocaleFile(stdout,
  476. "\n\n\nCluster Center Values: (Vector Size: %d)\n",MaxDimension);
  477. (void) FormatLocaleFile(stdout,"=====================");
  478. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  479. {
  480. (void) FormatLocaleFile(stdout,"\n\nCluster #%.20g\n\n",(double)
  481. cluster->id);
  482. (void) FormatLocaleFile(stdout,"%g %g %g\n",(double)
  483. cluster->red.center,(double) cluster->green.center,(double)
  484. cluster->blue.center);
  485. }
  486. (void) FormatLocaleFile(stdout,"\n");
  487. }
  488. if (number_clusters > 256)
  489. ThrowClassifyException(ImageError,"TooManyClusters",image->filename);
  490. /*
  491. Speed up distance calculations.
  492. */
  493. squares=(double *) AcquireQuantumMemory(513UL,sizeof(*squares));
  494. if (squares == (double *) NULL)
  495. ThrowClassifyException(ResourceLimitError,"MemoryAllocationFailed",
  496. image->filename);
  497. squares+=255;
  498. for (i=(-255); i <= 255; i++)
  499. squares[i]=(double) i*(double) i;
  500. /*
  501. Allocate image colormap.
  502. */
  503. if (AcquireImageColormap(image,number_clusters,exception) == MagickFalse)
  504. ThrowClassifyException(ResourceLimitError,"MemoryAllocationFailed",
  505. image->filename);
  506. i=0;
  507. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  508. {
  509. image->colormap[i].red=(double) ScaleCharToQuantum((unsigned char)
  510. (cluster->red.center+0.5));
  511. image->colormap[i].green=(double) ScaleCharToQuantum((unsigned char)
  512. (cluster->green.center+0.5));
  513. image->colormap[i].blue=(double) ScaleCharToQuantum((unsigned char)
  514. (cluster->blue.center+0.5));
  515. i++;
  516. }
  517. /*
  518. Do course grain classes.
  519. */
  520. image_view=AcquireAuthenticCacheView(image,exception);
  521. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  522. #pragma omp parallel for schedule(static) shared(progress,status) \
  523. magick_number_threads(image,image,image->rows,1)
  524. #endif
  525. for (y=0; y < (ssize_t) image->rows; y++)
  526. {
  527. Cluster
  528. *clust;
  529. register const PixelInfo
  530. *magick_restrict p;
  531. register ssize_t
  532. x;
  533. register Quantum
  534. *magick_restrict q;
  535. if (status == MagickFalse)
  536. continue;
  537. q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
  538. if (q == (Quantum *) NULL)
  539. {
  540. status=MagickFalse;
  541. continue;
  542. }
  543. for (x=0; x < (ssize_t) image->columns; x++)
  544. {
  545. SetPixelIndex(image,0,q);
  546. for (clust=head; clust != (Cluster *) NULL; clust=clust->next)
  547. {
  548. if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) >=
  549. (clust->red.left-SafeMargin)) &&
  550. ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,q)) <=
  551. (clust->red.right+SafeMargin)) &&
  552. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) >=
  553. (clust->green.left-SafeMargin)) &&
  554. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q)) <=
  555. (clust->green.right+SafeMargin)) &&
  556. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) >=
  557. (clust->blue.left-SafeMargin)) &&
  558. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q)) <=
  559. (clust->blue.right+SafeMargin)))
  560. {
  561. /*
  562. Classify this pixel.
  563. */
  564. SetPixelIndex(image,(Quantum) clust->id,q);
  565. break;
  566. }
  567. }
  568. if (clust == (Cluster *) NULL)
  569. {
  570. double
  571. distance_squared,
  572. local_minima,
  573. numerator,
  574. ratio,
  575. sum;
  576. register ssize_t
  577. j,
  578. k;
  579. /*
  580. Compute fuzzy membership.
  581. */
  582. local_minima=0.0;
  583. for (j=0; j < (ssize_t) image->colors; j++)
  584. {
  585. sum=0.0;
  586. p=image->colormap+j;
  587. distance_squared=squares[(ssize_t) ScaleQuantumToChar(
  588. GetPixelRed(image,q))-(ssize_t)
  589. ScaleQuantumToChar(ClampToQuantum(p->red))]+squares[(ssize_t)
  590. ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
  591. ScaleQuantumToChar(ClampToQuantum(p->green))]+squares[(ssize_t)
  592. ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
  593. ScaleQuantumToChar(ClampToQuantum(p->blue))];
  594. numerator=distance_squared;
  595. for (k=0; k < (ssize_t) image->colors; k++)
  596. {
  597. p=image->colormap+k;
  598. distance_squared=squares[(ssize_t) ScaleQuantumToChar(
  599. GetPixelRed(image,q))-(ssize_t)
  600. ScaleQuantumToChar(ClampToQuantum(p->red))]+squares[
  601. (ssize_t) ScaleQuantumToChar(GetPixelGreen(image,q))-(ssize_t)
  602. ScaleQuantumToChar(ClampToQuantum(p->green))]+squares[
  603. (ssize_t) ScaleQuantumToChar(GetPixelBlue(image,q))-(ssize_t)
  604. ScaleQuantumToChar(ClampToQuantum(p->blue))];
  605. ratio=numerator/distance_squared;
  606. sum+=SegmentPower(ratio);
  607. }
  608. if ((sum != 0.0) && ((1.0/sum) > local_minima))
  609. {
  610. /*
  611. Classify this pixel.
  612. */
  613. local_minima=1.0/sum;
  614. SetPixelIndex(image,(Quantum) j,q);
  615. }
  616. }
  617. }
  618. q+=GetPixelChannels(image);
  619. }
  620. if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
  621. status=MagickFalse;
  622. if (image->progress_monitor != (MagickProgressMonitor) NULL)
  623. {
  624. MagickBooleanType
  625. proceed;
  626. #if defined(MAGICKCORE_OPENMP_SUPPORT)
  627. #pragma omp atomic
  628. #endif
  629. progress++;
  630. proceed=SetImageProgress(image,SegmentImageTag,progress,2*image->rows);
  631. if (proceed == MagickFalse)
  632. status=MagickFalse;
  633. }
  634. }
  635. image_view=DestroyCacheView(image_view);
  636. status&=SyncImage(image,exception);
  637. /*
  638. Relinquish resources.
  639. */
  640. for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
  641. {
  642. next_cluster=cluster->next;
  643. cluster=(Cluster *) RelinquishMagickMemory(cluster);
  644. }
  645. squares-=255;
  646. free_squares=squares;
  647. free_squares=(double *) RelinquishMagickMemory(free_squares);
  648. return(MagickTrue);
  649. }
  650. /*
  651. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  652. % %
  653. % %
  654. % %
  655. + C o n s o l i d a t e C r o s s i n g s %
  656. % %
  657. % %
  658. % %
  659. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  660. %
  661. % ConsolidateCrossings() guarantees that an even number of zero crossings
  662. % always lie between two crossings.
  663. %
  664. % The format of the ConsolidateCrossings method is:
  665. %
  666. % ConsolidateCrossings(ZeroCrossing *zero_crossing,
  667. % const size_t number_crossings)
  668. %
  669. % A description of each parameter follows.
  670. %
  671. % o zero_crossing: Specifies an array of structures of type ZeroCrossing.
  672. %
  673. % o number_crossings: This size_t specifies the number of elements
  674. % in the zero_crossing array.
  675. %
  676. */
  677. static void ConsolidateCrossings(ZeroCrossing *zero_crossing,
  678. const size_t number_crossings)
  679. {
  680. register ssize_t
  681. i,
  682. j,
  683. k,
  684. l;
  685. ssize_t
  686. center,
  687. correct,
  688. count,
  689. left,
  690. right;
  691. /*
  692. Consolidate zero crossings.
  693. */
  694. for (i=(ssize_t) number_crossings-1; i >= 0; i--)
  695. for (j=0; j <= 255; j++)
  696. {
  697. if (zero_crossing[i].crossings[j] == 0)
  698. continue;
  699. /*
  700. Find the entry that is closest to j and still preserves the
  701. property that there are an even number of crossings between
  702. intervals.
  703. */
  704. for (k=j-1; k > 0; k--)
  705. if (zero_crossing[i+1].crossings[k] != 0)
  706. break;
  707. left=MagickMax(k,0);
  708. center=j;
  709. for (k=j+1; k < 255; k++)
  710. if (zero_crossing[i+1].crossings[k] != 0)
  711. break;
  712. right=MagickMin(k,255);
  713. /*
  714. K is the zero crossing just left of j.
  715. */
  716. for (k=j-1; k > 0; k--)
  717. if (zero_crossing[i].crossings[k] != 0)
  718. break;
  719. if (k < 0)
  720. k=0;
  721. /*
  722. Check center for an even number of crossings between k and j.
  723. */
  724. correct=(-1);
  725. if (zero_crossing[i+1].crossings[j] != 0)
  726. {
  727. count=0;
  728. for (l=k+1; l < center; l++)
  729. if (zero_crossing[i+1].crossings[l] != 0)
  730. count++;
  731. if (((count % 2) == 0) && (center != k))
  732. correct=center;
  733. }
  734. /*
  735. Check left for an even number of crossings between k and j.
  736. */
  737. if (correct == -1)
  738. {
  739. count=0;
  740. for (l=k+1; l < left; l++)
  741. if (zero_crossing[i+1].crossings[l] != 0)
  742. count++;
  743. if (((count % 2) == 0) && (left != k))
  744. correct=left;
  745. }
  746. /*
  747. Check right for an even number of crossings between k and j.
  748. */
  749. if (correct == -1)
  750. {
  751. count=0;
  752. for (l=k+1; l < right; l++)
  753. if (zero_crossing[i+1].crossings[l] != 0)
  754. count++;
  755. if (((count % 2) == 0) && (right != k))
  756. correct=right;
  757. }
  758. l=(ssize_t) zero_crossing[i].crossings[j];
  759. zero_crossing[i].crossings[j]=0;
  760. if (correct != -1)
  761. zero_crossing[i].crossings[correct]=(short) l;
  762. }
  763. }
  764. /*
  765. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  766. % %
  767. % %
  768. % %
  769. + D e f i n e R e g i o n %
  770. % %
  771. % %
  772. % %
  773. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  774. %
  775. % DefineRegion() defines the left and right boundaries of a peak region.
  776. %
  777. % The format of the DefineRegion method is:
  778. %
  779. % ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
  780. %
  781. % A description of each parameter follows.
  782. %
  783. % o extrema: Specifies a pointer to an array of integers. They
  784. % represent the peaks and valleys of the histogram for each color
  785. % component.
  786. %
  787. % o extents: This pointer to an ExtentPacket represent the extends
  788. % of a particular peak or valley of a color component.
  789. %
  790. */
  791. static ssize_t DefineRegion(const short *extrema,ExtentPacket *extents)
  792. {
  793. /*
  794. Initialize to default values.
  795. */
  796. extents->left=0;
  797. extents->center=0.0;
  798. extents->right=255;
  799. /*
  800. Find the left side (maxima).
  801. */
  802. for ( ; extents->index <= 255; extents->index++)
  803. if (extrema[extents->index] > 0)
  804. break;
  805. if (extents->index > 255)
  806. return(MagickFalse); /* no left side - no region exists */
  807. extents->left=extents->index;
  808. /*
  809. Find the right side (minima).
  810. */
  811. for ( ; extents->index <= 255; extents->index++)
  812. if (extrema[extents->index] < 0)
  813. break;
  814. extents->right=extents->index-1;
  815. return(MagickTrue);
  816. }
  817. /*
  818. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  819. % %
  820. % %
  821. % %
  822. + D e r i v a t i v e H i s t o g r a m %
  823. % %
  824. % %
  825. % %
  826. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  827. %
  828. % DerivativeHistogram() determines the derivative of the histogram using
  829. % central differencing.
  830. %
  831. % The format of the DerivativeHistogram method is:
  832. %
  833. % DerivativeHistogram(const double *histogram,
  834. % double *derivative)
  835. %
  836. % A description of each parameter follows.
  837. %
  838. % o histogram: Specifies an array of doubles representing the number
  839. % of pixels for each intensity of a particular color component.
  840. %
  841. % o derivative: This array of doubles is initialized by
  842. % DerivativeHistogram to the derivative of the histogram using central
  843. % differencing.
  844. %
  845. */
  846. static void DerivativeHistogram(const double *histogram,
  847. double *derivative)
  848. {
  849. register ssize_t
  850. i,
  851. n;
  852. /*
  853. Compute endpoints using second order polynomial interpolation.
  854. */
  855. n=255;
  856. derivative[0]=(-1.5*histogram[0]+2.0*histogram[1]-0.5*histogram[2]);
  857. derivative[n]=(0.5*histogram[n-2]-2.0*histogram[n-1]+1.5*histogram[n]);
  858. /*
  859. Compute derivative using central differencing.
  860. */
  861. for (i=1; i < n; i++)
  862. derivative[i]=(histogram[i+1]-histogram[i-1])/2.0;
  863. return;
  864. }
  865. /*
  866. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  867. % %
  868. % %
  869. % %
  870. + G e t I m a g e D y n a m i c T h r e s h o l d %
  871. % %
  872. % %
  873. % %
  874. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  875. %
  876. % GetImageDynamicThreshold() returns the dynamic threshold for an image.
  877. %
  878. % The format of the GetImageDynamicThreshold method is:
  879. %
  880. % MagickBooleanType GetImageDynamicThreshold(const Image *image,
  881. % const double cluster_threshold,const double smooth_threshold,
  882. % PixelInfo *pixel,ExceptionInfo *exception)
  883. %
  884. % A description of each parameter follows.
  885. %
  886. % o image: the image.
  887. %
  888. % o cluster_threshold: This double represents the minimum number of
  889. % pixels contained in a hexahedra before it can be considered valid
  890. % (expressed as a percentage).
  891. %
  892. % o smooth_threshold: the smoothing threshold eliminates noise in the second
  893. % derivative of the histogram. As the value is increased, you can expect a
  894. % smoother second derivative.
  895. %
  896. % o pixel: return the dynamic threshold here.
  897. %
  898. % o exception: return any errors or warnings in this structure.
  899. %
  900. */
  901. MagickExport MagickBooleanType GetImageDynamicThreshold(const Image *image,
  902. const double cluster_threshold,const double smooth_threshold,
  903. PixelInfo *pixel,ExceptionInfo *exception)
  904. {
  905. Cluster
  906. *background,
  907. *cluster,
  908. *object,
  909. *head,
  910. *last_cluster,
  911. *next_cluster;
  912. ExtentPacket
  913. blue,
  914. green,
  915. red;
  916. MagickBooleanType
  917. proceed;
  918. double
  919. threshold;
  920. register const Quantum
  921. *p;
  922. register ssize_t
  923. i,
  924. x;
  925. short
  926. *extrema[MaxDimension];
  927. ssize_t
  928. count,
  929. *histogram[MaxDimension],
  930. y;
  931. /*
  932. Allocate histogram and extrema.
  933. */
  934. assert(image != (Image *) NULL);
  935. assert(image->signature == MagickCoreSignature);
  936. if (image->debug != MagickFalse)
  937. (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  938. GetPixelInfo(image,pixel);
  939. for (i=0; i < MaxDimension; i++)
  940. {
  941. histogram[i]=(ssize_t *) AcquireQuantumMemory(256UL,sizeof(**histogram));
  942. extrema[i]=(short *) AcquireQuantumMemory(256UL,sizeof(**histogram));
  943. if ((histogram[i] == (ssize_t *) NULL) || (extrema[i] == (short *) NULL))
  944. {
  945. for (i-- ; i >= 0; i--)
  946. {
  947. extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
  948. histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
  949. }
  950. (void) ThrowMagickException(exception,GetMagickModule(),
  951. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  952. return(MagickFalse);
  953. }
  954. }
  955. /*
  956. Initialize histogram.
  957. */
  958. InitializeHistogram(image,histogram,exception);
  959. (void) OptimalTau(histogram[Red],Tau,0.2f,DeltaTau,
  960. (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Red]);
  961. (void) OptimalTau(histogram[Green],Tau,0.2f,DeltaTau,
  962. (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Green]);
  963. (void) OptimalTau(histogram[Blue],Tau,0.2f,DeltaTau,
  964. (smooth_threshold == 0.0f ? 1.0f : smooth_threshold),extrema[Blue]);
  965. /*
  966. Form clusters.
  967. */
  968. cluster=(Cluster *) NULL;
  969. head=(Cluster *) NULL;
  970. (void) memset(&red,0,sizeof(red));
  971. (void) memset(&green,0,sizeof(green));
  972. (void) memset(&blue,0,sizeof(blue));
  973. while (DefineRegion(extrema[Red],&red) != 0)
  974. {
  975. green.index=0;
  976. while (DefineRegion(extrema[Green],&green) != 0)
  977. {
  978. blue.index=0;
  979. while (DefineRegion(extrema[Blue],&blue) != 0)
  980. {
  981. /*
  982. Allocate a new class.
  983. */
  984. if (head != (Cluster *) NULL)
  985. {
  986. cluster->next=(Cluster *) AcquireMagickMemory(
  987. sizeof(*cluster->next));
  988. cluster=cluster->next;
  989. }
  990. else
  991. {
  992. cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
  993. head=cluster;
  994. }
  995. if (cluster == (Cluster *) NULL)
  996. {
  997. (void) ThrowMagickException(exception,GetMagickModule(),
  998. ResourceLimitError,"MemoryAllocationFailed","`%s'",
  999. image->filename);
  1000. return(MagickFalse);
  1001. }
  1002. /*
  1003. Initialize a new class.
  1004. */
  1005. cluster->count=0;
  1006. cluster->red=red;
  1007. cluster->green=green;
  1008. cluster->blue=blue;
  1009. cluster->next=(Cluster *) NULL;
  1010. }
  1011. }
  1012. }
  1013. if (head == (Cluster *) NULL)
  1014. {
  1015. /*
  1016. No classes were identified-- create one.
  1017. */
  1018. cluster=(Cluster *) AcquireMagickMemory(sizeof(*cluster));
  1019. if (cluster == (Cluster *) NULL)
  1020. {
  1021. (void) ThrowMagickException(exception,GetMagickModule(),
  1022. ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
  1023. return(MagickFalse);
  1024. }
  1025. /*
  1026. Initialize a new class.
  1027. */
  1028. cluster->count=0;
  1029. cluster->red=red;
  1030. cluster->green=green;
  1031. cluster->blue=blue;
  1032. cluster->next=(Cluster *) NULL;
  1033. head=cluster;
  1034. }
  1035. /*
  1036. Count the pixels for each cluster.
  1037. */
  1038. count=0;
  1039. for (y=0; y < (ssize_t) image->rows; y++)
  1040. {
  1041. p=GetVirtualPixels(image,0,y,image->columns,1,exception);
  1042. if (p == (const Quantum *) NULL)
  1043. break;
  1044. for (x=0; x < (ssize_t) image->columns; x++)
  1045. {
  1046. for (cluster=head; cluster != (Cluster *) NULL; cluster=cluster->next)
  1047. if (((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) >=
  1048. (cluster->red.left-SafeMargin)) &&
  1049. ((ssize_t) ScaleQuantumToChar(GetPixelRed(image,p)) <=
  1050. (cluster->red.right+SafeMargin)) &&
  1051. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) >=
  1052. (cluster->green.left-SafeMargin)) &&
  1053. ((ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p)) <=
  1054. (cluster->green.right+SafeMargin)) &&
  1055. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) >=
  1056. (cluster->blue.left-SafeMargin)) &&
  1057. ((ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p)) <=
  1058. (cluster->blue.right+SafeMargin)))
  1059. {
  1060. /*
  1061. Count this pixel.
  1062. */
  1063. count++;
  1064. cluster->red.center+=(double) ScaleQuantumToChar(
  1065. GetPixelRed(image,p));
  1066. cluster->green.center+=(double) ScaleQuantumToChar(
  1067. GetPixelGreen(image,p));
  1068. cluster->blue.center+=(double) ScaleQuantumToChar(
  1069. GetPixelBlue(image,p));
  1070. cluster->count++;
  1071. break;
  1072. }
  1073. p+=GetPixelChannels(image);
  1074. }
  1075. proceed=SetImageProgress(image,SegmentImageTag,(MagickOffsetType) y,
  1076. 2*image->rows);
  1077. if (proceed == MagickFalse)
  1078. break;
  1079. }
  1080. /*
  1081. Remove clusters that do not meet minimum cluster threshold.
  1082. */
  1083. count=0;
  1084. last_cluster=head;
  1085. next_cluster=head;
  1086. for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
  1087. {
  1088. next_cluster=cluster->next;
  1089. if ((cluster->count > 0) &&
  1090. (cluster->count >= (count*cluster_threshold/100.0)))
  1091. {
  1092. /*
  1093. Initialize cluster.
  1094. */
  1095. cluster->id=count;
  1096. cluster->red.center/=cluster->count;
  1097. cluster->green.center/=cluster->count;
  1098. cluster->blue.center/=cluster->count;
  1099. count++;
  1100. last_cluster=cluster;
  1101. continue;
  1102. }
  1103. /*
  1104. Delete cluster.
  1105. */
  1106. if (cluster == head)
  1107. head=next_cluster;
  1108. else
  1109. last_cluster->next=next_cluster;
  1110. cluster=(Cluster *) RelinquishMagickMemory(cluster);
  1111. }
  1112. object=head;
  1113. background=head;
  1114. if (count > 1)
  1115. {
  1116. object=head->next;
  1117. for (cluster=object; cluster->next != (Cluster *) NULL; )
  1118. {
  1119. if (cluster->count < object->count)
  1120. object=cluster;
  1121. cluster=cluster->next;
  1122. }
  1123. background=head->next;
  1124. for (cluster=background; cluster->next != (Cluster *) NULL; )
  1125. {
  1126. if (cluster->count > background->count)
  1127. background=cluster;
  1128. cluster=cluster->next;
  1129. }
  1130. }
  1131. if (background != (Cluster *) NULL)
  1132. {
  1133. threshold=(background->red.center+object->red.center)/2.0;
  1134. pixel->red=(double) ScaleCharToQuantum((unsigned char)
  1135. (threshold+0.5));
  1136. threshold=(background->green.center+object->green.center)/2.0;
  1137. pixel->green=(double) ScaleCharToQuantum((unsigned char)
  1138. (threshold+0.5));
  1139. threshold=(background->blue.center+object->blue.center)/2.0;
  1140. pixel->blue=(double) ScaleCharToQuantum((unsigned char)
  1141. (threshold+0.5));
  1142. }
  1143. /*
  1144. Relinquish resources.
  1145. */
  1146. for (cluster=head; cluster != (Cluster *) NULL; cluster=next_cluster)
  1147. {
  1148. next_cluster=cluster->next;
  1149. cluster=(Cluster *) RelinquishMagickMemory(cluster);
  1150. }
  1151. for (i=0; i < MaxDimension; i++)
  1152. {
  1153. extrema[i]=(short *) RelinquishMagickMemory(extrema[i]);
  1154. histogram[i]=(ssize_t *) RelinquishMagickMemory(histogram[i]);
  1155. }
  1156. return(MagickTrue);
  1157. }
  1158. /*
  1159. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1160. % %
  1161. % %
  1162. % %
  1163. + I n i t i a l i z e H i s t o g r a m %
  1164. % %
  1165. % %
  1166. % %
  1167. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1168. %
  1169. % InitializeHistogram() computes the histogram for an image.
  1170. %
  1171. % The format of the InitializeHistogram method is:
  1172. %
  1173. % InitializeHistogram(const Image *image,ssize_t **histogram)
  1174. %
  1175. % A description of each parameter follows.
  1176. %
  1177. % o image: Specifies a pointer to an Image structure; returned from
  1178. % ReadImage.
  1179. %
  1180. % o histogram: Specifies an array of integers representing the number
  1181. % of pixels for each intensity of a particular color component.
  1182. %
  1183. */
  1184. static void InitializeHistogram(const Image *image,ssize_t **histogram,
  1185. ExceptionInfo *exception)
  1186. {
  1187. register const Quantum
  1188. *p;
  1189. register ssize_t
  1190. i,
  1191. x;
  1192. ssize_t
  1193. y;
  1194. /*
  1195. Initialize histogram.
  1196. */
  1197. for (i=0; i <= 255; i++)
  1198. {
  1199. histogram[Red][i]=0;
  1200. histogram[Green][i]=0;
  1201. histogram[Blue][i]=0;
  1202. }
  1203. for (y=0; y < (ssize_t) image->rows; y++)
  1204. {
  1205. p=GetVirtualPixels(image,0,y,image->columns,1,exception);
  1206. if (p == (const Quantum *) NULL)
  1207. break;
  1208. for (x=0; x < (ssize_t) image->columns; x++)
  1209. {
  1210. histogram[Red][(ssize_t) ScaleQuantumToChar(GetPixelRed(image,p))]++;
  1211. histogram[Green][(ssize_t) ScaleQuantumToChar(GetPixelGreen(image,p))]++;
  1212. histogram[Blue][(ssize_t) ScaleQuantumToChar(GetPixelBlue(image,p))]++;
  1213. p+=GetPixelChannels(image);
  1214. }
  1215. }
  1216. }
  1217. /*
  1218. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1219. % %
  1220. % %
  1221. % %
  1222. + I n i t i a l i z e I n t e r v a l T r e e %
  1223. % %
  1224. % %
  1225. % %
  1226. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1227. %
  1228. % InitializeIntervalTree() initializes an interval tree from the lists of
  1229. % zero crossings.
  1230. %
  1231. % The format of the InitializeIntervalTree method is:
  1232. %
  1233. % InitializeIntervalTree(IntervalTree **list,ssize_t *number_nodes,
  1234. % IntervalTree *node)
  1235. %
  1236. % A description of each parameter follows.
  1237. %
  1238. % o zero_crossing: Specifies an array of structures of type ZeroCrossing.
  1239. %
  1240. % o number_crossings: This size_t specifies the number of elements
  1241. % in the zero_crossing array.
  1242. %
  1243. */
  1244. static void InitializeList(IntervalTree **list,ssize_t *number_nodes,
  1245. IntervalTree *node)
  1246. {
  1247. if (node == (IntervalTree *) NULL)
  1248. return;
  1249. if (node->child == (IntervalTree *) NULL)
  1250. list[(*number_nodes)++]=node;
  1251. InitializeList(list,number_nodes,node->sibling);
  1252. InitializeList(list,number_nodes,node->child);
  1253. }
  1254. static void MeanStability(IntervalTree *node)
  1255. {
  1256. register IntervalTree
  1257. *child;
  1258. if (node == (IntervalTree *) NULL)
  1259. return;
  1260. node->mean_stability=0.0;
  1261. child=node->child;
  1262. if (child != (IntervalTree *) NULL)
  1263. {
  1264. register ssize_t
  1265. count;
  1266. register double
  1267. sum;
  1268. sum=0.0;
  1269. count=0;
  1270. for ( ; child != (IntervalTree *) NULL; child=child->sibling)
  1271. {
  1272. sum+=child->stability;
  1273. count++;
  1274. }
  1275. node->mean_stability=sum/(double) count;
  1276. }
  1277. MeanStability(node->sibling);
  1278. MeanStability(node->child);
  1279. }
  1280. static void Stability(IntervalTree *node)
  1281. {
  1282. if (node == (IntervalTree *) NULL)
  1283. return;
  1284. if (node->child == (IntervalTree *) NULL)
  1285. node->stability=0.0;
  1286. else
  1287. node->stability=node->tau-(node->child)->tau;
  1288. Stability(node->sibling);
  1289. Stability(node->child);
  1290. }
  1291. static IntervalTree *InitializeIntervalTree(const ZeroCrossing *zero_crossing,
  1292. const size_t number_crossings)
  1293. {
  1294. IntervalTree
  1295. *head,
  1296. **list,
  1297. *node,
  1298. *root;
  1299. register ssize_t
  1300. i;
  1301. ssize_t
  1302. j,
  1303. k,
  1304. left,
  1305. number_nodes;
  1306. /*
  1307. Allocate interval tree.
  1308. */
  1309. list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
  1310. sizeof(*list));
  1311. if (list == (IntervalTree **) NULL)
  1312. return((IntervalTree *) NULL);
  1313. /*
  1314. The root is the entire histogram.
  1315. */
  1316. root=(IntervalTree *) AcquireCriticalMemory(sizeof(*root));
  1317. root->child=(IntervalTree *) NULL;
  1318. root->sibling=(IntervalTree *) NULL;
  1319. root->tau=0.0;
  1320. root->left=0;
  1321. root->right=255;
  1322. root->mean_stability=0.0;
  1323. root->stability=0.0;
  1324. (void) memset(list,0,TreeLength*sizeof(*list));
  1325. for (i=(-1); i < (ssize_t) number_crossings; i++)
  1326. {
  1327. /*
  1328. Initialize list with all nodes with no children.
  1329. */
  1330. number_nodes=0;
  1331. InitializeList(list,&number_nodes,root);
  1332. /*
  1333. Split list.
  1334. */
  1335. for (j=0; j < number_nodes; j++)
  1336. {
  1337. head=list[j];
  1338. left=head->left;
  1339. node=head;
  1340. for (k=head->left+1; k < head->right; k++)
  1341. {
  1342. if (zero_crossing[i+1].crossings[k] != 0)
  1343. {
  1344. if (node == head)
  1345. {
  1346. node->child=(IntervalTree *) AcquireMagickMemory(
  1347. sizeof(*node->child));
  1348. node=node->child;
  1349. }
  1350. else
  1351. {
  1352. node->sibling=(IntervalTree *) AcquireMagickMemory(
  1353. sizeof(*node->sibling));
  1354. node=node->sibling;
  1355. }
  1356. if (node == (IntervalTree *) NULL)
  1357. {
  1358. list=(IntervalTree **) RelinquishMagickMemory(list);
  1359. FreeNodes(root);
  1360. return((IntervalTree *) NULL);
  1361. }
  1362. node->tau=zero_crossing[i+1].tau;
  1363. node->child=(IntervalTree *) NULL;
  1364. node->sibling=(IntervalTree *) NULL;
  1365. node->left=left;
  1366. node->right=k;
  1367. left=k;
  1368. }
  1369. }
  1370. if (left != head->left)
  1371. {
  1372. node->sibling=(IntervalTree *) AcquireMagickMemory(
  1373. sizeof(*node->sibling));
  1374. node=node->sibling;
  1375. if (node == (IntervalTree *) NULL)
  1376. {
  1377. list=(IntervalTree **) RelinquishMagickMemory(list);
  1378. FreeNodes(root);
  1379. return((IntervalTree *) NULL);
  1380. }
  1381. node->tau=zero_crossing[i+1].tau;
  1382. node->child=(IntervalTree *) NULL;
  1383. node->sibling=(IntervalTree *) NULL;
  1384. node->left=left;
  1385. node->right=head->right;
  1386. }
  1387. }
  1388. }
  1389. /*
  1390. Determine the stability: difference between a nodes tau and its child.
  1391. */
  1392. Stability(root->child);
  1393. MeanStability(root->child);
  1394. list=(IntervalTree **) RelinquishMagickMemory(list);
  1395. return(root);
  1396. }
  1397. /*
  1398. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1399. % %
  1400. % %
  1401. % %
  1402. + O p t i m a l T a u %
  1403. % %
  1404. % %
  1405. % %
  1406. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1407. %
  1408. % OptimalTau() finds the optimal tau for each band of the histogram.
  1409. %
  1410. % The format of the OptimalTau method is:
  1411. %
  1412. % double OptimalTau(const ssize_t *histogram,const double max_tau,
  1413. % const double min_tau,const double delta_tau,
  1414. % const double smooth_threshold,short *extrema)
  1415. %
  1416. % A description of each parameter follows.
  1417. %
  1418. % o histogram: Specifies an array of integers representing the number
  1419. % of pixels for each intensity of a particular color component.
  1420. %
  1421. % o extrema: Specifies a pointer to an array of integers. They
  1422. % represent the peaks and valleys of the histogram for each color
  1423. % component.
  1424. %
  1425. */
  1426. static void ActiveNodes(IntervalTree **list,ssize_t *number_nodes,
  1427. IntervalTree *node)
  1428. {
  1429. if (node == (IntervalTree *) NULL)
  1430. return;
  1431. if (node->stability >= node->mean_stability)
  1432. {
  1433. list[(*number_nodes)++]=node;
  1434. ActiveNodes(list,number_nodes,node->sibling);
  1435. }
  1436. else
  1437. {
  1438. ActiveNodes(list,number_nodes,node->sibling);
  1439. ActiveNodes(list,number_nodes,node->child);
  1440. }
  1441. }
  1442. static void FreeNodes(IntervalTree *node)
  1443. {
  1444. if (node == (IntervalTree *) NULL)
  1445. return;
  1446. FreeNodes(node->sibling);
  1447. FreeNodes(node->child);
  1448. node=(IntervalTree *) RelinquishMagickMemory(node);
  1449. }
  1450. static double OptimalTau(const ssize_t *histogram,const double max_tau,
  1451. const double min_tau,const double delta_tau,const double smooth_threshold,
  1452. short *extrema)
  1453. {
  1454. IntervalTree
  1455. **list,
  1456. *node,
  1457. *root;
  1458. MagickBooleanType
  1459. peak;
  1460. double
  1461. average_tau,
  1462. *derivative,
  1463. *second_derivative,
  1464. tau,
  1465. value;
  1466. register ssize_t
  1467. i,
  1468. x;
  1469. size_t
  1470. count,
  1471. number_crossings;
  1472. ssize_t
  1473. index,
  1474. j,
  1475. k,
  1476. number_nodes;
  1477. ZeroCrossing
  1478. *zero_crossing;
  1479. /*
  1480. Allocate interval tree.
  1481. */
  1482. list=(IntervalTree **) AcquireQuantumMemory((size_t) TreeLength,
  1483. sizeof(*list));
  1484. if (list == (IntervalTree **) NULL)
  1485. return(0.0);
  1486. /*
  1487. Allocate zero crossing list.
  1488. */
  1489. count=(size_t) ((max_tau-min_tau)/delta_tau)+2;
  1490. zero_crossing=(ZeroCrossing *) AcquireQuantumMemory((size_t) count,
  1491. sizeof(*zero_crossing));
  1492. if (zero_crossing == (ZeroCrossing *) NULL)
  1493. {
  1494. list=(IntervalTree **) RelinquishMagickMemory(list);
  1495. return(0.0);
  1496. }
  1497. for (i=0; i < (ssize_t) count; i++)
  1498. zero_crossing[i].tau=(-1.0);
  1499. /*
  1500. Initialize zero crossing list.
  1501. */
  1502. derivative=(double *) AcquireCriticalMemory(256*sizeof(*derivative));
  1503. second_derivative=(double *)

Large files files are truncated, but you can click here to view the full file