contrib/brl/bbas/bgui/bgui_range_adjuster_tableau.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bgui/bgui_range_adjuster_tableau.cxx
00002 #include "bgui_range_adjuster_tableau.h"
00003 //:
00004 // \file
00005 // \author  J. L. Mundy after Matt Leotta original
00006 
00007 #include <vcl_cassert.h>
00008 #include <vcl_cmath.h> //for fabs()
00009 #include <vcl_limits.h> // for min and max
00010 
00011 #include <vil1/vil1_memory_image_of.h>
00012 #include <vil1/vil1_vil.h>
00013 #include <vil/vil_image_resource.h>
00014 #include <vil/vil_image_view.h>
00015 #include <vil/algo/vil_histogram.h>
00016 
00017 #include <vgui/vgui.h>
00018 #include <vgui/vgui_gl.h>
00019 #include <vgui/vgui_find.h>
00020 #include <vgui/vgui_easy2D_tableau.h>
00021 #include <vgui/vgui_range_map_params.h>
00022 #include <vgui/vgui_projection_inspector.h>
00023 
00024 void bgui_range_adjuster_tableau::draw_box()
00025 {
00026   // Draw a square around the histogram
00027   vcl_vector<float> x_corners, y_corners;
00028   x_corners.push_back(left_offset_);
00029   x_corners.push_back(left_offset_+graph_width_);
00030   x_corners.push_back(left_offset_+graph_width_);
00031   x_corners.push_back(left_offset_);
00032   y_corners.push_back(top_offset_);
00033   y_corners.push_back(top_offset_);
00034   y_corners.push_back(top_offset_+graph_height_);
00035   y_corners.push_back(top_offset_+graph_height_);
00036   vgui_soview2D_polygon* sov =
00037     this->add_polygon(4, &x_corners[0], &y_corners[0]);
00038   sov->set_selectable(false);
00039 }
00040 
00041 void bgui_range_adjuster_tableau::init()
00042 {
00043   hardware_ = false;
00044   this->set_foreground(0.8f, 1.0f, 0.0);
00045   this->set_line_width(5.0f);
00046   this->draw_box();
00047 }
00048 
00049 //========================================================================
00050 // Constructors
00051 
00052 bgui_range_adjuster_tableau::bgui_range_adjuster_tableau(const char* n) :
00053   vgui_easy2D_tableau(n), min_bar_(0), max_bar_(0),
00054   left_offset_(10), top_offset_(10),
00055   graph_width_(256), graph_height_(200), plot_(0), hist_(0,0)
00056 {   this->init(); }
00057 
00058 bgui_range_adjuster_tableau::bgui_range_adjuster_tableau(vgui_tableau_sptr const& t,
00059                                                          const char* n) :
00060   vgui_easy2D_tableau(t, n), min_bar_(0), max_bar_(0),
00061   left_offset_(10), top_offset_(10),
00062   graph_width_(256), graph_height_(200), plot_(0), hist_(0,0)
00063 {   this->init(); }
00064 
00065 bgui_range_adjuster_tableau::bgui_range_adjuster_tableau(vgui_image_tableau_sptr const& t,
00066                                                          const char* n) :
00067   vgui_easy2D_tableau(t,n), min_bar_(0), max_bar_(0),
00068   left_offset_(10), top_offset_(10),
00069   graph_width_(256), graph_height_(200), plot_(0), hist_(0,0)
00070 {   this->init(); }
00071 
00072 //========================================================================
00073 // Destructor.
00074 bgui_range_adjuster_tableau::~bgui_range_adjuster_tableau()
00075 {
00076 }
00077 
00078 //:map the data value of histogrammed intensity to display coordinates
00079 int bgui_range_adjuster_tableau::map_val_to_display(const double val)
00080 {
00081   //compute display scale
00082   double scale = 1.0;
00083   if (vcl_fabs(max_-min_)>0)
00084     scale = graph_width_/(max_-min_);
00085   int display_x = (int)((val-min_)*scale + left_offset_);
00086   return display_x;
00087 }
00088 
00089 //:map the data value of histogrammed intensity to display coordinates
00090 double bgui_range_adjuster_tableau::map_display_to_val(const int display_x)
00091 {
00092   //compute display scale
00093   double scale = 1.0;
00094   if (vcl_fabs(max_-min_)>0)
00095     scale = graph_width_/(max_-min_);
00096   double temp = display_x - left_offset_;
00097   temp/=scale;
00098   return temp + min_;
00099 }
00100 
00101 //:draw stretch bars
00102 void bgui_range_adjuster_tableau::draw_stretch_bars()
00103 {
00104   double temp = hist_.value_with_area_below(0.1);
00105   int min_pos = this->map_val_to_display(temp);
00106   temp = hist_.value_with_area_above(0.1);
00107   int max_pos = this->map_val_to_display(temp);
00108   this->set_foreground(0.0, 1.0, 0);
00109   min_bar_ =
00110     this->add_line(min_pos, top_offset_, min_pos, graph_height_+top_offset_);
00111   max_bar_ =
00112     this->add_line(max_pos, top_offset_, max_pos, graph_height_+top_offset_);
00113   this->set_foreground(1.0, 1.0, 0);
00114   min_bar_->set_selectable(false);
00115   max_bar_->set_selectable(false);
00116 }
00117 
00118 //: Update the histogram from image resource.
00119 //  Currently handle a few useful cases
00120 bool bgui_range_adjuster_tableau::update(vil_image_resource_sptr const& r)
00121 {
00122   data_.clear();
00123   unsigned np = r->nplanes();
00124   vil_pixel_format f = r->pixel_format();
00125   vil_pixel_format type = vil_pixel_format_component_format(f);
00126   switch (type )
00127   {
00128    case VIL_PIXEL_FORMAT_BYTE: {
00129     vil_image_view<vxl_byte> v = r->get_view();
00130     assert(v);
00131     min_ = vcl_numeric_limits<vxl_byte>::min();
00132     max_ = vcl_numeric_limits<vxl_byte>::max();
00133     vil_histogram_byte(v , data_);
00134     break; }
00135    case VIL_PIXEL_FORMAT_SBYTE: {
00136     vil_image_view<vxl_sbyte> v = r->get_view();
00137     assert(v);
00138     min_ = vcl_numeric_limits<vxl_sbyte>::min();
00139     max_ = vcl_numeric_limits<vxl_sbyte>::max();
00140     vil_histogram(v, data_, min_, max_, graph_width_);
00141     hardware_ = false;
00142     break; }
00143    case VIL_PIXEL_FORMAT_UINT_16: {
00144     vil_image_view<vxl_uint_16> v = r->get_view();
00145     assert(v);
00146     min_ = vcl_numeric_limits<vxl_uint_16>::min();
00147     max_ = vcl_numeric_limits<vxl_uint_16>::max();
00148     vil_histogram(v, data_, min_, max_, graph_width_);
00149     hardware_ = np==1;
00150     break; }
00151    case VIL_PIXEL_FORMAT_INT_16: {
00152     vil_image_view<vxl_int_16> v = r->get_view();
00153     assert(v);
00154     min_ = vcl_numeric_limits<vxl_int_16>::min();
00155     max_ = vcl_numeric_limits<vxl_int_16>::max();
00156     vil_histogram(v, data_, min_, max_, graph_width_);
00157     hardware_ = false;
00158     break; }
00159    case VIL_PIXEL_FORMAT_FLOAT: {
00160     vil_image_view<float> v = r->get_view();
00161     assert(v);
00162     min_ = -vcl_numeric_limits<float>::max();
00163     max_ = vcl_numeric_limits<float>::max();
00164     vil_histogram(v, data_, min_, max_, graph_width_);
00165     hardware_ = false;
00166     break; }
00167    case VIL_PIXEL_FORMAT_DOUBLE: {
00168     vil_image_view<double> v = r->get_view();
00169     assert(v);
00170     min_ = -vcl_numeric_limits<double>::max();
00171     max_ = vcl_numeric_limits<double>::max();
00172     vil_histogram(v, data_, min_, max_, graph_width_);
00173     hardware_ = false;
00174     break; }
00175    default:
00176     vcl_cout << "In bgui_range_adjuster_tableau - image type not supported\n";
00177     return false;
00178   }
00179   hist_ = bsta_histogram<double>(min_, max_, data_);
00180   this->draw_histogram();
00181   this->draw_stretch_bars();
00182   return true;
00183 }
00184 
00185 //: update from child
00186 bool bgui_range_adjuster_tableau::update()
00187 {
00188   vgui_image_tableau_sptr itab = this->get_child_image_tableau();
00189   if (!itab)
00190     return false;
00191   vil_image_resource_sptr image = itab->get_image_resource();
00192   return this->update(image);
00193 }
00194 
00195 bool bgui_range_adjuster_tableau::update(const double min, const double max,
00196                                          vcl_vector<double> const& hist)
00197 {
00198   if (!hist.size())
00199     return false;
00200   min_ = min;
00201   max_ = max;
00202   data_ = hist;
00203   hist_ = bsta_histogram<double>(min, max, data_);
00204   this->draw_histogram();
00205   this->draw_stretch_bars();
00206   return true;
00207 }
00208 
00209 bool bgui_range_adjuster_tableau::update(vil1_memory_image_of< vil1_rgb<unsigned char> >& img)
00210 {
00211   vil_image_resource_sptr image = vil1_to_vil_image_resource(img);
00212   return this->update();
00213 }
00214 
00215 void bgui_range_adjuster_tableau::draw_histogram()
00216 {
00217   double max = data_[0];
00218   for (unsigned int i=1; i<data_.size(); ++i)
00219     if (max < data_[i]) max = data_[i];
00220 
00221   // scale and shift the data points
00222   vcl_vector<float> xscaled, yscaled;
00223   for (unsigned int i=0; i<data_.size(); ++i) {
00224     xscaled.push_back(left_offset_ + i);
00225     yscaled.push_back(static_cast<float>(top_offset_ + graph_height_ - data_[i]/max*graph_height_));
00226   }
00227 
00228   if (plot_)
00229   {
00230     // Update the plot points
00231     // This is a bit more efficient that deleting and reconstructing
00232     //   but not as "clean"
00233     for (unsigned int i=0; i<xscaled.size(); ++i) {
00234       plot_->x[i] = xscaled[i];
00235       plot_->y[i] = yscaled[i];
00236     }
00237   }
00238   else
00239   {
00240     plot_ = this->add_linestrip(xscaled.size(), &xscaled[0], &yscaled[0]);
00241     plot_->set_selectable(false);
00242   }
00243   this->post_redraw();
00244 }
00245 
00246 vgui_image_tableau_sptr bgui_range_adjuster_tableau::get_child_image_tableau()
00247 {
00248   vgui_tableau_sptr ch = this->get_child(0);
00249   if (ch)
00250   {
00251     vgui_image_tableau_sptr itab;
00252     itab.vertical_cast(vgui_find_below_by_type_name(ch, vcl_string("vgui_image_tableau")));
00253     return itab;
00254   }
00255   else
00256     return 0;
00257 }
00258 
00259 float bgui_range_adjuster_tableau::screen_to_bar(const float sx)
00260 {
00261   return  sx + left_offset_;
00262 }
00263 
00264 float bgui_range_adjuster_tableau::bar_to_screen(const float bx)
00265 {
00266   return bx - left_offset_;
00267 }
00268 
00269 
00270 void bgui_range_adjuster_tableau::adjust_min_bar(const float x)
00271 {
00272   if (!(min_bar_&&max_bar_))
00273     return;
00274   float xb = screen_to_bar(x);
00275   float xmax = max_bar_->x0;
00276   if (xb<0)
00277   {
00278     min_bar_->x0=0;
00279     min_bar_->x1=0;
00280     return;
00281   }
00282   if (x>xmax)
00283   {
00284     min_bar_->x0=xmax;
00285     min_bar_->x1=xmax;
00286     return;
00287   }
00288   min_bar_->x0 = xb;
00289   min_bar_->x1 = xb;
00290 }
00291 
00292 void bgui_range_adjuster_tableau::adjust_max_bar(const float x)
00293 {
00294   if (!(min_bar_&&max_bar_))
00295     return;
00296   float xb = screen_to_bar(x);
00297   float xl = screen_to_bar(graph_width_);
00298   float xmin = min_bar_->x0;
00299   if (xb>xl)
00300   {
00301     max_bar_->x0=xl;
00302     max_bar_->x1=xl;
00303     return;
00304   }
00305   if (x<xmin)
00306   {
00307     max_bar_->x0=xmin;
00308     max_bar_->x1=xmin;
00309     return;
00310   }
00311   max_bar_->x0 = xb;
00312   max_bar_->x1 = xb;
00313 }
00314 
00315 //========================================================================
00316 //: Handles all events for this tableau.
00317 bool bgui_range_adjuster_tableau::handle(const vgui_event& event)
00318 {
00319   if (event.type == vgui_BUTTON_DOWN)
00320   {
00321     //Adjust the stretch bars
00322     float pointx, pointy;
00323     vgui_projection_inspector p_insp;
00324     p_insp.window_to_image_coordinates(event.wx, event.wy, pointx, pointy);
00325     float min_pos = 0, max_pos = 0, y = 0;
00326     if (event.modifier == vgui_SHIFT)
00327       this->adjust_max_bar(pointx);
00328     else
00329       this->adjust_min_bar(pointx);
00330 
00331     //Use the bar positions to set the range map max min values.
00332     if (min_bar_)
00333       min_bar_->get_centroid(&min_pos, &y);
00334     if (max_bar_)
00335       max_bar_->get_centroid(&max_pos, &y);
00336 
00337     double min_val = map_display_to_val((int)min_pos);
00338     double max_val = map_display_to_val((int)max_pos);
00339     if (min_val>max_val)
00340       return vgui_easy2D_tableau::handle(event);
00341 
00342     vgui_image_tableau_sptr child = this->get_child_image_tableau();
00343     if (!child)
00344       return vgui_easy2D_tableau::handle(event);
00345 
00346     vil_image_resource_sptr r = child->get_image_resource();
00347     if (!r)
00348       return vgui_easy2D_tableau::handle(event);
00349     //If the image can be hardware mapped, it uses glPixelMap* operations
00350     vgui_range_map_params_sptr rmp;
00351     if (r->nplanes()==1)
00352       rmp = new vgui_range_map_params(min_val,max_val, 1.0f,
00353                                       false, hardware_, hardware_);
00354     else if (r->nplanes()==3)
00355       rmp = new vgui_range_map_params(min_val,max_val, min_val, max_val,
00356                                       min_val, max_val,1.0f, 1.0f, 1.0f,
00357                                       false, hardware_, hardware_);
00358     else
00359       return vgui_easy2D_tableau::handle(event);
00360 
00361     child->set_mapping(rmp);
00362   }
00363   return vgui_easy2D_tableau::handle(event);
00364 }
00365 
00366 
00367 void bgui_range_adjuster_tableau::clear()
00368 {
00369   this->remove(plot_);
00370   delete plot_;
00371   plot_ = 0;
00372   this->post_redraw();
00373 }