昨天已經介紹到已經將顏色轉成 HSV
的形式,那今天就可以來介紹飽和度調整的部分囉,飽和度也是調整照片中常用的選項,透過飽和度的調整可以讓整個相片帶給人不同的視覺感官,通常來說在自然、風景類的照片中會呈現比較鮮艷的顏色。
來看一下算法的部分吧,因為昨天已經轉換成 HSV
的呈現方式了,今天要做的只是將 S
加上強度,但最後要記得轉換回去 RGB
的呈現方式
export const saturation = (pixelData, amount) => {
for (let i = 0; i < pixelData.length; i += 4) {
const [r, g, b] = [pixelData[i], pixelData[i + 1], pixelData[i + 2]]
const hsv = rgbToHsv(r, g, b)
hsv[1] = clamp(hsv[1] + amount, 0, 100)
const finalRgb = hsvToRgb(hsv)
pixelData[i] = finalRgb[0]
pixelData[i + 1] = finalRgb[1]
pixelData[i + 2] = finalRgb[2]
}
return pixelData
}
因為 S
的最大值為 100,但是我們加上去的值卻有可能會超過,所以實作了一個通用函數,之後應該也會常用到,主要用途就是給定一個值,超過上下限的值就會轉變成最近的界線
export const clamp = (input, min, max) => {
return Math.min(Math.max(input, min), max)
}
其實之前其他的算法就有機會超過 255 的值了,但是因為我們是直接對 RGB
做操作,所以之後在放回去 Unit8ClampArray
的時候會自動幫我們把超出邊界的值歸位,所以如果是用其他語言實作的話請注意這個問題。
因為這次還會需要轉回去 RGB
所以要特別注意一下。
接下來就是 HSV
to RGB
的轉換了,這裡 有轉換數學公式,一樣參考同一個 Repo 實現
export const hsvToRgb = hsv => {
const h = hsv[0] / 60
const s = hsv[1] / 100
let v = hsv[2] / 100
const hi = Math.floor(h) % 6
const f = h - Math.floor(h)
const p = 255 * v * (1 - s)
const q = 255 * v * (1 - s * f)
const t = 255 * v * (1 - s * (1 - f))
v *= 255
switch (hi) {
case 0:
return [v, t, p]
case 1:
return [q, v, p]
case 2:
return [p, v, t]
case 3:
return [p, q, v]
case 4:
return [t, p, v]
case 5:
return [v, p, q]
}
}
一樣在 State
增加值及增加 Slider
元件,流程跟前幾篇一樣,就不特別多說了。
照片拍攝在班公錯湖,也就是三個傻瓜裡面結尾最後的地方,很美!
來看看這次的效果吧,拖到最底的時候發現天空的顏色好像不太對( 原本白色的部分轉藍了,注意圖片左上角 ),明天來看一下要怎麼調整吧