使用 ColorMatrix 将图像转换为单色

问题描述

我正在尝试构建一个彩色图像转换为单色的函数。关于术语有很多混淆,但我说的是真正的黑白,我们只有两种颜色:黑色和白色 - 没有灰色。

以下是我要实现的目标的示例:

Original Image

-->

Monochrome Image

我还想要一种方法来控制转换的“阈值”(即像素必须有多“亮”才能产生白色像素)。

这是我现在拥有的。

private Bitmap bitmap2Monochrome(Bitmap srcImg,int brightness)
{
    Bitmap monoImg = new Bitmap(srcImg.Width,srcImg.Height);

    // Loop through all the pixels in the image
    for (int y = 0; y < srcImg.Height; y++)
    {
        for (int x = 0; x < srcImg.Width; x++)
        {
            // Get pixel color
            Color existingColor = srcImg.GetPixel(x,y);
            
            // Average R,G,and B to determine "brightness" of this pixel
            int gray = (int)((existingColor.R + existingColor.G + existingColor.G) / 3);

            // If the "brightness" is greater than the threshold,this is a white pixel
            int color = 0;
            if (gray > brightness)
            {
                color = 255;
            }

            // Update the output image
            Color newColor = Color.FromArgb(color,color,color);
            monoImg.SetPixel(x,y,newColor);
        }
    }

    return monoImg;
}

这种方法完全按照我想要的方式工作,但它(可以理解)非常慢。这是因为 GetPixel()SetPixel() 函数非常慢。

我很想使用 ColorMatrix,因为它们太快了,但我不太擅长矩阵,而且我似乎无法想出一个矩阵来实现这个结果。

>

以下是逻辑工作原理的示例:

  1. 源颜色 = (200,150,250)
  2. 所以,灰度等效 = (200,200,200)
  3. 所以,灰度值 = 200
  4. 所以,200 > threshold
  5. 所以,单色值 = 255
  6. 所以,单色 = (255,255,255)

有什么办法可以使用 ColorMatrix 实现这种功能吗?

我也乐于接受其他想法!

解决方法

考虑将身份 ColorMatrix 与第五行

一起使用
{ -threshold,-threshold,1 }

这将允许您将低于阈值的所有颜色转换为 0

然后您可以使用第二个 ColorMatrix 将所有 RGB 相乘,使它们大于 1.0d。这将创建您想要的效果(假设 ColorMatrix 的实现防止负值和大于 1.0d 的值)

,

只是扩展 DekuDesu 的答案,这里有一个编码解决方案。

private Bitmap bitmap2Monochrome(Bitmap img,int threshold)
{
    // Convert the picture to grayscale (so we have "lightness values")
    Bitmap grayImg = bitmap2Grayscale(img,0);

    // Adjust threshold to be in range 0.0 - 1.0
    float thresh = -1 * ((float)threshold / 255);

    // Subtract threshold value from all pixels to change dark pixels to black
    // Note: Values are automatically bound in range 0 - 255
    float[][] colorTransMatrix =
    {
        new float[] {1.000F,0.000F,0.000F},new float[] {0.000F,1.000F,new float[] {thresh,thresh,1.000F}
    };
    Bitmap temp = translateBitmap(img,colorTransMatrix);

    // Multiply remaining pixels by large value to change light pixels to white
    // Note: Values are automatically bound in range 0 - 255
    float[][] colorTransMatrix2 =
    {
        new float[] {100.000F,100.000F,new float[] {100.000F,1.000F}
    };
    Bitmap monoImg = translateBitmap(temp,colorTransMatrix2);

    // Return the monochrome image
    return monoImg;
}


private Bitmap bitmap2Grayscale(Bitmap img,int brightness)
{
    // Adjust brightness to be in range 0.0 - 1.0
    float bright = -1 * ((float)brightness / 255);

    // Average R,G,B values of all pixels
    float[][] colorTransMatrix =
    {
        new float[] {0.333F,0.333F,new float[] {0.333F,new float[] {bright,bright,1.000F},};
    Bitmap grayImg = translateBitmap(img,colorTransMatrix);

    // Return the grayscale image
    return grayImg;
}


private Bitmap translateBitmap(Bitmap img,float[][] colorTranslationMatrix)
{
    // Setup color translation
    ColorMatrix colorMatrix = new ColorMatrix(colorTranslationMatrix);
    ImageAttributes imgAttr = new ImageAttributes();
    imgAttr.SetColorMatrix(colorMatrix,ColorMatrixFlag.Default,ColorAdjustType.Bitmap);

    // Draw the image with translated colors
    Bitmap trImg = new Bitmap(img.Width,img.Height);
    Graphics g = Graphics.FromImage(trImg);
    g.DrawImage(img,new Rectangle(0,trImg.Width,trImg.Height),img.Width,img.Height,GraphicsUnit.Pixel,imgAttr);

    // Return the translated image
    return trImg;
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...