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