00001 #include "bgui_image_utils.h"
00002
00003 #include <vcl_cstdlib.h>
00004 #include <vcl_cmath.h>
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
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
00084 vil_pyramid_image_resource_sptr pir =
00085 (vil_pyramid_image_resource*)((vil_image_resource*)image_.ptr());
00086
00087 image = pir->get_resource(0);
00088 }
00089 else
00090 image = image_;
00091
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
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
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
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
00163
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
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
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
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;
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
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
00333
00334
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
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
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
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
00383 unsigned nc = image_->nplanes();
00384 if (!(nc == 1 || nc == 3 || nc == 4))
00385 return false;
00386
00387 static double minv = 0.0, maxv = 1500.0;
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;
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;
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 }