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