/* * The Python Imaging Library * $Id$ * * min, max, median filters * * history: * 2002-06-08 fl Created * * Copyright (c) Secret Labs AB 2002. All rights reserved. * * See the README file for information on usage and redistribution. */ #include "Imaging.h" /* Fast rank algorithm (due to Wirth), based on public domain code by Nicolas Devillard, available at http://ndevilla.free.fr */ #define SWAP(type, a, b) \ { \ register type t = (a); \ (a) = (b); \ (b) = t; \ } #define MakeRankFunction(type) \ static type Rank##type(type a[], int n, int k) { \ register int i, j, l, m; \ register type x; \ l = 0; \ m = n - 1; \ while (l < m) { \ x = a[k]; \ i = l; \ j = m; \ do { \ while (a[i] < x) { \ i++; \ } \ while (x < a[j]) { \ j--; \ } \ if (i <= j) { \ SWAP(type, a[i], a[j]); \ i++; \ j--; \ } \ } while (i <= j); \ if (j < k) { \ l = i; \ } \ if (k < i) { \ m = j; \ } \ } \ return a[k]; \ } MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) Imaging ImagingRankFilter(Imaging im, int size, int rank) { Imaging imOut = NULL; int x, y; int i, margin, size2; if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL) { return (Imaging)ImagingError_ModeError(); } if (!(size & 1)) { return (Imaging)ImagingError_ValueError("bad filter size"); } /* malloc check ok, for overflow in the define below */ if (size > INT_MAX / size || size > INT_MAX / (size * (int)sizeof(FLOAT32))) { return (Imaging)ImagingError_ValueError("filter size too large"); } size2 = size * size; margin = (size - 1) / 2; if (rank < 0 || rank >= size2) { return (Imaging)ImagingError_ValueError("bad rank value"); } imOut = ImagingNew(im->mode, im->xsize - 2 * margin, im->ysize - 2 * margin); if (!imOut) { return NULL; } /* malloc check ok, checked above */ #define RANK_BODY(type) \ do { \ type *buf = malloc(size2 * sizeof(type)); \ if (!buf) { \ goto nomemory; \ } \ for (y = 0; y < imOut->ysize; y++) { \ for (x = 0; x < imOut->xsize; x++) { \ for (i = 0; i < size; i++) { \ memcpy( \ buf + i * size, \ &IMAGING_PIXEL_##type(im, x, y + i), \ size * sizeof(type)); \ } \ IMAGING_PIXEL_##type(imOut, x, y) = Rank##type(buf, size2, rank); \ } \ } \ free(buf); \ } while (0) if (im->image8) { RANK_BODY(UINT8); } else if (im->type == IMAGING_TYPE_INT32) { RANK_BODY(INT32); } else if (im->type == IMAGING_TYPE_FLOAT32) { RANK_BODY(FLOAT32); } else { /* safety net (we shouldn't end up here) */ ImagingDelete(imOut); return (Imaging)ImagingError_ModeError(); } ImagingCopyPalette(imOut, im); return imOut; nomemory: ImagingDelete(imOut); return (Imaging)ImagingError_MemoryError(); }