Leptonica  1.73
Image processing and image analysis suite
numafunc1.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
127 #include <math.h>
128 #include "allheaders.h"
129 
130 
131 /*----------------------------------------------------------------------*
132  * Arithmetic and logical ops on Numas *
133  *----------------------------------------------------------------------*/
152 NUMA *
154  NUMA *na1,
155  NUMA *na2,
156  l_int32 op)
157 {
158 l_int32 i, n;
159 l_float32 val1, val2;
160 
161  PROCNAME("numaArithOp");
162 
163  if (!na1 || !na2)
164  return (NUMA *)ERROR_PTR("na1, na2 not both defined", procName, nad);
165  n = numaGetCount(na1);
166  if (n != numaGetCount(na2))
167  return (NUMA *)ERROR_PTR("na1, na2 sizes differ", procName, nad);
168  if (nad && nad != na1)
169  return (NUMA *)ERROR_PTR("nad defined but not in-place", procName, nad);
170  if (op != L_ARITH_ADD && op != L_ARITH_SUBTRACT &&
171  op != L_ARITH_MULTIPLY && op != L_ARITH_DIVIDE)
172  return (NUMA *)ERROR_PTR("invalid op", procName, nad);
173  if (op == L_ARITH_DIVIDE) {
174  for (i = 0; i < n; i++) {
175  numaGetFValue(na2, i, &val2);
176  if (val2 == 0.0)
177  return (NUMA *)ERROR_PTR("na2 has 0 element", procName, nad);
178  }
179  }
180 
181  /* If nad is not identical to na1, make it an identical copy */
182  if (!nad)
183  nad = numaCopy(na1);
184 
185  for (i = 0; i < n; i++) {
186  numaGetFValue(nad, i, &val1);
187  numaGetFValue(na2, i, &val2);
188  switch (op) {
189  case L_ARITH_ADD:
190  numaSetValue(nad, i, val1 + val2);
191  break;
192  case L_ARITH_SUBTRACT:
193  numaSetValue(nad, i, val1 - val2);
194  break;
195  case L_ARITH_MULTIPLY:
196  numaSetValue(nad, i, val1 * val2);
197  break;
198  case L_ARITH_DIVIDE:
199  numaSetValue(nad, i, val1 / val2);
200  break;
201  default:
202  fprintf(stderr, " Unknown arith op: %d\n", op);
203  return nad;
204  }
205  }
206 
207  return nad;
208 }
209 
210 
232 NUMA *
234  NUMA *na1,
235  NUMA *na2,
236  l_int32 op)
237 {
238 l_int32 i, n, val1, val2, val;
239 
240  PROCNAME("numaLogicalOp");
241 
242  if (!na1 || !na2)
243  return (NUMA *)ERROR_PTR("na1, na2 not both defined", procName, nad);
244  n = numaGetCount(na1);
245  if (n != numaGetCount(na2))
246  return (NUMA *)ERROR_PTR("na1, na2 sizes differ", procName, nad);
247  if (nad && nad != na1)
248  return (NUMA *)ERROR_PTR("nad defined; not in-place", procName, nad);
249  if (op != L_UNION && op != L_INTERSECTION &&
250  op != L_SUBTRACTION && op != L_EXCLUSIVE_OR)
251  return (NUMA *)ERROR_PTR("invalid op", procName, nad);
252 
253  /* If nad is not identical to na1, make it an identical copy */
254  if (!nad)
255  nad = numaCopy(na1);
256 
257  for (i = 0; i < n; i++) {
258  numaGetIValue(nad, i, &val1);
259  numaGetIValue(na2, i, &val2);
260  val1 = (val1 == 0) ? 0 : 1;
261  val2 = (val2 == 0) ? 0 : 1;
262  switch (op) {
263  case L_UNION:
264  val = (val1 || val2) ? 1 : 0;
265  numaSetValue(nad, i, val);
266  break;
267  case L_INTERSECTION:
268  val = (val1 && val2) ? 1 : 0;
269  numaSetValue(nad, i, val);
270  break;
271  case L_SUBTRACTION:
272  val = (val1 && !val2) ? 1 : 0;
273  numaSetValue(nad, i, val);
274  break;
275  case L_EXCLUSIVE_OR:
276  val = (val1 != val2) ? 1 : 0;
277  numaSetValue(nad, i, val);
278  break;
279  default:
280  fprintf(stderr, " Unknown logical op: %d\n", op);
281  return nad;
282  }
283  }
284 
285  return nad;
286 }
287 
288 
305 NUMA *
307  NUMA *nas)
308 {
309 l_int32 i, n, val;
310 
311  PROCNAME("numaInvert");
312 
313  if (!nas)
314  return (NUMA *)ERROR_PTR("nas not defined", procName, nad);
315  if (nad && nad != nas)
316  return (NUMA *)ERROR_PTR("nad defined; not in-place", procName, nad);
317 
318  if (!nad)
319  nad = numaCopy(nas);
320  n = numaGetCount(nad);
321  for (i = 0; i < n; i++) {
322  numaGetIValue(nad, i, &val);
323  if (!val)
324  val = 1;
325  else
326  val = 0;
327  numaSetValue(nad, i, val);
328  }
329 
330  return nad;
331 }
332 
333 
350 l_int32
352  NUMA *na2,
353  l_float32 maxdiff,
354  l_int32 *psimilar)
355 {
356 l_int32 i, n;
357 l_float32 val1, val2;
358 
359  PROCNAME("numaSimilar");
360 
361  if (!psimilar)
362  return ERROR_INT("&similar not defined", procName, 1);
363  *psimilar = 0;
364  if (!na1 || !na2)
365  return ERROR_INT("na1 and na2 not both defined", procName, 1);
366  maxdiff = L_ABS(maxdiff);
367 
368  n = numaGetCount(na1);
369  if (n != numaGetCount(na2)) return 0;
370 
371  for (i = 0; i < n; i++) {
372  numaGetFValue(na1, i, &val1);
373  numaGetFValue(na2, i, &val2);
374  if (L_ABS(val1 - val2) > maxdiff) return 0;
375  }
376 
377  *psimilar = 1;
378  return 0;
379 }
380 
381 
399 l_int32
401  l_int32 index,
402  l_float32 val)
403 {
404 l_int32 n;
405 
406  PROCNAME("numaAddToNumber");
407 
408  if (!na)
409  return ERROR_INT("na not defined", procName, 1);
410  n = numaGetCount(na);
411  if (index < 0 || index >= n)
412  return ERROR_INT("index not in {0...n - 1}", procName, 1);
413 
414  na->array[index] += val;
415  return 0;
416 }
417 
418 
419 /*----------------------------------------------------------------------*
420  * Simple extractions *
421  *----------------------------------------------------------------------*/
430 l_int32
432  l_float32 *pminval,
433  l_int32 *piminloc)
434 {
435 l_int32 i, n, iminloc;
436 l_float32 val, minval;
437 
438  PROCNAME("numaGetMin");
439 
440  if (!pminval && !piminloc)
441  return ERROR_INT("nothing to do", procName, 1);
442  if (pminval) *pminval = 0.0;
443  if (piminloc) *piminloc = 0;
444  if (!na)
445  return ERROR_INT("na not defined", procName, 1);
446 
447  minval = +1000000000.;
448  iminloc = 0;
449  n = numaGetCount(na);
450  for (i = 0; i < n; i++) {
451  numaGetFValue(na, i, &val);
452  if (val < minval) {
453  minval = val;
454  iminloc = i;
455  }
456  }
457 
458  if (pminval) *pminval = minval;
459  if (piminloc) *piminloc = iminloc;
460  return 0;
461 }
462 
463 
472 l_int32
474  l_float32 *pmaxval,
475  l_int32 *pimaxloc)
476 {
477 l_int32 i, n, imaxloc;
478 l_float32 val, maxval;
479 
480  PROCNAME("numaGetMax");
481 
482  if (!pmaxval && !pimaxloc)
483  return ERROR_INT("nothing to do", procName, 1);
484  if (pmaxval) *pmaxval = 0.0;
485  if (pimaxloc) *pimaxloc = 0;
486  if (!na)
487  return ERROR_INT("na not defined", procName, 1);
488 
489  maxval = -1000000000.;
490  imaxloc = 0;
491  n = numaGetCount(na);
492  for (i = 0; i < n; i++) {
493  numaGetFValue(na, i, &val);
494  if (val > maxval) {
495  maxval = val;
496  imaxloc = i;
497  }
498  }
499 
500  if (pmaxval) *pmaxval = maxval;
501  if (pimaxloc) *pimaxloc = imaxloc;
502  return 0;
503 }
504 
505 
513 l_int32
515  l_float32 *psum)
516 {
517 l_int32 i, n;
518 l_float32 val, sum;
519 
520  PROCNAME("numaGetSum");
521 
522  if (!na)
523  return ERROR_INT("na not defined", procName, 1);
524  if (!psum)
525  return ERROR_INT("&sum not defined", procName, 1);
526 
527  sum = 0.0;
528  n = numaGetCount(na);
529  for (i = 0; i < n; i++) {
530  numaGetFValue(na, i, &val);
531  sum += val;
532  }
533  *psum = sum;
534  return 0;
535 }
536 
537 
552 NUMA *
554 {
555 l_int32 i, n;
556 l_float32 val, sum;
557 NUMA *nasum;
558 
559  PROCNAME("numaGetPartialSums");
560 
561  if (!na)
562  return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
563 
564  n = numaGetCount(na);
565  nasum = numaCreate(n);
566  sum = 0.0;
567  for (i = 0; i < n; i++) {
568  numaGetFValue(na, i, &val);
569  sum += val;
570  numaAddNumber(nasum, sum);
571  }
572  return nasum;
573 }
574 
575 
585 l_int32
587  l_int32 first,
588  l_int32 last,
589  l_float32 *psum)
590 {
591 l_int32 i, n, truelast;
592 l_float32 val, sum;
593 
594  PROCNAME("numaGetSumOnInterval");
595 
596  if (!na)
597  return ERROR_INT("na not defined", procName, 1);
598  if (!psum)
599  return ERROR_INT("&sum not defined", procName, 1);
600  *psum = 0.0;
601 
602  sum = 0.0;
603  n = numaGetCount(na);
604  if (first >= n) /* not an error */
605  return 0;
606  truelast = L_MIN(last, n - 1);
607 
608  for (i = first; i <= truelast; i++) {
609  numaGetFValue(na, i, &val);
610  sum += val;
611  }
612  *psum = sum;
613  return 0;
614 }
615 
616 
631 l_int32
633  l_int32 maxsamples,
634  l_int32 *pallints)
635 {
636 l_int32 i, n, incr;
637 l_float32 val;
638 
639  PROCNAME("numaHasOnlyIntegers");
640 
641  if (!pallints)
642  return ERROR_INT("&allints not defined", procName, 1);
643  *pallints = TRUE;
644  if (!na)
645  return ERROR_INT("na not defined", procName, 1);
646 
647  if ((n = numaGetCount(na)) == 0)
648  return ERROR_INT("na empty", procName, 1);
649  if (maxsamples <= 0)
650  incr = 1;
651  else
652  incr = (l_int32)((n + maxsamples - 1) / maxsamples);
653  for (i = 0; i < n; i += incr) {
654  numaGetFValue(na, i, &val);
655  if (val != (l_int32)val) {
656  *pallints = FALSE;
657  return 0;
658  }
659  }
660 
661  return 0;
662 }
663 
664 
672 NUMA *
674  l_int32 subfactor)
675 {
676 l_int32 i, n;
677 l_float32 val;
678 NUMA *nad;
679 
680  PROCNAME("numaSubsample");
681 
682  if (!nas)
683  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
684  if (subfactor < 1)
685  return (NUMA *)ERROR_PTR("subfactor < 1", procName, NULL);
686 
687  nad = numaCreate(0);
688  n = numaGetCount(nas);
689  for (i = 0; i < n; i++) {
690  if (i % subfactor != 0) continue;
691  numaGetFValue(nas, i, &val);
692  numaAddNumber(nad, val);
693  }
694 
695  return nad;
696 }
697 
698 
706 NUMA *
708 {
709 l_int32 i, n, prev, cur;
710 NUMA *nad;
711 
712  PROCNAME("numaMakeDelta");
713 
714  if (!nas)
715  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
716  n = numaGetCount(nas);
717  nad = numaCreate(n - 1);
718  prev = 0;
719  for (i = 1; i < n; i++) {
720  numaGetIValue(nas, i, &cur);
721  numaAddNumber(nad, cur - prev);
722  prev = cur;
723  }
724  return nad;
725 }
726 
727 
736 NUMA *
737 numaMakeSequence(l_float32 startval,
738  l_float32 increment,
739  l_int32 size)
740 {
741 l_int32 i;
742 l_float32 val;
743 NUMA *na;
744 
745  PROCNAME("numaMakeSequence");
746 
747  if ((na = numaCreate(size)) == NULL)
748  return (NUMA *)ERROR_PTR("na not made", procName, NULL);
749 
750  for (i = 0; i < size; i++) {
751  val = startval + i * increment;
752  numaAddNumber(na, val);
753  }
754 
755  return na;
756 }
757 
758 
767 NUMA *
768 numaMakeConstant(l_float32 val,
769  l_int32 size)
770 {
771  return numaMakeSequence(val, 0.0, size);
772 }
773 
774 
783 NUMA *
785  NUMA *nas)
786 {
787 l_int32 i, n;
788 l_float32 val;
789 
790  PROCNAME("numaMakeAbsValue");
791 
792  if (!nas)
793  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
794  if (nad && nad != nas)
795  return (NUMA *)ERROR_PTR("nad and not in-place", procName, NULL);
796 
797  if (!nad)
798  nad = numaCopy(nas);
799  n = numaGetCount(nad);
800  for (i = 0; i < n; i++) {
801  val = nad->array[i];
802  nad->array[i] = L_ABS(val);
803  }
804 
805  return nad;
806 }
807 
808 
817 NUMA *
819  l_int32 left,
820  l_int32 right,
821  l_float32 val)
822 {
823 l_int32 i, n, len;
824 l_float32 startx, delx;
825 l_float32 *fas, *fad;
826 NUMA *nad;
827 
828  PROCNAME("numaAddBorder");
829 
830  if (!nas)
831  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
832  if (left < 0) left = 0;
833  if (right < 0) right = 0;
834  if (left == 0 && right == 0)
835  return numaCopy(nas);
836 
837  n = numaGetCount(nas);
838  len = n + left + right;
839  nad = numaMakeConstant(val, len);
840  numaGetParameters(nas, &startx, &delx);
841  numaSetParameters(nad, startx - delx * left, delx);
842  fas = numaGetFArray(nas, L_NOCOPY);
843  fad = numaGetFArray(nad, L_NOCOPY);
844  for (i = 0; i < n; i++)
845  fad[left + i] = fas[i];
846 
847  return nad;
848 }
849 
850 
859 NUMA *
861  l_int32 left,
862  l_int32 right,
863  l_int32 type)
864 {
865 l_int32 i, n;
866 l_float32 *fa;
867 NUMA *nad;
868 
869  PROCNAME("numaAddSpecifiedBorder");
870 
871  if (!nas)
872  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
873  if (left < 0) left = 0;
874  if (right < 0) right = 0;
875  if (left == 0 && right == 0)
876  return numaCopy(nas);
877  if (type != L_CONTINUED_BORDER && type != L_MIRRORED_BORDER)
878  return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
879  n = numaGetCount(nas);
880  if (type == L_MIRRORED_BORDER && (left > n || right > n))
881  return (NUMA *)ERROR_PTR("border too large", procName, NULL);
882 
883  nad = numaAddBorder(nas, left, right, 0);
884  n = numaGetCount(nad);
885  fa = numaGetFArray(nad, L_NOCOPY);
886  if (type == L_CONTINUED_BORDER) {
887  for (i = 0; i < left; i++)
888  fa[i] = fa[left];
889  for (i = n - right; i < n; i++)
890  fa[i] = fa[n - right - 1];
891  } else { /* type == L_MIRRORED_BORDER */
892  for (i = 0; i < left; i++)
893  fa[i] = fa[2 * left - 1 - i];
894  for (i = 0; i < right; i++)
895  fa[n - right + i] = fa[n - right - i - 1];
896  }
897 
898  return nad;
899 }
900 
901 
909 NUMA *
911  l_int32 left,
912  l_int32 right)
913 {
914 l_int32 i, n, len;
915 l_float32 startx, delx;
916 l_float32 *fas, *fad;
917 NUMA *nad;
918 
919  PROCNAME("numaRemoveBorder");
920 
921  if (!nas)
922  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
923  if (left < 0) left = 0;
924  if (right < 0) right = 0;
925  if (left == 0 && right == 0)
926  return numaCopy(nas);
927 
928  n = numaGetCount(nas);
929  if ((len = n - left - right) < 0)
930  return (NUMA *)ERROR_PTR("len < 0 after removal", procName, NULL);
931  nad = numaMakeConstant(0, len);
932  numaGetParameters(nas, &startx, &delx);
933  numaSetParameters(nad, startx + delx * left, delx);
934  fas = numaGetFArray(nas, L_NOCOPY);
935  fad = numaGetFArray(nad, L_NOCOPY);
936  for (i = 0; i < len; i++)
937  fad[i] = fas[left + i];
938 
939  return nad;
940 }
941 
942 
950 l_int32
952  l_int32 *pcount)
953 {
954 l_int32 n, i, val, count, inrun;
955 
956  PROCNAME("numaCountNonzeroRuns");
957 
958  if (!pcount)
959  return ERROR_INT("&count not defined", procName, 1);
960  *pcount = 0;
961  if (!na)
962  return ERROR_INT("na not defined", procName, 1);
963  n = numaGetCount(na);
964  count = 0;
965  inrun = FALSE;
966  for (i = 0; i < n; i++) {
967  numaGetIValue(na, i, &val);
968  if (!inrun && val > 0) {
969  count++;
970  inrun = TRUE;
971  } else if (inrun && val == 0) {
972  inrun = FALSE;
973  }
974  }
975  *pcount = count;
976  return 0;
977 }
978 
979 
989 l_int32
991  l_float32 eps,
992  l_int32 *pfirst,
993  l_int32 *plast)
994 {
995 l_int32 n, i, found;
996 l_float32 val;
997 
998  PROCNAME("numaGetNonzeroRange");
999 
1000  if (pfirst) *pfirst = 0;
1001  if (plast) *plast = 0;
1002  if (!pfirst || !plast)
1003  return ERROR_INT("pfirst and plast not both defined", procName, 1);
1004  if (!na)
1005  return ERROR_INT("na not defined", procName, 1);
1006  n = numaGetCount(na);
1007  found = FALSE;
1008  for (i = 0; i < n; i++) {
1009  numaGetFValue(na, i, &val);
1010  if (val > eps) {
1011  found = TRUE;
1012  break;
1013  }
1014  }
1015  if (!found) {
1016  *pfirst = n - 1;
1017  *plast = 0;
1018  return 1;
1019  }
1020 
1021  *pfirst = i;
1022  for (i = n - 1; i >= 0; i--) {
1023  numaGetFValue(na, i, &val);
1024  if (val > eps)
1025  break;
1026  }
1027  *plast = i;
1028  return 0;
1029 }
1030 
1031 
1040 l_int32
1042  l_int32 type,
1043  l_int32 *pcount)
1044 {
1045 l_int32 n, i, count;
1046 l_float32 val;
1047 
1048  PROCNAME("numaGetCountRelativeToZero");
1049 
1050  if (!pcount)
1051  return ERROR_INT("&count not defined", procName, 1);
1052  *pcount = 0;
1053  if (!na)
1054  return ERROR_INT("na not defined", procName, 1);
1055  n = numaGetCount(na);
1056  for (i = 0, count = 0; i < n; i++) {
1057  numaGetFValue(na, i, &val);
1058  if (type == L_LESS_THAN_ZERO && val < 0.0)
1059  count++;
1060  else if (type == L_EQUAL_TO_ZERO && val == 0.0)
1061  count++;
1062  else if (type == L_GREATER_THAN_ZERO && val > 0.0)
1063  count++;
1064  }
1065 
1066  *pcount = count;
1067  return 0;
1068 }
1069 
1070 
1088 NUMA *
1090  l_int32 first,
1091  l_int32 last)
1092 {
1093 l_int32 n, i, truelast;
1094 l_float32 val, startx, delx;
1095 NUMA *nad;
1096 
1097  PROCNAME("numaClipToInterval");
1098 
1099  if (!nas)
1100  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1101  if (first > last)
1102  return (NUMA *)ERROR_PTR("range not valid", procName, NULL);
1103 
1104  n = numaGetCount(nas);
1105  if (first >= n)
1106  return (NUMA *)ERROR_PTR("no elements in range", procName, NULL);
1107  truelast = L_MIN(last, n - 1);
1108  if ((nad = numaCreate(truelast - first + 1)) == NULL)
1109  return (NUMA *)ERROR_PTR("nad not made", procName, NULL);
1110  for (i = first; i <= truelast; i++) {
1111  numaGetFValue(nas, i, &val);
1112  numaAddNumber(nad, val);
1113  }
1114  numaGetParameters(nas, &startx, &delx);
1115  numaSetParameters(nad, startx + first * delx, delx);
1116  return nad;
1117 }
1118 
1119 
1136 NUMA *
1138  l_float32 thresh,
1139  l_int32 type)
1140 {
1141 l_int32 n, i, ival;
1142 l_float32 fval;
1143 NUMA *nai;
1144 
1145  PROCNAME("numaMakeThresholdIndicator");
1146 
1147  if (!nas)
1148  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1149  n = numaGetCount(nas);
1150  nai = numaCreate(n);
1151  for (i = 0; i < n; i++) {
1152  numaGetFValue(nas, i, &fval);
1153  ival = 0;
1154  switch (type)
1155  {
1156  case L_SELECT_IF_LT:
1157  if (fval < thresh) ival = 1;
1158  break;
1159  case L_SELECT_IF_GT:
1160  if (fval > thresh) ival = 1;
1161  break;
1162  case L_SELECT_IF_LTE:
1163  if (fval <= thresh) ival = 1;
1164  break;
1165  case L_SELECT_IF_GTE:
1166  if (fval >= thresh) ival = 1;
1167  break;
1168  default:
1169  numaDestroy(&nai);
1170  return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
1171  }
1172  numaAddNumber(nai, ival);
1173  }
1174 
1175  return nai;
1176 }
1177 
1178 
1192 NUMA *
1194  l_int32 nsamp)
1195 {
1196 l_int32 n, i, j, ileft, iright;
1197 l_float32 left, right, binsize, lfract, rfract, sum, startx, delx;
1198 l_float32 *array;
1199 NUMA *nad;
1200 
1201  PROCNAME("numaUniformSampling");
1202 
1203  if (!nas)
1204  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1205  if (nsamp <= 0)
1206  return (NUMA *)ERROR_PTR("nsamp must be > 0", procName, NULL);
1207 
1208  n = numaGetCount(nas);
1209  nad = numaCreate(nsamp);
1210  array = numaGetFArray(nas, L_NOCOPY);
1211  binsize = (l_float32)n / (l_float32)nsamp;
1212  numaGetParameters(nas, &startx, &delx);
1213  numaSetParameters(nad, startx, binsize * delx);
1214  left = 0.0;
1215  for (i = 0; i < nsamp; i++) {
1216  sum = 0.0;
1217  right = left + binsize;
1218  ileft = (l_int32)left;
1219  lfract = 1.0 - left + ileft;
1220  if (lfract >= 1.0) /* on left bin boundary */
1221  lfract = 0.0;
1222  iright = (l_int32)right;
1223  rfract = right - iright;
1224  iright = L_MIN(iright, n - 1);
1225  if (ileft == iright) { /* both are within the same original sample */
1226  sum += (lfract + rfract - 1.0) * array[ileft];
1227  } else {
1228  if (lfract > 0.0001) /* left fraction */
1229  sum += lfract * array[ileft];
1230  if (rfract > 0.0001) /* right fraction */
1231  sum += rfract * array[iright];
1232  for (j = ileft + 1; j < iright; j++) /* entire pixels */
1233  sum += array[j];
1234  }
1235 
1236  numaAddNumber(nad, sum);
1237  left = right;
1238  }
1239  return nad;
1240 }
1241 
1242 
1257 NUMA *
1259  NUMA *nas)
1260 {
1261 l_int32 n, i;
1262 l_float32 val1, val2;
1263 
1264  PROCNAME("numaReverse");
1265 
1266  if (!nas)
1267  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1268  if (nad && nas != nad)
1269  return (NUMA *)ERROR_PTR("nad defined but != nas", procName, NULL);
1270 
1271  n = numaGetCount(nas);
1272  if (nad) { /* in-place */
1273  for (i = 0; i < n / 2; i++) {
1274  numaGetFValue(nad, i, &val1);
1275  numaGetFValue(nad, n - i - 1, &val2);
1276  numaSetValue(nad, i, val2);
1277  numaSetValue(nad, n - i - 1, val1);
1278  }
1279  } else {
1280  nad = numaCreate(n);
1281  for (i = n - 1; i >= 0; i--) {
1282  numaGetFValue(nas, i, &val1);
1283  numaAddNumber(nad, val1);
1284  }
1285  }
1286 
1287  /* Reverse the startx and delx fields */
1288  nad->startx = nas->startx + (n - 1) * nas->delx;
1289  nad->delx = -nas->delx;
1290  return nad;
1291 }
1292 
1293 
1294 /*----------------------------------------------------------------------*
1295  * Signal feature extraction *
1296  *----------------------------------------------------------------------*/
1312 NUMA *
1314  l_float32 thresh,
1315  l_float32 maxn)
1316 {
1317 l_int32 n, i, inrun;
1318 l_float32 maxval, threshval, fval, startx, delx, x0, x1;
1319 NUMA *nad;
1320 
1321  PROCNAME("numaLowPassIntervals");
1322 
1323  if (!nas)
1324  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1325  if (thresh < 0.0 || thresh > 1.0)
1326  return (NUMA *)ERROR_PTR("invalid thresh", procName, NULL);
1327 
1328  /* The input threshold is a fraction of the max.
1329  * The first entry in nad is the value of the max. */
1330  n = numaGetCount(nas);
1331  if (maxn == 0.0)
1332  numaGetMax(nas, &maxval, NULL);
1333  else
1334  maxval = maxn;
1335  numaGetParameters(nas, &startx, &delx);
1336  threshval = thresh * maxval;
1337  nad = numaCreate(0);
1338  numaAddNumber(nad, maxval);
1339 
1340  /* Write pairs of pts (x0, x1) for the intervals */
1341  inrun = FALSE;
1342  for (i = 0; i < n; i++) {
1343  numaGetFValue(nas, i, &fval);
1344  if (fval < threshval && inrun == FALSE) { /* start a new run */
1345  inrun = TRUE;
1346  x0 = startx + i * delx;
1347  } else if (fval > threshval && inrun == TRUE) { /* end the run */
1348  inrun = FALSE;
1349  x1 = startx + i * delx;
1350  numaAddNumber(nad, x0);
1351  numaAddNumber(nad, x1);
1352  }
1353  }
1354  if (inrun == TRUE) { /* must end the last run */
1355  x1 = startx + (n - 1) * delx;
1356  numaAddNumber(nad, x0);
1357  numaAddNumber(nad, x1);
1358  }
1359 
1360  return nad;
1361 }
1362 
1363 
1388 NUMA *
1390  l_float32 thresh1,
1391  l_float32 thresh2,
1392  l_float32 maxn)
1393 {
1394 l_int32 n, i, istart, inband, output, sign;
1395 l_int32 startbelow, below, above, belowlast, abovelast;
1396 l_float32 maxval, threshval1, threshval2, fval, startx, delx, x0, x1;
1397 NUMA *nad;
1398 
1399  PROCNAME("numaThresholdEdges");
1400 
1401  if (!nas)
1402  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1403  if (thresh1 < 0.0 || thresh1 > 1.0 || thresh2 < 0.0 || thresh2 > 1.0)
1404  return (NUMA *)ERROR_PTR("invalid thresholds", procName, NULL);
1405  if (thresh2 < thresh1)
1406  return (NUMA *)ERROR_PTR("thresh2 < thresh1", procName, NULL);
1407 
1408  /* The input thresholds are fractions of the max.
1409  * The first entry in nad is the value of the max used
1410  * here for normalization. */
1411  n = numaGetCount(nas);
1412  if (maxn == 0.0)
1413  numaGetMax(nas, &maxval, NULL);
1414  else
1415  maxval = maxn;
1416  numaGetMax(nas, &maxval, NULL);
1417  numaGetParameters(nas, &startx, &delx);
1418  threshval1 = thresh1 * maxval;
1419  threshval2 = thresh2 * maxval;
1420  nad = numaCreate(0);
1421  numaAddNumber(nad, maxval);
1422 
1423  /* Write triplets of pts (x0, x1, sign) for the edges.
1424  * First make sure we start search from outside the band.
1425  * Only one of {belowlast, abovelast} is true. */
1426  for (i = 0; i < n; i++) {
1427  istart = i;
1428  numaGetFValue(nas, i, &fval);
1429  belowlast = (fval < threshval1) ? TRUE : FALSE;
1430  abovelast = (fval > threshval2) ? TRUE : FALSE;
1431  if (belowlast == TRUE || abovelast == TRUE)
1432  break;
1433  }
1434  if (istart == n) /* no intervals found */
1435  return nad;
1436 
1437  /* x0 and x1 can only be set from outside the edge.
1438  * They are the values just before entering the band,
1439  * and just after entering the band. We can jump through
1440  * the band, in which case they differ by one index in nas. */
1441  inband = FALSE;
1442  startbelow = belowlast; /* one of these is true */
1443  output = FALSE;
1444  x0 = startx + istart * delx;
1445  for (i = istart + 1; i < n; i++) {
1446  numaGetFValue(nas, i, &fval);
1447  below = (fval < threshval1) ? TRUE : FALSE;
1448  above = (fval > threshval2) ? TRUE : FALSE;
1449  if (!inband && belowlast && above) { /* full jump up */
1450  x1 = startx + i * delx;
1451  sign = 1;
1452  startbelow = FALSE; /* for the next transition */
1453  output = TRUE;
1454  } else if (!inband && abovelast && below) { /* full jump down */
1455  x1 = startx + i * delx;
1456  sign = -1;
1457  startbelow = TRUE; /* for the next transition */
1458  output = TRUE;
1459  } else if (inband && startbelow && above) { /* exit rising; success */
1460  x1 = startx + i * delx;
1461  sign = 1;
1462  inband = FALSE;
1463  startbelow = FALSE; /* for the next transition */
1464  output = TRUE;
1465  } else if (inband && !startbelow && below) {
1466  /* exit falling; success */
1467  x1 = startx + i * delx;
1468  sign = -1;
1469  inband = FALSE;
1470  startbelow = TRUE; /* for the next transition */
1471  output = TRUE;
1472  } else if (inband && !startbelow && above) { /* exit rising; failure */
1473  x0 = startx + i * delx;
1474  inband = FALSE;
1475  } else if (inband && startbelow && below) { /* exit falling; failure */
1476  x0 = startx + i * delx;
1477  inband = FALSE;
1478  } else if (!inband && !above && !below) { /* enter */
1479  inband = TRUE;
1480  startbelow = belowlast;
1481  } else if (!inband && (above || below)) { /* outside and remaining */
1482  x0 = startx + i * delx; /* update position */
1483  }
1484  belowlast = below;
1485  abovelast = above;
1486  if (output) { /* we have exited; save new x0 */
1487  numaAddNumber(nad, x0);
1488  numaAddNumber(nad, x1);
1489  numaAddNumber(nad, sign);
1490  output = FALSE;
1491  x0 = startx + i * delx;
1492  }
1493  }
1494 
1495  return nad;
1496 }
1497 
1498 
1508 l_int32
1510  l_int32 span,
1511  l_int32 *pstart,
1512  l_int32 *pend)
1513 {
1514 l_int32 n, nspans;
1515 
1516  PROCNAME("numaGetSpanValues");
1517 
1518  if (!na)
1519  return ERROR_INT("na not defined", procName, 1);
1520  n = numaGetCount(na);
1521  if (n % 2 != 1)
1522  return ERROR_INT("n is not odd", procName, 1);
1523  nspans = n / 2;
1524  if (nspans < 0 || span >= nspans)
1525  return ERROR_INT("invalid span", procName, 1);
1526 
1527  if (pstart) numaGetIValue(na, 2 * span + 1, pstart);
1528  if (pend) numaGetIValue(na, 2 * span + 2, pend);
1529  return 0;
1530 }
1531 
1532 
1544 l_int32
1546  l_int32 edge,
1547  l_int32 *pstart,
1548  l_int32 *pend,
1549  l_int32 *psign)
1550 {
1551 l_int32 n, nedges;
1552 
1553  PROCNAME("numaGetEdgeValues");
1554 
1555  if (!na)
1556  return ERROR_INT("na not defined", procName, 1);
1557  n = numaGetCount(na);
1558  if (n % 3 != 1)
1559  return ERROR_INT("n % 3 is not 1", procName, 1);
1560  nedges = (n - 1) / 3;
1561  if (edge < 0 || edge >= nedges)
1562  return ERROR_INT("invalid edge", procName, 1);
1563 
1564  if (pstart) numaGetIValue(na, 3 * edge + 1, pstart);
1565  if (pend) numaGetIValue(na, 3 * edge + 2, pend);
1566  if (psign) numaGetIValue(na, 3 * edge + 3, psign);
1567  return 0;
1568 }
1569 
1570 
1571 /*----------------------------------------------------------------------*
1572  * Interpolation *
1573  *----------------------------------------------------------------------*/
1601 l_int32
1602 numaInterpolateEqxVal(l_float32 startx,
1603  l_float32 deltax,
1604  NUMA *nay,
1605  l_int32 type,
1606  l_float32 xval,
1607  l_float32 *pyval)
1608 {
1609 l_int32 i, n, i1, i2, i3;
1610 l_float32 x1, x2, x3, fy1, fy2, fy3, d1, d2, d3, del, fi, maxx;
1611 l_float32 *fa;
1612 
1613  PROCNAME("numaInterpolateEqxVal");
1614 
1615  if (!pyval)
1616  return ERROR_INT("&yval not defined", procName, 1);
1617  *pyval = 0.0;
1618  if (!nay)
1619  return ERROR_INT("nay not defined", procName, 1);
1620  if (deltax <= 0.0)
1621  return ERROR_INT("deltax not > 0", procName, 1);
1622  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1623  return ERROR_INT("invalid interp type", procName, 1);
1624  n = numaGetCount(nay);
1625  if (n < 2)
1626  return ERROR_INT("not enough points", procName, 1);
1627  if (type == L_QUADRATIC_INTERP && n == 2) {
1628  type = L_LINEAR_INTERP;
1629  L_WARNING("only 2 points; using linear interp\n", procName);
1630  }
1631  maxx = startx + deltax * (n - 1);
1632  if (xval < startx || xval > maxx)
1633  return ERROR_INT("xval is out of bounds", procName, 1);
1634 
1635  fa = numaGetFArray(nay, L_NOCOPY);
1636  fi = (xval - startx) / deltax;
1637  i = (l_int32)fi;
1638  del = fi - i;
1639  if (del == 0.0) { /* no interpolation required */
1640  *pyval = fa[i];
1641  return 0;
1642  }
1643 
1644  if (type == L_LINEAR_INTERP) {
1645  *pyval = fa[i] + del * (fa[i + 1] - fa[i]);
1646  return 0;
1647  }
1648 
1649  /* Quadratic interpolation */
1650  d1 = d3 = 0.5 / (deltax * deltax);
1651  d2 = -2. * d1;
1652  if (i == 0) {
1653  i1 = i;
1654  i2 = i + 1;
1655  i3 = i + 2;
1656  } else {
1657  i1 = i - 1;
1658  i2 = i;
1659  i3 = i + 1;
1660  }
1661  x1 = startx + i1 * deltax;
1662  x2 = startx + i2 * deltax;
1663  x3 = startx + i3 * deltax;
1664  fy1 = d1 * fa[i1];
1665  fy2 = d2 * fa[i2];
1666  fy3 = d3 * fa[i3];
1667  *pyval = fy1 * (xval - x2) * (xval - x3) +
1668  fy2 * (xval - x1) * (xval - x3) +
1669  fy3 * (xval - x1) * (xval - x2);
1670  return 0;
1671 }
1672 
1673 
1694 l_int32
1696  NUMA *nay,
1697  l_int32 type,
1698  l_float32 xval,
1699  l_float32 *pyval)
1700 {
1701 l_int32 i, im, nx, ny, i1, i2, i3;
1702 l_float32 delu, dell, fract, d1, d2, d3;
1703 l_float32 minx, maxx;
1704 l_float32 *fax, *fay;
1705 
1706  PROCNAME("numaInterpolateArbxVal");
1707 
1708  if (!pyval)
1709  return ERROR_INT("&yval not defined", procName, 1);
1710  *pyval = 0.0;
1711  if (!nax)
1712  return ERROR_INT("nax not defined", procName, 1);
1713  if (!nay)
1714  return ERROR_INT("nay not defined", procName, 1);
1715  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1716  return ERROR_INT("invalid interp type", procName, 1);
1717  ny = numaGetCount(nay);
1718  nx = numaGetCount(nax);
1719  if (nx != ny)
1720  return ERROR_INT("nax and nay not same size arrays", procName, 1);
1721  if (ny < 2)
1722  return ERROR_INT("not enough points", procName, 1);
1723  if (type == L_QUADRATIC_INTERP && ny == 2) {
1724  type = L_LINEAR_INTERP;
1725  L_WARNING("only 2 points; using linear interp\n", procName);
1726  }
1727  numaGetFValue(nax, 0, &minx);
1728  numaGetFValue(nax, nx - 1, &maxx);
1729  if (xval < minx || xval > maxx)
1730  return ERROR_INT("xval is out of bounds", procName, 1);
1731 
1732  fax = numaGetFArray(nax, L_NOCOPY);
1733  fay = numaGetFArray(nay, L_NOCOPY);
1734 
1735  /* Linear search for interval. We are guaranteed
1736  * to either return or break out of the loop.
1737  * In addition, we are assured that fax[i] - fax[im] > 0.0 */
1738  if (xval == fax[0]) {
1739  *pyval = fay[0];
1740  return 0;
1741  }
1742  im = 0;
1743  dell = 0.0;
1744  for (i = 1; i < nx; i++) {
1745  delu = fax[i] - xval;
1746  if (delu >= 0.0) { /* we've passed it */
1747  if (delu == 0.0) {
1748  *pyval = fay[i];
1749  return 0;
1750  }
1751  im = i - 1;
1752  dell = xval - fax[im]; /* >= 0 */
1753  break;
1754  }
1755  }
1756  fract = dell / (fax[i] - fax[im]);
1757 
1758  if (type == L_LINEAR_INTERP) {
1759  *pyval = fay[i] + fract * (fay[i + 1] - fay[i]);
1760  return 0;
1761  }
1762 
1763  /* Quadratic interpolation */
1764  if (im == 0) {
1765  i1 = im;
1766  i2 = im + 1;
1767  i3 = im + 2;
1768  } else {
1769  i1 = im - 1;
1770  i2 = im;
1771  i3 = im + 1;
1772  }
1773  d1 = (fax[i1] - fax[i2]) * (fax[i1] - fax[i3]);
1774  d2 = (fax[i2] - fax[i1]) * (fax[i2] - fax[i3]);
1775  d3 = (fax[i3] - fax[i1]) * (fax[i3] - fax[i2]);
1776  *pyval = fay[i1] * (xval - fax[i2]) * (xval - fax[i3]) / d1 +
1777  fay[i2] * (xval - fax[i1]) * (xval - fax[i3]) / d2 +
1778  fay[i3] * (xval - fax[i1]) * (xval - fax[i2]) / d3;
1779  return 0;
1780 }
1781 
1782 
1811 l_int32
1813  l_float32 deltax,
1814  NUMA *nasy,
1815  l_int32 type,
1816  l_float32 x0,
1817  l_float32 x1,
1818  l_int32 npts,
1819  NUMA **pnax,
1820  NUMA **pnay)
1821 {
1822 l_int32 i, n;
1823 l_float32 x, yval, maxx, delx;
1824 NUMA *nax, *nay;
1825 
1826  PROCNAME("numaInterpolateEqxInterval");
1827 
1828  if (pnax) *pnax = NULL;
1829  if (!pnay)
1830  return ERROR_INT("&nay not defined", procName, 1);
1831  *pnay = NULL;
1832  if (!nasy)
1833  return ERROR_INT("nasy not defined", procName, 1);
1834  if (deltax <= 0.0)
1835  return ERROR_INT("deltax not > 0", procName, 1);
1836  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1837  return ERROR_INT("invalid interp type", procName, 1);
1838  n = numaGetCount(nasy);
1839  if (type == L_QUADRATIC_INTERP && n == 2) {
1840  type = L_LINEAR_INTERP;
1841  L_WARNING("only 2 points; using linear interp\n", procName);
1842  }
1843  maxx = startx + deltax * (n - 1);
1844  if (x0 < startx || x1 > maxx || x1 <= x0)
1845  return ERROR_INT("[x0 ... x1] is not valid", procName, 1);
1846  if (npts < 3)
1847  return ERROR_INT("npts < 3", procName, 1);
1848  delx = (x1 - x0) / (l_float32)(npts - 1); /* delx is for output nay */
1849 
1850  if ((nay = numaCreate(npts)) == NULL)
1851  return ERROR_INT("nay not made", procName, 1);
1852  numaSetParameters(nay, x0, delx);
1853  *pnay = nay;
1854  if (pnax) {
1855  nax = numaCreate(npts);
1856  *pnax = nax;
1857  }
1858 
1859  for (i = 0; i < npts; i++) {
1860  x = x0 + i * delx;
1861  if (pnax)
1862  numaAddNumber(nax, x);
1863  numaInterpolateEqxVal(startx, deltax, nasy, type, x, &yval);
1864  numaAddNumber(nay, yval);
1865  }
1866 
1867  return 0;
1868 }
1869 
1870 
1899 l_int32
1901  NUMA *nay,
1902  l_int32 type,
1903  l_float32 x0,
1904  l_float32 x1,
1905  l_int32 npts,
1906  NUMA **pnadx,
1907  NUMA **pnady)
1908 {
1909 l_int32 i, im, j, nx, ny, i1, i2, i3, sorted;
1910 l_int32 *index;
1911 l_float32 del, xval, yval, excess, fract, minx, maxx, d1, d2, d3;
1912 l_float32 *fax, *fay;
1913 NUMA *nasx, *nasy, *nadx, *nady;
1914 
1915  PROCNAME("numaInterpolateArbxInterval");
1916 
1917  if (pnadx) *pnadx = NULL;
1918  if (!pnady)
1919  return ERROR_INT("&nady not defined", procName, 1);
1920  *pnady = NULL;
1921  if (!nay)
1922  return ERROR_INT("nay not defined", procName, 1);
1923  if (!nax)
1924  return ERROR_INT("nax not defined", procName, 1);
1925  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1926  return ERROR_INT("invalid interp type", procName, 1);
1927  if (x0 > x1)
1928  return ERROR_INT("x0 > x1", procName, 1);
1929  ny = numaGetCount(nay);
1930  nx = numaGetCount(nax);
1931  if (nx != ny)
1932  return ERROR_INT("nax and nay not same size arrays", procName, 1);
1933  if (ny < 2)
1934  return ERROR_INT("not enough points", procName, 1);
1935  if (type == L_QUADRATIC_INTERP && ny == 2) {
1936  type = L_LINEAR_INTERP;
1937  L_WARNING("only 2 points; using linear interp\n", procName);
1938  }
1939  numaGetMin(nax, &minx, NULL);
1940  numaGetMax(nax, &maxx, NULL);
1941  if (x0 < minx || x1 > maxx)
1942  return ERROR_INT("xval is out of bounds", procName, 1);
1943 
1944  /* Make sure that nax is sorted in increasing order */
1945  numaIsSorted(nax, L_SORT_INCREASING, &sorted);
1946  if (!sorted) {
1947  L_WARNING("we are sorting nax in increasing order\n", procName);
1948  numaSortPair(nax, nay, L_SORT_INCREASING, &nasx, &nasy);
1949  } else {
1950  nasx = numaClone(nax);
1951  nasy = numaClone(nay);
1952  }
1953 
1954  fax = numaGetFArray(nasx, L_NOCOPY);
1955  fay = numaGetFArray(nasy, L_NOCOPY);
1956 
1957  /* Get array of indices into fax for interpolated locations */
1958  if ((index = (l_int32 *)LEPT_CALLOC(npts, sizeof(l_int32))) == NULL) {
1959  numaDestroy(&nasx);
1960  numaDestroy(&nasy);
1961  return ERROR_INT("ind not made", procName, 1);
1962  }
1963  del = (x1 - x0) / (npts - 1.0);
1964  for (i = 0, j = 0; j < nx && i < npts; i++) {
1965  xval = x0 + i * del;
1966  while (j < nx - 1 && xval > fax[j])
1967  j++;
1968  if (xval == fax[j])
1969  index[i] = L_MIN(j, nx - 1);
1970  else /* the index of fax[] is just below xval */
1971  index[i] = L_MAX(j - 1, 0);
1972  }
1973 
1974  /* For each point to be interpolated, get the y value */
1975  nady = numaCreate(npts);
1976  *pnady = nady;
1977  if (pnadx) {
1978  nadx = numaCreate(npts);
1979  *pnadx = nadx;
1980  }
1981  for (i = 0; i < npts; i++) {
1982  xval = x0 + i * del;
1983  if (pnadx)
1984  numaAddNumber(nadx, xval);
1985  im = index[i];
1986  excess = xval - fax[im];
1987  if (excess == 0.0) {
1988  numaAddNumber(nady, fay[im]);
1989  continue;
1990  }
1991  fract = excess / (fax[im + 1] - fax[im]);
1992 
1993  if (type == L_LINEAR_INTERP) {
1994  yval = fay[im] + fract * (fay[im + 1] - fay[im]);
1995  numaAddNumber(nady, yval);
1996  continue;
1997  }
1998 
1999  /* Quadratic interpolation */
2000  if (im == 0) {
2001  i1 = im;
2002  i2 = im + 1;
2003  i3 = im + 2;
2004  } else {
2005  i1 = im - 1;
2006  i2 = im;
2007  i3 = im + 1;
2008  }
2009  d1 = (fax[i1] - fax[i2]) * (fax[i1] - fax[i3]);
2010  d2 = (fax[i2] - fax[i1]) * (fax[i2] - fax[i3]);
2011  d3 = (fax[i3] - fax[i1]) * (fax[i3] - fax[i2]);
2012  yval = fay[i1] * (xval - fax[i2]) * (xval - fax[i3]) / d1 +
2013  fay[i2] * (xval - fax[i1]) * (xval - fax[i3]) / d2 +
2014  fay[i3] * (xval - fax[i1]) * (xval - fax[i2]) / d3;
2015  numaAddNumber(nady, yval);
2016  }
2017 
2018  LEPT_FREE(index);
2019  numaDestroy(&nasx);
2020  numaDestroy(&nasy);
2021  return 0;
2022 }
2023 
2024 
2025 /*----------------------------------------------------------------------*
2026  * Functions requiring interpolation *
2027  *----------------------------------------------------------------------*/
2060 l_int32
2062  l_float32 *pmaxval,
2063  NUMA *naloc,
2064  l_float32 *pmaxloc)
2065 {
2066 l_float32 val;
2067 l_float32 smaxval; /* start value of maximum sample, before interpolating */
2068 l_int32 n, imaxloc;
2069 l_float32 x1, x2, x3, y1, y2, y3, c1, c2, c3, a, b, xmax, ymax;
2070 
2071  PROCNAME("numaFitMax");
2072 
2073  if (pmaxval) *pmaxval = 0.0;
2074  if (pmaxloc) *pmaxloc = 0.0;
2075  if (!na)
2076  return ERROR_INT("na not defined", procName, 1);
2077  if (!pmaxval)
2078  return ERROR_INT("&maxval not defined", procName, 1);
2079  if (!pmaxloc)
2080  return ERROR_INT("&maxloc not defined", procName, 1);
2081 
2082  n = numaGetCount(na);
2083  if (naloc) {
2084  if (n != numaGetCount(naloc))
2085  return ERROR_INT("na and naloc of unequal size", procName, 1);
2086  }
2087  numaGetMax(na, &smaxval, &imaxloc);
2088 
2089  /* Simple case: max is at end point */
2090  if (imaxloc == 0 || imaxloc == n - 1) {
2091  *pmaxval = smaxval;
2092  if (naloc) {
2093  numaGetFValue(naloc, imaxloc, &val);
2094  *pmaxloc = val;
2095  } else {
2096  *pmaxloc = imaxloc;
2097  }
2098  return 0;
2099  }
2100 
2101  /* Interior point; use quadratic interpolation */
2102  y2 = smaxval;
2103  numaGetFValue(na, imaxloc - 1, &val);
2104  y1 = val;
2105  numaGetFValue(na, imaxloc + 1, &val);
2106  y3 = val;
2107  if (naloc) {
2108  numaGetFValue(naloc, imaxloc - 1, &val);
2109  x1 = val;
2110  numaGetFValue(naloc, imaxloc, &val);
2111  x2 = val;
2112  numaGetFValue(naloc, imaxloc + 1, &val);
2113  x3 = val;
2114  } else {
2115  x1 = imaxloc - 1;
2116  x2 = imaxloc;
2117  x3 = imaxloc + 1;
2118  }
2119 
2120  /* Can't interpolate; just use the max val in na
2121  * and the corresponding one in naloc */
2122  if (x1 == x2 || x1 == x3 || x2 == x3) {
2123  *pmaxval = y2;
2124  *pmaxloc = x2;
2125  return 0;
2126  }
2127 
2128  /* Use lagrangian interpolation; set dy/dx = 0 */
2129  c1 = y1 / ((x1 - x2) * (x1 - x3));
2130  c2 = y2 / ((x2 - x1) * (x2 - x3));
2131  c3 = y3 / ((x3 - x1) * (x3 - x2));
2132  a = c1 + c2 + c3;
2133  b = c1 * (x2 + x3) + c2 * (x1 + x3) + c3 * (x1 + x2);
2134  xmax = b / (2 * a);
2135  ymax = c1 * (xmax - x2) * (xmax - x3) +
2136  c2 * (xmax - x1) * (xmax - x3) +
2137  c3 * (xmax - x1) * (xmax - x2);
2138  *pmaxval = ymax;
2139  *pmaxloc = xmax;
2140 
2141  return 0;
2142 }
2143 
2144 
2165 l_int32
2167  NUMA *nay,
2168  l_float32 x0,
2169  l_float32 x1,
2170  l_int32 npts,
2171  NUMA **pnadx,
2172  NUMA **pnady)
2173 {
2174 l_int32 i, nx, ny;
2175 l_float32 minx, maxx, der, invdel;
2176 l_float32 *fay;
2177 NUMA *nady, *naiy;
2178 
2179  PROCNAME("numaDifferentiateInterval");
2180 
2181  if (pnadx) *pnadx = NULL;
2182  if (!pnady)
2183  return ERROR_INT("&nady not defined", procName, 1);
2184  *pnady = NULL;
2185  if (!nay)
2186  return ERROR_INT("nay not defined", procName, 1);
2187  if (!nax)
2188  return ERROR_INT("nax not defined", procName, 1);
2189  if (x0 > x1)
2190  return ERROR_INT("x0 > x1", procName, 1);
2191  ny = numaGetCount(nay);
2192  nx = numaGetCount(nax);
2193  if (nx != ny)
2194  return ERROR_INT("nax and nay not same size arrays", procName, 1);
2195  if (ny < 2)
2196  return ERROR_INT("not enough points", procName, 1);
2197  numaGetMin(nax, &minx, NULL);
2198  numaGetMax(nax, &maxx, NULL);
2199  if (x0 < minx || x1 > maxx)
2200  return ERROR_INT("xval is out of bounds", procName, 1);
2201  if (npts < 2)
2202  return ERROR_INT("npts < 2", procName, 1);
2203 
2204  /* Generate interpolated array over specified interval */
2205  if (numaInterpolateArbxInterval(nax, nay, L_LINEAR_INTERP, x0, x1,
2206  npts, pnadx, &naiy))
2207  return ERROR_INT("interpolation failed", procName, 1);
2208 
2209  nady = numaCreate(npts);
2210  *pnady = nady;
2211  invdel = 0.5 * ((l_float32)npts - 1.0) / (x1 - x0);
2212  fay = numaGetFArray(naiy, L_NOCOPY);
2213 
2214  /* Compute and save derivatives */
2215  der = 0.5 * invdel * (fay[1] - fay[0]);
2216  numaAddNumber(nady, der);
2217  for (i = 1; i < npts - 1; i++) {
2218  der = invdel * (fay[i + 1] - fay[i - 1]);
2219  numaAddNumber(nady, der);
2220  }
2221  der = 0.5 * invdel * (fay[npts - 1] - fay[npts - 2]);
2222  numaAddNumber(nady, der);
2223 
2224  numaDestroy(&naiy);
2225  return 0;
2226 }
2227 
2228 
2248 l_int32
2250  NUMA *nay,
2251  l_float32 x0,
2252  l_float32 x1,
2253  l_int32 npts,
2254  l_float32 *psum)
2255 {
2256 l_int32 i, nx, ny;
2257 l_float32 minx, maxx, sum, del;
2258 l_float32 *fay;
2259 NUMA *naiy;
2260 
2261  PROCNAME("numaIntegrateInterval");
2262 
2263  if (!psum)
2264  return ERROR_INT("&sum not defined", procName, 1);
2265  *psum = 0.0;
2266  if (!nay)
2267  return ERROR_INT("nay not defined", procName, 1);
2268  if (!nax)
2269  return ERROR_INT("nax not defined", procName, 1);
2270  if (x0 > x1)
2271  return ERROR_INT("x0 > x1", procName, 1);
2272  if (npts < 2)
2273  return ERROR_INT("npts < 2", procName, 1);
2274  ny = numaGetCount(nay);
2275  nx = numaGetCount(nax);
2276  if (nx != ny)
2277  return ERROR_INT("nax and nay not same size arrays", procName, 1);
2278  if (ny < 2)
2279  return ERROR_INT("not enough points", procName, 1);
2280  numaGetMin(nax, &minx, NULL);
2281  numaGetMax(nax, &maxx, NULL);
2282  if (x0 < minx || x1 > maxx)
2283  return ERROR_INT("xval is out of bounds", procName, 1);
2284 
2285  /* Generate interpolated array over specified interval */
2286  if (numaInterpolateArbxInterval(nax, nay, L_LINEAR_INTERP, x0, x1,
2287  npts, NULL, &naiy))
2288  return ERROR_INT("interpolation failed", procName, 1);
2289 
2290  del = (x1 - x0) / ((l_float32)npts - 1.0);
2291  fay = numaGetFArray(naiy, L_NOCOPY);
2292 
2293  /* Compute integral (simple trapezoid) */
2294  sum = 0.5 * (fay[0] + fay[npts - 1]);
2295  for (i = 1; i < npts - 1; i++)
2296  sum += fay[i];
2297  *psum = del * sum;
2298 
2299  numaDestroy(&naiy);
2300  return 0;
2301 }
2302 
2303 
2304 /*----------------------------------------------------------------------*
2305  * Sorting *
2306  *----------------------------------------------------------------------*/
2353 l_int32
2355  NUMA **pnasort,
2356  NUMA **pnaindex,
2357  NUMA **pnainvert,
2358  l_int32 sortorder,
2359  l_int32 sorttype)
2360 {
2361 NUMA *naindex;
2362 
2363  PROCNAME("numaSortGeneral");
2364 
2365  if (!na)
2366  return ERROR_INT("na not defined", procName, 1);
2367  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2368  return ERROR_INT("invalid sort order", procName, 1);
2369  if (sorttype != L_SHELL_SORT && sorttype != L_BIN_SORT)
2370  return ERROR_INT("invalid sort type", procName, 1);
2371  if (!pnasort && !pnaindex && !pnainvert)
2372  return ERROR_INT("nothing to do", procName, 1);
2373  if (pnasort) *pnasort = NULL;
2374  if (pnaindex) *pnaindex = NULL;
2375  if (pnainvert) *pnainvert = NULL;
2376 
2377  if (sorttype == L_SHELL_SORT)
2378  naindex = numaGetSortIndex(na, sortorder);
2379  else /* sorttype == L_BIN_SORT */
2380  naindex = numaGetBinSortIndex(na, sortorder);
2381 
2382  if (pnasort)
2383  *pnasort = numaSortByIndex(na, naindex);
2384  if (pnainvert)
2385  *pnainvert = numaInvertMap(naindex);
2386  if (pnaindex)
2387  *pnaindex = naindex;
2388  else
2389  numaDestroy(&naindex);
2390  return 0;
2391 }
2392 
2393 
2407 NUMA *
2409  l_int32 sortorder)
2410 {
2411 l_int32 type;
2412 
2413  PROCNAME("numaSortAutoSelect");
2414 
2415  if (!nas)
2416  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2417  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2418  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2419 
2420  type = numaChooseSortType(nas);
2421  if (type == L_SHELL_SORT)
2422  return numaSort(NULL, nas, sortorder);
2423  else if (type == L_BIN_SORT)
2424  return numaBinSort(nas, sortorder);
2425  else
2426  return (NUMA *)ERROR_PTR("invalid sort type", procName, NULL);
2427 }
2428 
2429 
2443 NUMA *
2445  l_int32 sortorder)
2446 {
2447 l_int32 type;
2448 
2449  PROCNAME("numaSortIndexAutoSelect");
2450 
2451  if (!nas)
2452  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2453  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2454  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2455 
2456  type = numaChooseSortType(nas);
2457  if (type == L_SHELL_SORT)
2458  return numaGetSortIndex(nas, sortorder);
2459  else if (type == L_BIN_SORT)
2460  return numaGetBinSortIndex(nas, sortorder);
2461  else
2462  return (NUMA *)ERROR_PTR("invalid sort type", procName, NULL);
2463 }
2464 
2465 
2479 l_int32
2481 {
2482 l_int32 n, type;
2483 l_float32 minval, maxval;
2484 
2485  PROCNAME("numaChooseSortType");
2486 
2487  if (!nas)
2488  return ERROR_INT("nas not defined", procName, UNDEF);
2489 
2490  numaGetMin(nas, &minval, NULL);
2491  n = numaGetCount(nas);
2492 
2493  /* Very small histogram; use shell sort */
2494  if (minval < 0.0 || n < 200) {
2495  L_INFO("Shell sort chosen\n", procName);
2496  return L_SHELL_SORT;
2497  }
2498 
2499  /* Need to compare nlog(n) with maxval. The factor of 0.003
2500  * was determined by comparing times for different histogram
2501  * sizes and maxval. It is very small because binsort is fast
2502  * and shell sort gets slow for large n. */
2503  numaGetMax(nas, &maxval, NULL);
2504  if (n * log((l_float32)n) < 0.003 * maxval) {
2505  type = L_SHELL_SORT;
2506  L_INFO("Shell sort chosen\n", procName);
2507  } else {
2508  type = L_BIN_SORT;
2509  L_INFO("Bin sort chosen\n", procName);
2510  }
2511  return type;
2512 }
2513 
2514 
2530 NUMA *
2532  NUMA *nain,
2533  l_int32 sortorder)
2534 {
2535 l_int32 i, n, gap, j;
2536 l_float32 tmp;
2537 l_float32 *array;
2538 
2539  PROCNAME("numaSort");
2540 
2541  if (!nain)
2542  return (NUMA *)ERROR_PTR("nain not defined", procName, NULL);
2543  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2544  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2545 
2546  /* Make naout if necessary; otherwise do in-place */
2547  if (!naout)
2548  naout = numaCopy(nain);
2549  else if (nain != naout)
2550  return (NUMA *)ERROR_PTR("invalid: not in-place", procName, NULL);
2551  array = naout->array; /* operate directly on the array */
2552  n = numaGetCount(naout);
2553 
2554  /* Shell sort */
2555  for (gap = n/2; gap > 0; gap = gap / 2) {
2556  for (i = gap; i < n; i++) {
2557  for (j = i - gap; j >= 0; j -= gap) {
2558  if ((sortorder == L_SORT_INCREASING &&
2559  array[j] > array[j + gap]) ||
2560  (sortorder == L_SORT_DECREASING &&
2561  array[j] < array[j + gap]))
2562  {
2563  tmp = array[j];
2564  array[j] = array[j + gap];
2565  array[j + gap] = tmp;
2566  }
2567  }
2568  }
2569  }
2570 
2571  return naout;
2572 }
2573 
2574 
2592 NUMA *
2594  l_int32 sortorder)
2595 {
2596 NUMA *nat, *nad;
2597 
2598  PROCNAME("numaBinSort");
2599 
2600  if (!nas)
2601  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2602  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2603  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2604 
2605  nat = numaGetBinSortIndex(nas, sortorder);
2606  nad = numaSortByIndex(nas, nat);
2607  numaDestroy(&nat);
2608  return nad;
2609 }
2610 
2611 
2620 NUMA *
2622  l_int32 sortorder)
2623 {
2624 l_int32 i, n, gap, j;
2625 l_float32 tmp;
2626 l_float32 *array; /* copy of input array */
2627 l_float32 *iarray; /* array of indices */
2628 NUMA *naisort;
2629 
2630  PROCNAME("numaGetSortIndex");
2631 
2632  if (!na)
2633  return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
2634  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2635  return (NUMA *)ERROR_PTR("invalid sortorder", procName, NULL);
2636 
2637  n = numaGetCount(na);
2638  if ((array = numaGetFArray(na, L_COPY)) == NULL)
2639  return (NUMA *)ERROR_PTR("array not made", procName, NULL);
2640  if ((iarray = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL) {
2641  LEPT_FREE(array);
2642  return (NUMA *)ERROR_PTR("iarray not made", procName, NULL);
2643  }
2644  for (i = 0; i < n; i++)
2645  iarray[i] = i;
2646 
2647  /* Shell sort */
2648  for (gap = n/2; gap > 0; gap = gap / 2) {
2649  for (i = gap; i < n; i++) {
2650  for (j = i - gap; j >= 0; j -= gap) {
2651  if ((sortorder == L_SORT_INCREASING &&
2652  array[j] > array[j + gap]) ||
2653  (sortorder == L_SORT_DECREASING &&
2654  array[j] < array[j + gap]))
2655  {
2656  tmp = array[j];
2657  array[j] = array[j + gap];
2658  array[j + gap] = tmp;
2659  tmp = iarray[j];
2660  iarray[j] = iarray[j + gap];
2661  iarray[j + gap] = tmp;
2662  }
2663  }
2664  }
2665  }
2666 
2667  naisort = numaCreate(n);
2668  for (i = 0; i < n; i++)
2669  numaAddNumber(naisort, iarray[i]);
2670 
2671  LEPT_FREE(array);
2672  LEPT_FREE(iarray);
2673  return naisort;
2674 }
2675 
2676 
2696 NUMA *
2698  l_int32 sortorder)
2699 {
2700 l_int32 i, n, isize, ival, imax;
2701 l_float32 size;
2702 NUMA *na, *nai, *nad;
2703 L_PTRA *paindex;
2704 
2705  PROCNAME("numaGetBinSortIndex");
2706 
2707  if (!nas)
2708  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2709  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2710  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2711 
2712  /* Set up a ptra holding numa at indices for which there
2713  * are values in nas. Suppose nas has the value 230 at index
2714  * 7355. A numa holding the index 7355 is created and stored
2715  * at the ptra index 230. If there is another value of 230
2716  * in nas, its index is added to the same numa (at index 230
2717  * in the ptra). When finished, the ptra can be scanned for numa,
2718  * and the original indices in the nas can be read out. In this
2719  * way, the ptra effectively sorts the input numbers in the nas. */
2720  numaGetMax(nas, &size, NULL);
2721  isize = (l_int32)size;
2722  if (isize > 1000000)
2723  L_WARNING("large array: %d elements\n", procName, isize);
2724  paindex = ptraCreate(isize + 1);
2725  n = numaGetCount(nas);
2726  for (i = 0; i < n; i++) {
2727  numaGetIValue(nas, i, &ival);
2728  nai = (NUMA *)ptraGetPtrToItem(paindex, ival);
2729  if (!nai) { /* make it; no shifting will occur */
2730  nai = numaCreate(1);
2731  ptraInsert(paindex, ival, nai, L_MIN_DOWNSHIFT);
2732  }
2733  numaAddNumber(nai, i);
2734  }
2735 
2736  /* Sort by scanning the ptra, extracting numas and pulling
2737  * the (index into nas) numbers out of each numa, taken
2738  * successively in requested order. */
2739  ptraGetMaxIndex(paindex, &imax);
2740  nad = numaCreate(0);
2741  if (sortorder == L_SORT_INCREASING) {
2742  for (i = 0; i <= imax; i++) {
2743  na = (NUMA *)ptraRemove(paindex, i, L_NO_COMPACTION);
2744  if (!na) continue;
2745  numaJoin(nad, na, 0, -1);
2746  numaDestroy(&na);
2747  }
2748  } else { /* L_SORT_DECREASING */
2749  for (i = imax; i >= 0; i--) {
2750  na = (NUMA *)ptraRemoveLast(paindex);
2751  if (!na) break; /* they've all been removed */
2752  numaJoin(nad, na, 0, -1);
2753  numaDestroy(&na);
2754  }
2755  }
2756 
2757  ptraDestroy(&paindex, FALSE, FALSE);
2758  return nad;
2759 }
2760 
2761 
2769 NUMA *
2771  NUMA *naindex)
2772 {
2773 l_int32 i, n, index;
2774 l_float32 val;
2775 NUMA *nad;
2776 
2777  PROCNAME("numaSortByIndex");
2778 
2779  if (!nas)
2780  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2781  if (!naindex)
2782  return (NUMA *)ERROR_PTR("naindex not defined", procName, NULL);
2783 
2784  n = numaGetCount(nas);
2785  nad = numaCreate(n);
2786  for (i = 0; i < n; i++) {
2787  numaGetIValue(naindex, i, &index);
2788  numaGetFValue(nas, index, &val);
2789  numaAddNumber(nad, val);
2790  }
2791 
2792  return nad;
2793 }
2794 
2795 
2811 l_int32
2813  l_int32 sortorder,
2814  l_int32 *psorted)
2815 {
2816 l_int32 i, n;
2817 l_float32 prevval, val;
2818 
2819  PROCNAME("numaIsSorted");
2820 
2821  if (!psorted)
2822  return ERROR_INT("&sorted not defined", procName, 1);
2823  *psorted = FALSE;
2824  if (!nas)
2825  return ERROR_INT("nas not defined", procName, 1);
2826  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2827  return ERROR_INT("invalid sortorder", procName, 1);
2828 
2829  n = numaGetCount(nas);
2830  numaGetFValue(nas, 0, &prevval);
2831  for (i = 1; i < n; i++) {
2832  numaGetFValue(nas, i, &val);
2833  if ((sortorder == L_SORT_INCREASING && val < prevval) ||
2834  (sortorder == L_SORT_DECREASING && val > prevval))
2835  return 0;
2836  }
2837 
2838  *psorted = TRUE;
2839  return 0;
2840 }
2841 
2842 
2858 l_int32
2860  NUMA *nay,
2861  l_int32 sortorder,
2862  NUMA **pnasx,
2863  NUMA **pnasy)
2864 {
2865 l_int32 sorted;
2866 NUMA *naindex;
2867 
2868  PROCNAME("numaSortPair");
2869 
2870  if (pnasx) *pnasx = NULL;
2871  if (pnasy) *pnasy = NULL;
2872  if (!pnasx || !pnasy)
2873  return ERROR_INT("&nasx and/or &nasy not defined", procName, 1);
2874  if (!nax)
2875  return ERROR_INT("nax not defined", procName, 1);
2876  if (!nay)
2877  return ERROR_INT("nay not defined", procName, 1);
2878  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2879  return ERROR_INT("invalid sortorder", procName, 1);
2880 
2881  numaIsSorted(nax, sortorder, &sorted);
2882  if (sorted == TRUE) {
2883  *pnasx = numaCopy(nax);
2884  *pnasy = numaCopy(nay);
2885  } else {
2886  naindex = numaGetSortIndex(nax, sortorder);
2887  *pnasx = numaSortByIndex(nax, naindex);
2888  *pnasy = numaSortByIndex(nay, naindex);
2889  numaDestroy(&naindex);
2890  }
2891 
2892  return 0;
2893 }
2894 
2895 
2909 NUMA *
2911 {
2912 l_int32 i, n, val, error;
2913 l_int32 *test;
2914 NUMA *nad;
2915 
2916  PROCNAME("numaInvertMap");
2917 
2918  if (!nas)
2919  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2920 
2921  n = numaGetCount(nas);
2922  nad = numaMakeConstant(0.0, n);
2923  test = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32));
2924  error = 0;
2925  for (i = 0; i < n; i++) {
2926  numaGetIValue(nas, i, &val);
2927  if (val >= n) {
2928  error = 1;
2929  break;
2930  }
2931  numaReplaceNumber(nad, val, i);
2932  if (test[val] == 0) {
2933  test[val] = 1;
2934  } else {
2935  error = 1;
2936  break;
2937  }
2938  }
2939 
2940  LEPT_FREE(test);
2941  if (error) {
2942  numaDestroy(&nad);
2943  return (NUMA *)ERROR_PTR("nas not invertible", procName, NULL);
2944  }
2945 
2946  return nad;
2947 }
2948 
2949 
2950 /*----------------------------------------------------------------------*
2951  * Random permutation *
2952  *----------------------------------------------------------------------*/
2968 NUMA *
2970  l_int32 seed)
2971 {
2972 l_int32 i, index, temp;
2973 l_int32 *array;
2974 NUMA *na;
2975 
2976  PROCNAME("numaPseudorandomSequence");
2977 
2978  if (size <= 0)
2979  return (NUMA *)ERROR_PTR("size <= 0", procName, NULL);
2980 
2981  if ((array = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32))) == NULL)
2982  return (NUMA *)ERROR_PTR("array not made", procName, NULL);
2983  for (i = 0; i < size; i++)
2984  array[i] = i;
2985  srand(seed);
2986  for (i = size - 1; i > 0; i--) {
2987  index = (l_int32)((i + 1) * ((l_float64)rand() / (l_float64)RAND_MAX));
2988  index = L_MIN(index, i);
2989  temp = array[i];
2990  array[i] = array[index];
2991  array[index] = temp;
2992  }
2993 
2994  na = numaCreateFromIArray(array, size);
2995  LEPT_FREE(array);
2996  return na;
2997 }
2998 
2999 
3007 NUMA *
3009  l_int32 seed)
3010 {
3011 l_int32 i, index, size;
3012 l_float32 val;
3013 NUMA *naindex, *nad;
3014 
3015  PROCNAME("numaRandomPermutation");
3016 
3017  if (!nas)
3018  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
3019 
3020  size = numaGetCount(nas);
3021  naindex = numaPseudorandomSequence(size, seed);
3022  nad = numaCreate(size);
3023  for (i = 0; i < size; i++) {
3024  numaGetIValue(naindex, i, &index);
3025  numaGetFValue(nas, index, &val);
3026  numaAddNumber(nad, val);
3027  }
3028 
3029  numaDestroy(&naindex);
3030  return nad;
3031 }
3032 
3033 
3034 /*----------------------------------------------------------------------*
3035  * Functions requiring sorting *
3036  *----------------------------------------------------------------------*/
3064 l_int32
3066  l_float32 fract,
3067  NUMA *nasort,
3068  l_int32 usebins,
3069  l_float32 *pval)
3070 {
3071 l_int32 n, index;
3072 NUMA *nas;
3073 
3074  PROCNAME("numaGetRankValue");
3075 
3076  if (!pval)
3077  return ERROR_INT("&val not defined", procName, 1);
3078  *pval = 0.0; /* init */
3079  if (!na)
3080  return ERROR_INT("na not defined", procName, 1);
3081  if (fract < 0.0 || fract > 1.0)
3082  return ERROR_INT("fract not in [0.0 ... 1.0]", procName, 1);
3083  n = numaGetCount(na);
3084  if (n == 0)
3085  return ERROR_INT("na empty", procName, 1);
3086 
3087  if (nasort) {
3088  nas = nasort;
3089  } else {
3090  if (usebins == 0)
3091  nas = numaSort(NULL, na, L_SORT_INCREASING);
3092  else
3093  nas = numaBinSort(na, L_SORT_INCREASING);
3094  if (!nas)
3095  return ERROR_INT("nas not made", procName, 1);
3096  }
3097  index = (l_int32)(fract * (l_float32)(n - 1) + 0.5);
3098  numaGetFValue(nas, index, pval);
3099 
3100  if (!nasort) numaDestroy(&nas);
3101  return 0;
3102 }
3103 
3104 
3118 l_int32
3120  l_float32 *pval)
3121 {
3122  PROCNAME("numaGetMedian");
3123 
3124  if (!pval)
3125  return ERROR_INT("&val not defined", procName, 1);
3126  *pval = 0.0; /* init */
3127  if (!na)
3128  return ERROR_INT("na not defined", procName, 1);
3129 
3130  return numaGetRankValue(na, 0.5, NULL, 0, pval);
3131 }
3132 
3133 
3149 l_int32
3151  l_int32 *pval)
3152 {
3153 l_int32 ret;
3154 l_float32 fval;
3155 
3156  PROCNAME("numaGetBinnedMedian");
3157 
3158  if (!pval)
3159  return ERROR_INT("&val not defined", procName, 1);
3160  *pval = 0; /* init */
3161  if (!na)
3162  return ERROR_INT("na not defined", procName, 1);
3163 
3164  ret = numaGetRankValue(na, 0.5, NULL, 1, &fval);
3165  *pval = lept_roundftoi(fval);
3166  return ret;
3167 }
3168 
3169 
3186 l_int32
3188  l_float32 *pval,
3189  l_int32 *pcount)
3190 {
3191 l_int32 i, n, maxcount, prevcount;
3192 l_float32 val, maxval, prevval;
3193 l_float32 *array;
3194 NUMA *nasort;
3195 
3196  PROCNAME("numaGetMode");
3197 
3198  if (pcount) *pcount = 0;
3199  if (!pval)
3200  return ERROR_INT("&val not defined", procName, 1);
3201  *pval = 0.0;
3202  if (!na)
3203  return ERROR_INT("na not defined", procName, 1);
3204  if ((n = numaGetCount(na)) == 0)
3205  return 1;
3206 
3207  if ((nasort = numaSort(NULL, na, L_SORT_DECREASING)) == NULL)
3208  return ERROR_INT("nas not made", procName, 1);
3209  array = numaGetFArray(nasort, L_NOCOPY);
3210 
3211  /* Initialize with array[0] */
3212  prevval = array[0];
3213  prevcount = 1;
3214  maxval = prevval;
3215  maxcount = prevcount;
3216 
3217  /* Scan the sorted array, aggregating duplicates */
3218  for (i = 1; i < n; i++) {
3219  val = array[i];
3220  if (val == prevval) {
3221  prevcount++;
3222  } else { /* new value */
3223  if (prevcount > maxcount) { /* new max */
3224  maxcount = prevcount;
3225  maxval = prevval;
3226  }
3227  prevval = val;
3228  prevcount = 1;
3229  }
3230  }
3231 
3232  /* Was the mode the last run of elements? */
3233  if (prevcount > maxcount) {
3234  maxcount = prevcount;
3235  maxval = prevval;
3236  }
3237 
3238  *pval = maxval;
3239  if (pcount)
3240  *pcount = maxcount;
3241 
3242  numaDestroy(&nasort);
3243  return 0;
3244 }
3245 
3246 
3265 l_int32
3267  l_float32 *pmedval,
3268  l_float32 *pmedvar)
3269 {
3270 l_int32 n, i;
3271 l_float32 val, medval;
3272 NUMA *navar;
3273 
3274  PROCNAME("numaGetMedianVar");
3275 
3276  if (pmedval) *pmedval = 0.0;
3277  if (!pmedvar)
3278  return ERROR_INT("&medvar not defined", procName, 1);
3279  *pmedvar = 0.0;
3280  if (!na)
3281  return ERROR_INT("na not defined", procName, 1);
3282 
3283  numaGetMedian(na, &medval);
3284  if (pmedval) *pmedval = medval;
3285  n = numaGetCount(na);
3286  navar = numaCreate(n);
3287  for (i = 0; i < n; i++) {
3288  numaGetFValue(na, i, &val);
3289  numaAddNumber(navar, L_ABS(val - medval));
3290  }
3291  numaGetMedian(navar, pmedvar);
3292 
3293  numaDestroy(&navar);
3294  return 0;
3295 }
3296 
3297 
3298 
3299 /*----------------------------------------------------------------------*
3300  * Rearrangements *
3301  *----------------------------------------------------------------------*/
3318 l_int32
3320  NUMA *nas,
3321  l_int32 istart,
3322  l_int32 iend)
3323 {
3324 l_int32 n, i;
3325 l_float32 val;
3326 
3327  PROCNAME("numaJoin");
3328 
3329  if (!nad)
3330  return ERROR_INT("nad not defined", procName, 1);
3331  if (!nas)
3332  return 0;
3333 
3334  if (istart < 0)
3335  istart = 0;
3336  n = numaGetCount(nas);
3337  if (iend < 0 || iend >= n)
3338  iend = n - 1;
3339  if (istart > iend)
3340  return ERROR_INT("istart > iend; nothing to add", procName, 1);
3341 
3342  for (i = istart; i <= iend; i++) {
3343  numaGetFValue(nas, i, &val);
3344  numaAddNumber(nad, val);
3345  }
3346 
3347  return 0;
3348 }
3349 
3350 
3367 l_int32
3369  NUMAA *naas,
3370  l_int32 istart,
3371  l_int32 iend)
3372 {
3373 l_int32 n, i;
3374 NUMA *na;
3375 
3376  PROCNAME("numaaJoin");
3377 
3378  if (!naad)
3379  return ERROR_INT("naad not defined", procName, 1);
3380  if (!naas)
3381  return 0;
3382 
3383  if (istart < 0)
3384  istart = 0;
3385  n = numaaGetCount(naas);
3386  if (iend < 0 || iend >= n)
3387  iend = n - 1;
3388  if (istart > iend)
3389  return ERROR_INT("istart > iend; nothing to add", procName, 1);
3390 
3391  for (i = istart; i <= iend; i++) {
3392  na = numaaGetNuma(naas, i, L_CLONE);
3393  numaaAddNuma(naad, na, L_INSERT);
3394  }
3395 
3396  return 0;
3397 }
3398 
3399 
3415 NUMA *
3417 {
3418 l_int32 i, nalloc;
3419 NUMA *na, *nad;
3420 NUMA **array;
3421 
3422  PROCNAME("numaaFlattenToNuma");
3423 
3424  if (!naa)
3425  return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
3426 
3427  nalloc = naa->nalloc;
3428  array = numaaGetPtrArray(naa);
3429  nad = numaCreate(0);
3430  for (i = 0; i < nalloc; i++) {
3431  na = array[i];
3432  if (!na) continue;
3433  numaJoin(nad, na, 0, -1);
3434  }
3435 
3436  return nad;
3437 }
3438 
l_int32 numaCountNonzeroRuns(NUMA *na, l_int32 *pcount)
numaCountNonzeroRuns()
Definition: numafunc1.c:951
NUMA * numaInvertMap(NUMA *nas)
numaInvertMap()
Definition: numafunc1.c:2910
NUMA * numaBinSort(NUMA *nas, l_int32 sortorder)
numaBinSort()
Definition: numafunc1.c:2593
l_int32 numaGetNonzeroRange(NUMA *na, l_float32 eps, l_int32 *pfirst, l_int32 *plast)
numaGetNonzeroRange()
Definition: numafunc1.c:990
void * ptraGetPtrToItem(L_PTRA *pa, l_int32 index)
ptraGetPtrToItem()
Definition: ptra.c:759
l_int32 numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:472
NUMA * numaLowPassIntervals(NUMA *nas, l_float32 thresh, l_float32 maxn)
numaLowPassIntervals()
Definition: numafunc1.c:1313
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2621
NUMA * numaSortAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortAutoSelect()
Definition: numafunc1.c:2408
l_int32 numaGetSumOnInterval(NUMA *na, l_int32 first, l_int32 last, l_float32 *psum)
numaGetSumOnInterval()
Definition: numafunc1.c:586
l_int32 lept_roundftoi(l_float32 fval)
lept_roundftoi()
Definition: utils1.c:537
NUMA * numaReverse(NUMA *nad, NUMA *nas)
numaReverse()
Definition: numafunc1.c:1258
NUMA ** numaaGetPtrArray(NUMAA *naa)
numaaGetPtrArray()
Definition: numabasic.c:1604
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2770
l_int32 ptraGetMaxIndex(L_PTRA *pa, l_int32 *pmaxindex)
ptraGetMaxIndex()
Definition: ptra.c:699
l_int32 numaHasOnlyIntegers(NUMA *na, l_int32 maxsamples, l_int32 *pallints)
numaHasOnlyIntegers()
Definition: numafunc1.c:632
NUMA * numaRandomPermutation(NUMA *nas, l_int32 seed)
numaRandomPermutation()
Definition: numafunc1.c:3008
NUMA * numaaFlattenToNuma(NUMAA *naa)
numaaFlattenToNuma()
Definition: numafunc1.c:3416
NUMA * numaGetBinSortIndex(NUMA *nas, l_int32 sortorder)
numaGetBinSortIndex()
Definition: numafunc1.c:2697
Definition: pix.h:704
l_int32 numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:473
l_int32 numaIsSorted(NUMA *nas, l_int32 sortorder, l_int32 *psorted)
numaIsSorted()
Definition: numafunc1.c:2812
l_int32 nalloc
Definition: array.h:73
l_int32 numaFitMax(NUMA *na, l_float32 *pmaxval, NUMA *naloc, l_float32 *pmaxloc)
numaFitMax()
Definition: numafunc1.c:2061
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:768
l_float32 startx
Definition: array.h:64
NUMA * numaSort(NUMA *naout, NUMA *nain, l_int32 sortorder)
numaSort()
Definition: numafunc1.c:2531
l_int32 numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:691
l_int32 numaChooseSortType(NUMA *nas)
numaChooseSortType()
Definition: numafunc1.c:2480
l_int32 numaGetCountRelativeToZero(NUMA *na, l_int32 type, l_int32 *pcount)
numaGetCountRelativeToZero()
Definition: numafunc1.c:1041
l_int32 numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3319
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:186
l_float32 delx
Definition: array.h:65
l_int32 numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:514
NUMA * numaThresholdEdges(NUMA *nas, l_float32 thresh1, l_float32 thresh2, l_float32 maxn)
numaThresholdEdges()
Definition: numafunc1.c:1389
void * ptraRemoveLast(L_PTRA *pa)
ptraRemoveLast()
Definition: ptra.c:483
l_int32 numaGetSpanValues(NUMA *na, l_int32 span, l_int32 *pstart, l_int32 *pend)
numaGetSpanValues()
Definition: numafunc1.c:1509
NUMA * numaClipToInterval(NUMA *nas, l_int32 first, l_int32 last)
numaClipToInterval()
Definition: numafunc1.c:1089
l_int32 numaGetParameters(NUMA *na, l_float32 *pstartx, l_float32 *pdelx)
numaGetParameters()
Definition: numabasic.c:935
NUMA * numaGetPartialSums(NUMA *na)
numaGetPartialSums()
Definition: numafunc1.c:553
NUMA * numaSubsample(NUMA *nas, l_int32 subfactor)
numaSubsample()
Definition: numafunc1.c:673
NUMA * numaRemoveBorder(NUMA *nas, l_int32 left, l_int32 right)
numaRemoveBorder()
Definition: numafunc1.c:910
l_int32 numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1448
l_int32 numaGetBinnedMedian(NUMA *na, l_int32 *pval)
numaGetBinnedMedian()
Definition: numafunc1.c:3150
NUMA * numaUniformSampling(NUMA *nas, l_int32 nsamp)
numaUniformSampling()
Definition: numafunc1.c:1193
NUMA * numaArithOp(NUMA *nad, NUMA *na1, NUMA *na2, l_int32 op)
numaArithOp()
Definition: numafunc1.c:153
NUMA * numaMakeAbsValue(NUMA *nad, NUMA *nas)
numaMakeAbsValue()
Definition: numafunc1.c:784
l_int32 numaInterpolateEqxVal(l_float32 startx, l_float32 deltax, NUMA *nay, l_int32 type, l_float32 xval, l_float32 *pyval)
numaInterpolateEqxVal()
Definition: numafunc1.c:1602
NUMA * numaPseudorandomSequence(l_int32 size, l_int32 seed)
numaPseudorandomSequence()
Definition: numafunc1.c:2969
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1625
NUMA * numaMakeDelta(NUMA *nas)
numaMakeDelta()
Definition: numafunc1.c:707
Definition: array.h:59
static const l_int32 L_INSERT
Definition: pix.h:710
L_PTRA * ptraCreate(l_int32 n)
ptraCreate()
Definition: ptra.c:139
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_int32 numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3065
l_int32 numaInterpolateArbxVal(NUMA *nax, NUMA *nay, l_int32 type, l_float32 xval, l_float32 *pyval)
numaInterpolateArbxVal()
Definition: numafunc1.c:1695
l_float32 * array
Definition: array.h:66
Definition: ptra.h:51
NUMA * numaMakeThresholdIndicator(NUMA *nas, l_float32 thresh, l_int32 type)
numaMakeThresholdIndicator()
Definition: numafunc1.c:1137
l_int32 numaGetEdgeValues(NUMA *na, l_int32 edge, l_int32 *pstart, l_int32 *pend, l_int32 *psign)
numaGetEdgeValues()
Definition: numafunc1.c:1545
NUMA * numaAddSpecifiedBorder(NUMA *nas, l_int32 left, l_int32 right, l_int32 type)
numaAddSpecifiedBorder()
Definition: numafunc1.c:860
l_int32 numaGetMedianVariation(NUMA *na, l_float32 *pmedval, l_float32 *pmedvar)
numaGetMedianVariation()
Definition: numafunc1.c:3266
l_int32 numaaJoin(NUMAA *naad, NUMAA *naas, l_int32 istart, l_int32 iend)
numaaJoin()
Definition: numafunc1.c:3368
Definition: array.h:71
NUMA * numaCreateFromIArray(l_int32 *iarray, l_int32 size)
numaCreateFromIArray()
Definition: numabasic.c:227
NUMA * numaMakeSequence(l_float32 startval, l_float32 increment, l_int32 size)
numaMakeSequence()
Definition: numafunc1.c:737
l_int32 numaSetParameters(NUMA *na, l_float32 startx, l_float32 delx)
numaSetParameters()
Definition: numabasic.c:965
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:393
l_int32 numaAddToNumber(NUMA *na, l_int32 index, l_float32 val)
numaAddToNumber()
Definition: numafunc1.c:400
NUMA * numaAddBorder(NUMA *nas, l_int32 left, l_int32 right, l_float32 val)
numaAddBorder()
Definition: numafunc1.c:818
l_int32 numaInterpolateEqxInterval(l_float32 startx, l_float32 deltax, NUMA *nasy, l_int32 type, l_float32 x0, l_float32 x1, l_int32 npts, NUMA **pnax, NUMA **pnay)
numaInterpolateEqxInterval()
Definition: numafunc1.c:1812
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:359
l_int32 ptraInsert(L_PTRA *pa, l_int32 index, void *item, l_int32 shiftflag)
ptraInsert()
Definition: ptra.c:336
void ptraDestroy(L_PTRA **ppa, l_int32 freeflag, l_int32 warnflag)
ptraDestroy()
Definition: ptra.c:185
l_int32 numaReplaceNumber(NUMA *na, l_int32 index, l_float32 val)
numaReplaceNumber()
Definition: numabasic.c:601
l_int32 numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
Definition: numafunc1.c:431
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:864
l_int32 numaSortGeneral(NUMA *na, NUMA **pnasort, NUMA **pnaindex, NUMA **pnainvert, l_int32 sortorder, l_int32 sorttype)
numaSortGeneral()
Definition: numafunc1.c:2354
l_int32 numaIntegrateInterval(NUMA *nax, NUMA *nay, l_float32 x0, l_float32 x1, l_int32 npts, l_float32 *psum)
numaIntegrateInterval()
Definition: numafunc1.c:2249
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1516
Definition: pix.h:705
void * ptraRemove(L_PTRA *pa, l_int32 index, l_int32 flag)
ptraRemove()
Definition: ptra.c:434
NUMA * numaLogicalOp(NUMA *nad, NUMA *na1, NUMA *na2, l_int32 op)
numaLogicalOp()
Definition: numafunc1.c:233
l_int32 numaDifferentiateInterval(NUMA *nax, NUMA *nay, l_float32 x0, l_float32 x1, l_int32 npts, NUMA **pnadx, NUMA **pnady)
numaDifferentiateInterval()
Definition: numafunc1.c:2166
NUMA * numaSortIndexAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortIndexAutoSelect()
Definition: numafunc1.c:2444
l_int32 numaInterpolateArbxInterval(NUMA *nax, NUMA *nay, l_int32 type, l_float32 x0, l_float32 x1, l_int32 npts, NUMA **pnadx, NUMA **pnady)
numaInterpolateArbxInterval()
Definition: numafunc1.c:1900
l_int32 numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:758
Definition: pix.h:706
l_int32 numaGetMode(NUMA *na, l_float32 *pval, l_int32 *pcount)
numaGetMode()
Definition: numafunc1.c:3187
NUMA * numaClone(NUMA *na)
numaClone()
Definition: numabasic.c:422
l_int32 numaGetMedian(NUMA *na, l_float32 *pval)
numaGetMedian()
Definition: numafunc1.c:3119
l_int32 numaSimilar(NUMA *na1, NUMA *na2, l_float32 maxdiff, l_int32 *psimilar)
numaSimilar()
Definition: numafunc1.c:351
l_int32 numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:726
NUMA * numaInvert(NUMA *nad, NUMA *nas)
numaInvert()
Definition: numafunc1.c:306
l_int32 numaSortPair(NUMA *nax, NUMA *nay, l_int32 sortorder, NUMA **pnasx, NUMA **pnasy)
numaSortPair()
Definition: numafunc1.c:2859