Last active
February 1, 2019 12:56
-
-
Save yudi-matsuzake/9e74dfa87a70d95ce74ef11d3f56a634 to your computer and use it in GitHub Desktop.
c++17 opencv adaptors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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