Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

equalization.cc

Go to the documentation of this file.
00001 
00025 #include "inanna/equalization.h"
00026 #include "magic/mclass.h"
00027 
00028 impl_dynamic (Equalizer, {Object});
00029 impl_dynamic (HistogramEq, {Equalizer});
00030 impl_dynamic (GaussianEq, {Equalizer});
00031 impl_dynamic (MinmaxEq, {Equalizer});
00032 impl_dynamic (MatrixEqualizer, {Equalizer});
00033 
00034 // Testing XML flagging
00035 int xmlflag = ios::xalloc();
00036 
00037 
00038 
00040 //          |   | o                                      -----               //
00041 //          |   |    ____  |                  ___        |                   //
00042 //          |---| | (     -+-  __   ___  |/\  ___| |/|/| |---   __           //
00043 //          |   | |  \__   |  /  \ (   \ |   (   | | | | |     /  \          //
00044 //          |   | | ____)   \ \__/  ---/ |    \__| | | | |____ \__|          //
00045 //                                  __/                           |          //
00047 
00048 HistogramEq::HistogramEq (int precision, double floor, double ceiling) {
00049     mHistogram.make (precision);
00050     mMin = floor;
00051     mMax = ceiling;
00052     mLowBound = 1E30;
00053     mUpBound = -1E30;
00054 }
00055 
00056 HistogramEq::HistogramEq (const HistogramEq& orig) : Equalizer (orig) {
00057     mHistogram.make (orig.mHistogram.size());
00058     mMin = orig.mMin;
00059     mMax = orig.mMax;
00060     mLowBound = orig.mLowBound;
00061     mUpBound = orig.mUpBound;
00062 }
00063 
00064 int HistogramEq::determineDomain (float x, int precision, float lowBound, float upBound) {
00065 
00066     if (upBound-lowBound == 0)
00067         return 0;
00068 
00069     // Underflow: the value may not be in range if it's from another set
00070     if (x < lowBound)
00071         return 0;
00072 
00073     // Overflow
00074     if (x > upBound)
00075         return precision-1;
00076 
00077     // If in range
00078     return int (((x-lowBound)/(upBound-lowBound))*(precision-1));
00079 }
00080 
00081 void HistogramEq::analyze (const Vector& vec, bool additive)
00082 {
00083     if (additive) {
00084         // It is not possible to directly implement additive analysis with
00085         // histogram equalization. Therefore, we have to store all data
00086         // and perform the actual equalization later, when the equalize()
00087         // method is called for the first time.
00088         
00089         mData.add (new Vector (vec));
00090     } else {
00091         // If the analysis is non-additive, we analyze immediately.
00092         analyze2 (vec);
00093     }
00094 }
00095 
00096 void HistogramEq::finalize ()
00097 {
00098     // Calculate the total number of values in stored data.
00099     int totlen=0;
00100     for (int i=0; i<mData.size(); i++)
00101         totlen += mData[i].size();
00102     
00103     // Copy the accumulated data to an analysis vector
00104     Vector analvec (totlen);
00105     for (int i=0, t=0; i<mData.size(); i++)
00106         for (int j=0; j<mData[i].size(); j++, t++)
00107             analvec[t] = mData[i][j];
00108     
00109     // We do not need the data any longer, so we can destroy it now.
00110     mData.make (0);
00111     
00112     // Analyze the data
00113     analyze2 (analvec);
00114 }
00115 
00116 void HistogramEq::analyze2 (const Vector& vec)
00117 {
00118     mLowBound = min (vec);
00119     mUpBound = max (vec);
00120 
00121     // Initialize histogram
00122     for (int i=0; i<mHistogram.size(); i++)
00123         mHistogram[i] = 0.0;
00124     
00125     // Make histogram
00126     for (int i=0; i<vec.size(); i++)
00127         if (!is_undef (vec[i]))
00128             mHistogram [determineDomain (vec[i], mHistogram.size(), mLowBound, mUpBound)] += 1;
00129     
00130     // Make cumulative histogram
00131     float sum = 0.0;
00132     float lastsum = 0.0;
00133     int lastpos=0;
00134     for (int i=0; i<mHistogram.size(); i++)
00135         if (mHistogram[i]>0.0) {
00136             sum += mHistogram[i];
00137             if (i>0) {
00138                 for (int j=lastpos+1; j<=i; j++)
00139                     mHistogram[j] = lastsum+(j-lastpos)/(i-lastpos+0.0)*(sum-lastsum);
00140                 lastsum=sum;
00141             } else {
00142                 mHistogram[i] = 0.0;
00143                 sum=0.0;
00144             }
00145 
00146             lastpos=i;
00147         }
00148 
00149     // Put actual target values in the histogram
00150     for (int i=0; i<mHistogram.size(); i++)
00151         mHistogram[i] = mHistogram[i] / mHistogram[mHistogram.size()-1];
00152 }
00153 
00154 /*virtual*/ void HistogramEq::equalize (Vector& vec) const {
00155     // If additive analysis has been used, the analysis must be
00156     // finalized.
00157     if (mData.size()>0)
00158         const_cast<HistogramEq&>(*this).finalize ();
00159     ASSERTWITH (mHistogram.size(), "Histogram equalizer has not analyzed any data.");
00160     
00161     // Equalize each value in the vector
00162     for (int i=0; i<vec.size(); i++)
00163         if (!is_undef (vec[i]))
00164             vec[i] = mMin+(mMax-mMin) * mHistogram[determineDomain (vec[i], mHistogram.size(), mLowBound, mUpBound)];
00165         else if (mHandleMissing)
00166             vec[i] = (mMax+mMin)/2;
00167 }
00168 
00169 /*virtual*/ void HistogramEq::unequalize (Vector& vec) const {
00170     // If additive analysis has been used, the analysis must be
00171     // finalized.
00172     if (mData.size()>0)
00173         const_cast<HistogramEq&>(*this).finalize();
00174     ASSERTWITH (mHistogram.size(), "Histogram equalizer has not analyzed any data.");
00175     
00176     // Unequalize each value in the vector
00177     for (int i=0; i<vec.size(); i++) {
00178         if (!is_undef (vec[i])) {
00179             // Find reverse function by iterating through the
00180             // histogram and finding the slot. NOTE: This solution is
00181             // VERY slow! A binary search would be faster.
00182             double searchvalue01 = (vec[i]-mMin)/(mMax-mMin);
00183             bool found=false;
00184             for (int j=0; j<mHistogram.size()-1; j++)
00185                 if ((mHistogram[j]+mHistogram[j+1])/2 > searchvalue01) {
00186                     // Calculate the updated value. Note that we would
00187                     // get more accurate results by interpolating
00188                     // between current and previous slot.
00189                     vec[i] = mLowBound+mHistogram[j]*(mUpBound-mLowBound);
00190                     found = true;
00191                     break;
00192                 }
00193             // If the value was not found from the histogram, it must
00194             // be greater than the upper bound. Since we can't
00195             // calculate beyond the bounds, limit to the upper bound.
00196             if (!found)
00197                 vec[i] = mUpBound;
00198         } else if (mHandleMissing)
00199             vec[i] = mLowBound+mHistogram[mHistogram.size()/2]*(mUpBound-mLowBound);
00200     }
00201 }
00202 
00203 TextOStream& HistogramEq::operator>> (TextOStream& out) const
00204 {
00205     out << "<HistogramEq lowBound=" << mLowBound
00206         << " upBound=" << mUpBound
00207         << " min=" << mMin
00208         << " max=" << mMax
00209         << ">";
00210     out << "</HistogramEq>";
00211 
00212     return out;
00213 }
00214 
00215 
00217 //           ----                         o             -----               //
00218 //          |      ___         ____  ____    ___    _   |                   //
00219 //          | ---  ___| |   | (     (     |  ___| |/ \  |---   __           //
00220 //          |   \ (   | |   |  \__   \__  | (   | |   | |     /  \          //
00221 //          |___/  \__|  \__! ____) ____) |  \__| |   | |____ \__|          //
00222 //                                                               |          //
00224 
00225 GaussianEq::GaussianEq (const GaussianEq& orig)
00226         : Equalizer(orig),
00227           mAverage (orig.mAverage), mStdDev (orig.mStdDev) {    
00228 }
00229 
00230 /*virtual*/ void GaussianEq::analyze (const Vector& vec, bool additive) {
00231     // Calculate average
00232     float sum=0.0;
00233     int actualPatterns=0; // There may be missing values
00234     for (int i=0; i<vec.size(); i++)
00235         if (!is_undef (vec[i])) {
00236             sum += vec[i];
00237             actualPatterns++;
00238         }
00239     mAverage = sum/actualPatterns;
00240 
00241     // Calculate stddev
00242     sum=0.0;
00243     for (int i=0; i<vec.size(); i++)
00244         if (!is_undef (vec[i]))
00245             sum += sqr (vec[i]-mAverage);
00246     mStdDev = sqrt (sum / actualPatterns);
00247 }
00248 
00249 /*virtual*/ void GaussianEq::equalize (Vector& vec) const {
00250     for (int i=0; i<vec.size(); i++)
00251         if (!is_undef (vec[i]))
00252             vec[i] = (vec[i] - mAverage)/mStdDev;
00253         else if (mHandleMissing)
00254             vec[i] = 0.0;
00255 }
00256 
00257 /*virtual*/ void GaussianEq::unequalize (Vector& vec) const {
00258     for (int i=0; i<vec.size(); i++)
00259         if (!is_undef (vec[i]))
00260             vec[i] = (vec[i] - mAverage)/mStdDev;
00261         else if (mHandleMissing)
00262             vec[i] = mAverage;
00263 }
00264 
00265 
00266 
00268 //                 |   | o                       -----                      //
00269 //                 |\ /|     _          ___      |                          //
00270 //                 | V | | |/ \  |/|/|  ___| \ / |---   __                  //
00271 //                 | | | | |   | | | | (   |  X  |     /  \                 //
00272 //                 |   | | |   | | | |  \__| / \ |____ \__|                 //
00273 //                                                        |                 //
00275 
00276 MinmaxEq::MinmaxEq (double trgMin, double trgMax)
00277 {
00278     mTrgMin = trgMin;
00279     mTrgMax = trgMax;
00280     mDataMin = 1E30;
00281     mDataMax = -1E30;
00282 }
00283 
00284 MinmaxEq::MinmaxEq (const MinmaxEq& orig)
00285         : Equalizer(orig),
00286           mTrgMin (orig.mTrgMin), mTrgMax (orig.mTrgMax),
00287           mDataMin (orig.mDataMin), mDataMax (orig.mDataMax)
00288 {
00289 }
00290 
00291 // Deprecated: now implemented in standard libraries
00292 // template<class T> T min (T x, T y) {return (x<y)? x:y;}
00293 // template<class T> T max (T x, T y) {return (x>y)? x:y;}
00294 
00295 void MinmaxEq::analyze (const Vector& vec, bool additive)
00296 {
00297     mDataMin = additive? min<double>(mDataMin,min (vec)) : min (vec);
00298     mDataMax = additive? max<double>(mDataMax,max (vec)) : max (vec);
00299 }
00300 
00301 void MinmaxEq::equalize (Vector& vec) const
00302 {
00303     for (int i=0; i<vec.size(); i++)
00304         if (!is_undef (vec[i]))
00305             vec[i] = mTrgMin + (vec[i] - mDataMin)/(mDataMax-mDataMin)*(mTrgMax-mTrgMin);
00306         else if (mHandleMissing)
00307             vec[i] = (mTrgMax+mTrgMin)/2;
00308 }
00309 
00310 void MinmaxEq::unequalize (Vector& vec) const
00311 {
00312     for (int i=0; i<vec.size(); i++)
00313         if (!is_undef (vec[i]))
00314             vec[i] = (vec[i]-mTrgMin)/(mTrgMax-mTrgMin)*(mDataMax-mDataMin)+mDataMin;
00315         else if (mHandleMissing)
00316             vec[i] = (mDataMax+mDataMin)/2;
00317 }
00318 
00319 TextOStream& MinmaxEq::operator>> (TextOStream& out) const
00320 {
00321     out << getclassname() << " "
00322         << mDataMin << " " << mDataMax << " "
00323         << mTrgMin << " " << mTrgMax << " ";
00324     return out;
00325 }
00326 
00327 TextIStream& MinmaxEq::operator<< (TextIStream& in)
00328 {
00329     in >> mDataMin >> mDataMax >> mTrgMin >> mTrgMax;
00330     return in;
00331 }
00332 
00333 
00335 //    |   |               o     -----                  | o                  //
00336 //    |\ /|  ___   |            |                 ___  |   ___  ___         //
00337 //    | V |  ___| -+- |/\ | \ / |---   __  |   |  ___| | |   / /   ) |/\    //
00338 //    | | | (   |  |  |   |  X  |     /  \ |   | (   | | |  /  |---  |      //
00339 //    |   |  \__|   \ |   | / \ |____ \__|  \__!  \__| | | /__  \__  |      //
00340 //                                       |                                  //
00342 
00343 MatrixEqualizer::MatrixEqualizer (Equalizer* templ)
00344 {
00345     // Put the template as the first item in the equalizer set
00346     if (templ)
00347         mPlaneEqualizers.add (templ);
00348 }
00349 
00350 void MatrixEqualizer::analyze (const Matrix& mat, bool global)
00351 {
00352     // Copy the template
00353     if (!global)
00354         mPlaneEqualizers.resize (mat.cols);
00355     for (int i=0; i<mat.cols; i++) {
00356         if (i>0 && !global)
00357             mPlaneEqualizers.put (mPlaneEqualizers.getp(0)->clone(), i);
00358 
00359         // Copy matrix column to a vector
00360         Vector plane (mat.rows); // Component plane
00361         for (int j=0; j<plane.size(); j++)
00362             plane[j] = mat.get (j,i);
00363 
00364         // Analyze the column vector
00365         mPlaneEqualizers.getp(global? 0:i)->analyze (plane, global);
00366     }
00367 }
00368 
00369 void MatrixEqualizer::bothEqualize (Matrix& mat, bool uneq) const
00370 {
00371     for (int i=0; i<mat.cols; i++) {
00372         Vector plane (mat.rows);
00373 
00374         // Copy the column (component plane) vector from the matrix
00375         for (int j=0; j<plane.size(); j++)
00376             plane[j] = mat.get (j,i);
00377 
00378         // Apply the column equalizer. If there is only one equalizer,
00379         // but the matrix has more columns, we can assume that the
00380         // planes have been analyzed with global data.
00381         const Equalizer* eq = mPlaneEqualizers.getp((mPlaneEqualizers.size() == 1 && mat.cols>1)? 0:i);
00382         if (uneq)
00383             eq->unequalize (plane);
00384         else
00385             eq->equalize (plane);
00386 
00387         // Copy the equalized column (component plane) vector back to the matrix
00388         for (int j=0; j<plane.size(); j++)
00389             mat.get (j,i) = plane[j];
00390     }
00391 }
00392 
00393 void MatrixEqualizer::equalize (Matrix& mat) const
00394 {
00395     bothEqualize (mat, false);
00396 }
00397 
00398 void MatrixEqualizer::unequalize (Matrix& mat) const
00399 {
00400     bothEqualize (mat, true);
00401 }
00402 
00403 TextOStream& MatrixEqualizer::operator>> (TextOStream& out) const
00404 {
00405     if (false /* out.iword(xmlflag */) {
00406         out << "<planeEqualizers size="
00407             << mPlaneEqualizers.size() << ">\n";
00408         for (int i=0; i<mPlaneEqualizers.size(); i++) {
00409             out << "\t<equalizer id=" << i
00410                 << " class='" << mPlaneEqualizers[i].getclassname() << "'>"
00411                 << mPlaneEqualizers[i]
00412                 << "</equalizer>\n";
00413         }
00414         out << "</planeEqualizers>\n";
00415     } else {
00416         out << getclassname() << " " << mPlaneEqualizers.size() << " ";
00417         for (int i=0; i<mPlaneEqualizers.size(); i++)
00418             out << mPlaneEqualizers[i];
00419     }
00420     return out;
00421 }
00422 
00423 Equalizer* readEqualizer (TextIStream& in)
00424 {
00425     // Read class name of the equalizer
00426     String classname;
00427     in >> classname;
00428 
00429     // Create the equalizer dynamically by class name
00430     if (Equalizer* obj = dynamic_cast<Equalizer*> (dyncreate (classname))) {
00431         (*obj) << in;
00432         return obj;
00433     } else
00434         throw invalid_format (i18n("Unexpected object class identifier '%1', class Equalizer expected.").arg(classname));
00435 }
00436 
00437 TextIStream& MatrixEqualizer::operator<< (TextIStream& in)
00438 {
00439     // Read size
00440     int size;
00441     in >> size;
00442     mPlaneEqualizers.make(size);
00443 
00444     for (int i=0; i<size; i++)
00445         mPlaneEqualizers.put (readEqualizer(in), i);
00446     
00447     return in;
00448 }
00449 
00450 
00451 void MatrixEqualizer::handleMissing (bool enable)
00452 {
00453     mHandleMissing = enable;
00454     for (int i=0; i < mPlaneEqualizers.size(); i++)
00455         mPlaneEqualizers[i].handleMissing (enable);
00456 }
00457 

Generated on Thu Feb 10 20:06:44 2005 for Inanna by doxygen1.2.18