Leptonica  1.77.0
Image processing and image analysis suite
rank.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 
121 #include "allheaders.h"
122 
123 /*----------------------------------------------------------------------*
124  * Rank order filter *
125  *----------------------------------------------------------------------*/
146 PIX *
148  l_int32 wf,
149  l_int32 hf,
150  l_float32 rank)
151 {
152 l_int32 d;
153 
154  PROCNAME("pixRankFilter");
155 
156  if (!pixs)
157  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
158  if (pixGetColormap(pixs) != NULL)
159  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
160  d = pixGetDepth(pixs);
161  if (d != 8 && d != 32)
162  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
163  if (wf < 1 || hf < 1)
164  return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
165  if (rank < 0.0 || rank > 1.0)
166  return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
167  if (wf == 1 && hf == 1) /* no-op */
168  return pixCopy(NULL, pixs);
169 
170  if (d == 8)
171  return pixRankFilterGray(pixs, wf, hf, rank);
172  else /* d == 32 */
173  return pixRankFilterRGB(pixs, wf, hf, rank);
174 }
175 
176 
198 PIX *
200  l_int32 wf,
201  l_int32 hf,
202  l_float32 rank)
203 {
204 PIX *pixr, *pixg, *pixb, *pixrf, *pixgf, *pixbf, *pixd;
205 
206  PROCNAME("pixRankFilterRGB");
207 
208  if (!pixs)
209  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
210  if (pixGetDepth(pixs) != 32)
211  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
212  if (wf < 1 || hf < 1)
213  return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
214  if (rank < 0.0 || rank > 1.0)
215  return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
216  if (wf == 1 && hf == 1) /* no-op */
217  return pixCopy(NULL, pixs);
218 
219  pixr = pixGetRGBComponent(pixs, COLOR_RED);
220  pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
221  pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
222 
223  pixrf = pixRankFilterGray(pixr, wf, hf, rank);
224  pixgf = pixRankFilterGray(pixg, wf, hf, rank);
225  pixbf = pixRankFilterGray(pixb, wf, hf, rank);
226 
227  pixd = pixCreateRGBImage(pixrf, pixgf, pixbf);
228  pixDestroy(&pixr);
229  pixDestroy(&pixg);
230  pixDestroy(&pixb);
231  pixDestroy(&pixrf);
232  pixDestroy(&pixgf);
233  pixDestroy(&pixbf);
234  return pixd;
235 }
236 
237 
266 PIX *
268  l_int32 wf,
269  l_int32 hf,
270  l_float32 rank)
271 {
272 l_int32 w, h, d, i, j, k, m, n, rankloc, wplt, wpld, val, sum;
273 l_int32 *histo, *histo16;
274 l_uint32 *datat, *linet, *datad, *lined;
275 PIX *pixt, *pixd;
276 
277  PROCNAME("pixRankFilterGray");
278 
279  if (!pixs)
280  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
281  if (pixGetColormap(pixs) != NULL)
282  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
283  pixGetDimensions(pixs, &w, &h, &d);
284  if (d != 8)
285  return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
286  if (wf < 1 || hf < 1)
287  return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
288  if (rank < 0.0 || rank > 1.0)
289  return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
290  if (wf == 1 && hf == 1) /* no-op */
291  return pixCopy(NULL, pixs);
292 
293  /* For rank = 0.0, this is a grayscale erosion, and for rank = 1.0,
294  * a dilation. Grayscale morphology operations are implemented
295  * for filters of odd dimension, so we dispatch to grayscale
296  * morphology if both wf and hf are odd. Otherwise, we
297  * slightly adjust the rank (to get the correct behavior) and
298  * use the slower rank filter here. */
299  if (wf % 2 && hf % 2) {
300  if (rank == 0.0)
301  return pixErodeGray(pixs, wf, hf);
302  else if (rank == 1.0)
303  return pixDilateGray(pixs, wf, hf);
304  }
305  if (rank == 0.0) rank = 0.0001;
306  if (rank == 1.0) rank = 0.9999;
307 
308  /* Add wf/2 to each side, and hf/2 to top and bottom of the
309  * image, mirroring for accuracy and to avoid special-casing
310  * the boundary. */
311  if ((pixt = pixAddMirroredBorder(pixs, wf / 2, wf / 2, hf / 2, hf / 2))
312  == NULL)
313  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
314 
315  /* Set up the two histogram arrays. */
316  histo = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32));
317  histo16 = (l_int32 *)LEPT_CALLOC(16, sizeof(l_int32));
318  rankloc = (l_int32)(rank * wf * hf);
319 
320  /* Place the filter center at (0, 0). This is just a
321  * convenient location, because it allows us to perform
322  * the rank filter over x:(0 ... w - 1) and y:(0 ... h - 1). */
323  pixd = pixCreateTemplate(pixs);
324  datat = pixGetData(pixt);
325  wplt = pixGetWpl(pixt);
326  datad = pixGetData(pixd);
327  wpld = pixGetWpl(pixd);
328 
329  /* If hf > wf, it's more efficient to use row-major scanning.
330  * Otherwise, traverse the image in use column-major order. */
331  if (hf > wf) {
332  for (j = 0; j < w; j++) { /* row-major */
333  /* Start each column with clean histogram arrays. */
334  for (n = 0; n < 256; n++)
335  histo[n] = 0;
336  for (n = 0; n < 16; n++)
337  histo16[n] = 0;
338 
339  for (i = 0; i < h; i++) { /* fast scan on columns */
340  /* Update the histos for the new location */
341  lined = datad + i * wpld;
342  if (i == 0) { /* do full histo */
343  for (k = 0; k < hf; k++) {
344  linet = datat + (i + k) * wplt;
345  for (m = 0; m < wf; m++) {
346  val = GET_DATA_BYTE(linet, j + m);
347  histo[val]++;
348  histo16[val >> 4]++;
349  }
350  }
351  } else { /* incremental update */
352  linet = datat + (i - 1) * wplt;
353  for (m = 0; m < wf; m++) { /* remove top line */
354  val = GET_DATA_BYTE(linet, j + m);
355  histo[val]--;
356  histo16[val >> 4]--;
357  }
358  linet = datat + (i + hf - 1) * wplt;
359  for (m = 0; m < wf; m++) { /* add bottom line */
360  val = GET_DATA_BYTE(linet, j + m);
361  histo[val]++;
362  histo16[val >> 4]++;
363  }
364  }
365 
366  /* Find the rank value */
367  sum = 0;
368  for (n = 0; n < 16; n++) { /* search over coarse histo */
369  sum += histo16[n];
370  if (sum > rankloc) {
371  sum -= histo16[n];
372  break;
373  }
374  }
375  if (n == 16) { /* avoid accessing out of bounds */
376  L_WARNING("n = 16; reducing\n", procName);
377  n = 15;
378  sum -= histo16[n];
379  }
380  k = 16 * n; /* starting value in fine histo */
381  for (m = 0; m < 16; m++) {
382  sum += histo[k];
383  if (sum > rankloc) {
384  SET_DATA_BYTE(lined, j, k);
385  break;
386  }
387  k++;
388  }
389  }
390  }
391  } else { /* wf >= hf */
392  for (i = 0; i < h; i++) { /* column-major */
393  /* Start each row with clean histogram arrays. */
394  for (n = 0; n < 256; n++)
395  histo[n] = 0;
396  for (n = 0; n < 16; n++)
397  histo16[n] = 0;
398  lined = datad + i * wpld;
399  for (j = 0; j < w; j++) { /* fast scan on rows */
400  /* Update the histos for the new location */
401  if (j == 0) { /* do full histo */
402  for (k = 0; k < hf; k++) {
403  linet = datat + (i + k) * wplt;
404  for (m = 0; m < wf; m++) {
405  val = GET_DATA_BYTE(linet, j + m);
406  histo[val]++;
407  histo16[val >> 4]++;
408  }
409  }
410  } else { /* incremental update at left and right sides */
411  for (k = 0; k < hf; k++) {
412  linet = datat + (i + k) * wplt;
413  val = GET_DATA_BYTE(linet, j - 1);
414  histo[val]--;
415  histo16[val >> 4]--;
416  val = GET_DATA_BYTE(linet, j + wf - 1);
417  histo[val]++;
418  histo16[val >> 4]++;
419  }
420  }
421 
422  /* Find the rank value */
423  sum = 0;
424  for (n = 0; n < 16; n++) { /* search over coarse histo */
425  sum += histo16[n];
426  if (sum > rankloc) {
427  sum -= histo16[n];
428  break;
429  }
430  }
431  if (n == 16) { /* avoid accessing out of bounds */
432  L_WARNING("n = 16; reducing\n", procName);
433  n = 15;
434  sum -= histo16[n];
435  }
436  k = 16 * n; /* starting value in fine histo */
437  for (m = 0; m < 16; m++) {
438  sum += histo[k];
439  if (sum > rankloc) {
440  SET_DATA_BYTE(lined, j, k);
441  break;
442  }
443  k++;
444  }
445  }
446  }
447  }
448 
449  pixDestroy(&pixt);
450  LEPT_FREE(histo);
451  LEPT_FREE(histo16);
452  return pixd;
453 }
454 
455 
456 /*----------------------------------------------------------------------*
457  * Median filter *
458  *----------------------------------------------------------------------*/
466 PIX *
468  l_int32 wf,
469  l_int32 hf)
470 {
471  PROCNAME("pixMedianFilter");
472 
473  if (!pixs)
474  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
475  return pixRankFilter(pixs, wf, hf, 0.5);
476 }
477 
478 
479 /*----------------------------------------------------------------------*
480  * Rank filter (accelerated with downscaling) *
481  *----------------------------------------------------------------------*/
501 PIX *
503  l_int32 wf,
504  l_int32 hf,
505  l_float32 rank,
506  l_float32 scalefactor)
507 {
508 l_int32 w, h, d, wfs, hfs;
509 PIX *pix1, *pix2, *pixd;
510 
511  PROCNAME("pixRankFilterWithScaling");
512 
513  if (!pixs)
514  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
515  if (pixGetColormap(pixs) != NULL)
516  return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
517  d = pixGetDepth(pixs);
518  if (d != 8 && d != 32)
519  return (PIX *)ERROR_PTR("pixs not 8 or 32 bpp", procName, NULL);
520  if (wf < 1 || hf < 1)
521  return (PIX *)ERROR_PTR("wf < 1 || hf < 1", procName, NULL);
522  if (rank < 0.0 || rank > 1.0)
523  return (PIX *)ERROR_PTR("rank must be in [0.0, 1.0]", procName, NULL);
524  if (wf == 1 && hf == 1) /* no-op */
525  return pixCopy(NULL, pixs);
526  if (scalefactor < 0.2 || scalefactor > 0.7) {
527  L_ERROR("invalid scale factor; no scaling used\n", procName);
528  return pixRankFilter(pixs, wf, hf, rank);
529  }
530 
531  pix1 = pixScaleAreaMap(pixs, scalefactor, scalefactor);
532  wfs = L_MAX(1, (l_int32)(scalefactor * wf + 0.5));
533  hfs = L_MAX(1, (l_int32)(scalefactor * hf + 0.5));
534  pix2 = pixRankFilter(pix1, wfs, hfs, rank);
535  pixGetDimensions(pixs, &w, &h, NULL);
536  pixd = pixScaleToSize(pix2, w, h);
537  pixDestroy(&pix1);
538  pixDestroy(&pix2);
539  return pixd;
540 }
PIX * pixDilateGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixDilateGray()
Definition: graymorph.c:274
PIX * pixMedianFilter(PIX *pixs, l_int32 wf, l_int32 hf)
pixMedianFilter()
Definition: rank.c:467
PIX * pixRankFilterGray(PIX *pixs, l_int32 wf, l_int32 hf, l_float32 rank)
pixRankFilterGray()
Definition: rank.c:267
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1912
PIX * pixAddMirroredBorder(PIX *pixs, l_int32 left, l_int32 right, l_int32 top, l_int32 bot)
pixAddMirroredBorder()
Definition: pix2.c:2026
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
PIX * pixRankFilterWithScaling(PIX *pixs, l_int32 wf, l_int32 hf, l_float32 rank, l_float32 scalefactor)
pixRankFilterWithScaling()
Definition: rank.c:502
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2404
PIX * pixRankFilterRGB(PIX *pixs, l_int32 wf, l_int32 hf, l_float32 rank)
pixRankFilterRGB()
Definition: rank.c:199
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2348
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:317
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * pixRankFilter(PIX *pixs, l_int32 wf, l_int32 hf, l_float32 rank)
pixRankFilter()
Definition: rank.c:147
Definition: pix.h:134
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
Definition: pix.h:201
PIX * pixErodeGray(PIX *pixs, l_int32 hsize, l_int32 vsize)
pixErodeGray()
Definition: graymorph.c:158