core/vil/vil_pyramid_image_resource.cxx
Go to the documentation of this file.
00001 // This is core/vil/vil_pyramid_image_resource.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 #include "vil_pyramid_image_resource.h"
00006 //:
00007 // \file
00008 #include <vcl_cassert.h>
00009 #include <vcl_cstring.h>
00010 #include <vcl_vector.h>
00011 #include <vil/vil_property.h>
00012 #include <vil/vil_convert.h>
00013 #include <vil/vil_blocked_image_resource.h>
00014 #include <vil/vil_blocked_image_facade.h>
00015 #include <vil/vil_image_view.h>
00016 #include <vil/vil_new.h>
00017 #include <vil/vil_load.h>
00018 
00019 
00020 vil_pyramid_image_resource::vil_pyramid_image_resource()
00021 {}
00022 
00023 vil_pyramid_image_resource::~vil_pyramid_image_resource()
00024 {}
00025 
00026 bool vil_pyramid_image_resource::get_property(char const* tag, void* /*value*/) const
00027 {
00028   return vcl_strcmp(vil_property_pyramid, tag)==0;
00029 }
00030 
00031 
00032 //: return a decimated block.  The input is a 2x2 2d array of blocks.
00033 //  Assume all the data is valid
00034 static vil_image_view<float>
00035 decimate_block(vcl_vector<vcl_vector<vil_image_view<float> > > const& blocks)
00036 {
00037   vil_image_view<float> blk = blocks[0][0];
00038   unsigned int sbi = blk.ni(), sbj = blk.nj();
00039   vil_image_view<float> dec_block;
00040   dec_block.set_size(sbi, sbj);
00041   for (unsigned int dj = 0; dj<sbj; ++dj)
00042   {
00043     unsigned int r = 0, j0 = 2*dj;
00044     if (2*dj>=sbj)
00045     {
00046       r = 1;
00047       j0 = 2*dj-sbj;
00048     }
00049     for (unsigned int di = 0; di<sbi; ++di)
00050     {
00051       unsigned int c = 0, i0 = 2*di;
00052       if (2*di>=sbi)
00053       {
00054         c = 1;
00055         i0 = 2*di-sbi;
00056       }
00057       vil_image_view<float> blk = blocks[r][c];
00058       float v =
00059         0.25f*(blk(i0, j0)+blk(i0+1,j0)+blk(i0,j0+1)+blk(i0+1,j0+1));
00060       dec_block(di, dj) = v;
00061     }
00062   }
00063   return dec_block;
00064 }
00065 
00066 static
00067 bool convert_multi_plane_to_float(vil_image_view_base_sptr& blk,
00068                                   vcl_vector<vil_image_view<float> >& fblk)
00069 {
00070   if (!blk) return false;
00071   fblk.clear();
00072   vil_pixel_format fmt = blk->pixel_format();
00073   unsigned int ni = blk->ni(), nj = blk->nj();
00074   unsigned int np = blk->nplanes();
00075   if (fmt == VIL_PIXEL_FORMAT_BYTE)
00076   {
00077     vil_image_view<unsigned char> bv = blk;
00078     for (unsigned int p = 0; p<np; ++p){
00079       vil_image_view<float> bvf(ni, nj);
00080       for (unsigned int j = 0; j<nj; ++j)
00081         for (unsigned int i= 0; i<ni; ++i)
00082           bvf(i,j) = bv(i,j,p);
00083       fblk.push_back(bvf);
00084     }
00085     return true;
00086   }
00087   else if (fmt == VIL_PIXEL_FORMAT_UINT_16)
00088   {
00089     vil_image_view<unsigned short> bv = blk;
00090     for (unsigned int p = 0; p<np; ++p){
00091       vil_image_view<float> bvf(ni, nj);
00092       for (unsigned int j = 0; j<nj; ++j)
00093         for (unsigned int i= 0; i<ni; ++i)
00094           bvf(i,j) = bv(i,j,p);
00095       fblk.push_back(bvf);
00096     }
00097     return true;
00098   }
00099   return false;
00100 }
00101 
00102 static
00103 void convert_multi_plane_from_float(vcl_vector<vil_image_view<float> >& fblk,
00104                                     vil_image_view<unsigned char>& blk)
00105 {
00106   unsigned int ni = fblk[0].ni(), nj = fblk[0].nj();
00107   unsigned int np = (unsigned int)(fblk.size());
00108   for (unsigned int p = 0; p<np; ++p)
00109     for (unsigned int j = 0; j<nj; ++j)
00110       for (unsigned int i= 0; i<ni; ++i)
00111         blk(i,j,p) = static_cast<unsigned char>(fblk[p](i,j));
00112 }
00113 
00114 static
00115 void convert_multi_plane_from_float(vcl_vector<vil_image_view<float> >& fblk,
00116                                     vil_image_view<unsigned short>& blk)
00117 {
00118   unsigned int ni = fblk[0].ni(), nj = fblk[0].nj();
00119   unsigned int np = (unsigned int)(fblk.size());
00120   for (unsigned int p = 0; p<np; ++p)
00121     for (unsigned int j = 0; j<nj; ++j)
00122       for (unsigned int i= 0; i<ni; ++i)
00123         blk(i,j,p) = static_cast<unsigned short>(fblk[p](i,j));
00124 }
00125 
00126 bool vil_pyramid_image_resource::
00127 blocked_decimate(vil_blocked_image_resource_sptr const& brsc,
00128                  vil_blocked_image_resource_sptr &  dec_resc)
00129 {
00130   if (!brsc)
00131     return false;
00132   unsigned int nbi = brsc->n_block_i(), nbj = brsc->n_block_j();
00133   if (nbi==0||nbj==0)
00134     return false;
00135   unsigned int np = brsc->nplanes();
00136 
00137   //check for consistent block structure
00138   unsigned int sbi_src = brsc->size_block_i(), sbj_src = brsc->size_block_j();
00139   unsigned int sbi_dec = dec_resc->size_block_i(),
00140     sbj_dec = dec_resc->size_block_j();
00141   if (sbi_src!=sbi_dec||sbj_src!=sbj_dec)
00142     return false;
00143   vil_pixel_format fmt = brsc->pixel_format();
00144 
00145   //Set up the block buffer, a 2xnbi set of blocks needed to support 2x2
00146   //pixel decimation.  The buffer is updated as the next two rows of blocks is
00147   //scanned in from the resource.
00148   //
00149   //|b00 |b01|b02|b03|...|b0,nbi-1|
00150   //|b10 |b11|b12|b13|...|b1,nbi-1|
00151   //
00152   //=======================================================
00153   //
00154   //Decimate the image using a 2x2 block neighborhood
00155   //
00156   //   | buf[0][0]  buf[0][1] |==> [dec_blk]
00157   //   | buf[1][0]  buf[1][1] |
00158   //
00159   // This neighborhood "slides" along the 2xnbi block buffer,
00160   //  stepping two blocks each time.
00161   //=======================================================
00162   switch (np)
00163   {
00164     case 1: //grey scale images
00165     {
00166       vcl_vector<vcl_vector<vil_image_view<float> > > buf(2), nbrhd(2);
00167       for (unsigned int k =0; k<2; ++k)
00168       {
00169         buf[k] = vcl_vector<vil_image_view<float> >(nbi);
00170         nbrhd[k] = vcl_vector<vil_image_view<float> >(2);
00171       }
00172       vil_image_view<float> dec_blk;
00173       for (unsigned int bj=0; bj<nbj; bj+=2)
00174       {
00175         //update the block buffer by stepping down two block rows
00176         for (unsigned int bi = 0; bi<nbi; ++bi)
00177         {
00178           buf[0][bi] = vil_convert_cast(float(),brsc->get_block(bi,bj));
00179           //if (bj+2<=nbj)//make sure there are enough block rows
00180           if (bj+1<nbj)//make sure there are enough block rows
00181             buf[1][bi] = vil_convert_cast(float(),brsc->get_block(bi,bj+1));
00182           else
00183             buf[1][bi]=buf[0][bi];//otherwise just copy the upper block
00184         }
00185         for (unsigned int bi=0; bi<nbi; bi+=2)
00186         {
00187           //construct the 2x2 block neighborhood
00188           for (unsigned int r = 0; r<2; ++r)
00189             for (unsigned int c = 0; c<2; ++c)
00190             {
00191               unsigned int ki = bi+c;
00192               if (ki>=nbi)//make sure there are enough blocks in the row
00193                 ki = nbi-1;
00194               nbrhd[r][c] = buf[r][ki];//otherwise just copy
00195             }
00196           //construct the block
00197           dec_blk = decimate_block(nbrhd);
00198           //convert back to the orignal pixel format
00199           switch (fmt)
00200           {
00201 #define CONVERT_BLOCK_CASE(FORMAT, T) \
00202            case FORMAT: { \
00203             vil_image_view<T> out_blk; \
00204             vil_convert_cast(dec_blk, out_blk); \
00205             if (!dec_resc->put_block(bi/2, bj/2, out_blk )) \
00206               return false;\
00207             break;\
00208            }
00209             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00210 #if VXL_HAS_INT_64
00211             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00212 #endif
00213             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00214             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00215             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00216             CONVERT_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00217 #undef CONVERT_BLOCK_CASE
00218 
00219            default:
00220             assert(!"Unknown vil data type in pyramid image construction");
00221             return false;
00222           };
00223         }
00224       }
00225       return true;
00226     }// end of nplanes = 1 (grey scale)
00227     case 3:
00228     case 4:
00229     {
00230       vcl_vector<vcl_vector<vcl_vector<vil_image_view<float> > > > buf(2);
00231       vcl_vector<vcl_vector<vil_image_view<float> > > nbrhd(2);
00232       for (unsigned int k =0; k<2; ++k)
00233       {
00234         buf[k] = vcl_vector<vcl_vector<vil_image_view<float> > >(nbi);
00235         nbrhd[k] = vcl_vector<vil_image_view<float> >(2);
00236       }
00237 
00238       // The color planes of a block are separated into
00239       // individual float views
00240       for (unsigned int bj=0; bj<nbj; bj+=2)
00241       {
00242         //update the block buffer by stepping down two block rows
00243         for (unsigned int bi = 0; bi<nbi; ++bi)
00244         {
00245           vil_image_view_base_sptr bij = brsc->get_block(bi,bj);
00246           vcl_vector<vil_image_view<float> > fbij;
00247           //convert to float
00248           if (!convert_multi_plane_to_float(bij, fbij)) return false;
00249           buf[0][bi]=fbij;
00250           if (bj+2<=nbj)//make sure there are enough block rows
00251           {
00252             bij = brsc->get_block(bi,bj+1);
00253             //convert to float
00254             if (!convert_multi_plane_to_float(bij, fbij)) return false;
00255             buf[1][bi] = fbij;
00256           }
00257           else
00258             buf[1][bi]=buf[0][bi];//otherwise just copy the upper block
00259         }
00260         for (unsigned int bi=0; bi<nbi; bi+=2)
00261         {
00262           vcl_vector<vil_image_view<float> >dec_fblk(np);
00263           //create decimated blocks for each plane
00264           for (unsigned int p = 0; p<np; ++p){
00265             for (unsigned int r = 0; r<2; ++r)
00266               for (unsigned int c = 0; c<2; ++c)
00267               {
00268                 unsigned int ki = bi+c;
00269                 if (ki>=nbi)
00270                   ki = nbi-1;
00271                 nbrhd[r][c] = buf[r][ki][p];
00272               }
00273             //construct the block
00274             vil_image_view<float> fplane = decimate_block(nbrhd);
00275             dec_fblk[p]=fplane;
00276           }
00277           //convert back to original format only allow 8 bit and 16 bit
00278           //color image formats
00279           if (fmt == VIL_PIXEL_FORMAT_BYTE){
00280             vil_image_view<unsigned char> dblk(sbi_src, sbj_src, np);
00281             convert_multi_plane_from_float(dec_fblk, dblk);
00282             dec_resc->put_block(bi/2, bj/2, dblk);
00283           }
00284           else if (fmt == VIL_PIXEL_FORMAT_UINT_16){
00285             vil_image_view<unsigned short> dblk(sbi_src, sbj_src, np);
00286             convert_multi_plane_from_float(dec_fblk, dblk);
00287             dec_resc->put_block(bi/2, bj/2, dblk);
00288           }
00289           else return false;
00290         }
00291       }
00292       return true;
00293     }// end of nplanes = 3, 4
00294    default:
00295     return false;
00296   }
00297 }
00298 
00299 vil_image_resource_sptr vil_pyramid_image_resource::
00300 decimate(vil_image_resource_sptr const& resc, char const* filename,
00301          char const* format)
00302 {
00303   if (!resc)
00304     return 0;
00305   vil_pixel_format fmt = resc->pixel_format();
00306   switch (fmt)
00307   {
00308     case VIL_PIXEL_FORMAT_BYTE:
00309       break;
00310     case VIL_PIXEL_FORMAT_UINT_16:
00311       break;
00312     case VIL_PIXEL_FORMAT_UINT_32:
00313       break;
00314 #if VXL_HAS_INT_64
00315     case VIL_PIXEL_FORMAT_UINT_64:
00316       break;
00317 #endif
00318     case VIL_PIXEL_FORMAT_FLOAT:
00319       break;
00320     case VIL_PIXEL_FORMAT_DOUBLE:
00321       break;
00322     default:
00323       vcl_cout << "unrecognized pixel format in vil_pyramid_image_resource::decimate()\n";
00324       return 0;
00325   }
00326   //first determine if the resource is blocked, if not create a facade
00327   vil_blocked_image_resource_sptr brsc = blocked_image_resource(resc);
00328   if (brsc&&(brsc->size_block_i()%2!=0||brsc->size_block_j()%2!=0))
00329   {
00330     vcl_cout << "Blocked pyramid images must have even block sizes\n";
00331     return 0;
00332   }
00333   if (!brsc)
00334     brsc = new vil_blocked_image_facade(resc);
00335 
00336   // create the output decimated resource
00337   { //file scope to close resource
00338     unsigned int rni = resc->ni(), rnj = resc->nj();
00339     unsigned int np = resc->nplanes();
00340     //if source image has even dimensions then just divide by 2
00341     unsigned int dni = rni/2, dnj = rnj/2;
00342     //else if the dimension is odd, increase the output size by 1.
00343     dni += rni%2; dnj += rnj%2;
00344     vil_blocked_image_resource_sptr dec_resc =
00345       vil_new_blocked_image_resource(filename, dni, dnj, np,
00346                                      fmt, brsc->size_block_i(),
00347                                      brsc->size_block_j(),
00348                                      format);
00349     //fill the resource with decimated blocks.
00350     if (!blocked_decimate(brsc, dec_resc))
00351       return 0;
00352   } //file scope to close resource
00353   //reopen resource for reading
00354   vil_image_resource_sptr temp = vil_load_image_resource(filename);
00355   return temp;
00356 }