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 (at) intel.com> 19 * Author: Yinhang Liu <yinhangx.liu (at) 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 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 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 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 95 Stitcher::~Stitcher () 96 { 97 } 98 99 bool 100 Stitcher::set_bowl_config (const BowlDataConfig &config) 101 { 102 _bowl_config = config; 103 return true; 104 } 105 106 bool 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 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 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 141 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 177 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 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 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 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 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 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 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 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 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 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 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 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