Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
pixlabel.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
82#ifdef HAVE_CONFIG_H
83#include <config_auto.h>
84#endif /* HAVE_CONFIG_H */
85
86#include <string.h>
87#include <math.h>
88#include "allheaders.h"
89#include "pix_internal.h"
90
91/*-----------------------------------------------------------------------*
92 * Label pixels by an index for connected component membership *
93 *-----------------------------------------------------------------------*/
116PIX *
118 l_int32 connect,
119 l_int32 depth)
120{
121l_int32 i, n, index, w, h, xb, yb, wb, hb;
122BOXA *boxa;
123PIX *pix1, *pix2, *pixd;
124PIXA *pixa;
125
126 if (!pixs || pixGetDepth(pixs) != 1)
127 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
128 if (connect != 4 && connect != 8)
129 return (PIX *)ERROR_PTR("connectivity must be 4 or 8", __func__, NULL);
130 if (depth != 0 && depth != 8 && depth != 16 && depth != 32)
131 return (PIX *)ERROR_PTR("depth must be 0, 8, 16 or 32", __func__, NULL);
132
133 boxa = pixConnComp(pixs, &pixa, connect);
134 n = pixaGetCount(pixa);
135 boxaDestroy(&boxa);
136 pixGetDimensions(pixs, &w, &h, NULL);
137 if (depth == 0) {
138 if (n < 254)
139 depth = 8;
140 else if (n < 0xfffe)
141 depth = 16;
142 else
143 depth = 32;
144 }
145 pixd = pixCreate(w, h, depth);
146 pixSetSpp(pixd, 1);
147 if (n == 0) { /* no fg */
148 pixaDestroy(&pixa);
149 return pixd;
150 }
151
152 /* Label each component and blit it in */
153 for (i = 0; i < n; i++) {
154 pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
155 pix1 = pixaGetPix(pixa, i, L_CLONE);
156 if (depth == 8) {
157 index = 1 + (i % 254);
158 pix2 = pixConvert1To8(NULL, pix1, 0, index);
159 } else if (depth == 16) {
160 index = 1 + (i % 0xfffe);
161 pix2 = pixConvert1To16(NULL, pix1, 0, index);
162 } else { /* depth == 32 */
163 index = 1 + i;
164 pix2 = pixConvert1To32(NULL, pix1, 0, index);
165 }
166 pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix2, 0, 0);
167 pixDestroy(&pix1);
168 pixDestroy(&pix2);
169 }
170
171 pixaDestroy(&pixa);
172 return pixd;
173}
174
175
176/*-----------------------------------------------------------------------*
177 * Label pixels by the area of their connected component *
178 *-----------------------------------------------------------------------*/
194PIX *
196 l_int32 connect)
197{
198l_int32 i, n, npix, w, h, xb, yb, wb, hb;
199l_int32 *tab8;
200BOXA *boxa;
201PIX *pix1, *pix2, *pixd;
202PIXA *pixa;
203
204 if (!pixs || pixGetDepth(pixs) != 1)
205 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
206 if (connect != 4 && connect != 8)
207 return (PIX *)ERROR_PTR("connectivity must be 4 or 8", __func__, NULL);
208
209 boxa = pixConnComp(pixs, &pixa, connect);
210 n = pixaGetCount(pixa);
211 boxaDestroy(&boxa);
212 pixGetDimensions(pixs, &w, &h, NULL);
213 pixd = pixCreate(w, h, 32);
214 pixSetSpp(pixd, 1);
215 if (n == 0) { /* no fg */
216 pixaDestroy(&pixa);
217 return pixd;
218 }
219
220 /* Label each component and blit it in */
221 tab8 = makePixelSumTab8();
222 for (i = 0; i < n; i++) {
223 pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
224 pix1 = pixaGetPix(pixa, i, L_CLONE);
225 pixCountPixels(pix1, &npix, tab8);
226 pix2 = pixConvert1To32(NULL, pix1, 0, npix);
227 pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix2, 0, 0);
228 pixDestroy(&pix1);
229 pixDestroy(&pix2);
230 }
231
232 pixaDestroy(&pixa);
233 LEPT_FREE(tab8);
234 return pixd;
235}
236
237
238/*-------------------------------------------------------------------------*
239 * Label pixels to allow incremental computation of connected components *
240 *-------------------------------------------------------------------------*/
265l_ok
267 l_int32 conn,
268 PIX **ppixd,
269 PTAA **pptaa,
270 l_int32 *pncc)
271{
272l_int32 empty, w, h, ncc;
273PIX *pixd;
274PTA *pta;
275PTAA *ptaa;
276
277 if (ppixd) *ppixd = NULL;
278 if (pptaa) *pptaa = NULL;
279 if (pncc) *pncc = 0;
280 if (!ppixd || !pptaa || !pncc)
281 return ERROR_INT("&pixd, &ptaa, &ncc not all defined", __func__, 1);
282 if (!pixs || pixGetDepth(pixs) != 1)
283 return ERROR_INT("pixs undefined or not 1 bpp", __func__, 1);
284 if (conn != 4 && conn != 8)
285 return ERROR_INT("connectivity must be 4 or 8", __func__, 1);
286
287 pixGetDimensions(pixs, &w, &h, NULL);
288 pixZero(pixs, &empty);
289 if (empty) {
290 *ppixd = pixCreate(w, h, 32);
291 pixSetSpp(*ppixd, 1);
292 pixSetSpecial(*ppixd, conn);
293 *pptaa = ptaaCreate(0);
294 pta = ptaCreate(1);
295 ptaaAddPta(*pptaa, pta, L_INSERT); /* reserve index 0 for background */
296 return 0;
297 }
298
299 /* Set up the initial labeled image and indexed pixel arrays */
300 if ((pixd = pixConnCompTransform(pixs, conn, 32)) == NULL)
301 return ERROR_INT("pixd not made", __func__, 1);
302 pixSetSpecial(pixd, conn);
303 *ppixd = pixd;
304 if ((ptaa = ptaaIndexLabeledPixels(pixd, &ncc)) == NULL)
305 return ERROR_INT("ptaa not made", __func__, 1);
306 *pptaa = ptaa;
307 *pncc = ncc;
308 return 0;
309}
310
311
347l_int32
349 PTAA *ptaa,
350 l_int32 *pncc,
351 l_float32 x,
352 l_float32 y,
353 l_int32 debug)
354{
355l_int32 conn, i, j, w, h, count, nvals, ns, firstindex;
356l_uint32 val;
357l_int32 *neigh;
358PTA *ptas, *ptad;
359
360 if (!pixs || pixGetDepth(pixs) != 32)
361 return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
362 if (!ptaa)
363 return ERROR_INT("ptaa not defined", __func__, 1);
364 if (!pncc)
365 return ERROR_INT("&ncc not defined", __func__, 1);
366 conn = pixs->special;
367 if (conn != 4 && conn != 8)
368 return ERROR_INT("connectivity must be 4 or 8", __func__, 1);
369 pixGetDimensions(pixs, &w, &h, NULL);
370 if (x < 0 || x >= w)
371 return ERROR_INT("invalid x pixel location", __func__, 1);
372 if (y < 0 || y >= h)
373 return ERROR_INT("invalid y pixel location", __func__, 1);
374
375 pixGetPixel(pixs, x, y, &val);
376 if (val > 0) /* already belongs to a set */
377 return -1;
378
379 /* Find unique neighbor pixel values in increasing order of value.
380 * If %nvals > 0, these are returned in the %neigh array, which
381 * is of size %nvals. Note that the pixel values in each
382 * connected component are used as the index into the pta
383 * array of the ptaa, giving the pixel locations. */
384 pixGetSortedNeighborValues(pixs, x, y, conn, &neigh, &nvals);
385
386 /* If there are no neighbors, just add a new component */
387 if (nvals == 0) {
388 count = ptaaGetCount(ptaa);
389 pixSetPixel(pixs, x, y, count);
390 ptas = ptaCreate(1);
391 ptaAddPt(ptas, x, y);
392 ptaaAddPta(ptaa, ptas, L_INSERT);
393 *pncc += 1;
394 LEPT_FREE(neigh);
395 return 0;
396 }
397
398 /* Otherwise, there is at least one neighbor. Add the pixel
399 * to the first neighbor c.c. */
400 firstindex = neigh[0];
401 pixSetPixel(pixs, x, y, firstindex);
402 ptaaAddPt(ptaa, neigh[0], x, y);
403 if (nvals == 1) {
404 if (debug == 1)
405 lept_stderr("nvals = %d: neigh = (%d)\n", nvals, neigh[0]);
406 LEPT_FREE(neigh);
407 return 0;
408 }
409
410 /* If nvals > 1, there are at least 2 neighbors, so this pixel
411 * joins at least one pair of existing c.c. Join each component
412 * to the first component in the list, which is the one with
413 * the smallest integer label. This is done in two steps:
414 * (a) re-label the pixels in the component to the label of the
415 * first component, and
416 * (b) save the pixel locations in the pta for the first component. */
417 if (nvals == 2) {
418 if (debug >= 1 && debug <= 2) {
419 lept_stderr("nvals = %d: neigh = (%d,%d)\n", nvals,
420 neigh[0], neigh[1]);
421 }
422 } else if (nvals == 3) {
423 if (debug >= 1 && debug <= 3) {
424 lept_stderr("nvals = %d: neigh = (%d,%d,%d)\n", nvals,
425 neigh[0], neigh[1], neigh[2]);
426 }
427 } else { /* nvals == 4 */
428 if (debug >= 1 && debug <= 4) {
429 lept_stderr("nvals = %d: neigh = (%d,%d,%d,%d)\n", nvals,
430 neigh[0], neigh[1], neigh[2], neigh[3]);
431 }
432 }
433 ptad = ptaaGetPta(ptaa, firstindex, L_CLONE);
434 for (i = 1; i < nvals; i++) {
435 ptas = ptaaGetPta(ptaa, neigh[i], L_CLONE);
436 ns = ptaGetCount(ptas);
437 for (j = 0; j < ns; j++) { /* relabel pixels */
438 ptaGetPt(ptas, j, &x, &y);
439 pixSetPixel(pixs, x, y, firstindex);
440 }
441 ptaJoin(ptad, ptas, 0, -1); /* add relabeled pixel locations */
442 *pncc -= 1;
443 ptaDestroy(&ptaa->pta[neigh[i]]);
444 ptaDestroy(&ptas); /* the clone */
445 }
446 ptaDestroy(&ptad); /* the clone */
447 LEPT_FREE(neigh);
448 return 0;
449}
450
451
475l_ok
477 l_int32 x,
478 l_int32 y,
479 l_int32 conn,
480 l_int32 **pneigh,
481 l_int32 *pnvals)
482{
483l_int32 i, npt, index;
484l_int32 neigh[4];
485l_uint32 val;
486l_float32 fx, fy;
487L_ASET *aset;
489PTA *pta;
490RB_TYPE key;
491
492 if (pneigh) *pneigh = NULL;
493 if (pnvals) *pnvals = 0;
494 if (!pneigh || !pnvals)
495 return ERROR_INT("&neigh and &nvals not both defined", __func__, 1);
496 if (!pixs || pixGetDepth(pixs) < 8)
497 return ERROR_INT("pixs not defined or depth < 8", __func__, 1);
498
499 /* Identify the locations of nearest neighbor pixels */
500 if ((pta = ptaGetNeighborPixLocs(pixs, x, y, conn)) == NULL)
501 return ERROR_INT("pta of neighbors not made", __func__, 1);
502
503 /* Find the pixel values and insert into a set as keys */
504 aset = l_asetCreate(L_UINT_TYPE);
505 npt = ptaGetCount(pta);
506 for (i = 0; i < npt; i++) {
507 ptaGetPt(pta, i, &fx, &fy);
508 pixGetPixel(pixs, (l_int32)fx, (l_int32)fy, &val);
509 key.utype = val;
510 l_asetInsert(aset, key);
511 }
512
513 /* Extract the set keys and put them into the %neigh array.
514 * Omit the value 0, which indicates the pixel doesn't
515 * belong to one of the sets of connected components. */
516 node = l_asetGetFirst(aset);
517 index = 0;
518 while (node) {
519 val = node->key.utype;
520 if (val > 0)
521 neigh[index++] = (l_int32)val;
522 node = l_asetGetNext(node);
523 }
524 *pnvals = index;
525 if (index > 0) {
526 *pneigh = (l_int32 *)LEPT_CALLOC(index, sizeof(l_int32));
527 for (i = 0; i < index; i++)
528 (*pneigh)[i] = neigh[i];
529 }
530
531 ptaDestroy(&pta);
532 l_asetDestroy(&aset);
533 return 0;
534}
535
536
537/*-----------------------------------------------------------------------*
538 * Label pixels with spatially-dependent color coding *
539 *-----------------------------------------------------------------------*/
559PIX *
561{
562l_int32 w, h, w2, h2, wpls, wplr, wplg, wplb, wplcc, i, j, rval, gval, bval;
563l_float32 invw2, invh2;
564l_uint32 *datas, *datar, *datag, *datab, *datacc;
565l_uint32 *lines, *liner, *lineg, *lineb, *linecc;
566PIX *pix1, *pixcc, *pixr, *pixg, *pixb, *pixd;
567
568 if (!pixs || pixGetDepth(pixs) != 1)
569 return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", __func__, NULL);
570
571 /* Label each pixel with the area of the c.c. to which it belongs.
572 * Clip the result to 255 in an 8 bpp pix. This is used for
573 * the blue component of pixd. */
574 pixGetDimensions(pixs, &w, &h, NULL);
575 w2 = w / 2;
576 h2 = h / 2;
577 invw2 = 255.0f / (l_float32)w2;
578 invh2 = 255.0f / (l_float32)h2;
579 pix1 = pixConnCompAreaTransform(pixs, 8);
580 pixcc = pixConvert32To8(pix1, L_LS_TWO_BYTES, L_CLIP_TO_FF);
581 pixDestroy(&pix1);
582
583 /* Label the red and green components depending on the location
584 * of the fg pixels, in a way that is 4-fold rotationally invariant. */
585 pixr = pixCreate(w, h, 8);
586 pixg = pixCreate(w, h, 8);
587 pixb = pixCreate(w, h, 8);
588 wpls = pixGetWpl(pixs);
589 wplr = pixGetWpl(pixr);
590 wplg = pixGetWpl(pixg);
591 wplb = pixGetWpl(pixb);
592 wplcc = pixGetWpl(pixcc);
593 datas = pixGetData(pixs);
594 datar = pixGetData(pixr);
595 datag = pixGetData(pixg);
596 datab = pixGetData(pixb);
597 datacc = pixGetData(pixcc);
598 for (i = 0; i < h; i++) {
599 lines = datas + i * wpls;
600 liner = datar + i * wplr;
601 lineg = datag + i * wplg;
602 lineb = datab + i * wplb;
603 linecc = datacc+ i * wplcc;
604 for (j = 0; j < w; j++) {
605 if (GET_DATA_BIT(lines, j) == 0) continue;
606 if (w < h) {
607 rval = invh2 * L_ABS((l_float32)(i - h2));
608 gval = invw2 * L_ABS((l_float32)(j - w2));
609 } else {
610 rval = invw2 * L_ABS((l_float32)(j - w2));
611 gval = invh2 * L_ABS((l_float32)(i - h2));
612 }
613 bval = GET_DATA_BYTE(linecc, j);
614 SET_DATA_BYTE(liner, j, rval);
615 SET_DATA_BYTE(lineg, j, gval);
616 SET_DATA_BYTE(lineb, j, bval);
617 }
618 }
619 pixd = pixCreateRGBImage(pixr, pixg, pixb);
620
621 pixDestroy(&pixcc);
622 pixDestroy(&pixr);
623 pixDestroy(&pixg);
624 pixDestroy(&pixb);
625 return pixd;
626}
#define GET_DATA_BYTE(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
@ L_CLONE
Definition pix.h:506
@ L_INSERT
Definition pix.h:504
#define PIX_PAINT
Definition pix.h:450
@ L_CLIP_TO_FF
Definition pix.h:644
@ L_LS_TWO_BYTES
Definition pix.h:645
PIX * pixConnCompAreaTransform(PIX *pixs, l_int32 connect)
pixConnCompAreaTransform()
Definition pixlabel.c:195
l_ok pixConnCompIncrInit(PIX *pixs, l_int32 conn, PIX **ppixd, PTAA **pptaa, l_int32 *pncc)
pixConnCompIncrInit()
Definition pixlabel.c:266
PIX * pixLocToColorTransform(PIX *pixs)
pixLocToColorTransform()
Definition pixlabel.c:560
l_int32 pixConnCompIncrAdd(PIX *pixs, PTAA *ptaa, l_int32 *pncc, l_float32 x, l_float32 y, l_int32 debug)
pixConnCompIncrAdd()
Definition pixlabel.c:348
PIX * pixConnCompTransform(PIX *pixs, l_int32 connect, l_int32 depth)
pixConnCompTransform()
Definition pixlabel.c:117
l_ok pixGetSortedNeighborValues(PIX *pixs, l_int32 x, l_int32 y, l_int32 conn, l_int32 **pneigh, l_int32 *pnvals)
pixGetSortedNeighborValues()
Definition pixlabel.c:476
l_int32 special
struct Pta ** pta