Pillow/src/libImaging/RankFilter.c
2017-12-28 14:49:47 +00:00

114 lines
2.9 KiB
C

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