使用 ColorMatrix 将图像转换为单色
Convert image to monochrome using ColorMatrix
我正在尝试构建一个将彩色图像转换为单色图像的函数。关于术语有很多混淆,但我说的是真正的黑白,我们只有两种颜色:黑色和白色 - 没有灰色。
这是我正在努力实现的示例:
-->
我还想要一种方法来控制转换的“阈值”(即像素必须有多“亮”才能产生白色像素)。
这是我现在拥有的。
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
,因为它们速度非常快,但我不太擅长矩阵,而且我似乎无法想出一个可以实现此结果的矩阵。
下面是逻辑工作原理的示例:
- 源颜色=
(200, 150, 250)
- 所以,灰度等效 =
(200, 200, 200)
- 所以,灰度值=
200
- 所以,
200 > threshold
- 所以,单色值=
255
- 所以,单色=
(255, 255, 255)
有什么方法可以使用 ColorMatrix
实现这种功能?
我也乐于接受其他想法!
考虑在
的第五行使用身份 ColorMatrix
{ -threshold, -threshold, -threshold, 0, 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, 0.000F, 0.000F},
new float[] {0.000F, 1.000F, 0.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 1.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {thresh, thresh, thresh, 0.000F, 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, 100.000F, 0.000F, 0.000F},
new float[] {100.000F, 100.000F, 100.000F, 0.000F, 0.000F},
new float[] {100.000F, 100.000F, 100.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 0.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, 0.333F, 0.000F, 0.000F},
new float[] {0.333F, 0.333F, 0.333F, 0.000F, 0.000F},
new float[] {0.333F, 0.333F, 0.333F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {bright, bright, bright, 0.000F, 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, 0, trImg.Width, trImg.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttr);
// Return the translated image
return trImg;
}
我正在尝试构建一个将彩色图像转换为单色图像的函数。关于术语有很多混淆,但我说的是真正的黑白,我们只有两种颜色:黑色和白色 - 没有灰色。
这是我正在努力实现的示例:
我还想要一种方法来控制转换的“阈值”(即像素必须有多“亮”才能产生白色像素)。
这是我现在拥有的。
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
,因为它们速度非常快,但我不太擅长矩阵,而且我似乎无法想出一个可以实现此结果的矩阵。
下面是逻辑工作原理的示例:
- 源颜色=
(200, 150, 250)
- 所以,灰度等效 =
(200, 200, 200)
- 所以,灰度值=
200
- 所以,
200 > threshold
- 所以,单色值=
255
- 所以,单色=
(255, 255, 255)
有什么方法可以使用 ColorMatrix
实现这种功能?
我也乐于接受其他想法!
考虑在
的第五行使用身份ColorMatrix
{ -threshold, -threshold, -threshold, 0, 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, 0.000F, 0.000F},
new float[] {0.000F, 1.000F, 0.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 1.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {thresh, thresh, thresh, 0.000F, 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, 100.000F, 0.000F, 0.000F},
new float[] {100.000F, 100.000F, 100.000F, 0.000F, 0.000F},
new float[] {100.000F, 100.000F, 100.000F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 0.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, 0.333F, 0.000F, 0.000F},
new float[] {0.333F, 0.333F, 0.333F, 0.000F, 0.000F},
new float[] {0.333F, 0.333F, 0.333F, 0.000F, 0.000F},
new float[] {0.000F, 0.000F, 0.000F, 1.000F, 0.000F},
new float[] {bright, bright, bright, 0.000F, 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, 0, trImg.Width, trImg.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttr);
// Return the translated image
return trImg;
}