1 /*
2 * stitcher.cpp - stitcher base
3 *
4 * Copyright (c) 2017 Intel Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Wind Yuan <feng.yuan@intel.com>
19 * Author: Yinhang Liu <yinhangx.liu@intel.com>
20 */
21
22 #include "stitcher.h"
23 #include "xcam_utils.h"
24
25 // angle to position, output range [-180, 180]
26 #define OUT_WINDOWS_START 0.0f
27
28 #define constraint_margin (2 * _alignment_x)
29
30 #define XCAM_GL_RESTART_FIXED_INDEX 0xFFFF
31
32 namespace XCam {
33
34 static inline bool
merge_neighbor_area(const Stitcher::CopyArea & current,const Stitcher::CopyArea & next,Stitcher::CopyArea & merged)35 merge_neighbor_area (
36 const Stitcher::CopyArea ¤t,
37 const Stitcher::CopyArea &next,
38 Stitcher::CopyArea &merged)
39 {
40 if (current.in_idx == next.in_idx &&
41 current.in_area.pos_x + current.in_area.width == next.in_area.pos_x &&
42 current.out_area.pos_x + current.out_area.width == next.out_area.pos_x)
43 {
44 merged = current;
45 merged.in_area.pos_x = current.in_area.pos_x;
46 merged.in_area.width = current.in_area.width + next.in_area.width;
47 merged.out_area.pos_x = current.out_area.pos_x;
48 merged.out_area.width = current.out_area.width + next.out_area.width;
49 return true;
50 }
51 return false;
52 }
53
54 static inline bool
split_area_by_out(const Stitcher::CopyArea & area,const uint32_t round_width,Stitcher::CopyArea & split_a,Stitcher::CopyArea & split_b)55 split_area_by_out (
56 const Stitcher::CopyArea &area, const uint32_t round_width,
57 Stitcher::CopyArea &split_a, Stitcher::CopyArea &split_b)
58 {
59 XCAM_ASSERT (area.out_area.pos_x >= 0 && area.out_area.pos_x < (int32_t)round_width);
60 XCAM_ASSERT (area.out_area.width > 0 && area.out_area.width < (int32_t)round_width);
61 if (area.out_area.pos_x + area.out_area.width > (int32_t)round_width) {
62 split_a = area;
63 split_a.out_area.width = round_width - area.out_area.pos_x;
64 split_a.in_area.width = split_a.out_area.width;
65
66 split_b = area;
67 split_b.in_area.pos_x = area.in_area.pos_x + split_a.in_area.width;
68 split_b.in_area.width = area.in_area.width - split_a.in_area.width;
69 split_b.out_area.pos_x = 0;
70 split_b.out_area.width = split_b.in_area.width;
71 XCAM_ASSERT (split_b.out_area.width == area.out_area.pos_x + area.out_area.width - (int32_t)round_width);
72 return true;
73
74 }
75 XCAM_ASSERT (area.out_area.width == area.in_area.width);
76 return false;
77 }
78
Stitcher(uint32_t align_x,uint32_t align_y)79 Stitcher::Stitcher (uint32_t align_x, uint32_t align_y)
80 : _is_crop_set (false)
81 , _alignment_x (align_x)
82 , _alignment_y (align_y)
83 , _output_width (0)
84 , _output_height (0)
85 , _out_start_angle (OUT_WINDOWS_START)
86 , _camera_num (0)
87 , _is_round_view_set (false)
88 , _is_overlap_set (false)
89 , _is_center_marked (false)
90 {
91 XCAM_ASSERT (align_x >= 1);
92 XCAM_ASSERT (align_y >= 1);
93 }
94
~Stitcher()95 Stitcher::~Stitcher ()
96 {
97 }
98
99 bool
set_bowl_config(const BowlDataConfig & config)100 Stitcher::set_bowl_config (const BowlDataConfig &config)
101 {
102 _bowl_config = config;
103 return true;
104 }
105
106 bool
set_camera_num(uint32_t num)107 Stitcher::set_camera_num (uint32_t num)
108 {
109 XCAM_FAIL_RETURN (
110 ERROR, num <= XCAM_STITCH_MAX_CAMERAS, false,
111 "stitcher: set camera count failed, num(%d) is larger than max value(%d)",
112 num, XCAM_STITCH_MAX_CAMERAS);
113 _camera_num = num;
114 return true;
115 }
116
117 bool
set_camera_info(uint32_t index,const CameraInfo & info)118 Stitcher::set_camera_info (uint32_t index, const CameraInfo &info)
119 {
120 XCAM_FAIL_RETURN (
121 ERROR, index < _camera_num, false,
122 "stitcher: set camera info failed, index(%d) exceed max camera num(%d)",
123 index, _camera_num);
124 _camera_info[index] = info;
125 return true;
126 }
127
128 bool
set_crop_info(uint32_t index,const ImageCropInfo & info)129 Stitcher::set_crop_info (uint32_t index, const ImageCropInfo &info)
130 {
131 XCAM_FAIL_RETURN (
132 ERROR, index < _camera_num, false,
133 "stitcher: set camera info failed, index(%d) exceed max camera num(%d)",
134 index, _camera_num);
135 _crop_info[index] = info;
136 _is_crop_set = true;
137 return true;
138 }
139
140 bool
get_crop_info(uint32_t index,ImageCropInfo & info) const141 Stitcher::get_crop_info (uint32_t index, ImageCropInfo &info) const
142 {
143 XCAM_FAIL_RETURN (
144 ERROR, index < _camera_num, false,
145 "stitcher: get crop info failed, index(%d) exceed camera num(%d)",
146 index, _camera_num);
147 info = _crop_info[index];
148 return true;
149 }
150
151 #if 0
152 bool
153 Stitcher::set_overlap_info (uint32_t index, const ImageOverlapInfo &info)
154 {
155 XCAM_FAIL_RETURN (
156 ERROR, index < _camera_num, false,
157 "stitcher: set overlap info failed, index(%d) exceed max camera num(%d)",
158 index, _camera_num);
159 _overlap_info[index] = info;
160 _is_overlap_set = true;
161 return true;
162 }
163
164 bool
165 Stitcher::get_overlap_info (uint32_t index, ImageOverlapInfo &info) const
166 {
167 XCAM_FAIL_RETURN (
168 ERROR, index < _camera_num, false,
169 "stitcher: get overlap info failed, index(%d) exceed camera num(%d)",
170 index, _camera_num);
171 info = _overlap_info[index];
172 return true;
173 }
174 #endif
175
176 bool
get_camera_info(uint32_t index,CameraInfo & info) const177 Stitcher::get_camera_info (uint32_t index, CameraInfo &info) const
178 {
179 XCAM_FAIL_RETURN (
180 ERROR, index < XCAM_STITCH_MAX_CAMERAS, false,
181 "stitcher: get camera info failed, index(%d) exceed max camera value(%d)",
182 index, XCAM_STITCH_MAX_CAMERAS);
183 info = _camera_info[index];
184 return true;
185 }
186
187 XCamReturn
estimate_round_slices()188 Stitcher::estimate_round_slices ()
189 {
190 if (_is_round_view_set)
191 return XCAM_RETURN_NO_ERROR;
192
193 XCAM_FAIL_RETURN (
194 ERROR, _camera_num && _camera_num < XCAM_STITCH_MAX_CAMERAS, XCAM_RETURN_ERROR_PARAM,
195 "stitcher: camera num was not set, or camera num(%d) exceed max camera value(%d)",
196 _camera_num, XCAM_STITCH_MAX_CAMERAS);
197
198 for (uint32_t i = 0; i < _camera_num; ++i) {
199 CameraInfo &cam_info = _camera_info[i];
200 RoundViewSlice &view_slice = _round_view_slices[i];
201
202 view_slice.width = cam_info.angle_range / 360.0f * (float)_output_width;
203 view_slice.width = XCAM_ALIGN_UP (view_slice.width, _alignment_x);
204 view_slice.height = _output_height;
205 view_slice.hori_angle_range = view_slice.width * 360.0f / (float)_output_width;
206
207 uint32_t aligned_start = format_angle (cam_info.round_angle_start) / 360.0f * (float)_output_width;
208 aligned_start = XCAM_ALIGN_AROUND (aligned_start, _alignment_x);
209 if (_output_width <= constraint_margin + aligned_start || aligned_start <= constraint_margin)
210 aligned_start = 0;
211 view_slice.hori_angle_start = format_angle((float)aligned_start / (float)_output_width * 360.0f);
212 if (XCAM_DOUBLE_EQUAL_AROUND (view_slice.hori_angle_start, 0.0001f))
213 view_slice.hori_angle_start = 0.0f;
214
215 cam_info.round_angle_start = view_slice.hori_angle_start;
216 cam_info.angle_range = view_slice.hori_angle_range;
217 }
218
219 _is_round_view_set = true;
220 return XCAM_RETURN_NO_ERROR;
221 }
222
223 XCamReturn
estimate_coarse_crops()224 Stitcher::estimate_coarse_crops ()
225 {
226 if (_is_crop_set)
227 return XCAM_RETURN_NO_ERROR;
228
229 XCAM_FAIL_RETURN (
230 ERROR, _camera_num > 0 && _is_round_view_set, XCAM_RETURN_ERROR_ORDER,
231 "stitcher mark_centers failed, need set camera info and round_slices first");
232
233 for (uint32_t i = 0; i < _camera_num; ++i) {
234 _crop_info[i].left = 0;
235 _crop_info[i].right = 0;
236 _crop_info[i].top = 0;
237 _crop_info[i].bottom = 0;
238 }
239 _is_crop_set = true;
240 return XCAM_RETURN_NO_ERROR;
241 }
242
243 // after crop done
244 XCamReturn
mark_centers()245 Stitcher::mark_centers ()
246 {
247 if (_is_center_marked)
248 return XCAM_RETURN_NO_ERROR;
249
250 XCAM_FAIL_RETURN (
251 ERROR, _camera_num > 0 && _is_round_view_set, XCAM_RETURN_ERROR_ORDER,
252 "stitcher mark_centers failed, need set camera info and round_view slices first");
253
254 for (uint32_t i = 0; i < _camera_num; ++i) {
255 const RoundViewSlice &slice = _round_view_slices[i];
256
257 //calcuate final output postion
258 float center_angle = i * 360.0f / _camera_num;
259 uint32_t out_pos = format_angle (center_angle - _out_start_angle) / 360.0f * _output_width;
260 XCAM_ASSERT (out_pos < _output_width);
261 if (_output_width <= constraint_margin + out_pos || out_pos <= constraint_margin)
262 out_pos = 0;
263
264 // get slice center angle
265 center_angle = XCAM_ALIGN_AROUND (out_pos, _alignment_x) / (float)_output_width * 360.0f - _out_start_angle;
266 center_angle = format_angle (center_angle);
267
268 float center_in_slice = center_angle - slice.hori_angle_start;
269 center_in_slice = format_angle (center_in_slice);
270 XCAM_FAIL_RETURN (
271 ERROR, center_in_slice < slice.hori_angle_range,
272 XCAM_RETURN_ERROR_PARAM,
273 "stitcher mark center failed, slice:%d calculated center-angle:%.2f is out of slice angle(start:%.2f, range:%.2f)",
274 center_angle, slice.hori_angle_start, slice.hori_angle_range);
275
276 uint32_t slice_pos = (uint32_t)(center_in_slice / slice.hori_angle_range * slice.width);
277 slice_pos = XCAM_ALIGN_AROUND (slice_pos, _alignment_x);
278 XCAM_ASSERT (slice_pos > _crop_info[i].left && slice_pos < slice.width - _crop_info[i].right);
279
280 _center_marks[i].slice_center_x = slice_pos;
281 _center_marks[i].out_center_x = out_pos;
282 }
283 _is_center_marked = true;
284
285 return XCAM_RETURN_NO_ERROR;
286 }
287
288 XCamReturn
estimate_overlap()289 Stitcher::estimate_overlap ()
290 {
291 if (_is_overlap_set)
292 return XCAM_RETURN_NO_ERROR;
293
294 XCAM_FAIL_RETURN (
295 ERROR, _is_round_view_set && _is_crop_set && _is_center_marked, XCAM_RETURN_ERROR_ORDER,
296 "stitcher estimate_coarse_seam failed, need set round_view slices, crop info and mark centers first");
297
298 for (uint32_t idx = 0; idx < _camera_num; ++idx) {
299 uint32_t next_idx = (idx + 1) % _camera_num;
300 const RoundViewSlice &left = _round_view_slices[idx];
301 const RoundViewSlice &right = _round_view_slices[next_idx];
302 const CenterMark &left_center = _center_marks[idx];
303 const CenterMark &right_center = _center_marks[next_idx];
304 const ImageCropInfo &left_img_crop = _crop_info[idx];
305 const ImageCropInfo &right_img_crop = _crop_info[next_idx];
306
307 #if 0
308 XCAM_FAIL_RETURN (
309 ERROR,
310 (format_angle (right.hori_angle_start - left.hori_angle_start) < left.hori_angle_range)
311 XCAM_RETURN_ERROR_UNKNOWN,
312 "stitcher estimate_coarse_seam failed and there is no seam between slice %d and slice %d", idx, next_idx);
313
314 float seam_angle_start = right.hori_angle_start;
315 float seam_angle_range =
316 format_angle (left.hori_angle_start + left.hori_angle_range - right.hori_angle_start);
317
318 XCAM_FAIL_RETURN (
319 ERROR, seam_angle_range < right.hori_angle_range, XCAM_RETURN_ERROR_UNKNOWN,
320 "stitcher estimate_coarse_seam failed and left slice(%d)over covered right slice(%d)", idx, next_idx);
321
322 XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (left.hori_angle_range, 0.0f));
323 XCAM_ASSERT (!XCAM_DOUBLE_EQUAL_AROUND (right.hori_angle_range, 0.0f));
324 #endif
325 uint32_t out_right_center_x = right_center.out_center_x;
326 if (out_right_center_x == 0)
327 out_right_center_x = _output_width;
328
329 Rect valid_left_img, valid_right_img;
330 valid_left_img.pos_x = left_center.slice_center_x;
331 valid_left_img.width = left.width - left_img_crop.right - valid_left_img.pos_x;
332 valid_left_img.pos_y = left_img_crop.top;
333 valid_left_img.height = left.height - left_img_crop.top - left_img_crop.bottom;
334
335 valid_right_img.width = right_center.slice_center_x - right_img_crop.left;
336 valid_right_img.pos_x = right_center.slice_center_x - valid_right_img.width;
337 valid_right_img.pos_y = right_img_crop.top;
338 valid_right_img.height = right.height - right_img_crop.top - right_img_crop.bottom;
339
340 uint32_t merge_width = out_right_center_x - left_center.out_center_x;
341 XCAM_FAIL_RETURN (
342 ERROR,
343 valid_left_img.width + valid_right_img.width > (int32_t)merge_width,
344 XCAM_RETURN_ERROR_UNKNOWN,
345 "stitcher estimate_overlap failed and there is no overlap area between slice %d and slice %d", idx, next_idx);
346
347 uint32_t overlap_width = valid_left_img.width + valid_right_img.width - merge_width;
348
349 Rect left_img_overlap, right_img_overlap;
350 left_img_overlap.pos_x = valid_left_img.pos_x + valid_left_img.width - overlap_width;
351 left_img_overlap.width = overlap_width;
352 left_img_overlap.pos_y = valid_left_img.pos_y;
353 left_img_overlap.height = valid_left_img.height;
354 XCAM_ASSERT (left_img_overlap.pos_x >= (int32_t)left_center.slice_center_x && left_img_overlap.pos_x < (int32_t)left.width);
355
356 right_img_overlap.pos_x = valid_right_img.pos_x;
357 right_img_overlap.width = overlap_width;
358 right_img_overlap.pos_y = valid_right_img.pos_y;
359 right_img_overlap.height = valid_right_img.height;
360 XCAM_ASSERT (right_img_overlap.pos_x >= (int32_t)right_img_crop.left && right_img_overlap.pos_x < (int32_t)right_center.slice_center_x);
361
362 Rect out_overlap;
363 out_overlap.pos_x = left_center.out_center_x + valid_left_img.width - overlap_width;
364 out_overlap.width = overlap_width;
365 // out_overlap.pos_y/height not useful by now
366 out_overlap.pos_y = valid_left_img.pos_y;
367 out_overlap.height = valid_left_img.height;
368
369 #if 0
370 left_img_seam.pos_x =
371 left.width * format_angle (seam_angle_start - left.hori_angle_start) / left.hori_angle_range;
372 left_img_seam.pos_y = _crop_info[idx].top;
373 left_img_seam.width = left.width * seam_angle_range / left.hori_angle_range;
374 left_img_seam.height = left.height - _crop_info[idx].top - _crop_info[idx].bottom;
375
376 //consider crop
377 XCAM_ASSERT (left_img_seam.pos_x < left.width - _crop_info[idx].right);
378 if (left_img_seam.pos_x + left_img_seam.width > left.width - _crop_info[idx].right)
379 left_img_seam.width = left.width - _crop_info[idx].right;
380
381 right_img_seam.pos_x = 0;
382 right_img_seam.pos_y = _crop_info[next_idx].top;
383 right_img_seam.width = right.width * (seam_angle_range / right.hori_angle_range);
384 right_img_seam.height = right.height - _crop_info[next_idx].top - _crop_info[next_idx].bottom;
385
386 //consider crop
387 XCAM_ASSERT (right_img_seam.pos_x + right_img_seam.width > _crop_info[next_idx].left);
388 if (_crop_info[next_idx].left) {
389 right_img_seam.pos_x = _crop_info[next_idx].left;
390 right_img_seam.width -= _crop_info[next_idx].left;
391 left_img_seam.pos_x += _crop_info[next_idx].left;
392 left_img_seam.width -= _crop_info[next_idx].left;
393 }
394
395 XCAM_ASSERT (abs (left_img_seam.width - right_img_seam.width) < 16);
396 left_img_seam.pos_x = XCAM_ALIGN_DOWN (left_img_seam.pos_x, _alignment_x);
397 right_img_seam.pos_x = XCAM_ALIGN_DOWN (right_img_seam.pos_x, _alignment_x);
398
399 //find max seam width
400 uint32_t seam_width, seam_height;
401 seam_width = XCAM_MAX (left_img_seam.width, right_img_seam.width);
402 if (left_img_seam.pos_x + seam_width > left.width)
403 seam_width = left.width - left_img_seam.pos_x;
404 if (right_img_seam.pos_x + seam_width > right.width)
405 seam_width = right.width - right_img_seam.pos_x;
406
407 XCAM_FAIL_RETURN (
408 ERROR, seam_width >= XCAM_STITCH_MIN_SEAM_WIDTH, XCAM_RETURN_ERROR_UNKNOWN,
409 "stitcher estimate_coarse_seam failed, the seam(w:%d) is very narrow between(slice %d and %d)",
410 seam_width, idx, next_idx);
411 left_img_seam.width = right_img_seam.width = XCAM_ALIGN_DOWN (seam_width, _alignment_x);
412
413 // min height
414 uint32_t top = XCAM_MAX (left_img_seam.pos_y, right_img_seam.pos_y);
415 uint32_t bottom0 = left_img_seam.pos_y + left_img_seam.height;
416 uint32_t bottom1 = right_img_seam.pos_y + right_img_seam.height;
417 uint32_t bottom = XCAM_MIN (bottom0, bottom1);
418 top = XCAM_ALIGN_UP (top, _alignment_y);
419 left_img_seam.pos_y = right_img_seam.pos_y = top;
420 left_img_seam.height = right_img_seam.height = XCAM_ALIGN_DOWN (bottom - top, _alignment_y);
421 #endif
422 // set overlap info
423 _overlap_info[idx].left = left_img_overlap;
424 _overlap_info[idx].right = right_img_overlap;
425 _overlap_info[idx].out_area = out_overlap;
426 }
427
428 _is_overlap_set = true;
429
430 return XCAM_RETURN_NO_ERROR;
431 }
432
433 XCamReturn
update_copy_areas()434 Stitcher::update_copy_areas ()
435 {
436 XCAM_FAIL_RETURN (
437 ERROR, _camera_num > 1 && _is_round_view_set && _is_crop_set && _is_overlap_set, XCAM_RETURN_ERROR_ORDER,
438 "stitcher update_copy_areas failed, check orders, need"
439 "camera_info, round_view slices, crop_info and overlap_info set first.");
440
441 CopyAreaArray tmp_areas;
442 uint32_t i = 0;
443 uint32_t next_i = 0;
444 for (i = 0; i < _camera_num; ++i) {
445 next_i = (i + 1 ) % _camera_num;
446 const CenterMark &mark_left = _center_marks[i];
447 const CenterMark &mark_right = _center_marks[next_i];
448 const ImageOverlapInfo &overlap = _overlap_info[i];
449
450 CopyArea split_a, split_b;
451
452 CopyArea left;
453 left.in_idx = i;
454 left.in_area.pos_x = mark_left.slice_center_x;
455 left.in_area.width = overlap.left.pos_x - left.in_area.pos_x;
456 XCAM_ASSERT (left.in_area.width > 0);
457 left.in_area.pos_y = _crop_info[i].top;
458 left.in_area.height = _round_view_slices[i].height - _crop_info[i].top - _crop_info[i].bottom;
459 XCAM_ASSERT (left.in_area.height > 0);
460
461 left.out_area.pos_x = mark_left.out_center_x;
462 left.out_area.width = left.in_area.width;
463 left.out_area.pos_y = 0;
464 left.out_area.height = left.in_area.height;
465
466 if (split_area_by_out (left, _output_width, split_a, split_b)) {
467 tmp_areas.push_back (split_a);
468 tmp_areas.push_back (split_b);
469 } else {
470 tmp_areas.push_back (left);
471 }
472
473 CopyArea right;
474 right.in_idx = next_i;
475 right.in_area.pos_x = _overlap_info[i].right.pos_x + _overlap_info[i].right.width;
476 right.in_area.width = (int32_t)mark_right.slice_center_x - right.in_area.pos_x;
477 XCAM_ASSERT (right.in_area.width > 0);
478 right.in_area.pos_y = _crop_info[next_i].top;
479 right.in_area.height = _round_view_slices[next_i].height - _crop_info[next_i].top - _crop_info[next_i].bottom;
480 XCAM_ASSERT (right.in_area.height > 0);
481
482 uint32_t out_right_center_x = mark_right.out_center_x;
483 if (out_right_center_x == 0)
484 out_right_center_x = _output_width;
485 right.out_area.width = right.in_area.width;
486 right.out_area.pos_x = out_right_center_x - right.out_area.width;
487 right.out_area.pos_y = 0;
488 right.out_area.height = right.in_area.height;
489
490 if (split_area_by_out (right, _output_width, split_a, split_b)) {
491 tmp_areas.push_back (split_a);
492 tmp_areas.push_back (split_b);
493 } else {
494 tmp_areas.push_back (right);
495 }
496 }
497 XCAM_ASSERT (tmp_areas.size () > _camera_num && _camera_num >= 2);
498
499 CopyArea merged;
500 int32_t start = 0;
501 int32_t end = tmp_areas.size () - 1;
502 if (tmp_areas.size () > 2) {
503 const CopyArea &first = tmp_areas[0];
504 const CopyArea &last = tmp_areas[end];
505 // merge first and last
506 if (merge_neighbor_area (last, first, merged)) {
507 _copy_areas.push_back (merged);
508 ++start;
509 --end;
510 }
511 }
512
513 // merge areas
514 for (i = (uint32_t)start; (int32_t)i <= end; ) {
515 const CopyArea ¤t = tmp_areas[i];
516 if (i == (uint32_t)end) {
517 _copy_areas.push_back (current);
518 break;
519 }
520
521 const CopyArea &next = tmp_areas[i + 1];
522 if (merge_neighbor_area (current, next, merged)) {
523 _copy_areas.push_back (merged);
524 i += 2;
525 } else {
526 _copy_areas.push_back (current);
527 i += 1;
528 }
529 }
530
531 XCAM_ASSERT (_copy_areas.size() >= _camera_num);
532
533 return XCAM_RETURN_NO_ERROR;
534 }
535
BowlModel(const BowlDataConfig & config,const uint32_t image_width,const uint32_t image_height)536 BowlModel::BowlModel (const BowlDataConfig &config, const uint32_t image_width, const uint32_t image_height)
537 : _config (config)
538 , _bowl_img_width (image_width)
539 , _bowl_img_height (image_height)
540 {
541 //max area => x/a = y/b
542 XCAM_ASSERT (fabs(_config.center_z) < _config.c);
543 float mid = sqrt ((1.0f - _config.center_z * _config.center_z / (_config.c * _config.c)) / 2.0f);
544 _max_topview_length_mm = mid * _config.a * 2.0f;
545 _max_topview_width_mm = mid * _config.b * 2.0f;
546 }
547
548 bool
get_max_topview_area_mm(float & length_mm,float & width_mm)549 BowlModel::get_max_topview_area_mm (float &length_mm, float &width_mm)
550 {
551 if (_max_topview_width_mm <= 0.0f || _max_topview_length_mm <= 0.0f)
552 return false;
553 length_mm = _max_topview_length_mm;
554 width_mm = _max_topview_width_mm;
555 return true;
556 }
557
558 bool
get_topview_rect_map(PointMap & texture_points,uint32_t res_width,uint32_t res_height,float length_mm,float width_mm)559 BowlModel::get_topview_rect_map (
560 PointMap &texture_points,
561 uint32_t res_width, uint32_t res_height,
562 float length_mm, float width_mm)
563 {
564 if (XCAM_DOUBLE_EQUAL_AROUND (length_mm, 0.0f) ||
565 XCAM_DOUBLE_EQUAL_AROUND (width_mm, 0.0f)) {
566 get_max_topview_area_mm (length_mm, width_mm);
567 }
568
569 XCAM_FAIL_RETURN (
570 ERROR,
571 length_mm * length_mm / (_config.a * _config.a) / 4.0f + width_mm * width_mm / (_config.b * _config.b) / 4.0f +
572 _config.center_z * _config.center_z / (_config.c * _config.c) <= 1.0f + 0.001f,
573 false,
574 "bowl model topview input area(L:%.2fmm, W:%.2fmm) is larger than max area", length_mm, width_mm);
575
576 float center_pos_x = res_width / 2.0f;
577 float center_pos_y = res_height / 2.0f;
578 float mm_per_pixel_x = length_mm / res_width;
579 float mm_per_pixel_y = width_mm / res_height;
580
581 texture_points.resize (res_width * res_height);
582
583 for(uint32_t row = 0; row < res_height; row++) {
584 for(uint32_t col = 0; col < res_width; col++) {
585 PointFloat3 world_pos (
586 (col - center_pos_x) * mm_per_pixel_x,
587 (center_pos_y - row) * mm_per_pixel_y,
588 0.0f);
589
590 PointFloat2 texture_pos = bowl_view_coords_to_image (
591 _config, world_pos, _bowl_img_width, _bowl_img_height);
592
593 texture_points [res_width * row + col] = texture_pos;
594 }
595 }
596 return true;
597 }
598
599 bool
get_stitch_image_vertex_model(VertexMap & vertices,PointMap & texture_points,IndexVector & indeices,uint32_t res_width,uint32_t res_height,float vertex_height)600 BowlModel::get_stitch_image_vertex_model (
601 VertexMap &vertices, PointMap &texture_points, IndexVector &indeices,
602 uint32_t res_width, uint32_t res_height, float vertex_height)
603 {
604 vertices.reserve (2 * (res_width + 1) * (res_height + 1));
605 texture_points.reserve (2 * (res_width + 1) * (res_height + 1));
606 indeices.reserve (2 * (res_width + 1) * (res_height + 1) + (res_height + 1));
607
608 float step_x = (float)_bowl_img_width / res_width;
609 float step_y = vertex_height / res_height;
610 float offset_y = (float)_bowl_img_height - vertex_height;
611
612 int32_t indicator = 0;
613
614 for (uint32_t row = 0; row < res_height - 1; row++) {
615 PointFloat2 texture_pos0;
616 texture_pos0.y = row * step_y + offset_y;
617
618 PointFloat2 texture_pos1;
619 texture_pos1.y = (row + 1) * step_y + offset_y;
620
621 for (uint32_t col = 0; col <= res_width; col++) {
622
623 texture_pos0.x = col * step_x;
624 texture_pos1.x = col * step_x;
625
626 PointFloat3 world_pos0 =
627 bowl_view_image_to_world (
628 _config, _bowl_img_width, _bowl_img_height, texture_pos0);
629
630 vertices.push_back (PointFloat3(world_pos0.x / _config.a, world_pos0.y / _config.b, world_pos0.z / _config.c));
631 indeices.push_back (indicator++);
632 texture_points.push_back (PointFloat2(texture_pos0.x / _bowl_img_width, (_bowl_img_height - texture_pos0.y) / _bowl_img_height));
633
634 PointFloat3 world_pos1 =
635 bowl_view_image_to_world (
636 _config, _bowl_img_width, _bowl_img_height, texture_pos1);
637
638 vertices.push_back (PointFloat3(world_pos1.x / _config.a, world_pos1.y / _config.b, world_pos1.z / _config.c));
639 indeices.push_back (indicator++);
640 texture_points.push_back (PointFloat2(texture_pos1.x / _bowl_img_width, (_bowl_img_height - texture_pos1.y) / _bowl_img_height));
641 }
642 }
643 return true;
644 }
645
646
647 bool
get_bowlview_vertex_model(VertexMap & vertices,PointMap & texture_points,IndexVector & indeices,uint32_t res_width,uint32_t res_height)648 BowlModel::get_bowlview_vertex_model (
649 VertexMap &vertices, PointMap &texture_points, IndexVector &indeices,
650 uint32_t res_width, uint32_t res_height)
651 {
652 return get_stitch_image_vertex_model (vertices, texture_points, indeices, res_width, res_height, (float)_bowl_img_height);
653 }
654
655 bool
get_topview_vertex_model(VertexMap & vertices,PointMap & texture_points,IndexVector & indeices,uint32_t res_width,uint32_t res_height)656 BowlModel::get_topview_vertex_model (
657 VertexMap &vertices, PointMap &texture_points, IndexVector &indeices,
658 uint32_t res_width, uint32_t res_height)
659 {
660 float wall_image_height = _config.wall_height / (float)(_config.wall_height + _config.ground_length) * (float)_bowl_img_height;
661 float ground_image_height = (float)_bowl_img_height - wall_image_height;
662
663 return get_stitch_image_vertex_model (vertices, texture_points, indeices, res_width, res_height, ground_image_height);
664 }
665
666
667 }
668