opengl-es 2.0 を使用して、GPU 上の画像の勾配ベクトル フィールドを計算しようとしています。GPU実装との比較として使用するCPU実装を見つけました。ここでの課題は、CPU 実装が Java 型 float (32 ビット) に依存しているのに対し、私の gpu 実装は lowp float (8 ビット) を使用していることです。より良い結果を得るために mediump または highp を使用できることはわかっていますが、コードが可能な限り最も貧弱なハードウェアで実行できることを確認するために、引き続き lowp float を使用したいと考えています。
勾配ベクトル場を計算するための最初のいくつかの手順は非常に簡単です。
- 正規化されたグレースケール (赤 + 緑 + 青)/3.0 を計算します。
- エッジ マップ (右ピクセル - 左ピクセル)/2.0 および (上ピクセル - 下ピクセル)/2.0 を計算します。
- ラプラシアンを計算します (もう少し複雑ですが、ここで詳細を説明する必要はありません)
現在、派手なことをしなくても、CPU実装からの画像結果がGPUからの画像結果と同じになるように、ステップ1を正確に模倣することができます。
残念ながら、私のエッジ マップの計算は GPU で十分に正確ではないため、既にステップ 2 に行き詰まっています。
そこで、 http://andrewthall.org/papers/df64_qf128.pdfから着想を得て、拡張精度浮動小数点を実装しようとしました。
私はopengl-esにかなり慣れていないので、ここで正しく行ったかどうかさえわかりませんが、現在苦しんでいるこの精度の低下を解決するためにコーディングするつもりだった操作を以下に示します.
vec2 split(float a)
{
float t = a * (2e-8+1.0);
float aHi = t - (t -a);
float aLo = a - aHi;
return vec2(aHi,aLo);
}
vec2 twoProd(float a, float b)
{
float p = a * b;
vec2 aS = split(a);
vec2 bS = split(b);
float err = ( ( (aS.x * bS.x) - p) + (aS.x * bS.y) + (aS.y * bS.x) ) + (aS.y * bS.y);
return vec2(p,err);
}
vec2 FMAtwoProd(float a,float b)
{
float x = a * b;
float y = a * b - x;
return vec2(x,y);
}
vec2 div(vec2 a, vec2 b)
{
float q = a.x / b.x;
vec2 res = twoProd( q , b.x );
float r = ( a.x - res.x ) - res.y ;
return vec2(q,r);
}
vec2 div(vec2 a, float b)
{
return div(a,split(b));
}
vec2 quickTwoSum(float a,float b)
{
float s = a + b;
float e = b - (s-a);
return vec2(s,e);
}
vec2 twoSum(float a,float b)
{
float s = a + b;
float v = s - a;
float e = ( a - (s - v)) + ( b - v );
return vec2(s,e);
}
vec2 add(vec2 a, vec2 b)
{
vec2 s = twoSum(a.x , b.x);
vec2 t = twoSum(a.y , b.y);
s.y += t.x;
s = quickTwoSum(s.x,s.y);
s.y += t.y;
s = quickTwoSum(s.x,s.y);
return s;
}
vec2 add(vec2 a,float b)
{
return add(a,split(b));
}
vec2 mult2(vec2 a,vec2 b)
{
vec2 p = twoProd(a.x,b.x);
p.y += a.x * b.y;
p.y += a.y * b.x;
p = quickTwoSum(p.x,p.y);
return p;
}
vec2 mult(vec2 a,float b)
{
return mult2(a, split(b));
}
明らかに、単純な操作を使用しているか、拡張浮動小数点操作を使用しているかに関係なく、同じ結果が得られるため、ここで何か間違っているか、いくつかの非常に基本的な概念を見逃している必要があります...