Leptonica  1.77.0
Image processing and image analysis suite
readbarcode.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 "allheaders.h"
85 #include "readbarcode.h"
86 
87  /* Parameters for pixGenerateBarcodeMask() */
88 static const l_int32 MAX_SPACE_WIDTH = 19; /* was 15 */
89 static const l_int32 MAX_NOISE_WIDTH = 50; /* smaller than barcode width */
90 static const l_int32 MAX_NOISE_HEIGHT = 30; /* smaller than barcode height */
91 
92  /* Static functions */
93 static PIX *pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace,
94  l_int32 nwidth, l_int32 nheight);
95 static NUMA *pixAverageRasterScans(PIX *pixs, l_int32 nscans);
96 static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist,
97  NUMA **pnaodist, l_float32 *pmindist,
98  l_float32 *pmaxdist);
99 static NUMA *numaLocatePeakRanges(NUMA *nas, l_float32 minfirst,
100  l_float32 minsep, l_float32 maxmin);
101 static NUMA *numaGetPeakCentroids(NUMA *nahist, NUMA *narange);
102 static NUMA *numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent);
103 static l_int32 numaEvalBestWidthAndShift(NUMA *nas, l_int32 nwidth,
104  l_int32 nshift, l_float32 minwidth,
105  l_float32 maxwidth,
106  l_float32 *pbestwidth,
107  l_float32 *pbestshift,
108  l_float32 *pbestscore);
109 static l_int32 numaEvalSyncError(NUMA *nas, l_int32 ifirst, l_int32 ilast,
110  l_float32 width, l_float32 shift,
111  l_float32 *pscore, NUMA **pnad);
112 
113 
114 #ifndef NO_CONSOLE_IO
115 #define DEBUG_DESKEW 1
116 #define DEBUG_WIDTHS 0
117 #endif /* ~NO_CONSOLE_IO */
118 
119 
120 /*------------------------------------------------------------------------*
121  * Top level *
122  *------------------------------------------------------------------------*/
133 SARRAY *
135  l_int32 format,
136  l_int32 method,
137  SARRAY **psaw,
138  l_int32 debugflag)
139 {
140 PIX *pixg;
141 PIXA *pixa;
142 SARRAY *sad;
143 
144  PROCNAME("pixProcessBarcodes");
145 
146  if (psaw) *psaw = NULL;
147  if (!pixs)
148  return (SARRAY *)ERROR_PTR("pixs not defined", procName, NULL);
149  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
150  return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
151  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
152  return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
153 
154  /* Get an 8 bpp image, no cmap */
155  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
156  pixg = pixClone(pixs);
157  else
158  pixg = pixConvertTo8(pixs, 0);
159 
160  if ((pixa = pixExtractBarcodes(pixg, debugflag)) == NULL) {
161  pixDestroy(&pixg);
162  return (SARRAY *)ERROR_PTR("no barcode(s) found", procName, NULL);
163  }
164 
165  sad = pixReadBarcodes(pixa, format, method, psaw, debugflag);
166 
167  pixDestroy(&pixg);
168  pixaDestroy(&pixa);
169  return sad;
170 }
171 
172 
181 PIXA *
183  l_int32 debugflag)
184 {
185 l_int32 i, n;
186 l_float32 angle, conf;
187 BOX *box;
188 BOXA *boxa;
189 PIX *pixb, *pixm, *pixt;
190 PIXA *pixa;
191 
192  PROCNAME("pixExtractBarcodes");
193 
194  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
195  return (PIXA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
196 
197  /* Locate them; use small threshold for edges. */
198  boxa = pixLocateBarcodes(pixs, 20, &pixb, &pixm);
199  n = boxaGetCount(boxa);
200  L_INFO("%d possible barcode(s) found\n", procName, n);
201  if (n == 0) {
202  boxaDestroy(&boxa);
203  pixDestroy(&pixb);
204  pixDestroy(&pixm);
205  return NULL;
206  }
207 
208  if (debugflag) {
209  boxaWriteStream(stderr, boxa);
210  pixDisplay(pixb, 100, 100);
211  pixDisplay(pixm, 800, 100);
212  }
213 
214  /* Deskew each barcode individually */
215  pixa = pixaCreate(n);
216  for (i = 0; i < n; i++) {
217  box = boxaGetBox(boxa, i, L_CLONE);
218  pixt = pixDeskewBarcode(pixs, pixb, box, 15, 20, &angle, &conf);
219  L_INFO("angle = %6.2f, conf = %6.2f\n", procName, angle, conf);
220  if (conf > 5.0) {
221  pixaAddPix(pixa, pixt, L_INSERT);
222  pixaAddBox(pixa, box, L_INSERT);
223  } else {
224  pixDestroy(&pixt);
225  boxDestroy(&box);
226  }
227  }
228 
229 #if DEBUG_DESKEW
230  pixt = pixaDisplayTiledInRows(pixa, 8, 1000, 1.0, 0, 30, 2);
231  pixWrite("junkpixt", pixt, IFF_PNG);
232  pixDestroy(&pixt);
233 #endif /* DEBUG_DESKEW */
234 
235  pixDestroy(&pixb);
236  pixDestroy(&pixm);
237  boxaDestroy(&boxa);
238  return pixa;
239 }
240 
241 
253 SARRAY *
255  l_int32 format,
256  l_int32 method,
257  SARRAY **psaw,
258  l_int32 debugflag)
259 {
260 char *barstr, *data;
261 char emptystring[] = "";
262 l_int32 i, j, n, nbars, ival;
263 NUMA *na;
264 PIX *pixt;
265 SARRAY *saw, *sad;
266 
267  PROCNAME("pixReadBarcodes");
268 
269  if (psaw) *psaw = NULL;
270  if (!pixa)
271  return (SARRAY *)ERROR_PTR("pixa not defined", procName, NULL);
272  if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
273  return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
274  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
275  return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
276 
277  n = pixaGetCount(pixa);
278  saw = sarrayCreate(n);
279  sad = sarrayCreate(n);
280  for (i = 0; i < n; i++) {
281  /* Extract the widths of the lines in each barcode */
282  pixt = pixaGetPix(pixa, i, L_CLONE);
283  na = pixReadBarcodeWidths(pixt, method, debugflag);
284  pixDestroy(&pixt);
285  if (!na) {
286  ERROR_INT("valid barcode widths not returned", procName, 1);
287  continue;
288  }
289 
290  /* Save the widths as a string */
291  nbars = numaGetCount(na);
292  barstr = (char *)LEPT_CALLOC(nbars + 1, sizeof(char));
293  for (j = 0; j < nbars; j++) {
294  numaGetIValue(na, j, &ival);
295  barstr[j] = 0x30 + ival;
296  }
297  sarrayAddString(saw, barstr, L_INSERT);
298  numaDestroy(&na);
299 
300  /* Decode the width strings */
301  data = barcodeDispatchDecoder(barstr, format, debugflag);
302  if (!data) {
303  ERROR_INT("barcode not decoded", procName, 1);
304  sarrayAddString(sad, emptystring, L_COPY);
305  continue;
306  }
307  sarrayAddString(sad, data, L_INSERT);
308  }
309 
310  /* If nothing found, clean up */
311  if (sarrayGetCount(saw) == 0) {
312  sarrayDestroy(&saw);
313  sarrayDestroy(&sad);
314  return (SARRAY *)ERROR_PTR("no valid barcode data", procName, NULL);
315  }
316 
317  if (psaw)
318  *psaw = saw;
319  else
320  sarrayDestroy(&saw);
321 
322  return sad;
323 }
324 
325 
334 NUMA *
336  l_int32 method,
337  l_int32 debugflag)
338 {
339 l_float32 winwidth;
340 NUMA *na;
341 
342  PROCNAME("pixReadBarcodeWidths");
343 
344  if (!pixs)
345  return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
346  if (pixGetDepth(pixs) != 8)
347  return (NUMA *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
348  if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
349  return (NUMA *)ERROR_PTR("invalid method", procName, NULL);
350 
351  /* Extract the widths of the lines in each barcode */
352  if (method == L_USE_WIDTHS)
353  na = pixExtractBarcodeWidths1(pixs, 120, 0.25, NULL, NULL,
354  debugflag);
355  else /* method == L_USE_WINDOWS */
356  na = pixExtractBarcodeWidths2(pixs, 120, &winwidth,
357  NULL, debugflag);
358 #if DEBUG_WIDTHS
359  if (method == L_USE_WINDOWS)
360  fprintf(stderr, "Window width for barcode: %7.3f\n", winwidth);
361  numaWriteStream(stderr, na);
362 #endif /* DEBUG_WIDTHS */
363 
364  if (!na)
365  return (NUMA *)ERROR_PTR("barcode widths invalid", procName, NULL);
366 
367  return na;
368 }
369 
370 
371 /*------------------------------------------------------------------------*
372  * Locate barcode in image *
373  *------------------------------------------------------------------------*/
383 BOXA *
385  l_int32 thresh,
386  PIX **ppixb,
387  PIX **ppixm)
388 {
389 BOXA *boxa;
390 PIX *pix8, *pixe, *pixb, *pixm;
391 
392  PROCNAME("pixLocateBarcodes");
393 
394  if (!pixs)
395  return (BOXA *)ERROR_PTR("pixs not defined", procName, NULL);
396 
397  /* Get an 8 bpp image, no cmap */
398  if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
399  pix8 = pixClone(pixs);
400  else
401  pix8 = pixConvertTo8(pixs, 0);
402 
403  /* Get a 1 bpp image of the edges */
404  pixe = pixSobelEdgeFilter(pix8, L_ALL_EDGES);
405  pixb = pixThresholdToBinary(pixe, thresh);
406  pixInvert(pixb, pixb);
407  pixDestroy(&pix8);
408  pixDestroy(&pixe);
409 
410  pixm = pixGenerateBarcodeMask(pixb, MAX_SPACE_WIDTH, MAX_NOISE_WIDTH,
411  MAX_NOISE_HEIGHT);
412  boxa = pixConnComp(pixm, NULL, 8);
413 
414  if (ppixb)
415  *ppixb = pixb;
416  else
417  pixDestroy(&pixb);
418  if (ppixm)
419  *ppixm = pixm;
420  else
421  pixDestroy(&pixm);
422 
423  return boxa;
424 }
425 
426 
443 static PIX *
445  l_int32 maxspace,
446  l_int32 nwidth,
447  l_int32 nheight)
448 {
449 PIX *pixt1, *pixt2, *pixd;
450 
451  PROCNAME("pixGenerateBarcodeMask");
452 
453  if (!pixs || pixGetDepth(pixs) != 1)
454  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
455 
456  /* Identify horizontal barcodes */
457  pixt1 = pixCloseBrick(NULL, pixs, maxspace + 1, 1);
458  pixt2 = pixOpenBrick(NULL, pixs, maxspace + 1, 1);
459  pixXor(pixt2, pixt2, pixt1);
460  pixOpenBrick(pixt2, pixt2, nwidth, nheight);
461  pixDestroy(&pixt1);
462 
463  /* Identify vertical barcodes */
464  pixt1 = pixCloseBrick(NULL, pixs, 1, maxspace + 1);
465  pixd = pixOpenBrick(NULL, pixs, 1, maxspace + 1);
466  pixXor(pixd, pixd, pixt1);
467  pixOpenBrick(pixd, pixd, nheight, nwidth);
468  pixDestroy(&pixt1);
469 
470  /* Combine to get all barcodes */
471  pixOr(pixd, pixd, pixt2);
472  pixDestroy(&pixt2);
473 
474  return pixd;
475 }
476 
477 
478 /*------------------------------------------------------------------------*
479  * Extract and deskew barcode *
480  *------------------------------------------------------------------------*/
499 PIX *
501  PIX *pixb,
502  BOX *box,
503  l_int32 margin,
504  l_int32 threshold,
505  l_float32 *pangle,
506  l_float32 *pconf)
507 {
508 l_int32 x, y, w, h, n;
509 l_float32 angle, angle1, angle2, conf, conf1, conf2, score1, score2, deg2rad;
510 BOX *boxe, *boxt;
511 BOXA *boxa, *boxat;
512 PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6, *pixd;
513 
514  PROCNAME("pixDeskewBarcode");
515 
516  if (!pixs || pixGetDepth(pixs) != 8)
517  return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
518  if (!pixb || pixGetDepth(pixb) != 1)
519  return (PIX *)ERROR_PTR("pixb undefined or not 1 bpp", procName, NULL);
520  if (!box)
521  return (PIX *)ERROR_PTR("box not defined or 1 bpp", procName, NULL);
522 
523  /* Clip out */
524  deg2rad = 3.1415926535 / 180.;
525  boxGetGeometry(box, &x, &y, &w, &h);
526  boxe = boxCreate(x - 25, y - 25, w + 51, h + 51);
527  pixt1 = pixClipRectangle(pixb, boxe, NULL);
528  pixt2 = pixClipRectangle(pixs, boxe, NULL);
529  boxDestroy(&boxe);
530 
531  /* Deskew, looking at all possible orientations over 180 degrees */
532  pixt3 = pixRotateOrth(pixt1, 1); /* look for vertical bar lines */
533  pixt4 = pixClone(pixt1); /* look for horizontal bar lines */
534  pixFindSkewSweepAndSearchScore(pixt3, &angle1, &conf1, &score1,
535  1, 1, 0.0, 45.0, 2.5, 0.01);
536  pixFindSkewSweepAndSearchScore(pixt4, &angle2, &conf2, &score2,
537  1, 1, 0.0, 45.0, 2.5, 0.01);
538 
539  /* Because we're using the boundary pixels of the barcodes,
540  * the peak can be sharper (and the confidence ratio higher)
541  * from the signal across the top and bottom of the barcode.
542  * However, the max score, which is the magnitude of the signal
543  * at the optimum skew angle, will be smaller, so we use the
544  * max score as the primary indicator of orientation. */
545  if (score1 >= score2) {
546  conf = conf1;
547  if (conf1 > 6.0 && L_ABS(angle1) > 0.1) {
548  angle = angle1;
549  pixt5 = pixRotate(pixt2, deg2rad * angle1, L_ROTATE_AREA_MAP,
550  L_BRING_IN_WHITE, 0, 0);
551  } else {
552  angle = 0.0;
553  pixt5 = pixClone(pixt2);
554  }
555  } else { /* score2 > score1 */
556  conf = conf2;
557  pixt6 = pixRotateOrth(pixt2, 1);
558  if (conf2 > 6.0 && L_ABS(angle2) > 0.1) {
559  angle = 90.0 + angle2;
560  pixt5 = pixRotate(pixt6, deg2rad * angle2, L_ROTATE_AREA_MAP,
561  L_BRING_IN_WHITE, 0, 0);
562  } else {
563  angle = 90.0;
564  pixt5 = pixClone(pixt6);
565  }
566  pixDestroy(&pixt6);
567  }
568  pixDestroy(&pixt3);
569  pixDestroy(&pixt4);
570 
571  /* Extract barcode plus a margin around it */
572  boxa = pixLocateBarcodes(pixt5, threshold, 0, 0);
573  if ((n = boxaGetCount(boxa)) != 1) {
574  L_WARNING("barcode mask in %d components\n", procName, n);
575  boxat = boxaSort(boxa, L_SORT_BY_AREA, L_SORT_DECREASING, NULL);
576  } else {
577  boxat = boxaCopy(boxa, L_CLONE);
578  }
579  boxt = boxaGetBox(boxat, 0, L_CLONE);
580  boxGetGeometry(boxt, &x, &y, &w, &h);
581  boxe = boxCreate(x - margin, y - margin, w + 2 * margin,
582  h + 2 * margin);
583  pixd = pixClipRectangle(pixt5, boxe, NULL);
584  boxDestroy(&boxt);
585  boxDestroy(&boxe);
586  boxaDestroy(&boxa);
587  boxaDestroy(&boxat);
588 
589  if (pangle) *pangle = angle;
590  if (pconf) *pconf = conf;
591 
592  pixDestroy(&pixt1);
593  pixDestroy(&pixt2);
594  pixDestroy(&pixt5);
595  return pixd;
596 }
597 
598 
599 /*------------------------------------------------------------------------*
600  * Process to get line widths *
601  *------------------------------------------------------------------------*/
625 NUMA *
627  l_float32 thresh,
628  l_float32 binfract,
629  NUMA **pnaehist,
630  NUMA **pnaohist,
631  l_int32 debugflag)
632 {
633 NUMA *nac, *nad;
634 
635  PROCNAME("pixExtractBarcodeWidths1");
636 
637  if (!pixs || pixGetDepth(pixs) != 8)
638  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
639 
640  /* Get the best estimate of the crossings, in pixel units */
641  nac = pixExtractBarcodeCrossings(pixs, thresh, debugflag);
642 
643  /* Get the array of bar widths, starting with a black bar */
644  nad = numaQuantizeCrossingsByWidth(nac, binfract, pnaehist,
645  pnaohist, debugflag);
646 
647  numaDestroy(&nac);
648  return nad;
649 }
650 
651 
678 NUMA *
680  l_float32 thresh,
681  l_float32 *pwidth,
682  NUMA **pnac,
683  l_int32 debugflag)
684 {
685 NUMA *nacp, *nad;
686 
687  PROCNAME("pixExtractBarcodeWidths2");
688 
689  if (!pixs || pixGetDepth(pixs) != 8)
690  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
691 
692  /* Get the best estimate of the crossings, in pixel units */
693  nacp = pixExtractBarcodeCrossings(pixs, thresh, debugflag);
694 
695  /* Quantize the crossings to get actual windowed data */
696  nad = numaQuantizeCrossingsByWindow(nacp, 2.0, pwidth, NULL, pnac, debugflag);
697 
698  numaDestroy(&nacp);
699  return nad;
700 }
701 
702 
712 NUMA *
714  l_float32 thresh,
715  l_int32 debugflag)
716 {
717 l_int32 w;
718 l_float32 bestthresh;
719 NUMA *nas, *nax, *nay, *nad;
720 
721  PROCNAME("pixExtractBarcodeCrossings");
722 
723  if (!pixs || pixGetDepth(pixs) != 8)
724  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
725 
726  /* Scan pixels horizontally and average results */
727  nas = pixAverageRasterScans(pixs, 51);
728 
729  /* Interpolate to get 4x the number of values */
730  w = pixGetWidth(pixs);
732  (l_float32)(w - 1), 4 * w + 1, &nax, &nay);
733 
734  if (debugflag) {
735  lept_mkdir("lept/barcode");
736  GPLOT *gplot = gplotCreate("/tmp/lept/barcode/signal", GPLOT_PNG,
737  "Pixel values", "dist in pixels", "value");
738  gplotAddPlot(gplot, nax, nay, GPLOT_LINES, "plot 1");
739  gplotMakeOutput(gplot);
740  gplotDestroy(&gplot);
741  }
742 
743  /* Locate the crossings. Run multiple times with different
744  * thresholds, and choose a threshold in the center of the
745  * run of thresholds that all give the maximum number of crossings. */
746  numaSelectCrossingThreshold(nax, nay, thresh, &bestthresh);
747 
748  /* Get the crossings with the best threshold. */
749  nad = numaCrossingsByThreshold(nax, nay, bestthresh);
750 
751  numaDestroy(&nas);
752  numaDestroy(&nax);
753  numaDestroy(&nay);
754  return nad;
755 }
756 
757 
758 /*------------------------------------------------------------------------*
759  * Average adjacent rasters *
760  *------------------------------------------------------------------------*/
768 static NUMA *
770  l_int32 nscans)
771 {
772 l_int32 w, h, first, last, i, j, wpl, val;
773 l_uint32 *line, *data;
774 l_float32 *array;
775 NUMA *nad;
776 
777  PROCNAME("pixAverageRasterScans");
778 
779  if (!pixs || pixGetDepth(pixs) != 8)
780  return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
781 
782  pixGetDimensions(pixs, &w, &h, NULL);
783  if (nscans <= h) {
784  first = 0;
785  last = h - 1;
786  nscans = h;
787  } else {
788  first = (h - nscans) / 2;
789  last = first + nscans - 1;
790  }
791 
792  nad = numaCreate(w);
793  numaSetCount(nad, w);
794  array = numaGetFArray(nad, L_NOCOPY);
795  wpl = pixGetWpl(pixs);
796  data = pixGetData(pixs);
797  for (j = 0; j < w; j++) {
798  for (i = first; i <= last; i++) {
799  line = data + i * wpl;
800  val = GET_DATA_BYTE(line, j);
801  array[j] += val;
802  }
803  array[j] = array[j] / (l_float32)nscans;
804  }
805 
806  return nad;
807 }
808 
809 
810 /*------------------------------------------------------------------------*
811  * Signal processing for barcode widths *
812  *------------------------------------------------------------------------*/
836 NUMA *
838  l_float32 binfract,
839  NUMA **pnaehist,
840  NUMA **pnaohist,
841  l_int32 debugflag)
842 {
843 l_int32 i, n, ned, nod, iw, width;
844 l_float32 val, minsize, maxsize, factor;
845 GPLOT *gplot;
846 NUMA *naedist, *naodist, *naehist, *naohist, *naecent, *naocent;
847 NUMA *naerange, *naorange, *naelut, *naolut, *nad;
848 
849  PROCNAME("numaQuantizeCrossingsByWidth");
850 
851  if (!nas)
852  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
853  n = numaGetCount(nas);
854  if (n < 2)
855  return (NUMA *)ERROR_PTR("n < 2", procName, NULL);
856  if (binfract <= 0.0)
857  return (NUMA *)ERROR_PTR("binfract <= 0.0", procName, NULL);
858 
859  /* Get even and odd crossing distances */
860  numaGetCrossingDistances(nas, &naedist, &naodist, &minsize, &maxsize);
861 
862  /* Bin the spans in units of binfract * minsize. These
863  * units are convenient because they scale to make at least
864  * 1/binfract bins in the smallest span (width). We want this
865  * number to be large enough to clearly separate the
866  * widths, but small enough so that the histogram peaks
867  * have very few if any holes (zeroes) within them. */
868  naehist = numaMakeHistogramClipped(naedist, binfract * minsize,
869  (1.25 / binfract) * maxsize);
870  naohist = numaMakeHistogramClipped(naodist, binfract * minsize,
871  (1.25 / binfract) * maxsize);
872 
873  if (debugflag) {
874  lept_mkdir("lept/barcode");
875  gplot = gplotCreate("/tmp/lept/barcode/histw", GPLOT_PNG,
876  "Raw width histogram", "Width", "Number");
877  gplotAddPlot(gplot, NULL, naehist, GPLOT_LINES, "plot black");
878  gplotAddPlot(gplot, NULL, naohist, GPLOT_LINES, "plot white");
879  gplotMakeOutput(gplot);
880  gplotDestroy(&gplot);
881  }
882 
883  /* Compute the peak ranges, still in units of binfract * minsize. */
884  naerange = numaLocatePeakRanges(naehist, 1.0 / binfract,
885  1.0 / binfract, 0.0);
886  naorange = numaLocatePeakRanges(naohist, 1.0 / binfract,
887  1.0 / binfract, 0.0);
888 
889  /* Find the centroid values of each peak */
890  naecent = numaGetPeakCentroids(naehist, naerange);
891  naocent = numaGetPeakCentroids(naohist, naorange);
892 
893  /* Generate the lookup tables that map from the bar width, in
894  * units of (binfract * minsize), to the integerized barcode
895  * units (1, 2, 3, 4), which are the output integer widths
896  * between transitions. */
897  naelut = numaGetPeakWidthLUT(naerange, naecent);
898  naolut = numaGetPeakWidthLUT(naorange, naocent);
899 
900  /* Get the widths. Because the LUT accepts our funny units,
901  * we first must convert the pixel widths to these units,
902  * which is what 'factor' does. */
903  nad = numaCreate(0);
904  ned = numaGetCount(naedist);
905  nod = numaGetCount(naodist);
906  if (nod != ned - 1)
907  L_WARNING("ned != nod + 1\n", procName);
908  factor = 1.0 / (binfract * minsize); /* for converting units */
909  for (i = 0; i < ned - 1; i++) {
910  numaGetFValue(naedist, i, &val);
911  width = (l_int32)(factor * val);
912  numaGetIValue(naelut, width, &iw);
913  numaAddNumber(nad, iw);
914 /* fprintf(stderr, "even: val = %7.3f, width = %d, iw = %d\n",
915  val, width, iw); */
916  numaGetFValue(naodist, i, &val);
917  width = (l_int32)(factor * val);
918  numaGetIValue(naolut, width, &iw);
919  numaAddNumber(nad, iw);
920 /* fprintf(stderr, "odd: val = %7.3f, width = %d, iw = %d\n",
921  val, width, iw); */
922  }
923  numaGetFValue(naedist, ned - 1, &val);
924  width = (l_int32)(factor * val);
925  numaGetIValue(naelut, width, &iw);
926  numaAddNumber(nad, iw);
927 
928  if (debugflag) {
929  fprintf(stderr, " ---- Black bar widths (pixels) ------ \n");
930  numaWriteStream(stderr, naedist);
931  fprintf(stderr, " ---- Histogram of black bar widths ------ \n");
932  numaWriteStream(stderr, naehist);
933  fprintf(stderr, " ---- Peak ranges in black bar histogram bins --- \n");
934  numaWriteStream(stderr, naerange);
935  fprintf(stderr, " ---- Peak black bar centroid width values ------ \n");
936  numaWriteStream(stderr, naecent);
937  fprintf(stderr, " ---- Black bar lookup table ------ \n");
938  numaWriteStream(stderr, naelut);
939  fprintf(stderr, " ---- White bar widths (pixels) ------ \n");
940  numaWriteStream(stderr, naodist);
941  fprintf(stderr, " ---- Histogram of white bar widths ------ \n");
942  numaWriteStream(stderr, naohist);
943  fprintf(stderr, " ---- Peak ranges in white bar histogram bins --- \n");
944  numaWriteStream(stderr, naorange);
945  fprintf(stderr, " ---- Peak white bar centroid width values ------ \n");
946  numaWriteStream(stderr, naocent);
947  fprintf(stderr, " ---- White bar lookup table ------ \n");
948  numaWriteStream(stderr, naolut);
949  }
950 
951  numaDestroy(&naedist);
952  numaDestroy(&naodist);
953  numaDestroy(&naerange);
954  numaDestroy(&naorange);
955  numaDestroy(&naecent);
956  numaDestroy(&naocent);
957  numaDestroy(&naelut);
958  numaDestroy(&naolut);
959  if (pnaehist)
960  *pnaehist = naehist;
961  else
962  numaDestroy(&naehist);
963  if (pnaohist)
964  *pnaohist = naohist;
965  else
966  numaDestroy(&naohist);
967  return nad;
968 }
969 
970 
981 static l_int32
983  NUMA **pnaedist,
984  NUMA **pnaodist,
985  l_float32 *pmindist,
986  l_float32 *pmaxdist)
987 {
988 l_int32 i, n;
989 l_float32 val, newval, mindist, maxdist, dist;
990 NUMA *naedist, *naodist;
991 
992  PROCNAME("numaGetCrossingDistances");
993 
994  if (pnaedist) *pnaedist = NULL;
995  if (pnaodist) *pnaodist = NULL;
996  if (pmindist) *pmindist = 0.0;
997  if (pmaxdist) *pmaxdist = 0.0;
998  if (!nas)
999  return ERROR_INT("nas not defined", procName, 1);
1000  if ((n = numaGetCount(nas)) < 2)
1001  return ERROR_INT("n < 2", procName, 1);
1002 
1003  /* Get numas of distances between crossings. Separate these
1004  * into even (e.g., black) and odd (e.g., white) spans.
1005  * For barcodes, the black spans are 0, 2, etc. These
1006  * distances are in pixel units. */
1007  naedist = numaCreate(n / 2 + 1);
1008  naodist = numaCreate(n / 2);
1009  numaGetFValue(nas, 0, &val);
1010  for (i = 1; i < n; i++) {
1011  numaGetFValue(nas, i, &newval);
1012  if (i % 2)
1013  numaAddNumber(naedist, newval - val);
1014  else
1015  numaAddNumber(naodist, newval - val);
1016  val = newval;
1017  }
1018 
1019  /* The mindist and maxdist of the spans are in pixel units. */
1020  numaGetMin(naedist, &mindist, NULL);
1021  numaGetMin(naodist, &dist, NULL);
1022  mindist = L_MIN(dist, mindist);
1023  numaGetMax(naedist, &maxdist, NULL);
1024  numaGetMax(naodist, &dist, NULL);
1025  maxdist = L_MAX(dist, maxdist);
1026  L_INFO("mindist = %7.3f, maxdist = %7.3f\n", procName, mindist, maxdist);
1027 
1028  if (pnaedist)
1029  *pnaedist = naedist;
1030  else
1031  numaDestroy(&naedist);
1032  if (pnaodist)
1033  *pnaodist = naodist;
1034  else
1035  numaDestroy(&naodist);
1036  if (pmindist) *pmindist = mindist;
1037  if (pmaxdist) *pmaxdist = maxdist;
1038  return 0;
1039 }
1040 
1041 
1070 static NUMA *
1072  l_float32 minfirst,
1073  l_float32 minsep,
1074  l_float32 maxmin)
1075 {
1076 l_int32 i, n, inpeak, left;
1077 l_float32 center, prevcenter, val;
1078 NUMA *nad;
1079 
1080  PROCNAME("numaLocatePeakRanges");
1081 
1082  if (!nas)
1083  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1084  n = numaGetCount(nas);
1085  nad = numaCreate(0);
1086 
1087  inpeak = FALSE;
1088  prevcenter = minfirst - minsep - 1.0;
1089  for (i = 0; i < n; i++) {
1090  numaGetFValue(nas, i, &val);
1091  if (inpeak == FALSE && val > maxmin) {
1092  inpeak = TRUE;
1093  left = i;
1094  } else if (inpeak == TRUE && val <= maxmin) { /* end peak */
1095  center = (left + i - 1.0) / 2.0;
1096  if (center - prevcenter >= minsep) { /* save new peak */
1097  inpeak = FALSE;
1098  numaAddNumber(nad, left);
1099  numaAddNumber(nad, i - 1);
1100  prevcenter = center;
1101  } else { /* attach to previous peak; revise the right edge */
1102  numaSetValue(nad, numaGetCount(nad) - 1, i - 1);
1103  }
1104  }
1105  }
1106  if (inpeak == TRUE) { /* save the last peak */
1107  numaAddNumber(nad, left);
1108  numaAddNumber(nad, n - 1);
1109  }
1110 
1111  return nad;
1112 }
1113 
1114 
1123 static NUMA *
1125  NUMA *narange)
1126 {
1127 l_int32 i, j, nr, low, high;
1128 l_float32 cent, sum, val;
1129 NUMA *nad;
1130 
1131  PROCNAME("numaGetPeakCentroids");
1132 
1133  if (!nahist)
1134  return (NUMA *)ERROR_PTR("nahist not defined", procName, NULL);
1135  if (!narange)
1136  return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1137  nr = numaGetCount(narange) / 2;
1138 
1139  nad = numaCreate(4);
1140  for (i = 0; i < nr; i++) {
1141  numaGetIValue(narange, 2 * i, &low);
1142  numaGetIValue(narange, 2 * i + 1, &high);
1143  cent = 0.0;
1144  sum = 0.0;
1145  for (j = low; j <= high; j++) {
1146  numaGetFValue(nahist, j, &val);
1147  cent += j * val;
1148  sum += val;
1149  }
1150  numaAddNumber(nad, cent / sum);
1151  }
1152 
1153  return nad;
1154 }
1155 
1156 
1174 static NUMA *
1176  NUMA *nacent)
1177 {
1178 l_int32 i, j, nc, low, high, imax;
1179 l_int32 assign[4];
1180 l_float32 *warray;
1181 l_float32 max, rat21, rat32, rat42;
1182 NUMA *nalut;
1183 
1184  PROCNAME("numaGetPeakWidthLUT");
1185 
1186  if (!narange)
1187  return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1188  if (!nacent)
1189  return (NUMA *)ERROR_PTR("nacent not defined", procName, NULL);
1190  nc = numaGetCount(nacent); /* half the size of narange */
1191  if (nc < 1 || nc > 4)
1192  return (NUMA *)ERROR_PTR("nc must be 1, 2, 3, or 4", procName, NULL);
1193 
1194  /* Check the peak centroids for consistency with bar widths.
1195  * The third peak can correspond to a width of either 3 or 4.
1196  * Use ratios 3/2 and 4/2 instead of 3/1 and 4/1 because the
1197  * former are more stable and closer to the expected ratio. */
1198  if (nc > 1) {
1199  warray = numaGetFArray(nacent, L_NOCOPY);
1200  if (warray[0] == 0)
1201  return (NUMA *)ERROR_PTR("first peak has width 0.0",
1202  procName, NULL);
1203  rat21 = warray[1] / warray[0];
1204  if (rat21 < 1.5 || rat21 > 2.6)
1205  L_WARNING("width ratio 2/1 = %f\n", procName, rat21);
1206  if (nc > 2) {
1207  rat32 = warray[2] / warray[1];
1208  if (rat32 < 1.3 || rat32 > 2.25)
1209  L_WARNING("width ratio 3/2 = %f\n", procName, rat32);
1210  }
1211  if (nc == 4) {
1212  rat42 = warray[3] / warray[1];
1213  if (rat42 < 1.7 || rat42 > 2.3)
1214  L_WARNING("width ratio 4/2 = %f\n", procName, rat42);
1215  }
1216  }
1217 
1218  /* Set width assignments.
1219  * The only possible ambiguity is with nc = 3 */
1220  for (i = 0; i < 4; i++)
1221  assign[i] = i + 1;
1222  if (nc == 3) {
1223  if (rat32 > 1.75)
1224  assign[2] = 4;
1225  }
1226 
1227  /* Put widths into the LUT */
1228  numaGetMax(narange, &max, NULL);
1229  imax = (l_int32)max;
1230  nalut = numaCreate(imax + 1);
1231  numaSetCount(nalut, imax + 1); /* fill the array with zeroes */
1232  for (i = 0; i < nc; i++) {
1233  numaGetIValue(narange, 2 * i, &low);
1234  if (i == 0) low--; /* catch smallest width */
1235  numaGetIValue(narange, 2 * i + 1, &high);
1236  for (j = low; j <= high; j++)
1237  numaSetValue(nalut, j, assign[i]);
1238  }
1239 
1240  return nalut;
1241 }
1242 
1243 
1266 NUMA *
1268  l_float32 ratio,
1269  l_float32 *pwidth,
1270  l_float32 *pfirstloc,
1271  NUMA **pnac,
1272  l_int32 debugflag)
1273 {
1274 l_int32 i, nw, started, count, trans;
1275 l_float32 minsize, minwidth, minshift, xfirst;
1276 NUMA *nac, *nad;
1277 
1278  PROCNAME("numaQuantizeCrossingsByWindow");
1279 
1280  if (!nas)
1281  return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1282  if (numaGetCount(nas) < 2)
1283  return (NUMA *)ERROR_PTR("nas size < 2", procName, NULL);
1284 
1285  /* Get the minsize, which is needed for the search for
1286  * the window width (ultimately found as 'minwidth') */
1287  numaGetCrossingDistances(nas, NULL, NULL, &minsize, NULL);
1288 
1289  /* Compute the width and shift increments; start at minsize
1290  * and go up to ratio * minsize */
1291  numaEvalBestWidthAndShift(nas, 100, 10, minsize, ratio * minsize,
1292  &minwidth, &minshift, NULL);
1293 
1294  /* Refine width and shift calculation */
1295  numaEvalBestWidthAndShift(nas, 100, 10, 0.98 * minwidth, 1.02 * minwidth,
1296  &minwidth, &minshift, NULL);
1297 
1298  L_INFO("best width = %7.3f, best shift = %7.3f\n",
1299  procName, minwidth, minshift);
1300 
1301  /* Get the crossing array (0,1,2) for the best window width and shift */
1302  numaEvalSyncError(nas, 0, 0, minwidth, minshift, NULL, &nac);
1303  if (pwidth) *pwidth = minwidth;
1304  if (pfirstloc) {
1305  numaGetFValue(nas, 0, &xfirst);
1306  *pfirstloc = xfirst + minshift;
1307  }
1308 
1309  /* Get the array of bar widths, starting with a black bar */
1310  nad = numaCreate(0);
1311  nw = numaGetCount(nac); /* number of window measurements */
1312  started = FALSE;
1313  count = 0; /* unnecessary init */
1314  for (i = 0; i < nw; i++) {
1315  numaGetIValue(nac, i, &trans);
1316  if (trans > 2)
1317  L_WARNING("trans = %d > 2 !!!\n", procName, trans);
1318  if (started) {
1319  if (trans > 1) { /* i.e., when trans == 2 */
1320  numaAddNumber(nad, count);
1321  trans--;
1322  count = 1;
1323  }
1324  if (trans == 1) {
1325  numaAddNumber(nad, count);
1326  count = 1;
1327  } else {
1328  count++;
1329  }
1330  }
1331  if (!started && trans) {
1332  started = TRUE;
1333  if (trans == 2) /* a whole bar in this window */
1334  numaAddNumber(nad, 1);
1335  count = 1;
1336  }
1337  }
1338 
1339  if (pnac)
1340  *pnac = nac;
1341  else
1342  numaDestroy(&nac);
1343  return nad;
1344 }
1345 
1346 
1368 static l_int32
1370  l_int32 nwidth,
1371  l_int32 nshift,
1372  l_float32 minwidth,
1373  l_float32 maxwidth,
1374  l_float32 *pbestwidth,
1375  l_float32 *pbestshift,
1376  l_float32 *pbestscore)
1377 {
1378 l_int32 i, j;
1379 l_float32 delwidth, delshift, width, shift, score;
1380 l_float32 bestwidth, bestshift, bestscore;
1381 
1382  PROCNAME("numaEvalBestWidthAndShift");
1383 
1384  if (!nas)
1385  return ERROR_INT("nas not defined", procName, 1);
1386  if (!pbestwidth || !pbestshift)
1387  return ERROR_INT("&bestwidth and &bestshift not defined", procName, 1);
1388 
1389  bestwidth = 0.0f;
1390  bestshift = 0.0f;
1391  bestscore = 1.0;
1392  delwidth = (maxwidth - minwidth) / (nwidth - 1.0);
1393  for (i = 0; i < nwidth; i++) {
1394  width = minwidth + delwidth * i;
1395  delshift = width / (l_float32)(nshift);
1396  for (j = 0; j < nshift; j++) {
1397  shift = -0.5 * (width - delshift) + j * delshift;
1398  numaEvalSyncError(nas, 0, 0, width, shift, &score, NULL);
1399  if (score < bestscore) {
1400  bestscore = score;
1401  bestwidth = width;
1402  bestshift = shift;
1403 #if DEBUG_FREQUENCY
1404  fprintf(stderr, "width = %7.3f, shift = %7.3f, score = %7.3f\n",
1405  width, shift, score);
1406 #endif /* DEBUG_FREQUENCY */
1407  }
1408  }
1409  }
1410 
1411  *pbestwidth = bestwidth;
1412  *pbestshift = bestshift;
1413  if (pbestscore)
1414  *pbestscore = bestscore;
1415  return 0;
1416 }
1417 
1418 
1442 static l_int32
1444  l_int32 ifirst,
1445  l_int32 ilast,
1446  l_float32 width,
1447  l_float32 shift,
1448  l_float32 *pscore,
1449  NUMA **pnad)
1450 {
1451 l_int32 i, n, nc, nw, ival;
1452 l_int32 iw; /* cell in which transition occurs */
1453 l_float32 score, xfirst, xlast, xleft, xc, xwc;
1454 NUMA *nad;
1455 
1456  PROCNAME("numaEvalSyncError");
1457 
1458  if (!nas)
1459  return ERROR_INT("nas not defined", procName, 1);
1460  if ((n = numaGetCount(nas)) < 2)
1461  return ERROR_INT("nas size < 2", procName, 1);
1462  if (ifirst < 0) ifirst = 0;
1463  if (ilast <= 0) ilast = n - 1;
1464  if (ifirst >= ilast)
1465  return ERROR_INT("ifirst not < ilast", procName, 1);
1466  nc = ilast - ifirst + 1;
1467 
1468  /* Set up an array corresponding to the (shifted) windows,
1469  * and fill in the crossings. */
1470  score = 0.0;
1471  numaGetFValue(nas, ifirst, &xfirst);
1472  numaGetFValue(nas, ilast, &xlast);
1473  nw = (l_int32) ((xlast - xfirst + 2.0 * width) / width);
1474  nad = numaCreate(nw);
1475  numaSetCount(nad, nw); /* init to all 0.0 */
1476  xleft = xfirst - width / 2.0 + shift; /* left edge of first window */
1477  for (i = ifirst; i <= ilast; i++) {
1478  numaGetFValue(nas, i, &xc);
1479  iw = (l_int32)((xc - xleft) / width);
1480  xwc = xleft + (iw + 0.5) * width; /* center of cell iw */
1481  score += (xwc - xc) * (xwc - xc);
1482  numaGetIValue(nad, iw, &ival);
1483  numaSetValue(nad, iw, ival + 1);
1484  }
1485 
1486  if (pscore)
1487  *pscore = 4.0 * score / (width * width * (l_float32)nc);
1488  if (pnad)
1489  *pnad = nad;
1490  else
1491  numaDestroy(&nad);
1492 
1493  return 0;
1494 }
void gplotDestroy(GPLOT **pgplot)
gplotDestroy()
Definition: gplot.c:197
NUMA * pixExtractBarcodeCrossings(PIX *pixs, l_float32 thresh, l_int32 debugflag)
pixExtractBarcodeCrossings()
Definition: readbarcode.c:713
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:692
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:1944
Definition: pix.h:717
l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plottitle)
gplotAddPlot()
Definition: gplot.c:263
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:568
static PIX * pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace, l_int32 nwidth, l_int32 nheight)
pixGenerateBarcodeMask()
Definition: readbarcode.c:444
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:878
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
Definition: gplot.c:379
GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel)
gplotCreate()
Definition: gplot.c:138
static l_int32 numaEvalSyncError(NUMA *nas, l_int32 ifirst, l_int32 ilast, l_float32 width, l_float32 shift, l_float32 *pscore, NUMA **pnad)
numaEvalSyncError()
Definition: readbarcode.c:1443
Definition: pix.h:716
static l_int32 numaEvalBestWidthAndShift(NUMA *nas, l_int32 nwidth, l_int32 nshift, l_float32 minwidth, l_float32 maxwidth, l_float32 *pbestwidth, l_float32 *pbestshift, l_float32 *pbestscore)
numaEvalBestWidthAndShift()
Definition: readbarcode.c:1369
l_ok boxaWriteStream(FILE *fp, BOXA *boxa)
boxaWriteStream()
Definition: boxbasic.c:2242
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
NUMA * numaQuantizeCrossingsByWidth(NUMA *nas, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
numaQuantizeCrossingsByWidth()
Definition: readbarcode.c:837
NUMA * numaMakeHistogramClipped(NUMA *na, l_float32 binsize, l_float32 maxsize)
numaMakeHistogramClipped()
Definition: numafunc2.c:1075
char * barcodeDispatchDecoder(char *barstr, l_int32 format, l_int32 debugflag)
barcodeDispatchDecoder()
Definition: bardecode.c:96
l_ok pixFindSkewSweepAndSearchScore(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_float32 *pendscore, l_int32 redsweep, l_int32 redsearch, l_float32 sweepcenter, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta)
pixFindSkewSweepAndSearchScore()
Definition: skew.c:612
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:163
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1395
NUMA * numaQuantizeCrossingsByWindow(NUMA *nas, l_float32 ratio, l_float32 *pwidth, l_float32 *pfirstloc, NUMA **pnac, l_int32 debugflag)
numaQuantizeCrossingsByWindow()
Definition: readbarcode.c:1267
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:534
l_ok numaWriteStream(FILE *fp, NUMA *na)
numaWriteStream()
Definition: numabasic.c:1246
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:580
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:658
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:443
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1020
Definition: pix.h:492
l_int32 barcodeFormatIsSupported(l_int32 format)
barcodeFormatIsSupported()
Definition: bardecode.c:173
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:759
l_ok numaSelectCrossingThreshold(NUMA *nax, NUMA *nay, l_float32 estthresh, l_float32 *pbestthresh)
numaSelectCrossingThreshold()
Definition: numafunc2.c:2672
Definition: array.h:116
NUMA * pixExtractBarcodeWidths1(PIX *pixs, l_float32 thresh, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
pixExtractBarcodeWidths1()
Definition: readbarcode.c:626
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:147
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1574
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:446
PIX * pixDeskewBarcode(PIX *pixs, PIX *pixb, BOX *box, l_int32 margin, l_int32 threshold, l_float32 *pangle, l_float32 *pconf)
pixDeskewBarcode()
Definition: readbarcode.c:500
SARRAY * pixReadBarcodes(PIXA *pixa, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixReadBarcodes()
Definition: readbarcode.c:254
PIX * pixaDisplayTiledInRows(PIXA *pixa, l_int32 outdepth, l_int32 maxwidth, l_float32 scalefactor, l_int32 background, l_int32 spacing, l_int32 border)
pixaDisplayTiledInRows()
Definition: pixafunc2.c:836
SARRAY * pixProcessBarcodes(PIX *pixs, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixProcessBarcodes()
Definition: readbarcode.c:134
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
NUMA * pixReadBarcodeWidths(PIX *pixs, l_int32 method, l_int32 debugflag)
pixReadBarcodeWidths()
Definition: readbarcode.c:335
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
NUMA * pixExtractBarcodeWidths2(PIX *pixs, l_float32 thresh, l_float32 *pwidth, NUMA **pnac, l_int32 debugflag)
pixExtractBarcodeWidths2()
Definition: readbarcode.c:679
Definition: gplot.h:75
static NUMA * pixAverageRasterScans(PIX *pixs, l_int32 nscans)
pixAverageRasterScans()
Definition: readbarcode.c:769
BOXA * pixLocateBarcodes(PIX *pixs, l_int32 thresh, PIX **ppixb, PIX **ppixm)
pixLocateBarcodes()
Definition: readbarcode.c:384
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
PIX * pixRotateOrth(PIX *pixs, l_int32 quads)
pixRotateOrth()
Definition: rotateorth.c:72
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:763
static NUMA * numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent)
numaGetPeakWidthLUT()
Definition: readbarcode.c:1175
Definition: pix.h:454
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:812
NUMA * numaCrossingsByThreshold(NUMA *nax, NUMA *nay, l_float32 thresh)
numaCrossingsByThreshold()
Definition: numafunc2.c:2779
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
l_ok numaGetMin(NUMA *na, l_float32 *pminval, l_int32 *piminloc)
numaGetMin()
Definition: numafunc1.c:444
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1446
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:865
static NUMA * numaGetPeakCentroids(NUMA *nahist, NUMA *narange)
numaGetPeakCentroids()
Definition: readbarcode.c:1124
static NUMA * numaLocatePeakRanges(NUMA *nas, l_float32 minfirst, l_float32 minsep, l_float32 maxmin)
numaLocatePeakRanges()
Definition: readbarcode.c:1071
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
Definition: pix.h:718
static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist, NUMA **pnaodist, l_float32 *pmindist, l_float32 *pmaxdist)
numaGetCrossingDistances()
Definition: readbarcode.c:982
Definition: pix.h:134
Definition: pix.h:719
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:91
PIXA * pixExtractBarcodes(PIX *pixs, l_int32 debugflag)
pixExtractBarcodes()
Definition: readbarcode.c:182
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:278
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:718
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:486
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:547
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:310
Definition: pix.h:480
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:408
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:165
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:631
PIX * pixRotate(PIX *pixs, l_float32 angle, l_int32 type, l_int32 incolor, l_int32 width, l_int32 height)
pixRotate()
Definition: rotate.c:99
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355