卡通滤波
来源:互联网 发布:报社上班 知乎 编辑:程序博客网 时间:2024/04/26 13:43
Here is a new entry in the GLSL Shader Library: a toonify post processing filter. This filter creates a cartoon version of an image. You can use the mouse (the vertical red line) to see the difference between the original and toonified versions of the image.
It would be interesting to update this shader with another edge detector. I’ll do it later.
A demo for GLSL Hacker is available in the host_api/PostFX/Toon/ folder of the code sample pack. The latest GLSL Hacker can be downloaded from this page.
As usual, this shader can be used in any OpenGL-based app with extremely minor changes only.
Here is the GLSL fragment shader (for OpenGL 3.2+):
#version 150uniform sampler2D tex0;uniform float mouse_x_offset; // 0.5in vec4 Vertex_UV;out vec4 FragColor;uniform float edge_thres; // 0.2;uniform float edge_thres2; // 5.0;#define HueLevCount 6#define SatLevCount 7#define ValLevCount 4float[HueLevCount] HueLevels = float[] (0.0,140.0,160.0,240.0,240.0,360.0);float[SatLevCount] SatLevels = float[] (0.0,0.15,0.3,0.45,0.6,0.8,1.0);float[ValLevCount] ValLevels = float[] (0.0,0.3,0.6,1.0);vec3 RGBtoHSV( float r, float g, float b) { float minv, maxv, delta; vec3 res; minv = min(min(r, g), b); maxv = max(max(r, g), b); res.z = maxv; // v delta = maxv - minv; if( maxv != 0.0 ) res.y = delta / maxv; // s else { // r = g = b = 0 // s = 0, v is undefined res.y = 0.0; res.x = -1.0; return res; } if( r == maxv ) res.x = ( g - b ) / delta; // between yellow & magenta else if( g == maxv ) res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow else res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan res.x = res.x * 60.0; // degrees if( res.x < 0.0 ) res.x = res.x + 360.0; return res;}vec3 HSVtoRGB(float h, float s, float v ) { int i; float f, p, q, t; vec3 res; if( s == 0.0 ) { // achromatic (grey) res.x = v; res.y = v; res.z = v; return res; } h /= 60.0; // sector 0 to 5 i = int(floor( h )); f = h - float(i); // factorial part of h p = v * ( 1.0 - s ); q = v * ( 1.0 - s * f ); t = v * ( 1.0 - s * ( 1.0 - f ) ); switch(i) { case 0: res.x = v; res.y = t; res.z = p; break; case 1: res.x = q; res.y = v; res.z = p; break; case 2: res.x = p; res.y = v; res.z = t; break; case 3: res.x = p; res.y = q; res.z = v; break; case 4: res.x = t; res.y = p; res.z = v; break; default: // case 5: res.x = v; res.y = p; res.z = q; break; } return res;}float nearestLevel(float col, int mode) { int levCount; if (mode==0) levCount = HueLevCount; if (mode==1) levCount = SatLevCount; if (mode==2) levCount = ValLevCount; for (int i =0; i<levCount-1; i++ ) { if (mode==0) { if (col >= HueLevels[i] && col <= HueLevels[i+1]) { return HueLevels[i+1]; } } if (mode==1) { if (col >= SatLevels[i] && col <= SatLevels[i+1]) { return SatLevels[i+1]; } } if (mode==2) { if (col >= ValLevels[i] && col <= ValLevels[i+1]) { return ValLevels[i+1]; } } }}// averaged pixel intensity from 3 color channelsfloat avg_intensity(vec4 pix) { return (pix.r + pix.g + pix.b)/3.;}vec4 get_pixel(vec2 coords, float dx, float dy) { return texture(tex0,coords + vec2(dx, dy));}// returns pixel colorfloat IsEdge(in vec2 coords){ float dxtex = 1.0 /float(textureSize(tex0,0)) ; float dytex = 1.0 /float(textureSize(tex0,0)); float pix[9]; int k = -1; float delta; // read neighboring pixel intensities for (int i=-1; i<2; i++) { for(int j=-1; j<2; j++) { k++; pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex, float(j)*dytex)); } } // average color differences around neighboring pixels delta = (abs(pix[1]-pix[7])+ abs(pix[5]-pix[3]) + abs(pix[0]-pix[8])+ abs(pix[2]-pix[6]) )/4.; //return clamp(5.5*delta,0.0,1.0); return clamp(edge_thres2*delta,0.0,1.0);}void main(){ vec2 uv = Vertex_UV.xy; vec4 tc = vec4(1.0, 0.0, 0.0, 1.0); if (uv.x > (mouse_x_offset+0.002)) { vec3 colorOrg = texture(tex0, uv).rgb; vec3 vHSV = RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b); vHSV.x = nearestLevel(vHSV.x, 0); vHSV.y = nearestLevel(vHSV.y, 1); vHSV.z = nearestLevel(vHSV.z, 2); float edg = IsEdge(uv); vec3 vRGB = (edg >= edge_thres)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z); tc = vec4(vRGB.x,vRGB.y,vRGB.z, 1); } else if (uv.x < (mouse_x_offset-0.002)) { tc = texture(tex0, uv); } FragColor = tc;}
Credits: this shader is based on this coding experiment.
Here is a new entry in the GLSL Shader Library: a toonify post processing filter. This filter creates a cartoon version of an image. You can use the mouse (the vertical red line) to see the difference between the original and toonified versions of the image.
It would be interesting to update this shader with another edge detector. I’ll do it later.
A demo for GLSL Hacker is available in the host_api/PostFX/Toon/ folder of the code sample pack. The latest GLSL Hacker can be downloaded from this page.
As usual, this shader can be used in any OpenGL-based app with extremely minor changes only.
Here is the GLSL fragment shader (for OpenGL 3.2+):
#version 150uniform sampler2D tex0;uniform float mouse_x_offset; // 0.5in vec4 Vertex_UV;out vec4 FragColor;uniform float edge_thres; // 0.2;uniform float edge_thres2; // 5.0;#define HueLevCount 6#define SatLevCount 7#define ValLevCount 4float[HueLevCount] HueLevels = float[] (0.0,140.0,160.0,240.0,240.0,360.0);float[SatLevCount] SatLevels = float[] (0.0,0.15,0.3,0.45,0.6,0.8,1.0);float[ValLevCount] ValLevels = float[] (0.0,0.3,0.6,1.0);vec3 RGBtoHSV( float r, float g, float b) { float minv, maxv, delta; vec3 res; minv = min(min(r, g), b); maxv = max(max(r, g), b); res.z = maxv; // v delta = maxv - minv; if( maxv != 0.0 ) res.y = delta / maxv; // s else { // r = g = b = 0 // s = 0, v is undefined res.y = 0.0; res.x = -1.0; return res; } if( r == maxv ) res.x = ( g - b ) / delta; // between yellow & magenta else if( g == maxv ) res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow else res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan res.x = res.x * 60.0; // degrees if( res.x < 0.0 ) res.x = res.x + 360.0; return res;}vec3 HSVtoRGB(float h, float s, float v ) { int i; float f, p, q, t; vec3 res; if( s == 0.0 ) { // achromatic (grey) res.x = v; res.y = v; res.z = v; return res; } h /= 60.0; // sector 0 to 5 i = int(floor( h )); f = h - float(i); // factorial part of h p = v * ( 1.0 - s ); q = v * ( 1.0 - s * f ); t = v * ( 1.0 - s * ( 1.0 - f ) ); switch(i) { case 0: res.x = v; res.y = t; res.z = p; break; case 1: res.x = q; res.y = v; res.z = p; break; case 2: res.x = p; res.y = v; res.z = t; break; case 3: res.x = p; res.y = q; res.z = v; break; case 4: res.x = t; res.y = p; res.z = v; break; default: // case 5: res.x = v; res.y = p; res.z = q; break; } return res;}float nearestLevel(float col, int mode) { int levCount; if (mode==0) levCount = HueLevCount; if (mode==1) levCount = SatLevCount; if (mode==2) levCount = ValLevCount; for (int i =0; i<levCount-1; i++ ) { if (mode==0) { if (col >= HueLevels[i] && col <= HueLevels[i+1]) { return HueLevels[i+1]; } } if (mode==1) { if (col >= SatLevels[i] && col <= SatLevels[i+1]) { return SatLevels[i+1]; } } if (mode==2) { if (col >= ValLevels[i] && col <= ValLevels[i+1]) { return ValLevels[i+1]; } } }}// averaged pixel intensity from 3 color channelsfloat avg_intensity(vec4 pix) { return (pix.r + pix.g + pix.b)/3.;}vec4 get_pixel(vec2 coords, float dx, float dy) { return texture(tex0,coords + vec2(dx, dy));}// returns pixel colorfloat IsEdge(in vec2 coords){ float dxtex = 1.0 /float(textureSize(tex0,0)) ; float dytex = 1.0 /float(textureSize(tex0,0)); float pix[9]; int k = -1; float delta; // read neighboring pixel intensities for (int i=-1; i<2; i++) { for(int j=-1; j<2; j++) { k++; pix[k] = avg_intensity(get_pixel(coords,float(i)*dxtex, float(j)*dytex)); } } // average color differences around neighboring pixels delta = (abs(pix[1]-pix[7])+ abs(pix[5]-pix[3]) + abs(pix[0]-pix[8])+ abs(pix[2]-pix[6]) )/4.; //return clamp(5.5*delta,0.0,1.0); return clamp(edge_thres2*delta,0.0,1.0);}void main(){ vec2 uv = Vertex_UV.xy; vec4 tc = vec4(1.0, 0.0, 0.0, 1.0); if (uv.x > (mouse_x_offset+0.002)) { vec3 colorOrg = texture(tex0, uv).rgb; vec3 vHSV = RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b); vHSV.x = nearestLevel(vHSV.x, 0); vHSV.y = nearestLevel(vHSV.y, 1); vHSV.z = nearestLevel(vHSV.z, 2); float edg = IsEdge(uv); vec3 vRGB = (edg >= edge_thres)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z); tc = vec4(vRGB.x,vRGB.y,vRGB.z, 1); } else if (uv.x < (mouse_x_offset-0.002)) { tc = texture(tex0, uv); } FragColor = tc;}
Credits: this shader is based on this coding experiment.
- 卡通滤波
- 卡通着色
- 滤波
- 滤波
- 滤波
- 滤波
- 滤波
- 滤波
- 滤波
- 卡通渲染最新进展汇报
- 个人卡通自画像软件
- ShaderSimpler(3) : 卡通渲染
- 多媒体、卡通网站
- 平淡生活:卡通快乐
- 可爱周杰伦卡通代码
- 我的卡通形象
- 超雷人卡通明星脸
- GLSL 卡通着色
- 关于对象引用
- 从如何解决问题到如何学习算法
- ecshop二次开发--放大镜2
- Android-xUtils框架原理分析
- VS2013的Release模式下进行调试 .
- 卡通滤波
- 212. Word Search II--python
- 不同系统下运行jar方法,以及设置内存
- Android textview改变部分文字的颜色和string.xml中文字的替换
- Java总结篇系列:Java泛型 转自 Corn
- SpringMVC学习笔记之SpringMVC的架构原理图
- Tab 选项卡
- Cocoapods 执行不同的版本,安装多个版本
- 自定义类加载器(实现加密和解密)