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