Skip to content

Commit

Permalink
First version of delayed evaluation for some image operations.
Browse files Browse the repository at this point in the history
Add functions returning expression result for flip, transpose, rotate.
  • Loading branch information
kmhofmann committed Mar 7, 2019
1 parent 2bd7202 commit 6377d49
Show file tree
Hide file tree
Showing 10 changed files with 379 additions and 107 deletions.
6 changes: 5 additions & 1 deletion selene/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ target_sources(selene_img PRIVATE
${CMAKE_CURRENT_LIST_DIR}/img/typed/ImageViewTypeAliases.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/TypedLayout.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/Utilities.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/_impl/ImageBaseTraits.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/_impl/ImageExprTraits.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/_impl/ImageFwd.hpp
${CMAKE_CURRENT_LIST_DIR}/img/typed/_impl/StaticChecks.hpp

Expand Down Expand Up @@ -267,7 +267,11 @@ target_sources(selene_img_ops PRIVATE
${CMAKE_CURRENT_LIST_DIR}/img_ops/PixelConversions.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/Resample.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/Transformations.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/TransformationDirections.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/View.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/_impl/FlipExpr.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/_impl/IdentityExpr.hpp
${CMAKE_CURRENT_LIST_DIR}/img_ops/_impl/TransposeExpr.hpp
)

target_compile_options(selene_img_ops PRIVATE ${SELENE_COMPILE_OPTIONS} ${SELENE_IMG_COMPILE_OPTIONS})
Expand Down
26 changes: 23 additions & 3 deletions selene/img/typed/Image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class Image
using iterator = typename ImageView<PixelType_, ImageModifiability::Mutable>::iterator; ///< The iterator type.
using const_iterator = typename ImageView<PixelType_, ImageModifiability::Mutable>::const_iterator; ///< The const_iterator type.

constexpr static bool is_view = impl::ImageBaseTraits<Image<PixelType>>::is_view;
constexpr static bool is_modifiable = impl::ImageBaseTraits<Image<PixelType>>::is_modifiable;
constexpr static bool is_view = false;
constexpr static bool is_modifiable = true;

constexpr static ImageModifiability modifiability()
{
return impl::ImageBaseTraits<Image<PixelType>>::modifiability();
return ImageModifiability::Mutable;
}

Image() = default; ///< Default constructor.
Expand Down Expand Up @@ -97,6 +97,9 @@ class Image
template <ImageModifiability modifiability>
Image<PixelType>& operator=(const ImageView<PixelType, modifiability>&);

template <typename ImgExpr>
explicit Image(const ImageExpr<ImgExpr>& expr);

const TypedLayout& layout() const noexcept;

PixelLength width() const noexcept;
Expand Down Expand Up @@ -356,6 +359,23 @@ Image<PixelType_>& Image<PixelType_, Allocator_>::operator=(const ImageView<Pixe
return *this;
}

template <typename PixelType_, typename Allocator_>
template <typename ImgExpr>
Image<PixelType_, Allocator_>::Image(const ImageExpr<ImgExpr>& expr)
: view_and_alloc_(ImageView<PixelType, ImageModifiability::Mutable>{}, Allocator{})
{
mem_view() = allocate_memory(expr.layout());

// TODO: optimize?
for (auto y = 0_idx; y < expr.height(); ++y)
{
for (auto x = 0_idx; x < expr.width(); ++x)
{
this->operator()(x, y) = expr(x, y);
}
}
}

/** \brief Returns the image layout.
*
* @tparam PixelType_ The pixel type.
Expand Down
92 changes: 52 additions & 40 deletions selene/img/typed/ImageBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <selene/img/common/DataPtr.hpp>

#include <selene/img/typed/TypedLayout.hpp>
#include <selene/img/typed/_impl/ImageBaseTraits.hpp>
#include <selene/img/typed/_impl/ImageExprTraits.hpp>
#include <selene/img/typed/_impl/StaticChecks.hpp>

#include <type_traits>
Expand All @@ -20,70 +20,82 @@ namespace sln {
/// \addtogroup group-img-typed
/// @{

template <typename Derived> class ImageExpr;

template <typename Derived>
class ImageBase
class ImageExpr
{
public:
static_assert(impl::is_image_type_v<Derived>);
// static_assert(impl::is_image_type_v<Derived>);

using PixelType = typename impl::ImageExprTraits<Derived>::PixelType;

using PixelType = typename impl::ImageBaseTraits<Derived>::PixelType;
constexpr static bool is_view = impl::ImageExprTraits<Derived>::is_view;
constexpr static bool is_modifiable = impl::ImageExprTraits<Derived>::is_modifiable;

constexpr static bool is_view = impl::ImageBaseTraits<Derived>::is_view;
constexpr static bool is_modifiable = impl::ImageBaseTraits<Derived>::is_modifiable;
constexpr static ImageModifiability modifiability() { return impl::ImageBaseTraits<Derived>::modifiability(); }
constexpr static ImageModifiability modifiability() { return is_modifiable ? ImageModifiability::Mutable : ImageModifiability::Constant; }

Derived& derived() noexcept { return *static_cast<Derived*>(this); }
const Derived& derived() const noexcept { return *static_cast<const Derived*>(this); }

const TypedLayout& layout() const noexcept { return derived().layout(); }
decltype(auto) layout() const noexcept { return this->derived().layout(); }

PixelLength width() const noexcept { return derived().width(); }
PixelLength height() const noexcept { return derived().height(); }
Stride stride_bytes() const noexcept { return derived().stride_bytes(); }
std::ptrdiff_t row_bytes() const noexcept { return derived().row_bytes(); }
std::ptrdiff_t total_bytes() const noexcept { return derived().total_bytes(); }
bool is_packed() const noexcept { return derived().is_packed(); }
Stride stride_bytes() const noexcept { return this->derived().stride_bytes(); }

bool is_empty() const noexcept { return derived().is_empty(); }
bool is_valid() const noexcept { return derived().is_valid(); }
decltype(auto) operator()(PixelIndex x, PixelIndex y) noexcept { return derived().operator()(x, y); }
decltype(auto) operator()(PixelIndex x, PixelIndex y) const noexcept { return derived().operator()(x, y); }
};

decltype(auto) begin() noexcept { return derived().begin(); }
decltype(auto) begin() const noexcept { return derived().begin(); }
decltype(auto) cbegin() const noexcept { return derived().cbegin(); }

decltype(auto) end() noexcept { return derived().end(); }
decltype(auto) end() const noexcept { return derived().end(); }
decltype(auto) cend() const noexcept { return derived().cend(); }
template <typename Derived>
class ImageBase : public ImageExpr<Derived>
{
public:
using PixelType = typename ImageExpr<Derived>::PixelType;

decltype(auto) byte_ptr() noexcept { return derived().byte_ptr(); }
decltype(auto) byte_ptr() const noexcept { return derived().byte_ptr(); }
std::ptrdiff_t row_bytes() const noexcept { return this->derived().row_bytes(); }
std::ptrdiff_t total_bytes() const noexcept { return this->derived().total_bytes(); }
bool is_packed() const noexcept { return this->derived().is_packed(); }

decltype(auto) byte_ptr(PixelIndex y) noexcept { return derived().byte_ptr(y); }
decltype(auto) byte_ptr(PixelIndex y) const noexcept { return derived().byte_ptr(y); }
bool is_empty() const noexcept { return this->derived().is_empty(); }
bool is_valid() const noexcept { return this->derived().is_valid(); }

decltype(auto) byte_ptr(PixelIndex x, PixelIndex y) noexcept { return derived().byte_ptr(x, y); }
decltype(auto) byte_ptr(PixelIndex x, PixelIndex y) const noexcept { return derived().byte_ptr(x, y); }
decltype(auto) begin() noexcept { return this->derived().begin(); }
decltype(auto) begin() const noexcept { return this->derived().begin(); }
decltype(auto) cbegin() const noexcept { return this->derived().cbegin(); }

decltype(auto) data() noexcept { return derived().data(); }
decltype(auto) data() const noexcept { return derived().data(); }
decltype(auto) end() noexcept { return this->derived().end(); }
decltype(auto) end() const noexcept { return this->derived().end(); }
decltype(auto) cend() const noexcept { return this->derived().cend(); }

decltype(auto) data(PixelIndex y) noexcept { return derived().data(y); }
decltype(auto) data(PixelIndex y) const noexcept { return derived().data(y); }
decltype(auto) byte_ptr() noexcept { return this->derived().byte_ptr(); }
decltype(auto) byte_ptr() const noexcept { return this->derived().byte_ptr(); }

decltype(auto) data_row_end(PixelIndex y) noexcept { return derived().data_row_end(y); }
decltype(auto) data_row_end(PixelIndex y) const noexcept { return derived().data_row_end(y); }
decltype(auto) byte_ptr(PixelIndex y) noexcept { return this->derived().byte_ptr(y); }
decltype(auto) byte_ptr(PixelIndex y) const noexcept { return this->derived().byte_ptr(y); }

decltype(auto) data(PixelIndex x, PixelIndex y) noexcept { return derived().data(x, y); }
decltype(auto) data(PixelIndex x, PixelIndex y) const noexcept { return derived().data(x, y); }
decltype(auto) byte_ptr(PixelIndex x, PixelIndex y) noexcept { return this->derived().byte_ptr(x, y); }
decltype(auto) byte_ptr(PixelIndex x, PixelIndex y) const noexcept { return this->derived().byte_ptr(x, y); }

decltype(auto) operator()(PixelIndex x, PixelIndex y) noexcept { return derived().operator()(x, y); }
decltype(auto) operator()(PixelIndex x, PixelIndex y) const noexcept { return derived().operator()(x, y); }
decltype(auto) data() noexcept { return this->derived().data(); }
decltype(auto) data() const noexcept { return this->derived().data(); }

decltype(auto) data(PixelIndex y) noexcept { return this->derived().data(y); }
decltype(auto) data(PixelIndex y) const noexcept { return this->derived().data(y); }

decltype(auto) data_row_end(PixelIndex y) noexcept { return this->derived().data_row_end(y); }
decltype(auto) data_row_end(PixelIndex y) const noexcept { return this->derived().data_row_end(y); }

decltype(auto) data(PixelIndex x, PixelIndex y) noexcept { return this->derived().data(x, y); }
decltype(auto) data(PixelIndex x, PixelIndex y) const noexcept { return this->derived().data(x, y); }

decltype(auto) view() noexcept { return derived().view(); }
decltype(auto) view() const noexcept { return derived().view(); }
decltype(auto) constant_view() const noexcept { return derived().constant_view(); }
decltype(auto) view() noexcept { return this->derived().view(); }
decltype(auto) view() const noexcept { return this->derived().view(); }
decltype(auto) constant_view() const noexcept { return this->derived().constant_view(); }

decltype(auto) clear() { return derived().clear(); }
decltype(auto) clear() { return this->derived().clear(); }
};

/// @}
Expand Down
6 changes: 3 additions & 3 deletions selene/img/typed/ImageView.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ class ImageView
using iterator = ImageRowIterator<ImageView<PixelType, modifiability_>, IteratorRow>; ///< The iterator type.
using const_iterator = ImageRowIterator<ImageView<PixelType, modifiability_>, ConstIteratorRow>; ///< The const_iterator type.

constexpr static bool is_view = impl::ImageBaseTraits<ImageView<PixelType_, modifiability_>>::is_view;
constexpr static bool is_modifiable = impl::ImageBaseTraits<ImageView<PixelType_, modifiability_>>::is_modifiable;
constexpr static bool is_view = true;
constexpr static bool is_modifiable = (modifiability_ == ImageModifiability::Mutable);

constexpr static ImageModifiability modifiability()
{
return impl::ImageBaseTraits<ImageView<PixelType_, modifiability_>>::modifiability();
return modifiability_;
}

ImageView() = default;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,24 @@

namespace sln::impl {

template <typename Derived>
struct ImageBaseTraits;
template <typename Derived> struct ImageExprTraits;

template <typename PixelType_, typename Allocator_>
struct ImageBaseTraits<Image<PixelType_, Allocator_>>
struct ImageExprTraits<Image<PixelType_, Allocator_>>
{
using PixelType = PixelType_;

constexpr static bool is_view = false;
constexpr static bool is_modifiable = true;

constexpr static ImageModifiability modifiability()
{
return ImageModifiability::Mutable;
}
};

template <typename PixelType_, ImageModifiability modifiability_>
struct ImageBaseTraits<ImageView<PixelType_, modifiability_>>
struct ImageExprTraits<ImageView<PixelType_, modifiability_>>
{
using PixelType = PixelType_;

constexpr static bool is_view = true;
constexpr static bool is_modifiable = (modifiability_ == ImageModifiability::Mutable);

constexpr static ImageModifiability modifiability()
{
return modifiability_;
}
};

} // namespace sln::impl
Expand Down
38 changes: 38 additions & 0 deletions selene/img_ops/TransformationDirections.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// This file is part of the `Selene` library.
// Copyright 2017-2019 Michael Hofmann (https://github.com/kmhofmann).
// Distributed under MIT license. See accompanying LICENSE file in the top-level directory.

#ifndef SELENE_IMG_TRANSFORMATION_DIRECTIONS_HPP
#define SELENE_IMG_TRANSFORMATION_DIRECTIONS_HPP

/// @file

namespace sln {

/// \addtogroup group-img-ops
/// @{

/** \brief Describes the flip direction. */
enum class FlipDirection
{
Horizontal, ///< Horizontal flip.
Vertical, ///< Vertical flip.
Both, ///< Combined horizontal and vertical flip.
};

/** \brief Describes the rotation direction. */
enum class RotationDirection
{
Clockwise0, ///< Rotation by 0 degrees clockwise.
Clockwise90, ///< Rotation by 90 degrees clockwise.
Clockwise180, ///< Rotation by 180 degrees clockwise.
Clockwise270, ///< Rotation by 270 degrees clockwise.
Counterclockwise0, ///< Rotation by 0 degrees counterclockwise.
Counterclockwise90, ///< Rotation by 90 degrees counterclockwise.
Counterclockwise180, ///< Rotation by 180 degrees counterclockwise.
Counterclockwise270, ///< Rotation by 270 degrees counterclockwise.
};

} // namespace sln

#endif // SELENE_IMG_TRANSFORMATION_DIRECTIONS_HPP
Loading

0 comments on commit 6377d49

Please sign in to comment.