1 /*
2  * Copyright (c) 2017-2019 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "WarpAffine.h"
25 
26 #include "Utils.h"
27 
28 namespace arm_compute
29 {
30 namespace test
31 {
32 namespace validation
33 {
34 namespace reference
35 {
valid_bilinear_policy(float xn,float yn,int width,int height,BorderMode border_mode)36 bool valid_bilinear_policy(float xn, float yn, int width, int height, BorderMode border_mode)
37 {
38     if(border_mode != BorderMode::UNDEFINED)
39     {
40         return true;
41     }
42     if((0 <= yn + 1) && (yn + 1 < height) && (0 <= xn + 1) && (xn + 1 < width))
43     {
44         return true;
45     }
46     return false;
47 }
48 
49 template <typename T>
warp_affine(const SimpleTensor<T> & src,SimpleTensor<T> & valid_mask,const float * matrix,InterpolationPolicy policy,BorderMode border_mode,uint8_t constant_border_value)50 SimpleTensor<T> warp_affine(const SimpleTensor<T> &src, SimpleTensor<T> &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, uint8_t constant_border_value)
51 {
52     SimpleTensor<T> dst(src.shape(), src.data_type());
53 
54     // x0 = M00 * x + M01 * y + M02
55     // y0 = M10 * x + M11 * y + M12
56     const float M00 = matrix[0];
57     const float M10 = matrix[1];
58     const float M01 = matrix[0 + 1 * 2];
59     const float M11 = matrix[1 + 1 * 2];
60     const float M02 = matrix[0 + 2 * 2];
61     const float M12 = matrix[1 + 2 * 2];
62 
63     const int width  = src.shape().x();
64     const int height = src.shape().y();
65 
66     const uint32_t num_elements = src.num_elements();
67     for(uint32_t element_idx = 0; element_idx < num_elements; ++element_idx)
68     {
69         valid_mask[element_idx] = 1;
70         Coordinates id          = index2coord(src.shape(), element_idx);
71         int         idx         = id.x();
72         int         idy         = id.y();
73 
74         float x0 = M00 * idx + M01 * idy + M02;
75         float y0 = M10 * idx + M11 * idy + M12;
76 
77         id.set(0, static_cast<int>(std::floor(x0)));
78         id.set(1, static_cast<int>(std::floor(y0)));
79         if((0 <= y0) && (y0 < height) && (0 <= x0) && (x0 < width))
80         {
81             switch(policy)
82             {
83                 case InterpolationPolicy::NEAREST_NEIGHBOR:
84                     dst[element_idx] = tensor_elem_at(src, id, border_mode, constant_border_value);
85                     break;
86                 case InterpolationPolicy::BILINEAR:
87                     (valid_bilinear_policy(x0, y0, width, height, border_mode)) ? dst[element_idx] = bilinear_policy(src, id, x0, y0, border_mode, constant_border_value) :
88                                                                                                      valid_mask[element_idx] = 0;
89                     break;
90                 case InterpolationPolicy::AREA:
91                 default:
92                     ARM_COMPUTE_ERROR("Interpolation not supported");
93             }
94         }
95         else
96         {
97             if(border_mode == BorderMode::UNDEFINED)
98             {
99                 valid_mask[element_idx] = 0;
100             }
101             else
102             {
103                 switch(policy)
104                 {
105                     case InterpolationPolicy::NEAREST_NEIGHBOR:
106                         if(border_mode == BorderMode::CONSTANT)
107                         {
108                             dst[element_idx] = constant_border_value;
109                         }
110                         else if(border_mode == BorderMode::REPLICATE)
111                         {
112                             id.set(0, std::max(0, std::min(static_cast<int>(x0), width - 1)));
113                             id.set(1, std::max(0, std::min(static_cast<int>(y0), height - 1)));
114                             dst[element_idx] = src[coord2index(src.shape(), id)];
115                         }
116                         break;
117                     case InterpolationPolicy::BILINEAR:
118                         dst[element_idx] = bilinear_policy(src, id, x0, y0, border_mode, constant_border_value);
119                         break;
120                     case InterpolationPolicy::AREA:
121                     default:
122                         ARM_COMPUTE_ERROR("Interpolation not supported");
123                 }
124             }
125         }
126     }
127 
128     return dst;
129 }
130 
131 template SimpleTensor<uint8_t> warp_affine(const SimpleTensor<uint8_t> &src, SimpleTensor<uint8_t> &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode,
132                                            uint8_t constant_border_value);
133 } // namespace reference
134 } // namespace validation
135 } // namespace test
136 } // namespace arm_compute