aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Richardson <john.richardson@arm.com>2017-11-27 14:35:09 +0000
committerAnthony Barbier <anthony.barbier@arm.com>2018-11-02 16:42:33 +0000
commit25f23680b211b6dd27c006cb9575e816e8f80bb5 (patch)
treef46132851600739d8d05f7bf8e3b9b0896bd39bf
parent1d25ed54a948639d1894c8b021940df70005d519 (diff)
downloadComputeLibrary-25f23680b211b6dd27c006cb9575e816e8f80bb5.tar.gz
COMPMID-589: Port HOGDescriptor to new validation
Change-Id: I2021612e61de1b82aaeb49249d06929c7fceb15f Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/115216 Reviewed-by: Pablo Tello <pablo.tello@arm.com> Tested-by: Jenkins <bsgcomp@arm.com>
-rw-r--r--arm_compute/core/HOGInfo.h8
-rw-r--r--src/core/CL/cl_kernels/hog.cl4
-rw-r--r--src/core/HOGInfo.cpp12
-rw-r--r--tests/SimpleTensor.h9
-rw-r--r--tests/Utils.h28
-rw-r--r--tests/datasets/HOGDescriptorDataset.h137
-rw-r--r--tests/validation/CL/HOGDescriptor.cpp83
-rw-r--r--tests/validation/NEON/HOGDescriptor.cpp84
-rw-r--r--tests/validation/fixtures/HOGDescriptorFixture.h142
-rw-r--r--tests/validation/reference/HOGDescriptor.cpp273
-rw-r--r--tests/validation/reference/HOGDescriptor.h43
-rw-r--r--utils/TypePrinter.h71
12 files changed, 884 insertions, 10 deletions
diff --git a/arm_compute/core/HOGInfo.h b/arm_compute/core/HOGInfo.h
index 654629306d..f55574288e 100644
--- a/arm_compute/core/HOGInfo.h
+++ b/arm_compute/core/HOGInfo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017 ARM Limited.
+ * Copyright (c) 2016, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -123,6 +123,12 @@ public:
* @return The Size2D data object which stores the number of cells along the x and y directions
*/
Size2D num_cells_per_block() const;
+
+ /** Calculates the number of cells per block stride
+ *
+ * @return The Size2D data object which stores the number of cells per block stride along the x and y directions
+ */
+ Size2D num_cells_per_block_stride() const;
/** Calculates the number of blocks for the given image size
*
* @param[in] image_size The input image size data object
diff --git a/src/core/CL/cl_kernels/hog.cl b/src/core/CL/cl_kernels/hog.cl
index 5d3a607c44..3d37fbcaf2 100644
--- a/src/core/CL/cl_kernels/hog.cl
+++ b/src/core/CL/cl_kernels/hog.cl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -124,7 +124,7 @@ __kernel void hog_orientation_binning(IMAGE_DECLARATION(mag),
for(; xc < CELL_WIDTH; xc++)
{
const float mag_value = *((__global short *)mag_row_ptr + xc);
- const float phase_value = *(mag_row_ptr + xc) * (float)PHASE_SCALE + 0.5f;
+ const float phase_value = *(phase_row_ptr + xc) * (float)PHASE_SCALE + 0.5f;
const float w1 = phase_value - floor(phase_value);
// The quantised phase is the histogram index [0, NUM_BINS - 1]
diff --git a/src/core/HOGInfo.cpp b/src/core/HOGInfo.cpp
index 1b6175e68f..73f4c42041 100644
--- a/src/core/HOGInfo.cpp
+++ b/src/core/HOGInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017 ARM Limited.
+ * Copyright (c) 2016, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -66,10 +66,20 @@ void HOGInfo::init(const Size2D &cell_size, const Size2D &block_size, const Size
Size2D HOGInfo::num_cells_per_block() const
{
+ ARM_COMPUTE_ERROR_ON(_cell_size.width == 0 || _cell_size.height == 0);
+
return Size2D(_block_size.width / _cell_size.width,
_block_size.height / _cell_size.height);
}
+Size2D HOGInfo::num_cells_per_block_stride() const
+{
+ ARM_COMPUTE_ERROR_ON(_cell_size.width == 0 || _cell_size.height == 0);
+
+ return Size2D(_block_stride.width / _cell_size.width,
+ _block_stride.height / _cell_size.height);
+}
+
Size2D HOGInfo::num_blocks_per_image(const Size2D &image_size) const
{
return Size2D(((image_size.width - _block_size.width) / _block_stride.width) + 1,
diff --git a/tests/SimpleTensor.h b/tests/SimpleTensor.h
index 6091991e66..902f5b51b5 100644
--- a/tests/SimpleTensor.h
+++ b/tests/SimpleTensor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -191,7 +191,8 @@ SimpleTensor<T>::SimpleTensor(TensorShape shape, Format format, int fixed_point_
_fixed_point_position(fixed_point_position),
_quantization_info()
{
- _buffer = support::cpp14::make_unique<T[]>(num_elements() * num_channels());
+ _num_channels = num_channels();
+ _buffer = support::cpp14::make_unique<T[]>(num_elements() * _num_channels);
}
template <typename T>
@@ -338,13 +339,13 @@ T *SimpleTensor<T>::data()
template <typename T>
const void *SimpleTensor<T>::operator()(const Coordinates &coord) const
{
- return _buffer.get() + coord2index(_shape, coord);
+ return _buffer.get() + coord2index(_shape, coord) * _num_channels;
}
template <typename T>
void *SimpleTensor<T>::operator()(const Coordinates &coord)
{
- return _buffer.get() + coord2index(_shape, coord);
+ return _buffer.get() + coord2index(_shape, coord) * _num_channels;
}
template <typename U>
diff --git a/tests/Utils.h b/tests/Utils.h
index d5c0a36ba2..5814965a40 100644
--- a/tests/Utils.h
+++ b/tests/Utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -27,6 +27,8 @@
#include "arm_compute/core/Coordinates.h"
#include "arm_compute/core/Error.h"
#include "arm_compute/core/FixedPoint.h"
+#include "arm_compute/core/HOGInfo.h"
+#include "arm_compute/core/Size2D.h"
#include "arm_compute/core/TensorInfo.h"
#include "arm_compute/core/TensorShape.h"
#include "arm_compute/core/Types.h"
@@ -494,6 +496,30 @@ inline T create_tensor(const TensorShape &shape, Format format)
return tensor;
}
+/** Create and initialize a HOG (Histogram of Oriented Gradients) of the given type.
+ *
+ * @param[in] cell_size Cell size in pixels
+ * @param[in] block_size Block size in pixels. Must be a multiple of cell_size.
+ * @param[in] detection_window_size Detection window size in pixels. Must be a multiple of block_size and block_stride.
+ * @param[in] block_stride Distance in pixels between 2 consecutive blocks along the x and y direction. Must be a multiple of cell size
+ * @param[in] num_bins Number of histogram bins for each cell
+ * @param[in] normalization_type (Optional) Normalization type to use for each block
+ * @param[in] l2_hyst_threshold (Optional) Threshold used for L2HYS_NORM normalization method
+ * @param[in] phase_type (Optional) Type of @ref PhaseType
+ *
+ * @return Initialized HOG of given type.
+ */
+template <typename T>
+inline T create_HOG(const Size2D &cell_size, const Size2D &block_size, const Size2D &detection_window_size, const Size2D &block_stride, size_t num_bins,
+ HOGNormType normalization_type = HOGNormType::L2HYS_NORM, float l2_hyst_threshold = 0.2f, PhaseType phase_type = PhaseType::UNSIGNED)
+{
+ T hog;
+ HOGInfo hog_info(cell_size, block_size, block_size, block_stride, num_bins, normalization_type, l2_hyst_threshold, phase_type);
+ hog.init(hog_info);
+
+ return hog;
+}
+
/** Create a vector of random ROIs.
*
* @param[in] shape The shape of the input tensor.
diff --git a/tests/datasets/HOGDescriptorDataset.h b/tests/datasets/HOGDescriptorDataset.h
new file mode 100644
index 0000000000..73c64946ec
--- /dev/null
+++ b/tests/datasets/HOGDescriptorDataset.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2017, 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_HOG_DESCRIPTOR_DATASET
+#define ARM_COMPUTE_TEST_HOG_DESCRIPTOR_DATASET
+
+#include "utils/TypePrinter.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace datasets
+{
+class HOGDescriptorDataset
+{
+public:
+ using type = std::tuple<std::string, HOGInfo>;
+
+ struct iterator
+ {
+ iterator(std::vector<std::string>::const_iterator image_it,
+ std::vector<HOGInfo>::const_iterator hog_info_it)
+ : _image_it{ std::move(image_it) },
+ _hog_info_it{ std::move(hog_info_it) }
+ {
+ }
+
+ std::string description() const
+ {
+ std::stringstream description;
+ description << "Image=" << *_image_it << ":";
+ description << "HOGInfo=" << *_hog_info_it;
+
+ return description.str();
+ }
+
+ HOGDescriptorDataset::type operator*() const
+ {
+ return std::make_tuple(*_image_it, *_hog_info_it);
+ }
+
+ iterator &operator++()
+ {
+ ++_image_it;
+ ++_hog_info_it;
+
+ return *this;
+ }
+
+ private:
+ std::vector<std::string>::const_iterator _image_it;
+ std::vector<HOGInfo>::const_iterator _hog_info_it;
+ };
+
+ iterator begin() const
+ {
+ return iterator(_image.begin(), _hog_info.begin());
+ }
+
+ int size() const
+ {
+ return std::min(_image.size(), _hog_info.size());
+ }
+
+ void add_config(std::string image,
+ Size2D cell_size, Size2D block_size, Size2D detection_window_size, Size2D block_stride,
+ size_t num_bins, HOGNormType normalization_type, float l2_hyst_threshold, PhaseType phase_type)
+ {
+ _image.emplace_back(std::move(image));
+ _hog_info.emplace_back(HOGInfo(cell_size, block_size, detection_window_size, block_stride, num_bins, normalization_type, l2_hyst_threshold, phase_type));
+ }
+
+protected:
+ HOGDescriptorDataset() = default;
+ HOGDescriptorDataset(HOGDescriptorDataset &&) = default;
+
+private:
+ std::vector<std::string> _image{};
+ std::vector<HOGInfo> _hog_info{};
+};
+
+// *INDENT-OFF*
+// clang-format off
+class SmallHOGDescriptorDataset final : public HOGDescriptorDataset
+{
+public:
+ SmallHOGDescriptorDataset()
+ {
+ // image cell_size block_size detection_size block_stride bin normalization_type thresh phase_type
+ add_config("800x600.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2HYS_NORM, 0.2f, PhaseType::SIGNED);
+ add_config("800x600.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2HYS_NORM, 0.2f, PhaseType::UNSIGNED);
+ }
+};
+
+class LargeHOGDescriptorDataset final : public HOGDescriptorDataset
+{
+public:
+ LargeHOGDescriptorDataset()
+ {
+ // image cell_size block_size detection_size block_stride bin normalization_type thresh phase_type
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2HYS_NORM, 0.2f, PhaseType::SIGNED);
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2_NORM, 0.2f, PhaseType::SIGNED);
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L1_NORM, 0.2f, PhaseType::SIGNED);
+
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2HYS_NORM, 0.2f, PhaseType::UNSIGNED);
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L2_NORM, 0.2f, PhaseType::UNSIGNED);
+ add_config("1920x1080.ppm", Size2D(8U, 8U), Size2D(16U, 16U), Size2D(64U, 128U), Size2D(8U, 8U), 9U, HOGNormType::L1_NORM, 0.2f, PhaseType::UNSIGNED);
+ }
+};
+// clang-format on
+// *INDENT-ON*
+
+} // namespace datasets
+} // namespace test
+} // namespace arm_compute
+#endif /* ARM_COMPUTE_TEST_HOG_DESCRIPTOR_DATASET */
diff --git a/tests/validation/CL/HOGDescriptor.cpp b/tests/validation/CL/HOGDescriptor.cpp
new file mode 100644
index 0000000000..aef265a657
--- /dev/null
+++ b/tests/validation/CL/HOGDescriptor.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, 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/CLHOG.h"
+#include "arm_compute/runtime/CL/functions/CLHOGDescriptor.h"
+#include "arm_compute/runtime/Tensor.h"
+#include "arm_compute/runtime/TensorAllocator.h"
+#include "tests/CL/CLAccessor.h"
+#include "tests/PaddingCalculator.h"
+#include "tests/datasets/BorderModeDataset.h"
+#include "tests/datasets/HOGDescriptorDataset.h"
+#include "tests/datasets/ShapeDatasets.h"
+#include "tests/framework/Asserts.h"
+#include "tests/framework/Macros.h"
+#include "tests/framework/datasets/Datasets.h"
+#include "tests/validation/Validation.h"
+#include "tests/validation/fixtures/HOGDescriptorFixture.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+namespace
+{
+AbsoluteTolerance<float> tolerance(1e-2f);
+} // namespace
+
+TEST_SUITE(CL)
+TEST_SUITE(HOGDescriptor)
+
+using CLHOGDescriptorFixture = HOGDescriptorValidationFixture<CLTensor, CLHOG, CLAccessor, CLHOGDescriptor, uint8_t, float>;
+
+// *INDENT-OFF*
+// clang-format off
+FIXTURE_DATA_TEST_CASE(RunSmall, CLHOGDescriptorFixture, framework::DatasetMode::PRECOMMIT,
+ combine(combine(
+ datasets::SmallHOGDescriptorDataset(),
+ framework::dataset::make("Format", Format::U8)),
+ framework::dataset::make("BorderMode", {BorderMode::CONSTANT, BorderMode::REPLICATE})))
+{
+ // Validate output
+ validate(CLAccessor(_target), _reference, tolerance);
+}
+
+FIXTURE_DATA_TEST_CASE(RunLarge, CLHOGDescriptorFixture, framework::DatasetMode::NIGHTLY,
+ combine(combine(
+ datasets::LargeHOGDescriptorDataset(),
+ framework::dataset::make("Format", Format::U8)),
+ framework::dataset::make("BorderMode", {BorderMode::CONSTANT, BorderMode::REPLICATE})))
+{
+ // Validate output
+ validate(CLAccessor(_target), _reference, tolerance);
+}
+// clang-format on
+// *INDENT-ON*
+
+TEST_SUITE_END()
+TEST_SUITE_END()
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
diff --git a/tests/validation/NEON/HOGDescriptor.cpp b/tests/validation/NEON/HOGDescriptor.cpp
new file mode 100644
index 0000000000..5f31773aad
--- /dev/null
+++ b/tests/validation/NEON/HOGDescriptor.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017, 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/HOG.h"
+#include "arm_compute/runtime/NEON/functions/NEHOGDescriptor.h"
+#include "arm_compute/runtime/Tensor.h"
+#include "arm_compute/runtime/TensorAllocator.h"
+#include "tests/NEON/Accessor.h"
+#include "tests/PaddingCalculator.h"
+#include "tests/datasets/BorderModeDataset.h"
+#include "tests/datasets/HOGDescriptorDataset.h"
+#include "tests/datasets/ShapeDatasets.h"
+#include "tests/framework/Asserts.h"
+#include "tests/framework/Macros.h"
+#include "tests/framework/datasets/Datasets.h"
+#include "tests/validation/Validation.h"
+#include "tests/validation/fixtures/HOGDescriptorFixture.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+namespace
+{
+AbsoluteTolerance<float> tolerance(0.5f);
+constexpr float tolerance_number = 0.01f;
+} // namespace
+
+TEST_SUITE(NEON)
+TEST_SUITE(HOGDescriptor)
+
+// *INDENT-OFF*
+// clang-format off
+using NEHOGDescriptorFixture = HOGDescriptorValidationFixture<Tensor, HOG, Accessor, NEHOGDescriptor, uint8_t, float>;
+
+FIXTURE_DATA_TEST_CASE(RunSmall, NEHOGDescriptorFixture, framework::DatasetMode::PRECOMMIT,
+ combine(combine(
+ datasets::SmallHOGDescriptorDataset(),
+ framework::dataset::make("Format", Format::U8)),
+ framework::dataset::make("BorderMode", {BorderMode::CONSTANT, BorderMode::REPLICATE})))
+{
+ // Validate output
+ validate(Accessor(_target), _reference, tolerance, tolerance_number);
+}
+
+FIXTURE_DATA_TEST_CASE(RunLarge, NEHOGDescriptorFixture, framework::DatasetMode::NIGHTLY,
+ combine(combine(
+ datasets::LargeHOGDescriptorDataset(),
+ framework::dataset::make("Format", Format::U8)),
+ framework::dataset::make("BorderMode", {BorderMode::CONSTANT, BorderMode::REPLICATE})))
+{
+ // Validate output
+ validate(Accessor(_target), _reference, tolerance, tolerance_number);
+}
+// clang-format on
+// *INDENT-ON*
+
+TEST_SUITE_END()
+TEST_SUITE_END()
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
diff --git a/tests/validation/fixtures/HOGDescriptorFixture.h b/tests/validation/fixtures/HOGDescriptorFixture.h
new file mode 100644
index 0000000000..cabee63ae3
--- /dev/null
+++ b/tests/validation/fixtures/HOGDescriptorFixture.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017, 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_HOG_DESCRIPTOR_FIXTURE
+#define ARM_COMPUTE_TEST_HOG_DESCRIPTOR_FIXTURE
+
+#include "arm_compute/core/HOGInfo.h"
+#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/reference/HOGDescriptor.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+template <typename TensorType, typename HOGType, typename AccessorType, typename FunctionType, typename T, typename U>
+class HOGDescriptorValidationFixture : public framework::Fixture
+{
+public:
+ template <typename...>
+ void setup(std::string image, HOGInfo hog_info, Format format, BorderMode border_mode)
+ {
+ // Only defined borders supported
+ ARM_COMPUTE_ERROR_ON(border_mode == BorderMode::UNDEFINED);
+
+ // Generate a random constant value
+ std::mt19937 gen(library->seed());
+ std::uniform_int_distribution<T> int_dist(0, 255);
+ const T constant_border_value = int_dist(gen);
+
+ _target = compute_target(image, format, border_mode, constant_border_value, hog_info);
+ _reference = compute_reference(image, format, border_mode, constant_border_value, hog_info);
+ }
+
+protected:
+ template <typename V>
+ void fill(V &&tensor, const std::string image, Format format)
+ {
+ library->fill(tensor, image, format);
+ }
+
+ template <typename V, typename D>
+ void fill(V &&tensor, int i, D max)
+ {
+ library->fill_tensor_uniform(tensor, i, static_cast<D>(0), max);
+ }
+
+ TensorType compute_target(const std::string image, Format &format, BorderMode &border_mode, T constant_border_value, const HOGInfo &hog_info)
+ {
+ // Get image shape for src tensor
+ TensorShape shape = library->get_image_shape(image);
+
+ // Create tensor info for HOG descriptor
+ TensorInfo tensor_info_hog_descriptor(hog_info, shape.x(), shape.y());
+
+ // Create HOG
+ HOGType hog = create_HOG<HOGType>(hog_info.cell_size(),
+ hog_info.block_size(),
+ hog_info.detection_window_size(),
+ hog_info.block_stride(),
+ hog_info.num_bins(),
+ hog_info.normalization_type(),
+ hog_info.l2_hyst_threshold(),
+ hog_info.phase_type());
+
+ // Create tensors
+ TensorType src = create_tensor<TensorType>(shape, data_type_from_format(format));
+ TensorType dst = create_tensor<TensorType>(tensor_info_hog_descriptor.tensor_shape(), DataType::F32, tensor_info_hog_descriptor.num_channels());
+
+ ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+
+ // Create and configure function
+ FunctionType hog_descriptor;
+ hog_descriptor.configure(&src, &dst, &hog, border_mode, constant_border_value);
+
+ ARM_COMPUTE_EXPECT(src.info()->is_resizable(), framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+ ARM_COMPUTE_EXPECT(!src.info()->is_resizable(), framework::LogLevel::ERRORS);
+ ARM_COMPUTE_EXPECT(!dst.info()->is_resizable(), framework::LogLevel::ERRORS);
+
+ const T max = std::numeric_limits<T>::max();
+
+ // Fill tensors
+ fill(AccessorType(src), image, format);
+ fill(AccessorType(dst), 1, static_cast<U>(max));
+
+ // Compute function
+ hog_descriptor.run();
+
+ return dst;
+ }
+
+ SimpleTensor<U> compute_reference(const std::string image, Format format, BorderMode border_mode, T constant_border_value, const HOGInfo &hog_info)
+ {
+ // Create reference
+ SimpleTensor<T> src{ library->get_image_shape(image), data_type_from_format(format) };
+
+ // Fill reference
+ fill(src, image, format);
+
+ return reference::hog_descriptor<U>(src, border_mode, constant_border_value, hog_info);
+ }
+
+ TensorType _target{};
+ SimpleTensor<U> _reference{};
+};
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
+#endif /* ARM_COMPUTE_TEST_HOG_DESCRIPTOR_FIXTURE */
diff --git a/tests/validation/reference/HOGDescriptor.cpp b/tests/validation/reference/HOGDescriptor.cpp
new file mode 100644
index 0000000000..369ac74edc
--- /dev/null
+++ b/tests/validation/reference/HOGDescriptor.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2017, 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 "HOGDescriptor.h"
+
+#include "Derivative.h"
+#include "Magnitude.h"
+#include "Phase.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+namespace reference
+{
+namespace
+{
+template <typename T>
+void hog_orientation_compute(const SimpleTensor<T> &mag, const SimpleTensor<T> &phase, std::vector<T> &bins, const HOGInfo &hog_info)
+{
+ const size_t num_bins = hog_info.num_bins();
+ const size_t cell_height = hog_info.cell_size().height;
+ const size_t cell_width = hog_info.cell_size().width;
+
+ float phase_scale = (PhaseType::SIGNED == hog_info.phase_type() ? num_bins / 360.0f : num_bins / 180.0f);
+ phase_scale *= (PhaseType::SIGNED == hog_info.phase_type() ? 360.0f / 255.0f : 1.0f);
+
+ int row_idx = 0;
+ for(size_t yc = 0; yc < cell_height; ++yc)
+ {
+ for(size_t xc = 0; xc < cell_height; xc++)
+ {
+ const float mag_value = mag[(row_idx + xc)];
+ const float phase_value = phase[(row_idx + xc)] * phase_scale + 0.5f;
+ const float w1 = phase_value - floor(phase_value);
+
+ // The quantised phase is the histogram index [0, num_bins - 1]
+ // Check limit of histogram index. If hidx == num_bins, hidx = 0
+ const auto hidx = static_cast<unsigned int>(phase_value) % num_bins;
+
+ // Weighted vote between 2 bins
+ bins[hidx] += mag_value * (1.0f - w1);
+ bins[(hidx + 1) % num_bins] += mag_value * w1;
+ }
+
+ row_idx += cell_width;
+ }
+}
+
+template <typename T>
+void hog_block_normalization_compute(SimpleTensor<T> &block, SimpleTensor<T> &desc, const HOGInfo &hog_info, size_t block_idx)
+{
+ const int num_bins_per_block = desc.num_channels();
+ const HOGNormType norm_type = hog_info.normalization_type();
+ const Coordinates id = index2coord(desc.shape(), block_idx);
+
+ float sum = 0.0f;
+
+ // Calculate sum
+ for(int i = 0; i < num_bins_per_block; ++i)
+ {
+ const float val = block[i];
+ sum += (norm_type == HOGNormType::L1_NORM) ? std::fabs(val) : val * val;
+ }
+
+ // Calculate normalization scale
+ float scale = 1.0f / (std::sqrt(sum) + num_bins_per_block * 0.1f);
+
+ if(norm_type == HOGNormType::L2HYS_NORM)
+ {
+ // Reset sum
+ sum = 0.0f;
+ for(int i = 0; i < num_bins_per_block; ++i)
+ {
+ float val = block[i] * scale;
+
+ // Clip scaled input_value if over l2_hyst_threshold
+ val = fmin(val, hog_info.l2_hyst_threshold());
+ sum += val * val;
+ block[i] = val;
+ }
+
+ // We use the same constants of OpenCV
+ scale = 1.0f / (std::sqrt(sum) + 1e-3f);
+ }
+
+ for(int i = 0; i < num_bins_per_block; ++i)
+ {
+ block[i] *= scale;
+ reinterpret_cast<float *>(desc(id))[i] = block[i];
+ }
+}
+} // namespace
+
+template <typename T, typename U, typename V>
+void hog_orientation_binning(const SimpleTensor<T> &mag, const SimpleTensor<U> &phase, SimpleTensor<V> &hog_space, const HOGInfo &hog_info)
+{
+ const size_t cell_width = hog_info.cell_size().width;
+ const size_t cell_height = hog_info.cell_size().height;
+ const size_t shape_width = hog_space.shape().x() * hog_info.cell_size().width;
+ const size_t shape_height = hog_space.shape().y() * hog_info.cell_size().height;
+
+ SimpleTensor<V> mag_cell(TensorShape(cell_width, cell_height), DataType::F32);
+ SimpleTensor<V> phase_cell(TensorShape(cell_width, cell_height), DataType::F32);
+
+ int cell_idx = 0;
+ int y_offset = 0;
+ int x_offset = 0;
+
+ // Traverse shape
+ for(auto sy = cell_height - 1; sy < shape_height; sy += cell_height)
+ {
+ x_offset = 0;
+ for(auto sx = cell_width - 1; sx < shape_width; sx += cell_width)
+ {
+ int row_idx = 0;
+ int elem_idx = 0;
+
+ // Traverse cell
+ for(auto y = 0u; y < cell_height; ++y)
+ {
+ for(auto x = 0u; x < cell_width; ++x)
+ {
+ int shape_idx = x + row_idx + x_offset + y_offset;
+ mag_cell[elem_idx] = mag[shape_idx];
+ phase_cell[elem_idx] = phase[shape_idx];
+ elem_idx++;
+ }
+
+ row_idx += shape_width;
+ }
+
+ // Partition magnitude values into bins based on phase values
+ std::vector<V> bins(hog_info.num_bins());
+ hog_orientation_compute(mag_cell, phase_cell, bins, hog_info);
+
+ for(size_t i = 0; i < hog_info.num_bins(); ++i)
+ {
+ hog_space[cell_idx * hog_info.num_bins() + i] = bins[i];
+ }
+
+ x_offset += cell_width;
+ cell_idx++;
+ }
+
+ y_offset += (cell_height * shape_width);
+ }
+}
+
+template <typename T>
+void hog_block_normalization(SimpleTensor<T> &desc, const SimpleTensor<T> &hog_space, const HOGInfo &hog_info)
+{
+ const Size2D cells_per_block = hog_info.num_cells_per_block();
+ const Size2D cells_per_block_stride = hog_info.num_cells_per_block_stride();
+
+ const size_t block_width = hog_info.block_size().width;
+ const size_t block_height = hog_info.block_size().height;
+ const size_t block_stride_width = hog_info.block_stride().width;
+ const size_t block_stride_height = hog_info.block_stride().height;
+ const size_t shape_width = hog_space.shape().x() * hog_info.cell_size().width;
+ const size_t shape_height = hog_space.shape().y() * hog_info.cell_size().height;
+
+ const size_t num_bins = hog_info.num_bins();
+ const size_t num_channels = cells_per_block.area() * num_bins;
+
+ SimpleTensor<T> block(TensorShape{ 1u, 1u }, DataType::F32, num_channels);
+
+ int block_idx = 0;
+ int block_y_offset = 0;
+
+ // Traverse shape
+ for(auto sy = block_width - 1; sy < shape_height; sy += block_stride_height)
+ {
+ int block_x_offset = 0;
+ for(auto sx = block_height - 1; sx < shape_width; sx += block_stride_width)
+ {
+ int cell_y_offset = 0;
+ int elem_idx = 0;
+
+ // Traverse block
+ for(auto y = 0u; y < cells_per_block.height; ++y)
+ {
+ int cell_x_offset = 0;
+ for(auto x = 0u; x < cells_per_block.width; ++x)
+ {
+ for(auto bin = 0u; bin < num_bins; ++bin)
+ {
+ int idx = bin + cell_x_offset + cell_y_offset + block_x_offset + block_y_offset;
+ block[elem_idx] = hog_space[idx];
+ elem_idx++;
+ }
+
+ cell_x_offset += num_bins;
+ }
+
+ cell_y_offset += hog_space.shape().x() * num_bins;
+ }
+
+ // Normalize block and write to descriptor
+ hog_block_normalization_compute(block, desc, hog_info, block_idx);
+
+ block_x_offset += cells_per_block_stride.width * num_bins;
+ block_idx++;
+ }
+
+ block_y_offset += cells_per_block_stride.height * num_bins * hog_space.shape().x();
+ }
+}
+
+template <typename T, typename U>
+SimpleTensor<T> hog_descriptor(const SimpleTensor<U> &src, BorderMode border_mode, U constant_border_value, const HOGInfo &hog_info)
+{
+ SimpleTensor<int16_t> _mag;
+ SimpleTensor<uint8_t> _phase;
+
+ SimpleTensor<int16_t> grad_x;
+ SimpleTensor<int16_t> grad_y;
+
+ // Create tensor info for HOG descriptor
+ TensorInfo desc_info(hog_info, src.shape().x(), src.shape().y());
+ SimpleTensor<T> desc(desc_info.tensor_shape(), DataType::F32, desc_info.num_channels());
+
+ // Create HOG space tensor (num_cells_x, num_cells_y)
+ TensorShape hog_space_shape(src.shape().x() / hog_info.cell_size().width,
+ src.shape().y() / hog_info.cell_size().height);
+
+ // For each cell a histogram with a num_bins is created
+ TensorInfo info_hog_space(hog_space_shape, hog_info.num_bins(), DataType::F32);
+ SimpleTensor<T> hog_space(info_hog_space.tensor_shape(), DataType::F32, info_hog_space.num_channels());
+
+ // Calculate derivative
+ std::tie(grad_x, grad_y) = derivative<int16_t>(src, border_mode, constant_border_value, GradientDimension::GRAD_XY);
+
+ // Calculate magnitude and phase
+ _mag = magnitude(grad_x, grad_y, MagnitudeType::L2NORM);
+ _phase = phase(grad_x, grad_y, hog_info.phase_type());
+
+ // For each cell create histogram based on magnitude and phase
+ hog_orientation_binning(_mag, _phase, hog_space, hog_info);
+
+ // Normalize histograms based on block size
+ hog_block_normalization(desc, hog_space, hog_info);
+
+ return desc;
+}
+
+template SimpleTensor<float> hog_descriptor(const SimpleTensor<uint8_t> &src, BorderMode border_mode, uint8_t constant_border_value, const HOGInfo &hog_info);
+} // namespace reference
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
diff --git a/tests/validation/reference/HOGDescriptor.h b/tests/validation/reference/HOGDescriptor.h
new file mode 100644
index 0000000000..e886445ec7
--- /dev/null
+++ b/tests/validation/reference/HOGDescriptor.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017, 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_HOG_DESCRIPTOR_H__
+#define __ARM_COMPUTE_TEST_HOG_DESCRIPTOR_H__
+
+#include "tests/SimpleTensor.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace validation
+{
+namespace reference
+{
+template <typename T, typename U>
+SimpleTensor<T> hog_descriptor(const SimpleTensor<U> &src, BorderMode border_mode, U constant_border_value, const HOGInfo &hog_info);
+} // namespace reference
+} // namespace validation
+} // namespace test
+} // namespace arm_compute
+#endif /* __ARM_COMPUTE_TEST_HOG_DESCRIPTOR_H__ */
diff --git a/utils/TypePrinter.h b/utils/TypePrinter.h
index 22e6554224..5805ee6ed0 100644
--- a/utils/TypePrinter.h
+++ b/utils/TypePrinter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017, 2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -26,6 +26,8 @@
#include "arm_compute/core/Dimensions.h"
#include "arm_compute/core/Error.h"
+#include "arm_compute/core/HOGInfo.h"
+#include "arm_compute/core/Size2D.h"
#include "arm_compute/core/Strides.h"
#include "arm_compute/core/TensorInfo.h"
#include "arm_compute/core/Types.h"
@@ -856,5 +858,72 @@ inline std::string to_string(const arm_compute::GradientDimension &type)
str << type;
return str.str();
}
+
+/** Formatted output of the HOGNormType type. */
+inline ::std::ostream &operator<<(::std::ostream &os, const HOGNormType &norm_type)
+{
+ switch(norm_type)
+ {
+ case HOGNormType::L1_NORM:
+ os << "L1_NORM";
+ break;
+ case HOGNormType::L2_NORM:
+ os << "L2_NORM";
+ break;
+ case HOGNormType::L2HYS_NORM:
+ os << "L2HYS_NORM";
+ break;
+ default:
+ ARM_COMPUTE_ERROR("NOT_SUPPORTED!");
+ }
+
+ return os;
+}
+
+inline std::string to_string(const HOGNormType &type)
+{
+ std::stringstream str;
+ str << type;
+ return str.str();
+}
+
+/** Formatted output of the Size2D type. */
+inline ::std::ostream &operator<<(::std::ostream &os, const Size2D &size)
+{
+ os << size.width << "x" << size.height;
+
+ return os;
+}
+
+inline std::string to_string(const Size2D &type)
+{
+ std::stringstream str;
+ str << type;
+ return str.str();
+}
+
+/** Formatted output of the Size2D type. */
+inline ::std::ostream &operator<<(::std::ostream &os, const HOGInfo &hog_info)
+{
+ os << "{CellSize=" << hog_info.cell_size() << ","
+ << "BlockSize=" << hog_info.block_size() << ","
+ << "DetectionWindowSize=" << hog_info.detection_window_size() << ","
+ << "BlockStride=" << hog_info.block_stride() << ","
+ << "NumBins=" << hog_info.num_bins() << ","
+ << "NormType=" << hog_info.normalization_type() << ","
+ << "L2HystThreshold=" << hog_info.l2_hyst_threshold() << ","
+ << "PhaseType=" << hog_info.phase_type() << "}";
+
+ return os;
+}
+
+/** Formatted output of the HOGInfo type. */
+inline std::string to_string(const HOGInfo &type)
+{
+ std::stringstream str;
+ str << type;
+ return str.str();
+}
+
} // namespace arm_compute
#endif /* __ARM_COMPUTE_TEST_TYPE_PRINTER_H__ */