web-dev-qa-db-ja.com

グレースケールから赤緑青(MATLAB Jet)カラースケール

基本的に画像であるデータセットが与えられましたが、画像の各ピクセルは-1から1までの値として表されます。これらの-1から1のグレースケール値を取得し、MATLAB「Jet」カラースケール(赤-緑-青のカラーグラデーション)の関連RGB値にマップする必要があるアプリケーションを作成しています。

リニア値(-1から1など)を取得し、このスケールにマッピングする方法を誰かが知っている場合、私は興味があります。私は実際にこれにMATLABを使用していないことに注意してください(またはすることもできません)、グレースケール値を取得してJetグラデーションに配置するだけです。

ありがとう、アダム

34
Adam Shook

これがあなたが探しているものであることを願っています:

double interpolate( double val, double y0, double x0, double y1, double x1 ) {
  return (val-x0)*(y1-y0)/(x1-x0) + y0;
}
double blue( double grayscale ) {
  if ( grayscale < -0.33 ) return 1.0;
  else if ( grayscale < 0.33 ) return interpolate( grayscale, 1.0, -0.33, 0.0, 0.33 );
  else return 0.0;
}
double green( double grayscale ) {
  if ( grayscale < -1.0 ) return 0.0; // unexpected grayscale value
  if  ( grayscale < -0.33 ) return interpolate( grayscale, 0.0, -1.0, 1.0, -0.33 );
  else if ( grayscale < 0.33 ) return 1.0;
  else if ( grayscale <= 1.0 ) return interpolate( grayscale, 1.0, 0.33, 0.0, 1.0 );
  else return 1.0; // unexpected grayscale value
}
double red( double grayscale ) {
  if ( grayscale < -0.33 ) return 0.0;
  else if ( grayscale < 0.33 ) return interpolate( grayscale, 0.0, -0.33, 1.0, 0.33 );
  else return 1.0;
}

この縮尺がリンクした画像と100%同じかどうかはわかりませんが、非常によく似ているはずです。

[〜#〜] update [〜#〜]見つかったMatLabのJetパレットの説明に従ってコードを書き換えました ここ

double interpolate( double val, double y0, double x0, double y1, double x1 ) {
    return (val-x0)*(y1-y0)/(x1-x0) + y0;
}

double base( double val ) {
    if ( val <= -0.75 ) return 0;
    else if ( val <= -0.25 ) return interpolate( val, 0.0, -0.75, 1.0, -0.25 );
    else if ( val <= 0.25 ) return 1.0;
    else if ( val <= 0.75 ) return interpolate( val, 1.0, 0.25, 0.0, 0.75 );
    else return 0.0;
}

double red( double gray ) {
    return base( gray - 0.5 );
}
double green( double gray ) {
    return base( gray );
}
double blue( double gray ) {
    return base( gray + 0.5 );
}
22
Ilya Denisov

次の関数( Paul Bourke -Colour Ramping for Data Visualisation):

/*
   Return a RGB colour value given a scalar v in the range [vmin,vmax]
   In this case each colour component ranges from 0 (no contribution) to
   1 (fully saturated), modifications for other ranges is trivial.
   The colour is clipped at the end of the scales if v is outside
   the range [vmin,vmax]
*/

typedef struct {
    double r,g,b;
} COLOUR;

COLOUR GetColour(double v,double vmin,double vmax)
{
   COLOUR c = {1.0,1.0,1.0}; // white
   double dv;

   if (v < vmin)
      v = vmin;
   if (v > vmax)
      v = vmax;
   dv = vmax - vmin;

   if (v < (vmin + 0.25 * dv)) {
      c.r = 0;
      c.g = 4 * (v - vmin) / dv;
   } else if (v < (vmin + 0.5 * dv)) {
      c.r = 0;
      c.b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
   } else if (v < (vmin + 0.75 * dv)) {
      c.r = 4 * (v - vmin - 0.5 * dv) / dv;
      c.b = 0;
   } else {
      c.g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
      c.b = 0;
   }

   return(c);
}

あなたの場合、それを使用して範囲[-1,1]を次のように色付けします(CコードからMATLAB関数に変換するのは簡単です):

c = GetColour(v,-1.0,1.0);

これにより、次の「ホットからコールド」カラーランプが生成されます。

color_ramp

基本的に、RGBカラーキューブの端から端までの青から赤への移動(シアン、緑、黄色を通過)を表し、このパスに沿って値を補間します。

color_cube


これは、MATLABで使用される「Jet」カラーマップとは少し異なります。これは、私が知る限り、次のパスを通過します。

#00007F: dark blue
#0000FF: blue
#007FFF: Azure
#00FFFF: cyan
#7FFF7F: light green
#FFFF00: yellow
#FF7F00: orange
#FF0000: red
#7F0000: dark red

以下は、MATLABで行った比較です。

%# values
num = 64;
v = linspace(-1,1,num);

%# colormaps
clr1 = jet(num);
clr2 = zeros(num,3);
for i=1:num
    clr2(i,:) = GetColour(v(i), v(1), v(end));
end

次に、以下を使用して両方をプロットします。

figure
subplot(4,1,1), imagesc(v), colormap(clr), axis off
subplot(4,1,2:4), h = plot(v,clr); axis tight
set(h, {'Color'},{'r';'g';'b'}, 'LineWidth',3)

jethot_to_cold

これで、上記のCコードを変更し、提案されたストップポイントを使用して、ジェットカラーマップに似たものを実現できます(上記のプロットからわかるように、すべてR、G、Bチャネルで線形補間を使用します)...

72
Amro

他の答えは、補間を区分的線形関数として扱います。これは、補間にクランプされた三角基底関数を使用することにより簡素化できます。入力を閉じた単位間隔にマッピングするクランプ関数が必要です。

clamp(x)=max(0, min(x, 1))

補間の基底関数:

N(t) = clamp(1.5 - |2t|)

その後、色は次のようになります。

r = N(t - 0.5), g = N(t), b = N(t + 0.5)

これを-1から1にプロットすると、次のようになります。

Plot of RGB values from -1 to 1

これは、 この回答 で提供されているものと同じです。 効率的なクランプ実装を使用する

double clamp(double v)
{
  const double t = v < 0 ? 0 : v;
  return t > 1.0 ? 1.0 : t;
}

tが[-1、1]にあることを確認すると、ジェットの色は次のようになります。

double red   = clamp(1.5 - std::abs(2.0 * t - 1.0));
double green = clamp(1.5 - std::abs(2.0 * t));
double blue  = clamp(1.5 - std::abs(2.0 * t + 1.0));

clampの実装に関する上記のリンクに示されているように、コンパイラはブランチを最適化できます。コンパイラは、組み込み関数を使用してstd::absの符号ビットを設定し、別の分岐を削除することもできます。

「ホットツーコールド」

同様の処理は、「ホットツーコールド」カラーマッピングに使用できます。この場合、基底関数と色関数は次のとおりです。

N(t) = clamp(2 - |2t|)

r(t)=N(t-1), g(t) = N(t), b(t) = N(t+1)

[-1、1]のホットツーコールドプロット:

Hot-to-cold plot

OpenGLシェーダープログラム

明示的なブランチを削除すると、このアプローチはOpenGLシェーダープログラムとして実装するのに効率的です。 GLSLは、3Dベクトルで動作するabsclampの両方に組み込み関数を提供します。色の計算をベクトル化し、分岐よりも組み込み関数を優先すると、パフォーマンスが大幅に向上します。以下は、vec3としてRGBジェットカラーを返すGLSLの実装です。基底関数は、tが他の例で使用されている範囲ではなく[0,1]になければならないように変更されていることに注意してください。

vec3 jet(float t)
{
  return clamp(vec3(1.5) - abs(4.0 * vec3(t) + vec3(-3, -2, -1)), vec3(0), vec3(1));
}
8
Joshua Fraser

HSLシステムの色相値があり、彩度と明度が暗黙的であるようです。インターネットでHSLからRGBへの変換を検索すると、多くの説明やコードなどが見つかります(ここに 1つのリンク があります)

ただし、特定のケースでは、すべての色の彩度を1に、明度を0.5にデフォルト設定すると仮定します。 RGB値を取得するために使用できる式は次のとおりです。

すべてのピクセルを想像すると、hはデータから読み取った値です。

hue = (h+1.0)/2;  // This is to make it in range [0, 1]
temp[3] = {hue+1.0/3, hue, hue-1.0/3};
if (temp[0] > 1.0)
    temp[0] -= 1.0;
if (temp[2] < 0.0)
    temp[2] += 1.0;

float RGB[3];
for (int i = 0; i < 3; ++i)
{
    if (temp[i]*6.0 < 1.0)
        RGB[i] = 6.0f*temp[i];
    else if (temp[i]*2.0 < 1.0)
        RGB[i] = 1;
    else if (temp[i]*3.0 < 2.0)
        RGB[i] = ((2.0/3.0)-temp[i])*6.0f;
    else
        RGB[i] = 0;
}

そして、RGBのRGB値はすべて[0、1]の範囲にあります。元の変換はより複雑であることに注意してください。saturation = 1およびlightness = 0.5の値に基づいて単純化しました。

なぜこの式?こちらをご覧ください wikipedia entry

1
Shahbaz