DxLibEx
DxLibEx copied to clipboard
色空間をあつかうクラスの作成
#1 より
色空間同士の変換

赤線:劣化しない(高速化のためにbit演算にした時の計算誤差は考慮しない) 青線:劣化する
full:0-255 com:16-235
BT601:ITU-R BT.601のこと BT709:ITU-R BT.709のこと
COLORREF:Win32APIの色を扱う型 *HSVとHSBについて:本来どちらも同じだが、0-100%で表すか0-255で表すかで分けた。
暗黙変換しないもの同士については、color_castをつくる(少なくともADLで見つかるようにし、名前空間を書かなくて良いようにする)。
YUV系の実装のイメージ(仮)
namespace dxle::color {
enum color_range : uint8_t {
full,
compress
};
enum covert_algorithm : uint8_t {
BT601,
BT709
};
template<color_range range, covert_algorithm alg> class yc48;
}
べつにtemplate使わなくてもいいですが、この方が楽だと思いまして
参考サイト
- http://ofo.jp/osakana/cgtips/hsb.phtml
- http://www.marumo.ne.jp/bt601/
- http://www.peko-step.com/tool/hsvrgb.html
- http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
- https://e182bb01e8864f37f9ce365b879822eb6da3f1f1.googledrive.com/host/0B-PAN4aatmy1ZGctNFU0YlFJc2c/doc/aviutlyc.html
- https://onedrive.live.com/view.aspx?cid=6BDD4375AC8933C6&resid=6BDD4375AC8933C6!755
論点
- 上の図は正しいのか?
- 劣化するものはキャスト必須として、劣化しないけどキャストするべきなのはどれだろうか
- ~~キャストは、
static_castにするか独自にcolor_castを作るべきか。(後者のほうがいい気がする)~~ - どれを実装するか(全部はいらないんじゃないか説)
- これを引数に取る関数にスレッドセーフ保障は必要か
とりあえず。
キャストは、
static_castにするか独自にcolor_castを作るべきか。
color_castを作りましょう。
これを引数に取る関数にスレッドセーフ保障は必要か
DrawLine系のスレッドセーフの話をしたのはScreenの方のスレッドセーフに絡むからです。
DrawLine系のスレッドセーフの話をしたのはScreenの方のスレッドセーフに絡むからです。
手間が2倍ですが、必要かなと。
相互変換の実装を考えてみました。 全てのクラスが
- RGBに暗黙に変換できる
- RGBから明示的にコンストラクトできる
を満たすようにすれば、color_castを多様性を保ちつつ
template<typename to, typename from>
to color_cast(from&& bace)
{
return static_cast<to>(std::forward<from>(bace));
}
のように単純に実装できます。 これで問題ないでしょうか?
YUY2もRGBと直接変換可能にするんでしょうか?
あとDxLib型式やCOLORREFへの変換はどうしましょう。
enumつくってcolor_castのtemplate実引数に指定することをイメージしているんですが。
いろいろ不安だったのでTwitterで聞いてみました。
MaverickTse https://twitter.com/MaverickTse/status/676948740662501376 @yumetodo YC48はchannelごと4096段階あるので、RGB24に変換する場合rounding/downsamplingが必要になる 11:15 - 2015年12月16日
yumetodo https://twitter.com/yumetodo/status/676949133815623681 @MaverickTse つまりYC48->RGB(24bit)は劣化の可能性あり、と? 11:17 - 2015年12月16日
MaverickTse https://twitter.com/MaverickTse/status/676949720888143872 @yumetodo 情報が減っているので理論上劣化する。でもソースがHDRではない限り大体目に見えないほうど 11:19 - 2015年12月16日
yumetodo https://twitter.com/yumetodo/status/676950107468791808 @MaverickTse YUY2(16-235)->YC48(com)->YC48(full)->RGB(24bit)とかやるとどうなるんだろうか 11:20 - 2015年12月16日
MaverickTse https://twitter.com/MaverickTse/status/676950808177561600 @yumetodo ソースが0xFF以内ので大丈夫。com->fullのrounding error除くなら 11:23 - 2015年12月16日
とのことだったので、YC48を介さずにRGBへの変換を作るほうがいいのかもしれない。YUY2->RGB
There is no reason to use an intermediate format. Colorspace/format conversion is expensive and should be done in 1-step if possible.
If for some reason you want a common format for data exchange, consider float32.
This is because all CPU and GPU nowadays has native support for float32 (and int32) calculation, while support for short is minimal
YC48 is an odd thing as it is 3x short:
struct PIXEL_YC{
short y; //-2048~+2048
short cb; //0~4096
short cr; //0~4096
}
please refer to filter.h of AviUtl SDK for details. Actually 3x short is not good for memory alignment... I'd not recommend it unless you have some special needs.
可能な限り一度の処理で変換するとなると、やっぱり直接変換のコンストラクタかoperatorを作るしかないですね。そうするとコンストラクタとoperatorのどっちを作るべきなんでしょう?
operator ですかね・・・。
RGBというクラス名がwindowsのdefineと干渉してしまいました...。 小文字rgbというのもなにか違うような気がしますし...。 どうしましょう?
- Put it into a namespace
- Prefix with "dle"(e.g. dleRGB)
COLORREF型を作るのに一般に用いられるRGBマクロと競合することを見越して
#1
では小文字にしていたんですが。
それが嫌ならいっそ全部PIXEL_から全て始まるようにするとか。
yumetodo なるほど。それで#1では小文字だったのか...。
言い出しっぺが言うのもなんですが、先に #9 でクラス名の命名規則を決めたほうが良いと思いました。 他のライブラリと名前が衝突した場合の対処も考えないといけませんね...。
color_castつくるにせよ、共通関数をつくるにせよあったほうが便利だと思うので、色関係クラスは例えばdxle::color_baseを継承するようにしたほうがいい気がしますがどうでしょう?
https://github.com/MaverickTse/MPUtl/issues/12 なんか似たような話が始まりかけてるな・・・
これってどうなっていますか?
とりあえず見ていて思った疑問ですが、
dxle::color::dx_colorクラスって今get関数がありますが、いっそunsigned intへの暗黙の型変換を許してもいいんじゃないか?dx_color_paramクラスはなにをするものでしょうか?- rgbクラスのrgb_value_t型は実質int型ですが、わざわざ構造体を作った理由は?そしてsignedな理由は?
- 0-255のデータをintであつかうのはどうなんでしょうか?
- C#でいうとそれを参考に作っていますか?(URLください)
私がじっくりコーディングできるのは2月中旬に入ってからになりそうですが、とりあえず疑問を書いておかないと2月になっても作業できないので。
color_base
(一か月前のですが...)共通するメンバ関数がないので、空クラスにしかできないと思いますが、どのようなものを想定していますか?
dx_color クラスのunsigned intへの暗黙の型変換
「間違えて座標を引数にすべきところに色を入れてしまった」といったケースをエラーにしたいので、やりたくないです。
dx_color_paramクラス
コメントのサンプルが全てです。 color系クラスを引数にとってDxLibに転送するためのutilityです。なので、dx_colorに変換可能な型から暗黙にコンストラクトできる代わりに、不可逆にしてあります。
0-255のデータをintであつかうのはどうなんでしょうか?
これは整数演算ならintがメモリアラインメント的に一番良いと思ったからです。僕はこのあたりには疎いので、間違っているかもしれませんが...。
signedな理由は?
特に意識してsignedにした訳ではないです。
rgbクラスのrgb_value_t型 C#でいうとそれを参考に作っていますか?
上でメンバ変数の型をintにしてしまったため、publicのままだと不正な値の代入を許すことになってしまいます。そこで、C#の文法のプロパティみたいなことをできないかと思って作ったのがrgb_value_t型です。 C#で参考にしたのはこれだけです。(というわけで、貼れるURLが無いです)
C#のプロパティ ( @Nagarei はC#を触ったことがないので、下のは完全には正しくない可能性があります)
class C
{
private int v_;
//プロパティ
public int v
{
set
{
//valueは引数
Debug.Assert( 0 <= value && value <= 255, "error" );
v_ = value;
}
get
{
return v_;
}
}
}
class Sample
{
static void Main()
{
C c = new C();
c.v = 0;//OK setが呼ばれる
int a = c.v;//OK getが呼ばれる
c.v = -1;//error setが呼ばれ、assertに引っかかる <- これがやりたかった
}
}
color_base
SFINAEにつかう型制約(concept)に必要なメタクラスが作りやすいかなと。is_colorcastableみたいな。
dx_color クラスのunsigned intへの暗黙の型変換
なるほど・・・。
メモリアラインメント的に
だれか詳しそうな人を探したい、深刻に。
C#のプロパティ
C++17に提案されているOpaque Typedefs(N3515, N3741, P0109R0)とかNamed Types(P0027R0)みたいな機能がC#にもあるのか。
現在の実装だとrgbの引数に大きすぎたり、小さすぎたりする値を入れられたときはassertしていますが、 これは丸めたほうが良いのでしょうか? (負数のときは0、256以上のときは255にする)
いや、assertでいいと思います。見えない挙動が増えるのは良くないので。