Meanshift filter实现简单图片的卡通化效果
利用Meanshift filter和canny边缘检测的效果,可以实现简单的图片的卡通化效果。简单的说,就是用Meanshift filter的结果减去canny算法的结果得到卡通化的效果。
代码如下:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui//highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cv::Mat img = cv::imread("../lenna.jpg");
cv::namedWindow("image");
cv::imshow("image", img);
cv::Mat img1;
img1 = img.clone();
//meanshift filter
cv::pyrMeanShiftFiltering(img1.clone(), img1, 10, 30);
cv::namedWindow("image1");
cv::imshow("image1", img1);
cv::Mat img2;
cv::Mat img3;
cv::Mat img4;
//canny
cv::cvtColor(img, img2, CV_BGR2GRAY);
cv::Canny(img2, img3, 150, 150);
cv::cvtColor(img3, img4, CV_GRAY2BGR);
cv::namedWindow("image4");
cv::imshow("image4", img4);
//卡通化的图片
img4 = img1 - img4;
cv::namedWindow("image4_1");
cv::imshow("image4_1", img4);
cv::waitKey(0);
}
下面分别为,原始图像,meanshift filter后的图像,canny边缘图像,以及最终的卡通化图像。

下面我们看看meanshift filter算法的原理。
在OpenCV中,meanshift filter函数为 pyrMeanShiftFiltering, 它的函数调用格式如下:
C++: void pyrMeanShiftFiltering(InputArray src, OutputArray dst, double sp, double sr, int maxLevel=1, TermCriteriatermcrit=TermCriteria( TermCriteria::MAX_ITER+TermCriteria::EPS,5,1) )
-
Parameters:
- src – The source 8-bit, 3-channel image. //三通道的输入图像
- dst – The destination image of the same format and the same size as the source. //相同尺寸格式输出图像
- sp – The spatial window radius. //空间域半径
- sr – The color window radius. //颜色域半径
- maxLevel – Maximum level of the pyramid for the segmentation. //分割用金字塔的最大层数
- termcrit – Termination criteria: when to stop meanshift iterations. //迭代终止的条件
算法的描述大致如下:
对于输入图像的每个像素点(X,Y) ,在它的半径为sp的空间域,执行meanshift迭代算法,

像素点(X,Y)的颜色值为(R,G,B), 它的空间邻域点(x,y)的颜色值为(r,g,b),如果点(x,y)的到(X,Y)的颜色距离小于sr,则满足条件,最终我们求得满足条件点的平均空间坐标(X’,Y’)以及平均颜色向量(R',G',B'),并把它们作为下一次迭代的输入。

迭代结果后,我们把最初输入位置的颜色值用最终迭代的颜色值代替。

算法代码如下:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui//highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp> #include <iostream>
using namespace std;
using namespace cv; //forward声明
void gMeanShift(int x0, int y0, uchar *sptr, uchar *dptr,
int sstep, cv::Size size, int sp, int sr, int maxIter,
float eps, int *tab); void gMeanShiftFilter(const cv::Mat src, cv::Mat &dst, int sp,
int sr, cv::TermCriteria crit = cv::TermCriteria(
cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 5, 1)); int main()
{
cv::Mat img = cv::imread("../lenna.jpg");
cv::namedWindow("image");
cv::imshow("image", img); cv::Mat img1;
img1 = img.clone();
//meanshift filter
//转化图像为4BGRA 4通道格式
cv::cvtColor(img1.clone(), img1, CV_BGR2BGRA);
gMeanShiftFilter(img1.clone(), img1, 10, 30);
cv::cvtColor(img1.clone(), img1, CV_BGRA2BGR); //meanshift filter result image
cv::namedWindow("image1");
cv::imshow("image1", img1); cv::Mat img2;
cv::Mat img3;
cv::Mat img4; //canny
cv::cvtColor(img, img2, CV_BGR2GRAY);
cv::Canny(img2, img3, 150, 150);
cv::cvtColor(img3, img4, CV_GRAY2BGR); cv::namedWindow("image4");
cv::imshow("image4", img4); img4 = img1 - img4;
cv::namedWindow("image4_1");
cv::imshow("image4_1", img4); cv::waitKey(0);
} void gMeanShift(int x0, int y0, uchar *sptr, uchar *dptr,
int sstep, cv::Size size, int sp, int sr, int maxIter,
float eps, int *tab)
{
int isr2 = sr * sr;
int c0, c1, c2, c3;
int iter;
uchar *ptr = NULL;
uchar *pstart = NULL;
int revx = 0, revy = 0;
c0 = sptr[0];
c1 = sptr[1];
c2 = sptr[2];
c3 = sptr[3]; /****************************************************************************
* Iterate meanshift procedure *
****************************************************************************/
for (iter = 0; iter < maxIter; iter++)
{
int count = 0;
int s0 = 0, s1 = 0, s2 = 0, sx = 0, sy = 0; /****************************************************************************
* mean shift: process pixels in window (p-sigmaSp)x(p+sigmaSp) *
****************************************************************************/
int minx = x0 - sp;
int miny = y0 - sp;
int maxx = x0 + sp;
int maxy = y0 + sp; /****************************************************************************
* Deal with the image boundary. *
****************************************************************************/
if (minx < 0)
{
minx = 0;
}
if (miny < 0)
{
miny = 0;
}
if (maxx >= size.width)
{
maxx = size.width - 1;
}
if (maxy >= size.height)
{
maxy = size.height - 1;
}
if (iter == 0)
{
pstart = sptr;
}
else
{
pstart = pstart + revy * sstep + (revx << 2); //point to the new position
}
ptr = pstart;
//point to the start in the row
ptr = ptr + (miny - y0) * sstep + ((minx - x0) << 2);
for (int y = miny; y <= maxy; y++, ptr += sstep - ((maxx - minx + 1) << 2))
{
int rowCount = 0;
int temp, temp1;
temp1 = (maxx - minx + 1) << 2;
temp = sstep - ((maxx - minx + 1) << 2);
int x = minx;
for (; x <= maxx; x++, ptr += 4)
{
int t0 = ptr[0], t1 = ptr[1], t2 = ptr[2];
if (tab[t0 - c0 + 255] + tab[t1 - c1 + 255] + tab[t2 - c2 + 255] <= isr2)
{
s0 += t0;
s1 += t1;
s2 += t2;
sx += x;
rowCount++;
}
}
if (rowCount == 0)
{
continue;
}
count += rowCount;
sy += y * rowCount;
}
if (count == 0)
{
break;
} int x1 = sx / count;
int y1 = sy / count;
s0 = s0 / count;
s1 = s1 / count;
s2 = s2 / count; bool stopFlag = (x0 == x1 && y0 == y1) || (abs(x1 - x0) + abs(y1 - y0) +
tab[s0 - c0 + 255] + tab[s1 - c1 + 255] + tab[s2 - c2 + 255] <= eps); /****************************************************************************
* Revise the pointer corresponding to the new (y0,x0) *
****************************************************************************/
//
revx = x1 - x0;
revy = y1 - y0; x0 = x1;
y0 = y1;
c0 = s0;
c1 = s1;
c2 = s2; if (stopFlag)
{
break;
} } dptr[0] = (uchar)c0;
dptr[1] = (uchar)c1;
dptr[2] = (uchar)c2;
dptr[3] = (uchar)c3;
} void gMeanShiftFilter(const cv::Mat src, cv::Mat &dst,
int sp, int sr, cv::TermCriteria crit)
{
if (src.empty())
{
cout << "Source is null" << endl;
} if (!(crit.type & cv::TermCriteria::MAX_ITER))
{
crit.maxCount = 5;
}
int maxIter = std::min(std::max(crit.maxCount, 1), 100);
float eps;
if (!(crit.type & cv::TermCriteria::EPS))
{
eps = 1.f;
}
eps = (float)std::max(crit.epsilon, 0.0); int tab[512];
for (int i = 0; i < 512; i++)
{
tab[i] = (i - 255) * (i - 255);
}
uchar *sptr = src.data;
uchar *dptr = dst.data;
int sstep = (int)src.step;
int dstep = (int)dst.step;
cv::Size size = src.size(); for (int i = 0; i < size.height; i++, sptr += sstep - (size.width << 2),
dptr += dstep - (size.width << 2))
{
int tt, tt1;
tt = size.width << 2;
tt1 = sstep - (size.width << 2);
for (int j = 0; j < size.width; j++, sptr += 4, dptr += 4)
{
gMeanShift(j, i, sptr, dptr, sstep, size, sp,
sr, maxIter, eps, tab);
}
}
}
Meanshift filter实现简单图片的卡通化效果的更多相关文章
- js简单 图片版时钟,带翻转效果
js简单 图片版时钟,带翻转效果 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- 3-5 编程练习:jQuery实现简单的图片对应展示效果
3-5 编程练习:jQuery实现简单的图片对应展示效果 通过这个章节的学习, 老师带领大家完成了一个基本的图片切换特效,接下来,我们也实现一个类似的效果,点击相应的按钮,切换对应的图片. 效果图 : ...
- JQuery图片切换动画效果
由于博主我懒,所以页面画的比较粗糙,但是没关系,因为我主要讲的是如何实现图片动画切换. 思路:想必大家都逛过淘宝或者其他的一些网站,一般都会有图片动画切换的效果,那是怎样实现的呢?博主我呢,技术不是很 ...
- 纯CSS3写的10个不同的酷炫图片遮罩层效果【转】
这个是纯CSS3实现的的10个不同的酷炫图片遮罩层效果,可以欣赏一下 在线预览 下载地址 实例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
- 纯CSS3写的10个不同的酷炫图片遮罩层效果
这个是纯CSS3实现的的10个不同的酷炫图片遮罩层效果,可以欣赏一下 在线预览 下载地址 实例代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...
- Page Scroll Effects - 简单的页面滚动效果
Codyhouse 收集了一组页面滚动效果,就是目前大家很常见的用户在浏览网页的时候.一些效果虽然极端,但如果你的目标是创建一个身临其境的用户体验,他们是非常有用的.所有的动画都使用 Velocity ...
- jQuery演示10种不同的切换图片列表动画效果以及tab动画演示 2
很常用的一款特效纯CSS完成tab实现5种不同切换对应内容效果 实例预览 下载地址 实例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ...
- 用仿ActionScript的语法来编写html5——第八篇,图片处理+粒子效果
用仿ActionScript的语法来编写html5系列开发到现在,应该可以做出一些东西了,下面先来研究下图片的各种效果预览各种效果看下图效果和代码看这里,看不到效果的请下载支持html5的浏览器 ht ...
- JS实现图片翻书效果示例代码
js 图片翻书效果. picture.html <html xmlns="http://www.w3.org/1999/xhtml"> <head> ...
随机推荐
- Thrift中实现按照时间戳范围操作Hbase数据
在一次做项目的过程中,要实现一个功能,功能描述为前端给定日期范围,在该日期范围内取出指定行的信息.在Thrift常用的API中,取出一行所有的数据接口为getVer(),getver()具体描述如下: ...
- NET Framework 4.0的安装失败处理
如果是XP系统,这么做:1.开始——运行——输入cmd——回车——在打开的窗口中输入net stop WuAuServ2.开始——运行——输入%windir%3.在打开的窗口中有个文件夹叫Softwa ...
- js 获取、清空 input type="file"的值 .(转)
上传控件基础知识说明: 上传控件(<input type="file"/>)用于在客户端浏览并上传文件,用户选取的路径可以由value属性获取,但value属性是只读的 ...
- freeCodeCamp:Repeat a string repeat a string
重复一个指定的字符串 num次,如果num是一个负数则返回一个空字符串. /*思路 fo循环将字符串重复num次并组成数组 将数组组成新的字符串并返回 */ function repeat(str, ...
- P1147连续自然数和
洛谷1147 连续自然数和 题目描述 对一个给定的自然数M,求出所有的连续的自然数段,这些连续的自然数段中的全部数之和为M. 例子:1998+1999+2000+2001+2002 = 10000,所 ...
- Xcode升级更新后,恢复cocoapods以及插件的方法
今天将手机系统更新到iOS9.3了,在Xcode7.1上做真机调试,提示找不到适合的SDK,才知道必须要升级Xcode才行,于是升级Xcode到7.3. 升级之后遇到很多麻烦,cocoapods没有了 ...
- 在Linux中让打印带颜色的字
echo显示带颜色,需要使用参数-e 格式如下: echo -e "\033[字背景颜色;文字颜色m字符串\033[0m" 例如: echo -e "\033[41;37 ...
- spring 框架通过new Object()获取applicationContext 中的bean方案
工作中,需要手动创建一个对象,但用到了spring容器中对象的业务逻辑,这时候就要去通过获取容器中的对象.这时候,可以通过实例化一个实现了ApplicationContextAware接口的类获取sp ...
- xvfb启动PyQt4程序报Unable to load library icui18n错误
xvfb启动PyQt4程序报如下错误: Unable to load library icui18n "Cannot load library icui18n: (libicui18n.so ...
- oracle11g数据库的安装以及安装之后的配置
1.按照正常的顺序进行安装,然后安装完成后可以对用户进行管理,(设置sys sysmanager的口令,激活scott的用户并设置新密码) 这一步没什么好多的,关键是进行安装完成之后的配置,这个就比 ...