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

目录
  • 边缘检测
  • 贴边缘图到原图
  • 双边滤波
  • HSI空间修改饱和度
  • 后续:
  • 总结

最近对图像处理十分感兴趣,也学着用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图片动漫化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于OpenCV和C++ 实现图片旋转

    图片旋转,本质上是对旋转后的图片中每个像素点计算在原图的位置.然后照搬过来就好. (多说一句,如果计算出来在原图中的位置不是整数而是小数,因为像素点个数都是整数,就需要小数到整数的转换.这个转换过程是有讲究的,需要用到插值:最近邻插值.双线性插值等等.这里我使用的是最简单的最近邻插值,即对小数四舍五入成整数,C/C++ 实现四舍五入见 这里 ) 图形图像课上一般会介绍旋转变换矩阵,其中 t 为需要旋转的角度,[x'; y']是变换后坐标(其中分号表示上下关系): 即表示为:[x'; y'] =

  • C++使用opencv处理两张图片的帧差

    本文为大家分享了使用opencv处理两张图片帧差的具体代码,供大家参考,具体内容如下 这个程序是两张图片做帧差,用C++实现的,把不同的地方用框框起来,仔细读一下程序,应该还是蛮简单的哈哈,opencv处理图片的基础. opencv配置不用我说了吧,源码cmake编译,然后导入vs即可. #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int mai

  • C++ OpenCV制作黑客帝国风格的照片

    目录 准备工作 开始写代码 完整代码 总结 前不久,黑客帝国系列最新的 <矩阵重启> 上映了.黑客帝国是早期科幻类型的翘楚.但是这次有点垮了.豆瓣评分不到6分. 小的时候,看到黑客帝国的那些照片,一串串数字从上而下, 感觉特别酷炫. 今天我们就来看看怎么制作类似的效果. 准备工作 一张基努里维斯的照片 准备好项目需要使用到的库 opencv,在 CMakeLists.txt 里配置完成. cmake_minimum_required(VERSION 3.17) project(opencv_d

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

    目录 边缘检测 贴边缘图到原图 双边滤波 HSI空间修改饱和度 后续: 总结 最近对图像处理十分感兴趣,也学着用opencv 实现各种简单的图像处理,因此,有了下面的实验,就是将照片处理成漫画的风格. 对照片进行动漫话一般需要四个步骤1.边缘检测2.将边缘检测得到的边缘 以黑色的形式贴在原来的画上.3.对贴了边缘的图进行双边滤波,双边滤波可以较好的滤波的同时保留边缘.4.修改图像的颜色的饱和度,本文采用的是将RGB转化为HSI空间,然后调整S分量. 边缘检测 对于边缘检测,本文采用的是canny

  • Python OpenCV实现人物动漫化效果

    目录 前言 效果展示 代码展示 前言 前几天玩抖音,发现一个人像动漫化的操作,觉得很好玩儿.我心想:python既然这么强大,是不是也可以使用python程序来实现这样一个操作呢? 哈哈!我自己当然是没有这个本事编写这样一个牛逼的程序出来,但是百度可以呀,并且还很好用.百度AI开放平台给我们提供了完整的接口,甚至贴心的将代码都给我们写好了.这些接口还支持很多主流语言都呢,像Java.Python.PHP.C#等,我们做的就是直接调用它即可. 效果怎么样呢?我们先来看看下方的对比图吧. 效果展示

  • C++使用opencv读取图片的操作代码(图像处理)

    目录 代码理解 全部代码 读取结果 参考 代码理解 using namespace cv; 解释:加入此代码,后面就不需要在函数前加入cv:: 如从cv::imread(),可以直接写成imread() int main(int argc, char** argv) { return 0: } 解释: // argc是命令行,总的参数个数; argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数命令行后面跟的用户输入的参数 // char *argv[] 用来取得你所输入的参数 /

  • python3读取图片并灰度化图片的四种方法(OpenCV、PIL.Image、TensorFlow方法)总结

    在处理图像的时候经常是读取图片以后把图片转换为灰度图.作为一个刚入坑的小白,我在这篇博客记录了四种处理的方法. 首先导入包: import numpy as np import cv2 import tensorflow as tf from PIL import Image 方法一:在使用OpenCV读取图片的同时将图片转换为灰度图: img = cv2.imread(imgfile, cv2.IMREAD_GRAYSCALE) print("cv2.imread(imgfile, cv2.I

  • Python+opencv 实现图片文字的分割的方法示例

    实现步骤: 1.通过水平投影对图形进行水平分割,获取每一行的图像: 2.通过垂直投影对分割的每一行图像进行垂直分割,最终确定每一个字符的坐标位置,分割出每一个字符: 先简单介绍一下投影法:分别在水平和垂直方向对预处理(二值化)的图像某一种像素进行统计,对于二值化图像非黑即白,我们通过对其中的白点或者黑点进行统计,根据统计结果就可以判断出每一行的上下边界以及每一列的左右边界,从而实现分割的目的. 下面通过Python+opencv来实现该功能 首先来实现水平投影: import cv2 impor

  • python opencv实现图片缺陷检测(讲解直方图以及相关系数对比法)

    一.利用直方图的方式进行批量的图片缺陷检测(方法简单) 二.步骤(完整代码见最后) 2.1灰度转换(将原图和要检测对比的图分开灰度化) 灰度化的作用是因为后面的直方图比较需要以像素256为基准进行相关性比较 img = cv2.imread("0.bmp") #原图灰度转换 gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) #循环要检测的图,均灰度化 for i in range(1, 6): t1=cv2.cvtColor(cv2.imread

  • python实现人像动漫化的示例代码

    利用百度api实现人像动漫化 百度API地址:https://ai.baidu.com/tech/imageprocess/selfie_anime 技术文档:https://ai.baidu.com/ai-doc/IMAGEPROCESS/Mk4i6olx5 注册百度账号,开通实现人像动漫化,创建应用. # encoding:utf-8 import requests import base64 # client_id 为官网获取的AK, client_secret 为官网获取的SK host

  • 用opencv给图片换背景色的示例代码

    图像平滑 模糊/平滑图片来消除图片噪声 OpenCV函数:cv2.blur(), cv2.GaussianBlur(), cv2.medianBlur(), cv2.bilateralFilter() 2D 卷积 OpenCV中用cv2.filter2D()实现卷积操作,比如我们的核是下面这样(3×3区域像素的和除以10): img = cv2.imread('lena.jpg') # 定义卷积核 kernel = np.ones((3, 3), np.float32) / 10 # 卷积操作,

  • python实战之百度智能云使人像动漫化

    一.目标 之前无意中看到有某位博主写过人像动漫化这样的文章,看着还挺好玩,所以我也想尝试一下. 利用百度智能云中的人工智能,对图片进行处理达到人像动漫化的效果. 二.准备工作 1.百度云智能账号创建 2.图像特效应用 3.开发环境python3.7+pycharm 首先要注册一个百度智能云账号,并创建这个图像特效应用 三.操作流程 3.1 阅读官方文档 当我们要使用一个我们不太了解的东西时,阅读官方文档无疑是最重要的,官方文档一般都写的特别详细,对每一个功能描述的很细节,我们先来看一下 而且这里

  • Unity 百度AI实现人像动漫化效果

    接口介绍: 运用对抗生成网络技术,结合人脸检测.头发分割.人像分割等技术,为用户量身定制千人千面的二次元动漫形象,并支持通过参数设置,生成二次元动漫人像. 创建应用: 在产品服务中搜索图像增强与特效,创建应用,获取AppID.APIKey.SecretKey信息: 查阅官方文档,以下是人像动漫画接口返回数据参数详情: 定义数据结构: using System; /// <summary> /// 人像动漫化接口响应数据结构 /// </summary> [Serializable]

随机推荐