Skip to content

Instantly share code, notes, and snippets.

@yudi-matsuzake
Last active February 1, 2019 12:56
Show Gist options
  • Save yudi-matsuzake/9e74dfa87a70d95ce74ef11d3f56a634 to your computer and use it in GitHub Desktop.
Save yudi-matsuzake/9e74dfa87a70d95ce74ef11d3f56a634 to your computer and use it in GitHub Desktop.
c++17 opencv adaptors
/** @file iterator.hpp
* Implementation of adaptors to help common
* objects manipulation
*/
#pragma once
#include <type_traits>
#include <opencv2/core/core.hpp>
namespace cv{
template <bool C, class A, class B>
struct type_if_else{};
template <class A, class B>
struct type_if_else<true, A, B>{
typedef A type;
};
template <class A, class B>
struct type_if_else<false, A, B>{
typedef B type;
};
/*
* adaptors for opencv
* -------------------
*/
template<class pixel_type, class M>
class pixels_iterator_adaptor{
public:
pixels_iterator_adaptor() = delete;
virtual ~pixels_iterator_adaptor() = default;
explicit pixels_iterator_adaptor(M& a_reference) noexcept
: m_reference(a_reference)
{}
auto begin()
{
return m_reference.template begin<pixel_type>();
}
auto begin() const
{
return m_reference.template begin<pixel_type>();
}
auto end()
{
return m_reference.template end<pixel_type>();
}
auto end() const
{
return m_reference.template end<pixel_type>();
}
protected:
M& m_reference;
};
/**
* build an adaptor to transverse the pixels of an opencv image
*/
template<class T>
auto pixels(cv::Mat& img)
{
return pixels_iterator_adaptor<T, cv::Mat>(img);
}
/**
* build an adaptor to transverse the pixels of an opencv image
*/
template<class T>
auto pixels(cv::Mat const& img)
{
return pixels_iterator_adaptor<T, cv::Mat const>(img);
}
template<class T, class I, class M>
class pixel_point_iterator : public I {
protected:
// type of the reference that will be returned in operator*
using return_reference_type = typename type_if_else<
std::is_same<I, cv::MatIterator_<T>>::value,
T,
T const
>::type;
public:
pixel_point_iterator() = delete;
virtual ~pixel_point_iterator() = default;
pixel_point_iterator(
I it,
cv::Point2i& a_coordinate,
M& a_img)
: I(it),
m_coordinate(a_coordinate),
m_rows(a_img.rows),
m_cols(a_img.cols)
{}
pixel_point_iterator& operator++()
{
++m_coordinate.x;
if(m_coordinate.x == m_cols){
m_coordinate.x = 0;
++m_coordinate.y;
}
I::operator++();
return *this;
}
pixel_point_iterator operator++(int)
{
++m_coordinate.x;
if(m_coordinate.x == m_cols){
m_coordinate.x = 0;
++m_coordinate.y;
}
I::operator++(0);
return *this;
}
std::tuple<return_reference_type&, cv::Point2i&> operator*()
{
return { I::operator*(), m_coordinate };
}
protected:
cv::Point2i& m_coordinate;
int32_t m_rows;
int32_t m_cols;
};
template<class T, class I, class M>
class pixel_point_iterator_adaptor{
public:
pixel_point_iterator_adaptor() = delete;
virtual ~pixel_point_iterator_adaptor() = default;
pixel_point_iterator_adaptor(M& a_img)
: m_reference(a_img),
m_point{0, 0}
{}
auto begin()
{
return pixel_point_iterator<T, I, M>(
m_reference.template begin<T>(),
m_point,
m_reference
);
}
auto begin() const
{
return pixel_point_iterator<T, I, M>(
m_reference.template begin<T>(),
m_point,
m_reference
);
}
auto end()
{
return pixel_point_iterator<T, I, M>(
m_reference.template end<T>(),
m_point,
m_reference
);
}
auto end() const
{
return pixel_point_iterator<T, I, M>(
m_reference.template end<T>(),
m_point,
m_reference
);
}
protected:
M& m_reference;
cv::Point2i m_point;
};
/**
* build an adaptor to transverse the pixels and the coordinate
* of an opencv image
*/
template<class T>
auto pixels_at(cv::Mat& img)
{
return pixel_point_iterator_adaptor<
T,
cv::MatIterator_<T>,
cv::Mat
>(img);
}
/**
* build an adaptor to transverse the pixels and the coordinate
* of an opencv image
*/
template<class T>
auto pixels_at(cv::Mat const& img)
{
return pixel_point_iterator_adaptor<
T,
cv::MatConstIterator_<T>,
cv::Mat const
>(img);
}
}
cmake_minimum_required(VERSION 2.8)
project(adaptors)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(adaptors main.cpp)
target_compile_features(adaptors PUBLIC cxx_std_17)
target_link_libraries(adaptors ${OpenCV_LIBS})
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "adaptors.hpp"
int main()
{
cv::Mat img(cv::Size{ 500, 250 }, CV_8UC1);
// to modify the pixel, you need to get it by the reference using auto&
for(auto& pixel : cv::pixels<uchar>(img))
pixel = 255;
cv::imwrite("00-test.png", img);
// the default is get the pixel by the reference
// in this case, auto& will try to get the reference
// of the temporary tuple
//
// for colorful images, use cv::Vec3 instead uchar
auto max_norm = std::sqrt(img.cols*img.cols + img.rows*img.rows);
for(auto [ pixel, coordinate ] : cv::pixels_at<uchar>(img)){
auto normalized_norm = cv::norm(coordinate)/max_norm;
pixel = static_cast<uchar>(normalized_norm*255);
}
cv::imwrite("01-test.png", img);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment