1 // This is core/vil/vil_blocked_image_resource.cxx
2 #include "vil_blocked_image_resource.h"
3 
4 #include <cassert>
5 #ifdef _MSC_VER
6 #  include "vcl_msvc_warnings.h"
7 #endif
8 #include "vil/vil_property.h"
9 #include "vil/vil_image_view.h"
10 #include "vil/vil_crop.h"
11 #include "vil/vil_copy.h"
12 
13 
14 vil_blocked_image_resource::vil_blocked_image_resource() = default;
15 
16 vil_blocked_image_resource::~vil_blocked_image_resource() = default;
17 
18 unsigned int
n_block_i() const19 vil_blocked_image_resource::n_block_i() const
20 {
21   unsigned int sbi = size_block_i();
22   if (sbi == 0)
23     return 0;
24   return (ni() + sbi - 1) / sbi;
25 }
26 
27 unsigned int
n_block_j() const28 vil_blocked_image_resource::n_block_j() const
29 {
30   unsigned int sbj = size_block_j();
31   if (sbj == 0)
32     return 0;
33   return (nj() + sbj - 1) / sbj;
34 }
35 
36 bool
get_blocks(unsigned int start_block_i,unsigned int end_block_i,unsigned int start_block_j,unsigned int end_block_j,std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const37 vil_blocked_image_resource::get_blocks(unsigned int start_block_i,
38                                        unsigned int end_block_i,
39                                        unsigned int start_block_j,
40                                        unsigned int end_block_j,
41                                        std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const
42 {
43   for (unsigned int bi = start_block_i; bi <= end_block_i; ++bi)
44   {
45     std::vector<vil_image_view_base_sptr> jblocks;
46 
47     for (unsigned int bj = start_block_j; bj <= end_block_j; ++bj)
48     {
49       vil_image_view_base_sptr view = this->get_block(bi, bj);
50       if (view)
51         jblocks.push_back(view);
52       else
53         return false;
54     }
55     blocks.push_back(jblocks);
56   }
57   return true;
58 }
59 
60 bool
put_blocks(unsigned int start_block_i,unsigned int end_block_i,unsigned int start_block_j,unsigned int end_block_j,std::vector<std::vector<vil_image_view_base_sptr>> const & blocks)61 vil_blocked_image_resource::put_blocks(unsigned int start_block_i,
62                                        unsigned int end_block_i,
63                                        unsigned int start_block_j,
64                                        unsigned int end_block_j,
65                                        std::vector<std::vector<vil_image_view_base_sptr>> const & blocks)
66 {
67   for (unsigned int bi = start_block_i; bi <= end_block_i; ++bi)
68     for (unsigned int bj = start_block_j; bj <= end_block_j; ++bj)
69       if (!this->put_block(bi, bj, *blocks[bi][bj]))
70         return false;
71   return true;
72 }
73 
74 vil_image_view_base_sptr
glue_blocks_together(const std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const75 vil_blocked_image_resource::glue_blocks_together(
76   const std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const
77 {
78   vil_image_view_base_sptr result;
79   if (blocks.empty())
80     return result;
81 
82   // first calculate the overall size of the output image (all blocks glued together)
83 
84   unsigned int output_width = 0;
85   unsigned int output_height = 0;
86   unsigned int i;
87   for (i = 0; i < blocks.size(); i++)
88   {
89     output_width += blocks[i][0]->ni();
90   }
91   for (i = 0; i < blocks[0].size(); i++)
92   {
93     output_height += blocks[0][i]->nj();
94   }
95 
96   // now paste all the image blocks into their proper location in outImage
97   unsigned int curr_i = 0;
98   unsigned int curr_j = 0;
99   vil_pixel_format fmt = vil_pixel_format_component_format(this->pixel_format());
100   switch (fmt)
101   {
102 #define GLUE_BLOCK_CASE(FORMAT, T)                                                                                     \
103   case FORMAT: {                                                                                                       \
104     vil_image_view<T> * output_image = new vil_image_view<T>(output_width, output_height, 1, nplanes());               \
105     for (unsigned int bi = 0; bi < blocks.size(); bi++)                                                                \
106     {                                                                                                                  \
107       for (unsigned int bj = 0; bj < blocks[bi].size(); bj++)                                                          \
108       {                                                                                                                \
109         vil_copy_to_window(static_cast<vil_image_view<T> &>(*blocks[bi][bj]), *output_image, curr_i, curr_j);          \
110         curr_j += blocks[bi][bj]->nj();                                                                                \
111       }                                                                                                                \
112       curr_j = 0;                                                                                                      \
113       curr_i += blocks[bi][0]->ni();                                                                                   \
114     }                                                                                                                  \
115     result = output_image;                                                                                             \
116     return result;                                                                                                     \
117   }
118     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
119     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
120 #if VXL_HAS_INT_64
121     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
122     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
123 #endif
124     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
125     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
126     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
127     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
128     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
129     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
130     GLUE_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
131 #undef GLUE_BLOCK_CASE
132 
133     default:
134       assert(!"Unknown vil data type in tiff file format");
135       break;
136   }
137   return result;
138 }
139 
140 // Get the offset from the start of the block row for pixel position i
141 bool
block_i_offset(unsigned int block_i,unsigned int i,unsigned int & i_offset) const142 vil_blocked_image_resource::block_i_offset(unsigned int block_i, unsigned int i, unsigned int & i_offset) const
143 {
144   i_offset = 0;
145   unsigned int tw = size_block_i();
146   if (tw == 0)
147     return false;
148   unsigned int bstrt = tw * block_i;
149   if (i < bstrt)
150     return false;
151   i_offset = i - bstrt;
152   return true;
153 }
154 
155 // Get the offset from the start of the block column for pixel position j
156 bool
block_j_offset(unsigned int block_j,unsigned int j,unsigned int & j_offset) const157 vil_blocked_image_resource::block_j_offset(unsigned int block_j, unsigned int j, unsigned int & j_offset) const
158 {
159   j_offset = 0;
160   unsigned int tl = size_block_j();
161   if (tl == 0)
162     return false;
163   unsigned int bstrt = tl * block_j;
164   if (j < bstrt)
165     return false;
166   j_offset = j - bstrt;
167   return true;
168 }
169 
170 // The blocks may overlap the edges of the requested view
171 // Therefore we need to trim them in order to have the
172 // correct pieces to glue together to form the view.
173 bool
trim_border_blocks(unsigned int i0,unsigned int ni,unsigned int j0,unsigned int nj,unsigned int start_block_i,unsigned int start_block_j,std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const174 vil_blocked_image_resource::trim_border_blocks(unsigned int i0,
175                                                unsigned int ni,
176                                                unsigned int j0,
177                                                unsigned int nj,
178                                                unsigned int start_block_i,
179                                                unsigned int start_block_j,
180                                                std::vector<std::vector<vil_image_view_base_sptr>> & blocks) const
181 {
182   // loop through all the boxes and trim the boxes around the border if necessary.
183   for (unsigned int bi = 0; bi < blocks.size(); bi++)
184   {
185     for (unsigned int bj = 0; bj < blocks[bi].size(); bj++)
186     {
187       if (!blocks[bi][bj])
188         continue;
189       auto last_col_index = (unsigned int)(blocks.size() - 1);
190       auto last_row_index = (unsigned int)(blocks[bi].size() - 1);
191       // booleans that tell me whether this box is some sort of border box
192       bool first_block_in_row = bi == 0;
193       bool first_block_in_col = bj == 0;
194       bool last_block_in_row = bi == last_col_index;
195       bool last_block_in_col = bj == last_row_index;
196 
197       // nothing to do if this isn't a border box
198       if (!first_block_in_row && !first_block_in_col && !last_block_in_row && !last_block_in_col)
199         continue;
200 
201       unsigned int bi0 = 0, bin = size_block_i() - 1;
202       unsigned int bj0 = 0, bjn = size_block_j() - 1;
203       if (first_block_in_row)
204         if (!block_i_offset(start_block_i + bi, i0, bi0))
205           return false;
206       if (last_block_in_row)
207         if (!block_i_offset(start_block_i + bi, i0 + ni - 1, bin))
208           return false;
209       if (first_block_in_col)
210         if (!block_j_offset(start_block_j + bj, j0, bj0))
211           return false;
212       if (last_block_in_col)
213         if (!block_j_offset(start_block_j + bj, j0 + nj - 1, bjn))
214           return false;
215 
216       switch (vil_pixel_format_component_format(pixel_format()))
217       {
218 #define TRIM_BORDER_BLOCK_CASE(FORMAT, T)                                                                              \
219   case FORMAT: {                                                                                                       \
220     vil_image_view<T> currBlock = static_cast<vil_image_view<T> &>(*blocks[bi][bj]);                                   \
221     vil_image_view<T> * croppedBlock = new vil_image_view<T>();                                                        \
222     *croppedBlock = vil_crop(currBlock, bi0, bin - bi0 + 1, bj0, bjn - bj0 + 1);                                       \
223     blocks[bi][bj] = croppedBlock;                                                                                     \
224   }                                                                                                                    \
225   break
226         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
227         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
228 #if VXL_HAS_INT_64
229         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
230         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
231 #endif
232         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
233         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
234         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
235         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
236         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
237         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
238         TRIM_BORDER_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
239 #undef TRIM_BORDER_BLOCK_CASE
240 
241         default:
242           assert(!"Unknown vil data type.");
243           return false;
244       }
245     }
246   }
247   return true;
248 }
249 
250 // Get blocks including those that might be in the cache
251 vil_image_view_base_sptr
get_copy_view(unsigned int i0,unsigned int n_i,unsigned int j0,unsigned int n_j) const252 vil_blocked_image_resource::get_copy_view(unsigned int i0, unsigned int n_i, unsigned int j0, unsigned int n_j) const
253 {
254   vil_image_view_base_sptr view = nullptr;
255 
256   unsigned int tw = size_block_i(), tl = size_block_j();
257   if (tw == 0 || tl == 0)
258     return view;
259 
260   // block index ranges
261   unsigned int bi_start = i0 / tw, bi_end = (i0 + n_i - 1) / tw;
262   unsigned int bj_start = j0 / tl, bj_end = (j0 + n_j - 1) / tl;
263   // last block index
264   unsigned int lbi = n_block_i() - 1, lbj = n_block_j() - 1;
265 
266   if (bi_start > lbi || bi_end > lbi || bj_start > lbj || bj_end > lbj)
267     return view;
268 
269   // Get set of blocks covering the view
270   std::vector<std::vector<vil_image_view_base_sptr>> blocks;
271 
272   this->get_blocks(bi_start, bi_end, bj_start, bj_end, blocks);
273   if (blocks.empty())
274     return view;
275   // Trim them if necessary to fit the view
276   if (!trim_border_blocks(i0, n_i, j0, n_j, bi_start, bj_start, blocks))
277     return view;
278   // Assemble them to fill the requested view
279   view = this->glue_blocks_together(blocks);
280 #ifdef DEBUG
281   unsigned int nblocks = (bi_end - bi_start + 1) * (bj_end - bj_start + 1);
282   if (nblocks > 1)
283     std::cout << "Get copy view of " << nblocks << " blocks in " << t.real() << "msecs\n";
284 #endif
285   return view;
286 }
287 
288 vil_blocked_image_resource_sptr
blocked_image_resource(const vil_image_resource_sptr & ir)289 blocked_image_resource(const vil_image_resource_sptr & ir)
290 {
291   if (!ir)
292     return nullptr;
293   unsigned int sbi = 0, sbj = 0;
294   if (ir->get_property(vil_property_size_block_i, &sbi) && ir->get_property(vil_property_size_block_j, &sbj))
295     return (vil_blocked_image_resource *)ir.ptr();
296   else
297     return nullptr;
298 }
299