contrib/brl/bbas/bgui/bgui_image_utils.cxx
Go to the documentation of this file.
00001 #include "bgui_image_utils.h"
00002 
00003 #include <vcl_cstdlib.h> // for rand()
00004 #include <vcl_cmath.h> // for ceil()
00005 
00006 #include <vil/vil_new.h>
00007 #include <vil/vil_property.h>
00008 #include <vil/vil_blocked_image_resource.h>
00009 #include <vil/vil_pyramid_image_resource.h>
00010 #include <vgui/vgui_range_map_params.h>
00011 #include <vul/vul_timer.h>
00012 #include <vnl/vnl_numeric_traits.h>
00013 
00014 bgui_image_utils::bgui_image_utils():
00015   hist_valid_(false), percent_limit_(0.0002), bin_limit_(1000),
00016   n_skip_upper_bins_(0), n_skip_lower_bins_(1), min_blocks_(50),
00017   scan_fraction_(0.005), image_(0)
00018 {
00019 }
00020 
00021 bgui_image_utils::bgui_image_utils(vil_image_resource_sptr const& image):
00022   hist_valid_(false), percent_limit_(0.0002),
00023   bin_limit_(1000), n_skip_upper_bins_(0),
00024   n_skip_lower_bins_(1), min_blocks_(50),
00025   scan_fraction_(0.005), image_(image)
00026 {
00027   if (!image)
00028     return;
00029   unsigned np = image->nplanes();
00030   hist_.resize(np,bsta_histogram<double>(0.0,0.0,1));
00031   data_.resize(np);
00032 }
00033 
00034 void bgui_image_utils::set_image(vil_image_resource_sptr const& image)
00035 {
00036   if (!image)
00037   {
00038     image_ = 0;
00039     return;
00040   }
00041   image_ = image;
00042   unsigned np = image->nplanes();
00043   hist_.resize(np,bsta_histogram<double>(0.0,0.0,1));
00044   data_.resize(np);
00045   hist_valid_ = false;
00046 }
00047 
00048 
00049 bool bgui_image_utils::range(double& min_value, double& max_value,
00050                              unsigned plane)
00051 {
00052   if (!hist_valid_)
00053     if (!this->construct_histogram())
00054       return false;
00055 
00056   min_value = this->compute_lower_bound(plane);
00057   max_value = this->compute_upper_bound(plane);
00058   return min_value < max_value;
00059 }
00060 
00061 // fill the histogram by randomly sampling pixels from the image
00062 bool bgui_image_utils::init_histogram_from_data()
00063 {
00064   hist_valid_ = false;
00065   if (!image_)
00066     return false;
00067 
00068   vil_image_resource_sptr image;
00069   bool pyr = image_->get_property(vil_property_pyramid, 0);
00070   if (pyr)
00071   {
00072     // cast to pyramid resource
00073     vil_pyramid_image_resource_sptr pir =
00074       (vil_pyramid_image_resource*)((vil_image_resource*)image_.ptr());
00075     // highest resolution resource
00076     image = pir->get_resource(0);
00077   }
00078   else
00079     image = image_;
00080   // create a blocked image resource from image
00081   vil_blocked_image_resource_sptr bir = blocked_image_resource(image);
00082   if (!bir)
00083     bir = vil_new_blocked_image_facade(image);
00084 
00085   if (!this->set_data_by_random_blocks(min_blocks_, bir, scan_fraction_))
00086     return false;
00087 
00088   unsigned np = image_->nplanes();
00089 
00090   vil_pixel_format type = image_->pixel_format();
00091 
00092   if (np!=1&&np!=3&&np!=4)
00093   {
00094     vcl_cout << "Format not supported by bgui_image_utils\n";
00095     return false;
00096   }
00097   double min_val=0.0, max_val = 255.0;
00098   switch (type )
00099   {
00100    case  VIL_PIXEL_FORMAT_BYTE:
00101     for (unsigned p = 0; p<np; ++p) {
00102       hist_[p] = bsta_histogram<double>(min_val, max_val, 255);
00103       for (vcl_vector<double>::iterator dit = data_[p].begin();
00104            dit != data_[p].end(); dit++)
00105         hist_[p].upcount(*dit, 1.0);
00106     }
00107     return true;
00108    case  VIL_PIXEL_FORMAT_UINT_16:
00109    {
00110     max_val = 65535.0;
00111 
00112     // determine the min and max range of image values
00113     vcl_vector<double> minr(np, max_val), maxr(np,min_val);
00114     for (unsigned p = 0; p<np; ++p) {
00115       for (vcl_vector<double>::iterator dit = data_[p].begin();
00116            dit != data_[p].end(); dit++)
00117       {
00118         if ((*dit)<minr[p]) minr[p] = *dit;
00119         if ((*dit)>maxr[p]) maxr[p] = *dit;
00120       }
00121       // determine if the number of bins exceess the limit
00122       unsigned short smin = static_cast<unsigned short>(minr[p]);
00123       unsigned short smax = static_cast<unsigned short>(maxr[p]);
00124       unsigned short nbins = static_cast<unsigned short>(smax-smin);
00125       if (nbins>bin_limit_) {
00126         nbins = static_cast<unsigned short>(bin_limit_);
00127         // increase max value to make bin delta an integer
00128         double range = smax-smin;
00129         unsigned short del = static_cast<unsigned short>(vcl_ceil(range/nbins));
00130         smax = static_cast<unsigned short>(smin + nbins*del);
00131       }
00132       hist_[p] = bsta_histogram<double>(static_cast<double>(smin),
00133                                         static_cast<double>(smax), nbins);
00134       for (vcl_vector<double>::iterator dit = data_[p].begin();
00135            dit != data_[p].end(); ++dit)
00136         hist_[p].upcount(*dit, 1.0);
00137     }
00138     return true;
00139    }
00140    default:
00141     vcl_cout << "Format not supported by bgui_image_utils\n";
00142     return false;
00143   }
00144   return false;
00145 }
00146 
00147 // Determine the pixel format of the view and cast to appropriate type
00148 // Upcount the histogram with values from the view.
00149 bool bgui_image_utils::set_data_from_view(vil_image_view_base_sptr const& view,
00150                                           double fraction)
00151 {
00152   if (!view)
00153   {
00154     vcl_cout << "set histogram failed in bgui_image_utils\n";
00155     return false;
00156   }
00157   vil_pixel_format type = view->pixel_format();
00158   unsigned ni = view->ni(), nj = view->nj();
00159   float area_frac = static_cast<float>(ni*nj*fraction);
00160   unsigned np = view->nplanes();
00161   switch (type )
00162   {
00163    case  VIL_PIXEL_FORMAT_BYTE:
00164    {
00165     vil_image_view<unsigned char> v = view;
00166     for (unsigned p = 0; p<np; ++p) {
00167       float cnt = 0.0f;
00168       while (cnt++<area_frac)
00169       {
00170         unsigned i = static_cast<unsigned>((ni-1)*(vcl_rand()/(RAND_MAX+1.0)));
00171         unsigned j = static_cast<unsigned>((nj-1)*(vcl_rand()/(RAND_MAX+1.0)));
00172         double val = static_cast<double>(v(i,j,p));
00173         data_[p].push_back(val);
00174       }
00175     }
00176     return true;
00177    }
00178    case  VIL_PIXEL_FORMAT_UINT_16:
00179    {
00180     vil_image_view<unsigned short> v = view;
00181     for (unsigned p = 0; p<np; ++p) {
00182       float cnt = 0.0f;
00183       while (cnt++<area_frac)
00184       {
00185         unsigned i = static_cast<unsigned>((ni-1)*(vcl_rand()/(RAND_MAX+1.0)));
00186         unsigned j = static_cast<unsigned>((nj-1)*(vcl_rand()/(RAND_MAX+1.0)));
00187         double val = static_cast<double>(v(i,j,p));
00188         data_[p].push_back(val);
00189       }
00190     }
00191     return true;
00192    }
00193    default:
00194      vcl_cout << "Format not supported for histogram construction by bgui_image_utils\n";
00195   }
00196   return false;
00197 }
00198 
00199 bool bgui_image_utils::
00200 set_data_by_random_blocks(const unsigned total_num_blocks,
00201                           vil_blocked_image_resource_sptr const& bir,
00202                           double fraction)
00203 {
00204   unsigned nbi = bir->n_block_i(), nbj = bir->n_block_j();
00205   for (unsigned ib = 0; ib<total_num_blocks; ++ib)
00206   {
00207     unsigned bi = static_cast<unsigned>((nbi-1)*(vcl_rand()/(RAND_MAX+1.0)));
00208     unsigned bj = static_cast<unsigned>((nbj-1)*(vcl_rand()/(RAND_MAX+1.0)));
00209     if (!this->set_data_from_view(bir->get_block(bi, bj), fraction))
00210       return false;
00211   }
00212  return true;
00213 }
00214 
00215 bool bgui_image_utils::construct_histogram()
00216 {
00217   vul_timer t;
00218   if (!this->init_histogram_from_data())
00219   {
00220     vcl_cout << "Unable to construct histogram in bgui_image_utils\n";
00221     return false;
00222   }
00223   unsigned  np = image_->nplanes();
00224   // zero out the bins of the histogram according to the skip parameters
00225   for (unsigned p = 0; p<np; ++p)
00226     for (unsigned s = 0; s<n_skip_lower_bins_; ++s)
00227       hist_[p].set_count(s, 0.0);
00228 
00229   unsigned last_bin = hist_[0].nbins()-1;
00230   for (unsigned p = 0; p<np; ++p)
00231     for (unsigned s =last_bin; s>last_bin-n_skip_upper_bins_; s--)
00232       hist_[p].set_count(s, 0.0);
00233 
00234   vcl_cout << "computed histogram on " << np*data_[0].size()
00235            << " pixels in " << t.real() << " milliseconds\n";
00236   hist_valid_ = true;
00237   return true;
00238 }
00239 
00240 double bgui_image_utils::compute_lower_bound( unsigned plane )
00241 {
00242   if (plane >= hist_.size())
00243     return 0;
00244   return hist_[plane].value_with_area_below(percent_limit_);
00245 }
00246 
00247 double bgui_image_utils::compute_upper_bound( unsigned plane )
00248 {
00249   if (plane >= hist_.size())
00250     return 0;
00251   return hist_[plane].value_with_area_above(percent_limit_);
00252 }
00253 
00254 // generate a graph tableau from the histogram
00255 bgui_graph_tableau_sptr bgui_image_utils::hist_graph()
00256 {
00257   unsigned n_planes = image_->nplanes();
00258 
00259   if (!image_ || n_planes>4)
00260     return 0;
00261 
00262   if (!hist_valid_)
00263     if (!this->construct_histogram())
00264       return 0;
00265 
00266   bgui_graph_tableau_sptr g = bgui_graph_tableau_new(512, 512);
00267 
00268   if (n_planes ==1)
00269   {
00270     unsigned lowbin =hist_[0].low_bin(), highbin = hist_[0].high_bin();
00271     if (lowbin>highbin) return 0; // shouldn't happen
00272     vcl_vector<double> pos = hist_[0].value_array();
00273     vcl_vector<double> counts = hist_[0].count_array();
00274     vcl_vector<double> trim_pos, trim_counts;
00275     // make sure the lowest sample starts at a multiple of 10
00276     double p0 = pos[lowbin];
00277     double pten = 10.0*static_cast<int>(p0/10);
00278     trim_pos.push_back(pten);
00279     trim_counts.push_back(0.0);
00280     for (unsigned b = lowbin; b<=highbin; ++b)
00281     {
00282       trim_pos.push_back(static_cast<unsigned>(pos[b]));
00283       trim_counts.push_back(counts[b]);
00284     }
00285     g->update(trim_pos, trim_counts);
00286     return g;
00287   }
00288 
00289   // In order to create a multiplot for a color histogram
00290   // all the plots have to have the same integral bin locations
00291   // get the max min range of bin values
00292   double minpos = vnl_numeric_traits<double>::maxval, maxpos = 0;
00293   double min_delta = vnl_numeric_traits<double>::maxval;
00294   for (unsigned p = 0; p<n_planes; ++p)
00295   {
00296     unsigned lbin = hist_[p].low_bin(), hbin = hist_[p].high_bin();
00297     vcl_vector<double> pos = hist_[p].value_array();
00298     if (pos[lbin]<minpos) minpos = pos[lbin];
00299     if (pos[hbin]>maxpos) maxpos = pos[hbin];
00300     double delta = hist_[p].delta();
00301     if (delta<min_delta) min_delta = delta;
00302   }
00303 
00304   // start at a multiple of 10
00305   double min_ten = 10.0*static_cast<int>(minpos/10);
00306   double max_ten = 10.0*(static_cast<int>(maxpos/10)+1);
00307   double range = max_ten-min_ten;
00308 
00309   // Insure at least a bin width of 1.0
00310   double delta_i = static_cast<int>(min_delta);
00311   if (delta_i==0) delta_i += 1.0;
00312   unsigned npos = static_cast<unsigned>(range/delta_i);
00313   // set  up the integral positions
00314   vcl_vector<double> dpos(npos);
00315   for (unsigned i = 0; i<npos; ++i)
00316     dpos[i] = i*delta_i;
00317 
00318   vcl_vector<vcl_vector<double> > mpos(n_planes, dpos);
00319 
00320   vcl_vector<vcl_vector<double> > mcounts(n_planes);
00321   for (unsigned p = 0; p<n_planes; ++p)
00322   {
00323     double area = hist_[p].area();
00324     for (unsigned i = 0; i<npos; ++i) {
00325       double v = area*hist_[p].p(dpos[i]);
00326       mcounts[p].push_back(v);
00327     }
00328   }
00329   g->update(mpos, mcounts);
00330 
00331   return g;
00332 }
00333 
00334 bool bgui_image_utils::default_range_map(vgui_range_map_params_sptr& rmp,
00335                                          double gamma, bool invert,
00336                                          bool gl_map, bool cache)
00337 {
00338   if (!image_) return false;
00339   // Allow only grey scale for now
00340   unsigned nc = image_->nplanes();
00341   if (!(nc == 1 || nc == 3 || nc == 4))
00342     return false; // all available formats
00343   // default values
00344   static double minv = 0.0, maxv = 1500.0; // typical for uint_16
00345   if (image_->pixel_format()==VIL_PIXEL_FORMAT_BYTE)
00346     maxv = 255.0;
00347   if (image_->pixel_format()==VIL_PIXEL_FORMAT_FLOAT)
00348     maxv = 1.0;
00349   if (image_->pixel_format()==VIL_PIXEL_FORMAT_DOUBLE)
00350     maxv = 1.0;
00351   switch (nc)
00352   {
00353     case 1:
00354       rmp=new vgui_range_map_params(minv, maxv, float(gamma), invert, gl_map, cache);
00355       return true;
00356     case 3:
00357       rmp = new vgui_range_map_params(minv, maxv, minv, maxv, minv, maxv,
00358                                       float(gamma), float(gamma), float(gamma), invert,
00359                                       gl_map, cache);
00360       return true;
00361     case 4:
00362     {
00363       int band_map = 1; // map RGB-InfraRed -> RGB
00364       rmp = new vgui_range_map_params(minv, maxv, minv, maxv, minv, maxv,
00365                                       minv, maxv, float(gamma), float(gamma), float(gamma), float(gamma),
00366                                       band_map, invert, gl_map, cache);
00367       return true;
00368     }
00369     default:
00370       return false;
00371   }
00372   return true; // never reached
00373 }
00374 
00375 bool bgui_image_utils::range_map_from_hist(float gamma, bool invert,
00376                                            bool gl_map, bool cache,
00377                                            vgui_range_map_params_sptr& rmp)
00378 {
00379   rmp = 0;
00380   if (!image_)
00381     return false;
00382 
00383   unsigned np = image_->nplanes();
00384   vcl_vector<double> minr(np, 0.0), maxr(np, 0.0);
00385 
00386   for (unsigned p = 0; p<np; ++p)
00387     if (!this->range(minr[p], maxr[p], p))
00388       return false;
00389 
00390   if (np == 1)
00391   {
00392     rmp= new vgui_range_map_params(minr[0], maxr[0], gamma, invert,
00393                                    gl_map, cache);
00394     return true;
00395   }
00396   else if (np == 3)
00397   {
00398     rmp = new vgui_range_map_params(minr[0], maxr[0], minr[1], maxr[1],
00399                                     minr[2], maxr[2],
00400                                     gamma, gamma, gamma, invert,
00401                                     gl_map, cache);
00402     return true;
00403   }
00404   else if (np == 4)
00405   {
00406     int bm = vgui_range_map_params::RGB_m;
00407     rmp = new vgui_range_map_params(minr[0], maxr[0], minr[1], maxr[1],
00408                                     minr[2], maxr[2], minr[3], maxr[3],
00409                                     gamma, gamma, gamma, gamma, bm, invert,
00410                                     gl_map, cache);
00411     return true;
00412   }
00413   else
00414     return false;
00415 }