Leptonica  1.82.0
Image processing and image analysis suite
kernel.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 
27 
83 #ifdef HAVE_CONFIG_H
84 #include <config_auto.h>
85 #endif /* HAVE_CONFIG_H */
86 
87 #include <string.h>
88 #include <math.h>
89 #include "allheaders.h"
90 
91  /* Array size must be > 0 and not larger than this */
92 static const l_uint32 MaxArraySize = 100000;
93 
94 /*------------------------------------------------------------------------*
95  * Create / Destroy *
96  *------------------------------------------------------------------------*/
111 L_KERNEL *
112 kernelCreate(l_int32 height,
113  l_int32 width)
114 {
115 l_uint64 size64;
116 L_KERNEL *kel;
117 
118  PROCNAME("kernelCreate");
119 
120  if (width <= 0)
121  return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
122  if (height <= 0)
123  return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
124 
125  /* Avoid overflow in malloc arg */
126  size64 = (l_uint64)width * (l_uint64)height;
127  if (size64 >= (1LL << 29)) {
128  L_ERROR("requested width = %d, height = %d\n", procName, width, height);
129  return (L_KERNEL *)ERROR_PTR("size >= 2^29", procName, NULL);
130  }
131 
132  kel = (L_KERNEL *)LEPT_CALLOC(1, sizeof(L_KERNEL));
133  kel->sy = height;
134  kel->sx = width;
135  if ((kel->data = create2dFloatArray(height, width)) == NULL) {
136  LEPT_FREE(kel);
137  return (L_KERNEL *)ERROR_PTR("data not allocated", procName, NULL);
138  }
139  return kel;
140 }
141 
142 
149 void
151 {
152 l_int32 i;
153 L_KERNEL *kel;
154 
155  PROCNAME("kernelDestroy");
156 
157  if (pkel == NULL) {
158  L_WARNING("ptr address is NULL!\n", procName);
159  return;
160  }
161  if ((kel = *pkel) == NULL)
162  return;
163 
164  for (i = 0; i < kel->sy; i++)
165  LEPT_FREE(kel->data[i]);
166  LEPT_FREE(kel->data);
167  LEPT_FREE(kel);
168  *pkel = NULL;
169 }
170 
171 
178 L_KERNEL *
180 {
181 l_int32 i, j, sx, sy, cx, cy;
182 L_KERNEL *keld;
183 
184  PROCNAME("kernelCopy");
185 
186  if (!kels)
187  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
188 
189  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
190  if ((keld = kernelCreate(sy, sx)) == NULL)
191  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
192  keld->cy = cy;
193  keld->cx = cx;
194  for (i = 0; i < sy; i++)
195  for (j = 0; j < sx; j++)
196  keld->data[i][j] = kels->data[i][j];
197 
198  return keld;
199 }
200 
201 
202 /*----------------------------------------------------------------------*
203  * Accessors *
204  *----------------------------------------------------------------------*/
214 l_ok
216  l_int32 row,
217  l_int32 col,
218  l_float32 *pval)
219 {
220  PROCNAME("kernelGetElement");
221 
222  if (!pval)
223  return ERROR_INT("&val not defined", procName, 1);
224  *pval = 0;
225  if (!kel)
226  return ERROR_INT("kernel not defined", procName, 1);
227  if (row < 0 || row >= kel->sy)
228  return ERROR_INT("kernel row out of bounds", procName, 1);
229  if (col < 0 || col >= kel->sx)
230  return ERROR_INT("kernel col out of bounds", procName, 1);
231 
232  *pval = kel->data[row][col];
233  return 0;
234 }
235 
236 
246 l_ok
248  l_int32 row,
249  l_int32 col,
250  l_float32 val)
251 {
252  PROCNAME("kernelSetElement");
253 
254  if (!kel)
255  return ERROR_INT("kel not defined", procName, 1);
256  if (row < 0 || row >= kel->sy)
257  return ERROR_INT("kernel row out of bounds", procName, 1);
258  if (col < 0 || col >= kel->sx)
259  return ERROR_INT("kernel col out of bounds", procName, 1);
260 
261  kel->data[row][col] = val;
262  return 0;
263 }
264 
265 
273 l_ok
275  l_int32 *psy,
276  l_int32 *psx,
277  l_int32 *pcy,
278  l_int32 *pcx)
279 {
280  PROCNAME("kernelGetParameters");
281 
282  if (psy) *psy = 0;
283  if (psx) *psx = 0;
284  if (pcy) *pcy = 0;
285  if (pcx) *pcx = 0;
286  if (!kel)
287  return ERROR_INT("kernel not defined", procName, 1);
288  if (psy) *psy = kel->sy;
289  if (psx) *psx = kel->sx;
290  if (pcy) *pcy = kel->cy;
291  if (pcx) *pcx = kel->cx;
292  return 0;
293 }
294 
295 
303 l_ok
305  l_int32 cy,
306  l_int32 cx)
307 {
308  PROCNAME("kernelSetOrigin");
309 
310  if (!kel)
311  return ERROR_INT("kel not defined", procName, 1);
312  kel->cy = cy;
313  kel->cx = cx;
314  return 0;
315 }
316 
317 
325 l_ok
327  l_float32 *psum)
328 {
329 l_int32 sx, sy, i, j;
330 
331  PROCNAME("kernelGetSum");
332 
333  if (!psum)
334  return ERROR_INT("&sum not defined", procName, 1);
335  *psum = 0.0;
336  if (!kel)
337  return ERROR_INT("kernel not defined", procName, 1);
338 
339  kernelGetParameters(kel, &sy, &sx, NULL, NULL);
340  for (i = 0; i < sy; i++) {
341  for (j = 0; j < sx; j++) {
342  *psum += kel->data[i][j];
343  }
344  }
345  return 0;
346 }
347 
348 
357 l_ok
359  l_float32 *pmin,
360  l_float32 *pmax)
361 {
362 l_int32 sx, sy, i, j;
363 l_float32 val, minval, maxval;
364 
365  PROCNAME("kernelGetMinmax");
366 
367  if (!pmin && !pmax)
368  return ERROR_INT("neither &min nor &max defined", procName, 1);
369  if (pmin) *pmin = 0.0;
370  if (pmax) *pmax = 0.0;
371  if (!kel)
372  return ERROR_INT("kernel not defined", procName, 1);
373 
374  kernelGetParameters(kel, &sy, &sx, NULL, NULL);
375  minval = 10000000.0;
376  maxval = -10000000.0;
377  for (i = 0; i < sy; i++) {
378  for (j = 0; j < sx; j++) {
379  val = kel->data[i][j];
380  if (val < minval)
381  minval = val;
382  if (val > maxval)
383  maxval = val;
384  }
385  }
386  if (pmin)
387  *pmin = minval;
388  if (pmax)
389  *pmax = maxval;
390 
391  return 0;
392 }
393 
394 
395 /*----------------------------------------------------------------------*
396  * Normalize/Invert *
397  *----------------------------------------------------------------------*/
413 L_KERNEL *
415  l_float32 normsum)
416 {
417 l_int32 i, j, sx, sy, cx, cy;
418 l_float32 sum, factor;
419 L_KERNEL *keld;
420 
421  PROCNAME("kernelNormalize");
422 
423  if (!kels)
424  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
425 
426  kernelGetSum(kels, &sum);
427  if (L_ABS(sum) < 0.00001) {
428  L_WARNING("null sum; not normalizing; returning a copy\n", procName);
429  return kernelCopy(kels);
430  }
431 
432  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
433  if ((keld = kernelCreate(sy, sx)) == NULL)
434  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
435  keld->cy = cy;
436  keld->cx = cx;
437 
438  factor = normsum / sum;
439  for (i = 0; i < sy; i++)
440  for (j = 0; j < sx; j++)
441  keld->data[i][j] = factor * kels->data[i][j];
442 
443  return keld;
444 }
445 
446 
459 L_KERNEL *
461 {
462 l_int32 i, j, sx, sy, cx, cy;
463 L_KERNEL *keld;
464 
465  PROCNAME("kernelInvert");
466 
467  if (!kels)
468  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
469 
470  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
471  if ((keld = kernelCreate(sy, sx)) == NULL)
472  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
473  keld->cy = sy - 1 - cy;
474  keld->cx = sx - 1 - cx;
475 
476  for (i = 0; i < sy; i++)
477  for (j = 0; j < sx; j++)
478  keld->data[i][j] = kels->data[sy - 1 - i][sx - 1 - j];
479 
480  return keld;
481 }
482 
483 
484 /*----------------------------------------------------------------------*
485  * Helper function *
486  *----------------------------------------------------------------------*/
502 l_float32 **
504  l_int32 sx)
505 {
506 l_int32 i;
507 l_float32 **array;
508 
509  PROCNAME("create2dFloatArray");
510 
511  if (sx <= 0 || sx > MaxArraySize)
512  return (l_float32 **)ERROR_PTR("sx out of bounds", procName, NULL);
513  if (sy <= 0 || sy > MaxArraySize)
514  return (l_float32 **)ERROR_PTR("sy out of bounds", procName, NULL);
515 
516  array = (l_float32 **)LEPT_CALLOC(sy, sizeof(l_float32 *));
517  for (i = 0; i < sy; i++)
518  array[i] = (l_float32 *)LEPT_CALLOC(sx, sizeof(l_float32));
519  return array;
520 }
521 
522 
523 /*----------------------------------------------------------------------*
524  * Kernel serialized I/O *
525  *----------------------------------------------------------------------*/
532 L_KERNEL *
533 kernelRead(const char *fname)
534 {
535 FILE *fp;
536 L_KERNEL *kel;
537 
538  PROCNAME("kernelRead");
539 
540  if (!fname)
541  return (L_KERNEL *)ERROR_PTR("fname not defined", procName, NULL);
542 
543  if ((fp = fopenReadStream(fname)) == NULL)
544  return (L_KERNEL *)ERROR_PTR("stream not opened", procName, NULL);
545  if ((kel = kernelReadStream(fp)) == NULL) {
546  fclose(fp);
547  return (L_KERNEL *)ERROR_PTR("kel not returned", procName, NULL);
548  }
549  fclose(fp);
550 
551  return kel;
552 }
553 
554 
561 L_KERNEL *
563 {
564 l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
565 L_KERNEL *kel;
566 
567  PROCNAME("kernelReadStream");
568 
569  if (!fp)
570  return (L_KERNEL *)ERROR_PTR("stream not defined", procName, NULL);
571 
572  ret = fscanf(fp, " Kernel Version %d\n", &version);
573  if (ret != 1)
574  return (L_KERNEL *)ERROR_PTR("not a kernel file", procName, NULL);
575  if (version != KERNEL_VERSION_NUMBER)
576  return (L_KERNEL *)ERROR_PTR("invalid kernel version", procName, NULL);
577 
578  if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n",
579  &sy, &sx, &cy, &cx) != 4)
580  return (L_KERNEL *)ERROR_PTR("dimensions not read", procName, NULL);
581  if (sx > MaxArraySize || sy > MaxArraySize) {
582  L_ERROR("sx = %d or sy = %d > %d\n", procName, sx, sy, MaxArraySize);
583  return NULL;
584  }
585  if ((kel = kernelCreate(sy, sx)) == NULL)
586  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
587  kernelSetOrigin(kel, cy, cx);
588 
589  for (i = 0; i < sy; i++) {
590  for (j = 0; j < sx; j++)
591  ignore = fscanf(fp, "%15f", &kel->data[i][j]);
592  ignore = fscanf(fp, "\n");
593  }
594  ignore = fscanf(fp, "\n");
595 
596  return kel;
597 }
598 
599 
607 l_ok
608 kernelWrite(const char *fname,
609  L_KERNEL *kel)
610 {
611 FILE *fp;
612 
613  PROCNAME("kernelWrite");
614 
615  if (!fname)
616  return ERROR_INT("fname not defined", procName, 1);
617  if (!kel)
618  return ERROR_INT("kel not defined", procName, 1);
619 
620  if ((fp = fopenWriteStream(fname, "wb")) == NULL)
621  return ERROR_INT("stream not opened", procName, 1);
622  kernelWriteStream(fp, kel);
623  fclose(fp);
624 
625  return 0;
626 }
627 
628 
636 l_ok
638  L_KERNEL *kel)
639 {
640 l_int32 sx, sy, cx, cy, i, j;
641 
642  PROCNAME("kernelWriteStream");
643 
644  if (!fp)
645  return ERROR_INT("stream not defined", procName, 1);
646  if (!kel)
647  return ERROR_INT("kel not defined", procName, 1);
648  kernelGetParameters(kel, &sy, &sx, &cy, &cx);
649 
650  fprintf(fp, " Kernel Version %d\n", KERNEL_VERSION_NUMBER);
651  fprintf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", sy, sx, cy, cx);
652  for (i = 0; i < sy; i++) {
653  for (j = 0; j < sx; j++)
654  fprintf(fp, "%15.4f", kel->data[i][j]);
655  fprintf(fp, "\n");
656  }
657  fprintf(fp, "\n");
658 
659  return 0;
660 }
661 
662 
663 /*----------------------------------------------------------------------*
664  * Making a kernel from a compiled string *
665  *----------------------------------------------------------------------*/
688 L_KERNEL *
690  l_int32 w,
691  l_int32 cy,
692  l_int32 cx,
693  const char *kdata)
694 {
695 l_int32 n, i, j, index;
696 l_float32 val;
697 L_KERNEL *kel;
698 NUMA *na;
699 
700  PROCNAME("kernelCreateFromString");
701 
702  if (h < 1)
703  return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
704  if (w < 1)
705  return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
706  if (cy < 0 || cy >= h)
707  return (L_KERNEL *)ERROR_PTR("cy invalid", procName, NULL);
708  if (cx < 0 || cx >= w)
709  return (L_KERNEL *)ERROR_PTR("cx invalid", procName, NULL);
710 
711  kel = kernelCreate(h, w);
712  kernelSetOrigin(kel, cy, cx);
713  na = parseStringForNumbers(kdata, " \t\n");
714  n = numaGetCount(na);
715  if (n != w * h) {
716  kernelDestroy(&kel);
717  numaDestroy(&na);
718  lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
719  return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
720  }
721 
722  index = 0;
723  for (i = 0; i < h; i++) {
724  for (j = 0; j < w; j++) {
725  numaGetFValue(na, index, &val);
726  kernelSetElement(kel, i, j, val);
727  index++;
728  }
729  }
730 
731  numaDestroy(&na);
732  return kel;
733 }
734 
735 
736 /*----------------------------------------------------------------------*
737  * Making a kernel from a simple file format *
738  *----------------------------------------------------------------------*/
774 L_KERNEL *
775 kernelCreateFromFile(const char *filename)
776 {
777 char *filestr, *line;
778 l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
779 l_float32 val;
780 size_t size;
781 NUMA *na, *nat;
782 SARRAY *sa;
783 L_KERNEL *kel;
784 
785  PROCNAME("kernelCreateFromFile");
786 
787  if (!filename)
788  return (L_KERNEL *)ERROR_PTR("filename not defined", procName, NULL);
789 
790  if ((filestr = (char *)l_binaryRead(filename, &size)) == NULL)
791  return (L_KERNEL *)ERROR_PTR("file not found", procName, NULL);
792  if (size == 0) {
793  LEPT_FREE(filestr);
794  return (L_KERNEL *)ERROR_PTR("file is empty", procName, NULL);
795  }
796 
797  sa = sarrayCreateLinesFromString(filestr, 1);
798  LEPT_FREE(filestr);
799  nlines = sarrayGetCount(sa);
800 
801  /* Find the first data line. */
802  for (i = 0, first = 0; i < nlines; i++) {
803  line = sarrayGetString(sa, i, L_NOCOPY);
804  if (line[0] != '#') {
805  first = i;
806  break;
807  }
808  }
809 
810  /* Find the kernel dimensions and origin location. */
811  line = sarrayGetString(sa, first, L_NOCOPY);
812  if (sscanf(line, "%d %d", &h, &w) != 2) {
813  sarrayDestroy(&sa);
814  return (L_KERNEL *)ERROR_PTR("error reading h,w", procName, NULL);
815  }
816  if (h > MaxArraySize || w > MaxArraySize) {
817  L_ERROR("h = %d or w = %d > %d\n", procName, h, w, MaxArraySize);
818  sarrayDestroy(&sa);
819  return NULL;
820  }
821  line = sarrayGetString(sa, first + 1, L_NOCOPY);
822  if (sscanf(line, "%d %d", &cy, &cx) != 2) {
823  sarrayDestroy(&sa);
824  return (L_KERNEL *)ERROR_PTR("error reading cy,cx", procName, NULL);
825  }
826 
827  /* Extract the data. This ends when we reach eof, or when we
828  * encounter a line of data that is either a null string or
829  * contains just a newline. */
830  na = numaCreate(0);
831  for (i = first + 2; i < nlines; i++) {
832  line = sarrayGetString(sa, i, L_NOCOPY);
833  if (line[0] == '\0' || line[0] == '\n' || line[0] == '#')
834  break;
835  nat = parseStringForNumbers(line, " \t\n");
836  numaJoin(na, nat, 0, -1);
837  numaDestroy(&nat);
838  }
839  sarrayDestroy(&sa);
840 
841  n = numaGetCount(na);
842  if (n != w * h) {
843  numaDestroy(&na);
844  lept_stderr("w = %d, h = %d, num ints = %d\n", w, h, n);
845  return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
846  }
847 
848  kel = kernelCreate(h, w);
849  kernelSetOrigin(kel, cy, cx);
850  index = 0;
851  for (i = 0; i < h; i++) {
852  for (j = 0; j < w; j++) {
853  numaGetFValue(na, index, &val);
854  kernelSetElement(kel, i, j, val);
855  index++;
856  }
857  }
858 
859  numaDestroy(&na);
860  return kel;
861 }
862 
863 
864 /*----------------------------------------------------------------------*
865  * Making a kernel from a Pix *
866  *----------------------------------------------------------------------*/
879 L_KERNEL *
881  l_int32 cy,
882  l_int32 cx)
883 {
884 l_int32 i, j, w, h, d;
885 l_uint32 val;
886 L_KERNEL *kel;
887 
888  PROCNAME("kernelCreateFromPix");
889 
890  if (!pix)
891  return (L_KERNEL *)ERROR_PTR("pix not defined", procName, NULL);
892  pixGetDimensions(pix, &w, &h, &d);
893  if (d != 8)
894  return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", procName, NULL);
895  if (cy < 0 || cx < 0 || cy >= h || cx >= w)
896  return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", procName, NULL);
897 
898  kel = kernelCreate(h, w);
899  kernelSetOrigin(kel, cy, cx);
900  for (i = 0; i < h; i++) {
901  for (j = 0; j < w; j++) {
902  pixGetPixel(pix, j, i, &val);
903  kernelSetElement(kel, i, j, (l_float32)val);
904  }
905  }
906 
907  return kel;
908 }
909 
910 
911 /*----------------------------------------------------------------------*
912  * Display a kernel in a pix *
913  *----------------------------------------------------------------------*/
940 PIX *
942  l_int32 size,
943  l_int32 gthick)
944 {
945 l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
946 l_int32 normval;
947 l_float32 minval, maxval, max, val, norm;
948 PIX *pixd, *pixt0, *pixt1;
949 
950  PROCNAME("kernelDisplayInPix");
951 
952  if (!kel)
953  return (PIX *)ERROR_PTR("kernel not defined", procName, NULL);
954 
955  /* Normalize the max value to be 255 for display */
956  kernelGetParameters(kel, &sy, &sx, &cy, &cx);
957  kernelGetMinMax(kel, &minval, &maxval);
958  max = L_MAX(maxval, -minval);
959  if (max == 0.0)
960  return (PIX *)ERROR_PTR("kernel elements all 0.0", procName, NULL);
961  norm = 255. / (l_float32)max;
962 
963  /* Handle the 1 element/pixel case; typically with large kernels */
964  if (size == 1 && gthick == 0) {
965  pixd = pixCreate(sx, sy, 8);
966  for (i = 0; i < sy; i++) {
967  for (j = 0; j < sx; j++) {
968  kernelGetElement(kel, i, j, &val);
969  normval = (l_int32)(norm * L_ABS(val));
970  pixSetPixel(pixd, j, i, normval);
971  }
972  }
973  return pixd;
974  }
975 
976  /* Enforce the constraints for the grid line version */
977  if (size < 17) {
978  L_WARNING("size < 17; setting to 17\n", procName);
979  size = 17;
980  }
981  if (size % 2 == 0)
982  size++;
983  if (gthick < 2) {
984  L_WARNING("grid thickness < 2; setting to 2\n", procName);
985  gthick = 2;
986  }
987 
988  w = size * sx + gthick * (sx + 1);
989  h = size * sy + gthick * (sy + 1);
990  pixd = pixCreate(w, h, 8);
991 
992  /* Generate grid lines */
993  for (i = 0; i <= sy; i++)
994  pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
995  w - 1, gthick / 2 + i * (size + gthick),
996  gthick, L_SET_PIXELS);
997  for (j = 0; j <= sx; j++)
998  pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
999  gthick / 2 + j * (size + gthick), h - 1,
1000  gthick, L_SET_PIXELS);
1001 
1002  /* Generate mask for each element */
1003  pixt0 = pixCreate(size, size, 1);
1004  pixSetAll(pixt0);
1005 
1006  /* Generate crossed lines for origin pattern */
1007  pixt1 = pixCreate(size, size, 1);
1008  width = size / 8;
1009  pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
1010  size / 2, (l_int32)(0.88 * size),
1011  width, L_SET_PIXELS);
1012  pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
1013  (l_int32)(0.85 * size), size / 2,
1014  width, L_FLIP_PIXELS);
1015  pixRasterop(pixt1, size / 2 - width, size / 2 - width,
1016  2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);
1017 
1018  /* Paste the patterns in */
1019  y0 = gthick;
1020  for (i = 0; i < sy; i++) {
1021  x0 = gthick;
1022  for (j = 0; j < sx; j++) {
1023  kernelGetElement(kel, i, j, &val);
1024  normval = (l_int32)(norm * L_ABS(val));
1025  pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
1026  if (i == cy && j == cx)
1027  pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
1028  x0 += size + gthick;
1029  }
1030  y0 += size + gthick;
1031  }
1032 
1033  pixDestroy(&pixt0);
1034  pixDestroy(&pixt1);
1035  return pixd;
1036 }
1037 
1038 
1039 /*------------------------------------------------------------------------*
1040  * Parse string to extract numbers *
1041  *------------------------------------------------------------------------*/
1054 NUMA *
1055 parseStringForNumbers(const char *str,
1056  const char *seps)
1057 {
1058 char *newstr, *head;
1059 char *tail = NULL;
1060 l_float32 val;
1061 NUMA *na;
1062 
1063  PROCNAME("parseStringForNumbers");
1064 
1065  if (!str)
1066  return (NUMA *)ERROR_PTR("str not defined", procName, NULL);
1067 
1068  newstr = stringNew(str); /* to enforce const-ness of str */
1069  na = numaCreate(0);
1070  head = strtokSafe(newstr, seps, &tail);
1071  val = atof(head);
1072  numaAddNumber(na, val);
1073  LEPT_FREE(head);
1074  while ((head = strtokSafe(NULL, seps, &tail)) != NULL) {
1075  val = atof(head);
1076  numaAddNumber(na, val);
1077  LEPT_FREE(head);
1078  }
1079 
1080  LEPT_FREE(newstr);
1081  return na;
1082 }
1083 
1084 
1085 /*------------------------------------------------------------------------*
1086  * Simple parametric kernels *
1087  *------------------------------------------------------------------------*/
1106 L_KERNEL *
1107 makeFlatKernel(l_int32 height,
1108  l_int32 width,
1109  l_int32 cy,
1110  l_int32 cx)
1111 {
1112 l_int32 i, j;
1113 l_float32 normval;
1114 L_KERNEL *kel;
1115 
1116  PROCNAME("makeFlatKernel");
1117 
1118  if ((kel = kernelCreate(height, width)) == NULL)
1119  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1120  kernelSetOrigin(kel, cy, cx);
1121  normval = 1.0 / (l_float32)(height * width);
1122  for (i = 0; i < height; i++) {
1123  for (j = 0; j < width; j++) {
1124  kernelSetElement(kel, i, j, normval);
1125  }
1126  }
1127 
1128  return kel;
1129 }
1130 
1131 
1152 L_KERNEL *
1153 makeGaussianKernel(l_int32 halfh,
1154  l_int32 halfw,
1155  l_float32 stdev,
1156  l_float32 max)
1157 {
1158 l_int32 sx, sy, i, j;
1159 l_float32 val;
1160 L_KERNEL *kel;
1161 
1162  PROCNAME("makeGaussianKernel");
1163 
1164  sx = 2 * halfw + 1;
1165  sy = 2 * halfh + 1;
1166  if ((kel = kernelCreate(sy, sx)) == NULL)
1167  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1168  kernelSetOrigin(kel, halfh, halfw);
1169  for (i = 0; i < sy; i++) {
1170  for (j = 0; j < sx; j++) {
1171  val = expf(-(l_float32)((i - halfh) * (i - halfh) +
1172  (j - halfw) * (j - halfw)) /
1173  (2. * stdev * stdev));
1174  kernelSetElement(kel, i, j, max * val);
1175  }
1176  }
1177 
1178  return kel;
1179 }
1180 
1181 
1207 l_ok
1209  l_int32 halfw,
1210  l_float32 stdev,
1211  l_float32 max,
1212  L_KERNEL **pkelx,
1213  L_KERNEL **pkely)
1214 {
1215  PROCNAME("makeGaussianKernelSep");
1216 
1217  if (!pkelx || !pkely)
1218  return ERROR_INT("&kelx and &kely not defined", procName, 1);
1219 
1220  *pkelx = makeGaussianKernel(0, halfw, stdev, max);
1221  *pkely = makeGaussianKernel(halfh, 0, stdev, 1.0);
1222  return 0;
1223 }
1224 
1225 
1253 L_KERNEL *
1254 makeDoGKernel(l_int32 halfh,
1255  l_int32 halfw,
1256  l_float32 stdev,
1257  l_float32 ratio)
1258 {
1259 l_int32 sx, sy, i, j;
1260 l_float32 pi, squaredist, highnorm, lownorm, val;
1261 L_KERNEL *kel;
1262 
1263  PROCNAME("makeDoGKernel");
1264 
1265  sx = 2 * halfw + 1;
1266  sy = 2 * halfh + 1;
1267  if ((kel = kernelCreate(sy, sx)) == NULL)
1268  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1269  kernelSetOrigin(kel, halfh, halfw);
1270 
1271  pi = 3.1415926535;
1272  for (i = 0; i < sy; i++) {
1273  for (j = 0; j < sx; j++) {
1274  squaredist = (l_float32)((i - halfh) * (i - halfh) +
1275  (j - halfw) * (j - halfw));
1276  highnorm = 1. / (2 * stdev * stdev);
1277  lownorm = highnorm / (ratio * ratio);
1278  val = (highnorm / pi) * expf(-(highnorm * squaredist))
1279  - (lownorm / pi) * expf(-(lownorm * squaredist));
1280  kernelSetElement(kel, i, j, val);
1281  }
1282  }
1283 
1284  return kel;
1285 }
l_ok pixRenderLine(PIX *pix, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2, l_int32 width, l_int32 op)
pixRenderLine()
Definition: graphics.c:1496
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition: kernel.c:533
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:358
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:460
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1107
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:150
l_ok kernelWrite(const char *fname, L_KERNEL *kel)
kernelWrite()
Definition: kernel.c:608
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:304
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition: kernel.c:112
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition: kernel.c:274
l_ok kernelGetSum(L_KERNEL *kel, l_float32 *psum)
kernelGetSum()
Definition: kernel.c:326
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1055
L_KERNEL * makeGaussianKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1153
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:414
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition: kernel.c:637
L_KERNEL * makeDoGKernel(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition: kernel.c:1254
PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick)
kernelDisplayInPix()
Definition: kernel.c:941
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:247
l_float32 ** create2dFloatArray(l_int32 sy, l_int32 sx)
create2dFloatArray()
Definition: kernel.c:503
l_ok kernelGetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 *pval)
kernelGetElement()
Definition: kernel.c:215
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:179
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition: kernel.c:562
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition: kernel.c:880
l_ok makeGaussianKernelSep(l_int32 halfh, l_int32 halfw, l_float32 stdev, l_float32 max, L_KERNEL **pkelx, L_KERNEL **pkely)
makeGaussianKernelSep()
Definition: kernel.c:1208
L_KERNEL * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata)
kernelCreateFromString()
Definition: kernel.c:689
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition: kernel.c:775
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3640
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:817
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition: pix3.c:302
#define PIX_DST
Definition: pix.h:331
@ L_FLIP_PIXELS
Definition: pix.h:774
@ L_SET_PIXELS
Definition: pix.h:772
@ L_NOCOPY
Definition: pix.h:710
#define PIX_NOT(op)
Definition: pix.h:332
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:283
Definition: morph.h:89
l_int32 cx
Definition: morph.h:93
l_int32 sx
Definition: morph.h:91
l_int32 cy
Definition: morph.h:92
l_float32 ** data
Definition: morph.h:94
l_int32 sy
Definition: morph.h:90
Definition: array.h:71
Definition: pix.h:139
Definition: array.h:127
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:223
char * strtokSafe(char *cstr, const char *seps, char **psaveptr)
strtokSafe()
Definition: utils2.c:649
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1975
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1932
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1352