@@ -62,6 +62,7 @@ __all__ = [ | |||||
"softmax", | "softmax", | ||||
"softplus", | "softplus", | ||||
"svd", | "svd", | ||||
"warp_affine", | |||||
"warp_perspective", | "warp_perspective", | ||||
"conv1d", | "conv1d", | ||||
] | ] | ||||
@@ -914,6 +915,45 @@ def resize( | |||||
return result | return result | ||||
def warp_affine( | |||||
inp: Tensor, | |||||
weight: Tensor, | |||||
out_shape, | |||||
border_mode="REPLICATE", | |||||
border_val=0, | |||||
format="NHWC", | |||||
imode="LINEAR", | |||||
): | |||||
""" | |||||
Batched affine transform on 2D images. | |||||
:param inp: input image. | |||||
:param weight: weight tensor. | |||||
:param out_shape: output tensor shape. | |||||
:param border_mode: pixel extrapolation method. | |||||
Default: "WRAP". Currently "CONSTANT", "REFLECT", | |||||
"REFLECT_101", "ISOLATED", "WRAP", "REPLICATE", "TRANSPARENT" are supported. | |||||
:param border_val: value used in case of a constant border. Default: 0 | |||||
:param format: "NHWC" as default based on historical concerns, | |||||
"NCHW" is also supported. Default: "NCHW". | |||||
:param imode: interpolation methods. Could be "LINEAR", "NEAREST", "CUBIC", "AREA". | |||||
Default: "LINEAR". | |||||
:return: output tensor. | |||||
.. note:: | |||||
Here all available options for params are listed, | |||||
however it does not mean that you can use all the combinations. | |||||
On different platforms, different combinations are supported. | |||||
""" | |||||
op = builtin.WarpAffine( | |||||
border_mode=border_mode, border_val=border_val, format=format, imode=imode | |||||
) | |||||
out_shape = utils.astensor1d(out_shape, inp, dtype="int32", device=inp.device) | |||||
(result,) = apply(op, inp, weight, out_shape) | |||||
return result | |||||
def warp_perspective( | def warp_perspective( | ||||
inp: Tensor, | inp: Tensor, | ||||
M: Tensor, | M: Tensor, | ||||
@@ -369,6 +369,24 @@ def test_warp_perspective(): | |||||
) | ) | ||||
def test_warp_affine(): | |||||
inp_shape = (1, 3, 3, 3) | |||||
x = tensor(np.arange(27, dtype=np.float32).reshape(inp_shape)) | |||||
weightv = [[[1.26666667, 0.6, -83.33333333], [-0.33333333, 1, 66.66666667]]] | |||||
outp = F.warp_affine(x, tensor(weightv), (2, 2), border_mode="WRAP") | |||||
res = np.array( | |||||
[ | |||||
[ | |||||
[[7.875, 8.875, 9.875], [8.90625, 9.90625, 10.90625]], | |||||
[[18.75, 19.75, 20.75], [14.90625, 15.90625, 16.90625]], | |||||
] | |||||
], | |||||
dtype=np.float32, | |||||
) | |||||
if not is_cuda_available(): | |||||
np.testing.assert_almost_equal(outp.numpy(), res, 5) | |||||
def test_remap(): | def test_remap(): | ||||
inp_shape = (1, 1, 4, 4) | inp_shape = (1, 1, 4, 4) | ||||
inp = tensor(np.arange(16, dtype=np.float32).reshape(inp_shape)) | inp = tensor(np.arange(16, dtype=np.float32).reshape(inp_shape)) | ||||
@@ -0,0 +1,32 @@ | |||||
/** | |||||
* \file imperative/src/impl/ops/warp_affine.cpp | |||||
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License") | |||||
* | |||||
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved. | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, | |||||
* software distributed under the License is distributed on an | |||||
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
*/ | |||||
#include "../op_trait.h" | |||||
#include "megbrain/imperative/ops/autogen.h" | |||||
#include "megbrain/opr/imgproc.h" | |||||
namespace mgb::imperative { | |||||
namespace { namespace warp_affine { | |||||
auto apply_on_var_node( | |||||
const OpDef& def, | |||||
const VarNodeArray& inputs) { | |||||
mgb_assert(inputs.size() == 3); | |||||
auto&& op = static_cast<const WarpAffine&>(def); | |||||
return opr::WarpAffine::make(inputs[0], inputs[1], inputs[2], op.param()); | |||||
} | |||||
OP_TRAIT_REG(WarpAffine, WarpAffine) | |||||
.apply_on_var_node(apply_on_var_node) | |||||
.fallback(); | |||||
}} // warp_affine | |||||
} // namespace mgb::imperative |
@@ -74,6 +74,8 @@ def ROIAlign: MgbHashableOp<"ROIAlign", [ROIAlignParam]>; | |||||
def WarpPerspective: MgbHashableOp<"WarpPerspective", [WarpPerspectiveParam]>; | def WarpPerspective: MgbHashableOp<"WarpPerspective", [WarpPerspectiveParam]>; | ||||
def WarpAffine: MgbHashableOp<"WarpAffine", [WarpAffineParam]>; | |||||
def Remap: MgbHashableOp<"Remap", [RemapParam]>; | def Remap: MgbHashableOp<"Remap", [RemapParam]>; | ||||
def Resize: MgbHashableOp<"Resize", [ResizeParam]>; | def Resize: MgbHashableOp<"Resize", [ResizeParam]>; | ||||