#region ******************彩色图像记录的格式,YUV 转 RGB******************
/* YUV, http://zh.wikipedia.org/wiki/YUV#.E5.B8.B8.E7.94.A8.E7.9A.84YUV.E6.A0.BC.E5.BC.8F
* 作为视频媒体类型的辅助说明类型(Subtype),它们对应的GUID如下:
* 在DirectShow中,常见的RGB和YUV格式
GUID 格式描述
MEDIASUBTYPE_RGB1 2色,每个像素用1位表示,需要调色板
MEDIASUBTYPE_RGB4 16色,每个像素用4位表示,需要调色板
MEDIASUBTYPE_RGB8 256色,每个像素用8位表示,需要调色板
MEDIASUBTYPE_RGB565 每个像素用16位表示,RGB分量分别使用5位、6位、5位
MEDIASUBTYPE_RGB555 每个像素用16位表示,RGB分量都使用5位(剩下的1位不用)
MEDIASUBTYPE_RGB24 每个像素用24位表示,RGB分量各使用8位
MEDIASUBTYPE_RGB32 每个像素用32位表示,RGB分量各使用8位(剩下的8位不用)
MEDIASUBTYPE_ARGB32 每个像素用32位表示,RGB分量各使用8位(剩下的8位用于表示Alpha通道值)
*
MEDIASUBTYPE_YUY2 YUY2格式,以4:2:2方式打包
MEDIASUBTYPE_YUYV YUYV格式(实际格式与YUY2相同)
MEDIASUBTYPE_YVYU YVYU格式,以4:2:2方式打包
MEDIASUBTYPE_UYVY UYVY格式,以4:2:2方式打包
MEDIASUBTYPE_AYUV 带Alpha通道的4:4:4 YUV格式
MEDIASUBTYPE_Y41P Y41P格式,以4:1:1方式打包
MEDIASUBTYPE_Y411 Y411格式(实际格式与Y41P相同)
MEDIASUBTYPE_Y211 Y211格式
MEDIASUBTYPE_IF09 IF09格式
MEDIASUBTYPE_IYUV IYUV格式
MEDIASUBTYPE_YV12 YV12格式
MEDIASUBTYPE_YVU9 YVU9格式
*/
#region RGB TO RGB32
/* RGB32 */
/// <summary>
/// 根据指针地址及内存块长度,获取RGB32数组
/// @20140516
/// </summary>
/// <param name="pBuffer"></param>
/// <param name="lBufferSize"></param>
/// <param name="lPicWidth"></param>
/// <param name="lPicHeight"></param>
/// <returns></returns>
public static byte[] GetRgb32_FromIntptr(IntPtr pBuffer, Int32 lBufferSize, Int32 lPicWidth, Int32 lPicHeight)
{
// 设置数组大小
byte[] rgba32 = new byte[lPicHeight * lPicWidth * 4];
Marshal.Copy(pBuffer, rgba32, 0, lBufferSize);
return rgba32;
}
#endregion
#region YUV TO RGB32
/// <summary>
/// YUV 转 RGB32
/// </summary>
/// <param name="pYPlaneByte"></param>
/// <param name="pVPlaneByte"></param>
/// <param name="pUPlaneByte"></param>
/// <param name="lPicHeight"></param>
/// <param name="lPicWidth"></param>
/// <param name="bError">是否存在错误</param>
/// <param name="strErrorDesc">错误消息</param>
/// <returns></returns>
public static byte[] GetRgb32_From_Yuv(byte[] pYPlaneByte, byte[] pUPlaneByte, byte[] pVPlaneByte, Int32 lPicHeight, Int32 lPicWidth, ref bool bError, ref string strErrorDesc)
{
bError = true;
strErrorDesc = "无错误";
int picSize = lPicWidth * lPicHeight;
byte[] pRrgaByte = new byte[picSize * 4];
int A = 0;
try
{
for (int iRow = 0; iRow < lPicHeight; iRow++)
{
for (int jCol = 0; jCol < lPicWidth; jCol++)
{
//int Y = pYPlane[i * dwWidth + j];
//int U = pUPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
//int V = pVPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
//int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
//int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
//int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
//R = max(0, min(255, R));
//G = max(0, min(255, G));
//B = max(0, min(255, B));
int Y = pYPlaneByte[iRow * lPicWidth + jCol];
int U = pUPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
int V = pVPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
/* 存在颜色转换错误问题。现象:公交车编号的LED灯显示颜色,与实际不符。如K30,图片上的30颜色为蓝色,但实际上30是红色 */
/* 1、宣传横幅,红色变成蓝色 */
/* 2、公交编号LED,红色变成蓝色 */
/* 3、信号灯LED,红色变成蓝色 */
//int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
//int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
//int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
// http://zh.wikipedia.org/wiki/YUV#YV12
//Int32 R = Y + 1.13983 * (V - 128);
//Int32 G = Y - 0.39456 * (U - 128) - 0.58060 * (V - 128);
//Int32 B = Y + 2.03211 * (U - 128);
/* 2012.12.24,纠正颜色错位问题R与B */
int R = Y + (V - 128) + (((V - 128) * 103) >> 8);
int G = Y - (((U - 128) * 88) >> 8) - (((V - 128) * 183) >> 8);
int B = Y + (U - 128) + (((U - 128) * 198) >> 8);
R = Math.Max(0, Math.Min(255, R));
G = Math.Max(0, Math.Min(255, G));
B = Math.Max(0, Math.Min(255, B));
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(B);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(R);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(R);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(B);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
}
}
return pRrgaByte;
}
catch (Exception exp)
{
pRrgaByte = null;
bError = false;
strErrorDesc = exp.ToString();
//throw;
}
return null;
}
/* YUV420 / I420
* 存储格式:yuv yuv yuv
*/
/* YUV420P:
* 存储格式:yyyyyyyy uuuuuuuu vvvvv
* yuv420p 和 YUV420的区别 在存储格式上有区别
yuv420p:yyyyyyyy uuuuuuuu vvvvv
yuv420: yuv yuv yuv
*/
/// <summary>
/// GetRgb32_From_Yuv420
/// @20140521,内存排列顺序有疑问
/// </summary>
/// <param name="pYuvPackedByte"></param>
/// <param name="lBuffSize"></param>
/// <param name="lPicHeight"></param>
/// <param name="lPicWidth"></param>
/// <param name="bError"></param>
/// <param name="strErrorDesc"></param>
/// <returns></returns>
public static byte[] GetRgb32_From_Yuv420(byte[] pYuvPackedByte, Int32 lBuffSize, Int32 lPicHeight, Int32 lPicWidth, ref bool bError, ref string strErrorDesc)
{
bError = true;
int picSize = lPicWidth * lPicHeight;
strErrorDesc = string.Format("无错误.picSize4 = '{0}', lBuffSize1.5 = '{1}'", picSize * 4, lBuffSize * 3 / 2);
byte[] pRrgaByte = new byte[picSize * 4];
int A = 0;
try
{
for (int iRow = 0; iRow < lPicHeight; iRow++)
{
for (int jCol = 0; jCol < lPicWidth; jCol++)
{
int Y = pYuvPackedByte[iRow * lPicWidth + jCol + 0];
int U = pYuvPackedByte[iRow * lPicWidth + jCol + 1];
int V = pYuvPackedByte[iRow * lPicWidth + jCol + 2];
// http://zh.wikipedia.org/wiki/YUV#YV12
//Int32 R = Y + 1.13983 * (V - 128);
//Int32 G = Y - 0.39456 * (U - 128) - 0.58060 * (V - 128);
//Int32 B = Y + 2.03211 * (U - 128);
/* 2012.12.24,纠正颜色错位问题R与B */
int R = Y + (V - 128) + (((V - 128) * 103) >> 8);
int G = Y - (((U - 128) * 88) >> 8) - (((V - 128) * 183) >> 8);
int B = Y + (U - 128) + (((U - 128) * 198) >> 8);
R = Math.Max(0, Math.Min(255, R));
G = Math.Max(0, Math.Min(255, G));
B = Math.Max(0, Math.Min(255, B));
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(B);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(R);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(R);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(B);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
}
}
return pRrgaByte;
}
catch (Exception exp)
{
pRrgaByte = null;
bError = false;
strErrorDesc = exp.ToString();
//throw;
}
return null;
}
/* UYVY / YVYU */
/// <summary>
///
/// </summary>
/// <param name="pYuvPackedByte"></param>
/// <param name="lBuffSize"></param>
/// <param name="lPicHeight"></param>
/// <param name="lPicWidth"></param>
/// <param name="bError"></param>
/// <param name="strErrorDesc"></param>
/// <returns></returns>
public static byte[] GetRgb32_From_Uyvy(byte[] pYuvPackedByte, Int32 lBuffSize, Int32 lPicHeight, Int32 lPicWidth, ref bool bError, ref string strErrorDesc)
{
bError = true;
int picSize = lPicWidth * lPicHeight;
strErrorDesc = string.Format("无错误.picSize4 = '{0}', lBuffSize2 = '{1}'", picSize * 4, lBuffSize * 2);
byte[] pRrgaByte = new byte[picSize * 4];
//int A = 0;
byte[] pYPlaneByte;
byte[] pUPlaneByte;
byte[] pVPlaneByte;
try
{
// 使用每行跨距
pYPlaneByte = new byte[lPicHeight * lPicWidth];
pUPlaneByte = new byte[(lPicHeight) * (lPicWidth / 2)];
pVPlaneByte = new byte[(lPicHeight) * (lPicWidth / 2)];
for (int idxSrc = 0, idxDest = 0; idxSrc < lBuffSize; )
{
pUPlaneByte[idxDest * 2] = pYuvPackedByte[idxSrc + 0];
pYPlaneByte[idxDest] = pYuvPackedByte[idxSrc + 1];
pVPlaneByte[idxDest * 2 + 1] = pYuvPackedByte[idxSrc + 2];
pYPlaneByte[idxDest] = pYuvPackedByte[idxSrc + 3];
idxSrc = idxSrc + 4;
idxDest++;
}
pRrgaByte = GetRgb32_From_Yuv(pYPlaneByte, pUPlaneByte, pVPlaneByte, lPicHeight, lPicWidth, ref bError, ref strErrorDesc);
pYPlaneByte = null;
pUPlaneByte = null;
pVPlaneByte = null;
return pRrgaByte;
}
catch (Exception exp)
{
pYPlaneByte = null;
pUPlaneByte = null;
pVPlaneByte = null;
pRrgaByte = null;
bError = false;
strErrorDesc = exp.ToString();
//throw;
}
return null;
}
/* YV12 / I420
*
* YV12格式与IYUV类似,每个像素都提取Y,在UV提取时,将图像2 x 2的矩阵,每个矩阵提取一个U和一个V。
*
* YV12格式和I420格式的不同处在V平面和U平面的位置不同。在YV12格式中,V平面紧跟在Y平面之后,然后才是U平面(即:YVU);但I420则是相反(即:YUV)。
*
* NV12与YV12类似,效果一样,YV12中U和V是连续排列的,而在NV12中,U和V就交错排列的。
*/
/// <summary>
/// YV12 转 RGB32
/// @在YV12格式中,V平面紧跟在Y平面之后,然后才是U平面(即:YVU);但I420则是相反(即:YUV)
/// </summary>
/// <param name="pYPlaneByte"></param>
/// <param name="pVPlaneByte"></param>
/// <param name="pUPlaneByte"></param>
/// <param name="lPicHeight"></param>
/// <param name="lPicWidth"></param>
/// <returns></returns>
public static byte[] GetRgb32_From_Yv12(byte[] pYPlaneByte, byte[] pUPlaneByte, byte[] pVPlaneByte, Int32 lPicHeight, Int32 lPicWidth)
{
int picSize = lPicWidth * lPicHeight;
byte[] pRrgaByte = new byte[picSize * 4];
int A = 0;
try
{
for (int iRow = 0; iRow < lPicHeight; iRow++)
{
for (int jCol = 0; jCol < lPicWidth; jCol++)
{
//int Y = pYPlane[i * dwWidth + j];
//int U = pUPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
//int V = pVPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
//int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
//int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
//int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
//R = max(0, min(255, R));
//G = max(0, min(255, G));
//B = max(0, min(255, B));
int Y = pYPlaneByte[iRow * lPicWidth + jCol];
int U = pUPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
int V = pVPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
/* 存在颜色转换错误问题。现象:公交车编号的LED灯显示颜色,与实际不符。如K30,图片上的30颜色为蓝色,但实际上30是红色 */
/* 1、宣传横幅,红色变成蓝色 */
/* 2、公交编号LED,红色变成蓝色 */
/* 3、信号灯LED,红色变成蓝色 */
//int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
//int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
//int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
/* 2012.12.24,纠正颜色错位问题R与B */
int R = Y + (V - 128) + (((V - 128) * 103) >> 8);
int G = Y - (((U - 128) * 88) >> 8) - (((V - 128) * 183) >> 8);
int B = Y + (U - 128) + (((U - 128) * 198) >> 8);
R = Math.Max(0, Math.Min(255, R));
G = Math.Max(0, Math.Min(255, G));
B = Math.Max(0, Math.Min(255, B));
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(B);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(R);
pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(R);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(B);
//pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
}
}
return pRrgaByte;
}
catch (Exception exp)
{
pRrgaByte = null;
//throw;
}
return null;
}
///// <summary>
///// YV12 转 RGB32(GetRgb32_From_Yv12_20130417,纠正R与B的转换错误)
///// </summary>
///// <param name="pYPlaneByte"></param>
///// <param name="pUPlaneByte"></param>
///// <param name="pVPlaneByte"></param>
///// <param name="lPicHeight"></param>
///// <param name="lPicWidth"></param>
///// <returns></returns>
//public static byte[] GetRgb32_From_Yv12_20130417(byte[] pYPlaneByte, byte[] pUPlaneByte, byte[] pVPlaneByte, Int32 lPicHeight, Int32 lPicWidth)
//{
// try
// {
// int picSize = lPicWidth * lPicHeight;
// byte[] pRrgaByte = new byte[picSize * 4];
// int A = 0;
// for (int iRow = 0; iRow < lPicHeight; iRow++)
// {
// for (int jCol = 0; jCol < lPicWidth; jCol++)
// {
// //int Y = pYPlane[i * dwWidth + j];
// //int U = pUPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
// //int V = pVPlane[(i / 2) * (dwWidth / 2) + (j / 2)];
// //int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
// //int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
// //int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
// //R = max(0, min(255, R));
// //G = max(0, min(255, G));
// //B = max(0, min(255, B));
// int Y = pYPlaneByte[iRow * lPicWidth + jCol];
// int U = pUPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
// int V = pVPlaneByte[(iRow / 2) * (lPicWidth / 2) + (jCol / 2)];
// /* 存在颜色转换错误问题。现象:公交车编号的LED灯显示颜色,与实际不符。如K30,图片上的30颜色为蓝色,但实际上30是红色 */
// //int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
// //int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
// //int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
// /* 2012.12.24,纠正颜色错位问题R与B */
// int R = Y + (V - 128) + (((V - 128) * 103) >> 8);
// int G = Y - (((U - 128) * 88) >> 8) - (((V - 128) * 183) >> 8);
// int B = Y + (U - 128) + (((U - 128) * 198) >> 8);
// R = Math.Max(0, Math.Min(255, R));
// G = Math.Max(0, Math.Min(255, G));
// B = Math.Max(0, Math.Min(255, B));
// pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(B);
// pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
// pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(R);
// pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
// //pRrgaByte[4 * (iRow * lPicWidth + jCol) + 0] = Convert.ToByte(R);
// //pRrgaByte[4 * (iRow * lPicWidth + jCol) + 1] = Convert.ToByte(G);
// //pRrgaByte[4 * (iRow * lPicWidth + jCol) + 2] = Convert.ToByte(B);
// //pRrgaByte[4 * (iRow * lPicWidth + jCol) + 3] = Convert.ToByte(A);
// }
// }
// return pRrgaByte;
// }
// catch (Exception exp)
// {
// //throw;
// }
// return null;
//}
static double[,] YUV2RGB_CONVERT_MATRIX = new double[3, 3] { { 1, 0, 1.4022 }, { 1, -0.3456, -0.7145 }, { 1, 1.771, 0 } };
/// <summary>
/// YUV420 转 RGB 参考地址http://www.haogongju.net/art/953565
/// </summary>
/// <param name="yuvFrame">yuv数据</param>
/// <param name="width">图片宽</param>
/// <param name="height">图片高</param>
/// <returns></returns>
public static byte[] ConvertYUV420RGB(byte[] yuvFrame, int width, int height)
{
int gIndex = width * height;
int uIndex = width * height;
int vIndex = uIndex + ((width * height) >> 2);
byte[] rgbFrame = new byte[gIndex * 3];
int bIndex = gIndex * 2;
int temp = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// R分量
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));
//rgbFrame[bIndex + y * width + x] = Math.Max(0, Math.Min(255, temp));
}
}
return rgbFrame;
}
public static byte[] ConvertYUV420RGB(byte[] pYPlaneByte, byte[] pUPlaneByte, byte[] pVPlaneByte, Int32 lPicHeight, Int32 lPicWidth)
{
return null;
}
#endregion
#endregion
YUV转RGB汇总
猜你喜欢
转载自blog.csdn.net/mt122/article/details/38459963
今日推荐
周排行