1 // imagesource_histogram.h
2 // Copyright (c) 2009 by Alastair M. Robinson
3 //
4 // This imagesource performs a straight pass-through of the image data
5 // but counts pixel values as it goes, creating a histogram.
6 // The histogram itself is owned by the client application and is supplied
7 // by reference, so much remain valid for the lifetime of the
8 // ImageSource_Histogram.
9 //
10 
11 #ifndef IMAGESOURCE_HISTOGRAM_H
12 #define IMAGESOURCE_HISTOGRAM_H
13 
14 #define IS_HISTOGRAM_BUCKETS 256
15 
16 #include "imagesource.h"
17 
18 
19 // An individual channel's histogram.  Access the data using the [] operator.
20 // A reference is returned, so the result can be modified as well as read.
21 
22 class ISHistogram_Channel
23 {
24 	public:
ISHistogram_Channel()25 	ISHistogram_Channel() : channeldata(NULL)
26 	{
27 		channeldata=new int[IS_HISTOGRAM_BUCKETS];
28 	}
~ISHistogram_Channel()29 	~ISHistogram_Channel()
30 	{
31 		if(channeldata)
32 			delete[] channeldata;
33 	}
34 	int &operator[](int samp)
35 	{
36 		if(samp>=IS_HISTOGRAM_BUCKETS || samp<0)
37 			throw "ISHistogram_Channel: Sample out of range";
38 //		std::cerr << "bucket " << samp << " - current value " << channeldata[samp] << std::endl;
39 		return(channeldata[samp]);
40 	}
Clear()41 	void Clear()
42 	{
43 		for(int i=0;i<IS_HISTOGRAM_BUCKETS;++i)
44 			channeldata[i]=0;
45 	}
46 	protected:
47 	int *channeldata;
48 };
49 
50 
51 class ISHistogram
52 {
53 	public:
54 	// Three constructors are provided - one takes the channel count and type directly,
55 	// one takes an existing imagesource and takes the channel count and type from that,
56 	// and the last takes no arguments, but requires the caller to call
57 	// SetHistogramType with channels and type before use.
channels(NULL)58 	ISHistogram(int channelcount,IS_TYPE type=IS_TYPE_RGB) : channels(NULL), channelcount(channelcount),type(type)
59 	{
60 		SetHistogramType(channelcount,type);
61 	}
ISHistogram(ImageSource * is)62 	ISHistogram(ImageSource *is) : channels(NULL)
63 	{
64 		SetHistogramType(is->samplesperpixel,is->type);
65 	}
ISHistogram()66 	ISHistogram() : channels(NULL), channelcount(0), type(IS_TYPE_NULL)
67 	{
68 	}
~ISHistogram()69 	~ISHistogram()
70 	{
71 		if(channels)
72 			delete[] channels;
73 	}
74 
75 	// Use this to set or change the number of channels and image type.
76 	// The type will be used by the histogram display widget to choose
77 	// which colorants to use when drawing the histogram.
78 	void SetHistogramType(int channelcount,IS_TYPE type=IS_TYPE_RGB)
79 	{
80 		this->channelcount=channelcount;
81 		this->type=type;
82 		if(channels)
83 			delete[] channels;
84 		channels=new ISHistogram_Channel[channelcount];
85 		Clear();
86 	}
87 
88 	// Access the histogram channels through the [] operator.
89 	// The result is returned as a reference so you can follow it with
90 	// another [] to access a specific bucket within a channel.
91 	ISHistogram_Channel &operator[](int chan)
92 	{
93 		if(!channels)
94 			throw "ISHistogram: Must set the histogram type before use!";
95 		if(chan>=channelcount || chan<0)
96 			throw "ISHistogram: Channel out of range";
97 		return(channels[chan]);
98 	}
Clear()99 	void Clear()
100 	{
101 		if(!channels)
102 			throw "ISHistogram: Must set the histogram type before use!";
103 		for(int i=0;i<channelcount;++i)
104 			channels[i].Clear();
105 		samplecount=0;
106 	}
107 	void Record(ISDataType *data,int count=1)
108 	{
109 		if(!channels)
110 			throw "ISHistogram: Must set the histogram type before use!";
111 		for(int x=0;x<count;++x)
112 		{
113 			for(int s=0;s<channelcount;++s)
114 			{
115 				int d=*data++;
116 				d=(d*IS_HISTOGRAM_BUCKETS)/(IS_SAMPLEMAX+1);
117 				channels[s][d]+=1;
118 			}
119 		}
120 		samplecount+=count;
121 	}
GetType()122 	IS_TYPE GetType()
123 	{
124 		return(type);
125 	}
GetChannelCount()126 	int GetChannelCount()
127 	{
128 		return(channelcount);
129 	}
GetSampleCount()130 	int GetSampleCount()
131 	{
132 		return(samplecount);
133 	}
GetMax()134 	int GetMax()
135 	{
136 		int max=0;
137 		for(int c=0;c<channelcount;++c)
138 		{
139 			for(int b=0;b<IS_HISTOGRAM_BUCKETS;++b)
140 			{
141 				int t=channels[c][b];
142 				if(t>max)
143 					max=t;
144 			}
145 		}
146 		return(max);
147 	}
148 	protected:
149 	ISHistogram_Channel *channels;
150 	int channelcount;
151 	int samplecount;
152 	IS_TYPE type;
153 };
154 
155 
156 // Wedge this into a chain of imagesources - it will tally the pixels as they're processed, but
157 // pass them though unmodified.
158 
159 class ImageSource_Histogram : public ImageSource
160 {
161 	public:
162 	ImageSource_Histogram(ImageSource *source,ISHistogram &histogram);
163 	~ImageSource_Histogram();
164 	ISDataType *GetRow(int row);
165 	protected:
166 	ImageSource *source;
167 	ISHistogram &histogram;
168 };
169 
170 #endif
171 
172