代码之家  ›  专栏  ›  技术社区  ›  Hassan

执行alpha混合的正确方法是什么((三)

  •  3
  • Hassan  · 技术社区  · 16 年前

    我在写一封信 非常 简单的图形库,我想弄清楚如何进行alpha混合。我试了几次,但结果不太令人满意。根据维基百科,我应该:

    值=(1-α) 值0+alpha

    然而,这根本不起作用。也许我做错了什么?

    #include "hgl.h"
    
    void proximity()
    {
        int x = 0, y = 0, d1, d2, d3, dcenter;
    
        while(x < WIDTH){
            while(y < HEIGHT){
                d1 = distance(x, y, (WIDTH/2) - 200, (HEIGHT/2) + 200);
                d2 = distance(x, y, (WIDTH/2) + 200, (HEIGHT/2) + 200);
                d3 = distance(x, y, (WIDTH/2), (HEIGHT/2) - 150);
                dcenter = distance(x, y, WIDTH/2, HEIGHT/2);
                putpixel(x, y, d1, d2, d3);
                y++;
            }
            y = 0;
            x++;
        }
    }
    
    int alpha_transparency(float alpha, float value1, float value2)
    {
        return (1-alpha) * value1 + alpha * value2;
    }
    
    void transparent_box(int pos_x, int pos_y, int width, int height, float alpha, char r, char g, char b)
    {
        int x = 0, y = 0;
        while(x < width)
        {
            while(y < height)
            {
                int rr, rg, rb;
                rr = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].r, r);
                rg = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].g, g);
                rb = alpha_transparency(alpha, p.bitmap[x+pos_x][y+pos_y].b, b);
                putpixel(pos_x + x, pos_y + y, rr, rg, rb);
                y++;
            }
            x++;
            y = 0;
        }
    }
    
    int main()
    {
        fp = fopen("out.bmp","wb");
    
        set_dimensions(1440, 900);
        insert_header();
    
        white_screen();
    
        proximity();
        transparent_box(100, 100, 500, 500, .9, 255, 255, 255);
    
        insert_image();
        fclose(fp);
        return 0;
    }
    

    Original Picture

    Picture with "transparent" box

    3 回复  |  直到 16 年前
        1
  •  2
  •   MSN    16 年前

    你的alpha混合函数是正确的;考虑alpha混合的另一种方法是它基于alpha在两个颜色值之间插值,因此它应该是[0,1]中的一个值。

    char ,默认情况下已签名。你应该把它们作为 unsigned char 255 -1 .

    换句话说,将颜色组件存储为 无符号字符 以确保你没有恶作剧(见EDIT2)。

    EDIT2:另外,如果你将像素存储为 而不是 无符号字符 ,这可以解释我看到的奇怪的夹持:

    alpha_transparency(0.9, (char)255, (char)255)
    == alpha_transparency(0.9f, -1.0f, -1.0f)
    == -1.0f
    == 0xff (cast to char)
    
    alpha_transparency(0.9, (char)128, (char)255)
    == alpha_transparency(0.9f, -128.0f, -1.0f)
    == -13.7f
    == 0xf3
    
    alpha_transparency(0.9, (char)127, (char)255)
    == alpha_transparency(0.9f, 127.0f, -1.0f)
    == -11.80f
    == 0x0b
    
    alpha_transparency(0.9, (char)0, (char)255)
    == alpha_transparency(0.9f, 0.0f, -1.0f)
    == -0.9f
    == 0x00
    
        2
  •  0
  •   Timothy Baldridge    16 年前

    所以正确的代码是:

    return (255-alpha)*value1+alpha*value2;
    

    你也可能会在你认为不可能的地方遭受到麻烦。我会将函数中的代码更改为:

    float result = (255.0f-alpha)*value1+alpha*value2;
    return (int) result;
    

    一般来说,使用浮点而不是int来处理图像是非常常见的。现在许多程序将整个图像转换为浮点数,处理后再转换回来。这样可以避免几个错误。

        3
  •  0
  •   comingstorm    16 年前

    对于所有整数,您需要记住重新调整整数的比例,以便将结果拟合回原始范围:

    int alpha_transparency(int alpha, int value1, int value2) {
      int unscaled= (255-alpha)*value1 + alpha*value2;
      return unscaled / 255;  /* integer division */
    }
    

    对于所有浮点,您需要记住将整数输入从[0..255]中的原始值规范化为[0.0。。1.0],执行所有处理,然后仅在最后转换回整数。

    float input_raw_value(unsigned char value)  { return value/255.0; }
    ...
    float alpha_transparency(float alpha, float value1, float value2) {
      return (1.0-alpha)*value1 + alpha*value2;
    }
    ...
    unsigned char output_raw_value(float value) { return value*255.0; }
    

    注意,我忽略了每个方法中的舍入问题;一旦你掌握了基本的数学知识,你就应该注意这一点。此外,还有各种技巧可以通过乘法或位摆弄来代替除法(可能相对较慢)。

    推荐文章