Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
selgen.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
71#ifdef HAVE_CONFIG_H
72#include <config_auto.h>
73#endif /* HAVE_CONFIG_H */
74
75#include "allheaders.h"
76
77 /* Default minimum distance of a hit-miss pixel element to
78 * a boundary pixel of its color. */
79static const l_int32 DefaultDistanceToBoundary = 1;
80static const l_int32 MaxDistanceToBoundary = 4;
81
82 /* Default min runlength to accept a hit or miss element located
83 * at its center */
84static const l_int32 DefaultMinRunlength = 3;
85
86 /* Default scalefactor for displaying image and hit-miss sel
87 * that is derived from it */
88static const l_int32 DefaultSelScalefactor = 7;
89static const l_int32 MaxSelScalefactor = 31; /* should be big enough */
90
91#ifndef NO_CONSOLE_IO
92#define DEBUG_DISPLAY_HM_SEL 0
93#endif /* ~NO_CONSOLE_IO */
94
95
96/*-----------------------------------------------------------------*
97 * Generate a subsampled structuring element *
98 *-----------------------------------------------------------------*/
99
142SEL *
144 l_int32 hitdist,
145 l_int32 missdist,
146 l_int32 hitskip,
147 l_int32 missskip,
148 l_int32 topflag,
149 l_int32 botflag,
150 l_int32 leftflag,
151 l_int32 rightflag,
152 PIX **ppixe)
153{
154l_int32 ws, hs, w, h, x, y, ix, iy, i, npt;
155PIX *pixt1, *pixt2, *pixt3, *pixfg, *pixbg;
156SEL *selh, *selm, *sel_3, *sel;
157PTA *ptah = NULL, *ptam = NULL;
158
159 if (ppixe) *ppixe = NULL;
160 if (!pixs)
161 return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
162 if (pixGetDepth(pixs) != 1)
163 return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
164 if (hitdist < 0 || hitdist > 4 || missdist < 0 || missdist > 4)
165 return (SEL *)ERROR_PTR("dist not in {0 .. 4}", __func__, NULL);
166 if (hitskip < 0 && missskip < 0)
167 return (SEL *)ERROR_PTR("no hits or misses", __func__, NULL);
168
169 /* Locate the foreground */
170 pixClipToForeground(pixs, &pixt1, NULL);
171 if (!pixt1)
172 return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
173 ws = pixGetWidth(pixt1);
174 hs = pixGetHeight(pixt1);
175 w = ws;
176 h = hs;
177
178 /* Crop out a region including the foreground, and add pixels
179 * on sides depending on the side flags */
180 if (topflag || botflag || leftflag || rightflag) {
181 x = y = 0;
182 if (topflag) {
183 h += missdist + 1;
184 y = missdist + 1;
185 }
186 if (botflag)
187 h += missdist + 1;
188 if (leftflag) {
189 w += missdist + 1;
190 x = missdist + 1;
191 }
192 if (rightflag)
193 w += missdist + 1;
194 pixt2 = pixCreate(w, h, 1);
195 pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
196 } else {
197 pixt2 = pixClone(pixt1);
198 }
199 if (ppixe)
200 *ppixe = pixClone(pixt2);
201 pixDestroy(&pixt1);
202
203 /* Identify fg and bg pixels that are exactly hitdist and
204 * missdist (rsp) away from the boundary pixels in their set.
205 * Then get a subsampled set of these points. */
206 sel_3 = selCreateBrick(3, 3, 1, 1, SEL_HIT);
207 if (hitskip >= 0) {
208 selh = selCreateBrick(2 * hitdist + 1, 2 * hitdist + 1,
209 hitdist, hitdist, SEL_HIT);
210 pixt3 = pixErode(NULL, pixt2, selh);
211 pixfg = pixErode(NULL, pixt3, sel_3);
212 pixXor(pixfg, pixfg, pixt3);
213 ptah = pixSubsampleBoundaryPixels(pixfg, hitskip);
214 pixDestroy(&pixt3);
215 pixDestroy(&pixfg);
216 selDestroy(&selh);
217 }
218 if (missskip >= 0) {
219 selm = selCreateBrick(2 * missdist + 1, 2 * missdist + 1,
220 missdist, missdist, SEL_HIT);
221 pixt3 = pixDilate(NULL, pixt2, selm);
222 pixbg = pixDilate(NULL, pixt3, sel_3);
223 pixXor(pixbg, pixbg, pixt3);
224 ptam = pixSubsampleBoundaryPixels(pixbg, missskip);
225 pixDestroy(&pixt3);
226 pixDestroy(&pixbg);
227 selDestroy(&selm);
228 }
229 selDestroy(&sel_3);
230 pixDestroy(&pixt2);
231
232 /* Generate the hit-miss sel from these point */
233 sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
234 if (hitskip >= 0) {
235 npt = ptaGetCount(ptah);
236 for (i = 0; i < npt; i++) {
237 ptaGetIPt(ptah, i, &ix, &iy);
238 selSetElement(sel, iy, ix, SEL_HIT);
239 }
240 }
241 if (missskip >= 0) {
242 npt = ptaGetCount(ptam);
243 for (i = 0; i < npt; i++) {
244 ptaGetIPt(ptam, i, &ix, &iy);
245 selSetElement(sel, iy, ix, SEL_MISS);
246 }
247 }
248
249 ptaDestroy(&ptah);
250 ptaDestroy(&ptam);
251 return sel;
252}
253
254
305SEL *
307 l_int32 nhlines,
308 l_int32 nvlines,
309 l_int32 distance,
310 l_int32 minlength,
311 l_int32 toppix,
312 l_int32 botpix,
313 l_int32 leftpix,
314 l_int32 rightpix,
315 PIX **ppixe)
316{
317l_int32 ws, hs, w, h, x, y, xval, yval, i, j, nh, nm;
318l_float32 delh, delw;
319NUMA *nah, *nam;
320PIX *pixt1, *pixt2, *pixfg, *pixbg;
321PTA *ptah, *ptam;
322SEL *seld, *sel;
323
324 if (ppixe) *ppixe = NULL;
325 if (!pixs)
326 return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
327 if (pixGetDepth(pixs) != 1)
328 return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
329 if (nhlines < 1 && nvlines < 1)
330 return (SEL *)ERROR_PTR("nvlines and nhlines both < 1", __func__, NULL);
331
332 if (distance <= 0)
333 distance = DefaultDistanceToBoundary;
334 if (minlength <= 0)
335 minlength = DefaultMinRunlength;
336 if (distance > MaxDistanceToBoundary) {
337 L_WARNING("distance too large; setting to max value\n", __func__);
338 distance = MaxDistanceToBoundary;
339 }
340
341 /* Locate the foreground */
342 pixClipToForeground(pixs, &pixt1, NULL);
343 if (!pixt1)
344 return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
345 ws = pixGetWidth(pixt1);
346 hs = pixGetHeight(pixt1);
347 w = ws;
348 h = hs;
349
350 /* Crop out a region including the foreground, and add pixels
351 * on sides depending on the side flags */
352 if (toppix || botpix || leftpix || rightpix) {
353 x = y = 0;
354 if (toppix) {
355 h += toppix;
356 y = toppix;
357 if (toppix < distance + minlength)
358 L_WARNING("no miss elements in added top pixels\n", __func__);
359 }
360 if (botpix) {
361 h += botpix;
362 if (botpix < distance + minlength)
363 L_WARNING("no miss elements in added bot pixels\n", __func__);
364 }
365 if (leftpix) {
366 w += leftpix;
367 x = leftpix;
368 if (leftpix < distance + minlength)
369 L_WARNING("no miss elements in added left pixels\n", __func__);
370 }
371 if (rightpix) {
372 w += rightpix;
373 if (rightpix < distance + minlength)
374 L_WARNING("no miss elements in added right pixels\n", __func__);
375 }
376 pixt2 = pixCreate(w, h, 1);
377 pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
378 } else {
379 pixt2 = pixClone(pixt1);
380 }
381 if (ppixe)
382 *ppixe = pixClone(pixt2);
383 pixDestroy(&pixt1);
384
385 /* Identify fg and bg pixels that are at least 'distance' pixels
386 * away from the boundary pixels in their set */
387 seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
388 distance, distance, SEL_HIT);
389 pixfg = pixErode(NULL, pixt2, seld);
390 pixbg = pixDilate(NULL, pixt2, seld);
391 pixInvert(pixbg, pixbg);
392 selDestroy(&seld);
393 pixDestroy(&pixt2);
394
395 /* Accumulate hit and miss points */
396 ptah = ptaCreate(0);
397 ptam = ptaCreate(0);
398 if (nhlines >= 1) {
399 delh = (l_float32)h / (l_float32)(nhlines + 1);
400 for (i = 0, y = 0; i < nhlines; i++) {
401 y += (l_int32)(delh + 0.5);
402 nah = pixGetRunCentersOnLine(pixfg, -1, y, minlength);
403 nam = pixGetRunCentersOnLine(pixbg, -1, y, minlength);
404 nh = numaGetCount(nah);
405 nm = numaGetCount(nam);
406 for (j = 0; j < nh; j++) {
407 numaGetIValue(nah, j, &xval);
408 ptaAddPt(ptah, xval, y);
409 }
410 for (j = 0; j < nm; j++) {
411 numaGetIValue(nam, j, &xval);
412 ptaAddPt(ptam, xval, y);
413 }
414 numaDestroy(&nah);
415 numaDestroy(&nam);
416 }
417 }
418 if (nvlines >= 1) {
419 delw = (l_float32)w / (l_float32)(nvlines + 1);
420 for (i = 0, x = 0; i < nvlines; i++) {
421 x += (l_int32)(delw + 0.5);
422 nah = pixGetRunCentersOnLine(pixfg, x, -1, minlength);
423 nam = pixGetRunCentersOnLine(pixbg, x, -1, minlength);
424 nh = numaGetCount(nah);
425 nm = numaGetCount(nam);
426 for (j = 0; j < nh; j++) {
427 numaGetIValue(nah, j, &yval);
428 ptaAddPt(ptah, x, yval);
429 }
430 for (j = 0; j < nm; j++) {
431 numaGetIValue(nam, j, &yval);
432 ptaAddPt(ptam, x, yval);
433 }
434 numaDestroy(&nah);
435 numaDestroy(&nam);
436 }
437 }
438
439 /* Make the Sel with those points */
440 sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
441 nh = ptaGetCount(ptah);
442 for (i = 0; i < nh; i++) {
443 ptaGetIPt(ptah, i, &x, &y);
444 selSetElement(sel, y, x, SEL_HIT);
445 }
446 nm = ptaGetCount(ptam);
447 for (i = 0; i < nm; i++) {
448 ptaGetIPt(ptam, i, &x, &y);
449 selSetElement(sel, y, x, SEL_MISS);
450 }
451
452 pixDestroy(&pixfg);
453 pixDestroy(&pixbg);
454 ptaDestroy(&ptah);
455 ptaDestroy(&ptam);
456 return sel;
457}
458
459
494SEL *
496 l_float32 hitfract,
497 l_float32 missfract,
498 l_int32 distance,
499 l_int32 toppix,
500 l_int32 botpix,
501 l_int32 leftpix,
502 l_int32 rightpix,
503 PIX **ppixe)
504{
505l_int32 ws, hs, w, h, x, y, i, j, thresh;
506l_uint32 val;
507PIX *pixt1, *pixt2, *pixfg, *pixbg;
508SEL *seld, *sel;
509
510 if (ppixe) *ppixe = NULL;
511 if (!pixs)
512 return (SEL *)ERROR_PTR("pixs not defined", __func__, NULL);
513 if (pixGetDepth(pixs) != 1)
514 return (SEL *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
515 if (hitfract <= 0.0 && missfract <= 0.0)
516 return (SEL *)ERROR_PTR("no hits or misses", __func__, NULL);
517 if (hitfract > 1.0 || missfract > 1.0)
518 return (SEL *)ERROR_PTR("fraction can't be > 1.0", __func__, NULL);
519
520 if (distance <= 0)
521 distance = DefaultDistanceToBoundary;
522 if (distance > MaxDistanceToBoundary) {
523 L_WARNING("distance too large; setting to max value\n", __func__);
524 distance = MaxDistanceToBoundary;
525 }
526
527 /* Locate the foreground */
528 pixClipToForeground(pixs, &pixt1, NULL);
529 if (!pixt1)
530 return (SEL *)ERROR_PTR("pixt1 not made", __func__, NULL);
531 ws = pixGetWidth(pixt1);
532 hs = pixGetHeight(pixt1);
533 w = ws;
534 h = hs;
535
536 /* Crop out a region including the foreground, and add pixels
537 * on sides depending on the side flags */
538 if (toppix || botpix || leftpix || rightpix) {
539 x = y = 0;
540 if (toppix) {
541 h += toppix;
542 y = toppix;
543 }
544 if (botpix)
545 h += botpix;
546 if (leftpix) {
547 w += leftpix;
548 x = leftpix;
549 }
550 if (rightpix)
551 w += rightpix;
552 pixt2 = pixCreate(w, h, 1);
553 pixRasterop(pixt2, x, y, ws, hs, PIX_SRC, pixt1, 0, 0);
554 } else {
555 pixt2 = pixClone(pixt1);
556 }
557 if (ppixe)
558 *ppixe = pixClone(pixt2);
559 pixDestroy(&pixt1);
560
561 /* Identify fg and bg pixels that are at least 'distance' pixels
562 * away from the boundary pixels in their set */
563 seld = selCreateBrick(2 * distance + 1, 2 * distance + 1,
564 distance, distance, SEL_HIT);
565 pixfg = pixErode(NULL, pixt2, seld);
566 pixbg = pixDilate(NULL, pixt2, seld);
567 pixInvert(pixbg, pixbg);
568 selDestroy(&seld);
569 pixDestroy(&pixt2);
570
571 /* Generate the sel from a random selection of these points */
572 sel = selCreateBrick(h, w, h / 2, w / 2, SEL_DONT_CARE);
573 if (hitfract > 0.0) {
574 thresh = (l_int32)(hitfract * (l_float64)RAND_MAX);
575 for (i = 0; i < h; i++) {
576 for (j = 0; j < w; j++) {
577 pixGetPixel(pixfg, j, i, &val);
578 if (val) {
579 if (rand() < thresh)
580 selSetElement(sel, i, j, SEL_HIT);
581 }
582 }
583 }
584 }
585 if (missfract > 0.0) {
586 thresh = (l_int32)(missfract * (l_float64)RAND_MAX);
587 for (i = 0; i < h; i++) {
588 for (j = 0; j < w; j++) {
589 pixGetPixel(pixbg, j, i, &val);
590 if (val) {
591 if (rand() < thresh)
592 selSetElement(sel, i, j, SEL_MISS);
593 }
594 }
595 }
596 }
597
598 pixDestroy(&pixfg);
599 pixDestroy(&pixbg);
600 return sel;
601}
602
603
604/*-----------------------------------------------------------------*
605 * Accumulate data on runs along lines *
606 *-----------------------------------------------------------------*/
636NUMA *
638 l_int32 x,
639 l_int32 y,
640 l_int32 minlength)
641{
642l_int32 w, h, i, r, nruns, len;
643NUMA *naruns, *nad;
644
645 if (!pixs)
646 return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
647 if (pixGetDepth(pixs) != 1)
648 return (NUMA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
649 if (x != -1 && y != -1)
650 return (NUMA *)ERROR_PTR("x or y must be -1", __func__, NULL);
651 if (x == -1 && y == -1)
652 return (NUMA *)ERROR_PTR("x or y cannot both be -1", __func__, NULL);
653
654 if ((nad = numaCreate(0)) == NULL)
655 return (NUMA *)ERROR_PTR("nad not made", __func__, NULL);
656 w = pixGetWidth(pixs);
657 h = pixGetHeight(pixs);
658 if (x == -1) { /* horizontal run */
659 if (y < 0 || y >= h)
660 return nad;
661 naruns = pixGetRunsOnLine(pixs, 0, y, w - 1, y);
662 } else { /* vertical run */
663 if (x < 0 || x >= w)
664 return nad;
665 naruns = pixGetRunsOnLine(pixs, x, 0, x, h - 1);
666 }
667 nruns = numaGetCount(naruns);
668
669 /* extract run center values; the first run is always bg */
670 r = 0; /* cumulative distance along line */
671 for (i = 0; i < nruns; i++) {
672 if (i % 2 == 0) { /* bg run */
673 numaGetIValue(naruns, i, &len);
674 r += len;
675 continue;
676 } else {
677 numaGetIValue(naruns, i, &len);
678 if (len >= minlength)
679 numaAddNumber(nad, r + len / 2);
680 r += len;
681 }
682 }
683
684 numaDestroy(&naruns);
685 return nad;
686}
687
688
706NUMA *
708 l_int32 x1,
709 l_int32 y1,
710 l_int32 x2,
711 l_int32 y2)
712{
713l_int32 w, h, x, y, npts;
714l_int32 i, runlen, preval;
715l_uint32 val;
716NUMA *numa;
717PTA *pta;
718
719 if (!pixs)
720 return (NUMA *)ERROR_PTR("pixs not defined", __func__, NULL);
721 if (pixGetDepth(pixs) != 1)
722 return (NUMA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
723
724 w = pixGetWidth(pixs);
725 h = pixGetHeight(pixs);
726 if (x1 < 0 || x1 >= w)
727 return (NUMA *)ERROR_PTR("x1 not valid", __func__, NULL);
728 if (x2 < 0 || x2 >= w)
729 return (NUMA *)ERROR_PTR("x2 not valid", __func__, NULL);
730 if (y1 < 0 || y1 >= h)
731 return (NUMA *)ERROR_PTR("y1 not valid", __func__, NULL);
732 if (y2 < 0 || y2 >= h)
733 return (NUMA *)ERROR_PTR("y2 not valid", __func__, NULL);
734
735 if ((pta = generatePtaLine(x1, y1, x2, y2)) == NULL)
736 return (NUMA *)ERROR_PTR("pta not made", __func__, NULL);
737 if ((npts = ptaGetCount(pta)) == 0) {
738 ptaDestroy(&pta);
739 return (NUMA *)ERROR_PTR("pta has no pts", __func__, NULL);
740 }
741 if ((numa = numaCreate(0)) == NULL) {
742 ptaDestroy(&pta);
743 return (NUMA *)ERROR_PTR("numa not made", __func__, NULL);
744 }
745
746 for (i = 0; i < npts; i++) {
747 ptaGetIPt(pta, i, &x, &y);
748 pixGetPixel(pixs, x, y, &val);
749 if (i == 0) {
750 if (val == 1) { /* black pixel; append white run of size 0 */
751 numaAddNumber(numa, 0);
752 }
753 preval = val;
754 runlen = 1;
755 continue;
756 }
757 if (val == preval) { /* extend current run */
758 preval = val;
759 runlen++;
760 } else { /* end previous run */
761 numaAddNumber(numa, runlen);
762 preval = val;
763 runlen = 1;
764 }
765 }
766 numaAddNumber(numa, runlen); /* append last run */
767
768 ptaDestroy(&pta);
769 return numa;
770}
771
772
773/*-----------------------------------------------------------------*
774 * Subsample boundary pixels in relatively ordered way *
775 *-----------------------------------------------------------------*/
799PTA *
801 l_int32 skip)
802{
803l_int32 x, y, xn, yn, xs, ys, xa, ya, count;
804PIX *pixt;
805PTA *pta;
806
807 if (!pixs)
808 return (PTA *)ERROR_PTR("pixs not defined", __func__, NULL);
809 if (pixGetDepth(pixs) != 1)
810 return (PTA *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
811 if (skip < 0)
812 return (PTA *)ERROR_PTR("skip < 0", __func__, NULL);
813
814 if (skip == 0)
815 return ptaGetPixelsFromPix(pixs, NULL);
816
817 pta = ptaCreate(0);
818 pixt = pixCopy(NULL, pixs);
819 xs = ys = 0;
820 while (nextOnPixelInRaster(pixt, xs, ys, &xn, &yn)) { /* new series */
821 xs = xn;
822 ys = yn;
823
824 /* Add first point in this series */
825 ptaAddPt(pta, xs, ys);
826
827 /* Trace out boundary, erasing all and saving every (skip + 1)th */
828 x = xs;
829 y = ys;
830 pixSetPixel(pixt, x, y, 0);
831 count = 0;
832 while (adjacentOnPixelInRaster(pixt, x, y, &xa, &ya)) {
833 x = xa;
834 y = ya;
835 pixSetPixel(pixt, x, y, 0);
836 if (count == skip) {
837 ptaAddPt(pta, x, y);
838 count = 0;
839 } else {
840 count++;
841 }
842 }
843 }
844
845 pixDestroy(&pixt);
846 return pta;
847}
848
849
864l_int32
866 l_int32 x,
867 l_int32 y,
868 l_int32 *pxa,
869 l_int32 *pya)
870{
871l_int32 w, h, i, xa, ya, found;
872l_int32 xdel[] = {-1, 0, 1, 0, -1, 1, 1, -1};
873l_int32 ydel[] = {0, 1, 0, -1, 1, 1, -1, -1};
874l_uint32 val;
875
876 if (!pixs)
877 return ERROR_INT("pixs not defined", __func__, 0);
878 if (pixGetDepth(pixs) != 1)
879 return ERROR_INT("pixs not 1 bpp", __func__, 0);
880 w = pixGetWidth(pixs);
881 h = pixGetHeight(pixs);
882 found = 0;
883 for (i = 0; i < 8; i++) {
884 xa = x + xdel[i];
885 ya = y + ydel[i];
886 if (xa < 0 || xa >= w || ya < 0 || ya >= h)
887 continue;
888 pixGetPixel(pixs, xa, ya, &val);
889 if (val == 1) {
890 found = 1;
891 *pxa = xa;
892 *pya = ya;
893 break;
894 }
895 }
896 return found;
897}
898
899
900
901/*-----------------------------------------------------------------*
902 * Display generated sel with originating image *
903 *-----------------------------------------------------------------*/
920PIX *
922 SEL *sel,
923 l_int32 scalefactor,
924 l_uint32 hitcolor,
925 l_uint32 misscolor)
926{
927l_int32 i, j, type;
928l_float32 fscale;
929PIX *pixt, *pixd;
930PIXCMAP *cmap;
931
932 if (!pixs)
933 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
934 if (pixGetDepth(pixs) != 1)
935 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
936 if (!sel)
937 return (PIX *)ERROR_PTR("sel not defined", __func__, NULL);
938
939 if (scalefactor <= 0)
940 scalefactor = DefaultSelScalefactor;
941 if (scalefactor > MaxSelScalefactor) {
942 L_WARNING("scalefactor too large; using max value\n", __func__);
943 scalefactor = MaxSelScalefactor;
944 }
945
946 /* Generate a version of pixs with a colormap */
947 pixt = pixConvert1To8(NULL, pixs, 0, 1);
948 cmap = pixcmapCreate(8);
949 pixcmapAddColor(cmap, 255, 255, 255);
950 pixcmapAddColor(cmap, 0, 0, 0);
951 pixcmapAddColor(cmap, hitcolor >> 24, (hitcolor >> 16) & 0xff,
952 (hitcolor >> 8) & 0xff);
953 pixcmapAddColor(cmap, misscolor >> 24, (misscolor >> 16) & 0xff,
954 (misscolor >> 8) & 0xff);
955 pixSetColormap(pixt, cmap);
956
957 /* Color the hits and misses */
958 for (i = 0; i < sel->sy; i++) {
959 for (j = 0; j < sel->sx; j++) {
960 selGetElement(sel, i, j, &type);
961 if (type == SEL_DONT_CARE)
962 continue;
963 if (type == SEL_HIT)
964 pixSetPixel(pixt, j, i, 2);
965 else /* type == SEL_MISS */
966 pixSetPixel(pixt, j, i, 3);
967 }
968 }
969
970 /* Scale it up */
971 fscale = (l_float32)scalefactor;
972 pixd = pixScaleBySampling(pixt, fscale, fscale);
973
974 pixDestroy(&pixt);
975 return pixd;
976}
#define PIX_SRC
Definition pix.h:444
PIX * pixDisplayHitMissSel(PIX *pixs, SEL *sel, l_int32 scalefactor, l_uint32 hitcolor, l_uint32 misscolor)
pixDisplayHitMissSel()
Definition selgen.c:921
SEL * pixGenerateSelWithRuns(PIX *pixs, l_int32 nhlines, l_int32 nvlines, l_int32 distance, l_int32 minlength, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe)
pixGenerateSelWithRuns()
Definition selgen.c:306
NUMA * pixGetRunsOnLine(PIX *pixs, l_int32 x1, l_int32 y1, l_int32 x2, l_int32 y2)
pixGetRunsOnLine()
Definition selgen.c:707
SEL * pixGenerateSelRandom(PIX *pixs, l_float32 hitfract, l_float32 missfract, l_int32 distance, l_int32 toppix, l_int32 botpix, l_int32 leftpix, l_int32 rightpix, PIX **ppixe)
pixGenerateSelRandom()
Definition selgen.c:495
SEL * pixGenerateSelBoundary(PIX *pixs, l_int32 hitdist, l_int32 missdist, l_int32 hitskip, l_int32 missskip, l_int32 topflag, l_int32 botflag, l_int32 leftflag, l_int32 rightflag, PIX **ppixe)
pixGenerateSelBoundary()
Definition selgen.c:143
PTA * pixSubsampleBoundaryPixels(PIX *pixs, l_int32 skip)
pixSubsampleBoundaryPixels()
Definition selgen.c:800
l_int32 adjacentOnPixelInRaster(PIX *pixs, l_int32 x, l_int32 y, l_int32 *pxa, l_int32 *pya)
adjacentOnPixelInRaster()
Definition selgen.c:865
NUMA * pixGetRunCentersOnLine(PIX *pixs, l_int32 x, l_int32 y, l_int32 minlength)
pixGetRunCentersOnLine()
Definition selgen.c:637
l_int32 sx
Definition morph.h:64
l_int32 sy
Definition morph.h:63