透明像素颜色 - Go语言图像处理

4

我正在尝试从眼动仪结果中创建热力图(显示用户最常看的屏幕区域)。

对于用户经常关注的像素,我想设置不透明的红色,对于稍微不那么频繁的橙色等颜色。我使用红到绿的渐变色来表示。但是对于最少被关注的像素,我不仅希望它们显示绿色,还希望它们是透明的。

imgfile, err := os.Open("unchanged.jpeg")
defer imgfile.Close()
if err != nil {
    fmt.Println(err.Error())
}

decodedImg, err := jpeg.Decode(imgfile)
img := image.NewRGBA(decodedImg.Bounds())

size := img.Bounds().Size()
for x := 0; x < size.X; x++ {
    for y := 0; y < size.Y; y++ {
        img.Set(x, y, decodedImg.At(x, y))
    }
}

// I change some pixels here with img.Set(...)

outFile, _ := os.Create("changed.png")
defer outFile.Close()
png.Encode(outFile, img)

问题是当我尝试改变颜色时,例如使用img.Set(x,y,color.RGBA {85,165,34,50}),它实际上并没有根据旧颜色和新颜色的平均值着色像素,而只显示一些新的、看起来奇怪的颜色。

alpha RGBA 值设置为 50 的图像:(透明)

enter image description here

alpha RGBA 值设置为 255 的图像:(不透明)

enter image description here

我使用 png 图像,据我所知,它支持透明度。

这是为什么?有什么方法可以解决这个问题,并使最不常见的像素显现为透明吗?

感谢每一个答案。

1个回答

4
这是因为Set()方法会设置(覆盖)指定位置像素的颜色。这不是你想要的。
你想要将像素的原始颜色与你选择的颜色结合起来,并且你希望这是最终的颜色。
为了实现这一点,首先你需要用Image.At()查询原始颜色,然后将颜色与任何你想要的颜色结合起来(你可以通过红、绿、蓝和透明度通道分别进行操作),并使用Set()方法设置最终颜色。
组合:
请注意,color.RGBA结构体的RGBA字段是预乘以Alpha通道值的值,这意味着例如R字段保存的是颜色的红色成分乘以Alpha通道的值。
你可以使用RGBA.RGBA()方法,它返回所有字段作为uint32值,并且所有值都在0..0xffff范围内,所以你可以对它们进行操作而不必担心溢出(uint8的最大值是255,因此即使添加两个uint8值也很容易溢出)。
因此,当你组合两种颜色时,你可以按分量进行组合。但请注意,color.RGBA中这些字段的类型是uint8,因此在组合后,你必须将结果转换为适合8位的值,因此你必须向右移动8位。
一个非常简单的组合方法:计算平均值:
// Query:
x, y := 1, 1
r, g, b, a := img.At(x, y).RGBA()

// Combine:
col := color.RGBA{85, 165, 34, 50}
r2, g2, b2, a2 := col.RGBA()

col.R = uint8((r + r2) >> 9) // div by 2 followed by ">> 8"  is ">> 9"
col.G = uint8((g + g2) >> 9)
col.B = uint8((b + b2) >> 9)
col.A = uint8((a + a2) >> 9)

// Set new pixel:
img.Set(x, y, col)

您可以将此内容融入到一个辅助函数中:
func combine(c1, c2 color.Color) color.Color {
    r, g, b, a := c1.RGBA()
    r2, g2, b2, a2 := c2.RGBA()

    return color.RGBA{
        uint8((r + r2) >> 9), // div by 2 followed by ">> 8"  is ">> 9"
        uint8((g + g2) >> 9),
        uint8((b + b2) >> 9),
        uint8((a + a2) >> 9),
    }
}

并使用它:

x, y := 1, 1
img.Set(x, y, combine(img.At(x, y), color.RGBA{85, 165, 34, 50}))

如果您需要逼真的颜色合成,请查看Alpha compositing页面。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接