当前位置:   article > 正文

OpenCV实现图像卡通化_基于opencv的图像卡通化

基于opencv的图像卡通化

一、前言

今天介绍一个有趣的demo,结合之前图像空域滤波边缘检测的知识,实现图像卡通化,通过实现的过程,可以发现几种图像边缘检测和差异和图像滤波的性质

Demo来自《Mastering OpenCV with Practical ComputerVision Projects》(目前没见到中文版),可以在网上下载Ebook。
Github地址:https://github.com/MasteringOpenCV/code

二、图像卡通化实现原理解析

实现原理:

图像卡通化的过程,实际上是对图像的内容部分进行平滑处理,对边缘部分锐化处理,使得图像内容更加光滑、边缘更加突出

步骤:

  1. 通过边缘检测滤波器获得灰度图像的边缘特征,阈值化后可得黑白素描图
  2. 通过双边滤波器多次迭代获得柔化图像,使平滑区域更光滑
  3. 将(1)中素描图作为掩膜叠加到(2)中柔化图像得卡通化图像

以上是图像卡通化的一般步骤,在实际过程中,我们还需要考虑以下问题:

Q: 若原图含噪声,应该如何处理?
A: 我们知道无论是一阶还是二阶微分算子,都对噪声敏感,在边缘检测之前,一定要先进行去噪处理,空域内图像平滑通常有五种方法:线性滤波(均值滤波、方框滤波和高斯滤波)、非线性滤波(中值滤波和双边滤波),在这里一般选择非线性滤波中的中值滤波,(1)中值滤波能够有效去除边缘孤立噪声点而不会平滑边缘特征,(2)中值滤波能够保持边缘的锐度,利于后面边缘检测。

Q: 边缘检测滤波器如何选择?
A: 常用的边缘检测算子有:一阶微分算子(Sobel、Scharr)、二阶微分算子(Canny、Laplace),关于这几种检测算子的使用,书籍原文给出了解释:

There are many different edge detection flters, such as Sobel, Scharr, Laplacian filters, or Canny-edge detector. We will use a Laplacian edge flter since it produces edges that look most similar to hand sketches compared to Sobel or Scharr, and that are quite consistent compared to a Canny-edge detector, which produces very clean line drawings but is affected more by random noise in the camera frames and the line drawings therefore often change drastically between frames.

原文选择Laplacian算子,我的理解有以下两点:
(1)像Sobel等一阶微分算子,通过XY方向上的灰度梯度来估算边缘信息,并不能将图像边缘与背景信息区分开来,如Sobel算子提取的边缘通常过于“细致”而不符合主观视觉上的真实图像边缘,相较之下,Laplacian、Canny等二阶微分算子往往能得到更加合理的边缘,看起来也更有“素描”的感觉。
(2)Canny算子检测的边缘连续性更好,轮廓也更清晰,但是它容易受随机噪声影响,相较之下,Laplacian算子的噪声抑制效果要更好,而相机自然拍摄的图片多少含有随机噪声,所以选择Laplacian算子是最好的选择。

Q:为什么选择双边滤波器柔化图像?
A:(1)双边滤波器是一种非线性滤波方法,有效结合图像的空间邻近度和像素值相似度的优势,用它柔化图像的原因是(1)同时考虑了空间信息和灰度相似性,同时达到保边去噪的目的;(2)对局部信息的保持效果好

Q:双边滤波的速度很慢,如何优化?
A:为了加速滤波过程,可以先缩小图像,再进行双边滤波,处理完成后,恢复原始尺寸,处理效果与直接原图滤波差不多,但是效率却提高了几倍。

三、实现卡通化图像源码

通过以上的分析过程,就可以写出代码,部分实现细节在代码中讲解:

#include<opencv2/opencv.hpp>
using namespace cv;

void cartoonify(Mat& src,Mat& dst, const char* typeName){
    Mat gray;
    cvtColor(src,gray,CV_RGB2GRAY);
    medianBlur(gray,gray,5); //去噪

    if(typeName == "Scharr"){
        Mat edge1=Mat(gray.size(),CV_8U);
        Mat edge2;
        Scharr(gray,edge1,CV_8U,1,0,1,0,BORDER_DEFAULT); //X方向差分运算 
        Scharr(gray,edge2,CV_8U,0,1,1,0,BORDER_DEFAULT); //Y方向差分运算 
        edge1 += edge2; //整体Scharr
        edge1.copyTo(gray);
    }
    else if(typeName == "Canny"){
        Canny(gray,gray,80,160,3); 
    }
    else{
        Laplacian(gray, gray, CV_8U, 5);
    }
    
    Mat mask(src.size(),CV_8U);
    threshold(gray,mask,120,255,THRESH_BINARY_INV);
    //medianBlur(mask,mask,3); 
    imshow("mask",mask);

    //对原始图像双边滤波
    Size smallSzie(src.cols/2,src.rows/2);
    Mat s_src=Mat(smallSzie,src.type());
    resize(src,s_src,smallSzie,0,0,INTER_LINEAR);
    Mat tmp=Mat(smallSzie,CV_8UC3);
    int iterator=7;
    for(int i=0;i<iterator;i++){
        int ksize=9;
        double sigmaColor=9;
        double sigmaSpace=7;
        bilateralFilter(s_src,tmp,ksize,sigmaColor,sigmaSpace);
        bilateralFilter(tmp,s_src,ksize,sigmaColor,sigmaSpace);
    }
    Mat b_src;
    resize(s_src,b_src,src.size(),0,0,INTER_LINEAR);

    //掩膜叠加
    dst=Mat(src.size(),src.type(),Scalar::all(0)); //初始化
    //dst.setTo(0);
    b_src.copyTo(dst,mask);
}

int main()
{
    Mat src=imread("C:/Users/Administrator/Desktop/beauty.jpg");
    if(!src.data){
        printf("Load failture...");
        return 0;
    }
    resize(src,src,Size(600,400),0,0,INTER_LINEAR);

    Mat dst;
    cartoonify(src,dst,"Canny");
    imshow("cartoonImg_Scharr",dst);

    waitKey(0);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

结果如下:
(1)使用Scharr边缘检测算子时:
在这里插入图片描述
(1)使用Canny边缘检测算子时:
在这里插入图片描述
(1)使用Lapcian边缘检测算子时:
在这里插入图片描述
整体来看Laplacian算子实现效果最好,Canny算子检测的边缘轮廓最清晰且连贯性好,但是视觉上边缘掩膜痕迹太重了(即素描轮廓过于清晰)。由于原图无噪声,所以从噪声方面考虑Canny算子实现的效果还是挺好的!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/327188
推荐阅读
相关标签
  

闽ICP备14008679号