diff options
author | giuros01 <giuseppe.rossini@arm.com> | 2018-10-03 12:44:35 +0100 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-11-02 16:55:45 +0000 |
commit | c04a0e8f93c620d05444251e1ae55dcf8c660a1b (patch) | |
tree | bdab0d171ea2d0439ea0c0405e8a1a3c9c27bf7c /tests/validation | |
parent | 08346e9b9a7dadd2f0765aea64e656902d843e8a (diff) | |
download | ComputeLibrary-c04a0e8f93c620d05444251e1ae55dcf8c660a1b.tar.gz |
COMPMID-1327: Add support for BBoxTransform operator in CL
Change-Id: I91865506166951b3bf7f06a0b2d4cde925cfefb6
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/153447
Tested-by: bsgcomp <bsgcomp@arm.com>
Reviewed-by: Pablo Tello <pablo.tello@arm.com>
Diffstat (limited to 'tests/validation')
-rw-r--r-- | tests/validation/CL/BoundingBoxTransform.cpp | 127 | ||||
-rw-r--r-- | tests/validation/fixtures/BoundingBoxTransformFixture.h | 173 | ||||
-rw-r--r-- | tests/validation/reference/BoundingBoxTransform.cpp | 101 | ||||
-rw-r--r-- | tests/validation/reference/BoundingBoxTransform.h | 47 |
4 files changed, 448 insertions, 0 deletions
diff --git a/tests/validation/CL/BoundingBoxTransform.cpp b/tests/validation/CL/BoundingBoxTransform.cpp new file mode 100644 index 0000000000..e5e2ad8f61 --- /dev/null +++ b/tests/validation/CL/BoundingBoxTransform.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CL/CLScheduler.h" +#include "arm_compute/runtime/CL/functions/CLBoundingBoxTransform.h" +#include "tests/CL/CLAccessor.h" +#include "tests/CL/CLArrayAccessor.h" +#include "tests/Globals.h" +#include "tests/framework/Macros.h" +#include "tests/framework/datasets/Datasets.h" +#include "tests/validation/Validation.h" +#include "tests/validation/fixtures/BoundingBoxTransformFixture.h" +#include "utils/TypePrinter.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +RelativeTolerance<float> relative_tolerance_f32(0.01f); +AbsoluteTolerance<float> absolute_tolerance_f32(0.001f); + +RelativeTolerance<half> relative_tolerance_f16(half(0.2)); +AbsoluteTolerance<float> absolute_tolerance_f16(half(0.02f)); + +const auto BboxInfoDataset = framework::dataset::make("BboxInfo", { BoundingBoxTransformInfo(20U, 20U, 2U, true), + BoundingBoxTransformInfo(128U, 128U, 4U, true), + BoundingBoxTransformInfo(800U, 600U, 1U, false), + BoundingBoxTransformInfo(800U, 600U, 2U, true, { 1.0, 0.5, 1.5, 2.0 }), + BoundingBoxTransformInfo(800U, 600U, 4U, false, { 1.0, 0.5, 1.5, 2.0 }) + }); + +const auto DeltaDataset = framework::dataset::make("DeltasShape", { TensorShape(4U, 1U), + TensorShape(4U, 2U), + TensorShape(8U, 2U), + TensorShape(36U, 1U), + TensorShape(36U, 20U), + TensorShape(36U, 100U), + TensorShape(36U, 200U) + }); + +} // namespace + +TEST_SUITE(CL) +TEST_SUITE(BBoxTransform) + +// *INDENT-OFF* +// clang-format off +DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip( + framework::dataset::make("BoxesInfo", { TensorInfo(TensorShape(4U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(5U, 128U), 1, DataType::F32), // Wrong number of box fields + TensorInfo(TensorShape(4U, 128U), 1, DataType::F16), // Wrong data type + TensorInfo(TensorShape(4U, 128U), 1, DataType::F32), // Wrong number of classes + TensorInfo(TensorShape(4U, 128U), 1, DataType::F32)}), // Deltas and predicted boxes have different dimensions + framework::dataset::make("PredBoxesInfo",{ TensorInfo(TensorShape(128U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(127U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 100U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 100U), 1, DataType::F32)})), + framework::dataset::make("DeltasInfo", { TensorInfo(TensorShape(128U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(127U, 128U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 100U), 1, DataType::F32), + TensorInfo(TensorShape(128U, 128U), 1, DataType::F32)})), + framework::dataset::make("BoundingBoxTransofmInfo", { BoundingBoxTransformInfo(800.f, 600.f, 1.f), + BoundingBoxTransformInfo(800.f, 600.f, 1.f), + BoundingBoxTransformInfo(800.f, 600.f, 1.f), + BoundingBoxTransformInfo(800.f, 600.f, 1.f)})), + framework::dataset::make("Expected", { true, false, false, false, false })), + boxes_info, pred_boxes_info, deltas_info, bbox_info, expected) +{ + ARM_COMPUTE_EXPECT(bool(CLBoundingBoxTransform::validate(&boxes_info.clone()->set_is_resizable(true), &pred_boxes_info.clone()->set_is_resizable(true), &deltas_info.clone()->set_is_resizable(true), bbox_info)) == expected, framework::LogLevel::ERRORS); +} +// clang-format on +// *INDENT-ON* + +template <typename T> +using CLBoundingBoxTransformFixture = BoundingBoxTransformFixture<CLTensor, CLAccessor, CLBoundingBoxTransform, T>; + +TEST_SUITE(Float) +TEST_SUITE(FP32) +FIXTURE_DATA_TEST_CASE(BoundingBox, CLBoundingBoxTransformFixture<float>, framework::DatasetMode::ALL, + combine(combine(DeltaDataset, BboxInfoDataset), framework::dataset::make("DataType", { DataType::F32 }))) +{ + // Validate output + validate(CLAccessor(_target), _reference, relative_tolerance_f32, 0.f, absolute_tolerance_f32); +} +TEST_SUITE_END() // FP32 + +TEST_SUITE(FP16) +FIXTURE_DATA_TEST_CASE(BoundingBox, CLBoundingBoxTransformFixture<half>, framework::DatasetMode::ALL, + combine(combine(DeltaDataset, BboxInfoDataset), framework::dataset::make("DataType", { DataType::F16 }))) +{ + // Validate output + validate(CLAccessor(_target), _reference, relative_tolerance_f16, 0.01f, absolute_tolerance_f16); +} +TEST_SUITE_END() // FP16 +TEST_SUITE_END() // Float + +TEST_SUITE_END() // BBoxTransform +TEST_SUITE_END() // CL +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/fixtures/BoundingBoxTransformFixture.h b/tests/validation/fixtures/BoundingBoxTransformFixture.h new file mode 100644 index 0000000000..b71da8e97d --- /dev/null +++ b/tests/validation/fixtures/BoundingBoxTransformFixture.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_FIXTURE +#define ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_FIXTURE + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/IAccessor.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Fixture.h" +#include "tests/validation/Helpers.h" +#include "tests/validation/reference/BoundingBoxTransform.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +template <typename TensorType, typename AccessorType, typename FunctionType, typename T> +class BoundingBoxTransformFixture : public framework::Fixture +{ +public: + template <typename...> + void setup(TensorShape deltas_shape, const BoundingBoxTransformInfo &info, DataType data_type) + { + std::mt19937 gen_target(library->seed()); + _target = compute_target(deltas_shape, data_type, info, gen_target); + + std::mt19937 gen_reference(library->seed()); + _reference = compute_reference(deltas_shape, data_type, info, gen_reference); + } + +protected: + TensorType compute_target(const TensorShape &deltas_shape, DataType data_type, + const BoundingBoxTransformInfo &bbox_info, std::mt19937 &gen) + { + // Create tensors + TensorShape boxes_shape(4, deltas_shape[1]); + TensorType deltas = create_tensor<TensorType>(deltas_shape, data_type); + TensorType boxes = create_tensor<TensorType>(boxes_shape, data_type); + TensorType pred_boxes; + + // Create and configure function + FunctionType bbox_transform; + bbox_transform.configure(&boxes, &pred_boxes, &deltas, bbox_info); + + ARM_COMPUTE_EXPECT(deltas.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(boxes.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(pred_boxes.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Allocate tensors + deltas.allocator()->allocate(); + boxes.allocator()->allocate(); + pred_boxes.allocator()->allocate(); + + ARM_COMPUTE_EXPECT(!deltas.info()->is_resizable(), framework::LogLevel::ERRORS); + ARM_COMPUTE_EXPECT(!boxes.info()->is_resizable(), framework::LogLevel::ERRORS); + + // Fill tensors + TensorShape img_shape(bbox_info.scale() * bbox_info.img_width(), bbox_info.scale() * bbox_info.img_height()); + generate_boxes(AccessorType(boxes), img_shape, boxes_shape[1], gen); + generate_deltas(AccessorType(deltas), AccessorType(boxes), img_shape, deltas_shape[1], deltas_shape[0] / 4, gen); + + // Compute function + bbox_transform.run(); + + return pred_boxes; + } + + SimpleTensor<T> compute_reference(const TensorShape &deltas_shape, + DataType data_type, + const BoundingBoxTransformInfo &bbox_info, std::mt19937 &gen) + { + // Create reference tensor + TensorShape boxes_shape(4, deltas_shape[1]); + SimpleTensor<T> boxes{ boxes_shape, data_type }; + SimpleTensor<T> deltas{ deltas_shape, data_type }; + + // Fill reference tensor + TensorShape img_shape(bbox_info.scale() * bbox_info.img_width(), bbox_info.scale() * bbox_info.img_height()); + generate_boxes(boxes, img_shape, boxes_shape[1], gen); + generate_deltas(deltas, boxes, img_shape, deltas_shape[1], deltas_shape[0] / 4, gen); + + return reference::bounding_box_transform(boxes, deltas, bbox_info); + } + + TensorType _target{}; + SimpleTensor<T> _reference{}; + +private: + template <typename U> + void generate_deltas(U &&deltas, U &&boxes, const TensorShape &image_shape, size_t num_boxes, size_t num_classes, std::mt19937 &gen) + { + T *deltas_ptr = static_cast<T *>(deltas.data()); + T *boxes_ptr = static_cast<T *>(boxes.data()); + + std::uniform_int_distribution<> dist_x1(0, image_shape[0] - 1); + std::uniform_int_distribution<> dist_y1(0, image_shape[1] - 1); + std::uniform_int_distribution<> dist_w(1, image_shape[0]); + std::uniform_int_distribution<> dist_h(1, image_shape[1]); + + for(size_t i = 0; i < num_boxes; ++i) + { + const T ex_width = boxes_ptr[4 * i + 2] - boxes_ptr[4 * i] + T(1); + const T ex_height = boxes_ptr[4 * i + 3] - boxes_ptr[4 * i + 1] + T(1); + const T ex_ctr_x = boxes_ptr[4 * i] + T(0.5) * ex_width; + const T ex_ctr_y = boxes_ptr[4 * i + 1] + T(0.5) * ex_height; + + for(size_t j = 0; j < num_classes; ++j) + { + const T x1 = T(dist_x1(gen)); + const T y1 = T(dist_y1(gen)); + const T width = T(dist_w(gen)); + const T height = T(dist_h(gen)); + const T ctr_x = x1 + T(0.5) * width; + const T ctr_y = y1 + T(0.5) * height; + + deltas_ptr[4 * num_classes * i + 4 * j] = (ctr_x - ex_ctr_x) / ex_width; + deltas_ptr[4 * num_classes * i + 4 * j + 1] = (ctr_y - ex_ctr_y) / ex_height; + deltas_ptr[4 * num_classes * i + 4 * j + 2] = log(width / ex_width); + deltas_ptr[4 * num_classes * i + 4 * j + 3] = log(height / ex_height); + } + } + } + + template <typename U> + void generate_boxes(U &&boxes, const TensorShape &image_shape, size_t num_boxes, std::mt19937 &gen) + { + T *boxes_ptr = (T *)boxes.data(); + + std::uniform_int_distribution<> dist_x1(0, image_shape[0] - 1); + std::uniform_int_distribution<> dist_y1(0, image_shape[1] - 1); + std::uniform_int_distribution<> dist_w(1, image_shape[0]); + std::uniform_int_distribution<> dist_h(1, image_shape[1]); + + for(size_t i = 0; i < num_boxes; ++i) + { + boxes_ptr[4 * i] = dist_x1(gen); + boxes_ptr[4 * i + 1] = dist_y1(gen); + boxes_ptr[4 * i + 2] = boxes_ptr[4 * i] + dist_w(gen) - 1; + boxes_ptr[4 * i + 3] = boxes_ptr[4 * i + 1] + dist_h(gen) - 1; + } + } +}; + +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_FIXTURE */ diff --git a/tests/validation/reference/BoundingBoxTransform.cpp b/tests/validation/reference/BoundingBoxTransform.cpp new file mode 100644 index 0000000000..6ac512e749 --- /dev/null +++ b/tests/validation/reference/BoundingBoxTransform.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "BoundingBoxTransform.h" + +#include "arm_compute/core/Types.h" +#include "arm_compute/core/utils/misc/ShapeCalculator.h" +#include "arm_compute/core/utils/misc/Utility.h" +#include "tests/validation/Helpers.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace reference +{ +template <typename T> +SimpleTensor<T> bounding_box_transform(const SimpleTensor<T> &boxes, const SimpleTensor<T> &deltas, const BoundingBoxTransformInfo &info) +{ + const DataType boxes_data_type = deltas.data_type(); + SimpleTensor<T> pred_boxes(deltas.shape(), boxes_data_type); + + const size_t num_classes = deltas.shape()[0] / 4; + const size_t num_boxes = deltas.shape()[1]; + const T *deltas_ptr = deltas.data(); + T *pred_boxes_ptr = pred_boxes.data(); + + const int img_h = floor(info.img_height() / info.scale() + 0.5f); + const int img_w = floor(info.img_width() / info.scale() + 0.5f); + + const T scale = (info.apply_scale() ? T(info.scale()) : T(1)); + + const size_t box_fields = 4; + const size_t class_fields = 4; + + for(size_t i = 0; i < num_boxes; ++i) + { + // Extract ROI information + const size_t start_box = box_fields * i; + const T width = boxes[start_box + 2] - boxes[start_box] + T(1.0); + const T height = boxes[start_box + 3] - boxes[start_box + 1] + T(1.0); + const T ctr_x = boxes[start_box] + T(0.5) * width; + const T ctr_y = boxes[start_box + 1] + T(0.5) * height; + + for(size_t j = 0; j < num_classes; ++j) + { + // Extract deltas + const size_t start_delta = i * num_classes * class_fields + class_fields * j; + const T dx = deltas_ptr[start_delta] / T(info.weights()[0]); + const T dy = deltas_ptr[start_delta + 1] / T(info.weights()[1]); + T dw = deltas_ptr[start_delta + 2] / T(info.weights()[2]); + T dh = deltas_ptr[start_delta + 3] / T(info.weights()[3]); + + // Clip dw and dh + dw = std::min(dw, T(info.bbox_xform_clip())); + dh = std::min(dh, T(info.bbox_xform_clip())); + + // Determine the predictions + const T pred_ctr_x = dx * width + ctr_x; + const T pred_ctr_y = dy * height + ctr_y; + const T pred_w = T(std::exp(dw)) * width; + const T pred_h = T(std::exp(dh)) * height; + + // Store the prediction into the output tensor + pred_boxes_ptr[start_delta] = scale * utility::clamp<T>(pred_ctr_x - T(0.5) * pred_w, T(0), T(img_w)); + pred_boxes_ptr[start_delta + 1] = scale * utility::clamp<T>(pred_ctr_y - T(0.5) * pred_h, T(0), T(img_h)); + pred_boxes_ptr[start_delta + 2] = scale * utility::clamp<T>(pred_ctr_x + T(0.5) * pred_w, T(0), T(img_w)); + pred_boxes_ptr[start_delta + 3] = scale * utility::clamp<T>(pred_ctr_y + T(0.5) * pred_h, T(0), T(img_h)); + } + } + return pred_boxes; +} + +template SimpleTensor<float> bounding_box_transform(const SimpleTensor<float> &boxes, const SimpleTensor<float> &deltas, const BoundingBoxTransformInfo &info); +template SimpleTensor<half> bounding_box_transform(const SimpleTensor<half> &boxes, const SimpleTensor<half> &deltas, const BoundingBoxTransformInfo &info); +} // namespace reference +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation/reference/BoundingBoxTransform.h b/tests/validation/reference/BoundingBoxTransform.h new file mode 100644 index 0000000000..33ef9d984f --- /dev/null +++ b/tests/validation/reference/BoundingBoxTransform.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_H__ +#define __ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_H__ + +#include "BoundingBoxTransform.h" + +#include "arm_compute/core/Types.h" +#include "arm_compute/core/utils/misc/ShapeCalculator.h" +#include "tests/validation/Helpers.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace reference +{ +template <typename T> +SimpleTensor<T> bounding_box_transform(const SimpleTensor<T> &boxes, const SimpleTensor<T> &deltas, const BoundingBoxTransformInfo &info); +} // namespace reference +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_BOUNDINGBOXTRANSFORM_H__ */ |