1/*M/////////////////////////////////////////////////////////////////////////////////////// 2// 3// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4// 5// By downloading, copying, installing or using the software you agree to this license. 6// If you do not agree to this license, do not download, install, 7// copy or use the software. 8// 9// 10// License Agreement 11// For Open Source Computer Vision Library 12// 13// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 14// Copyright (C) 2009, Willow Garage Inc., all rights reserved. 15// Third party copyrights are property of their respective owners. 16// 17// Redistribution and use in source and binary forms, with or without modification, 18// are permitted provided that the following conditions are met: 19// 20// * Redistribution's of source code must retain the above copyright notice, 21// this list of conditions and the following disclaimer. 22// 23// * Redistribution's in binary form must reproduce the above copyright notice, 24// this list of conditions and the following disclaimer in the documentation 25// and/or other materials provided with the distribution. 26// 27// * The name of the copyright holders may not be used to endorse or promote products 28// derived from this software without specific prior written permission. 29// 30// This software is provided by the copyright holders and contributors "as is" and 31// any express or implied warranties, including, but not limited to, the implied 32// warranties of merchantability and fitness for a particular purpose are disclaimed. 33// In no event shall the Intel Corporation or contributors be liable for any direct, 34// indirect, incidental, special, exemplary, or consequential damages 35// (including, but not limited to, procurement of substitute goods or services; 36// loss of use, data, or profits; or business interruption) however caused 37// and on any theory of liability, whether in contract, strict liability, 38// or tort (including negligence or otherwise) arising in any way out of 39// the use of this software, even if advised of the possibility of such damage. 40// 41//M*/ 42 43#include "precomp.hpp" 44#include "opencl_kernels_stitching.hpp" 45 46namespace cv { 47namespace detail { 48 49void ProjectorBase::setCameraParams(InputArray _K, InputArray _R, InputArray _T) 50{ 51 Mat K = _K.getMat(), R = _R.getMat(), T = _T.getMat(); 52 53 CV_Assert(K.size() == Size(3, 3) && K.type() == CV_32F); 54 CV_Assert(R.size() == Size(3, 3) && R.type() == CV_32F); 55 CV_Assert((T.size() == Size(1, 3) || T.size() == Size(3, 1)) && T.type() == CV_32F); 56 57 Mat_<float> K_(K); 58 k[0] = K_(0,0); k[1] = K_(0,1); k[2] = K_(0,2); 59 k[3] = K_(1,0); k[4] = K_(1,1); k[5] = K_(1,2); 60 k[6] = K_(2,0); k[7] = K_(2,1); k[8] = K_(2,2); 61 62 Mat_<float> Rinv = R.t(); 63 rinv[0] = Rinv(0,0); rinv[1] = Rinv(0,1); rinv[2] = Rinv(0,2); 64 rinv[3] = Rinv(1,0); rinv[4] = Rinv(1,1); rinv[5] = Rinv(1,2); 65 rinv[6] = Rinv(2,0); rinv[7] = Rinv(2,1); rinv[8] = Rinv(2,2); 66 67 Mat_<float> R_Kinv = R * K.inv(); 68 r_kinv[0] = R_Kinv(0,0); r_kinv[1] = R_Kinv(0,1); r_kinv[2] = R_Kinv(0,2); 69 r_kinv[3] = R_Kinv(1,0); r_kinv[4] = R_Kinv(1,1); r_kinv[5] = R_Kinv(1,2); 70 r_kinv[6] = R_Kinv(2,0); r_kinv[7] = R_Kinv(2,1); r_kinv[8] = R_Kinv(2,2); 71 72 Mat_<float> K_Rinv = K * Rinv; 73 k_rinv[0] = K_Rinv(0,0); k_rinv[1] = K_Rinv(0,1); k_rinv[2] = K_Rinv(0,2); 74 k_rinv[3] = K_Rinv(1,0); k_rinv[4] = K_Rinv(1,1); k_rinv[5] = K_Rinv(1,2); 75 k_rinv[6] = K_Rinv(2,0); k_rinv[7] = K_Rinv(2,1); k_rinv[8] = K_Rinv(2,2); 76 77 Mat_<float> T_(T.reshape(0, 3)); 78 t[0] = T_(0,0); t[1] = T_(1,0); t[2] = T_(2,0); 79} 80 81 82Point2f PlaneWarper::warpPoint(const Point2f &pt, InputArray K, InputArray R, InputArray T) 83{ 84 projector_.setCameraParams(K, R, T); 85 Point2f uv; 86 projector_.mapForward(pt.x, pt.y, uv.x, uv.y); 87 return uv; 88} 89 90Point2f PlaneWarper::warpPoint(const Point2f &pt, InputArray K, InputArray R) 91{ 92 float tz[] = {0.f, 0.f, 0.f}; 93 Mat_<float> T(3, 1, tz); 94 return warpPoint(pt, K, R, T); 95} 96 97Rect PlaneWarper::buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) 98{ 99 return buildMaps(src_size, K, R, Mat::zeros(3, 1, CV_32FC1), xmap, ymap); 100} 101 102Rect PlaneWarper::buildMaps(Size src_size, InputArray K, InputArray R, InputArray T, OutputArray _xmap, OutputArray _ymap) 103{ 104 projector_.setCameraParams(K, R, T); 105 106 Point dst_tl, dst_br; 107 detectResultRoi(src_size, dst_tl, dst_br); 108 109 Size dsize(dst_br.x - dst_tl.x + 1, dst_br.y - dst_tl.y + 1); 110 _xmap.create(dsize, CV_32FC1); 111 _ymap.create(dsize, CV_32FC1); 112 113 if (ocl::useOpenCL()) 114 { 115 ocl::Kernel k("buildWarpPlaneMaps", ocl::stitching::warpers_oclsrc); 116 if (!k.empty()) 117 { 118 int rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1; 119 Mat k_rinv(1, 9, CV_32FC1, projector_.k_rinv), t(1, 3, CV_32FC1, projector_.t); 120 UMat uxmap = _xmap.getUMat(), uymap = _ymap.getUMat(), 121 uk_rinv = k_rinv.getUMat(ACCESS_READ), ut = t.getUMat(ACCESS_READ); 122 123 k.args(ocl::KernelArg::WriteOnlyNoSize(uxmap), ocl::KernelArg::WriteOnly(uymap), 124 ocl::KernelArg::PtrReadOnly(uk_rinv), ocl::KernelArg::PtrReadOnly(ut), 125 dst_tl.x, dst_tl.y, 1/projector_.scale, rowsPerWI); 126 127 size_t globalsize[2] = { dsize.width, (dsize.height + rowsPerWI - 1) / rowsPerWI }; 128 if (k.run(2, globalsize, NULL, true)) 129 { 130 CV_IMPL_ADD(CV_IMPL_OCL); 131 return Rect(dst_tl, dst_br); 132 } 133 } 134 } 135 136 Mat xmap = _xmap.getMat(), ymap = _ymap.getMat(); 137 138 float x, y; 139 for (int v = dst_tl.y; v <= dst_br.y; ++v) 140 { 141 for (int u = dst_tl.x; u <= dst_br.x; ++u) 142 { 143 projector_.mapBackward(static_cast<float>(u), static_cast<float>(v), x, y); 144 xmap.at<float>(v - dst_tl.y, u - dst_tl.x) = x; 145 ymap.at<float>(v - dst_tl.y, u - dst_tl.x) = y; 146 } 147 } 148 149 return Rect(dst_tl, dst_br); 150} 151 152 153Point PlaneWarper::warp(InputArray src, InputArray K, InputArray R, InputArray T, int interp_mode, int border_mode, 154 OutputArray dst) 155{ 156 UMat uxmap, uymap; 157 Rect dst_roi = buildMaps(src.size(), K, R, T, uxmap, uymap); 158 159 dst.create(dst_roi.height + 1, dst_roi.width + 1, src.type()); 160 remap(src, dst, uxmap, uymap, interp_mode, border_mode); 161 162 return dst_roi.tl(); 163} 164 165Point PlaneWarper::warp(InputArray src, InputArray K, InputArray R, 166 int interp_mode, int border_mode, OutputArray dst) 167{ 168 float tz[] = {0.f, 0.f, 0.f}; 169 Mat_<float> T(3, 1, tz); 170 return warp(src, K, R, T, interp_mode, border_mode, dst); 171} 172 173Rect PlaneWarper::warpRoi(Size src_size, InputArray K, InputArray R, InputArray T) 174{ 175 projector_.setCameraParams(K, R, T); 176 177 Point dst_tl, dst_br; 178 detectResultRoi(src_size, dst_tl, dst_br); 179 180 return Rect(dst_tl, Point(dst_br.x + 1, dst_br.y + 1)); 181} 182 183Rect PlaneWarper::warpRoi(Size src_size, InputArray K, InputArray R) 184{ 185 float tz[] = {0.f, 0.f, 0.f}; 186 Mat_<float> T(3, 1, tz); 187 return warpRoi(src_size, K, R, T); 188} 189 190 191void PlaneWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) 192{ 193 float tl_uf = std::numeric_limits<float>::max(); 194 float tl_vf = std::numeric_limits<float>::max(); 195 float br_uf = -std::numeric_limits<float>::max(); 196 float br_vf = -std::numeric_limits<float>::max(); 197 198 float u, v; 199 200 projector_.mapForward(0, 0, u, v); 201 tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); 202 br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); 203 204 projector_.mapForward(0, static_cast<float>(src_size.height - 1), u, v); 205 tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); 206 br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); 207 208 projector_.mapForward(static_cast<float>(src_size.width - 1), 0, u, v); 209 tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); 210 br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); 211 212 projector_.mapForward(static_cast<float>(src_size.width - 1), static_cast<float>(src_size.height - 1), u, v); 213 tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v); 214 br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v); 215 216 dst_tl.x = static_cast<int>(tl_uf); 217 dst_tl.y = static_cast<int>(tl_vf); 218 dst_br.x = static_cast<int>(br_uf); 219 dst_br.y = static_cast<int>(br_vf); 220} 221 222 223void SphericalWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) 224{ 225 detectResultRoiByBorder(src_size, dst_tl, dst_br); 226 227 float tl_uf = static_cast<float>(dst_tl.x); 228 float tl_vf = static_cast<float>(dst_tl.y); 229 float br_uf = static_cast<float>(dst_br.x); 230 float br_vf = static_cast<float>(dst_br.y); 231 232 float x = projector_.rinv[1]; 233 float y = projector_.rinv[4]; 234 float z = projector_.rinv[7]; 235 if (y > 0.f) 236 { 237 float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; 238 float y_ = projector_.k[4] * y / z + projector_.k[5]; 239 if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) 240 { 241 tl_uf = std::min(tl_uf, 0.f); tl_vf = std::min(tl_vf, static_cast<float>(CV_PI * projector_.scale)); 242 br_uf = std::max(br_uf, 0.f); br_vf = std::max(br_vf, static_cast<float>(CV_PI * projector_.scale)); 243 } 244 } 245 246 x = projector_.rinv[1]; 247 y = -projector_.rinv[4]; 248 z = projector_.rinv[7]; 249 if (y > 0.f) 250 { 251 float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; 252 float y_ = projector_.k[4] * y / z + projector_.k[5]; 253 if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) 254 { 255 tl_uf = std::min(tl_uf, 0.f); tl_vf = std::min(tl_vf, static_cast<float>(0)); 256 br_uf = std::max(br_uf, 0.f); br_vf = std::max(br_vf, static_cast<float>(0)); 257 } 258 } 259 260 dst_tl.x = static_cast<int>(tl_uf); 261 dst_tl.y = static_cast<int>(tl_vf); 262 dst_br.x = static_cast<int>(br_uf); 263 dst_br.y = static_cast<int>(br_vf); 264} 265 266void SphericalPortraitWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) 267{ 268 detectResultRoiByBorder(src_size, dst_tl, dst_br); 269 270 float tl_uf = static_cast<float>(dst_tl.x); 271 float tl_vf = static_cast<float>(dst_tl.y); 272 float br_uf = static_cast<float>(dst_br.x); 273 float br_vf = static_cast<float>(dst_br.y); 274 275 float x = projector_.rinv[0]; 276 float y = projector_.rinv[3]; 277 float z = projector_.rinv[6]; 278 if (y > 0.f) 279 { 280 float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; 281 float y_ = projector_.k[4] * y / z + projector_.k[5]; 282 if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) 283 { 284 tl_uf = std::min(tl_uf, 0.f); tl_vf = std::min(tl_vf, static_cast<float>(CV_PI * projector_.scale)); 285 br_uf = std::max(br_uf, 0.f); br_vf = std::max(br_vf, static_cast<float>(CV_PI * projector_.scale)); 286 } 287 } 288 289 x = projector_.rinv[0]; 290 y = -projector_.rinv[3]; 291 z = projector_.rinv[6]; 292 if (y > 0.f) 293 { 294 float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; 295 float y_ = projector_.k[4] * y / z + projector_.k[5]; 296 if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) 297 { 298 tl_uf = std::min(tl_uf, 0.f); tl_vf = std::min(tl_vf, static_cast<float>(0)); 299 br_uf = std::max(br_uf, 0.f); br_vf = std::max(br_vf, static_cast<float>(0)); 300 } 301 } 302 303 dst_tl.x = static_cast<int>(tl_uf); 304 dst_tl.y = static_cast<int>(tl_vf); 305 dst_br.x = static_cast<int>(br_uf); 306 dst_br.y = static_cast<int>(br_vf); 307} 308 309/////////////////////////////////////////// SphericalWarper //////////////////////////////////////// 310 311Rect SphericalWarper::buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) 312{ 313 if (ocl::useOpenCL()) 314 { 315 ocl::Kernel k("buildWarpSphericalMaps", ocl::stitching::warpers_oclsrc); 316 if (!k.empty()) 317 { 318 int rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1; 319 projector_.setCameraParams(K, R); 320 321 Point dst_tl, dst_br; 322 detectResultRoi(src_size, dst_tl, dst_br); 323 324 Size dsize(dst_br.x - dst_tl.x + 1, dst_br.y - dst_tl.y + 1); 325 xmap.create(dsize, CV_32FC1); 326 ymap.create(dsize, CV_32FC1); 327 328 Mat k_rinv(1, 9, CV_32FC1, projector_.k_rinv); 329 UMat uxmap = xmap.getUMat(), uymap = ymap.getUMat(), uk_rinv = k_rinv.getUMat(ACCESS_READ); 330 331 k.args(ocl::KernelArg::WriteOnlyNoSize(uxmap), ocl::KernelArg::WriteOnly(uymap), 332 ocl::KernelArg::PtrReadOnly(uk_rinv), dst_tl.x, dst_tl.y, 1/projector_.scale, rowsPerWI); 333 334 size_t globalsize[2] = { dsize.width, (dsize.height + rowsPerWI - 1) / rowsPerWI }; 335 if (k.run(2, globalsize, NULL, true)) 336 { 337 CV_IMPL_ADD(CV_IMPL_OCL); 338 return Rect(dst_tl, dst_br); 339 } 340 } 341 } 342 343 return RotationWarperBase<SphericalProjector>::buildMaps(src_size, K, R, xmap, ymap); 344} 345 346Point SphericalWarper::warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst) 347{ 348 UMat uxmap, uymap; 349 Rect dst_roi = buildMaps(src.size(), K, R, uxmap, uymap); 350 351 dst.create(dst_roi.height + 1, dst_roi.width + 1, src.type()); 352 remap(src, dst, uxmap, uymap, interp_mode, border_mode); 353 354 return dst_roi.tl(); 355} 356 357/////////////////////////////////////////// CylindricalWarper //////////////////////////////////////// 358 359Rect CylindricalWarper::buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap) 360{ 361 if (ocl::useOpenCL()) 362 { 363 ocl::Kernel k("buildWarpCylindricalMaps", ocl::stitching::warpers_oclsrc); 364 if (!k.empty()) 365 { 366 int rowsPerWI = ocl::Device::getDefault().isIntel() ? 4 : 1; 367 projector_.setCameraParams(K, R); 368 369 Point dst_tl, dst_br; 370 detectResultRoi(src_size, dst_tl, dst_br); 371 372 Size dsize(dst_br.x - dst_tl.x + 1, dst_br.y - dst_tl.y + 1); 373 xmap.create(dsize, CV_32FC1); 374 ymap.create(dsize, CV_32FC1); 375 376 Mat k_rinv(1, 9, CV_32FC1, projector_.k_rinv); 377 UMat uxmap = xmap.getUMat(), uymap = ymap.getUMat(), uk_rinv = k_rinv.getUMat(ACCESS_READ); 378 379 k.args(ocl::KernelArg::WriteOnlyNoSize(uxmap), ocl::KernelArg::WriteOnly(uymap), 380 ocl::KernelArg::PtrReadOnly(uk_rinv), dst_tl.x, dst_tl.y, 1/projector_.scale, 381 rowsPerWI); 382 383 size_t globalsize[2] = { dsize.width, (dsize.height + rowsPerWI - 1) / rowsPerWI }; 384 if (k.run(2, globalsize, NULL, true)) 385 { 386 CV_IMPL_ADD(CV_IMPL_OCL); 387 return Rect(dst_tl, dst_br); 388 } 389 } 390 } 391 392 return RotationWarperBase<CylindricalProjector>::buildMaps(src_size, K, R, xmap, ymap); 393} 394 395Point CylindricalWarper::warp(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, OutputArray dst) 396{ 397 UMat uxmap, uymap; 398 Rect dst_roi = buildMaps(src.size(), K, R, uxmap, uymap); 399 400 dst.create(dst_roi.height + 1, dst_roi.width + 1, src.type()); 401 remap(src, dst, uxmap, uymap, interp_mode, border_mode); 402 403 return dst_roi.tl(); 404} 405 406} // namespace detail 407} // namespace cv 408