1

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

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);
} 
4

6 回答 6

4

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

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

于 2012-04-13T12:01:44.473 回答
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. 正确的; 偏移量是 step 函数中的步骤大小。每个颜色分量的深度是原始深度减去 log 2(偏移量)。例如,如果原始图像的每个分量 (bpc) 的深度为 8 位,偏移量为 16,则每个分量的深度为 8 - log 2 (16) = 8 - 4 = 4 bpc。但是请注意,这仅表示每个输出组件可以容纳多少熵,而不是每个组件实际用于存储结果的比特数。
  2. 输出文件的大小取决于存储的颜色深度和使用的压缩。简单地减少每个组件可以具有的不同值的数量不会自动导致每个组件使用更少的位,因此除非您明确选择每个组件使用更少位的编码,否则未压缩的图像不会缩小。如果您要保存压缩格式(例如 PNG),您可能会看到转换后的图像有所改进,或者您可能不会;这取决于图像的内容。具有许多平坦无纹理区域的图像(例如线条艺术图)的改进可以忽略不计,而照片可能会从变换中显着受益(尽管以牺牲感知质量为代价)。
于 2012-04-13T12:37:32.070 回答
1

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

诠释 i = 10;

现在 i = i--;

浇灭它对 i 大小的影响?答案是没有。

你在做同样的事情

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

你只是改变元素的值而不是删除它,所以它不会影响图像的大小

于 2012-04-13T12:08:35.610 回答
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 更改为您需要的任何内容。

于 2012-04-13T12:10:57.620 回答
0

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

GIF 文件格式可能是一个不错的选择,因为它最适用于相同颜色的连续像素(当您的颜色深度较低时,这种情况更常见)。

JPEG 非常适用于照片,但如果将 24 位图像转换为 16 位图像,然后使用 JPEG 对其进行压缩,则不会看到显着的结果,因为算法的工作方式(最好保存24 位图片直接为 JPEG)。

正如其他人所解释的那样,您的代码不会减少 Image 对象使用的大小,除非您实际将结果数据复制到另一个具有不同PixelFormat的 Bitmap 对象中,例如Format16bppRgb555.

于 2012-04-13T13:53:12.783 回答
0

具有一定像素数的位图图像始终大小相同,因为位图格式不应用压缩。如果您使用算法(例如JPEG)压缩图像,那么“缩小”的图像应该更小。

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

这不总是返回0吗?

于 2012-04-13T12:01:49.363 回答