/* * 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(); }