问题描述
我在将图像从 byte YUV420p[]
转换为 byte RGB[]
然后再转换为 Bitmap
时遇到问题。
这是我正在使用的从 YUV 转换为 RGB 的方法:
double[,] YUV2RGB_CONVERT_MATRIX = new double[3,3]
{
{ 1,1.4022 },{ 1,-0.3456,-0.7145 },1.771,0 }
};
unsafe Bitmap ConvertYUV2RGB(byte[] YUVFrame,int width,int height)
{
int uIndex = width * height;
int vIndex = uIndex + ((width * height) >> 2);
int gIndex = width * height;
int bIndex = gIndex * 2;
byte[] rgbFrame = new byte[uIndex * 3];
//图片为pic1,RGB颜色的二进制数据转换得的int r,g,b;
Bitmap bitmap = new Bitmap(width,height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// R分量
int temp = (int)(YUVFrame[y * width + x] + (YUVFrame[vIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[0,2]);
rgbFrame[y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
// G分量
temp = (int)(YUVFrame[y * width + x] + (YUVFrame[uIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[1,1] + (YUVFrame[vIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[1,2]);
rgbFrame[gIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
// B分量
temp = (int)(YUVFrame[y * width + x] + (YUVFrame[uIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[2,1]);
rgbFrame[bIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
System.Drawing.Color c = System.Drawing.Color.FromArgb(RGBFrame[y * width + x],RGBFrame[gIndex + y * width + x],RGBFrame[bIndex + y * width + x]);
bitmap.SetPixel(x,y,c);
}
}
return bitmap;
}
该函数 100% 有效,但由于显而易见的原因它非常慢:
System.Drawing.Color c = System.Drawing.Color.FromArgb(RGBFrame[y * width + x],c);
这是生成的图像:
因此,为了避免在循环内调用 bitmap.SetPixel(x,c)
,我将代码更改为:
unsafe Bitmap ConvertYUV2RGB(byte[] YUVFrame,int height)
{
int uIndex = width * height;
int vIndex = uIndex + ((width * height) >> 2);
int gIndex = width * height;
int bIndex = gIndex * 2;
byte[] RGBFrame = new byte[uIndex * 3];
//图片为pic1,b;
//Bitmap bitmap = new Bitmap(width,2]);
RGBFrame[y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
// G分量
temp = (int)(YUVFrame[y * width + x] + (YUVFrame[uIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[1,2]);
RGBFrame[gIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
// B分量
temp = (int)(YUVFrame[y * width + x] + (YUVFrame[uIndex + (y / 2) * (width / 2) + x / 2] - 128) * YUV2RGB_CONVERT_MATRIX[2,1]);
RGBFrame[bIndex + y * width + x] = (byte)(temp < 0 ? 0 : (temp > 255 ? 255 : temp));
// Commented to avoid calling functions from inside the for loop
// System.Drawing.Color c = System.Drawing.Color.FromArgb(RGBFrame[y * width + x],RGBFrame[bIndex + y * width + x]);
// bitmap.SetPixel(x,c);
}
}
return CreateBitmap(RGBFrame,width,height);
}
private Bitmap CreateBitmap(byte[] RGBFrame,int height)
{
PixelFormat pxFormat = PixelFormat.Format24bppRgb;
Bitmap bmp = new Bitmap(width,height,pxFormat);
BitmapData bmpData = bmp.LockBits(new Rectangle(0,height),ImageLockMode.ReadWrite,pxFormat);
IntPtr pNative = bmpData.Scan0;
Marshal.copy(RGBFrame,pNative,RGBFrame.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
但我无法正确创建图像。结果如下:
这里发生了什么?
解决方法
我终于用这个函数解决了我的问题:
unsafe Bitmap ConvertYUV2RGB(byte[] YUVFrame,int width,int height)
{
int numOfPixel = width * height;
int positionOfV = numOfPixel;
int positionOfU = numOfPixel / 4 + numOfPixel;
byte[] rgb = new byte[numOfPixel * 3];
int R = 0;
int G = 1;
int B = 2;
for (int i = 0; i < height; i++)
{
int startY = i * width;
int step = (i / 2) * (width / 2);
int startU = positionOfU + step;
int startV = positionOfV + step;
for (int j = 0; j < width; j++)
{
int Y = startY + j;
int U = startU + j / 2;
int V = startV + j / 2;
int index = Y * 3;
double r = ((YUVFrame[Y] & 0xff) + 1.4075 * ((YUVFrame[V] & 0xff) - 128));
double g = ((YUVFrame[Y] & 0xff) - 0.3455 * ((YUVFrame[U] & 0xff) - 128) - 0.7169 * ((YUVFrame[V] & 0xff) - 128));
double b = ((YUVFrame[Y] & 0xff) + 1.779 * ((YUVFrame[U] & 0xff) - 128));
r = (r < 0 ? 0 : r > 255 ? 255 : r);
g = (g < 0 ? 0 : g > 255 ? 255 : g);
b = (b < 0 ? 0 : b > 255 ? 255 : b);
rgb[index + R] = (byte)r;
rgb[index + G] = (byte)g;
rgb[index + B] = (byte)b;
}
}
return CreateBitmap(rgb,width,height);
}
并从 RGB[] 创建一个 Bitmap
:
Bitmap CreateBitmap(byte[] RGBFrame,int height)
{
PixelFormat pxFormat = PixelFormat.Format24bppRgb;
Bitmap bmp = new Bitmap(width,height,pxFormat);
BitmapData bmpData = bmp.LockBits(new Rectangle(0,height),ImageLockMode.ReadWrite,pxFormat);
IntPtr pNative = bmpData.Scan0;
Marshal.Copy(RGBFrame,pNative,RGBFrame.Length);
bmp.UnlockBits(bmpData);
return bmp;
}
或 WPF 的 BitmapSource
:
BitmapSource FromArray(byte[] data,int w,int h,int ch)
{
System.Windows.Media.PixelFormat format = PixelFormats.Default;
if (ch == 1)
format = PixelFormats.Gray8; //grey scale image 0-255
if (ch == 3)
format = PixelFormats.Bgr24; //RGB
if (ch == 4)
format = PixelFormats.Bgr32; //RGB + alpha
WriteableBitmap wbm = new WriteableBitmap(w,h,96,format,null);
wbm.WritePixels(new Int32Rect(0,w,h),data,ch * w,0);
return wbm;
}