如何计算一个位图的平均RGB颜色值如何计算一个位图的平均RGB颜色值(How to calculat

2019-05-14 09:43发布

在我的C#(3.5)申请我需要得到的平均颜色值的位图的红色,绿色和蓝色通道。 优选不使用外部库。 可以这样做? 如果是这样,怎么样? 提前致谢。

试图让事情变得更精确:位图中的每个像素都有一定的RGB颜色值。 我想获得的平均RGB值图像的所有像素。

Answer 1:

最快的方法是使用不安全的代码:

BitmapData srcData = bm.LockBits(
            new Rectangle(0, 0, bm.Width, bm.Height), 
            ImageLockMode.ReadOnly, 
            PixelFormat.Format32bppArgb);

int stride = srcData.Stride;

IntPtr Scan0 = srcData.Scan0;

long[] totals = new long[] {0,0,0};

int width = bm.Width;
int height = bm.Height;

unsafe
{
  byte* p = (byte*) (void*) Scan0;

  for (int y = 0; y < height; y++)
  {
    for (int x = 0; x < width; x++)
    {
      for (int color = 0; color < 3; color++)
      {
        int idx = (y*stride) + x*4 + color;

        totals[color] += p[idx];
      }
    }
  }
}

int avgB = totals[0] / (width*height);
int avgG = totals[1] / (width*height);
int avgR = totals[2] / (width*height);

请注意:我没有测试此代码...(我可能会削减一些角落)

此代码还asssumes一个32位的图像。 对于24位图像。 在x * 4更改为X * 3



Answer 2:

这里有一个更简单的方法:

Bitmap bmp = new Bitmap(1, 1);
Bitmap orig = (Bitmap)Bitmap.FromFile("path");
using (Graphics g = Graphics.FromImage(bmp))
{
    // updated: the Interpolation mode needs to be set to 
    // HighQualityBilinear or HighQualityBicubic or this method
    // doesn't work at all.  With either setting, the results are
    // slightly different from the averaging method.
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(orig, new Rectangle(0, 0, 1, 1));
}
Color pixel = bmp.GetPixel(0, 0);
// pixel will contain average values for entire orig Bitmap
byte avgR = pixel.R; // etc.

基本上,您使用的DrawImage到原来的位图复制到1个像素的位图。 然后该1个像素的RGB值将代表整个原始的平均值。 GetPixel相对缓慢,但只有当你使用它的一个大的位图,逐像素。 调用它曾经在这里根本不算什么。

使用LockBits确实很快,但是一些Windows用户具有阻止的“不安全”的代码执行安全策略。 我提到这一点,因为这实际上只是咬了我的身后最近。

更新 :与InterpolationMode设置为HighQualityBicubic,这种方法需要大约两倍,只要用LockBits平均; 与HighQualityBilinear,它仅比LockBits的时间会稍长。 所以,除非你的用户有禁止的安全策略unsafe代码,绝对不要用我的方法。

更新2:随着时间的推移,我现在明白为什么这种方法并不能在所有的工作。 即使是最高质量的插值算法包括只有几个相邻像素,所以有一个限度的图像可以有多少被压塌,而不会丢失信息。 和挤压一个图像到一个像素远远超出这个限度,不管你用什么算法。

做到这一点的唯一方法是收缩步骤图像(也许一半每次萎缩的话),直到你得到它归结为一个像素的大小。 我无法表达在单纯的文字是什么时间写这样的一个十足的浪费会,所以我很高兴我停止自己,当我想到这一点。 :)

请,没有人投给这个回答任何更多的-这可能是有史以来我的愚蠢想法。



Answer 3:

这种事情会工作,但它可能不够快是有益的。

public static Color getDominantColor(Bitmap bmp)
{

       //Used for tally
       int r = 0;
       int g = 0;
       int b = 0;

     int total = 0;

     for (int x = 0; x < bmp.Width; x++)
     {
          for (int y = 0; y < bmp.Height; y++)
          {
               Color clr = bmp.GetPixel(x, y);

               r += clr.R;
               g += clr.G;
               b += clr.B;

               total++;
          }
     }

     //Calculate average
     r /= total;
     g /= total;
     b /= total;

     return Color.FromArgb(r, g, b);
}


文章来源: How to calculate the average rgb color values of a bitmap