【问题标题】:Distribute 32bit float over 4 integers (RGBA) in java在java中分配32位浮点数超过4个整数(RGBA)
【发布时间】:2015-08-21 18:00:47
【问题描述】:

1. 考虑一个 32 位 java 浮点数 sample in (0.0f .. 1.0f) 和四个 32 位 java 整数 r, g, b, a 每个都在 (0 .. 255) 一个名为 @ 的向量中987654324@.

2.sample 变量包含我希望以热图的形式在ImageIcon 中呈现的标准化测量数据。最终 RGBA 值的目标是一个整数向量,稍后将作为像素数据传递给 java BufferdImage

3. 约束条件是当sample==0.0fRGBA==[0,0,0,255] 具有均匀分布,因此sample==1.0f 代表RGBA==[255,0,0,255],而sample==0.5f 则由RGBA==[255,255,255,255] 代表。 Alpha 通道始终为 255。

4. 到目前为止,我使用了一种静态方法,将颜色分成三个单独的部分 R G B 而 A 在 255 处保持静态。就像这样

/* BLUE */
if ( sample <= 0.340000f ){
    localSample = (sample/(0.340000f/255.000000f));
    sourceLinearData[localIndex] = 0; // R
    sourceLinearData[localIndex+1] = 0; // G
    sourceLinearData[localIndex+2] = Math.round(localSample); // B
}

5. 我的问题:A) 是否有任何合适的 java api/库可以帮助我做到这一点? B)如果不是,那么我会寻求解决方案的建议。

6. 想法:由于每个 R、G、B、A 都在 (0 .. 255) 中,我假设我可以使用字节而不是整数,然后可能将这些字节转换为一个变量,然后以这种方式提取浮点数。虽然到目前为止我还没有用这种方法取得任何成功。

7. 编辑:添加示例热图

已解决:因此,就像软件开发中的许多其他事情一样,这个问题也有不止一个答案。就我而言,我想要一条最直接的路线,而且额外的工作量最少。因此,我决定接受@haraldK 给出的答案。这就是说,如果您正在寻找一种具有更多控制力、精确度和灵活性的正式解决方案,@SashaSalauyou 提供的答案是更正确的答案。

【问题讨论】:

  • 请注意,java 使用有符号字节,因此您必须将它们转换回带 byte & 0xFF 的有符号整数。
  • 你可以做 r = sample * 255;这会产生蓝到红的渐变,但在 0.5 时它不会是白色的。
  • 如果我理解得很好,1.0 是红色,0.5 是白色,0.0 是黑色。如果是这样,很难想象线性颜色渐变会是什么样子。热图实际使用了哪些颜色?
  • @Emd4600:是的,我想我明白你的意思。虽然在这种情况下,我希望找到 0.5f 的白色渐变。
  • @SirDarius:你是对的。热图将显示沉积在介质中特定位置的能量分布。我将尝试在上面添加示例图像。

标签: java image image-processing


【解决方案1】:

详细说明我上面的评论。这并没有给出完全上面地图中的颜色,但它非常接近,并且非常简单:

float sample = ...; // [0...1]
float hue = (1 - sample) * .75f; // limit hue to [0...0.75] to avoid color "loop"
int rgb = Color.getHSBColor(hue, 1, 1).getRGB(); 

如果您想在刻度的“边缘”中使用较暗的色调,您可以使用正弦函数来计算亮度,例如:

float hue = (1 - sample) * .75f;
float brightness = .5f + (float) Math.sin(Math.PI * sample) / 2;
int rgb = Color.getHSBColor(hue, 1, brightness).getRGB();

【讨论】:

  • 它不会产生深红色和深蓝色,但如果不是绝对必要,这种方法更好。
  • 是的,HSV 空间“循环”。修复了从红色到蓝色/紫色的范围。但是您是对的,颜色仍然与图像中的不完全一样(我确实在答案中说明了这一点)。
  • @haraldK:您能否详细说明在我必须分别指定 r g 和 b 的每个值的情况下如何使用示例中的 rgb 值?
  • @Peter 您的意思是,您想将 RGB 值拆分为 {R, G, B} 的数组?你可以做类似int[] rgbs = new int[] {(rgb &gt;&gt; 16) &amp; 0xff, (rgb &gt;&gt; 8) &amp; 0xff, rgb &amp; 0xff} 的事情。但是在 Java 中处理图像(即BufferedImages)时,packed int RGB 格式通常更有用。
  • @haraldK:看来这是最直接的方法了。但是颜色的顺序是不正确的。我为阈值添加了一个特殊情况,例如低于 0.0nnn,以避免大部分为红色的图像。是否有可能以某种方式反转数据?
【解决方案2】:

我建议在从 0 到 1 的值在 3D 色彩空间中执行的路径中进行某种插值:

// black: c = 0.0
// blue:  c = 0.3 
// white: c = 0.5
// red:   c = 1.0
// add more color mappings if needed, keeping c[] sorted

static float[] c = {0.0, 0.3, 0.5, 1.0};
static int[] r =   {  0,   0, 255, 255}; // red components
static int[] g =   {  0,   0, 255,   0}; // green components
static int[] b =   {  0, 255, 255,   0}; // blue components

public int[] getColor(float f) {
    int i = 0;
    while (c[i] < f) 
       i++;
    if (i == 0) 
       return new int[] {r[0], g[0], b[0]};

    // interpolate
    float k = (f - c[i-1]) / (c[i] - c[i-1]);
    return new int[] {
         Math.round((r[i] - r[i-1]) * k + r[i-1]),
         Math.round((g[i] - g[i-1]) * k + g[i-1]),
         Math.round((b[i] - b[i-1]) * k + b[i-1])
         }
    }

}

【讨论】:

  • 您错过了数组声明中的分号。除此之外,它工作正常。
  • @Sasha:你能看到我上面贴的示例图片吗(matlab 生成相同的东西)?我确信您提供的解决方案是准确的,但我没有得到预期的结果。我假设我没有正确地向 c[] 添加其他颜色。我会继续调查。
  • @Peter 我为您在问题中提供的颜色和值提供了映射数组(crgb)。您可以根据需要更改它们以获得所需的结果。
  • @SashaSalauyou:注意。我会不断更新这篇文章。
  • 我在图片中看到,值 0.5 应该产生绿色 (0, 255, 0),但你首先说它必须是白色 (255, 255, 255) 等等。
【解决方案3】:

Lerp 应该可以解决问题:

public static void main(String[] args) {
    float value = 0.5f;

    float[] red = new float[] {1.0f, 0, 0};
    float[] white = new float[] {1.0f, 1.0f, 1.0f};
    float[] black = new float[] {0, 0, 0};

    if (value <= 0.5f) {
        float gradientValue = value * 2;
        int[] color = new int[] {(int) (lerp(white[0], black[0], gradientValue) * 255), (int) (lerp(white[1], black[1], gradientValue) * 255), 
                (int) (lerp(white[2], black[2], gradientValue) * 255), 255};
    } else if (value > 0.5f) {
        float gradientValue = (value + 1) / 2.0f;
        int[] color = new int[] {(int) (lerp(white[0], red[0], gradientValue) * 255), (int) (lerp(white[1], red[1], gradientValue) * 255), 
                (int) (lerp(white[2], red[2], gradientValue) * 255), 255};
    }
}

public static float lerp(float v0, float v1, float t) {
      return (1-t)*v0 + t*v1;
}

(lerp参数的顺序可能不同,我没有测试过)

【讨论】:

  • lerp 是线性插值吧?
  • 是的,但我习惯称它为 lerp。
猜你喜欢
  • 1970-01-01
  • 2011-10-25
  • 2015-03-21
  • 1970-01-01
  • 2020-04-27
  • 2015-12-19
  • 2011-04-28
  • 2020-09-04
  • 2011-12-14
相关资源
最近更新 更多