我试图写色彩平衡,但是数学上有些困难。我在Wikipedia
上找到了这个公式我要做的是以下事情:
(255 / col.red) * avgRed
(255 / col.green) * avgGreen
(255 / col.blue) * avgBlue
它看起来像这样:
function averageColor() {
let sumRed = 0, sumGreen = 0, sumBlue = 0
let pixels = 0
// Get the sum of each color
this.eachColor((col, idx) => {
sumRed += col.red
sumBlue += col.blue
sumGreen += col.green
pixels++
})
// Get the averages of each channel
let avgRed = sumRed / pixels
let avgGreen = sumGreen / pixels
let avgBlue = sumBlue / pixels
// Replace each color in the image
this.eachColor((col, idx) => {
this.setColorAtIndex(idx, color.rgb(
(255 / col.red) * avgRed,
(255 / col.green) * avgGreen,
(255 / col.blue) * avgBlue
))
})
}
以下是上面看到的两个函数(this._dta
是Uint8ClampedArray
的{{1}}):
ImageData.data
当我应用滤镜时,这就是前后的样子,因为您会看到白色太多了。我的公式有什么问题?
答案 0 :(得分:3)
您不想乘以平均值。您希望缩放平均值,因此最大值为255。这实际上是在假装平均值应为灰色,然后进行缩放。因此,如果您的平均值是Short
,那么白色可能是:
[133.54055621951161, 133.85785501369506, 95.50769969447687]
一旦有了您就可以使用它按公式进行缩放(在实践中,您应该使用伽玛校正此转换(srgb伽玛约为2.2,反之约为.45:
let avg = [133.54055621951161, 133.85785501369506, 95.50769969447687]
let max = Math.max(...avg)
let white = avg.map(c => 255 * c / max)
console.log(white)
您可以看到,所有这些操作都是按照 data[i] = (255/white[0]) ** .45 * data[i] ; // red
data[i + 1] = (255/white[1]) ** .45 * data[i+1]; // green
data[i + 2] = (255/white[2]) ** .45 * data[i+2] // blue
的比例缩放所有内容,这取决于平均值是接近灰色的。在这种情况下,它可以很好地消除黄变。
转换后,这是我的样子:
之前
之后