2744 lines
87 KiB
C
2744 lines
87 KiB
C
/**
|
|
** $Header: /roq/libim/imvfbhist.c 1 11/02/99 4:38p Zaphod $
|
|
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
|
|
** a division of General Atomics, San Diego, California, USA
|
|
**
|
|
** Users and possessors of this source code are hereby granted a
|
|
** nonexclusive, royalty-free copyright and design patent license to
|
|
** use this code in individual software. License is not granted for
|
|
** commercial resale, in whole or in part, without prior written
|
|
** permission from SDSC. This source is provided "AS IS" without express
|
|
** or implied warranty of any kind.
|
|
**
|
|
** For further information contact:
|
|
** E-Mail: info@sds.sdsc.edu
|
|
**
|
|
** Surface Mail: Information Center
|
|
** San Diego Supercomputer Center
|
|
** P.O. Box 85608
|
|
** San Diego, CA 92138-5608
|
|
** (619) 534-5000
|
|
**/
|
|
|
|
#define HEADER " $Header: /roq/libim/imvfbhist.c 1 11/02/99 4:38p Zaphod $"
|
|
|
|
|
|
|
|
/**
|
|
** FILE
|
|
** imhist.c - VFB histogram and statistics functions
|
|
**
|
|
** PROJECT
|
|
** libim - SDSC image manipulation library
|
|
**
|
|
** DESCRIPTION
|
|
** imhist compute image statistics and histograms.
|
|
**
|
|
** PUBLIC CONTENTS
|
|
** d =defined constant
|
|
** f =function
|
|
** m =defined macro
|
|
** t =typedef/struct/union
|
|
** v =variable
|
|
** ? =other
|
|
**
|
|
** ImVfbStat f compute simple image statistics
|
|
** ImVfbHist f compute a histogram of pixel values
|
|
** ImVfbHistTableFree f free histogram results
|
|
**
|
|
** PRIVATE CONTENTS
|
|
** imVfbHistTableSort f sort histogram results
|
|
** imVfbHistTableAlloc f allocate a histogram data table
|
|
** imVfbHistFieldOrder f determine the best ordering for field hashing
|
|
** imVfbHistAddValue f add value to histogram table
|
|
** imVfbHistHashFree f free a hash table
|
|
**
|
|
** imXXXHist f histogram computation functions
|
|
**
|
|
** imHistBucket t bucket in collision list
|
|
** imHistBucketHeader t collision list header
|
|
**
|
|
** imHistRGBA4WayFuncs v function table for 4-way RGBA hashing
|
|
** imHistRGBA3WayFuncs v function table for 3-way RGBA hashing
|
|
** imHistRGBA2WayFuncs v function table for 2-way RGBA hashing
|
|
**
|
|
** imHistHSIA4WayFuncs v function table for 4-way HSIA hashing
|
|
** imHistHSIA3WayFuncs v function table for 3-way HSIA hashing
|
|
** imHistHSIA2WayFuncs v function table for 2-way HSIA hashing
|
|
**
|
|
** IM_HIST1FIELD m build a function for single-field histograms
|
|
** IM_HIST1FIELDHSI m same deal but for HSI fields
|
|
**
|
|
** IM_HIST2FIELD m build a function for double-field histograms
|
|
** IM_HIST2FIELD1HSI m same deal but for 1 HSI field
|
|
** IM_HIST2FIELD2HSI m same deal but for 2 HSI fields
|
|
**
|
|
** IM_HIST3FIELD m build a function for triple-field histograms
|
|
** IM_HIST3FIELD1HSI m same deal but for 1 HSI field
|
|
** IM_HIST3FIELD2HSI m same deal but for 2 HSI fields
|
|
** IM_HIST3FIELD3HSI m same deal but for 2 HSI fields
|
|
**
|
|
** IM_HIST4FIELD m build a function for quadruple-field histograms
|
|
** IM_HIST4FIELD3HSI m same deal but for 3 HSI fields
|
|
** IM_HIST4FIELD3HSI2 m same deal but for 3 HSI fields, different alpha loc
|
|
**
|
|
** HISTORY
|
|
** $Log: /roq/libim/imvfbhist.c $
|
|
*
|
|
* 1 11/02/99 4:38p Zaphod
|
|
** Revision 1.9 1995/06/29 00:28:04 bduggan
|
|
** updated copyright year
|
|
**
|
|
** Revision 1.8 1995/06/16 08:54:12 bduggan
|
|
** changed bzero to memset
|
|
**
|
|
** Revision 1.7 1994/10/03 11:29:51 nadeau
|
|
** Updated to ANSI C and C++ compatibility.
|
|
** Removed all use of register keyword.
|
|
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
|
|
** Changed all float arguments to double.
|
|
** Added forward declarations.
|
|
** Added misc. casts to passify SGI and DEC compilers.
|
|
** Changed all macros and defined constants to have names
|
|
** starting with IM.
|
|
** Updated comments.
|
|
** Updated indenting on some code.
|
|
** Updated copyright message.
|
|
**
|
|
** Revision 1.7 1994/10/03 11:29:51 nadeau
|
|
** Updated to ANSI C and C++ compatibility.
|
|
** Removed all use of register keyword.
|
|
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
|
|
** Changed all float arguments to double.
|
|
** Added forward declarations.
|
|
** Added misc. casts to passify SGI and DEC compilers.
|
|
** Changed all macros and defined constants to have names
|
|
** starting with IM.
|
|
** Updated comments.
|
|
** Updated indenting on some code.
|
|
** Updated copyright message.
|
|
**
|
|
** Revision 1.6 92/12/03 02:39:26 nadeau
|
|
** Removed bogus semi-colons where they should be.
|
|
**
|
|
** Revision 1.5 92/12/03 01:55:03 nadeau
|
|
** Total rewrite.
|
|
**
|
|
** Revision 1.4 92/08/31 17:38:40 vle
|
|
** Updated copyright notice.
|
|
**
|
|
** Revision 1.3 92/08/26 12:46:23 groening
|
|
** minor error corrections
|
|
**
|
|
** Revision 1.2 92/08/07 14:38:30 groening
|
|
** Imitial revision
|
|
**
|
|
**/
|
|
|
|
/**
|
|
** CODE CREDITS
|
|
** Custom development, Chris Groening, San Diego Supercomputer Center, 1992.
|
|
** Custom development, Dave Nadeau, San Diego Supercomputer Center, 1992.
|
|
**/
|
|
|
|
#include "iminternal.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
* STRUCT & TYPEDEF
|
|
* imHistBucket - bucket in collision list
|
|
*
|
|
* DESCRIPTION
|
|
* Hash table collisions result in searching a collision list of
|
|
* buckets containing 3rd and 4th histogram field values (the 1st and
|
|
* 2nd histogram field values are used as hash table indexes). Each
|
|
* bucket holds an occurrence count and the two field values for which
|
|
* the bucket exists.
|
|
*/
|
|
#define IM_STARTSIZE 5
|
|
#define IM_SIZEINC 20
|
|
typedef struct imHistBucket
|
|
{
|
|
sdsc_uint16 imhist_value1; /* First value in bucket. */
|
|
sdsc_uint16 imhist_value2; /* Second value in bucket. */
|
|
sdsc_uint32 imhist_nOccur; /* Number of times combo has occurred */
|
|
} imHistBucket;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* STRUCT & TYPEDEF
|
|
* imHistBucketHeader - collision list header
|
|
*
|
|
* DESCRIPTION
|
|
* Collision lists are pointed to by a collision list header that is
|
|
* pointed at by each hash table entry. The header gives the size
|
|
* of the collision list, the next slot in the list that's available,
|
|
* and a pointer to the list itself.
|
|
*/
|
|
typedef struct imHistBucketHeader
|
|
{
|
|
int imhist_allocSize; /* Allocated size of imhist_list*/
|
|
int imhist_nextSlot; /* Next free slot in imhist_list*/
|
|
imHistBucket *imhist_list; /* Collision list of buckets */
|
|
} imHistBucketHeader;
|
|
|
|
|
|
#ifdef __STDC__
|
|
static struct ImHistTable * imVfbHistTableSort( ImHistTable *histTable, int left, int right );
|
|
static void imVfbHistFieldOrder( int fieldMask, int hashFields[3], ImVfb *vfb );
|
|
static ImHistTable * imVfbHistTableAlloc( int numEntry, int fieldMask, int numChannels );
|
|
|
|
extern ImHistTable * imRHist(ImVfb* vfb );
|
|
extern ImHistTable * imBHist(ImVfb* vfb );
|
|
extern ImHistTable * imGHist(ImVfb* vfb );
|
|
extern ImHistTable * imAHist(ImVfb* vfb );
|
|
|
|
extern ImHistTable * imHHist( ImVfb* vfb);
|
|
extern ImHistTable * imSHist( ImVfb* vfb);
|
|
extern ImHistTable * imIHist( ImVfb* vfb);
|
|
|
|
extern ImHistTable * imMHist( ImVfb* vfb);
|
|
extern ImHistTable * imMAHist( ImVfb* vfb);
|
|
extern ImHistTable * im8Hist( ImVfb* vfb);
|
|
extern ImHistTable * im8AHist( ImVfb* vfb);
|
|
extern ImHistTable * im16Hist( ImVfb* vfb);
|
|
extern ImHistTable * im16AHist( ImVfb* vfb);
|
|
|
|
extern ImHistTable * imRGHist( ImVfb* vfb);
|
|
extern ImHistTable * imRBHist( ImVfb* vfb);
|
|
extern ImHistTable * imRAHist( ImVfb* vfb);
|
|
extern ImHistTable * imGBHist( ImVfb* vfb);
|
|
extern ImHistTable * imGAHist( ImVfb* vfb);
|
|
extern ImHistTable * imBAHist( ImVfb* vfb);
|
|
|
|
extern ImHistTable * imHSHist( ImVfb* vfb);
|
|
extern ImHistTable * imHIHist( ImVfb* vfb);
|
|
extern ImHistTable * imHAHist( ImVfb* vfb);
|
|
extern ImHistTable * imSIHist( ImVfb* vfb);
|
|
extern ImHistTable * imSAHist( ImVfb* vfb);
|
|
extern ImHistTable * imIAHist( ImVfb* vfb);
|
|
#else
|
|
extern struct ImHistTable * imVfbHistTableSort( );
|
|
extern void imVfbHistFieldOrder( );
|
|
extern ImHistTable * imVfbHistTableAlloc( );
|
|
|
|
extern ImHistTable * imRHist( );
|
|
extern ImHistTable * imBHist( );
|
|
extern ImHistTable * imGHist( );
|
|
extern ImHistTable * imAHist( );
|
|
|
|
extern ImHistTable * imHHist( );
|
|
extern ImHistTable * imSHist( );
|
|
extern ImHistTable * imIHist( );
|
|
|
|
extern ImHistTable * imMHist( );
|
|
extern ImHistTable * imMAHist( );
|
|
extern ImHistTable * im8Hist( );
|
|
extern ImHistTable * im8AHist( );
|
|
extern ImHistTable * im16Hist( );
|
|
extern ImHistTable * im16AHist( );
|
|
|
|
extern ImHistTable * imRGHist( );
|
|
extern ImHistTable * imRBHist( );
|
|
extern ImHistTable * imRAHist( );
|
|
extern ImHistTable * imGBHist( );
|
|
extern ImHistTable * imGAHist( );
|
|
extern ImHistTable * imBAHist( );
|
|
|
|
extern ImHistTable * imHSHist( );
|
|
extern ImHistTable * imHIHist( );
|
|
extern ImHistTable * imHAHist( );
|
|
extern ImHistTable * imSIHist( );
|
|
extern ImHistTable * imSAHist( );
|
|
extern ImHistTable * imIAHist( );
|
|
|
|
#endif
|
|
|
|
#ifdef __STDC__
|
|
|
|
ImHistTable *imRGBHist(ImVfb * vfb);
|
|
ImHistTable *imRGAHist(ImVfb *vfb);
|
|
ImHistTable *imRBGHist(ImVfb *vfb);
|
|
ImHistTable *imRBAHist(ImVfb *vfb);
|
|
ImHistTable *imRAGHist(ImVfb *vfb);
|
|
ImHistTable *imRABHist(ImVfb *vfb);
|
|
ImHistTable *imBGRHist(ImVfb *vfb);
|
|
ImHistTable *imBGAHist(ImVfb *vfb);
|
|
ImHistTable *imGARHist(ImVfb *vfb);
|
|
ImHistTable *imGABHist(ImVfb *vfb);
|
|
ImHistTable *imBARHist(ImVfb *vfb);
|
|
ImHistTable *imBAGHist(ImVfb *vfb);
|
|
ImHistTable *imHSIHist(ImVfb *vfb);
|
|
ImHistTable *imHSAHist(ImVfb *vfb);
|
|
ImHistTable *imHISHist(ImVfb *vfb);
|
|
ImHistTable *imHIAHist(ImVfb *vfb);
|
|
ImHistTable *imHASHist(ImVfb *vfb);
|
|
ImHistTable *imHAIHist(ImVfb *vfb);
|
|
ImHistTable *imSIHHist(ImVfb *vfb);
|
|
ImHistTable *imSIAHist(ImVfb *vfb);
|
|
ImHistTable *imSAHHist(ImVfb *vfb);
|
|
ImHistTable *imSAIHist(ImVfb *vfb);
|
|
ImHistTable *imIAHHist(ImVfb *vfb);
|
|
ImHistTable *imIASHist(ImVfb *vfb);
|
|
ImHistTable *imRGBAHist(ImVfb *vfb);
|
|
ImHistTable *imRBGAHist(ImVfb *vfb);
|
|
ImHistTable *imRAGBHist(ImVfb *vfb);
|
|
ImHistTable *imRGBAHist(ImVfb *vfb);
|
|
ImHistTable *imGBRAHist(ImVfb *vfb);
|
|
ImHistTable *imGARBHist(ImVfb *vfb);
|
|
ImHistTable *imBARGHist(ImVfb *vfb);
|
|
ImHistTable *imHSIAHist(ImVfb *vfb);
|
|
ImHistTable *imHISAHist(ImVfb *vfb);
|
|
ImHistTable *imHAISHist(ImVfb *vfb);
|
|
ImHistTable *imSIHAHist(ImVfb *vfb);
|
|
ImHistTable *imSAHIHist(ImVfb *vfb);
|
|
ImHistTable *imIAHSHist(ImVfb *vfb);
|
|
ImHistTable *imHAISHist(ImVfb *vfb);
|
|
|
|
#else
|
|
|
|
ImHistTable *imRGBHist();
|
|
ImHistTable *imRGAHist();
|
|
ImHistTable *imRBGHist();
|
|
ImHistTable *imRBAHist();
|
|
ImHistTable *imRAGHist();
|
|
ImHistTable *imRABHist();
|
|
ImHistTable *imBGRHist();
|
|
ImHistTable *imBGAHist();
|
|
ImHistTable *imGARHist();
|
|
ImHistTable *imGABHist();
|
|
ImHistTable *imBARHist();
|
|
ImHistTable *imBAGHist();
|
|
ImHistTable *imHSIHist();
|
|
ImHistTable *imHSAHist();
|
|
ImHistTable *imHISHist();
|
|
ImHistTable *imHIAHist();
|
|
ImHistTable *imHASHist();
|
|
ImHistTable *imHAIHist();
|
|
ImHistTable *imSIHHist();
|
|
ImHistTable *imSIAHist();
|
|
ImHistTable *imSAHHist();
|
|
ImHistTable *imSAIHist();
|
|
ImHistTable *imIAHHist();
|
|
ImHistTable *imIASHist();
|
|
ImHistTable *imRGBAHist();
|
|
ImHistTable *imRBGAHist();
|
|
ImHistTable *imRAGBHist();
|
|
ImHistTable *imRGBAHist();
|
|
ImHistTable *imGBRAHist();
|
|
ImHistTable *imGARBHist();
|
|
ImHistTable *imBARGHist();
|
|
ImHistTable *imHSIAHist();
|
|
ImHistTable *imHISAHist();
|
|
ImHistTable *imHAISHist();
|
|
ImHistTable *imSIHAHist();
|
|
ImHistTable *imSAHIHist();
|
|
ImHistTable *imIAHSHist();
|
|
ImHistTable *imHAISHist();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
* GLOBALS
|
|
* imHistRGBA4WayFuncs - function table for 4-way RGBA hashing
|
|
* imHistRGBA3WayFuncs - function table for 3-way RGBA hashing
|
|
*
|
|
* imHistHSIA4WayFuncs - function table for 4-way HSIA hashing
|
|
* imHistHSIA3WayFuncs - function table for 3-way HSIA hashing
|
|
*
|
|
* DESCRIPTION
|
|
* A zillion individual histogram computation functions are vectored
|
|
* to based upon the choice of histogram fields. Vectoring is by
|
|
* way of the tables below, indexed into by the field numbers
|
|
* involved.
|
|
*/
|
|
|
|
#define IMVFBH_RED 0
|
|
#define IMVFBH_GREEN 1
|
|
#define IMVFBH_BLUE 2
|
|
#define IMVFBH_ALPHA 3
|
|
#define IMVFBH_HUE 0
|
|
#define IMVFBH_SATURATION 1
|
|
#define IMVFBH_INTENSITY 2
|
|
|
|
#ifdef __STDC__
|
|
static ImHistTable *(*imHistRGBA4WayFuncs[4][4])(ImVfb* ) =
|
|
#else
|
|
static ImHistTable *(*imHistRGBA4WayFuncs[4][4])( ) =
|
|
#endif
|
|
{
|
|
/* RED GREEN BLUE ALPHA */
|
|
/* RED */ { NULL, imRGBAHist, imRBGAHist, imRAGBHist },
|
|
/* GREEN */ { imRGBAHist, NULL, imGBRAHist, imGARBHist },
|
|
/* BLUE */ { imRBGAHist, imGBRAHist, NULL, imBARGHist },
|
|
/* ALPHA */ { imRAGBHist, imGARBHist, imBARGHist, NULL }
|
|
};
|
|
|
|
#ifdef __STDC__
|
|
static ImHistTable *(*imHistRGBA3WayFuncs[4][4][4])( ImVfb* ) =
|
|
#else
|
|
static ImHistTable *(*imHistRGBA3WayFuncs[4][4][4])( ) =
|
|
#endif
|
|
{
|
|
/* RED GREEN BLUE ALPHA */
|
|
/* RED */ {{NULL,NULL,NULL,NULL},
|
|
{NULL,NULL,imRGBHist,imRGAHist},
|
|
{NULL,imRBGHist,NULL,imRBAHist},
|
|
{NULL,imRAGHist,imRABHist,NULL}},
|
|
/* GREEN */ {{NULL,NULL,imRGBHist,imRGAHist},
|
|
{NULL,NULL,NULL,NULL},
|
|
{imBGRHist,NULL,NULL,imBGAHist},
|
|
{imGARHist,NULL,imGABHist,NULL}},
|
|
/* BLUE */ {{NULL,imRBGHist,NULL,imRBAHist},
|
|
{imBGRHist,NULL,NULL,imBGAHist},
|
|
{NULL,NULL,NULL,NULL},
|
|
{imBARHist,imBAGHist,NULL,NULL}},
|
|
/* ALPHA */ {{NULL,imRAGHist,imRABHist,NULL},
|
|
{imGARHist,NULL,imGABHist,NULL},
|
|
{imBARHist,imBAGHist,NULL,NULL},
|
|
{NULL,NULL,NULL,NULL}}
|
|
};
|
|
|
|
#ifdef __STDC__
|
|
static ImHistTable *(*imHistHSIA4WayFuncs[4][4])( ImVfb* ) =
|
|
#else
|
|
static ImHistTable *(*imHistHSIA4WayFuncs[4][4])( ) =
|
|
#endif
|
|
{
|
|
/* HUE SAT INTENT ALPHA */
|
|
/* HUE */ { NULL, imHSIAHist, imHISAHist, imHAISHist },
|
|
/* SAT */ { imHSIAHist, NULL, imSIHAHist, imSAHIHist },
|
|
/* INTENT */ { imHISAHist, imSIHAHist, NULL, imIAHSHist },
|
|
/* ALPHA */ { imHAISHist, imSAHIHist, imIAHSHist, NULL }
|
|
};
|
|
|
|
#ifdef __STDC__
|
|
static ImHistTable *(*imHistHSIA3WayFuncs[4][4][4])( ImVfb* ) =
|
|
#else
|
|
static ImHistTable *(*imHistHSIA3WayFuncs[4][4][4])( ) =
|
|
#endif
|
|
{
|
|
/* HUE SAT INTEN ALPHA */
|
|
/* HUE */ {{NULL,NULL,NULL,NULL},
|
|
{NULL,NULL,imHSIHist,imHSAHist},
|
|
{NULL,imHISHist,NULL,imHIAHist},
|
|
{NULL,imHASHist,imHAIHist,NULL}},
|
|
/* SAT */ {{NULL,NULL,imHSIHist,imHSAHist},
|
|
{NULL,NULL,NULL,NULL},
|
|
{imSIHHist,NULL,NULL,imSIAHist},
|
|
{imSAHHist,NULL,imSAIHist,NULL}},
|
|
/* INTEN */ {{NULL,imHISHist,NULL,imHIAHist},
|
|
{imSIHHist,NULL,NULL,imSIAHist},
|
|
{NULL,NULL,NULL,NULL},
|
|
{imIAHHist,imIASHist,NULL,NULL}},
|
|
/* ALPHA */ {{NULL,imHASHist,imHAIHist,NULL},
|
|
{imSAHHist,NULL,imSAIHist,NULL},
|
|
{imIAHHist,imIASHist,NULL,NULL},
|
|
{NULL,NULL,NULL,NULL}}
|
|
};
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* ImVfbStat - compute simple image statistics
|
|
*
|
|
* DESCRIPTION
|
|
* Scan the image and compute the minimum, maximum, and number of
|
|
* unique values for the field. All this is accomplished by scanning
|
|
* the image and using the pixel's field value as an index into a
|
|
* hash table of value occurrence counts (all initially zero).
|
|
*
|
|
* Note that the hash table size varies depending upon the type of
|
|
* field being scanned. For 8-bit integer fields, the table size
|
|
* is 256. For 16-bit integers its 65536. For saturation,
|
|
* and intensity floating point fields, we map from the range 0.0 to 1.0
|
|
* to 0 to 1024. For the hue floating point field, we map from the
|
|
* range 0.0 to 360.0 to 0 to 1024.
|
|
*/
|
|
|
|
|
|
#define IMVFBH_HASH( vfb, query, hash ) \
|
|
{ \
|
|
int i, j; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( j = 0; j < w; j++ ) \
|
|
{ \
|
|
hash[ query( vfb, pPixel ) ]++; \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
}
|
|
#define IMVFBH_HASHHSI( vfb, which, factor, hash ) \
|
|
{ \
|
|
int i, j; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( j = 0; j < w; j++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
hash[ (int)(hsi[which] * (factor)) ]++; \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
float * /* Returns pointer to results */
|
|
#ifdef __STDC__
|
|
ImVfbStat( ImVfb *vfb, int field, float data[IMMAXNUMSTATS] )
|
|
#else
|
|
ImVfbStat( vfb, field, data )
|
|
ImVfb *vfb; /* incoming vfb */
|
|
int field; /* What field to perform operation on */
|
|
float data[IMMAXNUMSTATS]; /* array to return results in */
|
|
#endif
|
|
{
|
|
sdsc_int32 *hash; /* Hash table */
|
|
int hashSize; /* Hash table size */
|
|
int i; /* Counter */
|
|
|
|
|
|
/*
|
|
* Create the hash table and zero it out.
|
|
*/
|
|
hashSize = 256;
|
|
if ( field & IMVFBINDEX16 )
|
|
hashSize = 65536;
|
|
if ( field & (IMHUE|IMSATURATION|IMINTENSITY) )
|
|
hashSize = 1024;
|
|
if ( (hash = (sdsc_int32 *) malloc( sizeof( sdsc_int32 ) * hashSize )) == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( NULL );
|
|
}
|
|
for ( i = 0; i < hashSize; i++ )
|
|
hash[i] = 0;
|
|
|
|
|
|
/*
|
|
* Hash the field values into the table, counting occurrences.
|
|
*/
|
|
if ( field & IMMONO ) IMVFBH_HASH( vfb, ImVfbQMono, hash );
|
|
if ( field & IMINDEX8 ) IMVFBH_HASH( vfb, ImVfbQIndex8, hash );
|
|
if ( field & IMINDEX16 ) IMVFBH_HASH( vfb, ImVfbQIndex16, hash );
|
|
if ( field & IMRED ) IMVFBH_HASH( vfb, ImVfbQRed, hash );
|
|
if ( field & IMGREEN ) IMVFBH_HASH( vfb, ImVfbQGreen, hash );
|
|
if ( field & IMBLUE ) IMVFBH_HASH( vfb, ImVfbQBlue, hash );
|
|
if ( field & IMALPHA ) IMVFBH_HASH( vfb, ImVfbQAlpha, hash );
|
|
|
|
if ( field & IMHUE ) IMVFBH_HASHHSI( vfb, 0, 1023.0/360.0, hash );
|
|
if ( field & IMSATURATION ) IMVFBH_HASHHSI( vfb, 1, 1023.0, hash );
|
|
if ( field & IMINTENSITY ) IMVFBH_HASHHSI( vfb, 2, 1023.0, hash );
|
|
|
|
|
|
/*
|
|
* Scan the hash table. The first non-zero value near the top
|
|
* of the hash table is the lowest value occurring in the image.
|
|
* Similarly, the first non-zero value near the bottom of the
|
|
* hash table is the highest value occurring in the image.
|
|
* Finally, we count the number of non-zero entries to get a
|
|
* count of the number of unique values for the field.
|
|
*/
|
|
data[IMMINIMUM] = -1.0;
|
|
for ( i = 0; i < hashSize; i++ )
|
|
{
|
|
if ( hash[i] != 0 )
|
|
{
|
|
/* First non-zero entry at top of table. */
|
|
data[IMMINIMUM] = (float)i;
|
|
break;
|
|
}
|
|
}
|
|
data[IMMAXIMUM] = -1.0;
|
|
for ( i = hashSize-1; i >= 0; i-- )
|
|
{
|
|
if ( hash[i] != 0 )
|
|
{
|
|
/* First non-zero entry at bottom of table. */
|
|
data[IMMAXIMUM] = (float)i;
|
|
break;
|
|
}
|
|
}
|
|
data[IMUNIQUEVAL] = 0.0;
|
|
for ( i = 0; i < hashSize; i++ )
|
|
if ( hash[i] != 0 )
|
|
data[IMUNIQUEVAL] += 1.0;
|
|
|
|
if ( field & IMHUE )
|
|
{
|
|
data[IMMINIMUM] *= (360.0/1023.0);
|
|
data[IMMAXIMUM] *= (360.0/1023.0);
|
|
}
|
|
if ( field & (IMSATURATION|IMINTENSITY) )
|
|
{
|
|
data[IMMINIMUM] /= 1023.0;
|
|
data[IMMAXIMUM] /= 1023.0;
|
|
}
|
|
|
|
free( (char *)hash );
|
|
|
|
return ( data );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* ImVfbHist - compute a histogram of pixel values
|
|
*
|
|
* DESCRIPTION
|
|
* Based upon image attributes and the field selection for creating
|
|
* the histogram, we vector to any of umpteen individualized histogram
|
|
* computation routines. The finished results are then sorted and
|
|
* returned.
|
|
*
|
|
* Our argument checking insures that color spaces are not mixed and
|
|
* that unsupported fields are excluded. This leaves the following
|
|
* histogram combinations:
|
|
*
|
|
* R, G, B, H, S, I, A, I8, and I16 individually
|
|
* I8A and I16A
|
|
* any 2 of RGBA
|
|
* any 2 of HSIA
|
|
* any 3 of RGBA
|
|
* any 3 of HSIA
|
|
* all 4 of RGBA
|
|
* all 4 of HSIA
|
|
*/
|
|
|
|
ImHistTable * /* Returns histogram data */
|
|
#ifdef __STDC__
|
|
ImVfbHist( ImVfb *vfb, int fieldMask, int sort )
|
|
#else
|
|
ImVfbHist( vfb, fieldMask, sort )
|
|
ImVfb *vfb; /* incoming vfb to do histogram on */
|
|
int fieldMask; /* what fields to do histogram on */
|
|
int sort; /* whether or not to sort histogram results */
|
|
#endif
|
|
{
|
|
ImHistTable *histTable; /* return data structure */
|
|
int hashFields[3]; /* Optimal hash ordering of fields */
|
|
int nColorSpaces; /* Number of color spaces asked for */
|
|
int nRGBA; /* Number of RGBA fields asked for */
|
|
int nHSIA; /* Number of HSIA fields asked for */
|
|
|
|
|
|
/*
|
|
* Check that the user hasn't requested any illegal field mixes.
|
|
*/
|
|
nColorSpaces = 0;
|
|
if ( fieldMask & (IMRED|IMGREEN|IMBLUE) )
|
|
nColorSpaces++;
|
|
if ( fieldMask & (IMHUE|IMSATURATION|IMINTENSITY) )
|
|
nColorSpaces++;
|
|
if ( fieldMask & (IMMONO|IMINDEX8|IMINDEX16) )
|
|
nColorSpaces++;
|
|
if ( nColorSpaces > 1 )
|
|
{
|
|
/* Can't mix color spaces. */
|
|
ImErrNo = IMEFIELD;
|
|
return ( NULL );
|
|
}
|
|
if ( fieldMask & (IMZ|IMWPROT|IMIDATA|IMFDATA) )
|
|
{
|
|
/* Don't support these pixel fields. */
|
|
ImErrNo = IMEFIELD;
|
|
return ( NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
* Build the histogram. The number of fields to use in computing
|
|
* the histogram depends upon the fieldMask and varies from 1 to 4
|
|
* in several combinations. To keep things speedy and memory
|
|
* efficient, each combination of fields is treated separately.
|
|
*/
|
|
nRGBA = 0;
|
|
nHSIA = 0;
|
|
if ( fieldMask & IMRED ) nRGBA++;
|
|
if ( fieldMask & IMGREEN ) nRGBA++;
|
|
if ( fieldMask & IMBLUE ) nRGBA++;
|
|
if ( fieldMask & IMHUE ) nHSIA++;
|
|
if ( fieldMask & IMSATURATION ) nHSIA++;
|
|
if ( fieldMask & IMINTENSITY ) nHSIA++;
|
|
if ( fieldMask & IMALPHA ) nRGBA++, nHSIA++;
|
|
|
|
/*
|
|
* When more than 2 fields are hashed, the choice of which two
|
|
* fields to hash on is important. For instance, if we hash on
|
|
* red and green, but the image has loads of different shades of
|
|
* blue, then the hash table will be only sparsely used, but we'll
|
|
* have a huge collision list. Since hashing is more efficient, we
|
|
* want to choose which two fields to hash on intelligently. This
|
|
* is done by selecting the two fields with the most unique values
|
|
* using imVfbHistFieldOrder().
|
|
*
|
|
* When hashing on 2 or fewer fields, we don't worry about this.
|
|
*/
|
|
if ( nRGBA == 4 )
|
|
{
|
|
/*
|
|
* Red, green, blue, and alpha, all at once. That's 4
|
|
* fields. We'll create a hash table for hashing the first
|
|
* two fields, then use a collision list afterwards for
|
|
* the remaining 2 fields.
|
|
*/
|
|
imVfbHistFieldOrder( fieldMask, hashFields, vfb );
|
|
histTable = (*imHistRGBA4WayFuncs[hashFields[0]][hashFields[1]])( vfb );
|
|
}
|
|
else if ( nRGBA == 3 )
|
|
{
|
|
/*
|
|
* Any 3 of Red, green, blue, and alpha. We'll create a
|
|
* hash table for hashing the first two fields, then use
|
|
* a collision list afterwards for the remaining field.
|
|
*/
|
|
imVfbHistFieldOrder( fieldMask, hashFields, vfb );
|
|
histTable = (*imHistRGBA3WayFuncs[hashFields[0]][hashFields[1]][hashFields[2]])( vfb );
|
|
}
|
|
else if ( nRGBA == 2 )
|
|
{
|
|
/*
|
|
* Any 2 of red, green, blue, and alpha. We'll just hash
|
|
* with both of them.
|
|
*/
|
|
if ( fieldMask & IMRED && fieldMask & IMGREEN )
|
|
histTable = imRGHist( vfb );
|
|
if ( fieldMask & IMRED && fieldMask & IMBLUE )
|
|
histTable = imRBHist( vfb );
|
|
if ( fieldMask & IMRED && fieldMask & IMALPHA )
|
|
histTable = imRAHist( vfb );
|
|
if ( fieldMask & IMGREEN && fieldMask & IMBLUE )
|
|
histTable = imGBHist( vfb );
|
|
if ( fieldMask & IMGREEN && fieldMask & IMALPHA )
|
|
histTable = imGAHist( vfb );
|
|
if ( fieldMask & IMBLUE && fieldMask & IMALPHA )
|
|
histTable = imBAHist( vfb );
|
|
}
|
|
else if ( nHSIA == 4 )
|
|
{
|
|
/*
|
|
* Hue, saturation, intensity, and alpha all at once. That's
|
|
* 4 fields. We'll create a hash table for hashing the first
|
|
* two fields, then use a collision list afterwards for
|
|
* the remaining 2 fields.
|
|
*/
|
|
imVfbHistFieldOrder( fieldMask, hashFields, vfb );
|
|
histTable = (*imHistHSIA4WayFuncs[hashFields[0]][hashFields[1]])( vfb );
|
|
}
|
|
else if ( nHSIA == 3 )
|
|
{
|
|
/*
|
|
* Any 3 of Hue, saturation, intensity, and alpha.
|
|
* We'll create a hash table for hashing the first
|
|
* two fields, then use a collision list afterwards for
|
|
* the remaining field.
|
|
*/
|
|
imVfbHistFieldOrder( fieldMask, hashFields, vfb );
|
|
histTable = (*imHistHSIA3WayFuncs[hashFields[0]][hashFields[1]][hashFields[2]])( vfb );
|
|
}
|
|
else if ( nHSIA == 2 )
|
|
{
|
|
/*
|
|
* Any 2 of hue, saturation, intensity, and alpha. We'll
|
|
* just hash with both of them.
|
|
*/
|
|
if ( fieldMask & IMHUE && fieldMask & IMSATURATION )
|
|
histTable = imHSHist( vfb );
|
|
if ( fieldMask & IMHUE && fieldMask & IMINTENSITY )
|
|
histTable = imHIHist( vfb );
|
|
if ( fieldMask & IMHUE && fieldMask & IMALPHA )
|
|
histTable = imHAHist( vfb );
|
|
if ( fieldMask & IMSATURATION && fieldMask & IMINTENSITY )
|
|
histTable = imSIHist( vfb );
|
|
if ( fieldMask & IMSATURATION && fieldMask & IMALPHA )
|
|
histTable = imSAHist( vfb );
|
|
if ( fieldMask & IMINTENSITY && fieldMask & IMALPHA )
|
|
histTable = imIAHist( vfb );
|
|
}
|
|
else if ( (fieldMask & (IMMONO|IMALPHA)) == (IMMONO|IMALPHA) )
|
|
histTable = imMAHist( vfb );
|
|
else if ( (fieldMask & (IMINDEX8|IMALPHA)) == (IMINDEX8|IMALPHA) )
|
|
histTable = im8AHist( vfb );
|
|
else if ( (fieldMask & (IMINDEX16|IMALPHA)) == (IMINDEX16|IMALPHA) )
|
|
histTable = im16AHist( vfb );
|
|
else if ( fieldMask & IMMONO )
|
|
histTable = imMHist( vfb );
|
|
else if ( fieldMask & IMINDEX8 )
|
|
histTable = im8Hist( vfb );
|
|
else if ( fieldMask & IMINDEX16 )
|
|
histTable = im16Hist( vfb );
|
|
else if ( fieldMask & IMRED )
|
|
histTable = imRHist( vfb );
|
|
else if ( fieldMask & IMGREEN )
|
|
histTable = imGHist( vfb );
|
|
else if ( fieldMask & IMBLUE )
|
|
histTable = imBHist( vfb );
|
|
else if ( fieldMask & IMHUE )
|
|
histTable = imHHist( vfb );
|
|
else if ( fieldMask & IMSATURATION )
|
|
histTable = imSHist( vfb );
|
|
else if ( fieldMask & IMINTENSITY )
|
|
histTable = imIHist( vfb );
|
|
else if ( fieldMask & IMALPHA )
|
|
histTable = imAHist( vfb );
|
|
else
|
|
{
|
|
ImErrNo = IMEFIELD;
|
|
return ( NULL );
|
|
}
|
|
if ( histTable == NULL )
|
|
{
|
|
/* ImErrNo already set. */
|
|
return ( NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
* Sort the results.
|
|
*/
|
|
if ( !sort )
|
|
return ( histTable );
|
|
histTable = imVfbHistTableSort( histTable, 0, histTable->imhist_nEntries-1 );
|
|
if ( histTable == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( NULL );
|
|
}
|
|
return ( histTable );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* imVfbHistTableSort - sort histogram results
|
|
*
|
|
* DESCRIPTION
|
|
* Recursively sort a portion of a histogram results structure.
|
|
* Sort based upon the count value, from high to low.
|
|
*/
|
|
|
|
|
|
#define IM_SWAP( field, i, j, results ) \
|
|
{ \
|
|
int tmp; /* Temp value holder */\
|
|
tmp = (results)->field[i]; \
|
|
(results)->field[i] = (results)->field[j]; \
|
|
(results)->field[j] = tmp; \
|
|
}
|
|
|
|
#define IM_SWAPF( field, i, j, results ) \
|
|
{ \
|
|
float tmp; /* Temp value holder */\
|
|
tmp = (results)->field[i]; \
|
|
(results)->field[i] = (results)->field[j]; \
|
|
(results)->field[j] = tmp; \
|
|
}
|
|
|
|
static ImHistTable * /* Returns sorted results */
|
|
#ifdef __STDC__
|
|
imVfbHistTableSort( ImHistTable *histTable, int left, int right )
|
|
#else
|
|
imVfbHistTableSort( histTable, left, right )
|
|
ImHistTable *histTable; /* Data to sort */
|
|
int left; /* left indicie to sort */
|
|
int right; /* right indicie to sort */
|
|
#endif
|
|
{
|
|
sdsc_uint32 v; /* Sort value */
|
|
int i, j; /* counters */
|
|
|
|
|
|
if ( right <= left )
|
|
/* End recursion and just return. */
|
|
return ( histTable );
|
|
|
|
v = histTable->imhist_nOccur[right]; /* start with right side*/
|
|
i = left - 1;
|
|
j = right;
|
|
|
|
for ( ; ; )
|
|
{
|
|
/* Collapse the sort area to unsorted entries. */
|
|
while ( histTable->imhist_nOccur[++i] > v )
|
|
;
|
|
while ( histTable->imhist_nOccur[--j] < v )
|
|
;
|
|
if ( i >= j )
|
|
/* They're already sorted. */
|
|
break;
|
|
|
|
/* Swap the two values. */
|
|
IM_SWAP( imhist_nOccur, i, j, histTable );
|
|
|
|
/* And swap the individual field values as well. */
|
|
if ( histTable->imhist_mono != NULL )
|
|
IM_SWAP( imhist_mono, i, j, histTable );
|
|
if ( histTable->imhist_index8 != NULL )
|
|
IM_SWAP( imhist_index8, i, j, histTable );
|
|
if ( histTable->imhist_index16 != NULL )
|
|
IM_SWAP( imhist_index16, i, j, histTable );
|
|
if ( histTable->imhist_red != NULL )
|
|
IM_SWAP( imhist_red, i, j, histTable );
|
|
if ( histTable->imhist_green != NULL )
|
|
IM_SWAP( imhist_green, i, j, histTable );
|
|
if ( histTable->imhist_blue != NULL )
|
|
IM_SWAP( imhist_blue, i, j, histTable );
|
|
if ( histTable->imhist_alpha != NULL )
|
|
IM_SWAP( imhist_alpha, i, j, histTable );
|
|
if ( histTable->imhist_hue != NULL )
|
|
IM_SWAPF( imhist_hue, i, j, histTable );
|
|
if ( histTable->imhist_saturation != NULL )
|
|
IM_SWAPF( imhist_saturation, i, j, histTable );
|
|
if ( histTable->imhist_intensity != NULL )
|
|
IM_SWAPF( imhist_intensity, i, j, histTable );
|
|
}
|
|
|
|
|
|
/* Swap the current and right edge values. */
|
|
IM_SWAP( imhist_nOccur, right, i, histTable );
|
|
|
|
/* And swap the individual field values as well. */
|
|
if ( histTable->imhist_mono != NULL )
|
|
IM_SWAP( imhist_mono, right, i, histTable );
|
|
if ( histTable->imhist_index8 != NULL )
|
|
IM_SWAP( imhist_index8, right, i, histTable );
|
|
if ( histTable->imhist_index16 != NULL )
|
|
IM_SWAP( imhist_index16, right, i, histTable );
|
|
if ( histTable->imhist_red != NULL )
|
|
IM_SWAP( imhist_red, right, i, histTable );
|
|
if ( histTable->imhist_green != NULL )
|
|
IM_SWAP( imhist_green, right, i, histTable );
|
|
if ( histTable->imhist_blue != NULL )
|
|
IM_SWAP( imhist_blue, right, i, histTable );
|
|
if ( histTable->imhist_alpha != NULL )
|
|
IM_SWAP( imhist_alpha, right, i, histTable );
|
|
if ( histTable->imhist_hue != NULL )
|
|
IM_SWAPF( imhist_hue, right, i, histTable );
|
|
if ( histTable->imhist_saturation != NULL )
|
|
IM_SWAPF( imhist_saturation, right, i, histTable );
|
|
if ( histTable->imhist_intensity != NULL )
|
|
IM_SWAPF( imhist_intensity, right, i, histTable );
|
|
|
|
|
|
/* Recurse on the two sublists. */
|
|
imVfbHistTableSort( histTable, left, i-1 );
|
|
imVfbHistTableSort( histTable, i+1, right );
|
|
|
|
return ( histTable );
|
|
}
|
|
|
|
#undef IM_SWAP
|
|
#undef IM_SWAPF
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* ImVfbHistTableFree - free histogram results
|
|
*
|
|
* DESCRUPTION
|
|
* Each of the field data lists is tossed.
|
|
*/
|
|
void /* Returns nothing */
|
|
#ifdef __STDC__
|
|
ImVfbHistTableFree( ImHistTable *histTable )
|
|
#else
|
|
ImVfbHistTableFree( histTable )
|
|
ImHistTable *histTable; /* Data to toss */
|
|
#endif
|
|
{
|
|
if ( histTable->imhist_nOccur != NULL )
|
|
free( (char *)histTable->imhist_nOccur );
|
|
if ( histTable->imhist_red != NULL )
|
|
free( (char *)histTable->imhist_red );
|
|
if ( histTable->imhist_green != NULL )
|
|
free( (char *)histTable->imhist_green );
|
|
if ( histTable->imhist_blue != NULL )
|
|
free( (char *)histTable->imhist_blue );
|
|
if ( histTable->imhist_alpha != NULL )
|
|
free( (char *)histTable->imhist_alpha );
|
|
if ( histTable->imhist_mono != NULL )
|
|
free( (char *)histTable->imhist_mono );
|
|
if ( histTable->imhist_index8 != NULL )
|
|
free( (char *)histTable->imhist_index8 );
|
|
if ( histTable->imhist_index16 != NULL )
|
|
free( (char *)histTable->imhist_index16 );
|
|
if ( histTable->imhist_hue != NULL )
|
|
free( (char *)histTable->imhist_hue );
|
|
if ( histTable->imhist_saturation != NULL )
|
|
free( (char *)histTable->imhist_saturation );
|
|
if ( histTable->imhist_intensity != NULL )
|
|
free( (char *)histTable->imhist_intensity );
|
|
|
|
free( (char *)histTable );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* imVfbHistTableAlloc - allocate a histogram data table
|
|
*
|
|
* DESCRIPTION
|
|
* Space is allocated for the histogram data table based upon the
|
|
* fields we're histogramming and the number of table entries.
|
|
*/
|
|
|
|
#define IM_HISTALLOC( mask, field, name, type, num, table ) \
|
|
{ \
|
|
if ( ((mask) & (field)) && ((table)->name = (type *)malloc( \
|
|
sizeof( type ) * (num)) ) == NULL ) \
|
|
{ \
|
|
ImVfbHistTableFree( table ); \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
static ImHistTable * /* Returns histogram table */
|
|
#ifdef __STDC__
|
|
imVfbHistTableAlloc( int numEntry, int fieldMask, int numChannels )
|
|
#else
|
|
imVfbHistTableAlloc( numEntry, fieldMask, numChannels )
|
|
int numEntry; /* number of entries in data strusture */
|
|
int fieldMask; /* what fields to do histogram on */
|
|
int numChannels; /* how many channels to do histogram on */
|
|
#endif
|
|
{
|
|
ImHistTable *histTable; /* return data structure */
|
|
|
|
/* Allocate the table itself. */
|
|
if ((histTable = (ImHistTable *)malloc( sizeof( ImHistTable )) )
|
|
== NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return( NULL );
|
|
}
|
|
memset( (void *) histTable, 0x00, sizeof( ImHistTable ) );
|
|
|
|
|
|
/* Allocate the occurrence count list. */
|
|
if ( (histTable->imhist_nOccur = (unsigned int *)malloc( sizeof( sdsc_uint32 ) *
|
|
numEntry)) == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( NULL );
|
|
}
|
|
|
|
/* Allocate the individual field data lists. */
|
|
IM_HISTALLOC( fieldMask, IMMONO, imhist_mono, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMINDEX8, imhist_index8, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMINDEX16, imhist_index16, sdsc_uint16,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMALPHA, imhist_alpha, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMRED, imhist_red, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMGREEN, imhist_green, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMBLUE, imhist_blue, unsigned char,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMHUE, imhist_hue, float,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMSATURATION, imhist_saturation, float,
|
|
numEntry, histTable );
|
|
IM_HISTALLOC( fieldMask, IMINTENSITY, imhist_intensity, float,
|
|
numEntry, histTable );
|
|
|
|
|
|
/* set up other header fields */
|
|
histTable->imhist_nEntries = numEntry;
|
|
histTable->imhist_fieldMask = fieldMask;
|
|
histTable->imhist_nFields = numChannels;
|
|
|
|
return ( histTable );
|
|
}
|
|
|
|
#undef IM_HISTALLOC
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* imVfbHistFieldOrder - determine the best ordering for field hasing
|
|
*
|
|
* DESCRIPTION
|
|
* To construct the histogram, pixel field data will be hashed into
|
|
* a hash table. For multi-channel histograms, such as RGB histograms,
|
|
* two fields are combined to construct a single hash index (such as
|
|
* index = (red << 8) | green). The selection of which two fields to
|
|
* combine is important.
|
|
*
|
|
* If, for instance, we have an image with lots of shades of blue, but
|
|
* use red and green for the hash index, then the hash table will be
|
|
* sparsly filled and we'll have huge collision chains. So, we'd like
|
|
* to pick the two hash fields as being the ones representing the most
|
|
* number of colors in the image.
|
|
*
|
|
* To do this we compute image statistics on the number of unique values
|
|
* for each of the fields and pick the top two.
|
|
*/
|
|
|
|
static void /* Returns nothing */
|
|
#ifdef __STDC__
|
|
imVfbHistFieldOrder( int fieldMask, int hashFields[3], ImVfb *vfb )
|
|
#else
|
|
imVfbHistFieldOrder( fieldMask, hashFields, vfb )
|
|
int fieldMask; /* what fields to do histogram on */
|
|
int hashFields[3]; /* Returned field order */
|
|
ImVfb *vfb; /* incoming vfb to do histogram on*/
|
|
#endif
|
|
{
|
|
int i; /* Counter */
|
|
float stats[IMMAXNUMSTATS]; /* Image statistics */
|
|
int hashFieldUniques[4]; /* Number of unique values for fields*/
|
|
int biggest, biggestUniques;/* Biggest number of unique values*/
|
|
int bigger, biggerUniques; /* Bigger number of unique values*/
|
|
int smaller, smallerUniques;/* Smaller number of unique values*/
|
|
|
|
|
|
/*
|
|
* Zero out our count of unique values for each of the fields.
|
|
*/
|
|
hashFieldUniques[IMVFBH_RED] = 0;
|
|
hashFieldUniques[IMVFBH_GREEN] = 0;
|
|
hashFieldUniques[IMVFBH_BLUE] = 0;
|
|
hashFieldUniques[IMVFBH_ALPHA] = 0;
|
|
hashFieldUniques[IMVFBH_HUE] = 0;
|
|
hashFieldUniques[IMVFBH_SATURATION] = 0;
|
|
hashFieldUniques[IMVFBH_INTENSITY] = 0;
|
|
|
|
|
|
/*
|
|
* Compute the number of unique values for each of the fields.
|
|
*/
|
|
if ( fieldMask & IMRED )
|
|
{
|
|
ImVfbStat( vfb, IMRED, stats );
|
|
hashFieldUniques[IMVFBH_RED] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMGREEN )
|
|
{
|
|
ImVfbStat( vfb, IMGREEN, stats );
|
|
hashFieldUniques[IMVFBH_GREEN] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMBLUE )
|
|
{
|
|
ImVfbStat( vfb, IMBLUE, stats );
|
|
hashFieldUniques[IMVFBH_BLUE] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMALPHA )
|
|
{
|
|
ImVfbStat( vfb, IMALPHA, stats );
|
|
hashFieldUniques[IMVFBH_ALPHA] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMHUE )
|
|
{
|
|
ImVfbStat( vfb, IMHUE, stats );
|
|
hashFieldUniques[IMVFBH_HUE] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMSATURATION )
|
|
{
|
|
ImVfbStat( vfb, IMSATURATION, stats );
|
|
hashFieldUniques[IMVFBH_SATURATION] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
if ( fieldMask & IMINTENSITY )
|
|
{
|
|
ImVfbStat( vfb, IMINTENSITY, stats );
|
|
hashFieldUniques[IMVFBH_INTENSITY] = (int)stats[IMUNIQUEVAL];
|
|
}
|
|
|
|
|
|
/*
|
|
* Determine which fields have the largest number of unique values
|
|
* and select them as the best choices for the hash field order.
|
|
*
|
|
* NOTE: RGB and HSI are mutually exclusive, but both can have
|
|
* alpha fields.
|
|
*/
|
|
biggestUniques = biggerUniques = smallerUniques = -1;
|
|
biggest = bigger = smaller = -1;
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( hashFieldUniques[i] > biggestUniques )
|
|
{
|
|
biggestUniques = hashFieldUniques[i];
|
|
biggest = i;
|
|
}
|
|
}
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( hashFieldUniques[i] <= biggestUniques &&
|
|
i != biggest && hashFieldUniques[i] > biggerUniques )
|
|
{
|
|
biggerUniques = hashFieldUniques[i];
|
|
bigger = i;
|
|
}
|
|
}
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
if ( hashFieldUniques[i] <= biggerUniques &&
|
|
i != biggest && i != bigger &&
|
|
hashFieldUniques[i] > smallerUniques )
|
|
{
|
|
smallerUniques = hashFieldUniques[i];
|
|
smaller = i;
|
|
}
|
|
}
|
|
|
|
hashFields[0] = biggest;
|
|
hashFields[1] = bigger;
|
|
hashFields[2] = smaller;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* imVfbHistAddValue - add value to histogram table
|
|
*
|
|
* DESCRUPTION
|
|
* When histogramming more than 2 fields at a time, we build a hash
|
|
* table where each entry points to a collision list. Two of the
|
|
* field values are used to index into the hash table. The remaining
|
|
* one or two fields are found in the collision list.
|
|
*
|
|
* imVfbHistAddValue( ) adds a new pair of values to the hash table
|
|
* and collision list. If the hashed-to entry doesn't have a
|
|
* collision list yet, one is allocated and initialized. The pair of
|
|
* values are then looked up in the collision list. If they're found,
|
|
* the entry's occurrence count is incremented. Otherwise the pair of
|
|
* values are put into a new collision list entry, possibly requiring
|
|
* a realloc to extend the collision list size to accomidate them.
|
|
*/
|
|
|
|
static int imVfbHistNColors; /* Number of unique colors */
|
|
|
|
static int /* Returns status */
|
|
#ifdef __STDC__
|
|
imVfbHistAddValue( imHistBucketHeader **hash, int index, int value1, int value2 )
|
|
#else
|
|
imVfbHistAddValue( hash, index, value1, value2 )
|
|
imHistBucketHeader **hash; /* Hash table to add to */
|
|
int index; /* Hash table index */
|
|
int value1; /* First value to add */
|
|
int value2; /* Second value to add */
|
|
#endif
|
|
{
|
|
imHistBucketHeader *pHash;/* Pointer to hash table entry */
|
|
int k; /* Counter */
|
|
|
|
|
|
/*
|
|
* If there's no collision list there yet, allocate one.
|
|
*/
|
|
pHash = hash[ index ];
|
|
if ( pHash == NULL )
|
|
{
|
|
/* Allocate a header. */
|
|
if ( (hash[ index ] = pHash = (imHistBucketHeader *)malloc(
|
|
sizeof( imHistBucketHeader ))) == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( -1 );
|
|
}
|
|
pHash->imhist_allocSize = IM_STARTSIZE;
|
|
pHash->imhist_nextSlot = 0;
|
|
|
|
/* Allocate an initial collision list. */
|
|
if ( (pHash->imhist_list = (imHistBucket *)malloc(
|
|
sizeof( imHistBucket ) * IM_STARTSIZE )) == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( -1 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Walk the collision list looking for this value.
|
|
*/
|
|
for ( k = 0; k < pHash->imhist_nextSlot; k++ )
|
|
{
|
|
if ( pHash->imhist_list[k].imhist_value1 == value1 &&
|
|
pHash->imhist_list[k].imhist_value2 == value2 )
|
|
{
|
|
++pHash->imhist_list[k].imhist_nOccur;
|
|
return ( 0 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Not found in the collision list. If there's no room left in
|
|
* the list, increase the size.
|
|
*/
|
|
if ( pHash->imhist_nextSlot == pHash->imhist_allocSize )
|
|
{
|
|
pHash->imhist_allocSize += IM_SIZEINC;
|
|
if ( (pHash->imhist_list = (imHistBucket *)realloc(
|
|
(char *)pHash->imhist_list,
|
|
sizeof( imHistBucket ) * pHash->imhist_allocSize )) == NULL )
|
|
{
|
|
ImErrNo = IMEMALLOC;
|
|
return ( -1 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Add a new collision list entry.
|
|
*/
|
|
pHash->imhist_list[k].imhist_value1 = value1;
|
|
pHash->imhist_list[k].imhist_value2 = value2;
|
|
pHash->imhist_list[k].imhist_nOccur = 1;
|
|
pHash->imhist_nextSlot++;
|
|
imVfbHistNColors++;
|
|
return( 0 );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* FUNCTION
|
|
* imVfbHistHashFree - free a hash table
|
|
*
|
|
* DESCRIPTION
|
|
* The hash table and all its collision lists are deallocated.
|
|
*/
|
|
|
|
static void /* Returns nothing */
|
|
#ifdef __STDC__
|
|
imVfbHistHashFree( imHistBucketHeader **hash, int hashSize )
|
|
#else
|
|
imVfbHistHashFree( hash, hashSize )
|
|
imHistBucketHeader **hash; /* Hash table to toss */
|
|
int hashSize; /* Size of hash table */
|
|
#endif
|
|
{
|
|
int j; /* Counter */
|
|
|
|
for ( j = 0; j < hashSize; j++ )
|
|
{
|
|
if ( hash[ j ] == NULL )
|
|
continue;
|
|
if ( hash[j]->imhist_list )
|
|
free( (char *)hash[j]->imhist_list );
|
|
free( (char *)hash[j] );
|
|
}
|
|
free( (char *)hash );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SINGLE FIELD HISTOGRAMS
|
|
*/
|
|
|
|
/*
|
|
* MACRO
|
|
* IM_HIST1FIELD - build a function for single-field histograms
|
|
* IM_HIST1FIELDHSI - same deal but for HSI fields
|
|
*
|
|
* DESCRIPTION
|
|
* Each of the histogram functions that compute for a single pixel
|
|
* field look nearly identical. They could all be combined into a
|
|
* single function, but we'd have to embedd lots of loop-invariant
|
|
* if-statements to select which field to work on. Instead, we
|
|
* split them into several nearly identical routines.
|
|
*
|
|
* These single-field histogram routines are all automatically
|
|
* generated by the IM_HIST1FIELD macro. Parameters to the macro
|
|
* select the function name to create, the field to compute on,
|
|
* the VFB query call to use to get that field value, the histogram
|
|
* table field to contain the value list, and the size of the hash
|
|
* table to work with.
|
|
*
|
|
* IM_HIST1FIELD hashes the field value into a hash table then counts
|
|
* the number of unique field values. A histogram data table is
|
|
* then allocated and those entries copied into it.
|
|
*
|
|
* IM_HIST1FIELDHSI is nearly identical to IM_HIST1FIELD, but does the
|
|
* extra work needed for dealing with HSI virtual fields.
|
|
*/
|
|
#ifdef __STDC__
|
|
#define IM_VFBHEADER(fn) fn( ImVfb * vfb)
|
|
#else
|
|
#define IM_VFBHEADER(fn) fn(vfb) ImVfb *vfb;
|
|
#endif
|
|
|
|
|
|
#define IM_HIST1FIELD( funcName, field, query, tableField, hashSize ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j; /* Counters */\
|
|
int hash[hashSize]; /* Hash table counting unique pixels */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
memset( (void *)hash, 0x00, sizeof( int ) * (hashSize) ); \
|
|
IMVFBH_HASH( vfb, query, hash ); \
|
|
\
|
|
/* Count the number of unique values. */\
|
|
for ( nEntry = i = 0; i < hashSize; i++ ) \
|
|
if ( hash[i] != 0 ) \
|
|
++nEntry; \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( nEntry, field, 1 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( i = j = 0; i < (hashSize); i++ ) \
|
|
{ \
|
|
if ( hash[i] != 0 ) \
|
|
{ \
|
|
histTable->tableField[j] = i; \
|
|
histTable->imhist_nOccur[j++] = hash[i]; \
|
|
} \
|
|
} \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
#define IM_HIST1FIELDHSI( funcName, field, which, factor, tableField, hashSize )\
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j; /* Counters */\
|
|
int hash[hashSize]; /* Hash table counting unique pixels */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
memset( (void *)hash, 0x00, sizeof( int ) * (hashSize) ); \
|
|
IMVFBH_HASHHSI( vfb, which, factor, hash ); \
|
|
\
|
|
/* Count the number of unique values. */\
|
|
for ( nEntry = i = 0; i < hashSize; i++ ) \
|
|
if ( hash[i] != 0 ) \
|
|
++nEntry; \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( nEntry, field, 1 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( i = j = 0; i < (hashSize); i++ ) \
|
|
{ \
|
|
if ( hash[i] != 0 ) \
|
|
{ \
|
|
histTable->tableField[j] = (float)i/(factor); \
|
|
histTable->imhist_nOccur[j++] = hash[i]; \
|
|
} \
|
|
} \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
IM_HIST1FIELD( imMHist, IMMONO, ImVfbQMono, imhist_mono, 2 )
|
|
IM_HIST1FIELD( im8Hist, IMINDEX8, ImVfbQIndex8, imhist_index8, 256 )
|
|
IM_HIST1FIELD( im16Hist, IMINDEX16, ImVfbQIndex16, imhist_index16, 65536 )
|
|
|
|
IM_HIST1FIELD( imRHist, IMRED, ImVfbQRed, imhist_red, 256 )
|
|
IM_HIST1FIELD( imGHist, IMGREEN, ImVfbQGreen, imhist_green, 256 )
|
|
IM_HIST1FIELD( imBHist, IMBLUE, ImVfbQBlue, imhist_blue, 256 )
|
|
IM_HIST1FIELD( imAHist, IMALPHA, ImVfbQAlpha, imhist_alpha, 256 )
|
|
|
|
IM_HIST1FIELDHSI( imHHist, IMHUE, 0, (1023.0/360.0),
|
|
imhist_hue, 1024 )
|
|
IM_HIST1FIELDHSI( imSHist, IMSATURATION, 1, (1023.0),
|
|
imhist_saturation, 1024 )
|
|
IM_HIST1FIELDHSI( imIHist, IMINTENSITY, 2, (1023.0),
|
|
imhist_intensity, 1024 )
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DOUBLE FIELD HISTOGRAMS
|
|
*/
|
|
|
|
/*
|
|
* MACRO
|
|
* IM_HIST2FIELD - build a function for double-field histograms
|
|
* IM_HIST2FIELD1HSI - same deal but for 1 HSI field
|
|
* IM_HIST2FIELD2HSI - same deal but for 2 HSI fields
|
|
*
|
|
* DESCRIPTION
|
|
* As with IM_HIST1FIELD, all of the double-field histogram functions
|
|
* are automatically generated.
|
|
*
|
|
* IM_HIST2FIELD hashes the field values into a hash table then counts
|
|
* the number of unique field values. A histogram data table is
|
|
* then allocated and those entries copied into it.
|
|
*
|
|
* IM_HIST1FIELD and IM_HIST2FIELD differ in that the former uses one
|
|
* pixel field in the hash function, and the later uses two.
|
|
*
|
|
* IM_HIST2FIELD1HSI and IM_HIST2FIELD2HSI are nearly identical to IM_HIST2FIELD,
|
|
* but include the extra work needed for dealing with HSI virtual fields.
|
|
*/
|
|
|
|
|
|
#define IM_HIST2FIELD( funcName, fields, query1, query2, tableField1, tableField2, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
int hash[(hashSize1)*(hashSize2)];/* Table counting unique pixels*/\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
memset( (void *)hash, 0x00, sizeof( int ) * hashSize ); \
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
index = (query1( vfb, pPixel ) << (shift)) | \
|
|
query2( vfb, pPixel ); \
|
|
hash[ index ]++; \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Count the number of unique values. */\
|
|
for ( nEntry = i = 0; i < hashSize; i++ ) \
|
|
if ( hash[i] != 0 ) \
|
|
++nEntry; \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( nEntry, fields, 2 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( i = j = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
if ( hash[index] != 0 ) \
|
|
{ \
|
|
histTable->tableField1[j] = i; \
|
|
histTable->tableField2[j] = k; \
|
|
histTable->imhist_nOccur[j++] = hash[index];\
|
|
} \
|
|
} \
|
|
} \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST2FIELD1HSI( funcName, fields, which1, factor1, query2, tableField1, tableField2, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
int hash[(hashSize1)*(hashSize2)];/* Table counting unique pixels*/\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
memset( (void *)hash, 0x00, sizeof( int ) * hashSize ); \
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
query2( vfb, pPixel ); \
|
|
hash[ index ]++; \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Count the number of unique values. */\
|
|
for ( nEntry = i = 0; i < hashSize; i++ ) \
|
|
if ( hash[i] != 0 ) \
|
|
++nEntry; \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( nEntry, fields, 2 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( i = j = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
if ( hash[index] != 0 ) \
|
|
{ \
|
|
histTable->tableField1[j] = (float)i/(factor1);\
|
|
histTable->tableField2[j] = k; \
|
|
histTable->imhist_nOccur[j++] = hash[index];\
|
|
} \
|
|
} \
|
|
} \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST2FIELD2HSI( funcName, fields, which1, factor1, which2, factor2, tableField1, tableField2, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
int hash[(hashSize1)*(hashSize2)];/* Table counting unique pixels*/\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
memset( (void *)hash, 0x00, sizeof( int ) * hashSize ); \
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
(int)(hsi[which2] * (factor2)); \
|
|
hash[ index ]++; \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Count the number of unique values. */\
|
|
for ( nEntry = i = 0; i < hashSize; i++ ) \
|
|
if ( hash[i] != 0 ) \
|
|
++nEntry; \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( nEntry, fields, 2 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( i = j = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
if ( hash[index] != 0 ) \
|
|
{ \
|
|
histTable->tableField1[j] = (float)i/(factor1);\
|
|
histTable->tableField2[j] = (float)k/(factor2);\
|
|
histTable->imhist_nOccur[j++] = hash[index];\
|
|
} \
|
|
} \
|
|
} \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
/*
|
|
* All possible legal combinations of 2 fields:
|
|
* ( different orderings of the first 2 fields are equivalent )
|
|
*
|
|
* R G
|
|
* R B
|
|
* R A
|
|
*
|
|
* G R (same as R G)
|
|
* G B
|
|
* G A
|
|
*
|
|
* B R (same as R B)
|
|
* B G (same as G B)
|
|
* B A
|
|
*
|
|
* M A
|
|
* 8 A
|
|
* 16 A
|
|
*
|
|
* H S
|
|
* H I
|
|
* H A
|
|
*
|
|
* S H (same as H S)
|
|
* S I
|
|
* S A
|
|
*
|
|
* I H (same as H I)
|
|
* I S (same as S I)
|
|
* I A
|
|
*/
|
|
|
|
IM_HIST2FIELD( imRGHist, IMRED|IMGREEN,
|
|
ImVfbQRed, ImVfbQGreen,
|
|
imhist_red, imhist_green,
|
|
256, 256, 8 )
|
|
IM_HIST2FIELD( imRBHist, IMRED|IMBLUE,
|
|
ImVfbQRed, ImVfbQBlue,
|
|
imhist_red, imhist_blue,
|
|
256, 256, 8 )
|
|
IM_HIST2FIELD( imRAHist, IMRED|IMALPHA,
|
|
ImVfbQRed, ImVfbQAlpha,
|
|
imhist_red, imhist_alpha,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST2FIELD( imGAHist, IMGREEN|IMALPHA,
|
|
ImVfbQGreen, ImVfbQAlpha,
|
|
imhist_green, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST2FIELD( imGBHist, IMGREEN|IMBLUE,
|
|
ImVfbQGreen, ImVfbQBlue,
|
|
imhist_green, imhist_blue,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST2FIELD( imBAHist, IMBLUE|IMALPHA,
|
|
ImVfbQBlue, ImVfbQAlpha,
|
|
imhist_blue, imhist_alpha,
|
|
256, 256, 8 )
|
|
|
|
|
|
IM_HIST2FIELD( imMAHist, IMMONO|IMALPHA,
|
|
ImVfbQMono, ImVfbQAlpha,
|
|
imhist_mono, imhist_alpha,
|
|
2, 256, 8 )
|
|
IM_HIST2FIELD( im8AHist, IMINDEX8|IMALPHA,
|
|
ImVfbQIndex8, ImVfbQAlpha,
|
|
imhist_index8, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST2FIELD( im16AHist, IMINDEX16|IMALPHA,
|
|
ImVfbQIndex16, ImVfbQAlpha,
|
|
imhist_index16, imhist_alpha,
|
|
65536, 256, 8 )
|
|
|
|
|
|
IM_HIST2FIELD2HSI( imHSHist, IMHUE|IMSATURATION,
|
|
0, (1023.0/360.0), 1, 1023.0,
|
|
imhist_hue, imhist_saturation,
|
|
1024, 1024, 10 )
|
|
IM_HIST2FIELD2HSI( imHIHist, IMHUE|IMINTENSITY,
|
|
0, (1023.0/360.0), 2, 1023.0,
|
|
imhist_hue, imhist_intensity,
|
|
1024, 1024, 10 )
|
|
IM_HIST2FIELD1HSI( imHAHist, IMHUE|IMALPHA,
|
|
0, (1023.0/360.0), ImVfbQAlpha,
|
|
imhist_hue, imhist_alpha,
|
|
1024, 256, 8 )
|
|
|
|
IM_HIST2FIELD2HSI( imSIHist, IMSATURATION|IMINTENSITY,
|
|
1, 1023.0, 2, (1023.0),
|
|
imhist_saturation, imhist_intensity,
|
|
1024, 1024, 10 )
|
|
IM_HIST2FIELD1HSI( imSAHist, IMSATURATION|IMALPHA,
|
|
1, 1023.0, ImVfbQAlpha,
|
|
imhist_saturation, imhist_alpha,
|
|
1024, 256, 8 )
|
|
|
|
IM_HIST2FIELD1HSI( imIAHist, IMINTENSITY|IMALPHA,
|
|
2, 1023.0, ImVfbQAlpha,
|
|
imhist_intensity, imhist_alpha,
|
|
1024, 256, 8 )
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* TRIPLE FIELD HISTOGRAMS
|
|
*/
|
|
|
|
/*
|
|
* MACRO
|
|
* IM_HIST3FIELD - build a function for triple-field histograms
|
|
* IM_HIST3FIELD1HSI - same deal but for 1 HSI field
|
|
* IM_HIST3FIELD2HSI - same deal but for 2 HSI fields
|
|
* IM_HIST3FIELD3HSI - same deal but for 2 HSI fields
|
|
*
|
|
* DESCRIPTION
|
|
* As with IM_HIST1FIELD, all of the triple-field histogram functions
|
|
* are automatically generated.
|
|
*
|
|
* IM_HIST3FIELD hashes two field values together, then follows a
|
|
* collision chain along until it finds the third field's value, or
|
|
* reaches the end. In the first case it just increments the occurrence
|
|
* count. In the second case it adds a new entry to the collision list
|
|
* and sets the occurrence count to 1.
|
|
*
|
|
* After hasing is complete, IM_HIST3FIELD functions allocate a histogram
|
|
* data table and copy the data into it.
|
|
*/
|
|
|
|
|
|
#define IM_HIST3FIELD( funcName, fields, query1, query2, query3, tableField1, tableField2, tableField3, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
index = (query1( vfb, pPixel ) << (shift)) | \
|
|
query2( vfb, pPixel ); \
|
|
if ( imVfbHistAddValue( hash, index, query3( vfb, pPixel ), 0 ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = i; \
|
|
histTable->tableField2[nEntry] = k; \
|
|
histTable->tableField3[nEntry] = pHash->imhist_list[j].imhist_value1;\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST3FIELD1HSI( funcName, fields, which1, factor1, query2, which3, factor3, tableField1, tableField2, tableField3, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
query2( vfb, pPixel ); \
|
|
if ( imVfbHistAddValue( hash, index, (int)(hsi[which3] * (factor3)), 0 ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = (float)i/(factor1);\
|
|
histTable->tableField2[nEntry] = k;\
|
|
histTable->tableField3[nEntry] = (float)(pHash->imhist_list[j].imhist_value1)/(factor3);\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST3FIELD2HSI( funcName, fields, which1, factor1, which2, factor2, query3, tableField1, tableField2, tableField3, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
(int)(hsi[which2] * (factor2)); \
|
|
if ( imVfbHistAddValue( hash, index, query3( vfb, pPixel ), 0 ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = (float)i/(factor1);\
|
|
histTable->tableField2[nEntry] = (float)k/(factor2);\
|
|
histTable->tableField3[nEntry] = pHash->imhist_list[j].imhist_value1;\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST3FIELD3HSI( funcName, fields, which1, factor1, which2, factor2, which3, factor3, tableField1, tableField2, tableField3, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
(int)(hsi[which2] * (factor2)); \
|
|
if ( imVfbHistAddValue( hash, index, (int)(hsi[which3] * (factor3)), 0 ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = (float)i/(factor1);\
|
|
histTable->tableField2[nEntry] = (float)k/(factor2);\
|
|
histTable->tableField3[nEntry] = (float)pHash->imhist_list[j].imhist_value1/(factor3);\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
/*
|
|
* All possible legal combinations of 3 fields:
|
|
* ( different orderings of the first 2 fields are equivalent )
|
|
*
|
|
* R G B
|
|
* R G A
|
|
* R B G
|
|
* R B A
|
|
* R A B
|
|
* R A G
|
|
*
|
|
* B R G (same as R B G)
|
|
* B R A (same as R B A)
|
|
* B G R
|
|
* B G A
|
|
* B A R
|
|
* B A G
|
|
*
|
|
* G B R (same as B G R)
|
|
* G B A (same as B G A)
|
|
* G R B (same as R G B)
|
|
* G R A (same as R G A)
|
|
* G A R
|
|
* G A B
|
|
*
|
|
* A R B (same as R A B)
|
|
* A R G (same as R A G)
|
|
* A B R (same as B A R)
|
|
* A B G (same as B A G)
|
|
* A G R (same as G A R)
|
|
* A G B (same as G A B)
|
|
*
|
|
* H S I
|
|
* H S A
|
|
* H I S
|
|
* H I A
|
|
* H A S
|
|
* H A I
|
|
*
|
|
* S H I (same as H S I)
|
|
* S H A (same as H S A)
|
|
* S I H
|
|
* S I A
|
|
* S A H
|
|
* S A I
|
|
*
|
|
* I H S (same as H I S)
|
|
* I H A (same as H I A)
|
|
* I S H (same as S I H)
|
|
* I S A (same as S I A)
|
|
* I A H
|
|
* I A S
|
|
*
|
|
* A H S (same as H A S)
|
|
* A H I (same as H A I)
|
|
* A S H (same as S A H)
|
|
* A S I (same as S A I)
|
|
* A I H (same as I A H)
|
|
* A I S (same as I A S)
|
|
*/
|
|
|
|
IM_HIST3FIELD( imRGBHist, IMRED|IMGREEN|IMBLUE,
|
|
ImVfbQRed, ImVfbQGreen, ImVfbQBlue,
|
|
imhist_red, imhist_green, imhist_blue,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imRGAHist, IMRED|IMGREEN|IMALPHA,
|
|
ImVfbQRed, ImVfbQGreen, ImVfbQAlpha,
|
|
imhist_red, imhist_green, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imRBGHist, IMRED|IMBLUE|IMGREEN,
|
|
ImVfbQRed, ImVfbQBlue, ImVfbQGreen,
|
|
imhist_red, imhist_blue, imhist_green,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imRBAHist, IMRED|IMBLUE|IMALPHA,
|
|
ImVfbQRed, ImVfbQBlue, ImVfbQAlpha,
|
|
imhist_red, imhist_blue, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imRABHist, IMRED|IMALPHA|IMBLUE,
|
|
ImVfbQRed, ImVfbQAlpha, ImVfbQBlue,
|
|
imhist_red, imhist_alpha, imhist_blue,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imRAGHist, IMRED|IMALPHA|IMGREEN,
|
|
ImVfbQRed, ImVfbQAlpha, ImVfbQGreen,
|
|
imhist_red, imhist_alpha, imhist_green,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST3FIELD( imBGRHist, IMBLUE|IMGREEN|IMRED,
|
|
ImVfbQBlue, ImVfbQGreen, ImVfbQRed,
|
|
imhist_blue, imhist_green, imhist_red,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imBGAHist, IMBLUE|IMGREEN|IMALPHA,
|
|
ImVfbQBlue, ImVfbQGreen, ImVfbQAlpha,
|
|
imhist_blue, imhist_green, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imBARHist, IMBLUE|IMALPHA|IMRED,
|
|
ImVfbQBlue, ImVfbQAlpha, ImVfbQRed,
|
|
imhist_blue, imhist_alpha, imhist_red,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imBAGHist, IMBLUE|IMALPHA|IMGREEN,
|
|
ImVfbQBlue, ImVfbQAlpha, ImVfbQGreen,
|
|
imhist_blue, imhist_alpha, imhist_green,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST3FIELD( imGARHist, IMGREEN|IMALPHA|IMRED,
|
|
ImVfbQGreen, ImVfbQAlpha, ImVfbQRed,
|
|
imhist_green, imhist_alpha, imhist_red,
|
|
256, 256, 8 )
|
|
IM_HIST3FIELD( imGABHist, IMGREEN|IMALPHA|IMBLUE,
|
|
ImVfbQGreen, ImVfbQAlpha, ImVfbQBlue,
|
|
imhist_green, imhist_alpha, imhist_blue,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST3FIELD3HSI( imHSIHist, IMHUE|IMSATURATION|IMINTENSITY,
|
|
0, (1023.0/360.0), 1, 1023.0, 2, 1023.0,
|
|
imhist_hue, imhist_saturation, imhist_intensity,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD2HSI( imHSAHist, IMHUE|IMSATURATION|IMALPHA,
|
|
0, (1023.0/360.0), 1, 1023.0, ImVfbQAlpha,
|
|
imhist_hue, imhist_saturation, imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD3HSI( imHISHist, IMHUE|IMINTENSITY|IMSATURATION,
|
|
0, (1023.0/360.0), 2, 1023.0, 1, 1023.0,
|
|
imhist_hue, imhist_intensity, imhist_saturation,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD2HSI( imHIAHist, IMHUE|IMINTENSITY|IMALPHA,
|
|
0, (1023.0/360.0), 2, 1023.0, ImVfbQAlpha,
|
|
imhist_hue, imhist_intensity, imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD1HSI( imHASHist, IMHUE|IMALPHA|IMSATURATION,
|
|
0, (1023.0/360.0), ImVfbQAlpha, 1, 1023.0,
|
|
imhist_hue, imhist_alpha, imhist_saturation,
|
|
1024, 256, 8 )
|
|
IM_HIST3FIELD1HSI( imHAIHist, IMHUE|IMALPHA|IMINTENSITY,
|
|
0, (1023.0/360.0), ImVfbQAlpha, 2, 1023.0,
|
|
imhist_hue, imhist_alpha, imhist_intensity,
|
|
1024, 256, 8 )
|
|
|
|
IM_HIST3FIELD3HSI( imSIHHist, IMSATURATION|IMINTENSITY|IMHUE,
|
|
1, 1023.0, 2, 1023.0, 0, (1023.0/360.0),
|
|
imhist_saturation, imhist_intensity, imhist_hue,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD2HSI( imSIAHist, IMSATURATION|IMINTENSITY|IMALPHA,
|
|
1, 1023.0, 2, 1023.0, ImVfbQAlpha,
|
|
imhist_saturation, imhist_intensity, imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST3FIELD1HSI( imSAHHist, IMSATURATION|IMALPHA|IMHUE,
|
|
1, 1023.0, ImVfbQAlpha, 0, (1023.0/360.0),
|
|
imhist_saturation, imhist_alpha, imhist_hue,
|
|
1024, 256, 8 )
|
|
IM_HIST3FIELD1HSI( imSAIHist, IMSATURATION|IMALPHA|IMINTENSITY,
|
|
1, 1023.0, ImVfbQAlpha, 2, 1023.0,
|
|
imhist_saturation, imhist_alpha, imhist_intensity,
|
|
1024, 256, 8 )
|
|
|
|
IM_HIST3FIELD1HSI( imIAHHist, IMINTENSITY|IMALPHA|IMHUE,
|
|
2, 1023.0, ImVfbQAlpha, 0, (1023.0/360.0),
|
|
imhist_intensity, imhist_alpha, imhist_hue,
|
|
1024, 256, 8 )
|
|
IM_HIST3FIELD1HSI( imIASHist, IMINTENSITY|IMALPHA|IMSATURATION,
|
|
2, 1023.0, ImVfbQAlpha, 1, 1023.0,
|
|
imhist_intensity, imhist_alpha, imhist_saturation,
|
|
1024, 256, 8 )
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* QUADRUPLE FIELD HISTOGRAMS
|
|
*/
|
|
|
|
/*
|
|
* MACRO
|
|
* IM_HIST4FIELD - build a function for quadruple-field histograms
|
|
* IM_HIST4FIELD3HSI - same deal but for 3 HSI fields
|
|
* IM_HIST4FIELD3HSI2 - same deal but for 3 HSI fields, different alpha loc
|
|
*
|
|
* DESCRIPTION
|
|
* As with IM_HIST1FIELD, all of the quadruple-field histogram functions
|
|
* are automatically generated.
|
|
*
|
|
* IM_HIST4FIELD hashes two field values together, then follows a
|
|
* collision chain along until it finds the third and fourth field values,
|
|
* or reaches the end. In the first case it just increments the occurrence
|
|
* count. In the second case it adds a new entry to the collision list
|
|
* and sets the occurrence count to 1.
|
|
*
|
|
* After hasing is complete, IM_HIST4FIELD functions allocate a histogram
|
|
* data table and copy the data into it.
|
|
*/
|
|
|
|
|
|
#define IM_HIST4FIELD( funcName, fields, query1, query2, query3, query4, tableField1, tableField2, tableField3, tableField4, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
index = (query1( vfb, pPixel ) << (shift)) | \
|
|
query2( vfb, pPixel ); \
|
|
if ( imVfbHistAddValue( hash, index, query3( vfb, pPixel ), query4( vfb, pPixel ) ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = i; \
|
|
histTable->tableField2[nEntry] = k; \
|
|
histTable->tableField3[nEntry] = pHash->imhist_list[j].imhist_value1;\
|
|
histTable->tableField4[nEntry] = pHash->imhist_list[j].imhist_value2;\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
#define IM_HIST4FIELD3HSI( funcName, fields, which1, factor1, query2, which3, factor3, which4, factor4, tableField1, tableField2, tableField3, tableField4, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
query2( vfb, pPixel ); \
|
|
if ( imVfbHistAddValue( hash, index, (int)(hsi[which3] * (factor3)), (int)(hsi[which4] * (factor4)) ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = (float)i/(factor1); \
|
|
histTable->tableField2[nEntry] = k; \
|
|
histTable->tableField3[nEntry] = (float)pHash->imhist_list[j].imhist_value1/(factor3);\
|
|
histTable->tableField4[nEntry] = (float)pHash->imhist_list[j].imhist_value2/(factor4);\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
#define IM_HIST4FIELD3HSI2( funcName, fields, which1, factor1, which2, factor2, which3, factor3, query4, tableField1, tableField2, tableField3, tableField4, hashSize1, hashSize2, shift ) \
|
|
ImHistTable * /* Returns histogram table */\
|
|
IM_VFBHEADER(funcName) \
|
|
{ \
|
|
int i, j, k; /* Counters */\
|
|
int h, w; /* Height and width of image */\
|
|
ImVfbPtr pPixel; /* Pixel pointer */\
|
|
imHistBucketHeader **hash;/* Hash table */\
|
|
imHistBucketHeader *pHash;/* Hash table pointer */\
|
|
int nEntry; /* Number of unique pixels */\
|
|
ImHistTable *histTable;/* Histogram table */\
|
|
int hashSize; /* Hash table size */\
|
|
int index; /* Hash table index */\
|
|
int rgb[3]; /* RGB triplet */\
|
|
float hsi[3]; /* HSI equivalent */\
|
|
\
|
|
/* Allocate the hash table as a table of collision lists. */\
|
|
hashSize = (hashSize1) * (hashSize2); \
|
|
if ( (hash = (imHistBucketHeader **)malloc( \
|
|
sizeof( imHistBucketHeader * ) * hashSize )) == NULL ) \
|
|
{ \
|
|
ImErrNo = IMEMALLOC; \
|
|
return ( NULL ); \
|
|
} \
|
|
memset( (void *)hash, 0x00, sizeof( imHistBucketHeader * ) * hashSize );\
|
|
\
|
|
/* Hash the color index into an occurrence table. */\
|
|
pPixel = ImVfbQFirst( vfb ); \
|
|
h = ImVfbQHeight( vfb ); \
|
|
w = ImVfbQWidth( vfb ); \
|
|
imVfbHistNColors = 0; \
|
|
for ( i = 0; i < h; i++ ) \
|
|
{ \
|
|
for ( k = 0; k < w; k++ ) \
|
|
{ \
|
|
rgb[0] = ImVfbQRed( vfb, pPixel ); \
|
|
rgb[1] = ImVfbQGreen( vfb, pPixel ); \
|
|
rgb[2] = ImVfbQBlue( vfb, pPixel ); \
|
|
ImRgbToHsi( rgb, hsi ); \
|
|
index = ((int)(hsi[which1] * (factor1)) << (shift)) |\
|
|
(int)(hsi[which2] * (factor2)); \
|
|
if ( imVfbHistAddValue( hash, index, (int)(hsi[which3] * (factor3)), query4( vfb, pPixel ) ) == -1 )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
imVfbHistHashFree( hash, hashSize ); \
|
|
return ( NULL ); \
|
|
} \
|
|
ImVfbSInc( vfb, pPixel ); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Allocate the histogram table. */\
|
|
if ( (histTable = imVfbHistTableAlloc( imVfbHistNColors, fields, 3 )) == NULL )\
|
|
{ \
|
|
/* ImErrNo already set. */\
|
|
return( NULL ); \
|
|
} \
|
|
\
|
|
/* Set the histogram table. */\
|
|
for ( nEntry = i = 0; i < (hashSize1); i++ ) \
|
|
{ \
|
|
for ( k = 0; k < (hashSize2); k++ ) \
|
|
{ \
|
|
index = (i << (shift)) | k; \
|
|
pHash = hash[ index ]; \
|
|
if ( pHash == NULL ) \
|
|
continue; \
|
|
for ( j = 0; j < pHash->imhist_nextSlot; j++ ) \
|
|
{ \
|
|
histTable->tableField1[nEntry] = (float)i/(factor1); \
|
|
histTable->tableField2[nEntry] = (float)k/(factor2); \
|
|
histTable->tableField3[nEntry] = (float)pHash->imhist_list[j].imhist_value1/(factor3);\
|
|
histTable->tableField4[nEntry] = pHash->imhist_list[j].imhist_value2;\
|
|
histTable->imhist_nOccur[nEntry++] = pHash->imhist_list[j].imhist_nOccur;\
|
|
} \
|
|
/* Toss the collision list. */\
|
|
free( (char *)pHash->imhist_list ); \
|
|
free( (char *)pHash ); \
|
|
} \
|
|
} \
|
|
free( (char *)hash ); \
|
|
return ( histTable ); \
|
|
}
|
|
|
|
|
|
/*
|
|
* All possible legal combinations of 4 fields:
|
|
* ( different orderings of the first 2 fields are equivalent )
|
|
* ( different orderings of the last 2 fields are equivalent )
|
|
*
|
|
* R G B A
|
|
* R G A B (same as R G B A)
|
|
* R B G A
|
|
* R B A G (same as R B G A)
|
|
* R A G B
|
|
* R A B G (same as R A G B)
|
|
*
|
|
* G R B A (same as R G B A)
|
|
* G R A B (same as R G B A)
|
|
* G B R A
|
|
* G B A R (same as G B R A)
|
|
* G A R B
|
|
* G A B R (same as G A R B)
|
|
*
|
|
* B R G A (same as R B G A)
|
|
* B R A G (same as R B G A)
|
|
* B G R A (same as G B R A)
|
|
* B G A R (same as G B R A)
|
|
* B A R G
|
|
* B A G R (same as B A R G)
|
|
*
|
|
* A R G B (same as R A B G)
|
|
* A R B G (same as R A B G)
|
|
* A B R G (same as B A R G)
|
|
* A B G R (same as B A R G)
|
|
* A G R B (same as G A R B)
|
|
* A G B R (same as G A R B)
|
|
*
|
|
* H S I A
|
|
* H S A I (same as H S I A)
|
|
* H I S A
|
|
* H I A S (same as H I S A)
|
|
* H A I S
|
|
* H A S I (same as H A I S)
|
|
*
|
|
* S H I A (same as H S I A)
|
|
* S H A I (same as H S I A)
|
|
* S I H A
|
|
* S I A H (same as S I H A)
|
|
* S A H I
|
|
* S A I H (same as S A H I)
|
|
*
|
|
* I H S A (same as H I S A)
|
|
* I H A S (same as H I S A)
|
|
* I S H A (same as S I H A)
|
|
* I S A H (same as S I H A)
|
|
* I A H S
|
|
* I A S H (same as I A H S)
|
|
*
|
|
* A H S I (same as H A I S)
|
|
* A H I S (same as H A I S)
|
|
* A I H S (same as I A H S)
|
|
* A I S H (same as I A H S)
|
|
* A S H I (same as S A H I)
|
|
* A S I H (same as S A H I)
|
|
*/
|
|
|
|
IM_HIST4FIELD( imRGBAHist, IMRED|IMGREEN|IMBLUE|IMALPHA,
|
|
ImVfbQRed, ImVfbQGreen, ImVfbQBlue, ImVfbQAlpha,
|
|
imhist_red, imhist_green, imhist_blue, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST4FIELD( imRBGAHist, IMRED|IMBLUE|IMGREEN|IMALPHA,
|
|
ImVfbQRed, ImVfbQBlue, ImVfbQGreen, ImVfbQAlpha,
|
|
imhist_red, imhist_blue, imhist_green, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST4FIELD( imRAGBHist, IMRED|IMALPHA|IMGREEN|IMBLUE,
|
|
ImVfbQRed, ImVfbQAlpha, ImVfbQGreen, ImVfbQBlue,
|
|
imhist_red, imhist_alpha, imhist_green, imhist_blue,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST4FIELD( imGBRAHist, IMGREEN|IMBLUE|IMRED|IMALPHA,
|
|
ImVfbQGreen, ImVfbQBlue, ImVfbQRed, ImVfbQAlpha,
|
|
imhist_green, imhist_blue, imhist_red, imhist_alpha,
|
|
256, 256, 8 )
|
|
IM_HIST4FIELD( imGARBHist, IMGREEN|IMALPHA|IMRED|IMBLUE,
|
|
ImVfbQGreen, ImVfbQAlpha, ImVfbQRed, ImVfbQBlue,
|
|
imhist_green, imhist_alpha, imhist_red, imhist_blue,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST4FIELD( imBARGHist, IMBLUE|IMALPHA|IMRED|IMGREEN,
|
|
ImVfbQBlue, ImVfbQAlpha, ImVfbQRed, ImVfbQGreen,
|
|
imhist_blue, imhist_alpha, imhist_red, imhist_green,
|
|
256, 256, 8 )
|
|
|
|
IM_HIST4FIELD3HSI2( imHSIAHist, IMHUE|IMSATURATION|IMINTENSITY|IMALPHA,
|
|
0, (1023.0/360.0),1, 1023.0, 2, 1023.0, ImVfbQAlpha,
|
|
imhist_hue, imhist_saturation,imhist_intensity,imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST4FIELD3HSI2( imHISAHist, IMHUE|IMINTENSITY|IMSATURATION|IMALPHA,
|
|
0, (1023.0/360.0),2, 1023.0, 1, 1023.0, ImVfbQAlpha,
|
|
imhist_hue, imhist_intensity,imhist_saturation,imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST4FIELD3HSI( imHAISHist, IMHUE|IMALPHA|IMINTENSITY|IMSATURATION,
|
|
0, (1023.0/360.0),ImVfbQAlpha, 2, 1023.0, 1, 1023.0,
|
|
imhist_hue, imhist_alpha, imhist_intensity,imhist_saturation,
|
|
1024, 256, 8 )
|
|
IM_HIST4FIELD3HSI2( imSIHAHist, IMSATURATION|IMINTENSITY|IMHUE|IMALPHA,
|
|
1, 1023.0, 2, 1023.0, 0, (1023.0/360.0),ImVfbQAlpha,
|
|
imhist_saturation,imhist_intensity,imhist_hue, imhist_alpha,
|
|
1024, 1024, 10 )
|
|
IM_HIST4FIELD3HSI( imSAHIHist, IMSATURATION|IMALPHA|IMHUE|IMINTENSITY,
|
|
1, 1023.0, ImVfbQAlpha, 0, (1023.0/360.0),2, 1023.0,
|
|
imhist_saturation,imhist_alpha, imhist_hue, imhist_intensity,
|
|
1024, 256, 8 )
|
|
IM_HIST4FIELD3HSI( imIAHSHist, IMINTENSITY|IMALPHA|IMHUE|IMSATURATION,
|
|
2, 1023.0, ImVfbQAlpha, 0, (1023.0/360.0),1, 1023.0,
|
|
imhist_intensity,imhist_alpha, imhist_hue, imhist_saturation,
|
|
1024, 256, 8 )
|