有時候咱們須要找出一張圖片中的主色調,這裏的主色調並非指顏色最多的,而是指最「醒目」的。算法
例如 win8 在更換桌面壁紙後,會將任務欄的背景色改成該壁紙的主色調。優化
看下面幾張圖能夠更直觀的明白「醒目」的意思。blog
(這張圖裏面最醒目的無疑是紫紅色的小花,而不是顏色佔大多數的淡青色背景)圖片
(這張圖也同樣,最醒目的顏色應該是深紅色,而不是深藍色)get
我想了一個簡單的辦法,就是根據圖片中每一個像素的色調值去判斷哪些像素符合「醒目」這個特性。it
分三步進行class
1.計算整個圖片的色調的平均值 (avg_hue)foreach
2.遍歷每一個像素,計算該像素的色調值與 avg_hue 的色差(即將兩者相減後取絕對值),若是該色差大於一個閾值(本文中取 30),List
則將該像素加入到「醒目像素」的列表遍歷
3.計算整個「醒目像素列表」的顏色均值,獲得的結果即爲該圖片的主色調。
下面看看該算法的效果如何
我將計算出的主色調畫在原圖的左上角,以方便對比。結果以下
能夠看到基本上達到了我想要的效果。
下面給出具體代碼,代碼未經任何優化,速度比較慢。
Color get_major_color(Bitmap bitmap) { //色調的總和 var sum_hue = 0d; //色差的閾值 var threshold = 30; //計算色調總和 for (int h = 0; h < bitmap.Height; h++) { for (int w = 0; w < bitmap.Width; w++) { var hue = bitmap.GetPixel(w, h).GetHue(); sum_hue += hue; } } var avg_hue = sum_hue / (bitmap.Width * bitmap.Height); //色差大於閾值的顏色值 var rgbs = new List<Color>(); for (int h = 0; h < bitmap.Height; h++) { for (int w = 0; w < bitmap.Width; w++) { var color = bitmap.GetPixel(w, h); var hue = color.GetHue(); //若是色差大於閾值,則加入列表 if (Math.Abs(hue - avg_hue) > threshold) { rgbs.Add(color); } } } if (rgbs.Count == 0) return Color.Black; //計算列表中的顏色均值,結果即爲該圖片的主色調 int sum_r = 0, sum_g = 0, sum_b = 0; foreach (var rgb in rgbs) { sum_r += rgb.R; sum_g += rgb.G; sum_b += rgb.B; } return Color.FromArgb(sum_r / rgbs.Count, sum_g / rgbs.Count, sum_b / rgbs.Count); }