Leptonica 1.82.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#ifdef HAVE_CONFIG_H
84#include <config_auto.h>
85#endif /* HAVE_CONFIG_H */
86
87#include <string.h>
88#include "allheaders.h"
89#include "readbarcode.h"
90
91 /* Parameters for pixGenerateBarcodeMask() */
92static const l_int32 MAX_SPACE_WIDTH = 19; /* was 15 */
93static const l_int32 MAX_NOISE_WIDTH = 50; /* smaller than barcode width */
94static const l_int32 MAX_NOISE_HEIGHT = 30; /* smaller than barcode height */
95
96 /* Minimum barcode image size */
97static const l_int32 MIN_BC_WIDTH = 50;
98static const l_int32 MIN_BC_HEIGHT = 50;
99
100 /* Static functions */
101static PIX *pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace,
102 l_int32 nwidth, l_int32 nheight);
103static NUMA *pixAverageRasterScans(PIX *pixs, l_int32 nscans);
104static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist,
105 NUMA **pnaodist, l_float32 *pmindist,
106 l_float32 *pmaxdist);
107static NUMA *numaLocatePeakRanges(NUMA *nas, l_float32 minfirst,
108 l_float32 minsep, l_float32 maxmin);
109static NUMA *numaGetPeakCentroids(NUMA *nahist, NUMA *narange);
110static NUMA *numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent);
111static l_int32 numaEvalBestWidthAndShift(NUMA *nas, l_int32 nwidth,
112 l_int32 nshift, l_float32 minwidth,
113 l_float32 maxwidth,
114 l_float32 *pbestwidth,
115 l_float32 *pbestshift,
116 l_float32 *pbestscore);
117static l_int32 numaEvalSyncError(NUMA *nas, l_int32 ifirst, l_int32 ilast,
118 l_float32 width, l_float32 shift,
119 l_float32 *pscore, NUMA **pnad);
120
121
122#ifndef NO_CONSOLE_IO
123#define DEBUG_DESKEW 0
124#define DEBUG_WIDTHS 0
125#endif /* ~NO_CONSOLE_IO */
126
127
128/*------------------------------------------------------------------------*
129 * Top level *
130 *------------------------------------------------------------------------*/
141SARRAY *
143 l_int32 format,
144 l_int32 method,
145 SARRAY **psaw,
146 l_int32 debugflag)
147{
148PIX *pixg;
149PIXA *pixa;
150SARRAY *sad;
151
152 PROCNAME("pixProcessBarcodes");
153
154 if (psaw) *psaw = NULL;
155 if (!pixs)
156 return (SARRAY *)ERROR_PTR("pixs not defined", procName, NULL);
157 if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
158 return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
159 if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
160 return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
161
162 /* Get an 8 bpp image, no cmap */
163 if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
164 pixg = pixClone(pixs);
165 else
166 pixg = pixConvertTo8(pixs, 0);
167
168 pixa = pixExtractBarcodes(pixg, debugflag);
169 pixDestroy(&pixg);
170 if (!pixa)
171 return (SARRAY *)ERROR_PTR("no barcode(s) found", procName, NULL);
172
173 sad = pixReadBarcodes(pixa, format, method, psaw, debugflag);
174 pixaDestroy(&pixa);
175 return sad;
176}
177
178
187PIXA *
189 l_int32 debugflag)
190{
191l_int32 i, n;
192l_float32 angle, conf;
193BOX *box;
194BOXA *boxa;
195PIX *pix1, *pix2, *pix3;
196PIXA *pixa;
197
198 PROCNAME("pixExtractBarcodes");
199
200 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
201 return (PIXA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
202
203 /* Locate them; use small threshold for edges. */
204 boxa = pixLocateBarcodes(pixs, 20, &pix2, &pix1);
205 n = boxaGetCount(boxa);
206 L_INFO("%d possible barcode(s) found\n", procName, n);
207 if (n == 0) {
208 boxaDestroy(&boxa);
209 pixDestroy(&pix2);
210 pixDestroy(&pix1);
211 return NULL;
212 }
213
214 if (debugflag) {
215 boxaWriteStderr(boxa);
216 pixDisplay(pix2, 100, 100);
217 pixDisplay(pix1, 800, 100);
218 }
219 pixDestroy(&pix1);
220
221 /* Deskew each barcode individually */
222 pixa = pixaCreate(n);
223 for (i = 0; i < n; i++) {
224 box = boxaGetBox(boxa, i, L_CLONE);
225 pix3 = pixDeskewBarcode(pixs, pix2, box, 15, 20, &angle, &conf);
226 if (!pix3) conf = 0.0; /* don't use */
227 L_INFO("angle = %6.2f, conf = %6.2f\n", procName, angle, conf);
228 if (conf > 5.0) {
229 pixaAddPix(pixa, pix3, L_INSERT);
230 pixaAddBox(pixa, box, L_INSERT);
231 } else {
232 pixDestroy(&pix3);
233 boxDestroy(&box);
234 }
235 }
236 pixDestroy(&pix2);
237 boxaDestroy(&boxa);
238
239#if DEBUG_DESKEW
240 pix3 = pixaDisplayTiledInRows(pixa, 8, 1000, 1.0, 0, 30, 2);
241 pixWrite("/tmp/lept/pix3.png", pix3, IFF_PNG);
242 pixDestroy(&pix3);
243#endif /* DEBUG_DESKEW */
244
245 return pixa;
246}
247
248
260SARRAY *
262 l_int32 format,
263 l_int32 method,
264 SARRAY **psaw,
265 l_int32 debugflag)
266{
267char *barstr, *data;
268char emptystring[] = "";
269l_int32 w, h, i, j, n, nbars, ival;
270NUMA *na;
271PIX *pix1;
272SARRAY *saw, *sad;
273
274 PROCNAME("pixReadBarcodes");
275
276 if (psaw) *psaw = NULL;
277 if (!pixa)
278 return (SARRAY *)ERROR_PTR("pixa not defined", procName, NULL);
279 if (format != L_BF_ANY && !barcodeFormatIsSupported(format))
280 return (SARRAY *)ERROR_PTR("unsupported format", procName, NULL);
281 if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
282 return (SARRAY *)ERROR_PTR("invalid method", procName, NULL);
283
284 n = pixaGetCount(pixa);
285 saw = sarrayCreate(n);
286 sad = sarrayCreate(n);
287 for (i = 0; i < n; i++) {
288 /* Extract the widths of the lines in each barcode */
289 pix1 = pixaGetPix(pixa, i, L_CLONE);
290 pixGetDimensions(pix1, &w, &h, NULL);
291 if (w < MIN_BC_WIDTH || h < MIN_BC_HEIGHT) {
292 L_ERROR("pix is too small: w = %d, h = %d\n", procName, w, h);
293 pixDestroy(&pix1);
294 continue;
295 }
296 na = pixReadBarcodeWidths(pix1, method, debugflag);
297 pixDestroy(&pix1);
298 if (!na) {
299 ERROR_INT("valid barcode widths not returned", procName, 1);
300 continue;
301 }
302
303 /* Save the widths as a string */
304 nbars = numaGetCount(na);
305 barstr = (char *)LEPT_CALLOC(nbars + 1, sizeof(char));
306 for (j = 0; j < nbars; j++) {
307 numaGetIValue(na, j, &ival);
308 barstr[j] = 0x30 + ival;
309 }
310 sarrayAddString(saw, barstr, L_INSERT);
311 numaDestroy(&na);
312
313 /* Decode the width strings */
314 data = barcodeDispatchDecoder(barstr, format, debugflag);
315 if (!data) {
316 ERROR_INT("barcode not decoded", procName, 1);
317 sarrayAddString(sad, emptystring, L_COPY);
318 continue;
319 }
320 sarrayAddString(sad, data, L_INSERT);
321 }
322
323 /* If nothing found, clean up */
324 if (sarrayGetCount(saw) == 0) {
325 sarrayDestroy(&saw);
326 sarrayDestroy(&sad);
327 return (SARRAY *)ERROR_PTR("no valid barcode data", procName, NULL);
328 }
329
330 if (psaw)
331 *psaw = saw;
332 else
333 sarrayDestroy(&saw);
334 return sad;
335}
336
337
346NUMA *
348 l_int32 method,
349 l_int32 debugflag)
350{
351l_float32 winwidth;
352NUMA *na;
353
354 PROCNAME("pixReadBarcodeWidths");
355
356 if (!pixs)
357 return (NUMA *)ERROR_PTR("pixs not defined", procName, NULL);
358 if (pixGetDepth(pixs) != 8)
359 return (NUMA *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
360 if (method != L_USE_WIDTHS && method != L_USE_WINDOWS)
361 return (NUMA *)ERROR_PTR("invalid method", procName, NULL);
362
363 /* Extract the widths of the lines in each barcode */
364 if (method == L_USE_WIDTHS)
365 na = pixExtractBarcodeWidths1(pixs, 120, 0.25, NULL, NULL,
366 debugflag);
367 else /* method == L_USE_WINDOWS */
368 na = pixExtractBarcodeWidths2(pixs, 120, &winwidth,
369 NULL, debugflag);
370#if DEBUG_WIDTHS
371 if (method == L_USE_WINDOWS)
372 lept_stderr("Window width for barcode: %7.3f\n", winwidth);
373 numaWriteStderr(na);
374#endif /* DEBUG_WIDTHS */
375
376 if (!na)
377 return (NUMA *)ERROR_PTR("barcode widths invalid", procName, NULL);
378
379 return na;
380}
381
382
383/*------------------------------------------------------------------------*
384 * Locate barcode in image *
385 *------------------------------------------------------------------------*/
395BOXA *
397 l_int32 thresh,
398 PIX **ppixb,
399 PIX **ppixm)
400{
401BOXA *boxa;
402PIX *pix8, *pixe, *pixb, *pixm;
403
404 PROCNAME("pixLocateBarcodes");
405
406 if (!pixs)
407 return (BOXA *)ERROR_PTR("pixs not defined", procName, NULL);
408
409 /* Get an 8 bpp image, no cmap */
410 if (pixGetDepth(pixs) == 8 && !pixGetColormap(pixs))
411 pix8 = pixClone(pixs);
412 else
413 pix8 = pixConvertTo8(pixs, 0);
414
415 /* Get a 1 bpp image of the edges */
416 pixe = pixSobelEdgeFilter(pix8, L_ALL_EDGES);
417 pixb = pixThresholdToBinary(pixe, thresh);
418 pixInvert(pixb, pixb);
419 pixDestroy(&pix8);
420 pixDestroy(&pixe);
421
422 pixm = pixGenerateBarcodeMask(pixb, MAX_SPACE_WIDTH, MAX_NOISE_WIDTH,
423 MAX_NOISE_HEIGHT);
424 boxa = pixConnComp(pixm, NULL, 8);
425
426 if (ppixb)
427 *ppixb = pixb;
428 else
429 pixDestroy(&pixb);
430 if (ppixm)
431 *ppixm = pixm;
432 else
433 pixDestroy(&pixm);
434
435 return boxa;
436}
437
438
455static PIX *
457 l_int32 maxspace,
458 l_int32 nwidth,
459 l_int32 nheight)
460{
461PIX *pixt1, *pixt2, *pixd;
462
463 PROCNAME("pixGenerateBarcodeMask");
464
465 if (!pixs || pixGetDepth(pixs) != 1)
466 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
467
468 /* Identify horizontal barcodes */
469 pixt1 = pixCloseBrick(NULL, pixs, maxspace + 1, 1);
470 pixt2 = pixOpenBrick(NULL, pixs, maxspace + 1, 1);
471 pixXor(pixt2, pixt2, pixt1);
472 pixOpenBrick(pixt2, pixt2, nwidth, nheight);
473 pixDestroy(&pixt1);
474
475 /* Identify vertical barcodes */
476 pixt1 = pixCloseBrick(NULL, pixs, 1, maxspace + 1);
477 pixd = pixOpenBrick(NULL, pixs, 1, maxspace + 1);
478 pixXor(pixd, pixd, pixt1);
479 pixOpenBrick(pixd, pixd, nheight, nwidth);
480 pixDestroy(&pixt1);
481
482 /* Combine to get all barcodes */
483 pixOr(pixd, pixd, pixt2);
484 pixDestroy(&pixt2);
485
486 return pixd;
487}
488
489
490/*------------------------------------------------------------------------*
491 * Extract and deskew barcode *
492 *------------------------------------------------------------------------*/
511PIX *
513 PIX *pixb,
514 BOX *box,
515 l_int32 margin,
516 l_int32 threshold,
517 l_float32 *pangle,
518 l_float32 *pconf)
519{
520l_int32 x, y, w, h, n;
521l_float32 angle, angle1, angle2, conf, conf1, conf2, score1, score2, deg2rad;
522BOX *box1, *box2;
523BOXA *boxa1, *boxa2;
524PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pixd;
525
526 PROCNAME("pixDeskewBarcode");
527
528 if (pangle) *pangle = 0.0;
529 if (pconf) *pconf = 0.0;
530 if (!pixs || pixGetDepth(pixs) != 8)
531 return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
532 if (!pixb || pixGetDepth(pixb) != 1)
533 return (PIX *)ERROR_PTR("pixb undefined or not 1 bpp", procName, NULL);
534 if (!box)
535 return (PIX *)ERROR_PTR("box not defined or 1 bpp", procName, NULL);
536
537 /* Clip out */
538 deg2rad = 3.1415926535 / 180.;
539 boxGetGeometry(box, &x, &y, &w, &h);
540 box2 = boxCreate(x - 25, y - 25, w + 51, h + 51);
541 pix1 = pixClipRectangle(pixb, box2, NULL);
542 pix2 = pixClipRectangle(pixs, box2, NULL);
543 boxDestroy(&box2);
544
545 /* Deskew, looking at all possible orientations over 180 degrees */
546 pix3 = pixRotateOrth(pix1, 1); /* look for vertical bar lines */
547 pix4 = pixClone(pix1); /* look for horizontal bar lines */
548 pixFindSkewSweepAndSearchScore(pix3, &angle1, &conf1, &score1,
549 1, 1, 0.0, 45.0, 2.5, 0.01);
550 pixFindSkewSweepAndSearchScore(pix4, &angle2, &conf2, &score2,
551 1, 1, 0.0, 45.0, 2.5, 0.01);
552 pixDestroy(&pix1);
553 pixDestroy(&pix3);
554 pixDestroy(&pix4);
555
556 /* Because we're using the boundary pixels of the barcodes,
557 * the peak can be sharper (and the confidence ratio higher)
558 * from the signal across the top and bottom of the barcode.
559 * However, the max score, which is the magnitude of the signal
560 * at the optimum skew angle, will be smaller, so we use the
561 * max score as the primary indicator of orientation. */
562 if (score1 >= score2) {
563 conf = conf1;
564 if (conf1 > 6.0 && L_ABS(angle1) > 0.1) {
565 angle = angle1;
566 pix5 = pixRotate(pix2, deg2rad * angle1, L_ROTATE_AREA_MAP,
567 L_BRING_IN_WHITE, 0, 0);
568 } else {
569 angle = 0.0;
570 pix5 = pixClone(pix2);
571 }
572 } else { /* score2 > score1 */
573 conf = conf2;
574 pix6 = pixRotateOrth(pix2, 1);
575 if (conf2 > 6.0 && L_ABS(angle2) > 0.1) {
576 angle = 90.0 + angle2;
577 pix5 = pixRotate(pix6, deg2rad * angle2, L_ROTATE_AREA_MAP,
578 L_BRING_IN_WHITE, 0, 0);
579 } else {
580 angle = 90.0;
581 pix5 = pixClone(pix6);
582 }
583 pixDestroy(&pix6);
584 }
585 pixDestroy(&pix2);
586
587 /* Extract barcode plus a margin around it */
588 boxa1 = pixLocateBarcodes(pix5, threshold, 0, 0);
589 if ((n = boxaGetCount(boxa1)) != 1) {
590 L_WARNING("barcode mask in %d components\n", procName, n);
591 boxa2 = boxaSort(boxa1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL);
592 } else {
593 boxa2 = boxaCopy(boxa1, L_CLONE);
594 }
595 box1 = boxaGetBox(boxa2, 0, L_CLONE);
596 boxGetGeometry(box1, &x, &y, &w, &h);
597 box2 = boxCreate(x - margin, y - margin, w + 2 * margin,
598 h + 2 * margin);
599 pixd = pixClipRectangle(pix5, box2, NULL);
600 boxDestroy(&box1);
601 boxDestroy(&box2);
602 boxaDestroy(&boxa1);
603 boxaDestroy(&boxa2);
604 pixDestroy(&pix5);
605
606 if (pangle) *pangle = angle;
607 if (pconf) *pconf = conf;
608
609 if (!pixd)
610 L_ERROR("pixd not made\n", procName);
611 return pixd;
612}
613
614
615/*------------------------------------------------------------------------*
616 * Process to get line widths *
617 *------------------------------------------------------------------------*/
641NUMA *
643 l_float32 thresh,
644 l_float32 binfract,
645 NUMA **pnaehist,
646 NUMA **pnaohist,
647 l_int32 debugflag)
648{
649NUMA *nac, *nad;
650
651 PROCNAME("pixExtractBarcodeWidths1");
652
653 if (pnaehist) *pnaehist = NULL;
654 if (pnaohist) *pnaehist = NULL;
655 if (!pixs || pixGetDepth(pixs) != 8)
656 return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
657
658 /* Get the best estimate of the crossings, in pixel units */
659 if ((nac = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
660 return (NUMA *)ERROR_PTR("nac not made", procName, NULL);
661
662 /* Get the array of bar widths, starting with a black bar */
663 nad = numaQuantizeCrossingsByWidth(nac, binfract, pnaehist,
664 pnaohist, debugflag);
665
666 numaDestroy(&nac);
667 return nad;
668}
669
670
697NUMA *
699 l_float32 thresh,
700 l_float32 *pwidth,
701 NUMA **pnac,
702 l_int32 debugflag)
703{
704l_int32 width;
705NUMA *nac, *nacp, *nad;
706
707 PROCNAME("pixExtractBarcodeWidths2");
708
709 if (pwidth) *pwidth = 0;
710 if (pnac) *pnac = NULL;
711 if (!pixs || pixGetDepth(pixs) != 8)
712 return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
713
714 /* Get the best estimate of the crossings, in pixel units */
715 if ((nacp = pixExtractBarcodeCrossings(pixs, thresh, debugflag)) == NULL)
716 return (NUMA *)ERROR_PTR("nacp not made", procName, NULL);
717
718 /* Quantize the crossings to get actual windowed data */
719 nad = numaQuantizeCrossingsByWindow(nacp, 2.0, pwidth, NULL,
720 pnac, debugflag);
721 numaDestroy(&nacp);
722 return nad;
723}
724
725
740NUMA *
742 l_float32 thresh,
743 l_int32 debugflag)
744{
745l_int32 w;
746l_float32 bestthresh;
747GPLOT *gplot;
748NUMA *nas, *nax, *nay, *nad;
749
750 PROCNAME("pixExtractBarcodeCrossings");
751
752 if (!pixs || pixGetDepth(pixs) != 8)
753 return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
754
755 /* Scan pixels horizontally and average results */
756 if ((nas = pixAverageRasterScans(pixs, 50)) == NULL)
757 return (NUMA *)ERROR_PTR("nas not made", procName, NULL);
758
759 /* Interpolate to get 4x the number of values */
760 w = pixGetWidth(pixs);
762 (l_float32)(w - 1), 4 * w + 1, &nax, &nay);
763
764 if (debugflag) {
765 lept_mkdir("lept/barcode");
766 gplot = gplotCreate("/tmp/lept/barcode/signal", GPLOT_PNG,
767 "Pixel values", "dist in pixels", "value");
768 gplotAddPlot(gplot, nax, nay, GPLOT_LINES, "plot 1");
769 gplotMakeOutput(gplot);
770 gplotDestroy(&gplot);
771 }
772
773 /* Locate the crossings. Run multiple times with different
774 * thresholds, and choose a threshold in the center of the
775 * run of thresholds that all give the maximum number of crossings. */
776 numaSelectCrossingThreshold(nax, nay, thresh, &bestthresh);
777
778 /* Get the crossings with the best threshold. */
779 nad = numaCrossingsByThreshold(nax, nay, bestthresh);
780 numaDestroy(&nas);
781 numaDestroy(&nax);
782 numaDestroy(&nay);
783
784 if (numaGetCount(nad) < 10) {
785 L_ERROR("Only %d crossings; failure\n", procName, numaGetCount(nad));
786 numaDestroy(&nad);
787 }
788 return nad;
789}
790
791
792/*------------------------------------------------------------------------*
793 * Average adjacent rasters *
794 *------------------------------------------------------------------------*/
802static NUMA *
804 l_int32 nscans)
805{
806l_int32 w, h, first, last, i, j, wpl, val;
807l_uint32 *line, *data;
808l_float32 *array;
809NUMA *nad;
810
811 PROCNAME("pixAverageRasterScans");
812
813 if (!pixs || pixGetDepth(pixs) != 8)
814 return (NUMA *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
815
816 pixGetDimensions(pixs, &w, &h, NULL);
817 if (nscans > h) {
818 first = 0;
819 last = h - 1;
820 nscans = h;
821 } else {
822 first = (h - nscans) / 2;
823 last = first + nscans - 1;
824 }
825
826 nad = numaCreate(w);
827 numaSetCount(nad, w);
828 array = numaGetFArray(nad, L_NOCOPY);
829 wpl = pixGetWpl(pixs);
830 data = pixGetData(pixs);
831 for (j = 0; j < w; j++) {
832 for (i = first; i <= last; i++) {
833 line = data + i * wpl;
834 val = GET_DATA_BYTE(line, j);
835 array[j] += val;
836 }
837 array[j] = array[j] / (l_float32)nscans;
838 }
839
840 return nad;
841}
842
843
844/*------------------------------------------------------------------------*
845 * Signal processing for barcode widths *
846 *------------------------------------------------------------------------*/
870NUMA *
872 l_float32 binfract,
873 NUMA **pnaehist,
874 NUMA **pnaohist,
875 l_int32 debugflag)
876{
877l_int32 i, n, ret, ned, nod, iw, width;
878l_float32 val, minsize, maxsize, factor;
879GPLOT *gplot;
880NUMA *naedist, *naodist, *naehist, *naohist, *naecent, *naocent;
881NUMA *naerange, *naorange, *naelut, *naolut, *nad;
882
883 PROCNAME("numaQuantizeCrossingsByWidth");
884
885 if (pnaehist) *pnaehist = NULL;
886 if (pnaohist) *pnaohist = NULL;
887 if (!nas)
888 return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
889 n = numaGetCount(nas);
890 if (n < 10)
891 return (NUMA *)ERROR_PTR("n < 10", procName, NULL);
892 if (binfract <= 0.0)
893 return (NUMA *)ERROR_PTR("binfract <= 0.0", procName, NULL);
894
895 /* Get even and odd crossing distances, and determine the rank
896 * widths for rank 0.1 (minsize) and 0.9 (maxsize). */
897 ret = numaGetCrossingDistances(nas, &naedist, &naodist, &minsize, &maxsize);
898 if (ret || minsize < 1.0 || maxsize / minsize > 8.0) {
899 L_ERROR("bad data, or minsize = %5.2f < 1.0 or max/min = %f > 4.0\n",
900 procName, minsize, maxsize / minsize);
901 numaDestroy(&naedist);
902 numaDestroy(&naodist);
903 return NULL;
904 }
905
906 /* Bin the spans in units of binfract * minsize. These
907 * units are convenient because they scale to make at least
908 * 1/binfract bins in the smallest span (width). We want this
909 * number to be large enough to clearly separate the
910 * widths, but small enough so that the histogram peaks
911 * have very few if any holes (zeroes) within them. */
912 naehist = numaMakeHistogramClipped(naedist, binfract * minsize,
913 (1.25 / binfract) * maxsize);
914 naohist = numaMakeHistogramClipped(naodist, binfract * minsize,
915 (1.25 / binfract) * maxsize);
916
917 if (debugflag) {
918 lept_mkdir("lept/barcode");
919 gplot = gplotCreate("/tmp/lept/barcode/histw", GPLOT_PNG,
920 "Raw width histogram", "Width", "Number");
921 gplotAddPlot(gplot, NULL, naehist, GPLOT_LINES, "plot black");
922 gplotAddPlot(gplot, NULL, naohist, GPLOT_LINES, "plot white");
923 gplotMakeOutput(gplot);
924 gplotDestroy(&gplot);
925 }
926
927 /* Compute the peak ranges, still in units of binfract * minsize. */
928 naerange = numaLocatePeakRanges(naehist, 1.0 / binfract,
929 1.0 / binfract, 0.0);
930 naorange = numaLocatePeakRanges(naohist, 1.0 / binfract,
931 1.0 / binfract, 0.0);
932
933 /* Find the centroid values of each peak */
934 naecent = numaGetPeakCentroids(naehist, naerange);
935 naocent = numaGetPeakCentroids(naohist, naorange);
936
937 /* Generate the lookup tables that map from the bar width, in
938 * units of (binfract * minsize), to the integerized barcode
939 * units (1, 2, 3, 4), which are the output integer widths
940 * between transitions. */
941 naelut = numaGetPeakWidthLUT(naerange, naecent);
942 naolut = numaGetPeakWidthLUT(naorange, naocent);
943
944 /* Get the widths. Because the LUT accepts our funny units,
945 * we first must convert the pixel widths to these units,
946 * which is what 'factor' does. */
947 nad = numaCreate(0);
948 ned = numaGetCount(naedist);
949 nod = numaGetCount(naodist);
950 if (nod != ned - 1)
951 L_WARNING("ned != nod + 1\n", procName);
952 factor = 1.0 / (binfract * minsize); /* for converting units */
953 for (i = 0; i < ned - 1; i++) {
954 numaGetFValue(naedist, i, &val);
955 width = (l_int32)(factor * val);
956 numaGetIValue(naelut, width, &iw);
957 numaAddNumber(nad, iw);
958/* lept_stderr("even: val = %7.3f, width = %d, iw = %d\n",
959 val, width, iw); */
960 numaGetFValue(naodist, i, &val);
961 width = (l_int32)(factor * val);
962 numaGetIValue(naolut, width, &iw);
963 numaAddNumber(nad, iw);
964/* lept_stderr("odd: val = %7.3f, width = %d, iw = %d\n",
965 val, width, iw); */
966 }
967 numaGetFValue(naedist, ned - 1, &val);
968 width = (l_int32)(factor * val);
969 numaGetIValue(naelut, width, &iw);
970 numaAddNumber(nad, iw);
971
972 if (debugflag) {
973 lept_stderr(" ---- Black bar widths (pixels) ------ \n");
974 numaWriteStderr(naedist);
975 lept_stderr(" ---- Histogram of black bar widths ------ \n");
976 numaWriteStderr(naehist);
977 lept_stderr(" ---- Peak ranges in black bar histogram bins --- \n");
978 numaWriteStderr(naerange);
979 lept_stderr(" ---- Peak black bar centroid width values ------ \n");
980 numaWriteStderr(naecent);
981 lept_stderr(" ---- Black bar lookup table ------ \n");
982 numaWriteStderr(naelut);
983 lept_stderr(" ---- White bar widths (pixels) ------ \n");
984 numaWriteStderr(naodist);
985 lept_stderr(" ---- Histogram of white bar widths ------ \n");
986 numaWriteStderr(naohist);
987 lept_stderr(" ---- Peak ranges in white bar histogram bins --- \n");
988 numaWriteStderr(naorange);
989 lept_stderr(" ---- Peak white bar centroid width values ------ \n");
990 numaWriteStderr(naocent);
991 lept_stderr(" ---- White bar lookup table ------ \n");
992 numaWriteStderr(naolut);
993 }
994
995 numaDestroy(&naedist);
996 numaDestroy(&naodist);
997 numaDestroy(&naerange);
998 numaDestroy(&naorange);
999 numaDestroy(&naecent);
1000 numaDestroy(&naocent);
1001 numaDestroy(&naelut);
1002 numaDestroy(&naolut);
1003 if (pnaehist)
1004 *pnaehist = naehist;
1005 else
1006 numaDestroy(&naehist);
1007 if (pnaohist)
1008 *pnaohist = naohist;
1009 else
1010 numaDestroy(&naohist);
1011 return nad;
1012}
1013
1014
1025static l_int32
1027 NUMA **pnaedist,
1028 NUMA **pnaodist,
1029 l_float32 *pmindist,
1030 l_float32 *pmaxdist)
1031{
1032l_int32 i, n, nspan;
1033l_float32 val, newval, mindist, maxdist, dist;
1034NUMA *na1, *na2, *naedist, *naodist;
1035
1036 PROCNAME("numaGetCrossingDistances");
1037
1038 if (pnaedist) *pnaedist = NULL;
1039 if (pnaodist) *pnaodist = NULL;
1040 if (pmindist) *pmindist = 0.0;
1041 if (pmaxdist) *pmaxdist = 0.0;
1042 if (!nas)
1043 return ERROR_INT("nas not defined", procName, 1);
1044 if ((n = numaGetCount(nas)) < 2)
1045 return ERROR_INT("n < 2", procName, 1);
1046
1047 /* Get numas of distances between crossings. Separate these
1048 * into even (e.g., black) and odd (e.g., white) spans.
1049 * For barcodes, the black spans are 0, 2, etc. These
1050 * distances are in pixel units. */
1051 naedist = numaCreate(n / 2 + 1);
1052 naodist = numaCreate(n / 2);
1053 numaGetFValue(nas, 0, &val);
1054 for (i = 1; i < n; i++) {
1055 numaGetFValue(nas, i, &newval);
1056 if (i % 2)
1057 numaAddNumber(naedist, newval - val);
1058 else
1059 numaAddNumber(naodist, newval - val);
1060 val = newval;
1061 }
1062
1063 /* The min and max rank distances of the spans are in pixel units. */
1064 na1 = numaCopy(naedist);
1065 numaJoin(na1, naodist, 0, -1); /* use both bars and spaces */
1066 nspan = numaGetCount(na1);
1067 na2 = numaMakeHistogram(na1, 100, NULL, NULL);
1068 numaHistogramGetValFromRank(na2, 0.1, &mindist);
1069 numaHistogramGetValFromRank(na2, 0.9, &maxdist);
1070 numaDestroy(&na1);
1071 numaDestroy(&na2);
1072 L_INFO("mindist = %7.3f, maxdist = %7.3f\n", procName, mindist, maxdist);
1073
1074 if (pnaedist)
1075 *pnaedist = naedist;
1076 else
1077 numaDestroy(&naedist);
1078 if (pnaodist)
1079 *pnaodist = naodist;
1080 else
1081 numaDestroy(&naodist);
1082 if (pmindist) *pmindist = mindist;
1083 if (pmaxdist) *pmaxdist = maxdist;
1084 return 0;
1085}
1086
1087
1116static NUMA *
1118 l_float32 minfirst,
1119 l_float32 minsep,
1120 l_float32 maxmin)
1121{
1122l_int32 i, n, inpeak, left;
1123l_float32 center, prevcenter, val;
1124NUMA *nad;
1125
1126 PROCNAME("numaLocatePeakRanges");
1127
1128 if (!nas)
1129 return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1130 n = numaGetCount(nas);
1131 nad = numaCreate(0);
1132
1133 inpeak = FALSE;
1134 prevcenter = minfirst - minsep - 1.0;
1135 for (i = 0; i < n; i++) {
1136 numaGetFValue(nas, i, &val);
1137 if (inpeak == FALSE && val > maxmin) {
1138 inpeak = TRUE;
1139 left = i;
1140 } else if (inpeak == TRUE && val <= maxmin) { /* end peak */
1141 center = (left + i - 1.0) / 2.0;
1142 if (center - prevcenter >= minsep) { /* save new peak */
1143 inpeak = FALSE;
1144 numaAddNumber(nad, left);
1145 numaAddNumber(nad, i - 1);
1146 prevcenter = center;
1147 } else { /* attach to previous peak; revise the right edge */
1148 numaSetValue(nad, numaGetCount(nad) - 1, i - 1);
1149 }
1150 }
1151 }
1152 if (inpeak == TRUE) { /* save the last peak */
1153 numaAddNumber(nad, left);
1154 numaAddNumber(nad, n - 1);
1155 }
1156
1157 return nad;
1158}
1159
1160
1169static NUMA *
1171 NUMA *narange)
1172{
1173l_int32 i, j, nr, low, high;
1174l_float32 cent, sum, val;
1175NUMA *nad;
1176
1177 PROCNAME("numaGetPeakCentroids");
1178
1179 if (!nahist)
1180 return (NUMA *)ERROR_PTR("nahist not defined", procName, NULL);
1181 if (!narange)
1182 return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1183 nr = numaGetCount(narange) / 2;
1184
1185 nad = numaCreate(4);
1186 for (i = 0; i < nr; i++) {
1187 numaGetIValue(narange, 2 * i, &low);
1188 numaGetIValue(narange, 2 * i + 1, &high);
1189 cent = 0.0;
1190 sum = 0.0;
1191 for (j = low; j <= high; j++) {
1192 numaGetFValue(nahist, j, &val);
1193 cent += j * val;
1194 sum += val;
1195 }
1196 numaAddNumber(nad, cent / sum);
1197 }
1198
1199 return nad;
1200}
1201
1202
1220static NUMA *
1222 NUMA *nacent)
1223{
1224l_int32 i, j, nc, low, high, imax;
1225l_int32 assign[4];
1226l_float32 *warray;
1227l_float32 max, rat21, rat32, rat42;
1228NUMA *nalut;
1229
1230 PROCNAME("numaGetPeakWidthLUT");
1231
1232 if (!narange)
1233 return (NUMA *)ERROR_PTR("narange not defined", procName, NULL);
1234 if (!nacent)
1235 return (NUMA *)ERROR_PTR("nacent not defined", procName, NULL);
1236 nc = numaGetCount(nacent); /* half the size of narange */
1237 if (nc < 1 || nc > 4)
1238 return (NUMA *)ERROR_PTR("nc must be 1, 2, 3, or 4", procName, NULL);
1239
1240 /* Check the peak centroids for consistency with bar widths.
1241 * The third peak can correspond to a width of either 3 or 4.
1242 * Use ratios 3/2 and 4/2 instead of 3/1 and 4/1 because the
1243 * former are more stable and closer to the expected ratio. */
1244 if (nc > 1) {
1245 warray = numaGetFArray(nacent, L_NOCOPY);
1246 if (warray[0] == 0)
1247 return (NUMA *)ERROR_PTR("first peak has width 0.0",
1248 procName, NULL);
1249 rat21 = warray[1] / warray[0];
1250 if (rat21 < 1.5 || rat21 > 2.6)
1251 L_WARNING("width ratio 2/1 = %f\n", procName, rat21);
1252 if (nc > 2) {
1253 rat32 = warray[2] / warray[1];
1254 if (rat32 < 1.3 || rat32 > 2.25)
1255 L_WARNING("width ratio 3/2 = %f\n", procName, rat32);
1256 }
1257 if (nc == 4) {
1258 rat42 = warray[3] / warray[1];
1259 if (rat42 < 1.7 || rat42 > 2.3)
1260 L_WARNING("width ratio 4/2 = %f\n", procName, rat42);
1261 }
1262 }
1263
1264 /* Set width assignments.
1265 * The only possible ambiguity is with nc = 3 */
1266 for (i = 0; i < 4; i++)
1267 assign[i] = i + 1;
1268 if (nc == 3) {
1269 if (rat32 > 1.75)
1270 assign[2] = 4;
1271 }
1272
1273 /* Put widths into the LUT */
1274 numaGetMax(narange, &max, NULL);
1275 imax = (l_int32)max;
1276 nalut = numaCreate(imax + 1);
1277 numaSetCount(nalut, imax + 1); /* fill the array with zeroes */
1278 for (i = 0; i < nc; i++) {
1279 numaGetIValue(narange, 2 * i, &low);
1280 if (i == 0) low--; /* catch smallest width */
1281 numaGetIValue(narange, 2 * i + 1, &high);
1282 for (j = low; j <= high; j++)
1283 numaSetValue(nalut, j, assign[i]);
1284 }
1285
1286 return nalut;
1287}
1288
1289
1312NUMA *
1314 l_float32 ratio,
1315 l_float32 *pwidth,
1316 l_float32 *pfirstloc,
1317 NUMA **pnac,
1318 l_int32 debugflag)
1319{
1320l_int32 i, nw, started, count, trans;
1321l_float32 minsize, minwidth, minshift, xfirst;
1322NUMA *nac, *nad;
1323
1324 PROCNAME("numaQuantizeCrossingsByWindow");
1325
1326 if (!nas)
1327 return (NUMA *)ERROR_PTR("nas not defined", procName, NULL);
1328 if (numaGetCount(nas) < 2)
1329 return (NUMA *)ERROR_PTR("nas size < 2", procName, NULL);
1330
1331 /* Get the minsize, which is needed for the search for
1332 * the window width (ultimately found as 'minwidth') */
1333 numaGetCrossingDistances(nas, NULL, NULL, &minsize, NULL);
1334
1335 /* Compute the width and shift increments; start at minsize
1336 * and go up to ratio * minsize */
1337 numaEvalBestWidthAndShift(nas, 100, 10, minsize, ratio * minsize,
1338 &minwidth, &minshift, NULL);
1339
1340 /* Refine width and shift calculation */
1341 numaEvalBestWidthAndShift(nas, 100, 10, 0.98 * minwidth, 1.02 * minwidth,
1342 &minwidth, &minshift, NULL);
1343
1344 L_INFO("best width = %7.3f, best shift = %7.3f\n",
1345 procName, minwidth, minshift);
1346
1347 /* Get the crossing array (0,1,2) for the best window width and shift */
1348 numaEvalSyncError(nas, 0, 0, minwidth, minshift, NULL, &nac);
1349 if (pwidth) *pwidth = minwidth;
1350 if (pfirstloc) {
1351 numaGetFValue(nas, 0, &xfirst);
1352 *pfirstloc = xfirst + minshift;
1353 }
1354
1355 /* Get the array of bar widths, starting with a black bar */
1356 nad = numaCreate(0);
1357 nw = numaGetCount(nac); /* number of window measurements */
1358 started = FALSE;
1359 count = 0; /* unnecessary init */
1360 for (i = 0; i < nw; i++) {
1361 numaGetIValue(nac, i, &trans);
1362 if (trans > 2)
1363 L_WARNING("trans = %d > 2 !!!\n", procName, trans);
1364 if (started) {
1365 if (trans > 1) { /* i.e., when trans == 2 */
1366 numaAddNumber(nad, count);
1367 trans--;
1368 count = 1;
1369 }
1370 if (trans == 1) {
1371 numaAddNumber(nad, count);
1372 count = 1;
1373 } else {
1374 count++;
1375 }
1376 }
1377 if (!started && trans) {
1378 started = TRUE;
1379 if (trans == 2) /* a whole bar in this window */
1380 numaAddNumber(nad, 1);
1381 count = 1;
1382 }
1383 }
1384
1385 if (pnac)
1386 *pnac = nac;
1387 else
1388 numaDestroy(&nac);
1389 return nad;
1390}
1391
1392
1414static l_int32
1416 l_int32 nwidth,
1417 l_int32 nshift,
1418 l_float32 minwidth,
1419 l_float32 maxwidth,
1420 l_float32 *pbestwidth,
1421 l_float32 *pbestshift,
1422 l_float32 *pbestscore)
1423{
1424l_int32 i, j;
1425l_float32 delwidth, delshift, width, shift, score;
1426l_float32 bestwidth, bestshift, bestscore;
1427
1428 PROCNAME("numaEvalBestWidthAndShift");
1429
1430 if (!nas)
1431 return ERROR_INT("nas not defined", procName, 1);
1432 if (!pbestwidth || !pbestshift)
1433 return ERROR_INT("&bestwidth and &bestshift not defined", procName, 1);
1434
1435 bestwidth = 0.0f;
1436 bestshift = 0.0f;
1437 bestscore = 1.0;
1438 delwidth = (maxwidth - minwidth) / (nwidth - 1.0);
1439 for (i = 0; i < nwidth; i++) {
1440 width = minwidth + delwidth * i;
1441 delshift = width / (l_float32)(nshift);
1442 for (j = 0; j < nshift; j++) {
1443 shift = -0.5 * (width - delshift) + j * delshift;
1444 numaEvalSyncError(nas, 0, 0, width, shift, &score, NULL);
1445 if (score < bestscore) {
1446 bestscore = score;
1447 bestwidth = width;
1448 bestshift = shift;
1449#if DEBUG_FREQUENCY
1450 lept_stderr("width = %7.3f, shift = %7.3f, score = %7.3f\n",
1451 width, shift, score);
1452#endif /* DEBUG_FREQUENCY */
1453 }
1454 }
1455 }
1456
1457 *pbestwidth = bestwidth;
1458 *pbestshift = bestshift;
1459 if (pbestscore)
1460 *pbestscore = bestscore;
1461 return 0;
1462}
1463
1464
1488static l_int32
1490 l_int32 ifirst,
1491 l_int32 ilast,
1492 l_float32 width,
1493 l_float32 shift,
1494 l_float32 *pscore,
1495 NUMA **pnad)
1496{
1497l_int32 i, n, nc, nw, ival;
1498l_int32 iw; /* cell in which transition occurs */
1499l_float32 score, xfirst, xlast, xleft, xc, xwc;
1500NUMA *nad;
1501
1502 PROCNAME("numaEvalSyncError");
1503
1504 if (!nas)
1505 return ERROR_INT("nas not defined", procName, 1);
1506 if ((n = numaGetCount(nas)) < 2)
1507 return ERROR_INT("nas size < 2", procName, 1);
1508 if (ifirst < 0) ifirst = 0;
1509 if (ilast <= 0) ilast = n - 1;
1510 if (ifirst >= ilast)
1511 return ERROR_INT("ifirst not < ilast", procName, 1);
1512 nc = ilast - ifirst + 1;
1513
1514 /* Set up an array corresponding to the (shifted) windows,
1515 * and fill in the crossings. */
1516 score = 0.0;
1517 numaGetFValue(nas, ifirst, &xfirst);
1518 numaGetFValue(nas, ilast, &xlast);
1519 nw = (l_int32) ((xlast - xfirst + 2.0 * width) / width);
1520 nad = numaCreate(nw);
1521 numaSetCount(nad, nw); /* init to all 0.0 */
1522 xleft = xfirst - width / 2.0 + shift; /* left edge of first window */
1523 for (i = ifirst; i <= ilast; i++) {
1524 numaGetFValue(nas, i, &xc);
1525 iw = (l_int32)((xc - xleft) / width);
1526 xwc = xleft + (iw + 0.5) * width; /* center of cell iw */
1527 score += (xwc - xc) * (xwc - xc);
1528 numaGetIValue(nad, iw, &ival);
1529 numaSetValue(nad, iw, ival + 1);
1530 }
1531
1532 if (pscore)
1533 *pscore = 4.0 * score / (width * width * (l_float32)nc);
1534 if (pnad)
1535 *pnad = nad;
1536 else
1537 numaDestroy(&nad);
1538
1539 return 0;
1540}
@ L_QUADRATIC_INTERP
Definition: array.h:152
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
char * barcodeDispatchDecoder(char *barstr, l_int32 format, l_int32 debugflag)
barcodeDispatchDecoder()
Definition: bardecode.c:97
l_int32 barcodeFormatIsSupported(l_int32 format)
barcodeFormatIsSupported()
Definition: bardecode.c:174
BOX * boxaGetBox(BOXA *boxa, l_int32 index, l_int32 accessflag)
boxaGetBox()
Definition: boxbasic.c:779
BOXA * boxaCopy(BOXA *boxa, l_int32 copyflag)
boxaCopy()
Definition: boxbasic.c:537
void boxDestroy(BOX **pbox)
boxDestroy()
Definition: boxbasic.c:282
BOX * boxCreate(l_int32 x, l_int32 y, l_int32 w, l_int32 h)
boxCreate()
Definition: boxbasic.c:172
l_int32 boxaGetCount(BOXA *boxa)
boxaGetCount()
Definition: boxbasic.c:734
l_ok boxaWriteStderr(BOXA *boxa)
boxaWriteStderr()
Definition: boxbasic.c:2333
l_ok boxGetGeometry(BOX *box, l_int32 *px, l_int32 *py, l_int32 *pw, l_int32 *ph)
boxGetGeometry()
Definition: boxbasic.c:313
void boxaDestroy(BOXA **pboxa)
boxaDestroy()
Definition: boxbasic.c:583
BOXA * boxaSort(BOXA *boxas, l_int32 sorttype, l_int32 sortorder, NUMA **pnaindex)
boxaSort()
Definition: boxfunc2.c:637
BOXA * pixConnComp(PIX *pixs, PIXA **ppixa, l_int32 connectivity)
pixConnComp()
Definition: conncomp.c:151
PIX * pixSobelEdgeFilter(PIX *pixs, l_int32 orientflag)
pixSobelEdgeFilter()
Definition: edge.c:94
l_ok gplotAddPlot(GPLOT *gplot, NUMA *nax, NUMA *nay, l_int32 plotstyle, const char *plotlabel)
gplotAddPlot()
Definition: gplot.c:320
l_ok gplotMakeOutput(GPLOT *gplot)
gplotMakeOutput()
Definition: gplot.c:466
GPLOT * gplotCreate(const char *rootname, l_int32 outformat, const char *title, const char *xlabel, const char *ylabel)
gplotCreate()
Definition: gplot.c:187
void gplotDestroy(GPLOT **pgplot)
gplotDestroy()
Definition: gplot.c:255
PIX * pixThresholdToBinary(PIX *pixs, l_int32 thresh)
pixThresholdToBinary()
Definition: grayquant.c:447
PIX * pixCloseBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixCloseBrick()
Definition: morph.c:900
PIX * pixOpenBrick(PIX *pixd, PIX *pixs, l_int32 hsize, l_int32 vsize)
pixOpenBrick()
Definition: morph.c:828
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
NUMA * numaCopy(NUMA *na)
numaCopy()
Definition: numabasic.c:399
l_ok numaGetFValue(NUMA *na, l_int32 index, l_float32 *pval)
numaGetFValue()
Definition: numabasic.c:719
l_ok numaWriteStderr(NUMA *na)
numaWriteStderr()
Definition: numabasic.c:1313
l_ok numaSetCount(NUMA *na, l_int32 newcount)
numaSetCount()
Definition: numabasic.c:685
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_ok numaSetValue(NUMA *na, l_int32 index, l_float32 val)
numaSetValue()
Definition: numabasic.c:786
l_float32 * numaGetFArray(NUMA *na, l_int32 copyflag)
numaGetFArray()
Definition: numabasic.c:892
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
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:1912
l_ok numaJoin(NUMA *nad, NUMA *nas, l_int32 istart, l_int32 iend)
numaJoin()
Definition: numafunc1.c:3640
l_ok numaGetMax(NUMA *na, l_float32 *pmaxval, l_int32 *pimaxloc)
numaGetMax()
Definition: numafunc1.c:496
l_ok numaSelectCrossingThreshold(NUMA *nax, NUMA *nay, l_float32 estthresh, l_float32 *pbestthresh)
numaSelectCrossingThreshold()
Definition: numafunc2.c:2848
NUMA * numaCrossingsByThreshold(NUMA *nax, NUMA *nay, l_float32 thresh)
numaCrossingsByThreshold()
Definition: numafunc2.c:2959
l_ok numaHistogramGetValFromRank(NUMA *na, l_float32 rank, l_float32 *prval)
numaHistogramGetValFromRank()
Definition: numafunc2.c:1634
NUMA * numaMakeHistogramClipped(NUMA *na, l_float32 binsize, l_float32 maxsize)
numaMakeHistogramClipped()
Definition: numafunc2.c:1082
NUMA * numaMakeHistogram(NUMA *na, l_int32 maxbins, l_int32 *pbinsize, l_int32 *pbinstart)
numaMakeHistogram()
Definition: numafunc2.c:885
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 * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
PIX * pixOr(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixOr()
Definition: pix3.c:1560
PIX * pixInvert(PIX *pixd, PIX *pixs)
pixInvert()
Definition: pix3.c:1509
PIX * pixXor(PIX *pixd, PIX *pixs1, PIX *pixs2)
pixXor()
Definition: pix3.c:1688
PIX * pixClipRectangle(PIX *pixs, BOX *box, BOX **pboxc)
pixClipRectangle()
Definition: pix5.c:1026
@ L_SORT_BY_AREA
Definition: pix.h:744
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
@ L_SORT_DECREASING
Definition: pix.h:730
@ L_BRING_IN_WHITE
Definition: pix.h:869
@ L_ROTATE_AREA_MAP
Definition: pix.h:862
@ L_ALL_EDGES
Definition: pix.h:1005
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
void pixaDestroy(PIXA **ppixa)
pixaDestroy()
Definition: pixabasic.c:412
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
l_ok pixaAddBox(PIXA *pixa, BOX *box, l_int32 copyflag)
pixaAddBox()
Definition: pixabasic.c:555
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
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:746
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
static l_int32 numaGetCrossingDistances(NUMA *nas, NUMA **pnaedist, NUMA **pnaodist, l_float32 *pmindist, l_float32 *pmaxdist)
numaGetCrossingDistances()
Definition: readbarcode.c:1026
static NUMA * pixAverageRasterScans(PIX *pixs, l_int32 nscans)
pixAverageRasterScans()
Definition: readbarcode.c:803
BOXA * pixLocateBarcodes(PIX *pixs, l_int32 thresh, PIX **ppixb, PIX **ppixm)
pixLocateBarcodes()
Definition: readbarcode.c:396
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:1415
NUMA * pixExtractBarcodeWidths2(PIX *pixs, l_float32 thresh, l_float32 *pwidth, NUMA **pnac, l_int32 debugflag)
pixExtractBarcodeWidths2()
Definition: readbarcode.c:698
NUMA * pixReadBarcodeWidths(PIX *pixs, l_int32 method, l_int32 debugflag)
pixReadBarcodeWidths()
Definition: readbarcode.c:347
PIX * pixDeskewBarcode(PIX *pixs, PIX *pixb, BOX *box, l_int32 margin, l_int32 threshold, l_float32 *pangle, l_float32 *pconf)
pixDeskewBarcode()
Definition: readbarcode.c:512
PIXA * pixExtractBarcodes(PIX *pixs, l_int32 debugflag)
pixExtractBarcodes()
Definition: readbarcode.c:188
static NUMA * numaLocatePeakRanges(NUMA *nas, l_float32 minfirst, l_float32 minsep, l_float32 maxmin)
numaLocatePeakRanges()
Definition: readbarcode.c:1117
SARRAY * pixReadBarcodes(PIXA *pixa, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixReadBarcodes()
Definition: readbarcode.c:261
static PIX * pixGenerateBarcodeMask(PIX *pixs, l_int32 maxspace, l_int32 nwidth, l_int32 nheight)
pixGenerateBarcodeMask()
Definition: readbarcode.c:456
static NUMA * numaGetPeakCentroids(NUMA *nahist, NUMA *narange)
numaGetPeakCentroids()
Definition: readbarcode.c:1170
NUMA * pixExtractBarcodeWidths1(PIX *pixs, l_float32 thresh, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
pixExtractBarcodeWidths1()
Definition: readbarcode.c:642
static NUMA * numaGetPeakWidthLUT(NUMA *narange, NUMA *nacent)
numaGetPeakWidthLUT()
Definition: readbarcode.c:1221
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:1489
NUMA * numaQuantizeCrossingsByWidth(NUMA *nas, l_float32 binfract, NUMA **pnaehist, NUMA **pnaohist, l_int32 debugflag)
numaQuantizeCrossingsByWidth()
Definition: readbarcode.c:871
NUMA * pixExtractBarcodeCrossings(PIX *pixs, l_float32 thresh, l_int32 debugflag)
pixExtractBarcodeCrossings()
Definition: readbarcode.c:741
SARRAY * pixProcessBarcodes(PIX *pixs, l_int32 format, l_int32 method, SARRAY **psaw, l_int32 debugflag)
pixProcessBarcodes()
Definition: readbarcode.c:142
NUMA * numaQuantizeCrossingsByWindow(NUMA *nas, l_float32 ratio, l_float32 *pwidth, l_float32 *pfirstloc, NUMA **pnac, l_int32 debugflag)
numaQuantizeCrossingsByWindow()
Definition: readbarcode.c:1313
PIX * pixRotate(PIX *pixs, l_float32 angle, l_int32 type, l_int32 incolor, l_int32 width, l_int32 height)
pixRotate()
Definition: rotate.c:101
PIX * pixRotateOrth(PIX *pixs, l_int32 quads)
pixRotateOrth()
Definition: rotateorth.c:75
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
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:617
Definition: pix.h:481
Definition: pix.h:492
Definition: gplot.h:77
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
Definition: array.h:127
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306
l_int32 lept_mkdir(const char *subdir)
lept_mkdir()
Definition: utils2.c:2218