12

アプリケーションの起動時に画面ガンマを調整し、終了時にリセットする機能を追加したいと思います。ガンマを改ざんするべきかどうかは議論の余地がありますが(個人的には役に立たず、有害だと思います)、そういうことができると期待している人もいます。

これも1つの単純なAPI呼び出しなので、すべて簡単ですよね?

MSDNによると、「ガンマランプは256 WORD要素の3つの配列で指定され、DACの独立性を高めるには、各[...]値を各WORDの最上位ビットに格納する必要があります。」。これは、私の理解では、のようなものを意味します。word_value = byte_value<<8これはかなり奇妙に聞こえますが、それは私がそれを読む方法です。

Doom3ソースコードには、値の3つの配列を受け取り、それらを上半分と下半分の両方で同じバイト値を持つ値charの配列に変換する関数が含まれています。言い換えれば、のようなものです。これも同様に奇妙ですが、さらに悪いことに、上記と同じではありませんuint16_tword_value = (byte_value<<8)|byte_value

また、インターネット上のさまざまな趣味のプログラマーサイトにいくつかのコードスニペットがあり(文字と同じであるため、明らかに一方が他方から盗まれています)、線形インデックスに値を掛け、128でバイアスをかけ、いくつかのあいまいな計算を行います。これが何であるかはよくわかりませんが、私にはまったく意味がないように見えます。また、上記の2つと同じではありません。

何が得られますか?推測することなく、明確に定義されている必要があります。提供するデータはどのように見える必要がありますか?最後に、元の値を読み取り、ユーザーがスライダーを微調整できるようにします(オプションで、ユーザーの構成を使用してそのBLOBをディスクに保存します)が、それでも...これらの値を変更するには、次のことを行う必要があります。彼らが何であるか、そして何が期待されているかを知っています。

誰かがこれを以前に行って(そしてテストして!)、どれが正しいか知っていますか?

4

2 に答える 2

11

プログラムで画面の明るさを変更する機能を調査しているときに、この記事に出くわしました。プログラムで画面の明るさを変更する-GamaRampAPIを使用します

デバッガーを使用して、GetDeviceGamaRamp()関数によって提供される値を確認しました。出力は、のようなものとして定義された2次元配列WORD GammaArray[3][256];であり、表示されたピクセルの赤、緑、および青の値を変更するための256個の値のテーブルです。私が見た値は、インデックス0でゼロ(0)の値から始まり、次の値を計算するために256の値を追加しました。したがって、インデックス0、1、2、...、254、255の場合、シーケンスは0、256、512、...、65024、65280になります。

私の理解では、これらの値は各ピクセルのRGB値を変更するために使用されます。テーブルの値を変更することにより、ディスプレイの明るさを変更できます。ただし、この手法の効果は、ディスプレイのハードウェアによって異なる場合があります。

Direct3Dの観点からではありますが、ガンマランプレベルについて説明しているこの短い記事、ガンマコントロールが興味深いと思われるかもしれません。この記事には、ガンマランプレベルについての説明があります。

Direct3Dでは、ガンマランプという用語は、フレームバッファ内のすべてのピクセルの特定の色成分(赤、緑、青)のレベルを、DACが表示用に受信する新しいレベルにマッピングする一連の値を表します。再マッピングは、カラーコンポーネントごとに1つずつ、3つのルックアップテーブルを使用して実行されます。

仕組みは次のとおりです。Direct3Dはフレームバッファからピクセルを取得し、個々の赤、緑、青の色成分を評価します。各コンポーネントは、0〜65535の値で表されます。Direct3Dは元の値を取得し、それを使用して256要素の配列(ランプ)にインデックスを付けます。各要素には、元の値を置き換える値が含まれます。Direct3Dは、フレームバッファー内の各ピクセルの各カラーコンポーネントに対してこのルックアップおよび置換プロセスを実行し、それによって画面上のすべてのピクセルの最終的なカラーを変更します。

のオンラインドキュメントによるとGetDeviceGamaRamp()SetDeviceGamaRamp()これらの関数はWindows2000Professional以降のWindowsAPIでサポートされています。

Windowsアプリケーションに挿入された次の例に要約されたソースを使用して、参照記事の値を使用して効果をテストしました。私のテストは、Windows7とAMDRadeonHD7450グラフィックスアダプターを使用して行われました。

このテストでは、2つのディスプレイがあり、両方のディスプレイが影響を受けました。

//Generate the 256-colors array for the specified wBrightness value.
WORD  GammaArray[3][256];
HDC   hGammaDC = ::GetDC(NULL);
WORD  wBrightness;

::GetDeviceGammaRamp (hGammaDC, GammaArray);

wBrightness = 64;     // reduce the brightness
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

wBrightness = 128;    // set the brightness back to normal
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

::ReleaseDC(NULL, hGammaDC);

追記として、上記のソースにわずかな変更を加えて、各RGB値を均等に変更するのではなく、最初の2つの割り当てをコメントアウトしてGammaArray[2][ik]変更のみにしました。その結果、ディスプレイに黄色がかったキャストが表示されました。

また、上記のソースをループに入れて、表示がどのように変化したかを確認してみましたが、とはかなり違いましwBrightness=0wBrightness=128

for (wBrightness = 0; wBrightness <= 128; wBrightness += 16) {
    for (int ik = 0; ik < 256; ik++) {
        int iArrayValue = ik * (wBrightness + 128);
        if (iArrayValue > 0xffff) iArrayValue = 0xffff;
        GammaArray[0][ik] = (WORD)iArrayValue;
        GammaArray[1][ik] = (WORD)iArrayValue;
        GammaArray[2][ik] = (WORD)iArrayValue;
    }

    ::SetDeviceGammaRamp (hGammaDC, GammaArray);
    Sleep (3000);
}

Microsoftは、ガンマ補正の使用に関するオンラインのMSDN記事を提供しています。これは、ガンマの基本を次のように説明しているDirect3Dドキュメントの一部です。

グラフィックスパイプラインの最後、つまり画像がコンピューターを離れてモニターケーブルに沿って移動する場所に、ピクセル値をその場で変換できる小さなハードウェアがあります。このハードウェアは通常、ルックアップテーブルを使用してピクセルを変換します。このハードウェアは、表示される表面からの赤、緑、青の値を使用して、テーブル内のガンマ補正値を検索し、実際の表面値の代わりに補正値をモニターに送信します。したがって、このルックアップテーブルは、任意の色を他の色に置き換える機会です。テーブルにはそのレベルのパワーがありますが、一般的な使用法は、モニターの応答の違いを補正するために画像を微調整することです。モニターの応答は、赤の数値を関連付ける関数です。

さらに、ソフトウェアアプリケーションRedshiftには、 MicrosoftWindowsについて言うことができるページWindowsガンマ調整があります。

RedshiftをWindowsに移植するときに、色温度を約4500Kより低く設定すると問題が発生しました。問題は、Windowsが、実行できるガンマ調整の種類に制限を設定していることです。おそらく、色を反転したり、ディスプレイを空白にしたり、ガンマランプで他の厄介なトリックを実行したりする邪悪なプログラムからユーザーを保護する手段としてです。この種の制限はおそらく理解できますが、問題はこの機能のドキュメントが完全に不足していることです(MSDNのSetDeviceGammaRamp)。許可されていないガンマランプを設定しようとするプログラムは、一般的なエラーで失敗し、プログラマーは何が悪かったのか疑問に思います。

于 2015-10-21T20:33:31.500 に答える
2

私はこれをテストしていませんが、推測しなければならない場合、Doomが作成され、時にはLOBYTEを使用し、時にはWORD値のHIBYTEを使用したとき、初期のグラフィックカードはSetDeviceGammaRamp()の実装で非標準でした。コンセンサスはHIBYTEのみを使用するようになり、したがってword_value = byte_value<<8

LOBYTEとHIBYTEを交換しているPsychoPyライブラリ(Python)からの別のデータポイントは次のとおりです。

 """Sets the hardware look-up table, using platform-specific ctypes functions. 
 For use with pyglet windows only (pygame has its own routines for this). 
 Ramp should be provided as 3x256 or 3x1024 array in range 0:1.0 
 """ 
if sys.platform=='win32':   
    newRamp= (255*newRamp).astype(numpy.uint16) 
    newRamp.byteswap(True)#necessary, according to pyglet post from Martin Spacek 
    success = windll.gdi32.SetDeviceGammaRamp(pygletWindow._dc, newRamp.ctypes) 
    if not success: raise AssertionError, 'SetDeviceGammaRamp failed' 

また、Windowsではすべてのガンマ設定が許可されていないようです。http: //jonls.dk/2010/09/windows-gamma-adjustments/を参照してください。

アップデート:

ガンマ制御を提供する最初のWindowsAPIは、Windows Graphics Device Interface(GDI)のSetDeviceGammaRampとGetDeviceGammaRampです。これらのAPIは、WORDの3つの256エントリ配列で動作します。各WORDは、0から1までをエンコードし、WORD値0および65535で表されます。WORDの追加の精度は、通常、実際のハードウェアルックアップテーブルでは利用できませんが、これらのAPIは柔軟にすることを目的としています。これらのAPIは、このセクションで後述する他のAPIとは対照的に、恒等関数からのわずかな逸脱のみを許可します。実際、ランプのエントリは、ID値の32768以内にある必要があります。この制限は、アプリがディスプレイを完全に黒または他の読み取り不可能な色に変えることができないことを意味します。

http://msdn.microsoft.com/en-us/library/windows/desktop/jj635732(v=vs.85).aspx

于 2014-01-22T22:31:52.897 に答える