广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++ opencv将图片动漫化介绍
  • 679
分享到

C++ opencv将图片动漫化介绍

2024-04-02 19:04:59 679人浏览 独家记忆
摘要

目录边缘检测贴边缘图到原图双边滤波HSI空间修改饱和度后续:总结最近对图像处理十分感兴趣,也学着用OpenCV 实现各种简单的图像处理,因此,有了下面的实验,就是将照片处理成漫画的风

最近对图像处理十分感兴趣,也学着用OpenCV 实现各种简单的图像处理,因此,有了下面的实验,就是将照片处理成漫画的风格。

对照片进行动漫话一般需要四个步骤
1、边缘检测
2、将边缘检测得到的边缘 以黑色的形式贴在原来的画上。
3、对贴了边缘的图进行双边滤波,双边滤波可以较好的滤波的同时保留边缘。
4、修改图像的颜色的饱和度,本文采用的是将RGB转化为HSI空间,然后调整S分量。

边缘检测

对于边缘检测,本文采用的是canny算法
此文中将低阈值设定在70,高阈值则为70*3。
执行后的结果为:

这里写图片描述

贴边缘图到原图

将边缘图以黑色贴到原图上,原图上非边缘区域仍然为原来的颜色,动漫就是边缘很明显,且边缘不是很多,不注重细节,因此这里将边缘贴上面当作边缘,后续利用双倍滤波将图中的其他相对小的细节边缘去掉。针对纹理贴图主要用到下面这个函数:

// 将边缘检测后的图 cannyImage 边以黑色的形式贴在原图 image上。
void pasteEdge(Mat &image, Mat &outImg, IplImage cannyImage)
{
    Mat cannyMat;
    //将IplImage转化为Mat
    cannyMat = cvarrToMat(&cannyImage); 
    //颜色反转
    cannyMat = cannyMat < 100;
    image.copyTo(outImg, cannyMat);
}

执行后的效果如下:

这里写图片描述

双边滤波

双边滤波(Bilateral filter)在图像美化,美颜上有广泛的运用,是一种可以保边去噪的滤波器,由两个函数构成。为了节约时间,这里就借用一张图来充当介绍了

这里写图片描述

opencv也对此有函数调用:

void bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigMacolor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

前面2个参数为输入图像,输出图像,d为双倍滤波的算子大小,sigmacolor ,sigmaSpace是2个滤波函数的nameda值(这里节约时间不打符号了)
本文相关代码:

    // 双边滤波
    Mat binateMat;
    bilateralFilter(pasteEdgeMat, binateMat, 10, 50, 50, BORDER_DEFAULT);

执行后的结果如下:

这里写图片描述

HSI空间修改饱和度

关于HSI颜色空间这里就不详细介绍了,大家可以百度下,很多文章介绍,后续我也可能总结一下各个颜色空间,并且与rgb转换方法。主要思路:将贴有边缘 且 双边滤波后的图像 转化为 HSI 空间,而将S分量增大到原来的SRadio倍,然后将HSI空间图像转化回Rgb,并显示。

将颜色空间转化HSI,并增加S分量为原来的sRadio倍,主要是使用了下面这个函数:

// 将image 像素转化到 HSI 空间,并调整S 即颜色的饱和度,
void changeSImage(Mat &image, IplImage &outImg, float sRadio)
{
    int rows = image.rows;
    int cols = image.cols;
    // 三个HSI空间数据矩阵
    CvMat* HSI_H = cvCreateMat(rows, cols, CV_32FC1);
    CvMat* HSI_S = cvCreateMat(rows, cols, CV_32FC1);
    CvMat* HSI_I = cvCreateMat(rows, cols, CV_32FC1);

    // 原始图像数据指针, HSI矩阵数据指针
    uchar* data;

    // rgb分量
    int img_r, img_g, img_b;
    int min_rgb;  // rgb分量中的最小值
    // HSI分量
    float fHue, fSaturation, fIntensity;
    int channels = image.channels();
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            data = image.ptr<uchar>(i);
            data = data + j*channels;
            img_b = *data;
            data++;
            img_g = *data;
            data++;
            img_r = *data;

            // Intensity分量[0, 1]
            fIntensity = (float)((img_b + img_g + img_r) / 3) / 255;

            // 得到RGB分量中的最小值
            float fTemp = img_r < img_g ? img_r : img_g;
            min_rgb = fTemp < img_b ? fTemp : img_b;
            // Saturation分量[0, 1]
            fSaturation = 1 - (float)(3 * min_rgb) / (img_r + img_g + img_b);

            // 计算theta角
            float numerator = (img_r - img_g + img_r - img_b) / 2;
            float denominator = sqrt(
                pow((img_r - img_g), 2) + (img_r - img_b)*(img_g - img_b));

            // 计算Hue分量
            if (denominator != 0)
            {
                float theta = acos(numerator / denominator) * 180 / 3.14;

                if (img_b <= img_g)
                {
                    fHue = theta;
                }
                else
                {
                    fHue = 360 - theta;
                }
            }
            else
            {
                fHue = 0;
            }

            // 赋值
            cvmSet(HSI_H, i, j, fHue);
            cvmSet(HSI_S, i, j, fSaturation * sRadio);
            cvmSet(HSI_I, i, j, fIntensity);
        }
    }
    outImg = *HSI2RGBImage(HSI_H, HSI_S, HSI_I);    
}

HSI2RGBImage(HSI_H, HSI_S, HSI_I)是将三个分类的Mat 合并并转化为BGR的图,函数如下:

IplImage* HSI2RGBImage(CvMat* HSI_H, CvMat* HSI_S, CvMat* HSI_I)
{
    IplImage * RGB_Image = cvCreateImage(cvGetSize(HSI_H), IPL_DEPTH_8U, 3);

    int iB, iG, iR;
    for (int i = 0; i < RGB_Image->height; i++)
    {
        for (int j = 0; j < RGB_Image->width; j++)
        {
            // 该点的色度H
            double dH = cvmGet(HSI_H, i, j);
            // 该点的色饱和度S
            double dS = cvmGet(HSI_S, i, j);
            // 该点的亮度
            double dI = cvmGet(HSI_I, i, j);

            double dTempB, dTempG, dTempR;
            // RG扇区
            if (dH < 120 && dH >= 0)
            {
                // 将H转为弧度表示
                dH = dH * 3.1415926 / 180;
                dTempB = dI * (1 - dS);
                dTempR = dI * (1 + (dS * cos(dH)) / cos(3.1415926 / 3 - dH));
                dTempG = (3 * dI - (dTempR + dTempB));
            }
            // GB扇区
            else if (dH < 240 && dH >= 120)
            {
                dH -= 120;

                // 将H转为弧度表示
                dH = dH * 3.1415926 / 180;

                dTempR = dI * (1 - dS);
                dTempG = dI * (1 + dS * cos(dH) / cos(3.1415926 / 3 - dH));
                dTempB = (3 * dI - (dTempR + dTempG));
            }
            // BR扇区
            else
            {
                dH -= 240;

                // 将H转为弧度表示
                dH = dH * 3.1415926 / 180;

                dTempG = dI * (1 - dS);
                dTempB = dI * (1 + (dS * cos(dH)) / cos(3.1415926 / 3 - dH));
                dTempR = (3 * dI - (dTempG + dTempB));
            }

            iB = dTempB * 255;
            iG = dTempG * 255;
            iR = dTempR * 255;

            cvSet2D(RGB_Image, i, j, cvScalar(iB, iG, iR));
        }
    }

    return RGB_Image;
}

执行后就大功告成了,效果如下:

这里写图片描述

后续:

上述执行基本完成了照片的漫画风格,但看到天空的云的一些边缘泰国刺眼,本着好玩的性子,去掉了第一步和第二步,直接图原图进行了双边滤波和增加颜色饱和度,感觉图清晰,自然了些,但漫画风格也少了些,具体如何见下图:

这里写图片描述

GitHub地址:https://github.com/hurtnotbad/cartoon

总结

到此这篇关于c++ opencv将图片动漫化介绍的文章就介绍到这了,更多相关C++ OpenCV图片动漫化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++ opencv将图片动漫化介绍

本文链接: https://www.lsjlt.com/news/163640.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ opencv将图片动漫化介绍
    目录边缘检测贴边缘图到原图双边滤波HSI空间修改饱和度后续:总结最近对图像处理十分感兴趣,也学着用opencv 实现各种简单的图像处理,因此,有了下面的实验,就是将照片处理成漫画的风...
    99+
    2022-11-13
  • C++ opencv如何将图片动漫化
    这篇文章给大家分享的是有关C++ opencv如何将图片动漫化的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。最近对图像处理十分感兴趣,也学着用opencv 实现各种简单的图像处理,因此,有了下面的实验,...
    99+
    2023-06-28
  • C#实现将网址生成二维码图片方法介绍
    二维码是什么 二维码 QR Code,全称为:Quick Response Code,最早用于日本汽车制造业追踪零部件。QR现有40个标准版本,4个微型版本。相比一维码(也就是我们目...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作