一文掌握 YUV 图像的基本处理

YUV为什么是YUV? YUV 视频 阅读详情
AI摘要

本文深入探讨YUV色彩编码模型的原理,包括其历史背景、采样方式、常见格式及在计算机系统中的应用。通过具体实例,讲解YUV图像的旋转、缩放和剪切操作,并提供代码实现。

该原创文章首发于微信公众号:字节流动

YUV 图片

YUV 的由来

YUV 是一种色彩编码模型,也叫做 YCbCr,其中 “Y” 表示明亮度(Luminance),“U” 和 “V” 分别表示色度(Chrominance)和浓度(Chroma)。

YUV 色彩编码模型,其设计初衷为了解决彩色电视机与黑白电视的兼容问题,利用了人类眼睛的生理特性(对亮度敏感,对色度不敏感),允许降低色度的带宽,降低了传输带宽。

在计算机系统中应用尤为广泛,利用 YUV 色彩编码模型可以降低图片数据的内存占用,提高数据处理效率。

另外,YUV 编码模型的图像数据一般不能直接用于显示,还需要将其转换为 RGB(RGBA) 编码模型,才能够正常显示图像。

YUV 几种常见采样方式

YUV 几种常见采样方式
YUV 图像主流的采样方式有三种:

  • YUV 4:4:4,每一个 Y 分量对于一对 UV 分量,每像素占用 (Y + U + V = 8 + 8 + 8 = 24bits)3 字节
  • YUV 4:2:2,每两个 Y 分量共用一对 UV 分量,每像素占用 (Y + 0.5U + 0.5V = 8 + 4 + 4 = 16bits)2 字节
  • YUV 4:2:0,每四个 Y 分量共用一对 UV 分量,每像素占用 (Y + 0.25U + 0.25V = 8 + 2 + 2 = 12bits)1.5 字节

其中最常用的采样方式是 YUV422 和 YUV420 。

YUV 格式也可按照 YUV 三个分量的组织方式分为打包(Packed)格式和平面格式(Planar)。

  • 打包(Packed)格式:每个像素点的 YUV 分量是连续交叉存储的,如 YUYV 格式;
  • 平面格式(Planar):YUV 图像数据的三个分量分别存放在不同的矩阵中,这种格式适用于采样,如 YV12、YU12 格式;

YUV 几种常用的格式

下面以一幅分辨率为 4x4 的 YUV 图为例,说明在不同 YUV 格式下的存储方式(括号内范围表示内存地址索引范围,默认以下不同格式图片存储使用的都是连续内存)。

YUYV (YUV422 采样方式)

YUYV 格式的存储格式

(0  ~  7)  Y00  U00  Y01  V00  Y02  U01   Y03  V01
(8  ~ 15)  Y10  U10  Y11  V10  Y12  U11   Y13  V11
(16 ~ 23)  Y20  U20  Y21  V20  Y22  U21   Y23  V21
(24 ~ 31)  Y30  U30  Y31  V30  Y32  U31   Y33  V31

一幅 720P (1280x720分辨率) 的图片,使用 YUV422 采样时占用存储大小为:

Y 分量:1280 * 720  = 921600 字节
U 分量:1280 * 720 * 0.5 = 460800 字节
V 分量:1280 * 720 * 0.5 = 460800 字节
总大小:Y 分量 + U 分量 + V 分量 = (1280 * 720 + 1280 * 720 * 0.5 * 2) / 1024 / 1024 = 1.76 MB 

由上面计算可以看出 YUV422 采样的图像比 RGB 模型图像节省了 1/3 的存储空间。,在传输时占用的带宽也会随之减小。

YV12/YU12 (YUV420 采样方式)

YV12/YU12 也属于 YUV420P ,即 YUV420 采样方式的平面模式,YUV 三个分量分别存储于 3 个不同的矩阵(平面)。

YUV420P 存储方式图

YV12 格式的存储方式

(0  ~  3) Y00  Y01  Y02  Y03  
(4  ~  7) Y10  Y11  Y12  Y13  
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 17) V00  V01
(18 ~ 19) V10  V11

(20 ~ 21) U00  U01
(22 ~ 23) U10  U11

YU12(也称 I420) 格式的存储方式

(0  ~  3) Y00  Y01  Y02  Y03
(4  ~  7) Y10  Y11  Y12  Y13
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 17) U00  U01
(18 ~ 19) U10  U11

(20 ~ 21) V00  V01
(22 ~ 23) V10  V11

一幅 720P (1280x720分辨率) 的图片,使用 YUV420 采样时(格式 YV12/YU12 )占用存储大小为:

Y 分量:1280 * 720  = 921600 字节
U 分量:1280 * 720 * (1/4) = 230400 字节
V 分量:1280 * 720 * (1/4) = 230400 字节
总大小:Y 分量 + U 分量 + V 分量 = (1280 * 720 + 1280 * 720 * (1/4)* 2) / 1024 / 1024 = 1.32 MB 

由上面计算可以看出 YUV420 采样(格式 YV12/YU12 )的图像比 RGB 模型图像节省了 1/2 的存储空间。

NV21/NV12 (YUV420 采样方式)

NV21/NV12 属于 YUV420SP ,YUV420SP 格式有 2 个平面,Y 分量存储于一个平面,UV 分量交错存储于另一个平面。

YUV420SP 存储方式图
NV21 格式的存储方式

(0  ~  3) Y00  Y01  Y02  Y03  
(4  ~  7) Y10  Y11  Y12  Y13  
(8  ~ 11) Y20  Y21  Y22  Y23  
(12 ~ 15) Y30  Y31  Y32  Y33  

(16 ~ 19) V00  U00  V01  U01 
(20 ~ 23) V10  U10  V11  U11

NV12 格式的存储方式

(0  ~  3) Y00  Y01  Y02  Y03
(4  ~  7) Y10  Y11  Y12  Y13
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 19) U00  V00  U01  V01 
(20 ~ 23) U10  V10  U11  V11

NV21 与 NV12 格式的区别仅在于 UV 分量排列的先后顺序不同。

一幅 720P (1280x720分辨率) 的图片,使用 YUV420 采样时(格式 NV21/NV12 )占用存储大小为:

Y 分量:1280 * 720  = 921600 字节
UV 分量:1280 * 720 * (1/2) = 460800 字节
总大小:Y 分量 + UV 分量 = (1280 * 720 + 1280 * 720 * (1/2)) / 1024 / 1024 = 1.32 MB 

由上面计算可以看出 YUV420 采样(格式 NV21/NV12 )的图像比 RGB 模型图像也节省了 1/2 的存储空间。

YUV 图像的基本操作

下面以最常用的 NV21 图为例介绍其旋转、缩放和剪切的基本方法。

YUV 图片的定义、加载、保存及内存释放。

//YUV420SP  NV21 or NV12 

typedef struct
{
	int width;                 // 图片宽
	int height;                // 图片高 
	unsigned char  *yPlane;    // Y 平面指针
	unsigned char  *uvPlane;   // UV 平面指针
} YUVImage;

void LoadYUVImage(const char *filePath, YUVImage *pImage)
{
	FILE *fpData = fopen(filePath, "rb+");
	if (fpData != NULL)
	{
		fseek(fpData, 0, SEEK_END);
		int len = ftell(fpData);
		pImage->yPlane = malloc(len);
		fseek(fpData, 0, SEEK_SET);
		fread(pImage->yPlane, 1, len, fpData);
		fclose(fpData);
		fpData = NULL;
	}
	pImage->uvPlane = pImage->yPlane + pImage->width * pImage->height;
}

void SaveYUVImage(const char *filePath, YUVImage *pImage)
{
	FILE *fp = fopen(filePath, "wb+");
	if (fp)
	{
		fwrite(pImage->yPlane, pImage->width * pImage->height, 1, fp);
		fwrite(pImage->uvPlane, pImage->width * (pImage->height >> 1), 1, fp);
	}
}

void ReleaseYUVImage(YUVImage *pImage)
{
	if (pImage->yPlane)
	{
		free(pImage->yPlane);
		pImage->yPlane = NULL;
		pImage->uvPlane = NULL;
	}
}

NV21 图片旋转

以顺时针旋转 90 度为例,Y 和 UV 两个平面分别从平面左下角进行纵向拷贝,需要注意的是每对 UV 分量作为一个整体进行拷贝。 以此类比,顺时针旋转 180 度时从平面右下角进行横向拷贝,顺时针旋转 270 度时从平面右上角进行纵向拷贝。

Y 平面旋转 90 度

UV 平面旋转 90 度


Y00  Y01  Y02  Y03              Y30  Y20  Y10  Y00
Y10  Y11  Y12  Y13    旋转90度   Y31  Y21  Y11  Y01
Y20  Y21  Y22  Y23    ----->    Y32  Y22  Y12  Y02
Y30  Y31  Y32  Y33              Y33  Y23  Y13  Y03

V00  U00  V01  U01    ----->    V10  U10  V00  U00
V10  U10  V11  U11              V11  U11  V01  U01

代码实现:

//angle 90,  270, 180
void RotateYUVImage(YUVImage *pSrcImg, YUVImage *pDstImg, int angle)
{
	int yIndex = 0;
	int uvIndex = 0;
	switch (angle)
	{
	case 90:
	{
		// y plane
		for (int i = 0; i < pSrcImg->width; i++) {
			for (int j = 0; j < pSrcImg->height; j++) {
				*(pDstImg->yPlane + yIndex) = *(pSrcImg->yPlane + (pSrcImg->height - j - 1) * pSrcImg->width + i);
				yIndex++;
			}
		}

		//uv plane
		for (int i = 0; i < pSrcImg->width; i += 2) {
			for (int j = 0; j < pSrcImg->height / 2; j++) {
				*(pDstImg->uvPlane + uvIndex) = *(pSrcImg->uvPlane + (pSrcImg->height / 2 - j - 1) * pSrcImg->width + i);
				*(pDstImg->uvPlane + uvIndex + 1) = *(pSrcImg->uvPlane + (pSrcImg->height / 2 - j - 1) * pSrcImg->width + i + 1);
				uvIndex += 2;
			}
		}
	}
	break;
	case 180:
	{
		// y plane
		for (int i = 0; i < pSrcImg->height; i++) {
			for (int j = 0; j < pSrcImg->width; j++) {
				*(pDstImg->yPlane + yIndex) = *(pSrcImg->yPlane + (pSrcImg->height - 1 - i) * pSrcImg->width + pSrcImg->width - 1 - j);
				yIndex++;
			}
		}

		//uv plane
		for (int i = 0; i < pSrcImg->height / 2; i++) {
			for (int j = 0; j < pSrcImg->width; j += 2) {
				*(pDstImg->uvPlane + uvIndex) = *(pSrcImg->uvPlane + (pSrcImg->height / 2 - 1 - i) * pSrcImg->width + pSrcImg->width - 2 - j);
				*(pDstImg->uvPlane + uvIndex + 1) = *(pSrcImg->uvPlane + (pSrcImg->height / 2 - 1 - i) * pSrcImg->width + pSrcImg->width - 1 - j);
				uvIndex += 2;
			}
		}
	}
	break;
	case 270:
	{
		// y plane
		for (int i = 0; i < pSrcImg->width; i++) {
			for (int j = 0; j < pSrcImg->height; j++) {
				*(pDstImg->yPlane + yIndex) = *(pSrcImg->yPlane + j * pSrcImg->width + (pSrcImg->width - i - 1));
				yIndex++;
			}
		}

		//uv plane
		for (int i = 0; i < pSrcImg->width; i += 2) {
			for (int j = 0; j < pSrcImg->height / 2; j++) {
				*(pDstImg->uvPlane + uvIndex + 1) = *(pSrcImg->uvPlane + j * pSrcImg->width + (pSrcImg->width - i - 1));
				*(pDstImg->uvPlane + uvIndex) = *(pSrcImg->uvPlane + j * pSrcImg->width + (pSrcImg->width - i - 2));
				uvIndex += 2;
			}
		}
	}
	break;
	default:
		break;
	}

}

NV21 图片缩放

将 2x2 的 NV21 图缩放成 4x4 的 NV21 图,原图横向每个像素的 Y 分量向右拷贝 1(放大倍数-1)次,纵向每列元素以列为单位向下拷贝 1(放大倍数-1)次.

将 2x2 的 NV21 图缩放成 4x4 的 NV21 图

将 4x4 的 NV21 图缩放成 2x2 的 NV21 图,实际上就是进行采样。

将 4x4 的 NV21 图缩放成 2x2 的 NV21 图

代码实现:

void ResizeYUVImage(YUVImage *pSrcImg, YUVImage *pDstImg)
{
	if (pSrcImg->width > pDstImg->width)
	{
		//缩小
		int x_scale = pSrcImg->width / pDstImg->width;
		int y_scale = pSrcImg->height / pDstImg->height;

		for (size_t i = 0; i < pDstImg->height; i++)
		{
			for (size_t j = 0; j < pDstImg->width; j++)
			{
				*(pDstImg->yPlane + i*pDstImg->width + j) = *(pSrcImg->yPlane + i * y_scale *pSrcImg->width + j * x_scale);
			}
		}

		for (size_t i = 0; i < pDstImg->height / 2; i++)
		{
			for (size_t j = 0; j < pDstImg->width; j += 2)
			{
				*(pDstImg->uvPlane + i*pDstImg->width + j) = *(pSrcImg->uvPlane + i * y_scale *pSrcImg->width + j * x_scale);
				*(pDstImg->uvPlane + i*pDstImg->width + j + 1) = *(pSrcImg->uvPlane + i * y_scale *pSrcImg->width + j * x_scale + 1);
			}
		}
	}
	else
	{
		// 放大
		int x_scale = pDstImg->width / pSrcImg->width;
		int y_scale = pDstImg->height / pSrcImg->height;

		for (size_t i = 0; i < pSrcImg->height; i++)
		{
			for (size_t j = 0; j < pSrcImg->width; j++)
			{
				int yValue = *(pSrcImg->yPlane + i *pSrcImg->width + j);
				for (size_t k = 0; k < x_scale; k++)
				{
					*(pDstImg->yPlane + i * y_scale * pDstImg->width + j  * x_scale + k) = yValue;
				}
			}

			unsigned char  *pSrcRow = pDstImg->yPlane + i * y_scale * pDstImg->width;
			unsigned char  *pDstRow = NULL;
			for (size_t l = 1; l < y_scale; l++)
			{
				pDstRow = (pDstImg->yPlane + (i * y_scale + l)* pDstImg->width);
				memcpy(pDstRow, pSrcRow, pDstImg->width * sizeof(unsigned char ));
			}
		}

		for (size_t i = 0; i < pSrcImg->height / 2; i++)
		{
			for (size_t j = 0; j < pSrcImg->width; j += 2)
			{
				int vValue = *(pSrcImg->uvPlane + i *pSrcImg->width + j);
				int uValue = *(pSrcImg->uvPlane + i *pSrcImg->width + j + 1);
				for (size_t k = 0; k < x_scale * 2; k += 2)
				{
					*(pDstImg->uvPlane + i * y_scale * pDstImg->width + j  * x_scale + k) = vValue;
					*(pDstImg->uvPlane + i * y_scale * pDstImg->width + j  * x_scale + k + 1) = uValue;
				}
			}

			unsigned char  *pSrcRow = pDstImg->uvPlane + i * y_scale * pDstImg->width;
			unsigned char  *pDstRow = NULL;
			for (size_t l = 1; l < y_scale; l++)
			{
				pDstRow = (pDstImg->uvPlane + (i * y_scale + l)* pDstImg->width);
				memcpy(pDstRow, pSrcRow, pDstImg->width * sizeof(unsigned char ));
			}
		}
	}
}

NV21 图片裁剪

图例中将 6x6 的 NV21 图按照横纵坐标偏移量为(2,2)裁剪成 4x4 的 NV21 图。

对 Y 平面裁剪

对 UV 平面裁剪

代码实现:

// x_offSet ,y_offSet % 2 == 0
void CropYUVImage(YUVImage *pSrcImg, int x_offSet, int y_offSet, YUVImage *pDstImg)
{
    // 确保裁剪区域不存在内存越界
	int cropWidth = pSrcImg->width - x_offSet;
	cropWidth = cropWidth > pDstImg->width ? pDstImg->width : cropWidth;
	int cropHeight = pSrcImg->height - y_offSet;
	cropHeight = cropHeight > pDstImg->height ? pDstImg->height : cropHeight;
	
	unsigned char  *pSrcCursor = NULL;
	unsigned char  *pDstCursor = NULL;

	//crop yPlane
	for (size_t i = 0; i < cropHeight; i++)
	{
		pSrcCursor = pSrcImg->yPlane + (y_offSet + i) * pSrcImg->width + x_offSet;
		pDstCursor = pDstImg->yPlane + i * pDstImg->width;
		memcpy(pDstCursor, pSrcCursor, sizeof(unsigned char ) * cropWidth);
	}

	//crop uvPlane
	for (size_t i = 0; i < cropHeight / 2; i++)
	{
		pSrcCursor = pSrcImg->uvPlane + (y_offSet / 2 + i) * pSrcImg->width + x_offSet;
		pDstCursor = pDstImg->uvPlane + i * pDstImg->width;
		memcpy(pDstCursor, pSrcCursor, sizeof(unsigned char ) * cropWidth);
	}

}

Sample 测试

原图

IMG_840x1074 原图(图片用于显示都已转成 PNG)

测试代码

void main()
{
	YUVImage srcImg = { 0 };
	srcImg.width = 840;
	srcImg.height = 1074;
	LoadYUVImage("IMG_840x1074.NV21", &srcImg);

	YUVImage rotateDstImg = { 0 };
	rotateDstImg.width = 1074;
	rotateDstImg.height = 840;
	rotateDstImg.yPlane = malloc(rotateDstImg.width * rotateDstImg.height*1.5);
	rotateDstImg.uvPlane = rotateDstImg.yPlane + rotateDstImg.width * rotateDstImg.height;

	RotateYUVImage(&srcImg, &rotateDstImg, 270);

	SaveYUVImage("D:\\material\\IMG_1074x840_270.NV21", &rotateDstImg);

	RotateYUVImage(&srcImg, &rotateDstImg, 90);

	SaveYUVImage("D:\\material\\IMG_1074x840_90.NV21", &rotateDstImg);

	rotateDstImg.width = 840;
	rotateDstImg.height = 1074;
	RotateYUVImage(&srcImg, &rotateDstImg, 180);

	SaveYUVImage("D:\\material\\IMG_840x1074_180.NV21", &rotateDstImg);


	YUVImage resizeDstImg = { 0 };
	resizeDstImg.width = 420;
	resizeDstImg.height = 536;
	resizeDstImg.yPlane = malloc(resizeDstImg.width * resizeDstImg.height*1.5);
	resizeDstImg.uvPlane = resizeDstImg.yPlane + resizeDstImg.width * resizeDstImg.height;

	ResizeYUVImage(&srcImg, &resizeDstImg);

	SaveYUVImage("D:\\material\\IMG_420x536_Resize.NV21", &resizeDstImg);

	YUVImage cropDstImg = { 0 };
	cropDstImg.width = 300;
	cropDstImg.height = 300;
	cropDstImg.yPlane = malloc(cropDstImg.width * cropDstImg.height*1.5);
	cropDstImg.uvPlane = cropDstImg.yPlane + cropDstImg.width * cropDstImg.height;

	CropYUVImage(&srcImg, 100, 500, &cropDstImg);

	SaveYUVImage("D:\\material\\IMG_300x300_crop.NV21", &cropDstImg);

	ReleaseYUVImage(&srcImg);
	ReleaseYUVImage(&rotateDstImg);
	ReleaseYUVImage(&resizeDstImg);
	ReleaseYUVImage(&cropDstImg);
}

测试结果

IMG_1074x840_270(旋转270度)

IMG_1074x840_90(旋转90度)

IMG_840x1074_180(旋转180度)

IMG_420x536_Resize(缩放)

IMG_300x300_Crop(裁剪)

联系与交流

技术交流可以添加我的微信:Byte-Flow
我的公众号

参考

https://blog.youkuaiyun.com/leixiaohua1020/article/details/50534150
https://cloud.tencent.com/developer/article/1442041

YUV域图像处理 YUV 域的处理流程大致是先将RGB颜色模式的图像转为YUV格式,再在YUV域对图像进行颜色降噪,图像锐化,色彩矫正等操作,再进行多帧合成,来提高图像的宽容度或者降低噪点。 色彩空间转化:在Android中,yuv采用yuv420的编码格式,因此还需要对yuv数据进行二次采样,尽量保留亮度信息而舍弃部分的颜色信息。它指的是对每行扫描线来说,只有一种色度分量以2:1 的抽样率存储。 一、HDR:色调映射(ToneMapping) 定义:色调映射算法,是指对图像颜色进行变换的算法。其目的在于调整.. 阅读详情

相关推荐

图像处理基础(像素、RGB、YUV )

YUV与像素的关系: YUV是利用一个亮度(Y)、两个色差(U,V)来代替传统的RGB三原色来压缩图像。传统的RGB三原色使用红绿蓝三原色表示一个像素,每种原色占用一个字节(8bit),因此一个像素用RGB表示则需要8*3=24bit。 如果使用YUV表示这个像素,假设YUV的采样率为:4:2:0,即每一个像素对于亮度Y的采样频率为1,对于色差U和V,则是每相邻的两个像素各取一个U和V。对于单个的像素来说,色差U和V的采样频率为亮度的一半。(解析不清楚,看下面图解) 如有三个相邻的像素,如果用RGB三原色表

u014583317的博客 3767

YUV图像格式详解

相对于常见且直观的RGB颜色编码,YUV的产生自有其意义,它基于人眼对亮度比色彩的敏感度更高的特点,使用Y、U、V三个分量来表示颜色,并通过降低U、V分量的采样率,尽可能保证图像质量的情况下,做到如下3点: 占用更低的存储空间 数据传输效率更高 兼容黑白与彩色显示 具体是怎么做到的,本博文一一讲解

肖云鹤的博客 1万+

OpenGL之深入解析YUV图像的基本处理

YUV 色彩编码模型,其设计初衷为了解决彩色电视机与黑白电视的兼容问题,利用了人类眼睛的生理特性(对亮度敏感,对色度不敏感),允许降低色度的带宽,降低了传输带宽。在计算机系统中应用尤为广泛,利用 YUV 色彩编码模型可以降低图片数据的内存占用,提高数据处理效率。另外,YUV 编码模型的图像数据一般不能直接用于显示,还需要将其转换为 RGB(RGBA) 编码模型,才能够正常显示图像。.......................................

╰つ栺尖篴夢ゞ 979

详解 YUV,一文搞定 YUV 是什么!

YUV 是一个颜色模型,通常用作彩色图像管道的一部分。它对彩色图像或视频进行编码时考虑到了人类的感知,与“直接”的 RGB 表示相比,允许减少色度分量的带宽。

洪伟的专栏 2万+

YUV_Viewer:YUV图像数据查看工具介绍

本文还有配套的精品资源,点击获取 简介:YUV色彩空间在图像处理和视频编码领域中扮演关键角色。YUV_Viewer是专为查看yuv422和420这两种格式设计的工具,它帮助用户直观展示YUV格式的图像数据。工具提供文件导入、图像展示、色彩空间转换、参数调整、缩放滚动以及快捷操作等功能,便于开发者和研究人员在视频处理算法调试和图像质量检查中使用。软件可能还包含了YUV到其他色...

weixin_29041443的博客 4345

YUVViewer - 专业YUV图像查看与处理工具

色彩空间是图像处理领域中的核心概念,YUV作为其中的一种,尤其在数字视频和图像处理领域具有举足轻重的地位。本章将介绍YUV色彩空间的基础知识,并解释其在现代技术中的重要性。YUV色彩空间由三个分量组成:亮度(Y)和两个色度分量(U和V)。其中,Y代表亮度信息,而U和V则携带色度信息,U代表蓝色和亮度差值,V代表红色和亮度差值。YUV色彩空间的设计允许将亮度信息和色度信息分离,这对于视频压缩非常有用,因为人眼对亮度的敏感度高于色度。

weixin_42590539的博客 1800

YUV数据和格式

YUV是一种颜色编码方法, 与RGB(红 - 绿 - 蓝)不同。Y表示亮度分量,也叫灰阶值:如果只显示Y,图片会是一张黑白照U(Cb)表示色度分量:是照片蓝色部分去掉亮度V(Cr)表示色度分量:是照片红色部分去掉亮度。

俗科技的博客 5021

UE5 Decal混合进阶:如何用DBuffer实现自定义Normal插值(附完整材质配置流程)

本文深入解析了UE5中利用DBuffer技术实现Decal自定义Normal插值的完整流程。通过详细的材质配置步骤和核心算法说明,帮助开发者突破传统混合模式限制,掌握高级法线控制技巧,特别适合需要精细环境细节的3A级项目开发。

table的专栏 224

YUV原理和格式详解

YUV是指亮度参数和色度参量分开表示的像素格式,其中“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V”表示的则是色度(Chrominance或Chrima),作用是描述色彩及饱和度,用于指定像素的颜色。Y:亮度分量,表示物理线性空间亮度。U:蓝色投影。V:红色投影。YUV同RGB 类似,也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它讲亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样能够显示完整的图像,只不过是黑白色的。

LiggerBill的博客 1万+

PX4开发环境搭建(Ubuntu1804+QGC+Qt Creator )

文章目录前言一、安装环境二、PX4环境搭建1. 在虚拟机中安装Ubuntu2. 安装PX4环境(1)下载PX4源码:(2) 安装工具链(3) jMAVSim仿真(4) 编译验证三、安装QGC四、安装Qt Creator 前言 在这之前作者完全没接触过PX4,安装过程遇到了很多坑,而且每安装下载一个东西都要等好久,出现问题又要重新开始,前后折腾了四天才弄好,希望此文对大家有所帮助。 一、安装环境 ...

Beyonderwei的博客 9023

将Apollo高精地图中的车道线叠加在多种导航地图上

本文介绍了将Apollo高精地图车道线叠加到普通导航地图的技术方案。高精地图具备厘米级车道精度和丰富的语义信息,叠加可实现可视化验证、调试分析和数据对比等功能。核心技术包括坐标系统转换(UTM/WGS84/BD09/GCJ02)和数据处理流程,通过Python脚本完成Apollo地图解析、坐标批量转换和多格式输出。文章详细提供了环境准备、工作目录创建和坐标转换脚本等操作步骤,实现了高精地图数据在OpenStreetMap、百度地图和高德地图上的可视化展示。

Hi20240217的博客 1333

yuv格式转换是那个组织定义的_一文掌握 YUV 图像的基本处理

YUV图1.YUV 的由来YUV 是一种色彩编码模型,也叫做 YCbCr,其中 “Y” 表示明亮度(Luminance),“U” 和 “V” 分别表示色度(Chrominance)和浓度(Chroma)。YUV 色彩编码模型,其设计初衷为了解决彩色电视机与黑白电视的兼容问题,利用了人类眼睛的生理特性(对亮度敏感,对色度不敏感),允许降低色度的带宽,降低了传输带宽。在计算机系统中应用尤...

weixin_30280259的博客 200

用STM32F103C8T6和TB6612驱动模块,从零搭建一辆能避障循迹的智能小车(附完整代码)

本文详细介绍了如何使用STM32F103C8T6和TB6612驱动模块从零搭建一辆能避障循迹的智能小车。内容涵盖硬件选型、电路设计、底层驱动配置以及智能行为算法实现,并附有完整代码示例,帮助开发者快速掌握嵌入式开发的核心技术。

weixin_42641741的博客 446

图像处理YUV的详解

文章目录1. 前言2. Y'CbCr详解3. Y'CbCr的编解码3.1 YUV采样3.2 RGB转YUV3.3 YUV转RGB3.4 YUV常见格式3.5 YUV的存储格式3.5.1 planar(平面)3.5.2 packed(打包)4. YUV实战5. 参考文档 1. 前言   端午节在慕课网看了李超老师的课程关于YUV的讲解,这里把所学的内容,加上自己的理解进行了整理加工,在这里做个分享。   图像有两种表达方式:RGB和YUV,RGB比较简单,这里不做赘述,今天重点讲YUV,那么既然有了RGB,为

美好心境 5782

1. 在 SAP ABAP 事物码 SEGW 里创建 SAP OData 项目

本文介绍如何在 SAP ABAP 事物码 SEGW 里创建 SEGW 项目,使用工具生成 Runtime 运行时需要的资源。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5443

主流反爬虫、反作弊防护与风控对抗手段

主流反爬虫、反作弊风控防护中的核心设计点与对抗策略

吴秋霖的博客 2555

掌握 YUV 图像的基本处理

YUV 是一种色彩编码模型,也叫做 YCbCr,其中 “Y” 表示明亮度(Luminance),“U” 和 “V” 分别表示色度(Chrominance)和浓度(Chroma)。在计算机系统中应用尤为广泛。

金戈鐡馬 1076

《Python Web项目集锦》-专栏介绍和目录

本专栏专注于Python Web项目,涉及内容包含FastAPI、Django、Flask等,所有项目代码完整且可直接运行。不管是零基础还是有经验的开发,相信都能从本专栏获益。有任何问题欢迎私聊博主,专栏持续更新中...

数据知道的博客 5213

YUV图像格式学习与灰度处理

YUV图像格式学习与灰度处理 前言 刚入职不久,导师要我完成一个任务,就是将将彩色YUV图像数据处理成黑白色,由于对YUV并不了解,所以才有了下面的学习。 YUV概述 YUV与RGB一样,都是像素数据的编码格式,一组YUV渲染屏幕上的一个像素,控制屏幕用色彩的形式将事物表现出来,其中Y表示像素中的亮度,U表示色度,V表示浓度或饱和度。它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白色。这是一种压缩后的颜色表示方法,占用更少的物理空间,且对颜色的表现失真不明显,

qq_24003917的博客 9236

4、Vitis_HLS、Vivado 和 Vitis IDE 工具的设置与使用

本文详细介绍了使用Vitis_HLS、Vivado和Vitis IDE进行FPGA开发的完整流程,涵盖开发板选择、软件安装、IP设计与模拟、综合、导出以及在FPGA上的实现与验证。以Xilinx Artix-7和Zynq系列开发板为例,指导用户从环境搭建到最终硬件验证,完成一个32位加法器IP的开发,适用于嵌入式系统和硬件加速项目的学习与实践。

fff88的博客 181

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【数字图像处理】数字图像处理:YUV与RGB的一些理解

引言 正常做算法,我们一般接触到的数据来源都是RGB,如果用深度摄像机的话,数据格式都是RGBD,但是在视频采集卡中,视频采集芯片输出的码流一般都是YUV格式数据。而且,LZ最近因为项目原因,获取的数据格式已经不是熟悉的rgb类型了,所以还是需要进行对应的理解和整理的。 RGB 相信做图像处理的小伙伴们对RGB格式的图像数据都不陌生,R、G、B是什么意思呢?在实际获取的数字图像中,图像是以像素的形...

Felaim的博客 3515

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

关于YUV视频的读取、播放,保存帧图片、以及处理的图像保存为YUV视频。

声明:原创博文,禁止转载。否则将追究法律责任!http://blog.youkuaiyun.com/sdlyjzh/article/details/8246752 要对YUV视频进行处理,首先要将视频保存为一帧帧的图片,对图片进行处理,也就是要读取YUV视频的数据。 下面结合代码,总结一下这两天掌握的内容。下面代码的功能,就是读取YUV视频指定帧的Y、U、V分量的值。通过这篇文章,会加深大家对YUV视频如

sdlyjzh的专栏 2万+

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

学习记录:各种YUV图像上画线的实现

几种常用YUV格式图像内存分布 (以 4x2 共8个像素为例): (1)YUV444I (interleaved) 每个Y分量都有一个UV分量 YUV YUV YUV YUV YUV YUV YUV YUV (2)YUV444P (planar) 每个Y分量都有一个UV分量 ...

fanchenxinok的专栏 5065

【图像格式专题】YUV图像格式说明

我们知道,对于RGB和YUV的色彩空间来说,有个位深(bit-depth)的概念;位深是指记录图像每个像素的色彩通道时所使用的bit数,常见的RGB888,YUV420-8bit。以RGB888为例,其代表R G B三个通道的取值范围为[0,255],这个范围也叫做灰阶。比如(255,255,255)代表白色,(255,0,0 )代表红色。0~255总共256个灰阶值。而Full Range的灰阶值范围即为[0, 255]。而在RGB色彩空间中Limit Range为[16, 235];

浩瀚之水的专栏 3648
上一篇: Android GLSurfaceView 透明
下一篇: OpenGL ES 3.0 开发(一):绘制一个三角形
字节流动
字节流动 优质创作者: 编程框架技术领域 优质创作者: 编程框架技术领域 领域专家: 嵌入式与硬件开发技术领域 领域专家: 嵌入式与硬件开发技术领域
博客等级 码龄11年 1912粉丝 168原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

字节流动

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值