QT5+OpenCV美白效果

【2017-04-01:完整项目文件GitHub】


皮肤美白的详细内容请参考:对皮肤美白算法的一些研究。



本文采用上面文中的第一种方法即色彩平衡进行美白,首先看了下ImageStone的源码,找到了色彩平衡功能的相关代码如下(源代码在ImageStone中的include\pixelprocessor\PixelProcessorBase.h头文件中):
FCPixelColorBalance (bool bPreLum, TONE_REGION ToneRgn, int cyan_red, int magenta_green, int yellow_blue)
    {
        m_bPreserveLuminosity = bPreLum ;

        int     cyan_red_rgn[3] = {0,0,0},
                magenta_green_rgn[3] = {0,0,0},
                yellow_blue_rgn[3] = {0,0,0} ;
        cyan_red_rgn[ToneRgn] = cyan_red ;
        magenta_green_rgn[ToneRgn] = magenta_green ;
        yellow_blue_rgn[ToneRgn] = yellow_blue ;

        // add for lightening, sub for darkening
        PCL_array  highlights_add(256), midtones_add(256), shadows_add(256),
                           highlights_sub(256), midtones_sub(256), shadows_sub(256) ;
        int     i ;
        for (i=0 ; i < 256 ; i++)
        {
            highlights_add[i] = shadows_sub[255 - i] = (1.075 - 1 / (i / 16.0 + 1)) ;
            midtones_add[i] = midtones_sub[i] = 0.667 * (1 - FSquare ((i - 127.0) / 127.0)) ;
            shadows_add[i] = highlights_sub[i] = 0.667 * (1 - FSquare ((i - 127.0) / 127.0)) ;
        }

        // Set the transfer arrays (for speed)
        double   * cyan_red_transfer[3], * magenta_green_transfer[3], * yellow_blue_transfer[3] ;
        cyan_red_transfer[TONE_SHADOWS] = (cyan_red_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
        cyan_red_transfer[TONE_MIDTONES] = (cyan_red_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
        cyan_red_transfer[TONE_HIGHLIGHTS] = (cyan_red_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;
        magenta_green_transfer[TONE_SHADOWS] = (magenta_green_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
        magenta_green_transfer[TONE_MIDTONES] = (magenta_green_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
        magenta_green_transfer[TONE_HIGHLIGHTS] = (magenta_green_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;
        yellow_blue_transfer[TONE_SHADOWS] = (yellow_blue_rgn[TONE_SHADOWS] > 0) ? shadows_add.get() : shadows_sub.get() ;
        yellow_blue_transfer[TONE_MIDTONES] = (yellow_blue_rgn[TONE_MIDTONES] > 0) ? midtones_add.get() : midtones_sub.get() ;
        yellow_blue_transfer[TONE_HIGHLIGHTS] = (yellow_blue_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add.get() : highlights_sub.get() ;

        for (i=0 ; i < 256 ; i++)
        {
            int     r_n = i, g_n = i, b_n = i ;

            r_n += (int)(cyan_red_rgn[TONE_SHADOWS] * cyan_red_transfer[TONE_SHADOWS][r_n]);        r_n = FClamp0255(r_n);
            r_n += (int)(cyan_red_rgn[TONE_MIDTONES] * cyan_red_transfer[TONE_MIDTONES][r_n]);      r_n = FClamp0255(r_n);
            r_n += (int)(cyan_red_rgn[TONE_HIGHLIGHTS] * cyan_red_transfer[TONE_HIGHLIGHTS][r_n]);  r_n = FClamp0255(r_n);

            g_n += (int)(magenta_green_rgn[TONE_SHADOWS] * magenta_green_transfer[TONE_SHADOWS][g_n]);        g_n = FClamp0255(g_n);
            g_n += (int)(magenta_green_rgn[TONE_MIDTONES] * magenta_green_transfer[TONE_MIDTONES][g_n]);      g_n = FClamp0255(g_n);
            g_n += (int)(magenta_green_rgn[TONE_HIGHLIGHTS] * magenta_green_transfer[TONE_HIGHLIGHTS][g_n]);  g_n = FClamp0255(g_n);

            b_n += (int)(yellow_blue_rgn[TONE_SHADOWS] * yellow_blue_transfer[TONE_SHADOWS][b_n]);        b_n = FClamp0255(b_n);
            b_n += (int)(yellow_blue_rgn[TONE_MIDTONES] * yellow_blue_transfer[TONE_MIDTONES][b_n]);      b_n = FClamp0255(b_n);
            b_n += (int)(yellow_blue_rgn[TONE_HIGHLIGHTS] * yellow_blue_transfer[TONE_HIGHLIGHTS][b_n]);  b_n = FClamp0255(b_n);

            m_pLookupR[i] = r_n ;
            m_pLookupG[i] = g_n ;
            m_pLookupB[i] = b_n ;
        }
    }


由于用色彩平衡来美白要满足以下三项,第一:色阶的三个调整值必须相同或者差异很小,不然输出图片会出现偏色,第二:一定选择中间调;第三:必须不勾选保持明度选项,所以对上面的代码简化后得到如下美白代码:
//定义转换数组
    double  highlights_add[256], highlights_sub[256];
    double  midtones_add[256], midtones_sub[256];
    double  shadows_add[256], shadows_sub[256];

//初始化转换数组
    for (int i = 0; i < 256; i++)
    {
        highlights_add[i] = shadows_sub[255 - i] = (1.075 - 1 / ((double) i / 16.0 + 1));
        midtones_add[i] = midtones_sub[i] = 0.667 * (1 - (((double) i - 127.0) / 127.0)*(((double) i - 127.0) / 127.0));
        shadows_add[i] = highlights_sub[i] = 0.667 * (1 - (((double) i - 127.0) / 127.0)*(((double) i - 127.0) / 127.0));
    }

//实现相关函数
int FMax(const int X, const int Y)
{
    return (X < Y ? Y : X);
}

int FMin(const int X, const int Y)
{
    return (Y < X ? Y : X);
}

void BalanceColor(Mat& bitmap,int value)
{
    int red, green, blue;
    unsigned char r_lookup[256],g_lookup[256],b_lookup[256];

    for (int i = 0; i < 256; i++)
    {
        red = i;
        green = i;
        blue = i;

        red += (int)( 0.0 * shadows_sub[red] + value * midtones_add[red] + 0.0 * highlights_sub[red]);
        red = FMax(0,FMin(0xFF,red));

        green += (int)( 0.0 * shadows_sub[green] + value * midtones_add[green] + 0.0 * highlights_sub[green]);
        green = FMax(0,FMin(0xFF,green));

        blue += (int)( 0.0 * shadows_sub[blue] + value * midtones_add[blue] + 0.0 * highlights_sub[blue]);
        blue = FMax(0,FMin(0xFF,blue));

        r_lookup[i] = (unsigned char)red;
        g_lookup[i] = (unsigned char)green;
        b_lookup[i] = (unsigned char)blue;
    }

    for (int row = 0; row < bitmap.rows; row++)
    {
        for (int col = 0; col < bitmap.cols; col++)
        {
            bitmap.at(row, col)[0] = b_lookup[bitmap.at(row, col)[0]];
            bitmap.at(row, col)[1] = g_lookup[bitmap.at(row, col)[1]];
            bitmap.at(row, col)[2] = r_lookup[bitmap.at(row, col)[2]];
        }
    }
}


附上磨皮加美白的效果图

QT5+OpenCV美白效果_第1张图片QT5+OpenCV美白效果_第2张图片


由于本文算法未对皮肤进行检测,所以美白对象为整张图,效果可能不是很好,有兴趣的可自行加上肤色检测


PS:磨皮加美白完整代码点这里


参考:
图像编辑之色彩平衡 
皮肤检测算法三种,示例与代码
Opencv之人脸肤色检测总结

你可能感兴趣的:(C/C++)