减少图像中的颜色深度不会减小文件大小?

时间:2012-04-13 11:54:22

标签: c# image-processing compression color-depth

我使用此代码来减少图像的深度:

public void ApplyDecreaseColourDepth(int offset)
{
    int A, R, G, B;

    Color pixelColor;

    for (int y = 0; y < bitmapImage.Height; y++)
    {
        for (int x = 0; x < bitmapImage.Width; x++)
        {
            pixelColor = bitmapImage.GetPixel(x, y);

            A = pixelColor.A;

            R = ((pixelColor.R + (offset / 2)) - ((pixelColor.R + (offset / 2)) % offset) - 1);

            if (R < 0)
            {
                R = 0;
            }

            G = ((pixelColor.G + (offset / 2)) - ((pixelColor.G + (offset / 2)) % offset) - 1);

            if (G < 0)
            {
                G = 0;
            }

            B = ((pixelColor.B + (offset / 2)) - ((pixelColor.B + (offset / 2)) % offset) - 1);

            if (B < 0)
            {
                B = 0;
            }

            bitmapImage.SetPixel(x, y, Color.FromArgb(A, R, G, B));
        }
    }
}

第一个问题是:我给函数的偏移量不是深度,是吗?

第二个是当我在减少颜色深度后尝试保存图像时,我获得与原始图像相同的大小。我不应该得到一个尺寸较小的文件,或者我错了。

这是我用来保存修改后图像的代码:

private Bitmap bitmapImage;

public void SaveImage(string path)
{
    bitmapImage.Save(path);
} 

6 个答案:

答案 0 :(得分:4)

您只是将像素值设置为较低级别。

例如,如果一个像素由3个通道表示,每个通道16位,则将每个像素颜色值减少到每通道8位。这将永远不会减小图像大小,因为分配的像素已经具有16位的固定深度。 尝试将新值保存到最大为8位深度的新图像 当然,您将以字节为单位缩小图像,但不会影响整体尺寸,即图像的X,Y尺寸将保持不变。你在做什么会降低图像质量。

答案 1 :(得分:2)

让我们首先清理一下代码。以下模式:

R = ((pixelColor.R + (offset / 2)) - ((pixelColor.R + (offset / 2)) % offset) - 1);
if (R < 0)
{
    R = 0;
}

等同于:

R = Math.Max(0, (pixelColor.R + offset / 2) / offset * offset - 1);

您可以简化您的功能:

public void ApplyDecreaseColourDepth(int offset)
{
    for (int y = 0; y < bitmapImage.Height; y++)
    {
        for (int x = 0; x < bitmapImage.Width; x++)
        {
            int pixelColor = bitmapImage.GetPixel(x, y);

            int A = pixel.A;

            int R = Math.Max(0, (pixelColor.R + offset / 2) / offset * offset - 1);
            int G = Math.Max(0, (pixelColor.G + offset / 2) / offset * offset - 1);
            int B = Math.Max(0, (pixelColor.B + offset / 2) / offset * offset - 1);

            bitmapImage.SetPixel(x, y, Color.FromArgb(A, R, G, B));
        }
    }
}

回答你的问题:

  1. 正确;偏移量是步长函数中步长的大小。每个颜色分量的深度是原始深度减去log 2 (偏移)。例如,如果原始图像的每个分量(bpc)的深度为8位,偏移量为16,则每个分量的深度为8 - log 2 (16)= 8 - 4 = 4 bpc。但请注意,这仅表示每个输出组件可以容纳多少熵,而不是每个组件实际用于存储结果的位数。
  2. 输出文件的大小取决于存储的颜色深度和使用的压缩。简单地减少每个组件可以具有的不同值的数量不会自动导致每个组件使用更少的位,因此除非您明确选择每个组件使用较少位的编码,否则未压缩的图像不会收缩。如果要保存压缩格式(如PNG),您可能会看到转换后的图像有所改善,或者您可能没有;这取决于图像的内容。具有大量平坦无纹理区域的图像(例如线条图画)将会看到微不足道的改善,而照片可能会从变换中获益(尽管以感知质量为代价)。

答案 2 :(得分:1)

首先,我想问你一个简单的问题:)

int i = 10;

现在i = i - ;

它对我的大小有影响吗? ans是否。

你正在做同样的事情

成像的索引表示在两个矩阵中 1用于颜色映射和 2来自图像映射

您只需更改元素的值而不删除它 所以它不会影响图像的大小

答案 3 :(得分:1)

使用Get / SetPixel无法降低颜色深度。这些方法只会改变颜色。

您似乎无法轻松将图像保存为某种像素格式,但我确实找到了一些代码来更改内存中的像素格式。您可以尝试保存它,它可能会起作用,具体取决于您保存的格式。

从这个问题:https://stackoverflow.com/a/2379838/785745

他给出了这个代码来改变颜色深度:

public static Bitmap ConvertTo16bpp(Image img) {
    var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
    using (var gr = Graphics.FromImage(bmp))
    {
        gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
    }
    return bmp;
}

您可以将代码中的PixelFormat更改为您需要的任何内容。

答案 4 :(得分:0)

某个像素计数的位图图像始终大小相同,因为位图格式不应用压缩。 如果您使用算法(例如JPEG)压缩图像,则缩小&#39;图像应该更小。

R = ((pixelColor.R + (offset / 2)) - ((pixelColor.R + (offset / 2))

这不总是返回0吗?

答案 5 :(得分:0)

如果要缩小图像的大小,可以在调用Image.Save()时指定其他压缩格式。

GIF文件格式可能是一个很好的选择,因为它最适用于相同颜色的连续像素(当颜色深度较低时更常出现)。

JPEG可以很好地处理照片,但是如果将24位图像转换为16位图像然后使用JPEG对其进行压缩,则不会看到明显的结果,因为算法的工作方式(你更好)关闭将24位图片直接保存为JPEG。

正如其他人所解释的那样,除非您将结果数据实际复制到另一个具有Format16bppRgb555 {{1}} {{}}}的Bitmap对象,否则您的代码不会减小Image对象使用的大小。< / p>