今天介紹一下修照片時常用的功能,對比度調整。
對比度可以想像成圖片中亮部與暗部的差距,當對比度越高時,畫面中亮暗差距就越明顯,如果用直方圖來想像的話,可以想像成當調整對比度變高時,直方圖的像素應該會往左右兩側擴散,也就是已經黑的越黑,白的越白。而是調低的話,則直方圖應該會往中間集中。
接下來看看演算法的部分吧,主要參考 這裡 的實現,下面是我的一些理解。
首先先看算法的這個部分
newRedColor = Factor * (oldRedColor -128) + 128
其中的 128,可以想像成是暗部與亮部的分界線。對比度調高時,代表亮部越亮,暗部越暗,而在這邊我們以 128 當做這個闕值。直接帶個值進去看看吧
假設今天這個值為 160 ( 也就是會被判定為亮部 ),當對比度增加時 ( 也就是 Factor
> 1 ),最後算出來的值會比原本的還大,也就是亮部越亮,反之亦然。
也有看到其他算法的實現是先算出整張照片的平均亮度,然後以那個亮度當做闕值,當然效能上就會有差距。而以 128 則是直接對半切的方法,但通常來說如果是一張正常曝光的照片,這兩者差距應該不會差距太大。
所以接下來要控制變強跟變弱的幅度,就是靠控制 Factor
這個係數。
Factor = 259( C + 255 ) / 255 ( 259 - C )
在這個算法中,C 代表調整強度,範圍介於 -255 ~ 255。
當等於 0 時, Factor
為 1,套入上面算法部分沒問題,顏色不改變。
當等於 -255 時, Factor
為 0,套入上面算法,所有值都將成為 128,也就是全部都變成灰色。
當等於 255 時, Factor
為 129.5,套入上面算法,當原值為 64 時,結果為 -8160,原值為 196 時, 結果為 8934
透過更改 259 及 255 這兩個值,可以改變增加幅度,這個就看個人需求。如果覺得在調整上顏色太強烈了可以變更。
雖然我們的範圍輸入控制在 -100 ~ 100 中間,目前來說,我不會考慮把上面的參數改成這樣
Factor = 259( C + 100 ) / 100 ( 259 - C )
因為就如剛剛所提,當輸入值為 -100 時,整個畫面都會變成灰階。這對於調整來說應該毫無意義。應該沒有人會想把照片調成一個全灰色的情況吧XD
但倒是覺得調整幅度有點太強烈了,所以稍微修改一下
Factor = 350( C + 255 ) / 255 ( 350 - C )
別問我這個數字怎麼來的XD,基本上就是看 PhotoShop 調整時的改變幅度來憑感覺調的結果,基本上這很主觀,所以這邊自行發揮
一樣傳入 Uint8ClampArray
,並且將透過 amount
來調整對比度 ( 使用的區間是 -100 ~ 100 ),大於 0 就是增加對比, 反之則是降低。實做如下
export const contrast = (pixelData, amount) => {
// const factor = (259 * (amount + 255)) / (255 * (259 - amount))
const contrastThreshold = 128
const factor = (350 * (amount + 255)) / (255 * (350 - amount))
for (let i = 0; i < pixelData.length; i += 4) {
pixelData[i] =
factor * (pixelData[i] - contrastThreshold) + contrastThreshold
pixelData[i + 1] =
factor * (pixelData[i + 1] - contrastThreshold) + contrastThreshold
pixelData[i + 2] =
factor * (pixelData[i + 2] - contrastThreshold) + contrastThreshold
}
return pixelData
}
新增 Slider
<Slider
title="對比度"
:min="-100"
:max="100"
:value="contrast"
@sliderChange="val => sliderChange(val, 'contrast')"
></Slider>
Store
裡面新增參數
state: {
sliderValue: {
brightness: 0,
contrast: 0
}
下面這段應該要找時間改一下了,未來參數只會更多
editImageData({ sliderValue, originalEditData }) {
if (originalEditData.data) {
const imageDataCopy = new ImageData(
new Uint8ClampedArray(originalEditData.data),
originalEditData.width,
originalEditData.height
)
if (sliderValue.brightness !== 0) {
filters.brightness(imageDataCopy.data, sliderValue.brightness)
}
if (sliderValue.contrast !== 0) {
filters.contrast(imageDataCopy.data, sliderValue.contrast)
}
return imageDataCopy
}
}
到這邊可以看一下效果囉!今天換張照片來調調看吧~
順便推薦一下這系列中用來示範的照片都拍攝自 拉達克,是一個美麗純樸的地方,喜好拍照的人一定會愛上。有空就在文章中介紹一下,明天見!
在旅途中,公路外面到處都是這種壯麗大山風景,喜歡拍風景的記得帶顆廣角鏡頭來唷!
今天介紹了對比度調整,在調整的時候對比度調整過後,圖片給人的飽和度也相對應提升了,其實這是正常的,因為飽和度、對比、銳利度其實就是只調整一個還是會互相影響的唷~