【问题标题】:Caculate color average returns "Attempt to divide by Zero"计算颜色平均值返回“尝试除以零”
【发布时间】:2021-02-22 04:07:10
【问题描述】:

我确实尝试在我的应用程序中使用这个代码来解决这个问题:

How to determine the background color of document when there are 3 options, using c# or imagemagick

private System.Drawing.Color CalculateAverageColor(Bitmap bm)
{
    int width = bm.Width;
    int height = bm.Height;
    int red = 0;
    int green = 0;
    int blue = 0;
    int minDiversion = 15; // drop pixels that do not differ by at least minDiversion between color values (white, gray or black)
    int dropped = 0; // keep track of dropped pixels
    long[] totals = new long[] { 0, 0, 0 };
    int bppModifier = bm.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb ? 3 : 4; // cutting corners, will fail on anything else but 32 and 24 bit images

    BitmapData srcData = bm.LockBits(new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, bm.PixelFormat);
    int stride = srcData.Stride;
    IntPtr Scan0 = srcData.Scan0;

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

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                int idx = (y * stride) + x * bppModifier;
                red = p[idx + 2];
                green = p[idx + 1];
                blue = p[idx];
                if (Math.Abs(red - green) > minDiversion || Math.Abs(red - blue) > minDiversion || Math.Abs(green - blue) > minDiversion)
                {
                    totals[2] += red;
                    totals[1] += green;
                    totals[0] += blue;
                }
                else
                {
                    dropped++;
                }
            }
        }
    }

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

    return System.Drawing.Color.FromArgb(avgR, avgG, avgB);
}

问题是当我添加位图时,会发生这种情况:

谁能帮我弄清楚到底发生了什么?

【问题讨论】:

  • 它总是在 else 里面,所以 drop 的值是 width*height。所以你必须调试为什么它会进入 else。
  • 您可能想检查 count 是否为零,然后将所有平均值分配为 0,假设所有像素都应该“丢弃”,就像位图是灰度或黑白一样。或者决定灰度或黑白的“平均”颜色应该是什么。
  • 显然count 是0。

标签: c# colors pixel


【解决方案1】:

虽然有问题,但更大的问题是如何确定问题?

您指出它在哪里崩溃,但它为什么会在那里崩溃?如果count 为零,它只会产生该错误。

int count = width * height - dropped;

假设宽度和高度是正确的(不要假设,在这一行放一个断点并验证它!),这意味着dropped必须等于width * height

if (Math.Abs(red - green) > minDiversion || Math.Abs(red - blue) > minDiversion || Math.Abs(green - blue) > minDiversion)
...
else
{
    dropped++;
}

这段代码表示如果像素是灰度颜色(或接近灰度颜色),那么它将递增dropped。这个想法是,它只会为您提供颜色像素的平均值,并避免灰度像素扭曲结果。

那么,解决方案是什么?有两种可能的答案,只有您可以为您的问题集选择正确的答案:

if (Math.Abs(red - green) > minDiversion || Math.Abs(red - blue) > minDiversion || Math.Abs(green - blue) > minDiversion)

您可以摆脱此检查并始终向totals 值添加一些内容。这将在所有情况下为您提供一种颜色,但正确程度取决于您的需求。

int count = width * height - dropped;
if (count == 0)
{
    return Color.Black;
}

或者,您可以检查找不到颜色的情况,只返回默认响应(或者,可能抛出异常)。

取决于你的需要。

【讨论】:

  • 我只是想出了一些东西,为了触发这个方法,我将它注册到一个位图发生变化的事件中,该位图将被放入方法中并触发它,但是当位图发生变化时,它会以某种方式添加上一个位图,而不是当前位图,这就是为什么位图基本上是空白的
【解决方案2】:

我应该让大家看到这个以更好地理解问题

【讨论】: