YUV視頻美顏處理

 

方式一 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);

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章