不知道大家有沒有遇過這種情況。
有時候拍完一張照片,總覺得哪裡怪怪的。
可能整張照片偏暗,也可能亮到天空一片白。

甚至有些照片明明沒有曝光失敗,但就是看起來灰灰的、沒有層次。
其實遇到這個狀況,真正重要的不是「把圖片變亮」,而是先了解這張圖片的亮度到底是怎麼分布的?
而回答這個問題的工具,就是今天要介紹的 Histogram(直方圖)。
Histogram 可以理解成:
統計圖片中,每個亮度值出現了多少次。
以灰階圖片來說,每個 Pixel 的亮度介於 0 到 255。
因此 Histogram 的橫軸,就是亮度值。
而縱軸代表的是:
有多少個 Pixel 擁有這個亮度。
所以 Histogram 並不是在畫圖片,而是在畫圖片亮度的分布。
先讀入一張圖片。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("dog.jpeg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
接著使用 Matplotlib 畫出 Histogram。
plt.figure(figsize=(8,4))
plt.hist(gray.ravel(), bins=256, range=[0,256])
plt.title("Histogram")
plt.xlabel("Pixel Value")
plt.ylabel("Count")
plt.show()
結果會長得像這樣:

看到 Histogram 時,第一個要看的問題就是 柱子都集中在哪裡?
例如:
代表圖片大部分都是暗的,通常就是欠曝(Under Exposure)
代表圖片非常亮,通常就是過曝(Over Exposure)
代表亮度集中在中間,整體曝光通常比較平均。
如果 Histogram 從左一路分布到右,通常代表:
圖片同時具有暗部與亮部,整體對比也會比較好。
我們可以故意調整圖片亮度。
dark = cv2.convertScaleAbs(gray, alpha=1, beta=-80)
bright = cv2.convertScaleAbs(gray, alpha=1, beta=80)
接著畫三張 Histogram。
images = [dark, gray, bright]
titles = ["Dark", "Original", "Bright"]
plt.figure(figsize=(12,4))
for i in range(3):
plt.subplot(1,3,i+1)
plt.hist(images[i].ravel(), bins=256, range=[0,256])
plt.title(titles[i])
plt.tight_layout()
plt.show()
這時候就可以很明顯看到:
亮度增加,Histogram 會往右移。
亮度降低,Histogram 則會往左移。

Histogram 其實是很多影像處理方法的重要基礎。
例如:
甚至連後面會介紹的 Otsu 演算法。
也是利用 Histogram 去找最佳 Threshold。
所以 Histogram 不只是觀察工具。
而是很多演算法,本身就是建立在 Histogram 上。
今天介紹了 Histogram。
它把圖片所有 Pixel 的亮度分布整理成一張統計圖。
透過 Histogram,我們可以快速知道:
後面的很多影像處理技巧,也都會建立在 Histogram 的概念之上。
明天,我們要正式進入數位影像處理最重要的核心之一:
Convolution(卷積)。