获取图片的主色调

huwei001982 2014-04-30 04:11:06
有时候我们需要找出一张图片中的主色调,这里的主色调并不是指颜色最多的,而是指最“醒目”的。

例如 win8 在更换桌面壁纸后,会将任务栏的背景色改为该壁纸的主色调。

看下面几张图可以更直观的明白“醒目”的意思。

(这张图里面最醒目的无疑是紫红色的小花,而不是颜色占大多数的淡青色背景)


(这张图也一样,最醒目的颜色应该是深红色,而不是深蓝色)

我想了一个简单的办法,就是根据图片中每个像素的色调值去判断哪些像素符合“醒目”这个特性。

分三步进行

1.计算整个图片的色调的平均值 (avg_hue)

2.遍历每个像素,计算该像素的色调值与 avg_hue 的色差(即将二者相减后取绝对值),如果该色差大于一个阈值(本文中取 30),

则将该像素加入到“醒目像素”的列表

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);
}
...全文
1919 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
tanta 2014-04-30
  • 打赏
  • 举报
回复
直接点GetPixel操作很慢,你可以用 private void LockUnlockBitsExample(PaintEventArgs e) { Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg"); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); System.Drawing.Imaging.BitmapData bmpbmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = bmp.Width * bmp.Height * 3; byte[] rgbValues = new byte[bytes]; for (int counter = 0; counter < rgbValues.Length; counter += 3) { Marshal.WriteByte(ptr, counter, 255); } bmp.UnlockBits(bmpData); e.Graphics.DrawImage(bmp, 0, 0); } 这个办法来快速运算,跟GetPixel不是一个数量级的。
devmiao 2014-04-30
  • 打赏
  • 举报
回复
不关心算法, 关心什么叫“主色调”。以及你的定义在极端情况下是否造成误判。
zylsky 2014-04-30
  • 打赏
  • 举报
回复
这功能好强大
唐洛阳 2014-04-30
  • 打赏
  • 举报
回复
这图很不错!
dianjixue1 2014-04-30
  • 打赏
  • 举报
回复
不错,感觉还是对比明显的图片效果比较明显。
huwei001982 2014-04-30
  • 打赏
  • 举报
回复
引用 1 楼 feiyun0112 的回复:
http://www.codeproject.com/Questions/677506/Csharp-find-the-majority-color-of-an-image
版主看仔细啊,我特意写了不是获取 “颜色值最多的“
oLanJieKou 2014-04-30
  • 打赏
  • 举报
回复
这功能好强大 火钳刘明
feiyun0112 2014-04-30
  • 打赏
  • 举报
回复
http://www.codeproject.com/Questions/677506/Csharp-find-the-majority-color-of-an-image

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧