Leptonica  1.77.0
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 
140 #include <math.h>
141 #include "allheaders.h"
142 
143 
144 /*----------------------------------------------------------------------*
145  * Arithmetic and logical ops on Numas *
146  *----------------------------------------------------------------------*/
165 NUMA *
167  NUMA *na1,
168  NUMA *na2,
169  l_int32 op)
170 {
171 l_int32 i, n;
172 l_float32 val1, val2;
173 
174  PROCNAME("numaArithOp");
175 
176  if (!na1 || !na2)
177  return (NUMA *)ERROR_PTR("na1, na2 not both defined", procName, nad);
178  n = numaGetCount(na1);
179  if (n != numaGetCount(na2))
180  return (NUMA *)ERROR_PTR("na1, na2 sizes differ", procName, nad);
181  if (nad && nad != na1)
182  return (NUMA *)ERROR_PTR("nad defined but not in-place", procName, nad);
183  if (op != L_ARITH_ADD && op != L_ARITH_SUBTRACT &&
184  op != L_ARITH_MULTIPLY && op != L_ARITH_DIVIDE)
185  return (NUMA *)ERROR_PTR("invalid op", procName, nad);
186  if (op == L_ARITH_DIVIDE) {
187  for (i = 0; i < n; i++) {
188  numaGetFValue(na2, i, &val2);
189  if (val2 == 0.0)
190  return (NUMA *)ERROR_PTR("na2 has 0 element", procName, nad);
191  }
192  }
193 
194  /* If nad is not identical to na1, make it an identical copy */
195  if (!nad)
196  nad = numaCopy(na1);
197 
198  for (i = 0; i < n; i++) {
199  numaGetFValue(nad, i, &val1);
200  numaGetFValue(na2, i, &val2);
201  switch (op) {
202  case L_ARITH_ADD:
203  numaSetValue(nad, i, val1 + val2);
204  break;
205  case L_ARITH_SUBTRACT:
206  numaSetValue(nad, i, val1 - val2);
207  break;
208  case L_ARITH_MULTIPLY:
209  numaSetValue(nad, i, val1 * val2);
210  break;
211  case L_ARITH_DIVIDE:
212  numaSetValue(nad, i, val1 / val2);
213  break;
214  default:
215  fprintf(stderr, " Unknown arith op: %d\n", op);
216  return nad;
217  }
218  }
219 
220  return nad;
221 }
222 
223 
245 NUMA *
247  NUMA *na1,
248  NUMA *na2,
249  l_int32 op)
250 {
251 l_int32 i, n, val1, val2, val;
252 
253  PROCNAME("numaLogicalOp");
254 
255  if (!na1 || !na2)
256  return (NUMA *)ERROR_PTR("na1, na2 not both defined", procName, nad);
257  n = numaGetCount(na1);
258  if (n != numaGetCount(na2))
259  return (NUMA *)ERROR_PTR("na1, na2 sizes differ", procName, nad);
260  if (nad && nad != na1)
261  return (NUMA *)ERROR_PTR("nad defined; not in-place", procName, nad);
262  if (op != L_UNION && op != L_INTERSECTION &&
263  op != L_SUBTRACTION && op != L_EXCLUSIVE_OR)
264  return (NUMA *)ERROR_PTR("invalid op", procName, nad);
265 
266  /* If nad is not identical to na1, make it an identical copy */
267  if (!nad)
268  nad = numaCopy(na1);
269 
270  for (i = 0; i < n; i++) {
271  numaGetIValue(nad, i, &val1);
272  numaGetIValue(na2, i, &val2);
273  val1 = (val1 == 0) ? 0 : 1;
274  val2 = (val2 == 0) ? 0 : 1;
275  switch (op) {
276  case L_UNION:
277  val = (val1 || val2) ? 1 : 0;
278  numaSetValue(nad, i, val);
279  break;
280  case L_INTERSECTION:
281  val = (val1 && val2) ? 1 : 0;
282  numaSetValue(nad, i, val);
283  break;
284  case L_SUBTRACTION:
285  val = (val1 && !val2) ? 1 : 0;
286  numaSetValue(nad, i, val);
287  break;
288  case L_EXCLUSIVE_OR:
289  val = (val1 != val2) ? 1 : 0;
290  numaSetValue(nad, i, val);
291  break;
292  default:
293  fprintf(stderr, " Unknown logical op: %d\n", op);
294  return nad;
295  }
296  }
297 
298  return nad;
299 }
300 
301 
318 NUMA *
320  NUMA *nas)
321 {
322 l_int32 i, n, val;
323 
324  PROCNAME("numaInvert");
325 
326  if (!nas)
327  return (NUMA *)ERROR_PTR("nas not defined", procName, nad);
328  if (nad && nad != nas)
329  return (NUMA *)ERROR_PTR("nad defined; not in-place", procName, nad);
330 
331  if (!nad)
332  nad = numaCopy(nas);
333  n = numaGetCount(nad);
334  for (i = 0; i < n; i++) {
335  numaGetIValue(nad, i, &val);
336  if (!val)
337  val = 1;
338  else
339  val = 0;
340  numaSetValue(nad, i, val);
341  }
342 
343  return nad;
344 }
345 
346 
363 l_int32
365  NUMA *na2,
366  l_float32 maxdiff,
367  l_int32 *psimilar)
368 {
369 l_int32 i, n;
370 l_float32 val1, val2;
371 
372  PROCNAME("numaSimilar");
373 
374  if (!psimilar)
375  return ERROR_INT("&similar not defined", procName, 1);
376  *psimilar = 0;
377  if (!na1 || !na2)
378  return ERROR_INT("na1 and na2 not both defined", procName, 1);
379  maxdiff = L_ABS(maxdiff);
380 
381  n = numaGetCount(na1);
382  if (n != numaGetCount(na2)) return 0;
383 
384  for (i = 0; i < n; i++) {
385  numaGetFValue(na1, i, &val1);
386  numaGetFValue(na2, i, &val2);
387  if (L_ABS(val1 - val2) > maxdiff) return 0;
388  }
389 
390  *psimilar = 1;
391  return 0;
392 }
393 
394 
412 l_ok
414  l_int32 index,
415  l_float32 val)
416 {
417 l_int32 n;
418 
419  PROCNAME("numaAddToNumber");
420 
421  if (!na)
422  return ERROR_INT("na not defined", procName, 1);
423  n = numaGetCount(na);
424  if (index < 0 || index >= n)
425  return ERROR_INT("index not in {0...n - 1}", procName, 1);
426 
427  na->array[index] += val;
428  return 0;
429 }
430 
431 
432 /*----------------------------------------------------------------------*
433  * Simple extractions *
434  *----------------------------------------------------------------------*/
443 l_ok
445  l_float32 *pminval,
446  l_int32 *piminloc)
447 {
448 l_int32 i, n, iminloc;
449 l_float32 val, minval;
450 
451  PROCNAME("numaGetMin");
452 
453  if (!pminval && !piminloc)
454  return ERROR_INT("nothing to do", procName, 1);
455  if (pminval) *pminval = 0.0;
456  if (piminloc) *piminloc = 0;
457  if (!na)
458  return ERROR_INT("na not defined", procName, 1);
459 
460  minval = +1000000000.;
461  iminloc = 0;
462  n = numaGetCount(na);
463  for (i = 0; i < n; i++) {
464  numaGetFValue(na, i, &val);
465  if (val < minval) {
466  minval = val;
467  iminloc = i;
468  }
469  }
470 
471  if (pminval) *pminval = minval;
472  if (piminloc) *piminloc = iminloc;
473  return 0;
474 }
475 
476 
485 l_ok
487  l_float32 *pmaxval,
488  l_int32 *pimaxloc)
489 {
490 l_int32 i, n, imaxloc;
491 l_float32 val, maxval;
492 
493  PROCNAME("numaGetMax");
494 
495  if (!pmaxval && !pimaxloc)
496  return ERROR_INT("nothing to do", procName, 1);
497  if (pmaxval) *pmaxval = 0.0;
498  if (pimaxloc) *pimaxloc = 0;
499  if (!na)
500  return ERROR_INT("na not defined", procName, 1);
501 
502  maxval = -1000000000.;
503  imaxloc = 0;
504  n = numaGetCount(na);
505  for (i = 0; i < n; i++) {
506  numaGetFValue(na, i, &val);
507  if (val > maxval) {
508  maxval = val;
509  imaxloc = i;
510  }
511  }
512 
513  if (pmaxval) *pmaxval = maxval;
514  if (pimaxloc) *pimaxloc = imaxloc;
515  return 0;
516 }
517 
518 
526 l_ok
528  l_float32 *psum)
529 {
530 l_int32 i, n;
531 l_float32 val, sum;
532 
533  PROCNAME("numaGetSum");
534 
535  if (!na)
536  return ERROR_INT("na not defined", procName, 1);
537  if (!psum)
538  return ERROR_INT("&sum not defined", procName, 1);
539 
540  sum = 0.0;
541  n = numaGetCount(na);
542  for (i = 0; i < n; i++) {
543  numaGetFValue(na, i, &val);
544  sum += val;
545  }
546  *psum = sum;
547  return 0;
548 }
549 
550 
565 NUMA *
567 {
568 l_int32 i, n;
569 l_float32 val, sum;
570 NUMA *nasum;
571 
572  PROCNAME("numaGetPartialSums");
573 
574  if (!na)
575  return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
576 
577  n = numaGetCount(na);
578  nasum = numaCreate(n);
579  sum = 0.0;
580  for (i = 0; i < n; i++) {
581  numaGetFValue(na, i, &val);
582  sum += val;
583  numaAddNumber(nasum, sum);
584  }
585  return nasum;
586 }
587 
588 
598 l_ok
600  l_int32 first,
601  l_int32 last,
602  l_float32 *psum)
603 {
604 l_int32 i, n, truelast;
605 l_float32 val, sum;
606 
607  PROCNAME("numaGetSumOnInterval");
608 
609  if (!na)
610  return ERROR_INT("na not defined", procName, 1);
611  if (!psum)
612  return ERROR_INT("&sum not defined", procName, 1);
613  *psum = 0.0;
614 
615  sum = 0.0;
616  n = numaGetCount(na);
617  if (first >= n) /* not an error */
618  return 0;
619  truelast = L_MIN(last, n - 1);
620 
621  for (i = first; i <= truelast; i++) {
622  numaGetFValue(na, i, &val);
623  sum += val;
624  }
625  *psum = sum;
626  return 0;
627 }
628 
629 
644 l_ok
646  l_int32 maxsamples,
647  l_int32 *pallints)
648 {
649 l_int32 i, n, incr;
650 l_float32 val;
651 
652  PROCNAME("numaHasOnlyIntegers");
653 
654  if (!pallints)
655  return ERROR_INT("&allints not defined", procName, 1);
656  *pallints = TRUE;
657  if (!na)
658  return ERROR_INT("na not defined", procName, 1);
659 
660  if ((n = numaGetCount(na)) == 0)
661  return ERROR_INT("na empty", procName, 1);
662  if (maxsamples <= 0)
663  incr = 1;
664  else
665  incr = (l_int32)((n + maxsamples - 1) / maxsamples);
666  for (i = 0; i < n; i += incr) {
667  numaGetFValue(na, i, &val);
668  if (val != (l_int32)val) {
669  *pallints = FALSE;
670  return 0;
671  }
672  }
673 
674  return 0;
675 }
676 
677 
685 NUMA *
687  l_int32 subfactor)
688 {
689 l_int32 i, n;
690 l_float32 val;
691 NUMA *nad;
692 
693  PROCNAME("numaSubsample");
694 
695  if (!nas)
696  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
697  if (subfactor < 1)
698  return (NUMA *)ERROR_PTR("subfactor < 1", procName, NULL);
699 
700  nad = numaCreate(0);
701  n = numaGetCount(nas);
702  for (i = 0; i < n; i++) {
703  if (i % subfactor != 0) continue;
704  numaGetFValue(nas, i, &val);
705  numaAddNumber(nad, val);
706  }
707 
708  return nad;
709 }
710 
711 
719 NUMA *
721 {
722 l_int32 i, n, prev, cur;
723 NUMA *nad;
724 
725  PROCNAME("numaMakeDelta");
726 
727  if (!nas)
728  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
729  n = numaGetCount(nas);
730  nad = numaCreate(n - 1);
731  prev = 0;
732  for (i = 1; i < n; i++) {
733  numaGetIValue(nas, i, &cur);
734  numaAddNumber(nad, cur - prev);
735  prev = cur;
736  }
737  return nad;
738 }
739 
740 
749 NUMA *
750 numaMakeSequence(l_float32 startval,
751  l_float32 increment,
752  l_int32 size)
753 {
754 l_int32 i;
755 l_float32 val;
756 NUMA *na;
757 
758  PROCNAME("numaMakeSequence");
759 
760  if ((na = numaCreate(size)) == NULL)
761  return (NUMA *)ERROR_PTR("na not made", procName, NULL);
762 
763  for (i = 0; i < size; i++) {
764  val = startval + i * increment;
765  numaAddNumber(na, val);
766  }
767 
768  return na;
769 }
770 
771 
780 NUMA *
781 numaMakeConstant(l_float32 val,
782  l_int32 size)
783 {
784  return numaMakeSequence(val, 0.0, size);
785 }
786 
787 
796 NUMA *
798  NUMA *nas)
799 {
800 l_int32 i, n;
801 l_float32 val;
802 
803  PROCNAME("numaMakeAbsValue");
804 
805  if (!nas)
806  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
807  if (nad && nad != nas)
808  return (NUMA *)ERROR_PTR("nad and not in-place", procName, NULL);
809 
810  if (!nad)
811  nad = numaCopy(nas);
812  n = numaGetCount(nad);
813  for (i = 0; i < n; i++) {
814  val = nad->array[i];
815  nad->array[i] = L_ABS(val);
816  }
817 
818  return nad;
819 }
820 
821 
831 NUMA *
833  l_int32 left,
834  l_int32 right,
835  l_float32 val)
836 {
837 l_int32 i, n, len;
838 l_float32 startx, delx;
839 l_float32 *fas, *fad;
840 NUMA *nad;
841 
842  PROCNAME("numaAddBorder");
843 
844  if (!nas)
845  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
846  if (left < 0) left = 0;
847  if (right < 0) right = 0;
848  if (left == 0 && right == 0)
849  return numaCopy(nas);
850 
851  n = numaGetCount(nas);
852  len = n + left + right;
853  nad = numaMakeConstant(val, len);
854  numaGetParameters(nas, &startx, &delx);
855  numaSetParameters(nad, startx - delx * left, delx);
856  fas = numaGetFArray(nas, L_NOCOPY);
857  fad = numaGetFArray(nad, L_NOCOPY);
858  for (i = 0; i < n; i++)
859  fad[left + i] = fas[i];
860 
861  return nad;
862 }
863 
864 
874 NUMA *
876  l_int32 left,
877  l_int32 right,
878  l_int32 type)
879 {
880 l_int32 i, n;
881 l_float32 *fa;
882 NUMA *nad;
883 
884  PROCNAME("numaAddSpecifiedBorder");
885 
886  if (!nas)
887  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
888  if (left < 0) left = 0;
889  if (right < 0) right = 0;
890  if (left == 0 && right == 0)
891  return numaCopy(nas);
892  if (type != L_CONTINUED_BORDER && type != L_MIRRORED_BORDER)
893  return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
894  n = numaGetCount(nas);
895  if (type == L_MIRRORED_BORDER && (left > n || right > n))
896  return (NUMA *)ERROR_PTR("border too large", procName, NULL);
897 
898  nad = numaAddBorder(nas, left, right, 0);
899  n = numaGetCount(nad);
900  fa = numaGetFArray(nad, L_NOCOPY);
901  if (type == L_CONTINUED_BORDER) {
902  for (i = 0; i < left; i++)
903  fa[i] = fa[left];
904  for (i = n - right; i < n; i++)
905  fa[i] = fa[n - right - 1];
906  } else { /* type == L_MIRRORED_BORDER */
907  for (i = 0; i < left; i++)
908  fa[i] = fa[2 * left - 1 - i];
909  for (i = 0; i < right; i++)
910  fa[n - right + i] = fa[n - right - i - 1];
911  }
912 
913  return nad;
914 }
915 
916 
925 NUMA *
927  l_int32 left,
928  l_int32 right)
929 {
930 l_int32 i, n, len;
931 l_float32 startx, delx;
932 l_float32 *fas, *fad;
933 NUMA *nad;
934 
935  PROCNAME("numaRemoveBorder");
936 
937  if (!nas)
938  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
939  if (left < 0) left = 0;
940  if (right < 0) right = 0;
941  if (left == 0 && right == 0)
942  return numaCopy(nas);
943 
944  n = numaGetCount(nas);
945  if ((len = n - left - right) < 0)
946  return (NUMA *)ERROR_PTR("len < 0 after removal", procName, NULL);
947  nad = numaMakeConstant(0, len);
948  numaGetParameters(nas, &startx, &delx);
949  numaSetParameters(nad, startx + delx * left, delx);
950  fas = numaGetFArray(nas, L_NOCOPY);
951  fad = numaGetFArray(nad, L_NOCOPY);
952  for (i = 0; i < len; i++)
953  fad[i] = fas[left + i];
954 
955  return nad;
956 }
957 
958 
966 l_ok
968  l_int32 *pcount)
969 {
970 l_int32 n, i, val, count, inrun;
971 
972  PROCNAME("numaCountNonzeroRuns");
973 
974  if (!pcount)
975  return ERROR_INT("&count not defined", procName, 1);
976  *pcount = 0;
977  if (!na)
978  return ERROR_INT("na not defined", procName, 1);
979  n = numaGetCount(na);
980  count = 0;
981  inrun = FALSE;
982  for (i = 0; i < n; i++) {
983  numaGetIValue(na, i, &val);
984  if (!inrun && val > 0) {
985  count++;
986  inrun = TRUE;
987  } else if (inrun && val == 0) {
988  inrun = FALSE;
989  }
990  }
991  *pcount = count;
992  return 0;
993 }
994 
995 
1005 l_ok
1007  l_float32 eps,
1008  l_int32 *pfirst,
1009  l_int32 *plast)
1010 {
1011 l_int32 n, i, found;
1012 l_float32 val;
1013 
1014  PROCNAME("numaGetNonzeroRange");
1015 
1016  if (pfirst) *pfirst = 0;
1017  if (plast) *plast = 0;
1018  if (!pfirst || !plast)
1019  return ERROR_INT("pfirst and plast not both defined", procName, 1);
1020  if (!na)
1021  return ERROR_INT("na not defined", procName, 1);
1022  n = numaGetCount(na);
1023  found = FALSE;
1024  for (i = 0; i < n; i++) {
1025  numaGetFValue(na, i, &val);
1026  if (val > eps) {
1027  found = TRUE;
1028  break;
1029  }
1030  }
1031  if (!found) {
1032  *pfirst = n - 1;
1033  *plast = 0;
1034  return 1;
1035  }
1036 
1037  *pfirst = i;
1038  for (i = n - 1; i >= 0; i--) {
1039  numaGetFValue(na, i, &val);
1040  if (val > eps)
1041  break;
1042  }
1043  *plast = i;
1044  return 0;
1045 }
1046 
1047 
1056 l_ok
1058  l_int32 type,
1059  l_int32 *pcount)
1060 {
1061 l_int32 n, i, count;
1062 l_float32 val;
1063 
1064  PROCNAME("numaGetCountRelativeToZero");
1065 
1066  if (!pcount)
1067  return ERROR_INT("&count not defined", procName, 1);
1068  *pcount = 0;
1069  if (!na)
1070  return ERROR_INT("na not defined", procName, 1);
1071  n = numaGetCount(na);
1072  for (i = 0, count = 0; i < n; i++) {
1073  numaGetFValue(na, i, &val);
1074  if (type == L_LESS_THAN_ZERO && val < 0.0)
1075  count++;
1076  else if (type == L_EQUAL_TO_ZERO && val == 0.0)
1077  count++;
1078  else if (type == L_GREATER_THAN_ZERO && val > 0.0)
1079  count++;
1080  }
1081 
1082  *pcount = count;
1083  return 0;
1084 }
1085 
1086 
1104 NUMA *
1106  l_int32 first,
1107  l_int32 last)
1108 {
1109 l_int32 n, i, truelast;
1110 l_float32 val, startx, delx;
1111 NUMA *nad;
1112 
1113  PROCNAME("numaClipToInterval");
1114 
1115  if (!nas)
1116  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1117  if (first > last)
1118  return (NUMA *)ERROR_PTR("range not valid", procName, NULL);
1119 
1120  n = numaGetCount(nas);
1121  if (first >= n)
1122  return (NUMA *)ERROR_PTR("no elements in range", procName, NULL);
1123  truelast = L_MIN(last, n - 1);
1124  if ((nad = numaCreate(truelast - first + 1)) == NULL)
1125  return (NUMA *)ERROR_PTR("nad not made", procName, NULL);
1126  for (i = first; i <= truelast; i++) {
1127  numaGetFValue(nas, i, &val);
1128  numaAddNumber(nad, val);
1129  }
1130  numaGetParameters(nas, &startx, &delx);
1131  numaSetParameters(nad, startx + first * delx, delx);
1132  return nad;
1133 }
1134 
1135 
1152 NUMA *
1154  l_float32 thresh,
1155  l_int32 type)
1156 {
1157 l_int32 n, i, ival;
1158 l_float32 fval;
1159 NUMA *nai;
1160 
1161  PROCNAME("numaMakeThresholdIndicator");
1162 
1163  if (!nas)
1164  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1165  n = numaGetCount(nas);
1166  nai = numaCreate(n);
1167  for (i = 0; i < n; i++) {
1168  numaGetFValue(nas, i, &fval);
1169  ival = 0;
1170  switch (type)
1171  {
1172  case L_SELECT_IF_LT:
1173  if (fval < thresh) ival = 1;
1174  break;
1175  case L_SELECT_IF_GT:
1176  if (fval > thresh) ival = 1;
1177  break;
1178  case L_SELECT_IF_LTE:
1179  if (fval <= thresh) ival = 1;
1180  break;
1181  case L_SELECT_IF_GTE:
1182  if (fval >= thresh) ival = 1;
1183  break;
1184  default:
1185  numaDestroy(&nai);
1186  return (NUMA *)ERROR_PTR("invalid type", procName, NULL);
1187  }
1188  numaAddNumber(nai, ival);
1189  }
1190 
1191  return nai;
1192 }
1193 
1194 
1208 NUMA *
1210  l_int32 nsamp)
1211 {
1212 l_int32 n, i, j, ileft, iright;
1213 l_float32 left, right, binsize, lfract, rfract, sum, startx, delx;
1214 l_float32 *array;
1215 NUMA *nad;
1216 
1217  PROCNAME("numaUniformSampling");
1218 
1219  if (!nas)
1220  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1221  if (nsamp <= 0)
1222  return (NUMA *)ERROR_PTR("nsamp must be > 0", procName, NULL);
1223 
1224  n = numaGetCount(nas);
1225  nad = numaCreate(nsamp);
1226  array = numaGetFArray(nas, L_NOCOPY);
1227  binsize = (l_float32)n / (l_float32)nsamp;
1228  numaGetParameters(nas, &startx, &delx);
1229  numaSetParameters(nad, startx, binsize * delx);
1230  left = 0.0;
1231  for (i = 0; i < nsamp; i++) {
1232  sum = 0.0;
1233  right = left + binsize;
1234  ileft = (l_int32)left;
1235  lfract = 1.0 - left + ileft;
1236  if (lfract >= 1.0) /* on left bin boundary */
1237  lfract = 0.0;
1238  iright = (l_int32)right;
1239  rfract = right - iright;
1240  iright = L_MIN(iright, n - 1);
1241  if (ileft == iright) { /* both are within the same original sample */
1242  sum += (lfract + rfract - 1.0) * array[ileft];
1243  } else {
1244  if (lfract > 0.0001) /* left fraction */
1245  sum += lfract * array[ileft];
1246  if (rfract > 0.0001) /* right fraction */
1247  sum += rfract * array[iright];
1248  for (j = ileft + 1; j < iright; j++) /* entire pixels */
1249  sum += array[j];
1250  }
1251 
1252  numaAddNumber(nad, sum);
1253  left = right;
1254  }
1255  return nad;
1256 }
1257 
1258 
1273 NUMA *
1275  NUMA *nas)
1276 {
1277 l_int32 n, i;
1278 l_float32 val1, val2;
1279 
1280  PROCNAME("numaReverse");
1281 
1282  if (!nas)
1283  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1284  if (nad && nas != nad)
1285  return (NUMA *)ERROR_PTR("nad defined but != nas", procName, NULL);
1286 
1287  n = numaGetCount(nas);
1288  if (nad) { /* in-place */
1289  for (i = 0; i < n / 2; i++) {
1290  numaGetFValue(nad, i, &val1);
1291  numaGetFValue(nad, n - i - 1, &val2);
1292  numaSetValue(nad, i, val2);
1293  numaSetValue(nad, n - i - 1, val1);
1294  }
1295  } else {
1296  nad = numaCreate(n);
1297  for (i = n - 1; i >= 0; i--) {
1298  numaGetFValue(nas, i, &val1);
1299  numaAddNumber(nad, val1);
1300  }
1301  }
1302 
1303  /* Reverse the startx and delx fields */
1304  nad->startx = nas->startx + (n - 1) * nas->delx;
1305  nad->delx = -nas->delx;
1306  return nad;
1307 }
1308 
1309 
1310 /*----------------------------------------------------------------------*
1311  * Signal feature extraction *
1312  *----------------------------------------------------------------------*/
1328 NUMA *
1330  l_float32 thresh,
1331  l_float32 maxn)
1332 {
1333 l_int32 n, i, inrun;
1334 l_float32 maxval, threshval, fval, startx, delx, x0, x1;
1335 NUMA *nad;
1336 
1337  PROCNAME("numaLowPassIntervals");
1338 
1339  if (!nas)
1340  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1341  if (thresh < 0.0 || thresh > 1.0)
1342  return (NUMA *)ERROR_PTR("invalid thresh", procName, NULL);
1343 
1344  /* The input threshold is a fraction of the max.
1345  * The first entry in nad is the value of the max. */
1346  n = numaGetCount(nas);
1347  if (maxn == 0.0)
1348  numaGetMax(nas, &maxval, NULL);
1349  else
1350  maxval = maxn;
1351  numaGetParameters(nas, &startx, &delx);
1352  threshval = thresh * maxval;
1353  nad = numaCreate(0);
1354  numaAddNumber(nad, maxval);
1355 
1356  /* Write pairs of pts (x0, x1) for the intervals */
1357  inrun = FALSE;
1358  for (i = 0; i < n; i++) {
1359  numaGetFValue(nas, i, &fval);
1360  if (fval < threshval && inrun == FALSE) { /* start a new run */
1361  inrun = TRUE;
1362  x0 = startx + i * delx;
1363  } else if (fval > threshval && inrun == TRUE) { /* end the run */
1364  inrun = FALSE;
1365  x1 = startx + i * delx;
1366  numaAddNumber(nad, x0);
1367  numaAddNumber(nad, x1);
1368  }
1369  }
1370  if (inrun == TRUE) { /* must end the last run */
1371  x1 = startx + (n - 1) * delx;
1372  numaAddNumber(nad, x0);
1373  numaAddNumber(nad, x1);
1374  }
1375 
1376  return nad;
1377 }
1378 
1379 
1404 NUMA *
1406  l_float32 thresh1,
1407  l_float32 thresh2,
1408  l_float32 maxn)
1409 {
1410 l_int32 n, i, istart, inband, output, sign;
1411 l_int32 startbelow, below, above, belowlast, abovelast;
1412 l_float32 maxval, threshval1, threshval2, fval, startx, delx, x0, x1;
1413 NUMA *nad;
1414 
1415  PROCNAME("numaThresholdEdges");
1416 
1417  if (!nas)
1418  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1419  if (thresh1 < 0.0 || thresh1 > 1.0 || thresh2 < 0.0 || thresh2 > 1.0)
1420  return (NUMA *)ERROR_PTR("invalid thresholds", procName, NULL);
1421  if (thresh2 < thresh1)
1422  return (NUMA *)ERROR_PTR("thresh2 < thresh1", procName, NULL);
1423 
1424  /* The input thresholds are fractions of the max.
1425  * The first entry in nad is the value of the max used
1426  * here for normalization. */
1427  n = numaGetCount(nas);
1428  if (maxn == 0.0)
1429  numaGetMax(nas, &maxval, NULL);
1430  else
1431  maxval = maxn;
1432  numaGetMax(nas, &maxval, NULL);
1433  numaGetParameters(nas, &startx, &delx);
1434  threshval1 = thresh1 * maxval;
1435  threshval2 = thresh2 * maxval;
1436  nad = numaCreate(0);
1437  numaAddNumber(nad, maxval);
1438 
1439  /* Write triplets of pts (x0, x1, sign) for the edges.
1440  * First make sure we start search from outside the band.
1441  * Only one of {belowlast, abovelast} is true. */
1442  for (i = 0; i < n; i++) {
1443  istart = i;
1444  numaGetFValue(nas, i, &fval);
1445  belowlast = (fval < threshval1) ? TRUE : FALSE;
1446  abovelast = (fval > threshval2) ? TRUE : FALSE;
1447  if (belowlast == TRUE || abovelast == TRUE)
1448  break;
1449  }
1450  if (istart == n) /* no intervals found */
1451  return nad;
1452 
1453  /* x0 and x1 can only be set from outside the edge.
1454  * They are the values just before entering the band,
1455  * and just after entering the band. We can jump through
1456  * the band, in which case they differ by one index in nas. */
1457  inband = FALSE;
1458  startbelow = belowlast; /* one of these is true */
1459  output = FALSE;
1460  x0 = startx + istart * delx;
1461  for (i = istart + 1; i < n; i++) {
1462  numaGetFValue(nas, i, &fval);
1463  below = (fval < threshval1) ? TRUE : FALSE;
1464  above = (fval > threshval2) ? TRUE : FALSE;
1465  if (!inband && belowlast && above) { /* full jump up */
1466  x1 = startx + i * delx;
1467  sign = 1;
1468  startbelow = FALSE; /* for the next transition */
1469  output = TRUE;
1470  } else if (!inband && abovelast && below) { /* full jump down */
1471  x1 = startx + i * delx;
1472  sign = -1;
1473  startbelow = TRUE; /* for the next transition */
1474  output = TRUE;
1475  } else if (inband && startbelow && above) { /* exit rising; success */
1476  x1 = startx + i * delx;
1477  sign = 1;
1478  inband = FALSE;
1479  startbelow = FALSE; /* for the next transition */
1480  output = TRUE;
1481  } else if (inband && !startbelow && below) {
1482  /* exit falling; success */
1483  x1 = startx + i * delx;
1484  sign = -1;
1485  inband = FALSE;
1486  startbelow = TRUE; /* for the next transition */
1487  output = TRUE;
1488  } else if (inband && !startbelow && above) { /* exit rising; failure */
1489  x0 = startx + i * delx;
1490  inband = FALSE;
1491  } else if (inband && startbelow && below) { /* exit falling; failure */
1492  x0 = startx + i * delx;
1493  inband = FALSE;
1494  } else if (!inband && !above && !below) { /* enter */
1495  inband = TRUE;
1496  startbelow = belowlast;
1497  } else if (!inband && (above || below)) { /* outside and remaining */
1498  x0 = startx + i * delx; /* update position */
1499  }
1500  belowlast = below;
1501  abovelast = above;
1502  if (output) { /* we have exited; save new x0 */
1503  numaAddNumber(nad, x0);
1504  numaAddNumber(nad, x1);
1505  numaAddNumber(nad, sign);
1506  output = FALSE;
1507  x0 = startx + i * delx;
1508  }
1509  }
1510 
1511  return nad;
1512 }
1513 
1514 
1524 l_int32
1526  l_int32 span,
1527  l_int32 *pstart,
1528  l_int32 *pend)
1529 {
1530 l_int32 n, nspans;
1531 
1532  PROCNAME("numaGetSpanValues");
1533 
1534  if (!na)
1535  return ERROR_INT("na not defined", procName, 1);
1536  n = numaGetCount(na);
1537  if (n % 2 != 1)
1538  return ERROR_INT("n is not odd", procName, 1);
1539  nspans = n / 2;
1540  if (nspans < 0 || span >= nspans)
1541  return ERROR_INT("invalid span", procName, 1);
1542 
1543  if (pstart) numaGetIValue(na, 2 * span + 1, pstart);
1544  if (pend) numaGetIValue(na, 2 * span + 2, pend);
1545  return 0;
1546 }
1547 
1548 
1560 l_int32
1562  l_int32 edge,
1563  l_int32 *pstart,
1564  l_int32 *pend,
1565  l_int32 *psign)
1566 {
1567 l_int32 n, nedges;
1568 
1569  PROCNAME("numaGetEdgeValues");
1570 
1571  if (!na)
1572  return ERROR_INT("na not defined", procName, 1);
1573  n = numaGetCount(na);
1574  if (n % 3 != 1)
1575  return ERROR_INT("n % 3 is not 1", procName, 1);
1576  nedges = (n - 1) / 3;
1577  if (edge < 0 || edge >= nedges)
1578  return ERROR_INT("invalid edge", procName, 1);
1579 
1580  if (pstart) numaGetIValue(na, 3 * edge + 1, pstart);
1581  if (pend) numaGetIValue(na, 3 * edge + 2, pend);
1582  if (psign) numaGetIValue(na, 3 * edge + 3, psign);
1583  return 0;
1584 }
1585 
1586 
1587 /*----------------------------------------------------------------------*
1588  * Interpolation *
1589  *----------------------------------------------------------------------*/
1617 l_ok
1618 numaInterpolateEqxVal(l_float32 startx,
1619  l_float32 deltax,
1620  NUMA *nay,
1621  l_int32 type,
1622  l_float32 xval,
1623  l_float32 *pyval)
1624 {
1625 l_int32 i, n, i1, i2, i3;
1626 l_float32 x1, x2, x3, fy1, fy2, fy3, d1, d2, d3, del, fi, maxx;
1627 l_float32 *fa;
1628 
1629  PROCNAME("numaInterpolateEqxVal");
1630 
1631  if (!pyval)
1632  return ERROR_INT("&yval not defined", procName, 1);
1633  *pyval = 0.0;
1634  if (!nay)
1635  return ERROR_INT("nay not defined", procName, 1);
1636  if (deltax <= 0.0)
1637  return ERROR_INT("deltax not > 0", procName, 1);
1638  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1639  return ERROR_INT("invalid interp type", procName, 1);
1640  n = numaGetCount(nay);
1641  if (n < 2)
1642  return ERROR_INT("not enough points", procName, 1);
1643  if (type == L_QUADRATIC_INTERP && n == 2) {
1644  type = L_LINEAR_INTERP;
1645  L_WARNING("only 2 points; using linear interp\n", procName);
1646  }
1647  maxx = startx + deltax * (n - 1);
1648  if (xval < startx || xval > maxx)
1649  return ERROR_INT("xval is out of bounds", procName, 1);
1650 
1651  fa = numaGetFArray(nay, L_NOCOPY);
1652  fi = (xval - startx) / deltax;
1653  i = (l_int32)fi;
1654  del = fi - i;
1655  if (del == 0.0) { /* no interpolation required */
1656  *pyval = fa[i];
1657  return 0;
1658  }
1659 
1660  if (type == L_LINEAR_INTERP) {
1661  *pyval = fa[i] + del * (fa[i + 1] - fa[i]);
1662  return 0;
1663  }
1664 
1665  /* Quadratic interpolation */
1666  d1 = d3 = 0.5 / (deltax * deltax);
1667  d2 = -2. * d1;
1668  if (i == 0) {
1669  i1 = i;
1670  i2 = i + 1;
1671  i3 = i + 2;
1672  } else {
1673  i1 = i - 1;
1674  i2 = i;
1675  i3 = i + 1;
1676  }
1677  x1 = startx + i1 * deltax;
1678  x2 = startx + i2 * deltax;
1679  x3 = startx + i3 * deltax;
1680  fy1 = d1 * fa[i1];
1681  fy2 = d2 * fa[i2];
1682  fy3 = d3 * fa[i3];
1683  *pyval = fy1 * (xval - x2) * (xval - x3) +
1684  fy2 * (xval - x1) * (xval - x3) +
1685  fy3 * (xval - x1) * (xval - x2);
1686  return 0;
1687 }
1688 
1689 
1710 l_ok
1712  NUMA *nay,
1713  l_int32 type,
1714  l_float32 xval,
1715  l_float32 *pyval)
1716 {
1717 l_int32 i, im, nx, ny, i1, i2, i3;
1718 l_float32 delu, dell, fract, d1, d2, d3;
1719 l_float32 minx, maxx;
1720 l_float32 *fax, *fay;
1721 
1722  PROCNAME("numaInterpolateArbxVal");
1723 
1724  if (!pyval)
1725  return ERROR_INT("&yval not defined", procName, 1);
1726  *pyval = 0.0;
1727  if (!nax)
1728  return ERROR_INT("nax not defined", procName, 1);
1729  if (!nay)
1730  return ERROR_INT("nay not defined", procName, 1);
1731  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1732  return ERROR_INT("invalid interp type", procName, 1);
1733  ny = numaGetCount(nay);
1734  nx = numaGetCount(nax);
1735  if (nx != ny)
1736  return ERROR_INT("nax and nay not same size arrays", procName, 1);
1737  if (ny < 2)
1738  return ERROR_INT("not enough points", procName, 1);
1739  if (type == L_QUADRATIC_INTERP && ny == 2) {
1740  type = L_LINEAR_INTERP;
1741  L_WARNING("only 2 points; using linear interp\n", procName);
1742  }
1743  numaGetFValue(nax, 0, &minx);
1744  numaGetFValue(nax, nx - 1, &maxx);
1745  if (xval < minx || xval > maxx)
1746  return ERROR_INT("xval is out of bounds", procName, 1);
1747 
1748  fax = numaGetFArray(nax, L_NOCOPY);
1749  fay = numaGetFArray(nay, L_NOCOPY);
1750 
1751  /* Linear search for interval. We are guaranteed
1752  * to either return or break out of the loop.
1753  * In addition, we are assured that fax[i] - fax[im] > 0.0 */
1754  if (xval == fax[0]) {
1755  *pyval = fay[0];
1756  return 0;
1757  }
1758  im = 0;
1759  dell = 0.0;
1760  for (i = 1; i < nx; i++) {
1761  delu = fax[i] - xval;
1762  if (delu >= 0.0) { /* we've passed it */
1763  if (delu == 0.0) {
1764  *pyval = fay[i];
1765  return 0;
1766  }
1767  im = i - 1;
1768  dell = xval - fax[im]; /* >= 0 */
1769  break;
1770  }
1771  }
1772  fract = dell / (fax[i] - fax[im]);
1773 
1774  if (type == L_LINEAR_INTERP) {
1775  *pyval = fay[i] + fract * (fay[i + 1] - fay[i]);
1776  return 0;
1777  }
1778 
1779  /* Quadratic interpolation */
1780  if (im == 0) {
1781  i1 = im;
1782  i2 = im + 1;
1783  i3 = im + 2;
1784  } else {
1785  i1 = im - 1;
1786  i2 = im;
1787  i3 = im + 1;
1788  }
1789  d1 = (fax[i1] - fax[i2]) * (fax[i1] - fax[i3]);
1790  d2 = (fax[i2] - fax[i1]) * (fax[i2] - fax[i3]);
1791  d3 = (fax[i3] - fax[i1]) * (fax[i3] - fax[i2]);
1792  *pyval = fay[i1] * (xval - fax[i2]) * (xval - fax[i3]) / d1 +
1793  fay[i2] * (xval - fax[i1]) * (xval - fax[i3]) / d2 +
1794  fay[i3] * (xval - fax[i1]) * (xval - fax[i2]) / d3;
1795  return 0;
1796 }
1797 
1798 
1827 l_ok
1829  l_float32 deltax,
1830  NUMA *nasy,
1831  l_int32 type,
1832  l_float32 x0,
1833  l_float32 x1,
1834  l_int32 npts,
1835  NUMA **pnax,
1836  NUMA **pnay)
1837 {
1838 l_int32 i, n;
1839 l_float32 x, yval, maxx, delx;
1840 NUMA *nax, *nay;
1841 
1842  PROCNAME("numaInterpolateEqxInterval");
1843 
1844  if (pnax) *pnax = NULL;
1845  if (!pnay)
1846  return ERROR_INT("&nay not defined", procName, 1);
1847  *pnay = NULL;
1848  if (!nasy)
1849  return ERROR_INT("nasy not defined", procName, 1);
1850  if (deltax <= 0.0)
1851  return ERROR_INT("deltax not > 0", procName, 1);
1852  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1853  return ERROR_INT("invalid interp type", procName, 1);
1854  n = numaGetCount(nasy);
1855  if (type == L_QUADRATIC_INTERP && n == 2) {
1856  type = L_LINEAR_INTERP;
1857  L_WARNING("only 2 points; using linear interp\n", procName);
1858  }
1859  maxx = startx + deltax * (n - 1);
1860  if (x0 < startx || x1 > maxx || x1 <= x0)
1861  return ERROR_INT("[x0 ... x1] is not valid", procName, 1);
1862  if (npts < 3)
1863  return ERROR_INT("npts < 3", procName, 1);
1864  delx = (x1 - x0) / (l_float32)(npts - 1); /* delx is for output nay */
1865 
1866  if ((nay = numaCreate(npts)) == NULL)
1867  return ERROR_INT("nay not made", procName, 1);
1868  numaSetParameters(nay, x0, delx);
1869  *pnay = nay;
1870  if (pnax) {
1871  nax = numaCreate(npts);
1872  *pnax = nax;
1873  }
1874 
1875  for (i = 0; i < npts; i++) {
1876  x = x0 + i * delx;
1877  if (pnax)
1878  numaAddNumber(nax, x);
1879  numaInterpolateEqxVal(startx, deltax, nasy, type, x, &yval);
1880  numaAddNumber(nay, yval);
1881  }
1882 
1883  return 0;
1884 }
1885 
1886 
1915 l_ok
1917  NUMA *nay,
1918  l_int32 type,
1919  l_float32 x0,
1920  l_float32 x1,
1921  l_int32 npts,
1922  NUMA **pnadx,
1923  NUMA **pnady)
1924 {
1925 l_int32 i, im, j, nx, ny, i1, i2, i3, sorted;
1926 l_int32 *index;
1927 l_float32 del, xval, yval, excess, fract, minx, maxx, d1, d2, d3;
1928 l_float32 *fax, *fay;
1929 NUMA *nasx, *nasy, *nadx, *nady;
1930 
1931  PROCNAME("numaInterpolateArbxInterval");
1932 
1933  if (pnadx) *pnadx = NULL;
1934  if (!pnady)
1935  return ERROR_INT("&nady not defined", procName, 1);
1936  *pnady = NULL;
1937  if (!nay)
1938  return ERROR_INT("nay not defined", procName, 1);
1939  if (!nax)
1940  return ERROR_INT("nax not defined", procName, 1);
1941  if (type != L_LINEAR_INTERP && type != L_QUADRATIC_INTERP)
1942  return ERROR_INT("invalid interp type", procName, 1);
1943  if (x0 > x1)
1944  return ERROR_INT("x0 > x1", procName, 1);
1945  ny = numaGetCount(nay);
1946  nx = numaGetCount(nax);
1947  if (nx != ny)
1948  return ERROR_INT("nax and nay not same size arrays", procName, 1);
1949  if (ny < 2)
1950  return ERROR_INT("not enough points", procName, 1);
1951  if (type == L_QUADRATIC_INTERP && ny == 2) {
1952  type = L_LINEAR_INTERP;
1953  L_WARNING("only 2 points; using linear interp\n", procName);
1954  }
1955  numaGetMin(nax, &minx, NULL);
1956  numaGetMax(nax, &maxx, NULL);
1957  if (x0 < minx || x1 > maxx)
1958  return ERROR_INT("xval is out of bounds", procName, 1);
1959 
1960  /* Make sure that nax is sorted in increasing order */
1961  numaIsSorted(nax, L_SORT_INCREASING, &sorted);
1962  if (!sorted) {
1963  L_WARNING("we are sorting nax in increasing order\n", procName);
1964  numaSortPair(nax, nay, L_SORT_INCREASING, &nasx, &nasy);
1965  } else {
1966  nasx = numaClone(nax);
1967  nasy = numaClone(nay);
1968  }
1969 
1970  fax = numaGetFArray(nasx, L_NOCOPY);
1971  fay = numaGetFArray(nasy, L_NOCOPY);
1972 
1973  /* Get array of indices into fax for interpolated locations */
1974  if ((index = (l_int32 *)LEPT_CALLOC(npts, sizeof(l_int32))) == NULL) {
1975  numaDestroy(&nasx);
1976  numaDestroy(&nasy);
1977  return ERROR_INT("ind not made", procName, 1);
1978  }
1979  del = (x1 - x0) / (npts - 1.0);
1980  for (i = 0, j = 0; j < nx && i < npts; i++) {
1981  xval = x0 + i * del;
1982  while (j < nx - 1 && xval > fax[j])
1983  j++;
1984  if (xval == fax[j])
1985  index[i] = L_MIN(j, nx - 1);
1986  else /* the index of fax[] is just below xval */
1987  index[i] = L_MAX(j - 1, 0);
1988  }
1989 
1990  /* For each point to be interpolated, get the y value */
1991  nady = numaCreate(npts);
1992  *pnady = nady;
1993  if (pnadx) {
1994  nadx = numaCreate(npts);
1995  *pnadx = nadx;
1996  }
1997  for (i = 0; i < npts; i++) {
1998  xval = x0 + i * del;
1999  if (pnadx)
2000  numaAddNumber(nadx, xval);
2001  im = index[i];
2002  excess = xval - fax[im];
2003  if (excess == 0.0) {
2004  numaAddNumber(nady, fay[im]);
2005  continue;
2006  }
2007  fract = excess / (fax[im + 1] - fax[im]);
2008 
2009  if (type == L_LINEAR_INTERP) {
2010  yval = fay[im] + fract * (fay[im + 1] - fay[im]);
2011  numaAddNumber(nady, yval);
2012  continue;
2013  }
2014 
2015  /* Quadratic interpolation */
2016  if (im == 0) {
2017  i1 = im;
2018  i2 = im + 1;
2019  i3 = im + 2;
2020  } else {
2021  i1 = im - 1;
2022  i2 = im;
2023  i3 = im + 1;
2024  }
2025  d1 = (fax[i1] - fax[i2]) * (fax[i1] - fax[i3]);
2026  d2 = (fax[i2] - fax[i1]) * (fax[i2] - fax[i3]);
2027  d3 = (fax[i3] - fax[i1]) * (fax[i3] - fax[i2]);
2028  yval = fay[i1] * (xval - fax[i2]) * (xval - fax[i3]) / d1 +
2029  fay[i2] * (xval - fax[i1]) * (xval - fax[i3]) / d2 +
2030  fay[i3] * (xval - fax[i1]) * (xval - fax[i2]) / d3;
2031  numaAddNumber(nady, yval);
2032  }
2033 
2034  LEPT_FREE(index);
2035  numaDestroy(&nasx);
2036  numaDestroy(&nasy);
2037  return 0;
2038 }
2039 
2040 
2041 /*----------------------------------------------------------------------*
2042  * Functions requiring interpolation *
2043  *----------------------------------------------------------------------*/
2076 l_ok
2078  l_float32 *pmaxval,
2079  NUMA *naloc,
2080  l_float32 *pmaxloc)
2081 {
2082 l_float32 val;
2083 l_float32 smaxval; /* start value of maximum sample, before interpolating */
2084 l_int32 n, imaxloc;
2085 l_float32 x1, x2, x3, y1, y2, y3, c1, c2, c3, a, b, xmax, ymax;
2086 
2087  PROCNAME("numaFitMax");
2088 
2089  if (pmaxval) *pmaxval = 0.0;
2090  if (pmaxloc) *pmaxloc = 0.0;
2091  if (!na)
2092  return ERROR_INT("na not defined", procName, 1);
2093  if (!pmaxval)
2094  return ERROR_INT("&maxval not defined", procName, 1);
2095  if (!pmaxloc)
2096  return ERROR_INT("&maxloc not defined", procName, 1);
2097 
2098  n = numaGetCount(na);
2099  if (naloc) {
2100  if (n != numaGetCount(naloc))
2101  return ERROR_INT("na and naloc of unequal size", procName, 1);
2102  }
2103  numaGetMax(na, &smaxval, &imaxloc);
2104 
2105  /* Simple case: max is at end point */
2106  if (imaxloc == 0 || imaxloc == n - 1) {
2107  *pmaxval = smaxval;
2108  if (naloc) {
2109  numaGetFValue(naloc, imaxloc, &val);
2110  *pmaxloc = val;
2111  } else {
2112  *pmaxloc = imaxloc;
2113  }
2114  return 0;
2115  }
2116 
2117  /* Interior point; use quadratic interpolation */
2118  y2 = smaxval;
2119  numaGetFValue(na, imaxloc - 1, &val);
2120  y1 = val;
2121  numaGetFValue(na, imaxloc + 1, &val);
2122  y3 = val;
2123  if (naloc) {
2124  numaGetFValue(naloc, imaxloc - 1, &val);
2125  x1 = val;
2126  numaGetFValue(naloc, imaxloc, &val);
2127  x2 = val;
2128  numaGetFValue(naloc, imaxloc + 1, &val);
2129  x3 = val;
2130  } else {
2131  x1 = imaxloc - 1;
2132  x2 = imaxloc;
2133  x3 = imaxloc + 1;
2134  }
2135 
2136  /* Can't interpolate; just use the max val in na
2137  * and the corresponding one in naloc */
2138  if (x1 == x2 || x1 == x3 || x2 == x3) {
2139  *pmaxval = y2;
2140  *pmaxloc = x2;
2141  return 0;
2142  }
2143 
2144  /* Use lagrangian interpolation; set dy/dx = 0 */
2145  c1 = y1 / ((x1 - x2) * (x1 - x3));
2146  c2 = y2 / ((x2 - x1) * (x2 - x3));
2147  c3 = y3 / ((x3 - x1) * (x3 - x2));
2148  a = c1 + c2 + c3;
2149  b = c1 * (x2 + x3) + c2 * (x1 + x3) + c3 * (x1 + x2);
2150  xmax = b / (2 * a);
2151  ymax = c1 * (xmax - x2) * (xmax - x3) +
2152  c2 * (xmax - x1) * (xmax - x3) +
2153  c3 * (xmax - x1) * (xmax - x2);
2154  *pmaxval = ymax;
2155  *pmaxloc = xmax;
2156 
2157  return 0;
2158 }
2159 
2160 
2181 l_ok
2183  NUMA *nay,
2184  l_float32 x0,
2185  l_float32 x1,
2186  l_int32 npts,
2187  NUMA **pnadx,
2188  NUMA **pnady)
2189 {
2190 l_int32 i, nx, ny;
2191 l_float32 minx, maxx, der, invdel;
2192 l_float32 *fay;
2193 NUMA *nady, *naiy;
2194 
2195  PROCNAME("numaDifferentiateInterval");
2196 
2197  if (pnadx) *pnadx = NULL;
2198  if (!pnady)
2199  return ERROR_INT("&nady not defined", procName, 1);
2200  *pnady = NULL;
2201  if (!nay)
2202  return ERROR_INT("nay not defined", procName, 1);
2203  if (!nax)
2204  return ERROR_INT("nax not defined", procName, 1);
2205  if (x0 > x1)
2206  return ERROR_INT("x0 > x1", procName, 1);
2207  ny = numaGetCount(nay);
2208  nx = numaGetCount(nax);
2209  if (nx != ny)
2210  return ERROR_INT("nax and nay not same size arrays", procName, 1);
2211  if (ny < 2)
2212  return ERROR_INT("not enough points", procName, 1);
2213  numaGetMin(nax, &minx, NULL);
2214  numaGetMax(nax, &maxx, NULL);
2215  if (x0 < minx || x1 > maxx)
2216  return ERROR_INT("xval is out of bounds", procName, 1);
2217  if (npts < 2)
2218  return ERROR_INT("npts < 2", procName, 1);
2219 
2220  /* Generate interpolated array over specified interval */
2221  if (numaInterpolateArbxInterval(nax, nay, L_LINEAR_INTERP, x0, x1,
2222  npts, pnadx, &naiy))
2223  return ERROR_INT("interpolation failed", procName, 1);
2224 
2225  nady = numaCreate(npts);
2226  *pnady = nady;
2227  invdel = 0.5 * ((l_float32)npts - 1.0) / (x1 - x0);
2228  fay = numaGetFArray(naiy, L_NOCOPY);
2229 
2230  /* Compute and save derivatives */
2231  der = 0.5 * invdel * (fay[1] - fay[0]);
2232  numaAddNumber(nady, der);
2233  for (i = 1; i < npts - 1; i++) {
2234  der = invdel * (fay[i + 1] - fay[i - 1]);
2235  numaAddNumber(nady, der);
2236  }
2237  der = 0.5 * invdel * (fay[npts - 1] - fay[npts - 2]);
2238  numaAddNumber(nady, der);
2239 
2240  numaDestroy(&naiy);
2241  return 0;
2242 }
2243 
2244 
2264 l_ok
2266  NUMA *nay,
2267  l_float32 x0,
2268  l_float32 x1,
2269  l_int32 npts,
2270  l_float32 *psum)
2271 {
2272 l_int32 i, nx, ny;
2273 l_float32 minx, maxx, sum, del;
2274 l_float32 *fay;
2275 NUMA *naiy;
2276 
2277  PROCNAME("numaIntegrateInterval");
2278 
2279  if (!psum)
2280  return ERROR_INT("&sum not defined", procName, 1);
2281  *psum = 0.0;
2282  if (!nay)
2283  return ERROR_INT("nay not defined", procName, 1);
2284  if (!nax)
2285  return ERROR_INT("nax not defined", procName, 1);
2286  if (x0 > x1)
2287  return ERROR_INT("x0 > x1", procName, 1);
2288  if (npts < 2)
2289  return ERROR_INT("npts < 2", procName, 1);
2290  ny = numaGetCount(nay);
2291  nx = numaGetCount(nax);
2292  if (nx != ny)
2293  return ERROR_INT("nax and nay not same size arrays", procName, 1);
2294  if (ny < 2)
2295  return ERROR_INT("not enough points", procName, 1);
2296  numaGetMin(nax, &minx, NULL);
2297  numaGetMax(nax, &maxx, NULL);
2298  if (x0 < minx || x1 > maxx)
2299  return ERROR_INT("xval is out of bounds", procName, 1);
2300 
2301  /* Generate interpolated array over specified interval */
2302  if (numaInterpolateArbxInterval(nax, nay, L_LINEAR_INTERP, x0, x1,
2303  npts, NULL, &naiy))
2304  return ERROR_INT("interpolation failed", procName, 1);
2305 
2306  del = (x1 - x0) / ((l_float32)npts - 1.0);
2307  fay = numaGetFArray(naiy, L_NOCOPY);
2308 
2309  /* Compute integral (simple trapezoid) */
2310  sum = 0.5 * (fay[0] + fay[npts - 1]);
2311  for (i = 1; i < npts - 1; i++)
2312  sum += fay[i];
2313  *psum = del * sum;
2314 
2315  numaDestroy(&naiy);
2316  return 0;
2317 }
2318 
2319 
2320 /*----------------------------------------------------------------------*
2321  * Sorting *
2322  *----------------------------------------------------------------------*/
2369 l_ok
2371  NUMA **pnasort,
2372  NUMA **pnaindex,
2373  NUMA **pnainvert,
2374  l_int32 sortorder,
2375  l_int32 sorttype)
2376 {
2377 NUMA *naindex;
2378 
2379  PROCNAME("numaSortGeneral");
2380 
2381  if (!na)
2382  return ERROR_INT("na not defined", procName, 1);
2383  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2384  return ERROR_INT("invalid sort order", procName, 1);
2385  if (sorttype != L_SHELL_SORT && sorttype != L_BIN_SORT)
2386  return ERROR_INT("invalid sort type", procName, 1);
2387  if (!pnasort && !pnaindex && !pnainvert)
2388  return ERROR_INT("nothing to do", procName, 1);
2389  if (pnasort) *pnasort = NULL;
2390  if (pnaindex) *pnaindex = NULL;
2391  if (pnainvert) *pnainvert = NULL;
2392 
2393  if (sorttype == L_SHELL_SORT)
2394  naindex = numaGetSortIndex(na, sortorder);
2395  else /* sorttype == L_BIN_SORT */
2396  naindex = numaGetBinSortIndex(na, sortorder);
2397 
2398  if (pnasort)
2399  *pnasort = numaSortByIndex(na, naindex);
2400  if (pnainvert)
2401  *pnainvert = numaInvertMap(naindex);
2402  if (pnaindex)
2403  *pnaindex = naindex;
2404  else
2405  numaDestroy(&naindex);
2406  return 0;
2407 }
2408 
2409 
2423 NUMA *
2425  l_int32 sortorder)
2426 {
2427 l_int32 type;
2428 
2429  PROCNAME("numaSortAutoSelect");
2430 
2431  if (!nas)
2432  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2433  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2434  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2435 
2436  type = numaChooseSortType(nas);
2437  if (type == L_SHELL_SORT)
2438  return numaSort(NULL, nas, sortorder);
2439  else if (type == L_BIN_SORT)
2440  return numaBinSort(nas, sortorder);
2441  else
2442  return (NUMA *)ERROR_PTR("invalid sort type", procName, NULL);
2443 }
2444 
2445 
2459 NUMA *
2461  l_int32 sortorder)
2462 {
2463 l_int32 type;
2464 
2465  PROCNAME("numaSortIndexAutoSelect");
2466 
2467  if (!nas)
2468  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2469  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2470  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2471 
2472  type = numaChooseSortType(nas);
2473  if (type == L_SHELL_SORT)
2474  return numaGetSortIndex(nas, sortorder);
2475  else if (type == L_BIN_SORT)
2476  return numaGetBinSortIndex(nas, sortorder);
2477  else
2478  return (NUMA *)ERROR_PTR("invalid sort type", procName, NULL);
2479 }
2480 
2481 
2495 l_int32
2497 {
2498 l_int32 n, type;
2499 l_float32 minval, maxval;
2500 
2501  PROCNAME("numaChooseSortType");
2502 
2503  if (!nas)
2504  return ERROR_INT("nas not defined", procName, UNDEF);
2505 
2506  numaGetMin(nas, &minval, NULL);
2507  n = numaGetCount(nas);
2508 
2509  /* Very small histogram; use shell sort */
2510  if (minval < 0.0 || n < 200) {
2511  L_INFO("Shell sort chosen\n", procName);
2512  return L_SHELL_SORT;
2513  }
2514 
2515  /* Need to compare nlog(n) with maxval. The factor of 0.003
2516  * was determined by comparing times for different histogram
2517  * sizes and maxval. It is very small because binsort is fast
2518  * and shell sort gets slow for large n. */
2519  numaGetMax(nas, &maxval, NULL);
2520  if (n * log((l_float32)n) < 0.003 * maxval) {
2521  type = L_SHELL_SORT;
2522  L_INFO("Shell sort chosen\n", procName);
2523  } else {
2524  type = L_BIN_SORT;
2525  L_INFO("Bin sort chosen\n", procName);
2526  }
2527  return type;
2528 }
2529 
2530 
2546 NUMA *
2548  NUMA *nain,
2549  l_int32 sortorder)
2550 {
2551 l_int32 i, n, gap, j;
2552 l_float32 tmp;
2553 l_float32 *array;
2554 
2555  PROCNAME("numaSort");
2556 
2557  if (!nain)
2558  return (NUMA *)ERROR_PTR("nain not defined", procName, NULL);
2559  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2560  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2561 
2562  /* Make naout if necessary; otherwise do in-place */
2563  if (!naout)
2564  naout = numaCopy(nain);
2565  else if (nain != naout)
2566  return (NUMA *)ERROR_PTR("invalid: not in-place", procName, NULL);
2567  array = naout->array; /* operate directly on the array */
2568  n = numaGetCount(naout);
2569 
2570  /* Shell sort */
2571  for (gap = n/2; gap > 0; gap = gap / 2) {
2572  for (i = gap; i < n; i++) {
2573  for (j = i - gap; j >= 0; j -= gap) {
2574  if ((sortorder == L_SORT_INCREASING &&
2575  array[j] > array[j + gap]) ||
2576  (sortorder == L_SORT_DECREASING &&
2577  array[j] < array[j + gap]))
2578  {
2579  tmp = array[j];
2580  array[j] = array[j + gap];
2581  array[j + gap] = tmp;
2582  }
2583  }
2584  }
2585  }
2586 
2587  return naout;
2588 }
2589 
2590 
2608 NUMA *
2610  l_int32 sortorder)
2611 {
2612 NUMA *nat, *nad;
2613 
2614  PROCNAME("numaBinSort");
2615 
2616  if (!nas)
2617  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2618  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2619  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2620 
2621  nat = numaGetBinSortIndex(nas, sortorder);
2622  nad = numaSortByIndex(nas, nat);
2623  numaDestroy(&nat);
2624  return nad;
2625 }
2626 
2627 
2636 NUMA *
2638  l_int32 sortorder)
2639 {
2640 l_int32 i, n, gap, j;
2641 l_float32 tmp;
2642 l_float32 *array; /* copy of input array */
2643 l_float32 *iarray; /* array of indices */
2644 NUMA *naisort;
2645 
2646  PROCNAME("numaGetSortIndex");
2647 
2648  if (!na)
2649  return (NUMA *)ERROR_PTR("na not defined", procName, NULL);
2650  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2651  return (NUMA *)ERROR_PTR("invalid sortorder", procName, NULL);
2652 
2653  n = numaGetCount(na);
2654  if ((array = numaGetFArray(na, L_COPY)) == NULL)
2655  return (NUMA *)ERROR_PTR("array not made", procName, NULL);
2656  if ((iarray = (l_float32 *)LEPT_CALLOC(n, sizeof(l_float32))) == NULL) {
2657  LEPT_FREE(array);
2658  return (NUMA *)ERROR_PTR("iarray not made", procName, NULL);
2659  }
2660  for (i = 0; i < n; i++)
2661  iarray[i] = i;
2662 
2663  /* Shell sort */
2664  for (gap = n/2; gap > 0; gap = gap / 2) {
2665  for (i = gap; i < n; i++) {
2666  for (j = i - gap; j >= 0; j -= gap) {
2667  if ((sortorder == L_SORT_INCREASING &&
2668  array[j] > array[j + gap]) ||
2669  (sortorder == L_SORT_DECREASING &&
2670  array[j] < array[j + gap]))
2671  {
2672  tmp = array[j];
2673  array[j] = array[j + gap];
2674  array[j + gap] = tmp;
2675  tmp = iarray[j];
2676  iarray[j] = iarray[j + gap];
2677  iarray[j + gap] = tmp;
2678  }
2679  }
2680  }
2681  }
2682 
2683  naisort = numaCreate(n);
2684  for (i = 0; i < n; i++)
2685  numaAddNumber(naisort, iarray[i]);
2686 
2687  LEPT_FREE(array);
2688  LEPT_FREE(iarray);
2689  return naisort;
2690 }
2691 
2692 
2712 NUMA *
2714  l_int32 sortorder)
2715 {
2716 l_int32 i, n, isize, ival, imax;
2717 l_float32 size;
2718 NUMA *na, *nai, *nad;
2719 L_PTRA *paindex;
2720 
2721  PROCNAME("numaGetBinSortIndex");
2722 
2723  if (!nas)
2724  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2725  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2726  return (NUMA *)ERROR_PTR("invalid sort order", procName, NULL);
2727 
2728  /* Set up a ptra holding numa at indices for which there
2729  * are values in nas. Suppose nas has the value 230 at index
2730  * 7355. A numa holding the index 7355 is created and stored
2731  * at the ptra index 230. If there is another value of 230
2732  * in nas, its index is added to the same numa (at index 230
2733  * in the ptra). When finished, the ptra can be scanned for numa,
2734  * and the original indices in the nas can be read out. In this
2735  * way, the ptra effectively sorts the input numbers in the nas. */
2736  numaGetMax(nas, &size, NULL);
2737  isize = (l_int32)size;
2738  if (isize > 1000000)
2739  L_WARNING("large array: %d elements\n", procName, isize);
2740  paindex = ptraCreate(isize + 1);
2741  n = numaGetCount(nas);
2742  for (i = 0; i < n; i++) {
2743  numaGetIValue(nas, i, &ival);
2744  nai = (NUMA *)ptraGetPtrToItem(paindex, ival);
2745  if (!nai) { /* make it; no shifting will occur */
2746  nai = numaCreate(1);
2747  ptraInsert(paindex, ival, nai, L_MIN_DOWNSHIFT);
2748  }
2749  numaAddNumber(nai, i);
2750  }
2751 
2752  /* Sort by scanning the ptra, extracting numas and pulling
2753  * the (index into nas) numbers out of each numa, taken
2754  * successively in requested order. */
2755  ptraGetMaxIndex(paindex, &imax);
2756  nad = numaCreate(0);
2757  if (sortorder == L_SORT_INCREASING) {
2758  for (i = 0; i <= imax; i++) {
2759  na = (NUMA *)ptraRemove(paindex, i, L_NO_COMPACTION);
2760  if (!na) continue;
2761  numaJoin(nad, na, 0, -1);
2762  numaDestroy(&na);
2763  }
2764  } else { /* L_SORT_DECREASING */
2765  for (i = imax; i >= 0; i--) {
2766  na = (NUMA *)ptraRemoveLast(paindex);
2767  if (!na) break; /* they've all been removed */
2768  numaJoin(nad, na, 0, -1);
2769  numaDestroy(&na);
2770  }
2771  }
2772 
2773  ptraDestroy(&paindex, FALSE, FALSE);
2774  return nad;
2775 }
2776 
2777 
2785 NUMA *
2787  NUMA *naindex)
2788 {
2789 l_int32 i, n, index;
2790 l_float32 val;
2791 NUMA *nad;
2792 
2793  PROCNAME("numaSortByIndex");
2794 
2795  if (!nas)
2796  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2797  if (!naindex)
2798  return (NUMA *)ERROR_PTR("naindex not defined", procName, NULL);
2799 
2800  n = numaGetCount(nas);
2801  nad = numaCreate(n);
2802  for (i = 0; i < n; i++) {
2803  numaGetIValue(naindex, i, &index);
2804  numaGetFValue(nas, index, &val);
2805  numaAddNumber(nad, val);
2806  }
2807 
2808  return nad;
2809 }
2810 
2811 
2827 l_int32
2829  l_int32 sortorder,
2830  l_int32 *psorted)
2831 {
2832 l_int32 i, n;
2833 l_float32 prevval, val;
2834 
2835  PROCNAME("numaIsSorted");
2836 
2837  if (!psorted)
2838  return ERROR_INT("&sorted not defined", procName, 1);
2839  *psorted = FALSE;
2840  if (!nas)
2841  return ERROR_INT("nas not defined", procName, 1);
2842  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2843  return ERROR_INT("invalid sortorder", procName, 1);
2844 
2845  n = numaGetCount(nas);
2846  numaGetFValue(nas, 0, &prevval);
2847  for (i = 1; i < n; i++) {
2848  numaGetFValue(nas, i, &val);
2849  if ((sortorder == L_SORT_INCREASING && val < prevval) ||
2850  (sortorder == L_SORT_DECREASING && val > prevval))
2851  return 0;
2852  }
2853 
2854  *psorted = TRUE;
2855  return 0;
2856 }
2857 
2858 
2874 l_ok
2876  NUMA *nay,
2877  l_int32 sortorder,
2878  NUMA **pnasx,
2879  NUMA **pnasy)
2880 {
2881 l_int32 sorted;
2882 NUMA *naindex;
2883 
2884  PROCNAME("numaSortPair");
2885 
2886  if (pnasx) *pnasx = NULL;
2887  if (pnasy) *pnasy = NULL;
2888  if (!pnasx || !pnasy)
2889  return ERROR_INT("&nasx and/or &nasy not defined", procName, 1);
2890  if (!nax)
2891  return ERROR_INT("nax not defined", procName, 1);
2892  if (!nay)
2893  return ERROR_INT("nay not defined", procName, 1);
2894  if (sortorder != L_SORT_INCREASING && sortorder != L_SORT_DECREASING)
2895  return ERROR_INT("invalid sortorder", procName, 1);
2896 
2897  numaIsSorted(nax, sortorder, &sorted);
2898  if (sorted == TRUE) {
2899  *pnasx = numaCopy(nax);
2900  *pnasy = numaCopy(nay);
2901  } else {
2902  naindex = numaGetSortIndex(nax, sortorder);
2903  *pnasx = numaSortByIndex(nax, naindex);
2904  *pnasy = numaSortByIndex(nay, naindex);
2905  numaDestroy(&naindex);
2906  }
2907 
2908  return 0;
2909 }
2910 
2911 
2925 NUMA *
2927 {
2928 l_int32 i, n, val, error;
2929 l_int32 *test;
2930 NUMA *nad;
2931 
2932  PROCNAME("numaInvertMap");
2933 
2934  if (!nas)
2935  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
2936 
2937  n = numaGetCount(nas);
2938  nad = numaMakeConstant(0.0, n);
2939  test = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32));
2940  error = 0;
2941  for (i = 0; i < n; i++) {
2942  numaGetIValue(nas, i, &val);
2943  if (val >= n) {
2944  error = 1;
2945  break;
2946  }
2947  numaReplaceNumber(nad, val, i);
2948  if (test[val] == 0) {
2949  test[val] = 1;
2950  } else {
2951  error = 1;
2952  break;
2953  }
2954  }
2955 
2956  LEPT_FREE(test);
2957  if (error) {
2958  numaDestroy(&nad);
2959  return (NUMA *)ERROR_PTR("nas not invertible", procName, NULL);
2960  }
2961 
2962  return nad;
2963 }
2964 
2965 
2966 /*----------------------------------------------------------------------*
2967  * Random permutation *
2968  *----------------------------------------------------------------------*/
2984 NUMA *
2986  l_int32 seed)
2987 {
2988 l_int32 i, index, temp;
2989 l_int32 *array;
2990 NUMA *na;
2991 
2992  PROCNAME("numaPseudorandomSequence");
2993 
2994  if (size <= 0)
2995  return (NUMA *)ERROR_PTR("size <= 0", procName, NULL);
2996 
2997  if ((array = (l_int32 *)LEPT_CALLOC(size, sizeof(l_int32))) == NULL)
2998  return (NUMA *)ERROR_PTR("array not made", procName, NULL);
2999  for (i = 0; i < size; i++)
3000  array[i] = i;
3001  srand(seed);
3002  for (i = size - 1; i > 0; i--) {
3003  index = (l_int32)((i + 1) * ((l_float64)rand() / (l_float64)RAND_MAX));
3004  index = L_MIN(index, i);
3005  temp = array[i];
3006  array[i] = array[index];
3007  array[index] = temp;
3008  }
3009 
3010  na = numaCreateFromIArray(array, size);
3011  LEPT_FREE(array);
3012  return na;
3013 }
3014 
3015 
3023 NUMA *
3025  l_int32 seed)
3026 {
3027 l_int32 i, index, size;
3028 l_float32 val;
3029 NUMA *naindex, *nad;
3030 
3031  PROCNAME("numaRandomPermutation");
3032 
3033  if (!nas)
3034  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
3035 
3036  size = numaGetCount(nas);
3037  naindex = numaPseudorandomSequence(size, seed);
3038  nad = numaCreate(size);
3039  for (i = 0; i < size; i++) {
3040  numaGetIValue(naindex, i, &index);
3041  numaGetFValue(nas, index, &val);
3042  numaAddNumber(nad, val);
3043  }
3044 
3045  numaDestroy(&naindex);
3046  return nad;
3047 }
3048 
3049 
3050 /*----------------------------------------------------------------------*
3051  * Functions requiring sorting *
3052  *----------------------------------------------------------------------*/
3080 l_ok
3082  l_float32 fract,
3083  NUMA *nasort,
3084  l_int32 usebins,
3085  l_float32 *pval)
3086 {
3087 l_int32 n, index;
3088 NUMA *nas;
3089 
3090  PROCNAME("numaGetRankValue");
3091 
3092  if (!pval)
3093  return ERROR_INT("&val not defined", procName, 1);
3094  *pval = 0.0; /* init */
3095  if (!na)
3096  return ERROR_INT("na not defined", procName, 1);
3097  if (fract < 0.0 || fract > 1.0)
3098  return ERROR_INT("fract not in [0.0 ... 1.0]", procName, 1);
3099  n = numaGetCount(na);
3100  if (n == 0)
3101  return ERROR_INT("na empty", procName, 1);
3102 
3103  if (nasort) {
3104  nas = nasort;
3105  } else {
3106  if (usebins == 0)
3107  nas = numaSort(NULL, na, L_SORT_INCREASING);
3108  else
3109  nas = numaBinSort(na, L_SORT_INCREASING);
3110  if (!nas)
3111  return ERROR_INT("nas not made", procName, 1);
3112  }
3113  index = (l_int32)(fract * (l_float32)(n - 1) + 0.5);
3114  numaGetFValue(nas, index, pval);
3115 
3116  if (!nasort) numaDestroy(&nas);
3117  return 0;
3118 }
3119 
3120 
3134 l_ok
3136  l_float32 *pval)
3137 {
3138  PROCNAME("numaGetMedian");
3139 
3140  if (!pval)
3141  return ERROR_INT("&val not defined", procName, 1);
3142  *pval = 0.0; /* init */
3143  if (!na)
3144  return ERROR_INT("na not defined", procName, 1);
3145 
3146  return numaGetRankValue(na, 0.5, NULL, 0, pval);
3147 }
3148 
3149 
3165 l_ok
3167  l_int32 *pval)
3168 {
3169 l_int32 ret;
3170 l_float32 fval;
3171 
3172  PROCNAME("numaGetBinnedMedian");
3173 
3174  if (!pval)
3175  return ERROR_INT("&val not defined", procName, 1);
3176  *pval = 0; /* init */
3177  if (!na)
3178  return ERROR_INT("na not defined", procName, 1);
3179 
3180  ret = numaGetRankValue(na, 0.5, NULL, 1, &fval);
3181  *pval = lept_roundftoi(fval);
3182  return ret;
3183 }
3184 
3185 
3194 l_ok
3196  l_float32 med,
3197  l_float32 *pdev)
3198 {
3199 l_int32 i, n;
3200 l_float32 val, dev;
3201 
3202  PROCNAME("numaGetMeanDevFromMedian");
3203 
3204  if (!pdev)
3205  return ERROR_INT("&dev not defined", procName, 1);
3206  *pdev = 0.0; /* init */
3207  if (!na)
3208  return ERROR_INT("na not defined", procName, 1);
3209  if ((n = numaGetCount(na)) == 0)
3210  return ERROR_INT("na is empty", procName, 1);
3211 
3212  dev = 0.0;
3213  for (i = 0; i < n; i++) {
3214  numaGetFValue(na, i, &val);
3215  dev += L_ABS(val - med);
3216  }
3217  *pdev = dev / (l_float32)n;
3218  return 0;
3219 }
3220 
3221 
3240 l_ok
3242  l_float32 *pmed,
3243  l_float32 *pdev)
3244 {
3245 l_int32 n, i;
3246 l_float32 val, med;
3247 NUMA *nadev;
3248 
3249  PROCNAME("numaGetMedianDevFromMedian");
3250 
3251  if (pmed) *pmed = 0.0;
3252  if (!pdev)
3253  return ERROR_INT("&dev not defined", procName, 1);
3254  *pdev = 0.0;
3255  if (!na)
3256  return ERROR_INT("na not defined", procName, 1);
3257 
3258  numaGetMedian(na, &med);
3259  if (pmed) *pmed = med;
3260  n = numaGetCount(na);
3261  nadev = numaCreate(n);
3262  for (i = 0; i < n; i++) {
3263  numaGetFValue(na, i, &val);
3264  numaAddNumber(nadev, L_ABS(val - med));
3265  }
3266  numaGetMedian(nadev, pdev);
3267 
3268  numaDestroy(&nadev);
3269  return 0;
3270 }
3271 
3272 
3289 l_ok
3291  l_float32 *pval,
3292  l_int32 *pcount)
3293 {
3294 l_int32 i, n, maxcount, prevcount;
3295 l_float32 val, maxval, prevval;
3296 l_float32 *array;
3297 NUMA *nasort;
3298 
3299  PROCNAME("numaGetMode");
3300 
3301  if (pcount) *pcount = 0;
3302  if (!pval)
3303  return ERROR_INT("&val not defined", procName, 1);
3304  *pval = 0.0;
3305  if (!na)
3306  return ERROR_INT("na not defined", procName, 1);
3307  if ((n = numaGetCount(na)) == 0)
3308  return 1;
3309 
3310  if ((nasort = numaSort(NULL, na, L_SORT_DECREASING)) == NULL)
3311  return ERROR_INT("nas not made", procName, 1);
3312  array = numaGetFArray(nasort, L_NOCOPY);
3313 
3314  /* Initialize with array[0] */
3315  prevval = array[0];
3316  prevcount = 1;
3317  maxval = prevval;
3318  maxcount = prevcount;
3319 
3320  /* Scan the sorted array, aggregating duplicates */
3321  for (i = 1; i < n; i++) {
3322  val = array[i];
3323  if (val == prevval) {
3324  prevcount++;
3325  } else { /* new value */
3326  if (prevcount > maxcount) { /* new max */
3327  maxcount = prevcount;
3328  maxval = prevval;
3329  }
3330  prevval = val;
3331  prevcount = 1;
3332  }
3333  }
3334 
3335  /* Was the mode the last run of elements? */
3336  if (prevcount > maxcount) {
3337  maxcount = prevcount;
3338  maxval = prevval;
3339  }
3340 
3341  *pval = maxval;
3342  if (pcount)
3343  *pcount = maxcount;
3344 
3345  numaDestroy(&nasort);
3346  return 0;
3347 }
3348 
3349 
3350 /*----------------------------------------------------------------------*
3351  * Rearrangements *
3352  *----------------------------------------------------------------------*/
3369 l_ok
3371  NUMA *nas,
3372  l_int32 istart,
3373  l_int32 iend)
3374 {
3375 l_int32 n, i;
3376 l_float32 val;
3377 
3378  PROCNAME("numaJoin");
3379 
3380  if (!nad)
3381  return ERROR_INT("nad not defined", procName, 1);
3382  if (!nas)
3383  return 0;
3384 
3385  if (istart < 0)
3386  istart = 0;
3387  n = numaGetCount(nas);
3388  if (iend < 0 || iend >= n)
3389  iend = n - 1;
3390  if (istart > iend)
3391  return ERROR_INT("istart > iend; nothing to add", procName, 1);
3392 
3393  for (i = istart; i <= iend; i++) {
3394  numaGetFValue(nas, i, &val);
3395  numaAddNumber(nad, val);
3396  }
3397 
3398  return 0;
3399 }
3400 
3401 
3418 l_ok
3420  NUMAA *naas,
3421  l_int32 istart,
3422  l_int32 iend)
3423 {
3424 l_int32 n, i;
3425 NUMA *na;
3426 
3427  PROCNAME("numaaJoin");
3428 
3429  if (!naad)
3430  return ERROR_INT("naad not defined", procName, 1);
3431  if (!naas)
3432  return 0;
3433 
3434  if (istart < 0)
3435  istart = 0;
3436  n = numaaGetCount(naas);
3437  if (iend < 0 || iend >= n)
3438  iend = n - 1;
3439  if (istart > iend)
3440  return ERROR_INT("istart > iend; nothing to add", procName, 1);
3441 
3442  for (i = istart; i <= iend; i++) {
3443  na = numaaGetNuma(naas, i, L_CLONE);
3444  numaaAddNuma(naad, na, L_INSERT);
3445  }
3446 
3447  return 0;
3448 }
3449 
3450 
3466 NUMA *
3468 {
3469 l_int32 i, nalloc;
3470 NUMA *na, *nad;
3471 NUMA **array;
3472 
3473  PROCNAME("numaaFlattenToNuma");
3474 
3475  if (!naa)
3476  return (NUMA *)ERROR_PTR("naa not defined", procName, NULL);
3477 
3478  nalloc = naa->nalloc;
3479  array = numaaGetPtrArray(naa);
3480  nad = numaCreate(0);
3481  for (i = 0; i < nalloc; i++) {
3482  na = array[i];
3483  if (!na) continue;
3484  numaJoin(nad, na, 0, -1);
3485  }
3486 
3487  return nad;
3488 }
3489 
l_ok numaGetSum(NUMA *na, l_float32 *psum)
numaGetSum()
Definition: numafunc1.c:527
NUMA * numaInvertMap(NUMA *nas)
numaInvertMap()
Definition: numafunc1.c:2926
NUMA * numaBinSort(NUMA *nas, l_int32 sortorder)
numaBinSort()
Definition: numafunc1.c:2609
void * ptraGetPtrToItem(L_PTRA *pa, l_int32 index)
ptraGetPtrToItem()
Definition: ptra.c:759
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:692
l_ok numaFitMax(NUMA *na, l_float32 *pmaxval, NUMA *naloc, l_float32 *pmaxloc)
numaFitMax()
Definition: numafunc1.c:2077
l_ok numaAddToNumber(NUMA *na, l_int32 index, l_float32 val)
numaAddToNumber()
Definition: numafunc1.c:413
Definition: pix.h:717
NUMA * numaLowPassIntervals(NUMA *nas, l_float32 thresh, l_float32 maxn)
numaLowPassIntervals()
Definition: numafunc1.c:1329
l_ok numaHasOnlyIntegers(NUMA *na, l_int32 maxsamples, l_int32 *pallints)
numaHasOnlyIntegers()
Definition: numafunc1.c:645
NUMA * numaGetSortIndex(NUMA *na, l_int32 sortorder)
numaGetSortIndex()
Definition: numafunc1.c:2637
NUMA * numaSortAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortAutoSelect()
Definition: numafunc1.c:2424
l_ok numaInterpolateEqxVal(l_float32 startx, l_float32 deltax, NUMA *nay, l_int32 type, l_float32 xval, l_float32 *pyval)
numaInterpolateEqxVal()
Definition: numafunc1.c:1618
l_int32 lept_roundftoi(l_float32 fval)
lept_roundftoi()
Definition: utils1.c:547
NUMA * numaReverse(NUMA *nad, NUMA *nas)
numaReverse()
Definition: numafunc1.c:1274
NUMA ** numaaGetPtrArray(NUMAA *naa)
numaaGetPtrArray()
Definition: numabasic.c:1638
NUMA * numaSortByIndex(NUMA *nas, NUMA *naindex)
numaSortByIndex()
Definition: numafunc1.c:2786
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
NUMA * numaRandomPermutation(NUMA *nas, l_int32 seed)
numaRandomPermutation()
Definition: numafunc1.c:3024
l_ok numaSortPair(NUMA *nax, NUMA *nay, l_int32 sortorder, NUMA **pnasx, NUMA **pnasy)
numaSortPair()
Definition: numafunc1.c:2875
NUMA * numaaFlattenToNuma(NUMAA *naa)
numaaFlattenToNuma()
Definition: numafunc1.c:3467
l_ok numaGetNonzeroRange(NUMA *na, l_float32 eps, l_int32 *pfirst, l_int32 *plast)
numaGetNonzeroRange()
Definition: numafunc1.c:1006
NUMA * numaGetBinSortIndex(NUMA *nas, l_int32 sortorder)
numaGetBinSortIndex()
Definition: numafunc1.c:2713
Definition: pix.h:716
l_int32 numaIsSorted(NUMA *nas, l_int32 sortorder, l_int32 *psorted)
numaIsSorted()
Definition: numafunc1.c:2828
l_int32 nalloc
Definition: array.h:73
l_ok numaGetMedian(NUMA *na, l_float32 *pval)
numaGetMedian()
Definition: numafunc1.c:3135
l_ok numaGetCountRelativeToZero(NUMA *na, l_int32 type, l_int32 *pcount)
numaGetCountRelativeToZero()
Definition: numafunc1.c:1057
NUMA * numaMakeConstant(l_float32 val, l_int32 size)
numaMakeConstant()
Definition: numafunc1.c:781
l_ok numaIntegrateInterval(NUMA *nax, NUMA *nay, l_float32 x0, l_float32 x1, l_int32 npts, l_float32 *psum)
numaIntegrateInterval()
Definition: numafunc1.c:2265
l_float32 startx
Definition: array.h:64
NUMA * numaSort(NUMA *naout, NUMA *nain, l_int32 sortorder)
numaSort()
Definition: numafunc1.c:2547
l_int32 numaChooseSortType(NUMA *nas)
numaChooseSortType()
Definition: numafunc1.c:2496
l_ok numaCountNonzeroRuns(NUMA *na, l_int32 *pcount)
numaCountNonzeroRuns()
Definition: numafunc1.c:967
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_float32 delx
Definition: array.h:65
NUMA * numaThresholdEdges(NUMA *nas, l_float32 thresh1, l_float32 thresh2, l_float32 maxn)
numaThresholdEdges()
Definition: numafunc1.c:1405
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:1525
NUMA * numaClipToInterval(NUMA *nas, l_int32 first, l_int32 last)
numaClipToInterval()
Definition: numafunc1.c:1105
NUMA * numaGetPartialSums(NUMA *na)
numaGetPartialSums()
Definition: numafunc1.c:566
NUMA * numaSubsample(NUMA *nas, l_int32 subfactor)
numaSubsample()
Definition: numafunc1.c:686
NUMA * numaRemoveBorder(NUMA *nas, l_int32 left, l_int32 right)
numaRemoveBorder()
Definition: numafunc1.c:926
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:759
l_ok ptraInsert(L_PTRA *pa, l_int32 index, void *item, l_int32 shiftflag)
ptraInsert()
Definition: ptra.c:336
NUMA * numaUniformSampling(NUMA *nas, l_int32 nsamp)
numaUniformSampling()
Definition: numafunc1.c:1209
NUMA * numaArithOp(NUMA *nad, NUMA *na1, NUMA *na2, l_int32 op)
numaArithOp()
Definition: numafunc1.c:166
NUMA * numaMakeAbsValue(NUMA *nad, NUMA *nas)
numaMakeAbsValue()
Definition: numafunc1.c:797
NUMA * numaPseudorandomSequence(l_int32 size, l_int32 seed)
numaPseudorandomSequence()
Definition: numafunc1.c:2985
NUMA * numaaGetNuma(NUMAA *naa, l_int32 index, l_int32 accessflag)
numaaGetNuma()
Definition: numabasic.c:1659
NUMA * numaMakeDelta(NUMA *nas)
numaMakeDelta()
Definition: numafunc1.c:720
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
Definition: array.h:59
l_ok numaDifferentiateInterval(NUMA *nax, NUMA *nay, l_float32 x0, l_float32 x1, l_int32 npts, NUMA **pnadx, NUMA **pnady)
numaDifferentiateInterval()
Definition: numafunc1.c:2182
L_PTRA * ptraCreate(l_int32 n)
ptraCreate()
Definition: ptra.c:139
l_ok numaInterpolateArbxVal(NUMA *nax, NUMA *nay, l_int32 type, l_float32 xval, l_float32 *pyval)
numaInterpolateArbxVal()
Definition: numafunc1.c:1711
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok numaGetMeanDevFromMedian(NUMA *na, l_float32 med, l_float32 *pdev)
numaGetMeanDevFromMedian()
Definition: numafunc1.c:3195
l_ok numaGetMode(NUMA *na, l_float32 *pval, l_int32 *pcount)
numaGetMode()
Definition: numafunc1.c:3290
l_ok ptraGetMaxIndex(L_PTRA *pa, l_int32 *pmaxindex)
ptraGetMaxIndex()
Definition: ptra.c:699
l_float32 * array
Definition: array.h:66
l_ok 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:1828
Definition: ptra.h:51
NUMA * numaMakeThresholdIndicator(NUMA *nas, l_float32 thresh, l_int32 type)
numaMakeThresholdIndicator()
Definition: numafunc1.c:1153
l_ok numaSetParameters(NUMA *na, l_float32 startx, l_float32 delx)
numaSetParameters()
Definition: numabasic.c:966
l_int32 numaGetEdgeValues(NUMA *na, l_int32 edge, l_int32 *pstart, l_int32 *pend, l_int32 *psign)
numaGetEdgeValues()
Definition: numafunc1.c:1561
l_ok 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:1916
NUMA * numaAddSpecifiedBorder(NUMA *nas, l_int32 left, l_int32 right, l_int32 type)
numaAddSpecifiedBorder()
Definition: numafunc1.c:875
l_ok numaGetParameters(NUMA *na, l_float32 *pstartx, l_float32 *pdelx)
numaGetParameters()
Definition: numabasic.c:936
Definition: array.h:71
NUMA * numaCreateFromIArray(l_int32 *iarray, l_int32 size)
numaCreateFromIArray()
Definition: numabasic.c:228
NUMA * numaMakeSequence(l_float32 startval, l_float32 increment, l_int32 size)
numaMakeSequence()
Definition: numafunc1.c:750
l_ok numaSortGeneral(NUMA *na, NUMA **pnasort, NUMA **pnaindex, NUMA **pnainvert, l_int32 sortorder, l_int32 sorttype)
numaSortGeneral()
Definition: numafunc1.c:2370
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:394
NUMA * numaAddBorder(NUMA *nas, l_int32 left, l_int32 right, l_float32 val)
numaAddBorder()
Definition: numafunc1.c:832
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
l_ok numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
Definition: numafunc1.c:444
void ptraDestroy(L_PTRA **ppa, l_int32 freeflag, l_int32 warnflag)
ptraDestroy()
Definition: ptra.c:185
l_ok numaaJoin(NUMAA *naad, NUMAA *naas, l_int32 istart, l_int32 iend)
numaaJoin()
Definition: numafunc1.c:3419
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3370
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:865
l_int32 numaaGetCount(NUMAA *naa)
numaaGetCount()
Definition: numabasic.c:1550
Definition: pix.h:718
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:246
NUMA * numaSortIndexAutoSelect(NUMA *nas, l_int32 sortorder)
numaSortIndexAutoSelect()
Definition: numafunc1.c:2460
Definition: pix.h:719
l_ok numaGetMedianDevFromMedian(NUMA *na, l_float32 *pmed, l_float32 *pdev)
numaGetMedianDevFromMedian()
Definition: numafunc1.c:3241
l_ok numaReplaceNumber(NUMA *na, l_int32 index, l_float32 val)
numaReplaceNumber()
Definition: numabasic.c:602
NUMA * numaClone(NUMA *na)
numaClone()
Definition: numabasic.c:423
l_int32 numaSimilar(NUMA *na1, NUMA *na2, l_float32 maxdiff, l_int32 *psimilar)
numaSimilar()
Definition: numafunc1.c:364
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:486
l_ok numaGetBinnedMedian(NUMA *na, l_int32 *pval)
numaGetBinnedMedian()
Definition: numafunc1.c:3166
NUMA * numaInvert(NUMA *nad, NUMA *nas)
numaInvert()
Definition: numafunc1.c:319
l_ok numaGetSumOnInterval(NUMA *na, l_int32 first, l_int32 last, l_float32 *psum)
numaGetSumOnInterval()
Definition: numafunc1.c:599
l_ok numaGetRankValue(NUMA *na, l_float32 fract, NUMA *nasort, l_int32 usebins, l_float32 *pval)
numaGetRankValue()
Definition: numafunc1.c:3081
l_ok numaaAddNuma(NUMAA *naa, NUMA *na, l_int32 copyflag)
numaaAddNuma()
Definition: numabasic.c:1482