Opencv C++图像处理:亮度+对比度+饱和度+高光+暖色调+阴影+漫画效果+白平衡+浮雕+羽化+锐化+颗粒感

文章目录
一、多功能色彩调整
1.1、亮度
1.2、对比度
1.3、饱和度
1.4、高光
1.5、暖色调
1.6、阴影
1.7、漫画效果
1.8、白平衡-灰度世界
1.9、白平衡-完美反射
1.10、浮雕
1.11、羽化
1.12、锐化
1.13、颗粒感
二、实战案例
2.1、主函数
2.2、函数定义
更多详细信息请看:OpenCV专栏:翟天保Steven

一、多功能色彩调整
1.1、亮度

//--------------------------------------------------------------------------------
// 亮度与对比度
cv::Mat Brightness(cv::Mat src, float brightness, int contrast)
{
    cv::Mat dst;
    dst = cv::Mat::zeros(src.size(), src.type());        //新建空白模板:大小/类型与原图像一致,像素值全0。
    int height = src.rows;                                //获取图像高度
    int width = src.cols;                                //获取图像宽度
    float alpha = brightness;                            //亮度(0~1为暗,1~正无穷为亮)
    float beta = contrast;                                //对比度

    cv::Mat template1;
    src.convertTo(template1, CV_32F);                    //将CV_8UC1转换为CV32F1数据格式。
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            if (src.channels() == 3)
            {
                float b = template1.at<cv::Vec3f>(row, col)[0];        //获取通道的像素值(blue)
                float g = template1.at<cv::Vec3f>(row, col)[1];        //获取通道的像素值(green)
                float r = template1.at<cv::Vec3f>(row, col)[2];        //获取通道的像素值(red)

                //cv::saturate_cast<uchar>(vaule):需注意,value值范围必须在0~255之间。
                dst.at<cv::Vec3b>(row, col)[0] = cv::saturate_cast<uchar>(b * alpha + beta);        //修改通道的像素值(blue)
                dst.at<cv::Vec3b>(row, col)[1] = cv::saturate_cast<uchar>(g * alpha + beta);        //修改通道的像素值(green)
                dst.at<cv::Vec3b>(row, col)[2] = cv::saturate_cast<uchar>(r * alpha + beta);        //修改通道的像素值(red)
            }
            else if (src.channels() == 1)
            {
                float v = src.at<uchar>(row, col);                                            //获取通道的像素值(单)
                dst.at<uchar>(row, col) = cv::saturate_cast<uchar>(v * alpha + beta);        //修改通道的像素值(单)
                //saturate_cast<uchar>:主要是为了防止颜色溢出操作。如果color<0,则color等于0;如果color>255,则color等于255。
            }
        }
    }
    return dst;
}


1.2、对比度

//--------------------------------------------------------------------------------
// 亮度与对比度
cv::Mat Brightness(cv::Mat src, float brightness, int contrast)
{
    cv::Mat dst;
    dst = cv::Mat::zeros(src.size(), src.type());        //新建空白模板:大小/类型与原图像一致,像素值全0。
    int height = src.rows;                                //获取图像高度
    int width = src.cols;                                //获取图像宽度
    float alpha = brightness;                            //亮度(0~1为暗,1~正无穷为亮)
    float beta = contrast;                                //对比度

    cv::Mat template1;
    src.convertTo(template1, CV_32F);                    //将CV_8UC1转换为CV32F1数据格式。
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
            if (src.channels() == 3)
            {
                float b = template1.at<cv::Vec3f>(row, col)[0];        //获取通道的像素值(blue)
                float g = template1.at<cv::Vec3f>(row, col)[1];        //获取通道的像素值(green)
                float r = template1.at<cv::Vec3f>(row, col)[2];        //获取通道的像素值(red)

                //cv::saturate_cast<uchar>(vaule):需注意,value值范围必须在0~255之间。
                dst.at<cv::Vec3b>(row, col)[0] = cv::saturate_cast<uchar>(b * alpha + beta);        //修改通道的像素值(blue)
                dst.at<cv::Vec3b>(row, col)[1] = cv::saturate_cast<uchar>(g * alpha + beta);        //修改通道的像素值(green)
                dst.at<cv::Vec3b>(row, col)[2] = cv::saturate_cast<uchar>(r * alpha + beta);        //修改通道的像素值(red)
            }
            else if (src.channels() == 1)
            {
                float v = src.at<uchar>(row, col);                                            //获取通道的像素值(单)
                dst.at<uchar>(row, col) = cv::saturate_cast<uchar>(v * alpha + beta);        //修改通道的像素值(单)
                //saturate_cast<uchar>:主要是为了防止颜色溢出操作。如果color<0,则color等于0;如果color>255,则color等于255。
            }
        }
    }
    return dst;
}


1.3、饱和度


//--------------------------------------------------------------------------------
// 饱和度
cv::Mat Saturation(cv::Mat src, int saturation)
{
    float Increment = saturation * 1.0f / 100;
    cv::Mat temp = src.clone();
    int row = src.rows;
    int col = src.cols;
    for (int i = 0; i < row; ++i)
    {
        uchar *t = temp.ptr<uchar>(i);
        uchar *s = src.ptr<uchar>(i);
        for (int j = 0; j < col; ++j)
        {
            uchar b = s[3 * j];
            uchar g = s[3 * j + 1];
            uchar r = s[3 * j + 2];
            float max = max3(r, g, b);
            float min = min3(r, g, b);
            float delta, value;
            float L, S, alpha;
            delta = (max - min) / 255;
            if (delta == 0)
                continue;
            value = (max + min) / 255;
            L = value / 2;
            if (L < 0.5)
                S = delta / value;
            else
                S = delta / (2 - value);
            if (Increment >= 0)
            {
                if ((Increment + S) >= 1)
                    alpha = S;
                else
                    alpha = 1 - Increment;
                alpha = 1 / alpha - 1;
                t[3 * j + 2] =static_cast<uchar>( r + (r - L * 255) * alpha);
                t[3 * j + 1] = static_cast<uchar>(g + (g - L * 255) * alpha);
                t[3 * j] = static_cast<uchar>(b + (b - L * 255) * alpha);
            }
            else
            {
                alpha = Increment;
                t[3 * j + 2] = static_cast<uchar>(L * 255 + (r - L * 255) * (1 + alpha));
                t[3 * j + 1] = static_cast<uchar>(L * 255 + (g - L * 255) * (1 + alpha));
                t[3 * j] = static_cast<uchar>(L * 255 + (b - L * 255) * (1 + alpha));
            }
        }
    }
    return temp;
}


1.4、高光

//--------------------------------------------------------------------------------
// 高光
cv::Mat HighLight(cv::Mat src, int highlight)
{
    // 生成灰度图
    cv::Mat gray = cv::Mat::zeros(src.size(), CV_32FC1);
    cv::Mat f = src.clone();
    f.convertTo(f, CV_32FC3);
    std::vector<cv::Mat> pics;
    split(f, pics);
    gray = 0.299f*pics[2] + 0.587*pics[2] + 0.114*pics[0];
    gray = gray / 255.f;
 
    // 确定高光区
    cv::Mat thresh = cv::Mat::zeros(gray.size(), gray.type());
    thresh = gray.mul(gray);
    // 取平均值作为阈值
    cv::Scalar t = mean(thresh);
    cv::Mat mask = cv::Mat::zeros(gray.size(), CV_8UC1);
    mask.setTo(255, thresh >= t[0]);
 
    // 参数设置
    int max = 4;
    float bright = highlight / 100.0f / max;
    float mid = 1.0f + max * bright;
 
    // 边缘平滑过渡
    cv::Mat midrate = cv::Mat::zeros(src.size(), CV_32FC1);
    cv::Mat brightrate = cv::Mat::zeros(src.size(), CV_32FC1);
    for (int i = 0; i < src.rows; ++i)
    {
        uchar *m = mask.ptr<uchar>(i);
        float *th = thresh.ptr<float>(i);
        float *mi = midrate.ptr<float>(i);
        float *br = brightrate.ptr<float>(i);
        for (int j = 0; j < src.cols; ++j)
        {
            if (m[j] == 255)
            {
                mi[j] = mid;
                br[j] = bright;
            }
            else {
                mi[j] = (mid - 1.0f) / t[0] * th[j] + 1.0f;
                br[j] = (1.0f / t[0] * th[j])*bright;
            }
        }
    }
 
    // 高光提亮,获取结果图
    cv::Mat result = cv::Mat::zeros(src.size(), src.type());
    for (int i = 0; i < src.rows; ++i)
    {
        float *mi = midrate.ptr<float>(i);
        float *br = brightrate.ptr<float>(i);
        uchar *in = src.ptr<uchar>(i);
        uchar *r = result.ptr<uchar>(i);
        for (int j = 0; j < src.cols; ++j)
        {
            for (int k = 0; k < 3; ++k)
            {
                float temp = pow(float(in[3 * j + k]) / 255.f, 1.0f / mi[j])*(1.0 / (1 - br[j]));
                if (temp > 1.0f)
                    temp = 1.0f;
                if (temp < 0.0f)
                    temp = 0.0f;
 &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值