灰度至红绿蓝(MATLAB Jet)色标

Ada*_*ook 34 c++ matlab colors

给我一个基本上是图像的数据集,但是图像中的每个像素都表示为从-1到1的值.我正在编写一个需要采用这些-1到1灰度值的应用程序,并将它们映射到MATLAB"Jet"色标(红 - 绿 - 蓝色渐变)的相关RGB值.

我很好奇,如果有人知道如何取一个线性值(如-1到1)并将其映射到此比例.请注意,我实际上并没有使用MATLAB(我也不能),我只需要获取灰度值并将其放在Jet渐变上.

谢谢,亚当

Amr*_*mro 73

考虑以下函数(由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);
}
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您可以使用它将范围中的值映射[-1,1]到颜色(将C语言转换为MATLAB函数很简单):

c = GetColour(v,-1.0,1.0);
Run Code Online (Sandbox Code Playgroud)

这会产生以下"热到冷"颜色斜坡:

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
Run Code Online (Sandbox Code Playgroud)

这是我在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
Run Code Online (Sandbox Code Playgroud)

然后我们使用以下两种情

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)
Run Code Online (Sandbox Code Playgroud)

喷射 hot_to_cold

现在你可以修改上面的C代码,并使用建议的停止点来实现类似于jet colormap的东西(它们都在R,G,B通道上使用线性插值,如上图所示)...


Ily*_*sov 22

我希望这是你正在寻找的:

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;
}
Run Code Online (Sandbox Code Playgroud)

我不确定这个刻度是否与您链接的图像100%相同但它应该看起来非常相似.

UPDATE 我根据Matlab的喷气调色板的发现说明重写代码在这里

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 );
}
Run Code Online (Sandbox Code Playgroud)

  • 我找到了一些关于MatLab的Jet调色板的信息:https://bugs.launchpad.net/inkscape/+bug/236508 (2认同)

小智 9

其他答案将插值视为分段线性函数.通过使用夹紧三角形基函数进行插值可以简化这一过程.我们需要一个钳制功能,将其输入映射到闭合单位间隔:

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

插值的基函数:

N(t)=钳位(1.5  -  | 2t |)

然后颜色变成:

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

将其从-1绘制为1给出:

RGB值的绘图从-1到1

这与本答案中提供的相同.使用有效的钳位实现:

double clamp(double v)
{
  const double t = v < 0 ? 0 : v;
  return t > 1.0 ? 1.0 : t;
}
Run Code Online (Sandbox Code Playgroud)

确保你的价值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));
Run Code Online (Sandbox Code Playgroud)

如上面的实现链接所示clamp,编译器可以优化分支.编译器还可以使用内在函数来设置符号位以std::abs消除另一个分支.

"热到冷"

类似的处理可用于"热 - 冷"颜色映射.在这种情况下,基础和颜色功能是:

N(t)=钳位(2  -  | 2t |)

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

[-1,1]的热到冷图:

从热到冷的情节

OpenGL着色器程序

消除显式分支使得该方法有效地实现为OpenGL着色器程序.GLSL两者提供了内置的功能absclamp三维矢量该操作.矢量化颜色计算并优先选择内置函数而不是分支可以显着提高性能.下面是GLSL中的一个实现,它将RGB喷射颜色作为a返回vec3.注意,修改基函数使得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));
}
Run Code Online (Sandbox Code Playgroud)