この日本語訳について
現在,この文章は作成中です.
- 原文:
-
- 原文の著者:
- Lubomir Bourdev (lbourdev@adobe.com) and Hailin Jin (hljin@adobe.com)
Adobe Systems Incorporated
- 原文のライセンス:
-
- 翻訳者:
-
- この文章のライセンス:
-
- 翻訳日時:
- 2008年7月14日開始
この文章はBoost.GILのデザインガイドを日本語に訳したものです.この訳はAdobeを含む原文の著者や権利者とまったく関係がありません.また,内容の正確さはいっさい保証されません.
Generic Image Library デザインガイド
- 著者:
- Lubomir Bourdev (lbourdev@adobe.com) and Hailin Jin (hljin@adobe.com)
Adobe Systems Incorporated
- Version:
- 2.1
- 作成日時:
- 2007年9月15日
この文章はアルゴリズムによる画像生成を抽象化するC++画像処理ライブラリであるGeneric Image Libraryのデザインについて記述したものです.この文章ではカジュアルな使用で必要となる知識以上の範囲を扱っています.迅速なjump-startを提供するGILのチュートリアルはGILのメインページhttp://opensource.adobe.com/gilでみつけることができます.
画像は画像処理やビジョンや動画像システムにおける基本的な要素ですが,画像構成の多様さはジェネリックかつ効果的な画像処理アルゴリズムの記述を困難なものにしています.このセクションでは,私たちが目指すいくつかの課題について述べることにしましょう.
以降,imageは2次元配列状のpixelであるとします.あるpixelは画像中のある座標における色情報を示すcolor channelのセットです.各channelは色の構成要素を表します.imageでよく用いられるメモリ上での構造は2種類のものがあります.Interleaved imageでは,pixel群がメモリ上でひとまとまりになっていて,pixelの各channelが隣接して順番に配置されています.一方のplanar imageは各channelがそれぞれ独立した色平面を構成しています.ここに4x3のRGB画像を図示し最初の行の2番目のpixelを赤い文字で示します.interleaved形式ではこのようになります.
planar形式では次のようになります.
各行は,末尾でpaddingが行われる場合があり,その幅が調整されているかもしれないことに注意しましょう.
Generic Image Library (GIL)では以下の要素に対応したimageのモデルを提供します.
- メモリ上での形式 (planar vs. interleaved)
- Color spaceとアルファチャネルの有無 (RGB, RGBA, CMYK, etc.)
- Channel深度(8-bit, 16-bit, etc.)
- Channel順序 (RGB vs. BGR, etc.)
- Row幅調整のポリシー (no alignment, word-alignment, etc.)
また,ユーザ定義のimageモデルや実行時にパラメータが決定するimageについてもサポートしています.GILは画像処理アルゴリズムによる画像構成を抽象化し,いちど記述したアルゴリズムから特定のimageフォーマットへ依存した手書きアルゴリズムにスピードで匹敵するコードを生成し,上記に示した様々なフォーマットのimageに対して適用することを可能にします.
この文章はボトムアップな構成になっています.各セクションではそれ以前のセクションで定義された上位conceptからなるconceptが定義されます.順番にそって読み進めることが推奨されます.
GILの全てのコンストラクトはGIL conceptのモデルです.conceptは型(もしくは,関連する型のセット)がジェネリックアルゴリズムにおいて正しく利用されるために満たすべき要件のセットです.これらの要件は構文上の保証とアルゴリズム上の保証を含みます.例えば,GILのpixelクラスはGILのPixelConceptのひとつのモデルです.ユーザが自身のつくったpixelクラスで代用しようとする際に,PixelConceptの要件を満たす限りにおいて,その他のGILクラスやアルゴリズムでも使用することができます.さらにconceptについて知るにはhttp://www.generic-programming.org/languages/conceptcpp/を参照してください.
この文章のなかで,私たちはconceptを定義するために,C++0xがhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdfにまとめているConcepts extensionの提案書に記述されたsyntaxを用います.
ここでGILのなかでよく用いられるいくつかのconceptを示します.これらの多くは次のサイトで定義されています.http://www.generic-programming.org/languages/conceptcpp/concept_web.php
auto concept DefaultConstructible<typename T> { T::T(); };
auto concept CopyConstructible<typename T> { T::T(T); T::~T(); };
auto concept Assignable<typename T, typename U = T> { typename result_type; result_type operator=(T&, U); };
auto concept EqualityComparable<typename T, typename U = T> { bool operator==(T x, T y); bool operator!=(T x, T y) { return !(x==y); } };
concept SameType<typename T, typename U> { unspecified }; template<typename T> concept_map SameType<T, T> { unspecified };
auto concept Swappable<typename T> { void swap(T& t, T& u); };
次に示すのはGILが追加で必要とするいくつかの基本conceptです.
auto concept Regular<typename T> : DefaultConstructible<T>, CopyConstructible<T>, EqualityComparable<T>, Assignable<T>, Swappable<T> {};
auto concept Metafunction<typename T> { typename type; };
画像内のあるpixelの位置はpointが定義します.また,pointは画像の各軸における長さを記述するためにも用いられます.ほとんどの場合,pointは多次元であり,次に示すconceptのモデルです.
concept PointNDConcept<typename T> : Regular<T> { // the type of a coordinate along each axis template <size_t K> struct axis; where Metafunction<axis>; const size_t num_dimensions; // accessor/modifier of the value of each axis. template <size_t K> const typename axis<K>::type& T::axis_value() const; template <size_t K> typename axis<K>::type& T::axis_value(); };
GILでは,全ての次元で同じ型をもつように改良したPointNDConceptである,2次元pointを使用しています.
concept Point2DConcept<typename T> : PointNDConcept<T> { where num_dimensions == 2; where SameType<axis<0>::type, axis<1>::type>;
typename value_type = axis<0>::type;
const value_type& operator[](const T&, size_t i); value_type& operator[]( T&, size_t i);
value_type x,y; };
関連するConcept:
- PointNDConcept<T>
- Point2DConcept<T>
モデル: GILではPoint2DConceptのモデルpoint2<T>を提供しています.ここでのTは座標の型を指定するパラメータです.
channelは,例えばRGB pixelにおけるred channelといったように,色の要素を指すものです.channelに対する典型的な操作として,channelの値の取得,比較,代入があります.channelはそのchannelに結びつけられた最小値,最大値をもっています.GILのchannelは次に示すconceptをモデルにしています.
concept ChannelConcept<typename T> : EqualityComparable<T> { typename value_type = T; // use channel_traits<T>::value_type to access it where ChannelValueConcept<value_type>; typename reference = T&; // use channel_traits<T>::reference to access it typename pointer = T*; // use channel_traits<T>::pointer to access it typename const_reference = const T&; // use channel_traits<T>::const_reference to access it typename const_pointer = const T*; // use channel_traits<T>::const_pointer to access it static const bool is_mutable; // use channel_traits<T>::is_mutable to access it
static T min_value(); // use channel_traits<T>::min_value to access it static T max_value(); // use channel_traits<T>::min_value to access it };
concept MutableChannelConcept<ChannelConcept T> : Swappable<T>, Assignable<T> {};
concept ChannelValueConcept<ChannelConcept T> : Regular<T> {};
GILでは,ビルトインの整数型と浮動小数点型についてchannelとしての使用を認めています.channelに結びつけられる型とその値の幅に関する情報は次に示すデフォルトの実装で定義されています.
template <typename T> struct channel_traits { typedef T value_type; typedef T& reference; typedef T* pointer; typedef T& const const_reference; typedef T* const const_pointer; static value_type min_value() { return std::numeric_limits<T>::min(); } static value_type max_value() { return std::numeric_limits<T>::max(); } };
ふたつのchannel型が同じvalue型をもつ場合,そのふたつのchannel型には互換性があります.
concept ChannelsCompatibleConcept<ChannelConcept T1, ChannelConcept T2> { where SameType<T1::value_type, T2::value_type>; };
また,channelは他のchannelへ変換可能かもしれません.
template <ChannelConcept Src, ChannelValueConcept Dst> concept ChannelConvertibleConcept { Dst channel_convert(Src); };
ChannenlConceptとMutableChannelConceptはデフォルトコンストラクタを要求しないことに注意してください.デフォルトコンストラクタをもつchannel (たとえば,標準で用意されているchannel)はChannelValueConceptをモデルとします.この区別の意図を理解するために,"565"のビットパターンをもつ16-bit RGB pixelの場合について考えることにしましょう.これらのchannelはビット長に応じたものになります.このようなchannelに対応するために,サブバイトchannelへのリファレンスに対応する独自のproxyクラスを作成する必要があります.そのようなproxyリファレンスクラスは,ネイティブC++のリファレンスと同じようにデフォルトコンストラクタをもっていない可能性があることから,ChannelConceptだけをモデルとします.
アルゴリズムもchannelに対して,例えば算術処理のサポートなどといった,追加の要求を課すかもしれないことに注意しましょう.
関連するConcept:
- ChannelConcept<T>
- ChannelValueConcept<T>
- MutableChannelConcept<T>
- ChannelsCompatibleConcept<T1,T2>
- ChannelConvertibleConcept<SrcChannel,DstChannel>
モデル: 全てのビルトイン整数型と浮動小数点型は有効なchannelです.GILはいくつかの整数型channelに標準のtypedefを提供しています.
typedef boost::uint8_t bits8; typedef boost::uint16_t bits16; typedef boost::uint32_t bits32; typedef boost::int8_t bits8s; typedef boost::int16_t bits16s; typedef boost::int32_t bits32s;
channelがとる最小値と最大値は,std::numeric_limitsで指定される,対応するビルトイン型における実装上の最小値と最大値にもとづきます.また,実装上の幅を用いるのが適当でない場合も考えられます.GILではscoped_channel_valueという独自の幅を設定するchannel adaptorのモデルを提供しています.私たちは,次に示すように,[0..1]幅の浮動小数点型valueをもつchannel型を定義するためにこのモデルを用いています.
struct float_zero { static float apply() { return 0.0f; } }; struct float_one { static float apply() { return 1.0f; } }; typedef scoped_channel_value<float,float_zero,float_one> bits32f;
GILではビット長に対応するchannelに対するモデルも提供しています.
// Value of a channel defined over NumBits bits. Models ChannelValueConcept template <int NumBits> class packed_channel_value;
// Reference to a channel defined over NumBits bits. Models ChannelConcept template <int FirstBit, int NumBits, // Defines the sequence of bits in the data value that contain the channel bool Mutable> // true if the reference is mutable class packed_channel_reference;
// Reference to a channel defined over NumBits bits. Its FirstBit is a run-time parameter. Models ChannelConcept template <int NumBits, // Defines the sequence of bits in the data value that contain the channel bool Mutable> // true if the reference is mutable class packed_dynamic_channel_reference;
channel幅の補正値の特定をテンプレートによっておこなうか,実行時のパラメータによっておこなうかの違いに基づいた2種類のリファレンスproxyのモデルがあることに着目しましょう.最初のモデルは高速で比較的コンパクトであり,ふたつめのモデルはより柔軟なモデルになっています.例えば,ふたつめのモデルはビット長が大きなchannelからiteratorを構築することを許しています.
アルゴリズム:
ここでは16-bit "565" pixelにおける各channelをいかに構築し, どのようにしてそれらに最大値を代入するかを示します.
typedef packed_channel_reference<0,5,true> channel16_0_5_reference_t; typedef packed_channel_reference<5,6,true> channel16_5_6_reference_t; typedef packed_channel_reference<11,5,true> channel16_11_5_reference_t;
boost::uint16_t data=0; channel16_0_5_reference_t channel1(&data); channel16_5_6_reference_t channel2(&data); channel16_11_5_reference_t channel3(&data);
channel1=channel_traits<channel16_0_5_reference_t>::max_value(); channel2=channel_traits<channel16_5_6_reference_t>::max_value(); channel3=channel_traits<channel16_11_5_reference_t>::max_value(); assert(data==65535);
代入,等価判定,コピーコンストラクトは互換をもつchannel間だけで定義されています.
packed_channel_value<5> channel_6bit = channel1; channel_6bit = channel3;
//channel_6bit = channel2; // compile error: Assignment between incompatible channels.
GILによって提供されている全てのchannelモデルは相互に変換可能です.
channel1 = channel_traits<channel16_0_5_reference_t>::max_value(); assert(channel1 == 31);
bits16 chan16 = channel_convert<bits16>(channel1); assert(chan16 == 65535);
channelの変換処理は非可逆です.GILのchannel変換は入力側の幅から出力側の幅に対しての線形変換です.最小値は最小値へ,最大値は最大値へと正確に対応しています.(例えば,uint8_tからuint16_tへの変換において,その最大値の値が一致しないので,GILはビットシフトを行いません.その代わりに,GILは入力値と257の積をとります.)
GILが提供する全てのchannelモデルは,整数型と浮動小数点型との間で変換可能です.これは,それらのchannelモデルが算術処理をサポートしていることによります.ここで,GILが提供するchannelレベルアルゴリズムを示します.
// Converts a source channel value into a destrination channel. Linearly maps the value of the source // into the range of the destination template <typename DstChannel, typename SrcChannel> typename channel_traits<DstChannel>::value_type channel_convert(SrcChannel src);
// returns max_value - x + min_value template <typename Channel> typename channel_traits<Channel>::value_type channel_invert(Channel x);
// returns a * b / max_value template <typename Channel> typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b);
color spaceはpixelに含まれるchannelの組とそれらの解釈を表現しています.それはcolor space中の全要素の型を含んだMPLランダムアクセスシークエンスです.ふたつのcolor spaceはそれらが同じものである場合(すなわち,同じcolorセットが同じ順序で並んでいる場合)に互換性があるとみなされます.
関連するConcept:
- ColorSpaceConcept<ColorSpace>
- ColorSpacesCompatibleConcept<ColorSpace1,ColorSpace2>
- ChannelMappingConcept<Mapping>
モデル: GILではいまのところgray_t, rgb_t, rgba_t, cmyk_tのcolor spaceを提供しています.また,2個から5個のchannelをもつ,devicen_t<2>, devicen_t<3>, devicen_t<4>, devicen_t<5>といった無名color spaceも提供しています.そして,GILは標準layoutとしてbgr_layout_t, bgra_layout_t, abgr_layout_t, argb_layout_tを提供しています.
ひとつの例として,GILがどのようにRGBA color spaceを定義しているのか示します.
struct red_t{}; struct green_t{}; struct blue_t{}; struct alpha_t{}; typedef mpl::vector4<red_t,green_t,blue_t,alpha_t> rgba_t;
color spaceにおけるchannelの順序は,そのcolor spaceにおけるセマンティックなchannelの順序を決定します.例えば,red_tはrgba_tのセマンティックな順序における1番目のchannelです.color spaceにおけるセマンティックなchannelの順序がひとつに定まっている場合でも,channelのメモリ上での実際の順序はひとつに決まっているとはかぎりません.channelのmappingは整数型によるMLPランダムアクセスシークエンスであるChannelMappingConceptによって定められています.color spaceとそのmappingはしばしば一緒に用いられます.つまり,それらはGILのlayoutとしてまとめられているのです.
template <typename ColorSpace, typename ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> > struct layout { typedef ColorSpace color_space_t; typedef ChannelMapping channel_mapping_t; };
ここに,RGBA color spaceのlayoutをどのようにして作成するかを示します.
typedef layout<rgba_t> rgba_layout_t; // default ordering is 0,1,2,3... typedef layout<rgba_t, mpl::vector4_c<int,2,1,0,3> > bgra_layout_t; typedef layout<rgba_t, mpl::vector4_c<int,1,2,3,0> > argb_layout_t; typedef layout<rgba_t, mpl::vector4_c<int,3,2,1,0> > abgr_layout_t;
color baseは色要素のコンテナです.color baseの使われ方として最も多いものはpixelの実装であり,そのときには色要素をchannelのvalueとしています.しかし,color base conceptは他の用途への利用も可能です.例えば,planar型のpixelはメモリ上で不連続に配置されたchannelをもっています.そのリファレンスは,色要素をchannel iteratorとするcolor baseを用いたproxyクラスです.
color baseモデルは次に示すconceptを満たさなければなりません.
concept ColorBaseConcept<typename T> : CopyConstructible<T>, EqualityComparable<T> { // a GIL layout (the color space and element permutation) typename layout_t; // The type of K-th element template <int K> struct kth_element_type; where Metafunction<kth_element_type>; // The result of at_c template <int K> struct kth_element_const_reference_type; where Metafunction<kth_element_const_reference_type>; template <int K> kth_element_const_reference_type<T,K>::type at_c(T); template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> } T::T(T2); template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> } bool operator==(const T&, const T2&); template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> } bool operator!=(const T&, const T2&);
};
concept MutableColorBaseConcept<ColorBaseConcept T> : Assignable<T>, Swappable<T> { template <int K> struct kth_element_reference_type; where Metafunction<kth_element_reference_type>;
template <int K> kth_element_reference_type<T,K>::type at_c(T); template <ColorBaseConcept T2> where { ColorBasesCompatibleConcept<T,T2> } T& operator=(T&, const T2&); };
concept ColorBaseValueConcept<typename T> : MutableColorBaseConcept<T>, Regular<T> { };
concept HomogeneousColorBaseConcept<ColorBaseConcept CB> { // For all K in [0 ... size<C1>::value-1): // where SameType<kth_element_type<K>::type, kth_element_type<K+1>::type>; kth_element_const_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n) const; };
concept MutableHomogeneousColorBaseConcept<MutableColorBaseConcept CB> : HomogeneousColorBaseConcept<CB> { kth_element_reference_type<0>::type dynamic_at_c(const CB&, std::size_t n); };
concept HomogeneousColorBaseValueConcept<typename T> : MutableHomogeneousColorBaseConcept<T>, Regular<T> { };
concept ColorBasesCompatibleConcept<ColorBaseConcept C1, ColorBaseConcept C2> { where SameType<C1::layout_t::color_space_t, C2::layout_t::color_space_t>; // also, for all K in [0 ... size<C1>::value): // where Convertible<kth_semantic_element_type<C1,K>::type, kth_semantic_element_type<C2,K>::type>; // where Convertible<kth_semantic_element_type<C2,K>::type, kth_semantic_element_type<C1,K>::type>; };
ひとつのcolor baseは必ず,対応するひとつのlayout(color spaceとchannel順からなる)をもっています.color baseの要素についてインデクシングは2通りの方法で行われています.メモリ上での要素の順序に対応づけられたフィジカルなインデクスと,color spaceにおける要素の順序に対応づけられたセマンティックなインデクスです.例えば,RGB color spaceにおける要素は{red_t, green_t, blue_t}の順に並べられています.BGR layoutをもつcolor baseを例にすると,フィジカルな順序における最初の要素はblue要素です.またその一方で,セマンティックな順序における最初の要素はred要素です.ColorBaseConceptのモデルは,フィジカルな順序によるアクセスを可能にするat_c<K>(ColorBase)という関数の提供を求められます.GILは,いかなるColorBaseConceptでも動作しセマンティックな対応付けをなされた要素を返す,semantic_at_c<K>(ColorBase)という関数(あとで記述します)を提供します.
モデル:
GILはhomogeneousなcolor base (全ての要素が同じ型をもつcolor base)のためのモデルを提供します. namespace detail { template <typename Element, typename Layout, int K> struct homogeneous_color_base; }
これはGILのpixel, planar pixel reference, planar pixel iteratorの実装に用いられています.もう一方のColorBaseConceptのモデルはpacked_pixelです.それはビット長によるchannelをもつpixelです.さらなる情報は,7.Pixelセクションを参照してください.
Algorithm:
GILはcolor baseにおいて動作する次に示す関数とメタ関数を提供します.
// Metafunction returning an mpl::int_ equal to the number of elements in the color base template <class ColorBase> struct size;
// Returns the type of the return value of semantic_at_c<K>(color_base) template <class ColorBase, int K> struct kth_semantic_element_reference_type; template <class ColorBase, int K> struct kth_semantic_element_const_reference_type;
// Returns a reference to the element with K-th semantic index. template <class ColorBase, int K> typename kth_semantic_element_reference_type<ColorBase,K>::type semantic_at_c(ColorBase& p) template <class ColorBase, int K> typename kth_semantic_element_const_reference_type<ColorBase,K>::type semantic_at_c(const ColorBase& p)
// Returns the type of the return value of get_color<Color>(color_base) template <typename Color, typename ColorBase> struct color_reference_t; template <typename Color, typename ColorBase> struct color_const_reference_t;
// Returns a reference to the element corresponding to the given color template <typename ColorBase, typename Color> typename color_reference_t<Color,ColorBase>::type get_color(ColorBase& cb, Color=Color()); template <typename ColorBase, typename Color> typename color_const_reference_t<Color,ColorBase>::type get_color(const ColorBase& cb, Color=Color());
// Returns the element type of the color base. Defined for homogeneous color bases only template <typename ColorBase> struct element_type; template <typename ColorBase> struct element_reference_type; template <typename ColorBase> struct element_const_reference_type;
GILはcolor baseで動作する次に示すアルゴリズムも提供しています.その全てがセマンティックな要素と組み合わされていることに注意しましょう.
// Equivalents to std::equal, std::copy, std::fill, std::generate template <typename CB1,typename CB2> bool static_equal(const CB1& p1, const CB2& p2); template <typename Src,typename Dst> void static_copy(const Src& src, Dst& dst); template <typename CB, typename Op> void static_generate(CB& dst,Op op);
// Equivalents to std::transform template <typename CB , typename Dst,typename Op> Op static_transform( CB&,Dst&,Op); template <typename CB , typename Dst,typename Op> Op static_transform(const CB&,Dst&,Op); template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&, CB2&,Dst&,Op); template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&, CB2&,Dst&,Op); template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform( CB1&,const CB2&,Dst&,Op); template <typename CB1,typename CB2,typename Dst,typename Op> Op static_transform(const CB1&,const CB2&,Dst&,Op);
// Equivalents to std::for_each template <typename CB1, typename Op> Op static_for_each( CB1&,Op); template <typename CB1, typename Op> Op static_for_each(const CB1&,Op); template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&, CB2&,Op); template <typename CB1,typename CB2, typename Op> Op static_for_each( CB1&,const CB2&,Op); template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&, CB2&,Op); template <typename CB1,typename CB2, typename Op> Op static_for_each(const CB1&,const CB2&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&, CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&, CB2&,const CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&, CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each( CB1&,const CB2&,const CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&, CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&, CB2&,const CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&, CB3&,Op); template <typename CB1,typename CB2,typename CB3,typename Op> Op static_for_each(const CB1&,const CB2&,const CB3&,Op);
// The following algorithms are only defined for homogeneous color bases: // Equivalent to std::fill template <typename HCB, typename Element> void static_fill(HCB& p, const Element& v);
// Equivalents to std::min_element and std::max_element template <typename HCB> typename element_const_reference_type<HCB>::type static_min(const HCB&); template <typename HCB> typename element_reference_type<HCB>::type static_min( HCB&); template <typename HCB> typename element_const_reference_type<HCB>::type static_max(const HCB&); template <typename HCB> typename element_reference_type<HCB>::type static_max( HCB&);
これらのアルゴリズムは,処理範囲の代わりにcolor baseを対象としてその各要素に処理行うことを除いて,対応するSTLアルゴリズムに倣ってデザインされています.加えて,コンパイル時の型解決も実装されています(よってプレフィックスは"static_").そして,これらのアルゴリズムは,メモリ上のフィジカルな順序によるのではなく,セマンティックに各要素へと結びつけられています.例として,static_equalの実装を示します.
namespace detail { template <int K> struct element_recursion { template <typename P1,typename P2> static bool static_equal(const P1& p1, const P2& p2) { return element_recursion<K-1>::static_equal(p1,p2) && semantic_at_c<K-1>(p1)==semantic_at_c<N-1>(p2); } }; template <> struct element_recursion<0> { template <typename P1,typename P2> static bool static_equal(const P1&, const P2&) { return true; } }; }
template <typename P1,typename P2> bool static_equal(const P1& p1, const P2& p2) { gil_function_requires<ColorSpacesCompatibleConcept<P1::layout_t::color_space_t,P2::layout_t::color_space_t> >(); return detail::element_recursion<size<P1>::value>::static_equal(p1,p2); }
このアルゴリズムは,例えば,ふたつのpixelでoperator==を呼び出した場合などに用いられます.セマンティックなアクセス機構を用いることで,RGB pixelとBGR pixelを正確に比較することができます.上記の2個以上のcolor baseをとる全てのアルゴリズムは,それらのcolor baseがもつcolor spaceが一致することを必要としている.
pixelはimageの与えられた座標における色が定義されたchannelのセットです.概念的に,pixelはChannelConceptをモデルとした要素をもつcolor baseよりも小さいものです.pixelがもつ全ての特性はcolor baseから受け継いだもので,そのcolor baseがもつchannelの全てが同じ型である場合にはhomogeneousであるでしょうし,それ以外の場合にはheterogeneousと呼ばれるでしょう.pixelのchannelへはセマンティックな,もしくはフィジカルなindexを用いて呼び出しが行われる可能性もあり,また色によっても呼び出しが行われる可能性もあります.全てのcolor-baseアルゴリズムがpixelにおいても上手く機能します.2個のpixelは,それらのcolor spaceが同じであり,それらのchannelがセマンティックに互換可能である場合に,互換が可能である.const性,メモリ上での構成,参照であるか値であるかについては無視されることに着目しておきましょう.例えば,8-bit RGB planar参照は,8-bit BGR interleaved pixel valueと互換可能です.ほとんどの2項pixel演算(コピーコンストラクト,代入,等価判定)は互換可能pixelに対してだけ定義されている.
pixel(iterator, locator, view, imageなどpixelに基づいたそのほかのGILコンストラクトも同様に)は,そのcolor space, channel mapping, channel数,そして(homogeneousなpixelにおいては)channel型へアクセスするメタ関数を提供しなければなりません.
concept PixelBasedConcept<typename T> { typename color_space_type<T>; where Metafunction<color_space_type<T> >; where ColorSpaceConcept<color_space_type<T>::type>; typename channel_mapping_type<T>; where Metafunction<channel_mapping_type<T> >; where ChannelMappingConcept<channel_mapping_type<T>::type>; typename is_planar<T>; where Metafunction<is_planar<T> >; where SameType<is_planar<T>::type, bool>; };
concept HomogeneousPixelBasedConcept<PixelBasedConcept T> { typename channel_type<T>; where Metafunction<channel_type<T> >; where ChannelConcept<channel_type<T>::type>; };
pixelは次に示すconceptをモデルとします.
concept PixelConcept<typename P> : ColorBaseConcept<P>, PixelBasedConcept<P> { where is_pixel<P>::type::value==true; // where for each K [0..size<P>::value-1]: // ChannelConcept<kth_element_type<K> >; typename value_type; where PixelValueConcept<value_type>; typename reference; where PixelConcept<reference>; typename const_reference; where PixelConcept<const_reference>; static const bool P::is_mutable;
template <PixelConcept P2> where { PixelConcept<P,P2> } P::P(P2); template <PixelConcept P2> where { PixelConcept<P,P2> } bool operator==(const P&, const P2&); template <PixelConcept P2> where { PixelConcept<P,P2> } bool operator!=(const P&, const P2&); };
concept MutablePixelConcept<typename P> : PixelConcept<P>, MutableColorBaseConcept<P> { where is_mutable==true; };
concept HomogeneousPixelConcept<PixelConcept P> : HomogeneousColorBaseConcept<P>, HomogeneousPixelBasedConcept<P> { P::template element_const_reference_type<P>::type operator[](P p, std::size_t i) const { return dynamic_at_c(P,i); } };
concept MutableHomogeneousPixelConcept<MutablePixelConcept P> : MutableHomogeneousColorBaseConcept<P> { P::template element_reference_type<P>::type operator[](P p, std::size_t i) { return dynamic_at_c(p,i); } };
concept PixelValueConcept<typename P> : PixelConcept<P>, Regular<P> { where SameType<value_type,P>; };
concept PixelsCompatibleConcept<PixelConcept P1, PixelConcept P2> : ColorBasesCompatibleConcept<P1,P2> { // where for each K [0..size<P1>::value): // ChannelsCompatibleConcept<kth_semantic_element_type<P1,K>::type, kth_semantic_element_type<P2,K>::type>; };
あるpixelは,もう一方のpixelの形式における色情報の値を概算できる場合について,もう一方のpixelへと変換可能です.変換は陽であり,非対称であり,そしてしばしば(そのchannelとcolor spaceの両方が原因で)非可逆変換です.Convertabilityは次のconceptによるモデリングを要求します.
template <PixelConcept SrcPixel, MutablePixelConcept DstPixel> concept PixelConvertibleConcept { void color_convert(const SrcPixel&, DstPixel&); };
PixelConceptとPixelValueConceptの違いは,それがchannelに対するものであるかcolor baseに対するものであるかという違いと似ている.pixel参照は両方のconceptをモデルとし,一方でpixel valueは後者だけをモデルとします.
関連するConcept:
- PixelBasedConcept<P>
- PixelConcept<Pixel>
- MutablePixelConcept<Pixel>
- PixelValueConcept<Pixel>
- HomogeneousPixelConcept<Pixel>
- MutableHomogeneousPixelConcept<Pixel>
- HomogeneousPixelValueConcept<Pixel>
- PixelsCompatibleConcept<Pixel1,Pixel2>
- PixelConvertibleConcept<SrcPixel,DstPixel>
モデル:
最もよく用いられるpixelは,値がメモリ上でひとまとまりに存在するhomogeneous pixelです.このためにGILはchannel valueとlayoutについてのテンプレートであるstruct pixelを提供します.
// models HomogeneousPixelValueConcept template <typename ChannelValue, typename Layout> struct pixel;
// Those typedefs are already provided by GIL typedef pixel<bits8, rgb_layout_t> rgb8_pixel_t; typedef pixel<bits8, bgr_layout_t> bgr8_pixel_t;
bgr8_pixel_t bgr8(255,0,0); // pixels can be initialized with the channels directly rgb8_pixel_t rgb8(bgr8); // compatible pixels can also be copy-constructed
rgb8 = bgr8; // assignment and equality is defined between compatible pixels assert(rgb8 == bgr8); // assignment and equality operate on the semantic channels
// The first physical channels of the two pixels are different assert(at_c<0>(rgb8) != at_c<0>(bgr8)); assert(dynamic_at_c(bgr8,0) != dynamic_at_c(rgb8,0)); assert(rgb8[0] != bgr8[0]); // same as above (but operator[] is defined for pixels only
planar pixelはメモリ上でバラバラに各channelをもっています.同じvalue型(のpixel)をinterleaved pixelと共有しているかぎりにおいて,それらの参照型は各channelへの参照を含んだproxyクラスです.これは,planar_pixel_reference構造体とともに実装されています.
// models HomogeneousPixel template <typename ChannelReference, typename ColorSpace> struct planar_pixel_reference;
// Define the type of a mutable and read-only reference. (These typedefs are already provided by GIL) typedef planar_pixel_reference< bits8&,rgb_t> rgb8_planar_ref_t; typedef planar_pixel_reference<const bits8&,rgb_t> rgb8c_planar_ref_t;
pixel構造体とは異なり,planar pixel referenceはcolor spaceについてテンプレート化されていて,pixel layoutについてはテンプレート化されていないことに注意しましょう.これらは常に標準のchannel順を用います.各要素は各channelを参照することから,要素の並び順についての情報は必要ないのです.
pixelのあるchannelの大きさがバイト単位にそろっていない場合があるかもしれません.例えば,'5-6-5'フォーマットのRGB
pixelはred, green,
blueでそれぞれ[0..4],[5..9],[10..15]のビットを占有しています.GILはこれらのようなpacked
pixelフォーマットにもモデルを提供しています.
// define an rgb565 pixel typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, rgb_layout_t>::type rgb565_pixel_t;
function_requires<PixelValueConcept<rgb565_pixel_t> >(); BOOST_STATIC_ASSERT((sizeof(rgb565_pixel_t)==2));
// define a bgr556 pixel typedef packed_pixel_type<uint16_t, mpl::vector3_c<unsigned,5,6,5>, bgr_layout_t>::type bgr556_pixel_t;
function_requires<PixelValueConcept<bgr556_pixel_t> >();
// rgb565 is compatible with bgr556. function_requires<PixelsCompatibleConcept<rgb565_pixel_t,bgr556_pixel_t> >();
いくつかの場合には,pixel自身の大きさもバイト単位にそろわないと考えられます.例えば,'2-3-2'フォーマットのRGB
pixelについて考えてみましょう.GILはそのようなpixel, pixel iterator,
imageを"bit-aligned"とみなして参照します.bit-aligned pixel (imageも同様)はpacked pixel
(またはimage)よりもさらに複雑です.packed pixelがbyte-alignedであったことから,packed
pixelへの参照型としてC++リファレンスを用いることができ,packed pixelによる行のx_iteratorとしてC
pointerを用いることができました.bit-alignedコンストラクタのために特別な参照proxyクラス
(bit_aligned_pixel_reference)とiteratorクラス(bit_aligned_pixel_iterator)を用意
する必要があります.bit-aligned
pixelのvalue型はpacked_pixelです.ここでは,bit_alignedなpixelとpixel
iteratorをいかに用いるかを示します.
// Mutable reference to a BGR232 pixel typedef const bit_aligned_pixel_reference<mpl::vector3_c<unsigned,2,3,2>, bgr_layout_t, true> bgr232_ref_t;
// A mutable iterator over BGR232 pixels typedef bit_aligned_pixel_iterator<bgr232_ref_t> bgr232_ptr_t;
// BGR232 pixel value. It is a packed_pixel of size 1 byte. (The last bit is unused) typedef std::iterator_traits<bgr232_ptr_t>::value_type bgr232_pixel_t; BOOST_STATIC_ASSERT((sizeof(bgr232_pixel_t)==1));
bgr232_pixel_t red(0,0,3); // = 0RRGGGBB, = 01100000 = 0x60
// a buffer of 7 bytes fits exactly 8 BGR232 pixels. unsigned char pix_buffer[7]; std::fill(pix_buffer,pix_buffer+7,0);
// Fill the 8 pixels with red bgr232_ptr_t pix_it(&pix_buffer[0],0); // start at bit 0 of the first pixel for (int i=0; i<8; ++i) { *pix_it++ = red; } // Result: 0x60 0x30 0x11 0x0C 0x06 0x83 0xC1
Algorithms:
pixelがColorBaseConceptとPixelBasedConceptをモデルとしていることから,全てのcolor baseについてのアルゴリズムとメタ関数はpixelで動作します. // This is how to access the first semantic channel (red) assert(semantic_at_c<0>(rgb8) == semantic_at_c<0>(bgr8));
// This is how to access the red channel by name assert(get_color<red_t>(rgb8) == get_color<red_t>(bgr8));
// This is another way of doing it (some compilers don't like the first one) assert(get_color(rgb8,red_t()) == get_color(bgr8,red_t()));
// This is how to use the PixelBasedConcept metafunctions BOOST_MPL_ASSERT(num_channels<rgb8_pixel_t>::value == 3); BOOST_MPL_ASSERT((is_same<channel_type<rgb8_pixel_t>::type, bits8>)); BOOST_MPL_ASSERT((is_same<color_space_type<bgr8_pixel_t>::type, rgb_t> )); BOOST_MPL_ASSERT((is_same<channel_mapping_type<bgr8_pixel_t>::type, mpl::vector3_c<int,2,1,0> > ));
// Pixels contain just the three channels and nothing extra BOOST_MPL_ASSERT(sizeof(rgb8_pixel_t)==3);
rgb8_planar_ref_t ref(bgr8); // copy construction is allowed from a compatible mutable pixel type
get_color<red_t>(ref) = 10; // assignment is ok because the reference is mutable assert(get_color<red_t>(bgr8)==10); // references modify the value they are bound to
// Create a zero packed pixel and a full regular unpacked pixel. rgb565_pixel_t r565; rgb8_pixel_t rgb_full(255,255,255);
// Convert all channels of the unpacked pixel to the packed one & assert the packed one is full get_color(r565,red_t()) = channel_convert<rgb565_channel0_t>(get_color(rgb_full,red_t())); get_color(r565,green_t()) = channel_convert<rgb565_channel1_t>(get_color(rgb_full,green_t())); get_color(r565,blue_t()) = channel_convert<rgb565_channel2_t>(get_color(rgb_full,blue_t())); assert(r565 == rgb565_pixel_t((uint16_t)65535));
GILは異なるcolor spaceとchannel型のpixelを変換するcolor_convertアルゴリズムを提供します.
rgb8_pixel_t red_in_rgb8(255,0,0); cmyk16_pixel_t red_in_cmyk16; color_convert(red_in_rgb8,red_in_cmyk16);
concept PixelIteratorConcept<RandomAccessTraversalIteratorConcept Iterator> : PixelBasedConcept<Iterator> { where PixelValueConcept<value_type>; typename const_iterator_type<It>::type; where PixelIteratorConcept<const_iterator_type<It>::type>; static const bool iterator_is_mutable<It>::type::value; static const bool is_iterator_adaptor<It>::type::value; // is it an iterator adaptor };
template <typename Iterator> concept MutablePixelIteratorConcept : PixelIteratorConcept<Iterator>, MutableRandomAccessIteratorConcept<Iterator> {};
barfoo...
template <typename ChannelPtr, typename ColorSpace> struct planar_pixel_iterator;
// GIL provided typedefs typedef planar_pixel_iterator<const bits8*, rgb_t> rgb8c_planar_ptr_t; typedef planar_pixel_iterator< bits8*, rgb_t> rgb8_planar_ptr_t;
barfoo...
template <typename T> struct inc : public std::unary_function<T,T> { T operator()(T x) const { return ++x; } };
template <typename ChannelPtr, typename ColorSpace> planar_pixel_iterator<ChannelPtr,ColorSpace>& planar_pixel_iterator<ChannelPtr,ColorSpace>::operator++() { static_transform(*this,*this,inc<ChannelPtr>()); return *this; }
barfoo...
concept IteratorAdaptorConcept<RandomAccessTraversalIteratorConcept Iterator> { where SameType<is_iterator_adaptor<Iterator>::type, mpl::true_>;
typename iterator_adaptor_get_base<Iterator>; where Metafunction<iterator_adaptor_get_base<Iterator> >; where boost_concepts::ForwardTraversalConcept<iterator_adaptor_get_base<Iterator>::type>; typename another_iterator; typename iterator_adaptor_rebind<Iterator,another_iterator>::type; where boost_concepts::ForwardTraversalConcept<another_iterator>; where IteratorAdaptorConcept<iterator_adaptor_rebind<Iterator,another_iterator>::type>;
const iterator_adaptor_get_base<Iterator>::type& Iterator::base() const; };
template <boost_concepts::Mutable_ForwardIteratorConcept Iterator> concept MutableIteratorAdaptorConcept : IteratorAdaptorConcept<Iterator> {};
barfoo...
template <boost::UnaryFunctionConcept D> concept PixelDereferenceAdaptorConcept : DefaultConstructibleConcept<D>, CopyConstructibleConcept<D>, AssignableConcept<D> { typename const_t; where PixelDereferenceAdaptorConcept<const_t>; typename value_type; where PixelValueConcept<value_type>; typename reference; where PixelConcept<remove_reference<reference>::type>; // may be mutable typename const_reference; // must not be mutable static const bool D::is_mutable;
where Convertible<value_type, result_type>; };
barfoo...
concept StepIteratorConcept<boost_concepts::ForwardTraversalConcept Iterator> { template <Integral D> void Iterator::set_step(D step); };
concept MutableStepIteratorConcept<boost_concepts::Mutable_ForwardIteratorConcept Iterator> : StepIteratorConcept<Iterator> {};
barfoo...
concept MemoryBasedIteratorConcept<boost_concepts::RandomAccessTraversalConcept Iterator> { typename byte_to_memunit<Iterator>; where metafunction<byte_to_memunit<Iterator> >; std::ptrdiff_t memunit_step(const Iterator&); std::ptrdiff_t memunit_distance(const Iterator& , const Iterator&); void memunit_advance(Iterator&, std::ptrdiff_t diff); Iterator memunit_advanced(const Iterator& p, std::ptrdiff_t diff) { Iterator tmp; memunit_advance(tmp,diff); return tmp; } Iterator::reference memunit_advanced_ref(const Iterator& p, std::ptrdiff_t diff) { return *memunit_advanced(p,diff); } };
barfoo...
concept HasDynamicXStepTypeConcept<typename T> { typename dynamic_x_step_type<T>; where Metafunction<dynamic_x_step_type<T> >; };
barfoo...
template <typename I> // Models MemoryBasedIteratorConcept, HasDynamicXStepTypeConcept typename dynamic_x_step_type<I>::type make_step_iterator(const I& it, std::ptrdiff_t step);
barfoo...
concept RandomAccessNDLocatorConcept<Regular Loc> { typename value_type; // value over which the locator navigates typename reference; // result of dereferencing typename difference_type; where PointNDConcept<difference_type>; // return value of operator-. typename const_t; // same as Loc, but operating over immutable values typename cached_location_t; // type to store relative location (for efficient repeated access) typename point_t = difference_type; static const size_t num_dimensions; // dimensionality of the locator where num_dimensions = point_t::num_dimensions; // The difference_type and iterator type along each dimension. The iterators may only differ in // difference_type. Their value_type must be the same as Loc::value_type template <size_t D> struct axis { typename coord_t = point_t::axis<D>::coord_t; typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis. where iterator::value_type == value_type; };
// Defines the type of a locator similar to this type, except it invokes Deref upon dereferencing template <PixelDereferenceAdaptorConcept Deref> struct add_deref { typename type; where RandomAccessNDLocatorConcept<type>; static type make(const Loc& loc, const Deref& deref); }; Loc& operator+=(Loc&, const difference_type&); Loc& operator-=(Loc&, const difference_type&); Loc operator+(const Loc&, const difference_type&); Loc operator-(const Loc&, const difference_type&); reference operator*(const Loc&); reference operator[](const Loc&, const difference_type&); // Storing relative location for faster repeated access and accessing it cached_location_t Loc::cache_location(const difference_type&) const; reference operator[](const Loc&,const cached_location_t&); // Accessing iterators along a given dimension at the current location or at a given offset template <size_t D> axis<D>::iterator& Loc::axis_iterator(); template <size_t D> axis<D>::iterator const& Loc::axis_iterator() const; template <size_t D> axis<D>::iterator Loc::axis_iterator(const difference_type&) const; };
template <typename Loc> concept MutableRandomAccessNDLocatorConcept : RandomAccessNDLocatorConcept<Loc> { where Mutable<reference>; };
barfoo...
concept RandomAccess2DLocatorConcept<RandomAccessNDLocatorConcept Loc> { where num_dimensions==2; where Point2DConcept<point_t>; typename x_iterator = axis<0>::iterator; typename y_iterator = axis<1>::iterator; typename x_coord_t = axis<0>::coord_t; typename y_coord_t = axis<1>::coord_t; // Only available to locators that have dynamic step in Y //Loc::Loc(const Loc& loc, y_coord_t);
// Only available to locators that have dynamic step in X and Y //Loc::Loc(const Loc& loc, x_coord_t, y_coord_t, bool transposed=false);
x_iterator& Loc::x(); x_iterator const& Loc::x() const; y_iterator& Loc::y(); y_iterator const& Loc::y() const; x_iterator Loc::x_at(const difference_type&) const; y_iterator Loc::y_at(const difference_type&) const; Loc Loc::xy_at(const difference_type&) const; // x/y versions of all methods that can take difference type x_iterator Loc::x_at(x_coord_t, y_coord_t) const; y_iterator Loc::y_at(x_coord_t, y_coord_t) const; Loc Loc::xy_at(x_coord_t, y_coord_t) const; reference operator()(const Loc&, x_coord_t, y_coord_t); cached_location_t Loc::cache_location(x_coord_t, y_coord_t) const;
bool Loc::is_1d_traversable(x_coord_t width) const; y_coord_t Loc::y_distance_to(const Loc& loc2, x_coord_t x_diff) const; };
concept MutableRandomAccess2DLocatorConcept<RandomAccess2DLocatorConcept Loc> : MutableRandomAccessNDLocatorConcept<Loc> {};
barfoo...
concept HasDynamicYStepTypeConcept<typename T> { typename dynamic_y_step_type<T>; where Metafunction<dynamic_y_step_type<T> >; };
barfoo...
concept HasTransposedTypeConcept<typename T> { typename transposed_type<T>; where Metafunction<transposed_type<T> >; };
barfoo...
concept PixelLocatorConcept<RandomAccess2DLocatorConcept Loc> { where PixelValueConcept<value_type>; where PixelIteratorConcept<x_iterator>; where PixelIteratorConcept<y_iterator>; where x_coord_t == y_coord_t;
typename coord_t = x_coord_t; };
concept MutablePixelLocatorConcept<PixelLocatorConcept Loc> : MutableRandomAccess2DLocatorConcept<Loc> {};
barfoo...
template <typename StepIterator> // Models StepIteratorConcept, MemoryBasedIteratorConcept class memory_based_2d_locator;
barfoo...
loc=img.xy_at(10,10); // start at pixel (x=10,y=10) above=loc.cache_location(0,-1); // remember relative locations of neighbors above and below below=loc.cache_location(0, 1); ++loc.x(); // move to (11,10) loc.y()+=15; // move to (11,25) loc-=point2<std::ptrdiff_t>(1,1);// move to (10,24) *loc=(loc(0,-1)+loc(0,1))/2; // set pixel (10,24) to the average of (10,23) and (10,25) (grayscale pixels only) *loc=(loc[above]+loc[below])/2; // the same, but faster using cached relative neighbor locations
barfoo...
template <typename Locator> // Models PixelLocatorConcept class iterator_from_2d { public: iterator_from_2d(const Locator& loc, int x, int width); iterator_from_2d& operator++(); // if (++_x<_width) ++_p.x(); else _p+=point_t(-_width,1);
... private: int _x, _width; Locator _p; };
barfoo...
concept RandomAccessNDImageViewConcept<Regular View> { typename value_type; // for pixel-based views, the pixel type typename reference; // result of dereferencing typename difference_type; // result of operator-(iterator,iterator) (1-dimensional!) typename const_t; where RandomAccessNDImageViewConcept<View>; // same as View, but over immutable values typename point_t; where PointNDConcept<point_t>; // N-dimensional point typename locator; where RandomAccessNDLocatorConcept<locator>; // N-dimensional locator. typename iterator; where RandomAccessTraversalConcept<iterator>; // 1-dimensional iterator over all values typename reverse_iterator; where RandomAccessTraversalConcept<reverse_iterator>; typename size_type; // the return value of size()
// Equivalent to RandomAccessNDLocatorConcept::axis template <size_t D> struct axis { typename coord_t = point_t::axis<D>::coord_t; typename iterator; where RandomAccessTraversalConcept<iterator>; // iterator along D-th axis. where SameType<coord_t, iterator::difference_type>; where SameType<iterator::value_type,value_type>; };
// Defines the type of a view similar to this type, except it invokes Deref upon dereferencing template <PixelDereferenceAdaptorConcept Deref> struct add_deref { typename type; where RandomAccessNDImageViewConcept<type>; static type make(const View& v, const Deref& deref); };
static const size_t num_dimensions = point_t::num_dimensions; // Create from a locator at the top-left corner and dimensions View::View(const locator&, const point_type&); size_type View::size() const; // total number of elements reference operator[](View, const difference_type&) const; // 1-dimensional reference iterator View::begin() const; iterator View::end() const; reverse_iterator View::rbegin() const; reverse_iterator View::rend() const; iterator View::at(const point_t&); point_t View::dimensions() const; // number of elements along each dimension bool View::is_1d_traversable() const; // Does an iterator over the first dimension visit each value?
// iterator along a given dimension starting at a given point template <size_t D> View::axis<D>::iterator View::axis_iterator(const point_t&) const;
reference operator()(View,const point_t&) const; };
concept MutableRandomAccessNDImageViewConcept<RandomAccessNDImageViewConcept View> { where Mutable<reference>; };
barfoo...
concept RandomAccess2DImageViewConcept<RandomAccessNDImageViewConcept View> { where num_dimensions==2;
typename x_iterator = axis<0>::iterator; typename y_iterator = axis<1>::iterator; typename x_coord_t = axis<0>::coord_t; typename y_coord_t = axis<1>::coord_t; typename xy_locator = locator; x_coord_t View::width() const; y_coord_t View::height() const; // X-navigation x_iterator View::x_at(const point_t&) const; x_iterator View::row_begin(y_coord_t) const; x_iterator View::row_end (y_coord_t) const;
// Y-navigation y_iterator View::y_at(const point_t&) const; y_iterator View::col_begin(x_coord_t) const; y_iterator View::col_end (x_coord_t) const; // navigating in 2D xy_locator View::xy_at(const point_t&) const;
// (x,y) versions of all methods taking point_t View::View(x_coord_t,y_coord_t,const locator&); iterator View::at(x_coord_t,y_coord_t) const; reference operator()(View,x_coord_t,y_coord_t) const; xy_locator View::xy_at(x_coord_t,y_coord_t) const; x_iterator View::x_at(x_coord_t,y_coord_t) const; y_iterator View::y_at(x_coord_t,y_coord_t) const; };
concept MutableRandomAccess2DImageViewConcept<RandomAccess2DImageViewConcept View> : MutableRandomAccessNDImageViewConcept<View> {};
barfoo...
concept ImageViewConcept<RandomAccess2DImageViewConcept View> { where PixelValueConcept<value_type>; where PixelIteratorConcept<x_iterator>; where PixelIteratorConcept<y_iterator>; where x_coord_t == y_coord_t; typename coord_t = x_coord_t;
std::size_t View::num_channels() const; };
concept MutableImageViewConcept<ImageViewConcept View> : MutableRandomAccess2DImageViewConcept<View> {};
barfoo...
concept ViewsCompatibleConcept<ImageViewConcept V1, ImageViewConcept V2> { where PixelsCompatibleConcept<V1::value_type, V2::value_type>; where V1::num_dimensions == V2::num_dimensions; };
barfoo...
template <typename Locator> // Models PixelLocatorConcept (could be MutablePixelLocatorConcept) class image_view { public: typedef Locator xy_locator; typedef iterator_from_2d<Locator> iterator; ... private: xy_locator _pixels; // 2D pixel locator at the top left corner of the image view range point_t _dimensions; // width and height };
barfoo...
template <typename Iterator> // Models pixel iterator (like rgb8_ptr_t or rgb8c_ptr_t) image_view<...> interleaved_view(ptrdiff_t width, ptrdiff_t height, Iterator pixels, ptrdiff_t rowsize)
barfoo...
template <typename IC> // Models channel iterator (like bits8* or const bits8*) image_view<...> planar_rgb_view(ptrdiff_t width, ptrdiff_t height, IC r, IC g, IC b, ptrdiff_t rowsize);
barfoo...
// Some result view types template <typename View> struct dynamic_xy_step_type : public dynamic_y_step_type<typename dynamic_x_step_type<View>::type> {};
template <typename View> struct dynamic_xy_step_transposed_type : public dynamic_xy_step_type<typename transposed_type<View>::type> {};
// color and bit depth converted view to match pixel type P template <typename SrcView, // Models ImageViewConcept typename DstP, // Models PixelConcept typename ColorConverter=gil::default_color_converter> struct color_converted_view_type { typedef ... type; // image view adaptor with value type DstP, over SrcView };
// single-channel view of the N-th channel of a given view template <typename SrcView> struct nth_channel_view_type { typedef ... type; };
barfoo...
// flipped upside-down, left-to-right, transposed view template <typename View> typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src); template <typename View> typename dynamic_x_step_type<View>::type flipped_left_right_view(const View& src); template <typename View> typename dynamic_xy_step_transposed_type<View>::type transposed_view(const View& src);
// rotations template <typename View> typename dynamic_xy_step_type<View>::type rotated180_view(const View& src); template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90cw_view(const View& src); template <typename View> typename dynamic_xy_step_transposed_type<View>::type rotated90ccw_view(const View& src);
// view of an axis-aligned rectangular area within an image template <typename View> View subimage_view(const View& src, const View::point_t& top_left, const View::point_t& dimensions);
// subsampled view (skipping pixels in X and Y) template <typename View> typename dynamic_xy_step_type<View>::type subsampled_view(const View& src, const View::point_t& step);
template <typename View, typename P> color_converted_view_type<View,P>::type color_converted_view(const View& src); template <typename View, typename P, typename CCV> // with a custom color converter color_converted_view_type<View,P,CCV>::type color_converted_view(const View& src);
template <typename View> nth_channel_view_type<View>::view_t nth_channel_view(const View& view, int n);
barfoo...
template <typename View> typename dynamic_y_step_type<View>::type flipped_up_down_view(const View& src) { gil_function_requires<ImageViewConcept<View> >(); typedef typename dynamic_y_step_type<View>::type RView; return RView(src.dimensions(),typename RView::xy_locator(src.xy_at(0,src.height()-1),-1)); }
barfoo...
rgb16_image_t img(100,100); // an RGB interleaved image
// grayscale view over the green (index 1) channel of img gray16_step_view_t green=nth_channel_view(view(img),1);
// 50x50 view of the green channel of img, upside down and taking every other pixel in X and in Y gray16_step_view_t ud_fud=flipped_up_down_view(subsampled_view(green,2,2));
barfoo...
// Equivalents of std::copy and std::uninitialized_copy // where ImageViewConcept<V1>, MutableImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2> template <typename V1, typename V2> void copy_pixels(const V1& src, const V2& dst); template <typename V1, typename V2> void uninitialized_copy_pixels(const V1& src, const V2& dst);
// Equivalents of std::fill and std::uninitialized_fill // where MutableImageViewConcept<V>, PixelConcept<Value>, PixelsCompatibleConcept<Value,V::value_type> template <typename V, typename Value> void fill_pixels(const V& dst, const Value& val); template <typename V, typename Value> void uninitialized_fill_pixels(const V& dst, const Value& val);
// Equivalent of std::for_each // where ImageViewConcept<V>, boost::UnaryFunctionConcept<F> // where PixelsCompatibleConcept<V::reference, F::argument_type> template <typename V, typename F> F for_each_pixel(const V& view, F fun); template <typename V, typename F> F for_each_pixel_position(const V& view, F fun);
// Equivalent of std::generate // where MutableImageViewConcept<V>, boost::UnaryFunctionConcept<F> // where PixelsCompatibleConcept<V::reference, F::argument_type> template <typename V, typename F> void generate_pixels(const V& dst, F fun);
// Equivalent of std::transform with one source // where ImageViewConcept<V1>, MutableImageViewConcept<V2> // where boost::UnaryFunctionConcept<F> // where PixelsCompatibleConcept<V1::const_reference, F::argument_type> // where PixelsCompatibleConcept<F::result_type, V2::reference> template <typename V1, typename V2, typename F> F transform_pixels(const V1& src, const V2& dst, F fun); template <typename V1, typename V2, typename F> F transform_pixel_positions(const V1& src, const V2& dst, F fun);
// Equivalent of std::transform with two sources // where ImageViewConcept<V1>, ImageViewConcept<V2>, MutableImageViewConcept<V3> // where boost::BinaryFunctionConcept<F> // where PixelsCompatibleConcept<V1::const_reference, F::first_argument_type> // where PixelsCompatibleConcept<V2::const_reference, F::second_argument_type> // where PixelsCompatibleConcept<F::result_type, V3::reference> template <typename V1, typename V2, typename V3, typename F> F transform_pixels(const V1& src1, const V2& src2, const V3& dst, F fun); template <typename V1, typename V2, typename V3, typename F> F transform_pixel_positions(const V1& src1, const V2& src2, const V3& dst, F fun);
// Copies a view into another, color converting the pixels if needed, with the default or user-defined color converter // where ImageViewConcept<V1>, MutableImageViewConcept<V2> // V1::value_type must be convertible to V2::value_type. template <typename V1, typename V2> void copy_and_convert_pixels(const V1& src, const V2& dst); template <typename V1, typename V2, typename ColorConverter> void copy_and_convert_pixels(const V1& src, const V2& dst, ColorConverter ccv);
// Equivalent of std::equal // where ImageViewConcept<V1>, ImageViewConcept<V2>, ViewsCompatibleConcept<V1,V2> template <typename V1, typename V2> bool equal_pixels(const V1& view1, const V2& view2);
barfoo...
concept RandomAccessNDImageConcept<typename Img> : Regular<Img> { typename view_t; where MutableRandomAccessNDImageViewConcept<view_t>; typename const_view_t = view_t::const_t; typename point_t = view_t::point_t; typename value_type = view_t::value_type; typename allocator_type;
Img::Img(point_t dims, std::size_t alignment=1); Img::Img(point_t dims, value_type fill_value, std::size_t alignment); void Img::recreate(point_t new_dims, std::size_t alignment=1); void Img::recreate(point_t new_dims, value_type fill_value, std::size_t alignment);
const point_t& Img::dimensions() const; const const_view_t& const_view(const Img&); const view_t& view(Img&); };
barfoo...
concept RandomAccess2DImageConcept<RandomAccessNDImageConcept Img> { typename x_coord_t = const_view_t::x_coord_t; typename y_coord_t = const_view_t::y_coord_t; Img::Img(x_coord_t width, y_coord_t height, std::size_t alignment=1); Img::Img(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment);
x_coord_t Img::width() const; y_coord_t Img::height() const; void Img::recreate(x_coord_t width, y_coord_t height, std::size_t alignment=1); void Img::recreate(x_coord_t width, y_coord_t height, value_type fill_value, std::size_t alignment); };
barfoo...
concept ImageConcept<RandomAccess2DImageConcept Img> { where MutableImageViewConcept<view_t>; typename coord_t = view_t::coord_t; };
barfoo...
template <typename Pixel, \\ Models PixelValueConcept bool IsPlanar, \\ planar or interleaved image typename A=std::allocator<unsigned char> > class image;
barfoo...
#include <boost/gil/extension/dynamic_image/dynamic_image_all.hpp> using namespace boost;
#define ASSERT_SAME(A,B) BOOST_STATIC_ASSERT((is_same< A,B >::value))
// Define the set of allowed images typedef mpl::vector<rgb8_image_t, cmyk16_planar_image_t> my_images_t;
// Create any_image class (or any_image_view) class typedef any_image<my_images_t> my_any_image_t;
// Associated view types are available (equivalent to the ones in image_t) typedef any_image_view<mpl::vector2<rgb8_view_t, cmyk16_planar_view_t > > AV; ASSERT_SAME(my_any_image_t::view_t, AV);
typedef any_image_view<mpl::vector2<rgb8c_view_t, cmyk16c_planar_view_t> > CAV; ASSERT_SAME(my_any_image_t::const_view_t, CAV); ASSERT_SAME(my_any_image_t::const_view_t, my_any_image_t::view_t::const_t);
typedef any_image_view<mpl::vector2<rgb8_step_view_t, cmyk16_planar_step_view_t> > SAV; ASSERT_SAME(typename dynamic_x_step_type<my_any_image_t::view_t>::type, SAV);
// Assign it a concrete image at run time: my_any_image_t myImg = my_any_image_t(rgb8_image_t(100,100));
// Change it to another at run time. The previous image gets destroyed myImg = cmyk16_planar_image_t(200,100);
// Assigning to an image not in the allowed set throws an exception myImg = gray8_image_t(); // will throw std::bad_cast
barfoo...
template <typename Types> // models MPL Random Access Container class variant { ... _bits; std::size_t _index; public: typedef Types types_t;
variant(); variant(const variant& v); virtual ~variant(); variant& operator=(const variant& v); template <typename TS> friend bool operator==(const variant<TS>& x, const variant<TS>& y); template <typename TS> friend bool operator!=(const variant<TS>& x, const variant<TS>& y);
// Construct/assign to type T. Throws std::bad_cast if T is not in Types template <typename T> explicit variant(const T& obj); template <typename T> variant& operator=(const T& obj);
// Construct/assign by swapping T with its current instance. Only possible if they are swappable template <typename T> explicit variant(T& obj, bool do_swap); template <typename T> void move_in(T& obj);
template <typename T> static bool has_type();
template <typename T> const T& _dynamic_cast() const; template <typename T> T& _dynamic_cast(); template <typename T> bool current_type_is() const; };
template <typename UOP, typename Types> UOP::result_type apply_operation(variant<Types>& v, UOP op); template <typename UOP, typename Types> UOP::result_type apply_operation(const variant<Types>& v, UOP op);
template <typename BOP, typename Types1, typename Types2> BOP::result_type apply_operation( variant<Types1>& v1, variant<Types2>& v2, UOP op);
template <typename BOP, typename Types1, typename Types2> BOP::result_type apply_operation(const variant<Types1>& v1, variant<Types2>& v2, UOP op);
template <typename BOP, typename Types1, typename Types2> BOP::result_type apply_operation(const variant<Types1>& v1, const variant<Types2>& v2, UOP op);
barfoo...
template <typename ImageViewTypes> class any_image_view : public variant<ImageViewTypes> { public: typedef ... const_t; // immutable equivalent of this typedef std::ptrdiff_t x_coord_t; typedef std::ptrdiff_t y_coord_t; typedef point2<std::ptrdiff_t> point_t;
any_image_view(); template <typename T> explicit any_image_view(const T& obj); any_image_view(const any_image_view& v);
template <typename T> any_image_view& operator=(const T& obj); any_image_view& operator=(const any_image_view& v);
// parameters of the currently instantiated view std::size_t num_channels() const; point_t dimensions() const; x_coord_t width() const; y_coord_t height() const; };
template <typename ImageTypes> class any_image : public variant<ImageTypes> { typedef variant<ImageTypes> parent_t; public: typedef ... const_view_t; typedef ... view_t; typedef std::ptrdiff_t x_coord_t; typedef std::ptrdiff_t y_coord_t; typedef point2<std::ptrdiff_t> point_t;
any_image(); template <typename T> explicit any_image(const T& obj); template <typename T> explicit any_image(T& obj, bool do_swap); any_image(const any_image& v);
template <typename T> any_image& operator=(const T& obj); any_image& operator=(const any_image& v);
void recreate(const point_t& dims, unsigned alignment=1); void recreate(x_coord_t width, y_coord_t height, unsigned alignment=1);
std::size_t num_channels() const; point_t dimensions() const; x_coord_t width() const; y_coord_t height() const; };
barfoo...
rgb8_view_t v1(...); // concrete image view bgr8_view_t v2(...); // concrete image view compatible with v1 and of the same size any_image_view<Types> av(...); // run-time specified image view
// Copies the pixels from v1 into v2. // If the pixels are incompatible triggers compile error copy_pixels(v1,v2);
// The source or destination (or both) may be run-time instantiated. // If they happen to be incompatible, throws std::bad_cast copy_pixels(v1, av); copy_pixels(av, v2); copy_pixels(av, av);
barfoo...
#include <boost\gil\extension\io\jpeg_dynamic_io.hpp>
template <typename Image> // Could be rgb8_image_t or any_image<...> void save_180rot(const std::string& file_name) { Image img; jpeg_read_image(file_name, img); jpeg_write_view(file_name, rotated180_view(view(img))); }
barfoo...
// implementation using templated view template <typename View> typename dynamic_xy_step_type<View>::type rotated180_view(const View& src) { ... }
namespace detail { // the function, wrapped inside a function object template <typename Result> struct rotated180_view_fn { typedef Result result_type; template <typename View> result_type operator()(const View& src) const { return result_type(rotated180_view(src)); } }; }
// overloading of the function using variant. Takes and returns run-time bound view. // The returned view has a dynamic step template <typename ViewTypes> inline // Models MPL Random Access Container of models of ImageViewConcept typename dynamic_xy_step_type<any_image_view<ViewTypes> >::type rotated180_view(const any_image_view<ViewTypes>& src) { return apply_operation(src,detail::rotated180_view_fn<typename dynamic_xy_step_type<any_image_view<ViewTypes> >::type>()); }
barfoo...
bgr8_image_t i; // 8-bit unsigned (unsigned char) interleaved BGR image cmyk16_pixel_t; x; // 16-bit unsigned (unsigned short) CMYK pixel value; cmyk16sc_planar_ref_t p(x); // const reference to a 16-bit signed integral (signed short) planar CMYK pixel x. rgb32f_planar_step_ptr_t ii; // step iterator to a floating point 32-bit (float) planar RGB pixel.
barfoo...
template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsMutable=true> struct pixel_reference_type { typedef ... type; };
template <typename Channel, typename Layout> struct pixel_value_type { typedef ... type; };
template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true> struct iterator_type { typedef ... type; };
template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true> struct locator_type { typedef ... type; };
template <typename ChannelValue, typename Layout, bool IsPlanar=false, bool IsXStep=false, bool IsMutable=true> struct view_type { typedef ... type; };
template <typename ChannelValue, typename Layout, bool IsPlanar=false, typename Alloc=std::allocator<unsigned char> > struct image_type { typedef ... type; };
template <typename BitField, typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image_type { typedef ... type; };
template <typename ChannelBitSizeVector, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image_type { typedef ... type; };
barfoo...
template <typename BitField, unsigned Size1, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image1_type { typedef ... type; };
template <typename BitField, unsigned Size1, unsigned Size2, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image2_type { typedef ... type; };
template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image3_type { typedef ... type; };
template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image4_type { typedef ... type; };
template <typename BitField, unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5, typename Layout, typename Alloc=std::allocator<unsigned char> > struct packed_image5_type { typedef ... type; };
template <unsigned Size1, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image1_type { typedef ... type; };
template <unsigned Size1, unsigned Size2, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image2_type { typedef ... type; };
template <unsigned Size1, unsigned Size2, unsigned Size3, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image3_type { typedef ... type; };
template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image4_type { typedef ... type; };
template <unsigned Size1, unsigned Size2, unsigned Size3, unsigned Size4, unsigned Size5, typename Layout, typename Alloc=std::allocator<unsigned char> > struct bit_aligned_image5_type { typedef ... type; };
barfoo...
template <typename Pixel, bool IsPlanar=false, bool IsStep=false, bool IsMutable=true> struct iterator_type_from_pixel { typedef ... type; };
template <typename Pixel, bool IsPlanar=false, bool IsStepX=false, bool IsMutable=true> struct view_type_from_pixel { typedef ... type; };
barfoo...
template <typename XIterator> struct type_from_x_iterator { typedef ... step_iterator_t; typedef ... xy_locator_t; typedef ... view_t; };
barfoo...
template <typename PixelReference, typename ChannelValue, typename Layout, typename IsPlanar, typename IsMutable> struct derived_pixel_reference_type { typedef ... type; // Models PixelConcept };
template <typename Iterator, typename ChannelValue, typename Layout, typename IsPlanar, typename IsStep, typename IsMutable> struct derived_iterator_type { typedef ... type; // Models PixelIteratorConcept };
template <typename View, typename ChannelValue, typename Layout, typename IsPlanar, typename IsXStep, typename IsMutable> struct derived_view_type { typedef ... type; // Models ImageViewConcept };
template <typename Image, typename ChannelValue, typename Layout, typename IsPlanar> struct derived_image_type { typedef ... type; // Models ImageConcept };
barfoo...
typedef typename derived_view_type<View, boost::use_default, gray_t, mpl::true_>::type VT;
barfoo...
template <typename T> struct color_space_type { typedef ... type; }; template <typename T> struct channel_mapping_type { typedef ... type; }; template <typename T> struct is_planar { typedef ... type; };
// Defined by homogeneous constructs template <typename T> struct channel_type { typedef ... type; }; template <typename T> struct num_channels { typedef ... type; };
barfoo...
BOOST_STATIC_ASSERT(is_planar<rgb8_planar_view_t>::value == true);
barfoo...
if (view_is_mutable<View>::value) { ... }
// Returns the width and height of the JPEG file at the specified location. // Throws std::ios_base::failure if the location does not correspond to a valid JPEG file point2<std::ptrdiff_t> jpeg_read_dimensions(const char*);
// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it. // Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension. // Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not // compatible with the ones specified by Image template <typename Img> void jpeg_read_image(const char*, Img&);
// Allocates a new image whose dimensions are determined by the given jpeg image file, and loads the pixels into it, // color-converting and channel-converting if necessary. // Triggers a compile assert if the image color space or channel depth are not supported by the JPEG library or by the I/O extension. // Throws std::ios_base::failure if the file is not a valid JPEG file or if it fails to read it. template <typename Img> void jpeg_read_and_convert_image(const char*, Img&); template <typename Img, typename CCV> void jpeg_read_and_convert_image(const char*, Img&, CCV color_converter);
// Loads the image specified by the given jpeg image file name into the given view. // Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. // Throws std::ios_base::failure if the file is not a valid JPEG file, or if its color space or channel depth are not // compatible with the ones specified by View, or if its dimensions don't match the ones of the view. template <typename View> void jpeg_read_view(const char*, const View&);
// Loads the image specified by the given jpeg image file name into the given view and color-converts (and channel-converts) it if necessary. // Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. // Throws std::ios_base::failure if the file is not a valid JPEG file, or if its dimensions don't match the ones of the view. template <typename View> void jpeg_read_and_convert_view(const char*, const View&); template <typename View, typename CCV> void jpeg_read_and_convert_view(const char*, const View&, CCV color_converter);
// Saves the view to a jpeg file specified by the given jpeg image file name. // Triggers a compile assert if the view color space and channel depth are not supported by the JPEG library or by the I/O extension. // Throws std::ios_base::failure if it fails to create the file. template <typename View> void jpeg_write_view(const char*, const View&);
// Determines whether the given view type is supported for reading template <typename View> struct jpeg_read_support { static const bool value = ...; };
// Determines whether the given view type is supported for writing template <typename View> struct jpeg_write_support { static const bool value = ...; };
barfoo...
// Opens the given JPEG file name, selects the first type in Images whose color space and channel are compatible to those of the image file // and creates a new image of that type with the dimensions specified by the image file. // Throws std::ios_base::failure if none of the types in Images are compatible with the type on disk. template <typename Images> void jpeg_read_image(const char*, any_image<Images>&);
// Saves the currently instantiated view to a jpeg file specified by the given jpeg image file name. // Throws std::ios_base::failure if the currently instantiated view type is not supported for writing by the I/O extension // or if it fails to create the file. template <typename Views> void jpeg_write_view(const char*, any_image_view<Views>&);
barfoo...
rgb8_pixel_t p1(255,0,0); // make a red RGB pixel bgr8_pixel_t p2 = p1; // RGB and BGR are compatible and the channels will be properly mapped. assert(p1==p2); // p2 will also be red. assert(p2[0]!=p1[0]); // operator[] gives physical channel order (as laid down in memory) assert(semantic_at_c<0>(p1)==semantic_at_c<0>(p2)); // this is how to compare the two red channels get_color(p1,green_t()) = get_color(p2,blue_t()); // channels can also be accessed by name
const unsigned char* r; const unsigned char* g; const unsigned char* b; rgb8c_planar_ptr_t ptr(r,g,b); // constructing const planar pointer from const pointers to each plane
rgb8c_planar_ref_t ref=*ptr; // just like built-in reference, dereferencing a planar pointer returns a planar reference
p2=ref; p2=p1; p2=ptr[7]; p2=rgb8_pixel_t(1,2,3); // planar/interleaved references and values to RGB/BGR can be freely mixed
//rgb8_planar_ref_t ref2; // compile error: References have no default constructors //ref2=*ptr; // compile error: Cannot construct non-const reference by dereferencing const pointer //ptr[3]=p1; // compile error: Cannot set the fourth pixel through a const pointer //p1 = pixel<float, rgb_layout_t>();// compile error: Incompatible channel depth //p1 = pixel<bits8, rgb_layout_t>();// compile error: Incompatible color space (even though it has the same number of channels) //p1 = pixel<bits8,rgba_layout_t>();// compile error: Incompatible color space (even though it contains red, green and blue channels)
barfoo...
template <typename GrayPixel, typename RGBPixel> void gray_to_rgb(const GrayPixel& src, RGBPixel& dst) { gil_function_requires<PixelConcept<GrayPixel> >(); gil_function_requires<MutableHomogeneousPixelConcept<RGBPixel> >();
typedef typename color_space_type<GrayPixel>::type gray_cs_t; BOOST_STATIC_ASSERT((boost::is_same<gray_cs_t,gray_t>::value));
typedef typename color_space_type<RGBPixel>::type rgb_cs_t; BOOST_STATIC_ASSERT((boost::is_same<rgb_cs_t,rgb_t>::value));
typedef typename channel_type<GrayPixel>::type gray_channel_t; typedef typename channel_type<RGBPixel>::type rgb_channel_t;
gray_channel_t gray = get_color(src,gray_color_t()); static_fill(dst, channel_convert<rgb_channel_t>(gray)); }
// example use patterns:
// converting gray l-value to RGB and storing at (5,5) in a 16-bit BGR interleaved image: bgr16_view_t b16(...); gray_to_rgb(gray8_pixel_t(33), b16(5,5));
// storing the first pixel of an 8-bit grayscale image as the 5-th pixel of 32-bit planar RGB image: rgb32f_planar_view_t rpv32; gray8_view_t gv8(...); gray_to_rgb(*gv8.begin(), rpv32[5]);
barfoo...
template <typename SrcView, // Models ImageViewConcept (the source view) typename DstImage> // Models ImageConcept (the returned image) void create_with_margin(const SrcView& src, int k, DstImage& result) { gil_function_requires<ImageViewConcept<SrcView> >(); gil_function_requires<ImageConcept<DstImage> >(); gil_function_requires<ViewsCompatibleConcept<SrcView, typename DstImage::view_t> >(); result=DstImage(src.width()+2*k, src.height()+2*k); typename DstImage::view_t centerImg=subimage_view(view(result), k,k,src.width(),src.height()); std::copy(src.begin(), src.end(), centerImg.begin()); }
barfoo...
template <typename SrcView, typename DstImage> void create_with_margin(const SrcView& src, int k, DstImage& result) { result.recreate(src.width()+2*k, src.height()+2*k); copy_pixels(src, subimage_view(view(result), k,k,src.width(),src.height())); }
barfoo...
template <typename GrayView, typename R> void grayimage_histogram(const GrayView& img, R& hist) { for (typename GrayView::iterator it=img.begin(); it!=img.end(); ++it) ++hist[*it]; }
barfoo...
template <typename GrayView, typename R> void grayimage_histogram(const GrayView& v, R& hist) { for_each_pixel(v, ++var(hist)[_1]); }
barfoo...
template <typename View, typename R> void luminosity_histogram(const View& v, R& hist) { grayimage_histogram(color_converted_view<gray8_pixel_t>(v),hist); }
barfoo...
unsigned char hist[256]; std::fill(hist,hist+256,0); luminosity_histogram(my_view,hist);
barfoo...
grayimage_histogram(nth_channel_view(subimage_view(img,0,0,100,100),1),hist);
barfoo...
jpeg_read_image("monkey.jpg", img); step1=view(img); step2=subimage_view(step1, 200,300, 150,150); step3=color_converted_view<rgb8_view_t,gray8_pixel_t>(step2); step4=rotated180_view(step3); step5=subsampled_view(step4, 2,1); jpeg_write_view("monkey_transform.jpg", step5);
barfoo...
typedef pixel<double,rgb_layout_t> rgb64_pixel_t; // 64 bit RGB pixel typedef rgb64_pixel* rgb64_pixel_ptr_t;// pointer to 64-bit interleaved data typedef image_type<double,rgb_layout_t>::type rgb64_image_t; // 64-bit interleaved image
barfoo...
// make the default use GIL's default template <typename SrcColorSpace, typename DstColorSpace> struct my_color_converter_impl : public default_color_converter_impl<SrcColorSpace,DstColorSpace> {};
// provide specializations only for cases you care about // (in this case, if the destination is grayscale, invert it) template <typename SrcColorSpace> struct my_color_converter_impl<SrcColorSpace,gray_t> { template <typename SrcP, typename DstP> // Model PixelConcept void operator()(const SrcP& src, DstP& dst) const { default_color_converter_impl<SrcColorSpace,gray_t>()(src,dst); get_color(dst,gray_color_t())=channel_invert(get_color(dst,gray_color_t())); } };
// create a color converter object that dispatches to your own implementation struct my_color_converter { template <typename SrcP, typename DstP> // Model PixelConcept void operator()(const SrcP& src,DstP& dst) const { typedef typename color_space_type<SrcP>::type SrcColorSpace; typedef typename color_space_type<DstP>::type DstColorSpace; my_color_converter_impl<SrcColorSpace,DstColorSpace>()(src,dst); } };
barfoo...
color_converted_view<gray8_pixel_t>(img_view,my_color_converter());
barfoo...
template <typename SrcConstRefP, // const reference to the source pixel typename DstP> // Destination pixel value (models PixelValueConcept) class color_convert_deref_fn { public: typedef color_convert_deref_fn const_t; typedef DstP value_type; typedef value_type reference; // read-only dereferencing typedef const value_type& const_reference; typedef SrcConstRefP argument_type; typedef reference result_type; BOOST_STATIC_CONSTANT(bool, is_mutable=false);
result_type operator()(argument_type srcP) const { result_type dstP; color_convert(srcP,dstP); return dstP; } };
barfoo...
template <typename SrcView, typename DstP> struct color_converted_view_type { private: typedef typename SrcView::const_t::reference src_pix_ref; // const reference to pixel in SrcView typedef color_convert_deref_fn<src_pix_ref, DstP> deref_t; // the dereference adaptor that performs color conversion typedef typename SrcView::template add_deref<deref_t> add_ref_t; public: typedef typename add_ref_t::type type; // the color converted view type static type make(const SrcView& sv) { return add_ref_t::make(sv, deref_t()); } };
barfoo...
template <typename DstP, typename View> inline typename color_converted_view_type<View,DstP>::type color_convert_view(const View& src) { return color_converted_view_type<View,DstP>::make(src); }
barfoo...
struct rgb_planar_pixel_iterator { typedef my_reference_proxy<T> reference; reference operator*() const { return reference(red,green,blue); } };
barfoo...
template <typename Pixel> // Models MutablePixelConcept void invert_pixel(Pixel& p);
rgb_planar_pixel_iterator myIt; invert_pixel(*myIt); // compile error!
barfoo...
template <typename T> struct my_reference_proxy { const my_reference_proxy& operator=(const my_reference_proxy& p) const; const my_reference_proxy* operator->() const { return this; } ... };
barfoo...
struct iterator_traits<rgb_planar_pixel_iterator> { typedef const my_reference_proxy<T> reference; };
barfoo...
namespace std { template <typename T> void swap(my_reference_proxy<T>& x, my_reference_proxy<T>& y) { my_value<T> tmp=x; x=y; y=tmp; } }
barfoo...
|