欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

YUV视频美颜处理

程序员文章站 2024-01-16 20:58:40
...

 

方式一 YUV美颜算法

1)对y值进行平衡处理

int temp_size = width*height;
colorbalance_yuv_u8((unsigned char*)data, temp_size,(size_t)(temp_size * 2 / 100), (size_t)(temp_size * 8 / 100));


/////////////////////////////////////////////////////////////////////////

	unsigned char *colorbalance_yuv_u8(unsigned char *yuv, size_t size, size_t nb_min, size_t nb_max)
	{
		(void)balance_u8(yuv, size, nb_min, nb_max,0,1); //对y值取平衡,对亮度进行调整
		return yuv;
	}


	unsigned char *balance_u8(unsigned char *data, size_t size,
		size_t nb_min, size_t nb_max,size_t offset,size_t step)
	{
		unsigned char min, max;

		/* sanity checks */
		if (NULL == data) {
			fprintf(stderr, "a pointer is NULL and should not be so\n");
			abort();
		}
		if (nb_min + nb_max >= size) {
			nb_min = (size - 1) / 2;
			nb_max = (size - 1) / 2;
			fprintf(stderr, "the number of pixels to flatten is too large\n");
			fprintf(stderr, "using (size - 1) / 2\n");
		}

		/* get the min/max */
		if (0 != nb_min || 0 != nb_max)
			quantiles_u8(data, size, nb_min, nb_max, &min, &max,offset,step);
		else
			minmax_u8(data, size, &min, &max, offset, step);

		/* rescale 
		*/
		(void)rescale_u8(data, size, min, max, offset, step);

		return data;
	}

 

2)采用均方差滤波进行磨皮

smooth_process((uint8_t*)data, width, height, 5, 0, 200);

//////////////////////////////////////////////////////////

	void smooth_process(uint8_t *i420, uint32_t width, uint32_t height, int sigema_level, int radius, uint8_t alpha)
	{
	
		smooth_info_t *info = smooth_init(i420, width, height);
		smooth_processing(info, i420, sigema_level*sigema_level * 5 + 10, radius, alpha);
		smooth_clear(&info);
	}

 

 

 

方式二      转成ARGB进行美颜后再转回来

将YUV转成ARGB,然后进行美颜,美颜后,在转成YUV

1) YUVToARGB

int I420ToARGB(const uint8* src_y, int src_stride_y,
               const uint8* src_u, int src_stride_u,
               const uint8* src_v, int src_stride_v,
               uint8* dst_argb, int dst_stride_argb,
               int width, int height);
YUV420ToARGB(char* src, char* dst, int width, int height)
	{
		uint8_t* src_y = (uint8_t*)src;
		uint8_t* src_u = src_y + width * height;
		uint8_t* src_v = src_u + width * height / 4;
		
// 		libyuv::I420ToRGB24(
// 			src_y, width,
// 			src_u, width / 2,
// 			src_v, width / 2,
// 			(uint8_t*)dst, width * 3,
// 			width, height);
		libyuv::I420ToARGB(
			src_y, width,
			src_u, width / 2,
			src_v, width / 2,
			(uint8_t*)dst, width * 4,
			width, height);
	}

 

  示例: ARGB 一个像素占四个字节

 			std::string beauty_src_data;
 			beauty_src_data.resize(width*height * 4);
 			YUV420ToARGB((char*)data, (char*)beauty_src_data.c_str(), width, height);

 

2 色彩平衡算法美白

	/**
	* @brief simplest color balance on RGB channels
	*
	* The input image is normalized by affine transformation on each RGB
	* channel, saturating a percentage of the pixels at the beginning and
	* end of the color space on each channel.
	*/
	unsigned char *colorbalance_rgb_u8(unsigned char *rgb, size_t size,
		size_t nb_min, size_t nb_max,size_t step)
	{
		(void)balance_u8(rgb, size, nb_min, nb_max,0,step); 
		(void)balance_u8(rgb, size, nb_min, nb_max,1,step);
		(void)balance_u8(rgb, size, nb_min, nb_max,2,step);
		return rgb;
	}

 

	/**
	* @brief normalize an unsigned char array
	*
	* This function operates in-place. It computes the minimum and
	* maximum values of the data, and rescales the data to
	* [0-UCHAR_MAX], with optionally flattening some extremal pixels.
	*
	* @param data input/output array
	* @param size array size
	* @param nb_min, nb_max number extremal pixels flattened
	*
	* @return data
	*/
	unsigned char *balance_u8(unsigned char *data, size_t size,
		size_t nb_min, size_t nb_max,size_t offset,size_t step)
	{
		unsigned char min, max;

		/* sanity checks */
		if (NULL == data) {
			fprintf(stderr, "a pointer is NULL and should not be so\n");
			abort();
		}
		if (nb_min + nb_max >= size) {
			nb_min = (size - 1) / 2;
			nb_max = (size - 1) / 2;
			fprintf(stderr, "the number of pixels to flatten is too large\n");
			fprintf(stderr, "using (size - 1) / 2\n");
		}

		/* get the min/max */
		if (0 != nb_min || 0 != nb_max)
			quantiles_u8(data, size, nb_min, nb_max, &min, &max,offset,step);
		else
			minmax_u8(data, size, &min, &max, offset, step);

		/* rescale 
		*/
		(void)rescale_u8(data, size, min, max, offset, step);

		return data;
	}

 

示例:

 			std::string beauty_src_data;
 			beauty_src_data.resize(width*height * 4);
 			YUV420ToARGB((char*)data, (char*)beauty_src_data.c_str(), width, height);
 			int wxh = width*height;
// 			//采用色彩平衡算法进行美白
			colorbalance_rgb_u8((unsigned char*)beauty_src_data.c_str(), wxh, (size_t)(wxh * 2 / 100), (size_t)(wxh * 8 / 100), 4);


3) ARGBtoYUV

// ARGB little endian (bgra in memory) to I420
int ARGBToI420(const uint8* src_frame, int src_stride_frame,
               uint8* dst_y, int dst_stride_y,
               uint8* dst_u, int dst_stride_u,
               uint8* dst_v, int dst_stride_v,
               int width, int height);

eg

ARGBToYUV420(char* src, char* dst, int width, int height)
	{
		int byte_width = width * 4;
		width -= width % 2;
		height -= height % 2;
		int wxh = width * height;
		uint8_t* des_y = (uint8_t*)dst;
		uint8_t* des_u = des_y + wxh;
		uint8_t* des_v = des_u + wxh / 4;
		


// 		libyuv::RGB24ToI420((const uint8*)src, byte_width,
// 			des_y, width,
// 			des_u, width / 2,
// 			des_v, width / 2,
// 			width, height);
		libyuv::ARGBToI420((const uint8_t*)src, byte_width,
			des_y, width,
			des_u, width / 2,
			des_v, width / 2,
			width, height);
	}
 			std::string beauty_src_data;
 			beauty_src_data.resize(width*height * 4);
 			YUV420ToARGB((char*)data, (char*)beauty_src_data.c_str(), width, height);
 			int wxh = width*height;
// 			//采用色彩平衡算法进行美白
			colorbalance_rgb_u8((unsigned char*)beauty_src_data.c_str(), wxh, (size_t)(wxh * 2 / 100), (size_t)(wxh * 8 / 100), 4);

  			ARGBToYUV420((char*)beauty_src_data.c_str(), (char*)data, width, height);