diff --git a/include/iterator.hpp b/include/iterator.hpp index ddbad18..b29c9bf 100644 --- a/include/iterator.hpp +++ b/include/iterator.hpp @@ -7,6 +7,21 @@ using namespace cv; using namespace std; +/** + * This is a wrapper over MatIterator_ to make it consistent with + * range based for loops in C++11. + * The IterableMat class has a begin() and an end() iterator + * that function similarly to MatIterator_ class. Also, while + * creating the IterableMat, a warning is issued if the type of + * the matrix is not the same as T + * + * A simple way to get an IterableMat from a Mat is to do + * iterate(mat). Thus, an easy range based for loop would look + * like: + * + * for(T elem : iterate(mat)) {...} + */ + template class IterableMat : public Mat { public: struct Iterator { @@ -43,10 +58,28 @@ template class IterableMat : public Mat { template IterableMat iterate(Mat &x) { - CHECKER_ASSERT(DataType::type == x.type(), "WARNING: Data type mismatch in iterable, may lead to wrong results\n"); + CHECKER_ASSERT(DataType::type == x.type(), + "WARNING: Data type mismatch in iterable, may lead to wrong results\n"); return IterableMat(x); } +/** + * This is another wrapper over MatIterator_ but it also gives the + * (x,y) coordinates of the current loop instance. + * The EnumerableMat class has an EnumerationIterator + * that gives back an Enumeration object upon dereference. The + * Enumeration object has three fields: x, y, T& val, which are + * set according to the current iteration. + * + * A simple way to get an EnumerableMat from a Mat is to do + * enumerate(mat). Thus, an easy range based for loop would look + * like: + * + * for(auto en : enumerate(mat)) { + * printf("%d %d %f", en.x, en.y, en.val); + * } + */ + template class EnumerableMat : public Mat { public: struct Enumeration { @@ -104,7 +137,8 @@ template class EnumerableMat : public Mat { template EnumerableMat enumerate(Mat &x) { - CHECKER_ASSERT(DataType::type == x.type(), "WARNING: Data type mismatch in enumerable, may lead to wrong results\n"); + CHECKER_ASSERT(DataType::type == x.type(), + "WARNING: Data type mismatch in enumerable, may lead to wrong results\n"); return EnumerableMat(x); } diff --git a/include/transform.hpp b/include/transform.hpp index b8e8d18..0ba73d3 100644 --- a/include/transform.hpp +++ b/include/transform.hpp @@ -7,6 +7,10 @@ using namespace std; using namespace cv; +/** + * a simple function_traits class to get argument and result types of functions + */ + template struct function_traits : public function_traits @@ -18,21 +22,57 @@ template struct function_traits // we specialize for pointers to member function { - enum { arity = sizeof...(Args) }; - // arity is the number of arguments. - typedef ReturnType result_type; typedef typename std::tuple_element<0, std::tuple>::type argument_type; - - template - struct arg - { - typedef typename std::tuple_element>::type type; - // the i-th argument is equivalent to the i-th tuple element of a tuple - // composed of those arguments. - }; }; + +/** + * This is the workhorse of per-pixel transforms and the like + * An IntermediateValue stores the current intermediate Mat in its val + * and can be freely cast to or from a Mat instance + * + * It provides two methods: + * pp_transform(func), which is equivalent to + * + * Mat output = Mat(val.size(), ) + * for(each pixel in val) { + * output[pixel] = func(input[pixel]); + * } + * return IntermediateValue(output); + * + * pp_transform can also be called with an explicit output + * type, such as: + * pp_transform(CV_32FC3, func); + * + * One can directly obtain an IntermediateValue by calling + * pp_transform(image, func) + * + * Since a pp_transform returns a IntermediateValue, one can create a chain + * of pp_transforms such as + * pp_transform(image, func). + * pp_transform(func2). + * pp_transform(func3); + * + * Also, another similar method is total_transform, which simply calls + * func on the Mat itself, like: + * + * Mat output = func(val); + * return IntermediateValue(output); + * + * This method is meant to be used for OpenCV implemented transforms such + * as edge detection etc. An example of edge detection on the R-channel of a + * normalized color image is below + * + * Mat output = pp_transform(image, [](Vec3b pixel) { // get normalized R channel + * float sum = pixel[0] + pixel[1] + pixel[2]; + * return saturate_cast(pixel[2]/sum*255); + * }).total_transform([](Mat input) { + * Mat output; + * Canny(input, output, 20, 60); + * return output; + * }); + */ struct IntermediateValue { Mat val;