OpenCV-图像漫画效果

作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

实现原理

       OpenCV中有自带的stylization函数,使图像呈漫画状态,可是有点不太像,于是自己重写了一个。定义Cartoon函数,有4个输入参数:src为输入图像;clevel为轮廓参数,调整可改变轮廓的数量;d为双边滤波中的参数d,sigma同时控制双边滤波中的参数sigmaColor和sigmaSpace;size为漫画同色区域的尺寸大小,该值越大,则同色区域面积越大。

       对图像进行中值滤波减少噪声,用Canny提取轮廓线并适当膨胀,反转后均值滤波处理下;对原图进行双边滤波,平滑感更强,符合漫画特征;将处理后的轮廓线点乘双边滤波图,以达到轮廓线加深的效果。

       话不多说,上代码。

功能函数代码

// 漫画效果
cv::Mat Cartoon(cv::Mat src, double clevel,int d,double sigma,int size)
{
	// 中值滤波
	cv::Mat m;
	cv::medianBlur(src, m, 7);
	// 提取轮廓
	cv::Mat c;
	clevel = max(40., min(80., clevel));
	cv::Canny(m, c, clevel, clevel *3);
	// 轮廓膨胀加深
	cv::Mat k = getStructuringElement(MORPH_RECT, Size(2, 2));
	cv::dilate(c, c, k);
	// 反转
	c = c / 255;
	c = 1 - c;
	// 类型转化
	cv::Mat cf;
	c.convertTo(cf, CV_32FC1);
	// 均值滤波
	cv::blur(cf, cf, Size(5, 5));
	// 双边滤波
	cv::Mat srcb;
	d = max(0, min(10, d));
	sigma = max(10., min(250., sigma));
	cv::bilateralFilter(src, srcb, d, sigma, sigma);
	size = max(10, min(25, size));
	cv::Mat temp = srcb / size;
	temp = temp * size;
	// 通道合并
	Mat c3;
	Mat cannyChannels[] = { cf, cf, cf };
	merge(cannyChannels, 3, c3);
	// 类型转化
	Mat tempf;
	temp.convertTo(tempf, CV_32FC3);
	// 图像相乘
	multiply(tempf, c3, tempf);
	// 类型转化
	tempf.convertTo(temp, CV_8UC3);
	return temp;
}

C++测试代码

#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"

using namespace cv;
using namespace std;

cv::Mat Cartoon(cv::Mat src, double clevel, int d, double sigma, int size);

int main()
{
	cv::Mat src = imread("test1.jpg");
	double clevel = 80.;
	int d = 5;
	double sigma = 150.;
	int size = 20;
	cv::Mat result = Cartoon(src, clevel,d,sigma,size);
	imshow("src", src);
	imshow("result", result);
	waitKey(0);
	return 0;
}

// 漫画效果
cv::Mat Cartoon(cv::Mat src, double clevel,int d,double sigma,int size)
{
	// 中值滤波
	cv::Mat m;
	cv::medianBlur(src, m, 7);
	// 提取轮廓
	cv::Mat c;
	clevel = max(40., min(80., clevel));
	cv::Canny(m, c, clevel, clevel *3);
	// 轮廓膨胀加深
	cv::Mat k = getStructuringElement(MORPH_RECT, Size(2, 2));
	cv::dilate(c, c, k);
	// 反转
	c = c / 255;
	c = 1 - c;
	// 类型转化
	cv::Mat cf;
	c.convertTo(cf, CV_32FC1);
	// 均值滤波
	cv::blur(cf, cf, Size(5, 5));
	// 双边滤波
	cv::Mat srcb;
	d = max(0, min(10, d));
	sigma = max(10., min(250., sigma));
	cv::bilateralFilter(src, srcb, d, sigma, sigma);
	size = max(10, min(25, size));
	cv::Mat temp = srcb / size;
	temp = temp * size;
	// 通道合并
	Mat c3;
	Mat cannyChannels[] = { cf, cf, cf };
	merge(cannyChannels, 3, c3);
	// 类型转化
	Mat tempf;
	temp.convertTo(tempf, CV_32FC3);
	// 图像相乘
	multiply(tempf, c3, tempf);
	// 类型转化
	tempf.convertTo(temp, CV_8UC3);
	return temp;
}

测试效果

图1 原图
图2 漫画效果(重)
图3 漫画效果(轻)

       函数对输入的参数作了限制,阈值是由我个人大量测试后设置的,因人而异。clevel阈值40-80,d阈值0-10,sigma阈值10-250,size阈值10-25。效果相比stylization函数一类的方法已经好很多了,后面给大家做一期stylization函数,看看恐怖风漫画是什么样子的哈哈。

       如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~

       如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

© 版权声明
THE END
喜欢就支持一下吧
点赞113 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容