From b047645f2f8e98f2e2253adf4ccf5f3c381fb1c2 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Wed, 22 Jun 2022 12:52:31 +0100 Subject: [PATCH] PerfectMemory: Accept non-uint8 images as inputs --- include/imgproc/convert_scale.h | 11 +++++ include/navigation/perfect_memory.h | 67 ++++++++++++++++++----------- src/imgproc/CMakeLists.txt | 3 +- src/imgproc/convert_scale.cc | 62 ++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 26 deletions(-) create mode 100644 include/imgproc/convert_scale.h create mode 100644 src/imgproc/convert_scale.cc diff --git a/include/imgproc/convert_scale.h b/include/imgproc/convert_scale.h new file mode 100644 index 000000000..e1ea3313e --- /dev/null +++ b/include/imgproc/convert_scale.h @@ -0,0 +1,11 @@ +#pragma once + +// OpenCV +#include + +namespace BoBRobotics { +namespace ImgProc { +void +convertScale(const cv::Mat &in, cv::Mat &out, int targetType); +} // ImgProc +} // BoBRobotics diff --git a/include/navigation/perfect_memory.h b/include/navigation/perfect_memory.h index 00be9b6b5..6e114492b 100644 --- a/include/navigation/perfect_memory.h +++ b/include/navigation/perfect_memory.h @@ -2,9 +2,10 @@ // BoB robotics includes #include "common/macros.h" -#include "differencers.h" -#include "insilico_rotater.h" -#include "perfect_memory_store_raw.h" +#include "imgproc/convert_scale.h" +#include "navigation/differencers.h" +#include "navigation/insilico_rotater.h" +#include "navigation/perfect_memory_store_raw.h" // Third-party includes #include "third_party/units.h" @@ -46,6 +47,7 @@ class PerfectMemory PerfectMemory(const cv::Size &unwrapRes, Ts &&... args) : m_UnwrapRes(unwrapRes) , m_Store(unwrapRes, std::forward(args)...) + , m_ScratchImage(unwrapRes, CV_8UC1) {} //------------------------------------------------------------------------ @@ -58,13 +60,10 @@ class PerfectMemory //------------------------------------------------------------------------ void train(const cv::Mat &image, const ImgProc::Mask &mask = ImgProc::Mask{}) { - const auto &unwrapRes = getUnwrapResolution(); - BOB_ASSERT(image.cols == unwrapRes.width); - BOB_ASSERT(image.rows == unwrapRes.height); - BOB_ASSERT(image.type() == CV_8UC1); + convertImage(image); // Add snapshot - m_Store.addSnapshot(image, mask); + m_Store.addSnapshot(m_ScratchImage, mask); } float test(const cv::Mat &image, const ImgProc::Mask &mask, const Window &window) const @@ -116,16 +115,6 @@ class PerfectMemory //! Get the resolution of images const cv::Size &getUnwrapResolution() const { return m_UnwrapRes; } -protected: - //------------------------------------------------------------------------ - // Protected API - //------------------------------------------------------------------------ - float calcSnapshotDifference(const cv::Mat &image, - const ImgProc::Mask &mask, size_t snapshot) const - { - return m_Store.calcSnapshotDifference(image, mask, snapshot); - } - private: //------------------------------------------------------------------------ // Private members @@ -136,11 +125,8 @@ class PerfectMemory void testInternal(const cv::Mat &image, const ImgProc::Mask &mask, const Window &window) const { - const auto &unwrapRes = getUnwrapResolution(); - BOB_ASSERT(image.cols == unwrapRes.width); - BOB_ASSERT(image.rows == unwrapRes.height); - BOB_ASSERT(image.type() == CV_8UC1); - BOB_ASSERT(mask.isValid(unwrapRes)); + convertImage(image); + BOB_ASSERT(mask.isValid(getUnwrapResolution())); BOB_ASSERT(window.first < getNumSnapshots()); BOB_ASSERT(window.second <= getNumSnapshots()); @@ -152,10 +138,32 @@ class PerfectMemory tbb::parallel_for(tbb::blocked_range(window.first, window.second), [&](const auto &r) { for (size_t s = r.begin(); s != r.end(); ++s) { - m_Differences[s - window.first] = calcSnapshotDifference(image, mask, s); + m_Differences[s - window.first] = calcSnapshotDifference(m_ScratchImage, mask, s); } }); } + +protected: + //------------------------------------------------------------------------ + // Protected API + //------------------------------------------------------------------------ + mutable cv::Mat m_ScratchImage; + + float calcSnapshotDifference(const cv::Mat &image, + const ImgProc::Mask &mask, size_t snapshot) const + { + return m_Store.calcSnapshotDifference(image, mask, snapshot); + } + + void convertImage(const cv::Mat &image) const + { + BOB_ASSERT(image.channels() == 1); + const auto &unwrapRes = getUnwrapResolution(); + BOB_ASSERT(image.cols == unwrapRes.width); + BOB_ASSERT(image.rows == unwrapRes.height); + + ImgProc::convertScale(image, m_ScratchImage, CV_8U); + } }; //------------------------------------------------------------------------ @@ -223,7 +231,16 @@ class PerfectMemoryRotater : public PerfectMemory template auto getHeading(const cv::Mat &image, ImgProc::Mask mask, typename PerfectMemory::Window window, Ts &&... args) const { - auto rotater = InSilicoRotater::create(this->getUnwrapResolution(), mask, image, std::forward(args)...); + /* + * We don't *need* to do this conversion here, as + * PerfectMemory<>::test() will accept non-uint8 images as inputs, but + * by doing so we only have to do the conversion once as opposed to once + * per rotation. + */ + this->convertImage(image); + auto rotater = InSilicoRotater::create(this->getUnwrapResolution(), + mask, this->m_ScratchImage, + std::forward(args)...); calcImageDifferences(window, rotater); // Now get the minimum for each snapshot and the column this corresponds to diff --git a/src/imgproc/CMakeLists.txt b/src/imgproc/CMakeLists.txt index f2efcf9c3..4ff86684c 100644 --- a/src/imgproc/CMakeLists.txt +++ b/src/imgproc/CMakeLists.txt @@ -3,7 +3,8 @@ include(../../cmake/BoBRobotics.cmake) project(imgproc) find_package(BoBRobotics REQUIRED COMPONENTS common) -BoB_module(bee_eye.cc mask.cc opencv_optical_flow.cc opencv_unwrap_360.cc roll.cc) +BoB_module(bee_eye.cc convert_scale.cc mask.cc opencv_optical_flow.cc + opencv_unwrap_360.cc roll.cc) find_package(OpenCV REQUIRED) target_include_directories(${BOB_MODULE_TARGET} PUBLIC ${OpenCV_INCLUDE_DIRS}) diff --git a/src/imgproc/convert_scale.cc b/src/imgproc/convert_scale.cc new file mode 100644 index 000000000..5ff6e00fb --- /dev/null +++ b/src/imgproc/convert_scale.cc @@ -0,0 +1,62 @@ +// BoB robotics includes +#include "common/macros.h" +#include "imgproc/convert_scale.h" + +// Standard C++ includes +#include +#include +#include + +// Standard C includes +#include + +// Anonymous namespace +namespace { +template +struct ImageMax; + +template +struct ImageMax::value>> { + static constexpr T value = std::numeric_limits::max(); +}; + +template +struct ImageMax::value>> { + static constexpr T value{ 1 }; +}; + +#define BOB_GET_MAX(TYPE) \ + case cv::DataType::type: \ + return ImageMax::value + +inline double +getMax(int type) +{ + switch (type) { + BOB_GET_MAX(uchar); + BOB_GET_MAX(uint16_t); + BOB_GET_MAX(float); + BOB_GET_MAX(double); + default: + throw std::invalid_argument("Unsupported matrix type"); + } +} +} + +namespace BoBRobotics { +namespace ImgProc { +void +convertScale(const cv::Mat &in, cv::Mat &out, int targetType) +{ + BOB_ASSERT(in.channels() == 1); + + if (in.type() == targetType) { + out = in; + return; + } + + in.convertTo(out, targetType, getMax(targetType) / getMax(in.type())); +} + +} // ImgProc +} // BoBRobotics