Pillow/src/libImaging/Histo.c

194 lines
6.3 KiB
C
Raw Normal View History

2010-07-31 06:52:47 +04:00
/*
* The Python Imaging Library
* $Id$
*
* histogram support
*
* history:
* 1995-06-15 fl Created.
* 1996-04-05 fl Fixed histogram for multiband images.
* 1997-02-23 fl Added mask support
* 1998-07-01 fl Added basic 32-bit float/integer support
*
* Copyright (c) 1997-2003 by Secret Labs AB.
* Copyright (c) 1995-2003 by Fredrik Lundh.
*
* See the README file for information on usage and redistribution.
*/
#include "Imaging.h"
/* HISTOGRAM */
/* --------------------------------------------------------------------
* Take a histogram of an image. Returns a histogram object containing
* 256 slots per band in the input image.
*/
void
ImagingHistogramDelete(ImagingHistogram h)
{
2020-05-10 12:56:36 +03:00
if (h->histogram) {
2020-05-01 15:08:57 +03:00
free(h->histogram);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
free(h);
}
ImagingHistogram
ImagingHistogramNew(Imaging im)
{
ImagingHistogram h;
/* Create histogram descriptor */
h = calloc(1, sizeof(struct ImagingHistogramInstance));
strncpy(h->mode, im->mode, IMAGING_MODE_LENGTH-1);
h->mode[IMAGING_MODE_LENGTH-1] = 0;
2010-07-31 06:52:47 +04:00
h->bands = im->bands;
h->histogram = calloc(im->pixelsize, 256 * sizeof(long));
return h;
}
ImagingHistogram
ImagingGetHistogram(Imaging im, Imaging imMask, void* minmax)
{
ImagingSectionCookie cookie;
int x, y, i;
ImagingHistogram h;
INT32 imin, imax;
FLOAT32 fmin, fmax, scale;
2020-05-10 12:56:36 +03:00
if (!im) {
2020-05-01 15:08:57 +03:00
return ImagingError_ModeError();
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
if (imMask) {
2020-05-01 15:08:57 +03:00
/* Validate mask */
2020-05-10 12:56:36 +03:00
if (im->xsize != imMask->xsize || im->ysize != imMask->ysize) {
2020-05-01 15:08:57 +03:00
return ImagingError_Mismatch();
2020-05-10 12:56:36 +03:00
}
if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0) {
2020-05-01 15:08:57 +03:00
return ImagingError_ValueError("bad transparency mask");
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
}
h = ImagingHistogramNew(im);
if (imMask) {
2020-05-01 15:08:57 +03:00
/* mask */
if (im->image8) {
2020-05-10 12:56:36 +03:00
ImagingSectionEnter(&cookie);
for (y = 0; y < im->ysize; y++) {
for (x = 0; x < im->xsize; x++) {
if (imMask->image8[y][x] != 0) {
h->histogram[im->image8[y][x]]++;
}
}
}
ImagingSectionLeave(&cookie);
2020-05-01 15:08:57 +03:00
} else { /* yes, we need the braces. C isn't Python! */
if (im->type != IMAGING_TYPE_UINT8) {
ImagingHistogramDelete(h);
2010-07-31 06:52:47 +04:00
return ImagingError_ModeError();
}
2010-07-31 06:52:47 +04:00
ImagingSectionEnter(&cookie);
2020-05-01 15:08:57 +03:00
for (y = 0; y < im->ysize; y++) {
UINT8* in = (UINT8*) im->image32[y];
2020-05-10 12:56:36 +03:00
for (x = 0; x < im->xsize; x++) {
2020-05-01 15:08:57 +03:00
if (imMask->image8[y][x] != 0) {
2010-07-31 06:52:47 +04:00
h->histogram[(*in++)]++;
h->histogram[(*in++)+256]++;
h->histogram[(*in++)+512]++;
h->histogram[(*in++)+768]++;
2020-05-10 12:56:36 +03:00
} else {
2020-05-01 15:08:57 +03:00
in += 4;
2020-05-10 12:56:36 +03:00
}
}
2020-05-01 15:08:57 +03:00
}
ImagingSectionLeave(&cookie);
}
} else {
/* mask not given; process pixels in image */
if (im->image8) {
2020-05-10 12:56:36 +03:00
ImagingSectionEnter(&cookie);
for (y = 0; y < im->ysize; y++) {
for (x = 0; x < im->xsize; x++) {
2020-05-01 15:08:57 +03:00
h->histogram[im->image8[y][x]]++;
2020-05-10 12:56:36 +03:00
}
}
ImagingSectionLeave(&cookie);
2020-05-01 15:08:57 +03:00
} else {
switch (im->type) {
case IMAGING_TYPE_UINT8:
ImagingSectionEnter(&cookie);
for (y = 0; y < im->ysize; y++) {
UINT8* in = (UINT8*) im->image[y];
for (x = 0; x < im->xsize; x++) {
h->histogram[(*in++)]++;
h->histogram[(*in++)+256]++;
h->histogram[(*in++)+512]++;
h->histogram[(*in++)+768]++;
}
2010-07-31 06:52:47 +04:00
}
2020-05-01 15:08:57 +03:00
ImagingSectionLeave(&cookie);
2010-07-31 06:52:47 +04:00
break;
2020-05-01 15:08:57 +03:00
case IMAGING_TYPE_INT32:
if (!minmax) {
ImagingHistogramDelete(h);
return ImagingError_ValueError("min/max not given");
}
2020-05-10 12:56:36 +03:00
if (!im->xsize || !im->ysize) {
2020-05-01 15:08:57 +03:00
break;
2020-05-10 12:56:36 +03:00
}
2020-05-01 15:08:57 +03:00
memcpy(&imin, minmax, sizeof(imin));
memcpy(&imax, ((char*)minmax) + sizeof(imin), sizeof(imax));
2020-05-10 12:56:36 +03:00
if (imin >= imax) {
2020-05-01 15:08:57 +03:00
break;
2020-05-10 12:56:36 +03:00
}
2020-05-01 15:08:57 +03:00
ImagingSectionEnter(&cookie);
scale = 255.0F / (imax - imin);
for (y = 0; y < im->ysize; y++) {
INT32* in = im->image32[y];
for (x = 0; x < im->xsize; x++) {
i = (int) (((*in++)-imin)*scale);
2020-05-10 12:56:36 +03:00
if (i >= 0 && i < 256) {
2020-05-01 15:08:57 +03:00
h->histogram[i]++;
2020-05-10 12:56:36 +03:00
}
2020-05-01 15:08:57 +03:00
}
}
ImagingSectionLeave(&cookie);
2010-07-31 06:52:47 +04:00
break;
2020-05-01 15:08:57 +03:00
case IMAGING_TYPE_FLOAT32:
if (!minmax) {
ImagingHistogramDelete(h);
return ImagingError_ValueError("min/max not given");
2010-07-31 06:52:47 +04:00
}
2020-05-10 12:56:36 +03:00
if (!im->xsize || !im->ysize) {
2020-05-01 15:08:57 +03:00
break;
2020-05-10 12:56:36 +03:00
}
2020-05-01 15:08:57 +03:00
memcpy(&fmin, minmax, sizeof(fmin));
memcpy(&fmax, ((char*)minmax) + sizeof(fmin), sizeof(fmax));
2020-05-10 12:56:36 +03:00
if (fmin >= fmax) {
2020-05-01 15:08:57 +03:00
break;
2020-05-10 12:56:36 +03:00
}
2020-05-01 15:08:57 +03:00
ImagingSectionEnter(&cookie);
scale = 255.0F / (fmax - fmin);
for (y = 0; y < im->ysize; y++) {
FLOAT32* in = (FLOAT32*) im->image32[y];
for (x = 0; x < im->xsize; x++) {
i = (int) (((*in++)-fmin)*scale);
if (i >= 0 && i < 256)
h->histogram[i]++;
}
}
ImagingSectionLeave(&cookie);
break;
2010-07-31 06:52:47 +04:00
}
}
}
return h;
}