【Python】圖像主色的 K-Means 分析
在我先前的博文中,我介紹了如何從網站上抓取圖片信息。如果說從網上抓取圖片非常容易實現,那么如何對這些圖像進行排序分類則稍微復雜一點。這個問題的關鍵在于,我們沒有一套尋找圖像主色的標準方法,不同的方法會產生不同的結果。
顏色理論
比方說我們已經下載好圖像信息,現在我們想要找出它的主色。如果你熟悉 Photoshop 的話,那么你一定認識代表主色分布的顏色直方圖。Corad Chavez 寫過一篇詳細介紹顏色直方圖的博文。我們可以直接從顏色直方圖中看出下圖的圖像主色是藍色和綠色。
我所使用的方法基于以下兩個假設條件:
-
圖像主色是由擁有多少該顏色的像素所決定的。
-
如果兩個顏色的RGB成分之間的歐式距離比較大,我們則認為這兩種顏色不同。
第一個假設聽起來非常有道理,但問題是:在真實的圖像中很難找到兩個顏色相同的像素。如果一個圖像是藍色的,那么它將擁有數以千計的深淺不同的藍 色像素。第二個假設條件需要決定哪個顏色和藍色比較相近。最常用的方法是觀測該顏色的 RGB 三維空間坐標,即兩個顏色之間的距離可以看成它們在三維空間中的直線距離。
讓我們從加載圖像開始吧:
值得一提的是,改變圖像的尺寸大小并不會改變其顏色的比例和分布,而且計算機處理小圖像時效率比較高。第 5-10 行的代碼目的是:在保持圖像比例不變的前提下,改變圖像的尺寸。
步驟一:利用 K-Means 對顏色聚類分析
給定之前的兩個假設條件,我們打算利用聚類來解決問題。我們擁有一大堆點的數據,我們需要根據它們的相似性對它們進行分組,同時我們還想找出每個組的中心點。 K-Means 算法是一種既簡單又高效的聚類算法。我們可以利用 Scikit 庫來實現它。
第 4 行代碼主要是將圖像轉換成包含像素的單列表文件,第 8 行代碼才是真正的聚類分析過程。OpenCV 中的圖像由 NumPy 的矩陣格式展現出來,比如一張包含 800*600 像素的圖像,它由一個 800*600*3 的數組所構成,每個像素分別由 R, G, B 三個成分表示。K-Means 所做的事情就是對這些三維空間的 RGB 數據進行聚類分析。
步驟二:根據像素點個數對聚類結果排序
接下來我們要做的事情是計算每個類群中包含多少像素點。我將利用 Adrian Rosebrock 的方法來處理這個問題。
第 2 行代碼用來尋找每個類群中所包含的像素點個數,而第 5-7 行代碼用來對它們進行排序處理,其中第一類群中擁有最多的像素點。
步驟三:聚類結果評估
本文的基礎性教程到這里就結束了,不過只要你接觸過 K-Means 算法,那么你肯定發現我跳過一個重要的步驟:如何選擇類群個數。類群個數是 K-Means 算法中很重要的一個參數,本文中選擇 k=3 。但是如果圖像的聚類群數小于 2 時,結果將會是啥樣的呢?此時要么是圖像中只有兩種主色,或者是在 RGB 空間中該算法無法較好地將顏色區分開來。如果你要探索 K-Means 算法的擬合情況,你可以利用 Silhouette 系數。該系數反映了聚類結果的得分情況,同時它還評估了兩個東西:每個類群中像素點的緊密程度和類群的聚類效果。強大的 Scikit 同樣可以算出 Silhouette 系數。
該系數的取值范圍是 -1 到 +1 之間,其中后者表示聚類結果優異。我們通常多次試驗 K-Means 算法從而選取最佳的類群個數。
圖像聚類的評估結果如下圖所示,其中我們可以看出第一個聚類結果更好。
對于色彩分明的圖像來說,聚類效果特別好。比如,下圖的聚類效果特別好,silhouette 系數表明最佳類群個數為 8。
結論
我們可以利用聚類算法找出圖像主色,其中最常用的模型是簡便又高效的 K-Means 算法。但需要注意的是,我們需要預先壓縮圖像的尺寸且找出最佳類群的個數。
本文的例子中,我們在 RGB 空間中對顏色進行聚類分析。其他文章認為:在 LAB 空間中分析問題可以得到更好的結果。如果你對這個問題感興趣的話,你可以查閱 Eddie Bell 的相關文章。
參考資料:
http://creativepro.com/better-tools-for-tones-why-i-don-t-look-the-histogram/
http://www.pyimagesearch.com/2014/05/26/opencv-python-k-means-color-clustering/
原文鏈接:
http://www.alanzucconi.com/2015/05/24/how-to-find-the-main-colours-in-an-image/
原文作者:Alan Zuccoi
翻譯:Fibears