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