Leptonica  1.77.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 #include <string.h>
84 #include <math.h>
85 #include "allheaders.h"
86 
87 
88 /*------------------------------------------------------------------------*
89  * Create / Destroy *
90  *------------------------------------------------------------------------*/
105 L_KERNEL *
106 kernelCreate(l_int32 height,
107  l_int32 width)
108 {
109 l_uint64 size64;
110 L_KERNEL *kel;
111 
112  PROCNAME("kernelCreate");
113 
114  if (width <= 0)
115  return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
116  if (height <= 0)
117  return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
118 
119  /* Avoid overflow in malloc arg */
120  size64 = (l_uint64)width * (l_uint64)height;
121  if (size64 >= (1LL << 29)) {
122  L_ERROR("requested width = %d, height = %d\n", procName, width, height);
123  return (L_KERNEL *)ERROR_PTR("size >= 2^29", procName, NULL);
124  }
125 
126  kel = (L_KERNEL *)LEPT_CALLOC(1, sizeof(L_KERNEL));
127  kel->sy = height;
128  kel->sx = width;
129  if ((kel->data = create2dFloatArray(height, width)) == NULL) {
130  LEPT_FREE(kel);
131  return (L_KERNEL *)ERROR_PTR("data not allocated", procName, NULL);
132  }
133  return kel;
134 }
135 
136 
143 void
145 {
146 l_int32 i;
147 L_KERNEL *kel;
148 
149  PROCNAME("kernelDestroy");
150 
151  if (pkel == NULL) {
152  L_WARNING("ptr address is NULL!\n", procName);
153  return;
154  }
155  if ((kel = *pkel) == NULL)
156  return;
157 
158  for (i = 0; i < kel->sy; i++)
159  LEPT_FREE(kel->data[i]);
160  LEPT_FREE(kel->data);
161  LEPT_FREE(kel);
162 
163  *pkel = NULL;
164  return;
165 }
166 
167 
174 L_KERNEL *
176 {
177 l_int32 i, j, sx, sy, cx, cy;
178 L_KERNEL *keld;
179 
180  PROCNAME("kernelCopy");
181 
182  if (!kels)
183  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
184 
185  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
186  if ((keld = kernelCreate(sy, sx)) == NULL)
187  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
188  keld->cy = cy;
189  keld->cx = cx;
190  for (i = 0; i < sy; i++)
191  for (j = 0; j < sx; j++)
192  keld->data[i][j] = kels->data[i][j];
193 
194  return keld;
195 }
196 
197 
198 /*----------------------------------------------------------------------*
199  * Accessors *
200  *----------------------------------------------------------------------*/
210 l_ok
212  l_int32 row,
213  l_int32 col,
214  l_float32 *pval)
215 {
216  PROCNAME("kernelGetElement");
217 
218  if (!pval)
219  return ERROR_INT("&val not defined", procName, 1);
220  *pval = 0;
221  if (!kel)
222  return ERROR_INT("kernel not defined", procName, 1);
223  if (row < 0 || row >= kel->sy)
224  return ERROR_INT("kernel row out of bounds", procName, 1);
225  if (col < 0 || col >= kel->sx)
226  return ERROR_INT("kernel col out of bounds", procName, 1);
227 
228  *pval = kel->data[row][col];
229  return 0;
230 }
231 
232 
242 l_ok
244  l_int32 row,
245  l_int32 col,
246  l_float32 val)
247 {
248  PROCNAME("kernelSetElement");
249 
250  if (!kel)
251  return ERROR_INT("kel not defined", procName, 1);
252  if (row < 0 || row >= kel->sy)
253  return ERROR_INT("kernel row out of bounds", procName, 1);
254  if (col < 0 || col >= kel->sx)
255  return ERROR_INT("kernel col out of bounds", procName, 1);
256 
257  kel->data[row][col] = val;
258  return 0;
259 }
260 
261 
269 l_ok
271  l_int32 *psy,
272  l_int32 *psx,
273  l_int32 *pcy,
274  l_int32 *pcx)
275 {
276  PROCNAME("kernelGetParameters");
277 
278  if (psy) *psy = 0;
279  if (psx) *psx = 0;
280  if (pcy) *pcy = 0;
281  if (pcx) *pcx = 0;
282  if (!kel)
283  return ERROR_INT("kernel not defined", procName, 1);
284  if (psy) *psy = kel->sy;
285  if (psx) *psx = kel->sx;
286  if (pcy) *pcy = kel->cy;
287  if (pcx) *pcx = kel->cx;
288  return 0;
289 }
290 
291 
299 l_ok
301  l_int32 cy,
302  l_int32 cx)
303 {
304  PROCNAME("kernelSetOrigin");
305 
306  if (!kel)
307  return ERROR_INT("kel not defined", procName, 1);
308  kel->cy = cy;
309  kel->cx = cx;
310  return 0;
311 }
312 
313 
321 l_ok
323  l_float32 *psum)
324 {
325 l_int32 sx, sy, i, j;
326 
327  PROCNAME("kernelGetSum");
328 
329  if (!psum)
330  return ERROR_INT("&sum not defined", procName, 1);
331  *psum = 0.0;
332  if (!kel)
333  return ERROR_INT("kernel not defined", procName, 1);
334 
335  kernelGetParameters(kel, &sy, &sx, NULL, NULL);
336  for (i = 0; i < sy; i++) {
337  for (j = 0; j < sx; j++) {
338  *psum += kel->data[i][j];
339  }
340  }
341  return 0;
342 }
343 
344 
353 l_ok
355  l_float32 *pmin,
356  l_float32 *pmax)
357 {
358 l_int32 sx, sy, i, j;
359 l_float32 val, minval, maxval;
360 
361  PROCNAME("kernelGetMinmax");
362 
363  if (!pmin && !pmax)
364  return ERROR_INT("neither &min nor &max defined", procName, 1);
365  if (pmin) *pmin = 0.0;
366  if (pmax) *pmax = 0.0;
367  if (!kel)
368  return ERROR_INT("kernel not defined", procName, 1);
369 
370  kernelGetParameters(kel, &sy, &sx, NULL, NULL);
371  minval = 10000000.0;
372  maxval = -10000000.0;
373  for (i = 0; i < sy; i++) {
374  for (j = 0; j < sx; j++) {
375  val = kel->data[i][j];
376  if (val < minval)
377  minval = val;
378  if (val > maxval)
379  maxval = val;
380  }
381  }
382  if (pmin)
383  *pmin = minval;
384  if (pmax)
385  *pmax = maxval;
386 
387  return 0;
388 }
389 
390 
391 /*----------------------------------------------------------------------*
392  * Normalize/Invert *
393  *----------------------------------------------------------------------*/
409 L_KERNEL *
411  l_float32 normsum)
412 {
413 l_int32 i, j, sx, sy, cx, cy;
414 l_float32 sum, factor;
415 L_KERNEL *keld;
416 
417  PROCNAME("kernelNormalize");
418 
419  if (!kels)
420  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
421 
422  kernelGetSum(kels, &sum);
423  if (L_ABS(sum) < 0.00001) {
424  L_WARNING("null sum; not normalizing; returning a copy\n", procName);
425  return kernelCopy(kels);
426  }
427 
428  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
429  if ((keld = kernelCreate(sy, sx)) == NULL)
430  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
431  keld->cy = cy;
432  keld->cx = cx;
433 
434  factor = normsum / sum;
435  for (i = 0; i < sy; i++)
436  for (j = 0; j < sx; j++)
437  keld->data[i][j] = factor * kels->data[i][j];
438 
439  return keld;
440 }
441 
442 
455 L_KERNEL *
457 {
458 l_int32 i, j, sx, sy, cx, cy;
459 L_KERNEL *keld;
460 
461  PROCNAME("kernelInvert");
462 
463  if (!kels)
464  return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL);
465 
466  kernelGetParameters(kels, &sy, &sx, &cy, &cx);
467  if ((keld = kernelCreate(sy, sx)) == NULL)
468  return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL);
469  keld->cy = sy - 1 - cy;
470  keld->cx = sx - 1 - cx;
471 
472  for (i = 0; i < sy; i++)
473  for (j = 0; j < sx; j++)
474  keld->data[i][j] = kels->data[sy - 1 - i][sx - 1 - j];
475 
476  return keld;
477 }
478 
479 
480 /*----------------------------------------------------------------------*
481  * Helper function *
482  *----------------------------------------------------------------------*/
498 l_float32 **
500  l_int32 sx)
501 {
502 l_int32 i;
503 l_float32 **array;
504 
505  PROCNAME("create2dFloatArray");
506 
507  if ((array = (l_float32 **)LEPT_CALLOC(sy, sizeof(l_float32 *))) == NULL)
508  return (l_float32 **)ERROR_PTR("ptr array not made", procName, NULL);
509 
510  for (i = 0; i < sy; i++)
511  array[i] = (l_float32 *)LEPT_CALLOC(sx, sizeof(l_float32));
512  return array;
513 }
514 
515 
516 /*----------------------------------------------------------------------*
517  * Kernel serialized I/O *
518  *----------------------------------------------------------------------*/
525 L_KERNEL *
526 kernelRead(const char *fname)
527 {
528 FILE *fp;
529 L_KERNEL *kel;
530 
531  PROCNAME("kernelRead");
532 
533  if (!fname)
534  return (L_KERNEL *)ERROR_PTR("fname not defined", procName, NULL);
535 
536  if ((fp = fopenReadStream(fname)) == NULL)
537  return (L_KERNEL *)ERROR_PTR("stream not opened", procName, NULL);
538  if ((kel = kernelReadStream(fp)) == NULL) {
539  fclose(fp);
540  return (L_KERNEL *)ERROR_PTR("kel not returned", procName, NULL);
541  }
542  fclose(fp);
543 
544  return kel;
545 }
546 
547 
554 L_KERNEL *
556 {
557 l_int32 sy, sx, cy, cx, i, j, ret, version, ignore;
558 L_KERNEL *kel;
559 
560  PROCNAME("kernelReadStream");
561 
562  if (!fp)
563  return (L_KERNEL *)ERROR_PTR("stream not defined", procName, NULL);
564 
565  ret = fscanf(fp, " Kernel Version %d\n", &version);
566  if (ret != 1)
567  return (L_KERNEL *)ERROR_PTR("not a kernel file", procName, NULL);
568  if (version != KERNEL_VERSION_NUMBER)
569  return (L_KERNEL *)ERROR_PTR("invalid kernel version", procName, NULL);
570 
571  if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n",
572  &sy, &sx, &cy, &cx) != 4)
573  return (L_KERNEL *)ERROR_PTR("dimensions not read", procName, NULL);
574 
575  if ((kel = kernelCreate(sy, sx)) == NULL)
576  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
577  kernelSetOrigin(kel, cy, cx);
578 
579  for (i = 0; i < sy; i++) {
580  for (j = 0; j < sx; j++)
581  ignore = fscanf(fp, "%15f", &kel->data[i][j]);
582  ignore = fscanf(fp, "\n");
583  }
584  ignore = fscanf(fp, "\n");
585 
586  return kel;
587 }
588 
589 
597 l_ok
598 kernelWrite(const char *fname,
599  L_KERNEL *kel)
600 {
601 FILE *fp;
602 
603  PROCNAME("kernelWrite");
604 
605  if (!fname)
606  return ERROR_INT("fname not defined", procName, 1);
607  if (!kel)
608  return ERROR_INT("kel not defined", procName, 1);
609 
610  if ((fp = fopenWriteStream(fname, "wb")) == NULL)
611  return ERROR_INT("stream not opened", procName, 1);
612  kernelWriteStream(fp, kel);
613  fclose(fp);
614 
615  return 0;
616 }
617 
618 
626 l_ok
628  L_KERNEL *kel)
629 {
630 l_int32 sx, sy, cx, cy, i, j;
631 
632  PROCNAME("kernelWriteStream");
633 
634  if (!fp)
635  return ERROR_INT("stream not defined", procName, 1);
636  if (!kel)
637  return ERROR_INT("kel not defined", procName, 1);
638  kernelGetParameters(kel, &sy, &sx, &cy, &cx);
639 
640  fprintf(fp, " Kernel Version %d\n", KERNEL_VERSION_NUMBER);
641  fprintf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", sy, sx, cy, cx);
642  for (i = 0; i < sy; i++) {
643  for (j = 0; j < sx; j++)
644  fprintf(fp, "%15.4f", kel->data[i][j]);
645  fprintf(fp, "\n");
646  }
647  fprintf(fp, "\n");
648 
649  return 0;
650 }
651 
652 
653 /*----------------------------------------------------------------------*
654  * Making a kernel from a compiled string *
655  *----------------------------------------------------------------------*/
678 L_KERNEL *
680  l_int32 w,
681  l_int32 cy,
682  l_int32 cx,
683  const char *kdata)
684 {
685 l_int32 n, i, j, index;
686 l_float32 val;
687 L_KERNEL *kel;
688 NUMA *na;
689 
690  PROCNAME("kernelCreateFromString");
691 
692  if (h < 1)
693  return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL);
694  if (w < 1)
695  return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL);
696  if (cy < 0 || cy >= h)
697  return (L_KERNEL *)ERROR_PTR("cy invalid", procName, NULL);
698  if (cx < 0 || cx >= w)
699  return (L_KERNEL *)ERROR_PTR("cx invalid", procName, NULL);
700 
701  kel = kernelCreate(h, w);
702  kernelSetOrigin(kel, cy, cx);
703  na = parseStringForNumbers(kdata, " \t\n");
704  n = numaGetCount(na);
705  if (n != w * h) {
706  kernelDestroy(&kel);
707  numaDestroy(&na);
708  fprintf(stderr, "w = %d, h = %d, num ints = %d\n", w, h, n);
709  return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
710  }
711 
712  index = 0;
713  for (i = 0; i < h; i++) {
714  for (j = 0; j < w; j++) {
715  numaGetFValue(na, index, &val);
716  kernelSetElement(kel, i, j, val);
717  index++;
718  }
719  }
720 
721  numaDestroy(&na);
722  return kel;
723 }
724 
725 
726 /*----------------------------------------------------------------------*
727  * Making a kernel from a simple file format *
728  *----------------------------------------------------------------------*/
764 L_KERNEL *
765 kernelCreateFromFile(const char *filename)
766 {
767 char *filestr, *line;
768 l_int32 nlines, i, j, first, index, w, h, cx, cy, n;
769 l_float32 val;
770 size_t size;
771 NUMA *na, *nat;
772 SARRAY *sa;
773 L_KERNEL *kel;
774 
775  PROCNAME("kernelCreateFromFile");
776 
777  if (!filename)
778  return (L_KERNEL *)ERROR_PTR("filename not defined", procName, NULL);
779 
780  if ((filestr = (char *)l_binaryRead(filename, &size)) == NULL)
781  return (L_KERNEL *)ERROR_PTR("file not found", procName, NULL);
782  if (size == 0) {
783  LEPT_FREE(filestr);
784  return (L_KERNEL *)ERROR_PTR("file is empty", procName, NULL);
785  }
786 
787  sa = sarrayCreateLinesFromString(filestr, 1);
788  LEPT_FREE(filestr);
789  nlines = sarrayGetCount(sa);
790 
791  /* Find the first data line. */
792  for (i = 0, first = 0; i < nlines; i++) {
793  line = sarrayGetString(sa, i, L_NOCOPY);
794  if (line[0] != '#') {
795  first = i;
796  break;
797  }
798  }
799 
800  /* Find the kernel dimensions and origin location. */
801  line = sarrayGetString(sa, first, L_NOCOPY);
802  if (sscanf(line, "%d %d", &h, &w) != 2) {
803  sarrayDestroy(&sa);
804  return (L_KERNEL *)ERROR_PTR("error reading h,w", procName, NULL);
805  }
806  line = sarrayGetString(sa, first + 1, L_NOCOPY);
807  if (sscanf(line, "%d %d", &cy, &cx) != 2) {
808  sarrayDestroy(&sa);
809  return (L_KERNEL *)ERROR_PTR("error reading cy,cx", procName, NULL);
810  }
811 
812  /* Extract the data. This ends when we reach eof, or when we
813  * encounter a line of data that is either a null string or
814  * contains just a newline. */
815  na = numaCreate(0);
816  for (i = first + 2; i < nlines; i++) {
817  line = sarrayGetString(sa, i, L_NOCOPY);
818  if (line[0] == '\0' || line[0] == '\n' || line[0] == '#')
819  break;
820  nat = parseStringForNumbers(line, " \t\n");
821  numaJoin(na, nat, 0, -1);
822  numaDestroy(&nat);
823  }
824  sarrayDestroy(&sa);
825 
826  n = numaGetCount(na);
827  if (n != w * h) {
828  numaDestroy(&na);
829  fprintf(stderr, "w = %d, h = %d, num ints = %d\n", w, h, n);
830  return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL);
831  }
832 
833  kel = kernelCreate(h, w);
834  kernelSetOrigin(kel, cy, cx);
835  index = 0;
836  for (i = 0; i < h; i++) {
837  for (j = 0; j < w; j++) {
838  numaGetFValue(na, index, &val);
839  kernelSetElement(kel, i, j, val);
840  index++;
841  }
842  }
843 
844  numaDestroy(&na);
845  return kel;
846 }
847 
848 
849 /*----------------------------------------------------------------------*
850  * Making a kernel from a Pix *
851  *----------------------------------------------------------------------*/
864 L_KERNEL *
866  l_int32 cy,
867  l_int32 cx)
868 {
869 l_int32 i, j, w, h, d;
870 l_uint32 val;
871 L_KERNEL *kel;
872 
873  PROCNAME("kernelCreateFromPix");
874 
875  if (!pix)
876  return (L_KERNEL *)ERROR_PTR("pix not defined", procName, NULL);
877  pixGetDimensions(pix, &w, &h, &d);
878  if (d != 8)
879  return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", procName, NULL);
880  if (cy < 0 || cx < 0 || cy >= h || cx >= w)
881  return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", procName, NULL);
882 
883  kel = kernelCreate(h, w);
884  kernelSetOrigin(kel, cy, cx);
885  for (i = 0; i < h; i++) {
886  for (j = 0; j < w; j++) {
887  pixGetPixel(pix, j, i, &val);
888  kernelSetElement(kel, i, j, (l_float32)val);
889  }
890  }
891 
892  return kel;
893 }
894 
895 
896 /*----------------------------------------------------------------------*
897  * Display a kernel in a pix *
898  *----------------------------------------------------------------------*/
925 PIX *
927  l_int32 size,
928  l_int32 gthick)
929 {
930 l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0;
931 l_int32 normval;
932 l_float32 minval, maxval, max, val, norm;
933 PIX *pixd, *pixt0, *pixt1;
934 
935  PROCNAME("kernelDisplayInPix");
936 
937  if (!kel)
938  return (PIX *)ERROR_PTR("kernel not defined", procName, NULL);
939 
940  /* Normalize the max value to be 255 for display */
941  kernelGetParameters(kel, &sy, &sx, &cy, &cx);
942  kernelGetMinMax(kel, &minval, &maxval);
943  max = L_MAX(maxval, -minval);
944  if (max == 0.0)
945  return (PIX *)ERROR_PTR("kernel elements all 0.0", procName, NULL);
946  norm = 255. / (l_float32)max;
947 
948  /* Handle the 1 element/pixel case; typically with large kernels */
949  if (size == 1 && gthick == 0) {
950  pixd = pixCreate(sx, sy, 8);
951  for (i = 0; i < sy; i++) {
952  for (j = 0; j < sx; j++) {
953  kernelGetElement(kel, i, j, &val);
954  normval = (l_int32)(norm * L_ABS(val));
955  pixSetPixel(pixd, j, i, normval);
956  }
957  }
958  return pixd;
959  }
960 
961  /* Enforce the constraints for the grid line version */
962  if (size < 17) {
963  L_WARNING("size < 17; setting to 17\n", procName);
964  size = 17;
965  }
966  if (size % 2 == 0)
967  size++;
968  if (gthick < 2) {
969  L_WARNING("grid thickness < 2; setting to 2\n", procName);
970  gthick = 2;
971  }
972 
973  w = size * sx + gthick * (sx + 1);
974  h = size * sy + gthick * (sy + 1);
975  pixd = pixCreate(w, h, 8);
976 
977  /* Generate grid lines */
978  for (i = 0; i <= sy; i++)
979  pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick),
980  w - 1, gthick / 2 + i * (size + gthick),
981  gthick, L_SET_PIXELS);
982  for (j = 0; j <= sx; j++)
983  pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0,
984  gthick / 2 + j * (size + gthick), h - 1,
985  gthick, L_SET_PIXELS);
986 
987  /* Generate mask for each element */
988  pixt0 = pixCreate(size, size, 1);
989  pixSetAll(pixt0);
990 
991  /* Generate crossed lines for origin pattern */
992  pixt1 = pixCreate(size, size, 1);
993  width = size / 8;
994  pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size),
995  size / 2, (l_int32)(0.88 * size),
996  width, L_SET_PIXELS);
997  pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2,
998  (l_int32)(0.85 * size), size / 2,
999  width, L_FLIP_PIXELS);
1000  pixRasterop(pixt1, size / 2 - width, size / 2 - width,
1001  2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0);
1002 
1003  /* Paste the patterns in */
1004  y0 = gthick;
1005  for (i = 0; i < sy; i++) {
1006  x0 = gthick;
1007  for (j = 0; j < sx; j++) {
1008  kernelGetElement(kel, i, j, &val);
1009  normval = (l_int32)(norm * L_ABS(val));
1010  pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0);
1011  if (i == cy && j == cx)
1012  pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval);
1013  x0 += size + gthick;
1014  }
1015  y0 += size + gthick;
1016  }
1017 
1018  pixDestroy(&pixt0);
1019  pixDestroy(&pixt1);
1020  return pixd;
1021 }
1022 
1023 
1024 /*------------------------------------------------------------------------*
1025  * Parse string to extract numbers *
1026  *------------------------------------------------------------------------*/
1039 NUMA *
1040 parseStringForNumbers(const char *str,
1041  const char *seps)
1042 {
1043 char *newstr, *head;
1044 char *tail = NULL;
1045 l_float32 val;
1046 NUMA *na;
1047 
1048  PROCNAME("parseStringForNumbers");
1049 
1050  if (!str)
1051  return (NUMA *)ERROR_PTR("str not defined", procName, NULL);
1052 
1053  newstr = stringNew(str); /* to enforce const-ness of str */
1054  na = numaCreate(0);
1055  head = strtokSafe(newstr, seps, &tail);
1056  val = atof(head);
1057  numaAddNumber(na, val);
1058  LEPT_FREE(head);
1059  while ((head = strtokSafe(NULL, seps, &tail)) != NULL) {
1060  val = atof(head);
1061  numaAddNumber(na, val);
1062  LEPT_FREE(head);
1063  }
1064 
1065  LEPT_FREE(newstr);
1066  return na;
1067 }
1068 
1069 
1070 /*------------------------------------------------------------------------*
1071  * Simple parametric kernels *
1072  *------------------------------------------------------------------------*/
1091 L_KERNEL *
1092 makeFlatKernel(l_int32 height,
1093  l_int32 width,
1094  l_int32 cy,
1095  l_int32 cx)
1096 {
1097 l_int32 i, j;
1098 l_float32 normval;
1099 L_KERNEL *kel;
1100 
1101  PROCNAME("makeFlatKernel");
1102 
1103  if ((kel = kernelCreate(height, width)) == NULL)
1104  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1105  kernelSetOrigin(kel, cy, cx);
1106  normval = 1.0 / (l_float32)(height * width);
1107  for (i = 0; i < height; i++) {
1108  for (j = 0; j < width; j++) {
1109  kernelSetElement(kel, i, j, normval);
1110  }
1111  }
1112 
1113  return kel;
1114 }
1115 
1116 
1136 L_KERNEL *
1137 makeGaussianKernel(l_int32 halfheight,
1138  l_int32 halfwidth,
1139  l_float32 stdev,
1140  l_float32 max)
1141 {
1142 l_int32 sx, sy, i, j;
1143 l_float32 val;
1144 L_KERNEL *kel;
1145 
1146  PROCNAME("makeGaussianKernel");
1147 
1148  sx = 2 * halfwidth + 1;
1149  sy = 2 * halfheight + 1;
1150  if ((kel = kernelCreate(sy, sx)) == NULL)
1151  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1152  kernelSetOrigin(kel, halfheight, halfwidth);
1153  for (i = 0; i < sy; i++) {
1154  for (j = 0; j < sx; j++) {
1155  val = expf(-(l_float32)((i - halfheight) * (i - halfheight) +
1156  (j - halfwidth) * (j - halfwidth)) /
1157  (2. * stdev * stdev));
1158  kernelSetElement(kel, i, j, max * val);
1159  }
1160  }
1161 
1162  return kel;
1163 }
1164 
1165 
1190 l_ok
1191 makeGaussianKernelSep(l_int32 halfheight,
1192  l_int32 halfwidth,
1193  l_float32 stdev,
1194  l_float32 max,
1195  L_KERNEL **pkelx,
1196  L_KERNEL **pkely)
1197 {
1198  PROCNAME("makeGaussianKernelSep");
1199 
1200  if (!pkelx || !pkely)
1201  return ERROR_INT("&kelx and &kely not defined", procName, 1);
1202 
1203  *pkelx = makeGaussianKernel(0, halfwidth, stdev, max);
1204  *pkely = makeGaussianKernel(halfheight, 0, stdev, 1.0);
1205  return 0;
1206 }
1207 
1208 
1235 L_KERNEL *
1236 makeDoGKernel(l_int32 halfheight,
1237  l_int32 halfwidth,
1238  l_float32 stdev,
1239  l_float32 ratio)
1240 {
1241 l_int32 sx, sy, i, j;
1242 l_float32 pi, squaredist, highnorm, lownorm, val;
1243 L_KERNEL *kel;
1244 
1245  PROCNAME("makeDoGKernel");
1246 
1247  sx = 2 * halfwidth + 1;
1248  sy = 2 * halfheight + 1;
1249  if ((kel = kernelCreate(sy, sx)) == NULL)
1250  return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL);
1251  kernelSetOrigin(kel, halfheight, halfwidth);
1252 
1253  pi = 3.1415926535;
1254  for (i = 0; i < sy; i++) {
1255  for (j = 0; j < sx; j++) {
1256  squaredist = (l_float32)((i - halfheight) * (i - halfheight) +
1257  (j - halfwidth) * (j - halfwidth));
1258  highnorm = 1. / (2 * stdev * stdev);
1259  lownorm = highnorm / (ratio * ratio);
1260  val = (highnorm / pi) * expf(-(highnorm * squaredist))
1261  - (lownorm / pi) * expf(-(lownorm * squaredist));
1262  kernelSetElement(kel, i, j, val);
1263  }
1264  }
1265 
1266  return kel;
1267 }
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:692
PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick)
kernelDisplayInPix()
Definition: kernel.c:926
L_KERNEL * makeGaussianKernel(l_int32 halfheight, l_int32 halfwidth, l_float32 stdev, l_float32 max)
makeGaussianKernel()
Definition: kernel.c:1137
NUMA * parseStringForNumbers(const char *str, const char *seps)
parseStringForNumbers()
Definition: kernel.c:1040
l_float32 ** data
Definition: morph.h:95
l_ok kernelGetParameters(L_KERNEL *kel, l_int32 *psy, l_int32 *psx, l_int32 *pcy, l_int32 *pcx)
kernelGetParameters()
Definition: kernel.c:270
l_ok kernelGetSum(L_KERNEL *kel, l_float32 *psum)
kernelGetSum()
Definition: kernel.c:322
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
Definition: pix.h:716
char * stringNew(const char *src)
stringNew()
Definition: utils2.c:215
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:193
L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx)
kernelCreateFromPix()
Definition: kernel.c:865
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
l_ok pixSetMaskedGeneral(PIX *pixd, PIX *pixm, l_uint32 val, l_int32 x, l_int32 y)
pixSetMaskedGeneral()
Definition: pix3.c:294
l_ok pixSetAll(PIX *pix)
pixSetAll()
Definition: pix2.c:741
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
l_ok makeGaussianKernelSep(l_int32 halfheight, l_int32 halfwidth, l_float32 stdev, l_float32 max, L_KERNEL **pkelx, L_KERNEL **pkely)
makeGaussianKernelSep()
Definition: kernel.c:1191
l_ok kernelWrite(const char *fname, L_KERNEL *kel)
kernelWrite()
Definition: kernel.c:598
Definition: array.h:116
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
l_uint8 * l_binaryRead(const char *filename, size_t *pnbytes)
l_binaryRead()
Definition: utils2.c:1212
l_int32 sy
Definition: morph.h:91
l_ok kernelSetOrigin(L_KERNEL *kel, l_int32 cy, l_int32 cx)
kernelSetOrigin()
Definition: kernel.c:300
Definition: array.h:59
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:253
L_KERNEL * kernelCopy(L_KERNEL *kels)
kernelCopy()
Definition: kernel.c:175
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:681
l_int32 cx
Definition: morph.h:94
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
L_KERNEL * kernelReadStream(FILE *fp)
kernelReadStream()
Definition: kernel.c:555
L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum)
kernelNormalize()
Definition: kernel.c:410
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:276
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:1483
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:180
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
FILE * fopenWriteStream(const char *filename, const char *modestring)
fopenWriteStream()
Definition: utils2.c:1700
L_KERNEL * kernelInvert(L_KERNEL *kels)
kernelInvert()
Definition: kernel.c:456
void kernelDestroy(L_KERNEL **pkel)
kernelDestroy()
Definition: kernel.c:144
FILE * fopenReadStream(const char *filename)
fopenReadStream()
Definition: utils2.c:1657
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
l_ok kernelSetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 val)
kernelSetElement()
Definition: kernel.c:243
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3370
l_ok kernelGetElement(L_KERNEL *kel, l_int32 row, l_int32 col, l_float32 *pval)
kernelGetElement()
Definition: kernel.c:211
#define PIX_NOT(op)
Definition: pix.h:329
l_ok kernelGetMinMax(L_KERNEL *kel, l_float32 *pmin, l_float32 *pmax)
kernelGetMinMax()
Definition: kernel.c:354
L_KERNEL * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata)
kernelCreateFromString()
Definition: kernel.c:679
Definition: morph.h:89
Definition: pix.h:134
L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx)
makeFlatKernel()
Definition: kernel.c:1092
L_KERNEL * kernelRead(const char *fname)
kernelRead()
Definition: kernel.c:526
l_int32 cy
Definition: morph.h:93
char * strtokSafe(char *cstr, const char *seps, char **psaveptr)
strtokSafe()
Definition: utils2.c:640
L_KERNEL * kernelCreateFromFile(const char *filename)
kernelCreateFromFile()
Definition: kernel.c:765
l_ok kernelWriteStream(FILE *fp, L_KERNEL *kel)
kernelWriteStream()
Definition: kernel.c:627
l_int32 sx
Definition: morph.h:92
L_KERNEL * makeDoGKernel(l_int32 halfheight, l_int32 halfwidth, l_float32 stdev, l_float32 ratio)
makeDoGKernel()
Definition: kernel.c:1236
l_float32 ** create2dFloatArray(l_int32 sy, l_int32 sx)
create2dFloatArray()
Definition: kernel.c:499
#define PIX_DST
Definition: pix.h:328
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355
L_KERNEL * kernelCreate(l_int32 height, l_int32 width)
kernelCreate()
Definition: kernel.c:106