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)
|
|
|
|
{
|
|
|
|
if (h->histogram)
|
|
|
|
free(h->histogram);
|
|
|
|
free(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImagingHistogram
|
|
|
|
ImagingHistogramNew(Imaging im)
|
|
|
|
{
|
|
|
|
ImagingHistogram h;
|
|
|
|
|
|
|
|
/* Create histogram descriptor */
|
|
|
|
h = calloc(1, sizeof(struct ImagingHistogramInstance));
|
2018-09-11 16:58:31 +03:00
|
|
|
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;
|
|
|
|
|
|
|
|
if (!im)
|
|
|
|
return ImagingError_ModeError();
|
|
|
|
|
|
|
|
if (imMask) {
|
|
|
|
/* Validate mask */
|
|
|
|
if (im->xsize != imMask->xsize || im->ysize != imMask->ysize)
|
|
|
|
return ImagingError_Mismatch();
|
|
|
|
if (strcmp(imMask->mode, "1") != 0 && strcmp(imMask->mode, "L") != 0)
|
|
|
|
return ImagingError_ValueError("bad transparency mask");
|
|
|
|
}
|
|
|
|
|
|
|
|
h = ImagingHistogramNew(im);
|
|
|
|
|
|
|
|
if (imMask) {
|
|
|
|
/* mask */
|
|
|
|
if (im->image8) {
|
|
|
|
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);
|
|
|
|
} else { /* yes, we need the braces. C isn't Python! */
|
2018-09-13 13:22:11 +03:00
|
|
|
if (im->type != IMAGING_TYPE_UINT8) {
|
|
|
|
ImagingHistogramDelete(h);
|
2010-07-31 06:52:47 +04:00
|
|
|
return ImagingError_ModeError();
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
ImagingSectionEnter(&cookie);
|
|
|
|
for (y = 0; y < im->ysize; y++) {
|
|
|
|
UINT8* in = (UINT8*) im->image32[y];
|
|
|
|
for (x = 0; x < im->xsize; x++)
|
|
|
|
if (imMask->image8[y][x] != 0) {
|
|
|
|
h->histogram[(*in++)]++;
|
|
|
|
h->histogram[(*in++)+256]++;
|
|
|
|
h->histogram[(*in++)+512]++;
|
|
|
|
h->histogram[(*in++)+768]++;
|
|
|
|
} else
|
|
|
|
in += 4;
|
|
|
|
}
|
|
|
|
ImagingSectionLeave(&cookie);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* mask not given; process pixels in image */
|
|
|
|
if (im->image8) {
|
|
|
|
ImagingSectionEnter(&cookie);
|
|
|
|
for (y = 0; y < im->ysize; y++)
|
|
|
|
for (x = 0; x < im->xsize; x++)
|
|
|
|
h->histogram[im->image8[y][x]]++;
|
|
|
|
ImagingSectionLeave(&cookie);
|
|
|
|
} 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]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImagingSectionLeave(&cookie);
|
|
|
|
break;
|
|
|
|
case IMAGING_TYPE_INT32:
|
2018-09-13 13:22:11 +03:00
|
|
|
if (!minmax) {
|
|
|
|
ImagingHistogramDelete(h);
|
2010-07-31 06:52:47 +04:00
|
|
|
return ImagingError_ValueError("min/max not given");
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (!im->xsize || !im->ysize)
|
|
|
|
break;
|
2018-06-29 23:33:08 +03:00
|
|
|
memcpy(&imin, minmax, sizeof(imin));
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(&imax, ((char*)minmax) + sizeof(imin), sizeof(imax));
|
2010-07-31 06:52:47 +04:00
|
|
|
if (imin >= imax)
|
|
|
|
break;
|
|
|
|
ImagingSectionEnter(&cookie);
|
2019-06-11 12:28:31 +03:00
|
|
|
scale = 255.0F / (imax - imin);
|
2010-07-31 06:52:47 +04:00
|
|
|
for (y = 0; y < im->ysize; y++) {
|
|
|
|
INT32* in = im->image32[y];
|
|
|
|
for (x = 0; x < im->xsize; x++) {
|
2019-06-11 12:28:31 +03:00
|
|
|
i = (int) (((*in++)-imin)*scale);
|
2010-07-31 06:52:47 +04:00
|
|
|
if (i >= 0 && i < 256)
|
|
|
|
h->histogram[i]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ImagingSectionLeave(&cookie);
|
|
|
|
break;
|
|
|
|
case IMAGING_TYPE_FLOAT32:
|
2018-09-13 13:22:11 +03:00
|
|
|
if (!minmax) {
|
|
|
|
ImagingHistogramDelete(h);
|
2010-07-31 06:52:47 +04:00
|
|
|
return ImagingError_ValueError("min/max not given");
|
2018-09-13 13:22:11 +03:00
|
|
|
}
|
2010-07-31 06:52:47 +04:00
|
|
|
if (!im->xsize || !im->ysize)
|
|
|
|
break;
|
2018-06-29 23:33:08 +03:00
|
|
|
memcpy(&fmin, minmax, sizeof(fmin));
|
2018-07-01 13:47:59 +03:00
|
|
|
memcpy(&fmax, ((char*)minmax) + sizeof(fmin), sizeof(fmax));
|
2010-07-31 06:52:47 +04:00
|
|
|
if (fmin >= fmax)
|
|
|
|
break;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|