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);