Skip to content

Commit

Permalink
PerfectMemory: Accept non-uint8 images as inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdewar committed Jun 22, 2022
1 parent df66677 commit b047645
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 26 deletions.
11 changes: 11 additions & 0 deletions include/imgproc/convert_scale.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

// OpenCV
#include <opencv2/opencv.hpp>

namespace BoBRobotics {
namespace ImgProc {
void
convertScale(const cv::Mat &in, cv::Mat &out, int targetType);
} // ImgProc
} // BoBRobotics
67 changes: 42 additions & 25 deletions include/navigation/perfect_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -46,6 +47,7 @@ class PerfectMemory
PerfectMemory(const cv::Size &unwrapRes, Ts &&... args)
: m_UnwrapRes(unwrapRes)
, m_Store(unwrapRes, std::forward<Ts>(args)...)
, m_ScratchImage(unwrapRes, CV_8UC1)
{}

//------------------------------------------------------------------------
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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());
Expand All @@ -152,10 +138,32 @@ class PerfectMemory
tbb::parallel_for(tbb::blocked_range<size_t>(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);
}
};

//------------------------------------------------------------------------
Expand Down Expand Up @@ -223,7 +231,16 @@ class PerfectMemoryRotater : public PerfectMemory<Store>
template<class... Ts>
auto getHeading(const cv::Mat &image, ImgProc::Mask mask, typename PerfectMemory<Store>::Window window, Ts &&... args) const
{
auto rotater = InSilicoRotater::create(this->getUnwrapResolution(), mask, image, std::forward<Ts>(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<Ts>(args)...);
calcImageDifferences(window, rotater);

// Now get the minimum for each snapshot and the column this corresponds to
Expand Down
3 changes: 2 additions & 1 deletion src/imgproc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
62 changes: 62 additions & 0 deletions src/imgproc/convert_scale.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// BoB robotics includes
#include "common/macros.h"
#include "imgproc/convert_scale.h"

// Standard C++ includes
#include <limits>
#include <stdexcept>
#include <type_traits>

// Standard C includes
#include <cstdint>

// Anonymous namespace
namespace {
template<class T, typename = void>
struct ImageMax;

template<class T>
struct ImageMax<T, std::enable_if_t<std::is_unsigned<T>::value>> {
static constexpr T value = std::numeric_limits<T>::max();
};

template<class T>
struct ImageMax<T, std::enable_if_t<std::is_floating_point<T>::value>> {
static constexpr T value{ 1 };
};

#define BOB_GET_MAX(TYPE) \
case cv::DataType<TYPE>::type: \
return ImageMax<TYPE>::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

0 comments on commit b047645

Please sign in to comment.