作者:翟天保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;
}
#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;
}
函数对输入的参数作了限制,阈值是由我个人大量测试后设置的,因人而异。clevel阈值40-80,d阈值0-10,sigma阈值10-250,size阈值10-25。效果相比stylization函数一类的方法已经好很多了,后面给大家做一期stylization函数,看看恐怖风漫画是什么样子的哈哈。
如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!
联系客服