C#从二进制图像到透明位图
C# get from binary Image to transparent Bitmap
我得到了一个二进制图像(来自 EMGU)A,我想得到一个位图,该位图在 A 为黑色的所有地方都是透明的,在所有地方都是透明的红色,其中 A 是白色的。一开始我想至少让黑色部分不可见,但已经失败了:
我尝试通过以下方式做到这一点:
private Graphics graphics;
private Bitmap bitmap;
private Image<Gray, Byte> mask;
//graphic, bitmap and mask are being initialized in the constructor of the object
public Bitmap getMask()
{
//...
graphics.clear(Color.FromArgb(0,0,0,0);
graphics.DrawImage(mask.ToBitmap(), 0, 0);
bitmap.makeTransparent(255, 0, 0, 0);
//...
}
如何处理白色到红色部分?
有没有一种 easier/more 有效的方法可以通过使用 EMGU 来做到这一点?
这是一个快速例程,可以满足您的要求:
public static Bitmap MakeSpecialTransparent(Bitmap bmp)
{
// we expect a 32bpp bitmap!
var bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite, bmp.PixelFormat);
long len = bmpData.Height * bmpData.Stride;
byte[] data = new byte[len];
Marshal.Copy(bmpData.Scan0, data, 0, data.Length);
for (int i = 0; i < len; i += 4)
{
if (data[i] == 0 && data[i+1] == 0 && data[i+2] == 0 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0;
}
else
if (data[i] == 255 && data[i+1] == 255 && data[i+2] == 255 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 255; data[i + 3] = 0;
}
}
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
请注意,此 a) 期望 Bitmap
以 32bpp
图像的形式出现,并且 b) 没有任何 公差 :如果黑白像素不是 100% 黑白,它们不会改变。
另请注意,我们在这里处理的物理像素是有序的 BGRA
,因此 data[i+3
] 是 Alpha
通道,data[i+2]
是 Red
等..
要增加容忍度,您可能需要研究 !
作为锁定位和一次处理一个像素(公认更快)的替代方法,您还可以使用颜色变换矩阵来实现相同的效果。矩阵方法相当灵活,您的原始图像不必是完美的;如果原始图像有噪点,这种方法仍然有效。
对于您的特定情况(黑色 => 透明,白色 => red/50%),代码如下所示:
using System.Drawing;
using System.Drawimg.Imaging;
...
// Original image to be transformed
var src = Image.FromFile(@"c:\temp\test.png");
// Destination image to receive the transformation
var dest = new Bitmap(src.Width, src.Height, PixelFormat.32bppArgb);
using (var g = Graphics.FromImage(dest))
{
var attr = new ImageAttributes();
float[][] matElements = {
new float[] { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f },
new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
new float[] { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }
};
attr.SetColorMatrix(new ColorMatrix(matElements), ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height), 0, 0,
src.Width, src.Height, GraphicsUnit.Pixel, attr);
}
从上面的颜色矩阵我们得到:
- 新的红色值 = 1
- 新绿色值 = 1 - 旧绿色值
- 新蓝色值 = 1 - 旧蓝色值
- 新的 alpha 值 = 0.5 * 旧的红色值
新的红色值是从矩阵的第 1 列开始计算的。绿色是从第2列开始计算的,依此类推...
我得到了一个二进制图像(来自 EMGU)A,我想得到一个位图,该位图在 A 为黑色的所有地方都是透明的,在所有地方都是透明的红色,其中 A 是白色的。一开始我想至少让黑色部分不可见,但已经失败了:
我尝试通过以下方式做到这一点:
private Graphics graphics;
private Bitmap bitmap;
private Image<Gray, Byte> mask;
//graphic, bitmap and mask are being initialized in the constructor of the object
public Bitmap getMask()
{
//...
graphics.clear(Color.FromArgb(0,0,0,0);
graphics.DrawImage(mask.ToBitmap(), 0, 0);
bitmap.makeTransparent(255, 0, 0, 0);
//...
}
如何处理白色到红色部分? 有没有一种 easier/more 有效的方法可以通过使用 EMGU 来做到这一点?
这是一个快速例程,可以满足您的要求:
public static Bitmap MakeSpecialTransparent(Bitmap bmp)
{
// we expect a 32bpp bitmap!
var bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite, bmp.PixelFormat);
long len = bmpData.Height * bmpData.Stride;
byte[] data = new byte[len];
Marshal.Copy(bmpData.Scan0, data, 0, data.Length);
for (int i = 0; i < len; i += 4)
{
if (data[i] == 0 && data[i+1] == 0 && data[i+2] == 0 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0;
}
else
if (data[i] == 255 && data[i+1] == 255 && data[i+2] == 255 )
{
data[i] = 0; data[i + 1] = 0; data[i + 2] = 255; data[i + 3] = 0;
}
}
Marshal.Copy(data, 0, bmpData.Scan0, data.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
请注意,此 a) 期望 Bitmap
以 32bpp
图像的形式出现,并且 b) 没有任何 公差 :如果黑白像素不是 100% 黑白,它们不会改变。
另请注意,我们在这里处理的物理像素是有序的 BGRA
,因此 data[i+3
] 是 Alpha
通道,data[i+2]
是 Red
等..
要增加容忍度,您可能需要研究
作为锁定位和一次处理一个像素(公认更快)的替代方法,您还可以使用颜色变换矩阵来实现相同的效果。矩阵方法相当灵活,您的原始图像不必是完美的;如果原始图像有噪点,这种方法仍然有效。
对于您的特定情况(黑色 => 透明,白色 => red/50%),代码如下所示:
using System.Drawing;
using System.Drawimg.Imaging;
...
// Original image to be transformed
var src = Image.FromFile(@"c:\temp\test.png");
// Destination image to receive the transformation
var dest = new Bitmap(src.Width, src.Height, PixelFormat.32bppArgb);
using (var g = Graphics.FromImage(dest))
{
var attr = new ImageAttributes();
float[][] matElements = {
new float[] { 0.0f, 0.0f, 0.0f, 0.5f, 0.0f },
new float[] { 0.0f, -1.0f, 0.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f },
new float[] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
new float[] { 1.0f, 1.0f, 1.0f, 0.0f, 1.0f }
};
attr.SetColorMatrix(new ColorMatrix(matElements), ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
g.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height), 0, 0,
src.Width, src.Height, GraphicsUnit.Pixel, attr);
}
从上面的颜色矩阵我们得到:
- 新的红色值 = 1
- 新绿色值 = 1 - 旧绿色值
- 新蓝色值 = 1 - 旧蓝色值
- 新的 alpha 值 = 0.5 * 旧的红色值
新的红色值是从矩阵的第 1 列开始计算的。绿色是从第2列开始计算的,依此类推...