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