Qt 3D的研究(九):尝试另外一种边缘检测方法

原创 2015年03月18日 10:37:34

Qt 3D的研究(九):尝试另外一种边缘检测方法

       三维应用程序,通过FBO,将3D图像渲染成纹理,然后对渲染成的纹理进行图像处理,最终显示在屏幕上的,是风格化后的图案。上一次我使用了一种普通的图像处理方法:索贝尔边缘检测法,与我们的卡通渲染结合起来,实现了这样的效果,接着,我将采用另外一种边缘检测方法——普雷维特(Prewitt)边缘检测方法来重新渲染图案。

蒋彩阳原创文章,首发地址:http://blog.csdn.net/gamesdev/article/details/44405219。欢迎同行前来探讨。

       首先让我们看看上一次的截图:

       我们看到,本不应该是边缘的机身部分,由于离散的调色,被索贝尔算子边缘检测一算,也被误认为是边缘了,同时,在背景与机身颜色不明显的部分,也由于采用不适当的阈值,不被认为是边缘。所以我想有没有一种方法能够解决这个问题呢?于是我采取了这样的方法:

1、 第一遍的render pass,取的不是卡通着色的颜色图,而是深度图;

2、 将深度图渲染至纹理;

3、 对该纹理进行边缘检测;

4、 与卡通着色的图进行叠加,做成效果图。

如何在GLSL中将片元的深度信息提取出来?这里我参考了前辈的博客,然后写出了这样的GLSL代码:

// Depth.vert
#version 100

// Qt 3D默认提供的参数
attribute vec3 vertexPosition;
uniform mat4 modelView;
uniform mat4 mvp;

void main( void )
{
    gl_Position = mvp * vec4( vertexPosition, 1.0 );
}

// Depth.frag
#version 110

// 自己提供的参数

bool inBetween( float v, float min, float max )
{
    return v > min && v < max;
}

void main( void )
{
    float exp = 256.0;
    gl_FragColor = vec4( vec3( pow( gl_FragCoord.z, exp ) ), 1.0);
}

       因为gl_FragCoord.z表示的片元深度信息相互之间非常接近,我们需要一个指数乘幂操作将这样的区别放大,这样才能区分不同的深度的值。

       紧接着,我们将Prewitt算子替换掉Sobel算子,最终的着色器代码如下:

// Ouput.vert
#version 100

// Qt 3D默认提供的参数
attribute vec4 vertexPosition;
uniform mat4 modelMatrix;

// 自己提供的参数

void main( void )
{
    gl_Position = modelMatrix * vertexPosition;
}

// Output.frag
#version 100

// 自己提供的参数
uniform sampler2D colorAttachTex;
//uniform sampler2D depthAttachTex;
uniform vec2 texSize;
uniform float texOffsetX;
uniform float texOffsetY;

float gray( vec4 color )
{
    return dot( color.xyz, vec3( 0.299, 0.587, 0.114 ) );
}

void main( void )
{
    vec4 texColor[9];
    texColor[0] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, texOffsetY ) );
    texColor[1] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
    texColor[2] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, texOffsetY ) );
    texColor[3] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, 0 ) );
    texColor[4] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, 0.0 ) );
    texColor[5] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, 0 ) );
    texColor[6] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( -texOffsetX, -texOffsetY ) );
    texColor[7] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( 0.0, -texOffsetY ) );
    texColor[8] = texture2D( colorAttachTex, gl_FragCoord.xy / texSize + vec2( texOffsetX, -texOffsetY ) );

    // 普雷维特算子
    float prewitt_x[9];
    prewitt_x[0] = -1.0;
    prewitt_x[1] = 0.0;
    prewitt_x[2] = 1.0;
    prewitt_x[3] = -1.0;
    prewitt_x[4] = 0.0;
    prewitt_x[5] = 1.0;
    prewitt_x[6] = -1.0;
    prewitt_x[7] = 0.0;
    prewitt_x[8] = 1.0;

    float prewitt_y[9];
    prewitt_y[0] = 1.0;
    prewitt_y[1] = 1.0;
    prewitt_y[2] = 1.0;
    prewitt_y[3] = 0.0;
    prewitt_y[4] = 0.0;
    prewitt_y[5] = 0.0;
    prewitt_y[6] = -1.0;
    prewitt_y[7] = -1.0;
    prewitt_y[8] = -1.0;

    // 卷积操作
    vec4 edgeX = vec4( 0.0 );
    vec4 edgeY = vec4( 0.0 );
    for ( int i = 0; i < 9; ++i )
    {
        edgeX += texColor[i] * prewitt_x[i];
        edgeY += texColor[i] * prewitt_y[i];
    }

    vec4 edgeColor = sqrt( ( edgeX * edgeX ) + ( edgeY * edgeY ) );
    float edgeIntensity = gray( edgeColor );
    const float threshold = 0.05;

    if ( edgeIntensity > threshold )
        gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
    else discard;
}

       由于代码比较长,我已经将其放至github中。有需要同行朋友们,可以从github中获取代码。地址:这里

如何修改CJlibrary608在VC.net环境下运行

CJlibrary 6.08是一套非常漂亮的用户界面类。为广大的VC用户所欢迎。但是在VC.net下编译的时候报错,需要修改方能运行通过。我已把我修改并编译通过的过程记录下来,供大家参考。下面列出每个...
  • objectman
  • objectman
  • 2003-04-09 09:56:00
  • 807

unity3d shader之Roberts,Sobel,Canny 三种边缘检测方法

三种边缘判断的算法应用到unity3d,用shader表现
  • wolf96
  • wolf96
  • 2015-02-09 14:48:38
  • 4805

图像边缘检测及提取方法总结(含Matlab代码)

写在前面   呼~最近开始入坑图像+机器学习了,学习的过程中遇到了不少不懂的东西,好在自学能力还可以(自恋中= =),所以断断续续也算学会了一些东西~因为这段时间一直在做边缘检测和提取的工作,所以本...
  • LemonXQ
  • LemonXQ
  • 2018-03-26 11:22:14
  • 579

Qt之高仿QQ截图(动态吸附直线)

最近在学Qt。学东西怎么能不动手。 就写了些小程序。看QQ截图能够动态吸附直线的功能挺有意思,所以就模仿了一个。 开发环境:VS2013 Qt5.7.1 先上效果图 界面很简单...
  • caoshangpa
  • caoshangpa
  • 2017-11-27 11:33:16
  • 256

Qt实现窗体在显示屏旁边自动隐藏(类似QQ)

Qt实现窗体在显示屏旁边自动隐藏(类似QQ)看群里有人问这个东西,本人先来无事编以自己的想法实现了下: 其实实现的点子很简单:void AutoHideWidget::leaveEvent(QEve...
  • q862343646
  • q862343646
  • 2016-12-09 10:45:09
  • 1722

qt实现的窗口吸附屏幕边缘,动画隐藏显示的效果,类似于qq主窗口 吸附 隐藏的效果

对于这个效果的实现,其实方法
  • chaney_f
  • chaney_f
  • 2014-09-22 16:04:03
  • 3042

Qt 3D的研究(九):尝试另外一种边缘检测方法

三维应用程序,通过FBO,将3D图像渲染成纹理,然后对渲染成的纹理进行图像处理,最终显示在屏幕上的,是风格化后的图案。上一次我使用了一种普通的图像处理方法:索贝尔边缘检测法,与我们的卡通渲染结合起来,...
  • jiangcaiyang123
  • jiangcaiyang123
  • 2015-03-18 10:37:34
  • 2119

【浅墨著作】《OpenCV3编程入门》内容简介&勘误&配套源代码下载

经过近一年的沉淀和总结,《OpenCV3编程入门》一书终于和大家见面了。最近有为数不少的小伙伴们发邮件给浅墨建议最好在博客里面贴出这本书的目录,方便大家更好的了解这本书的内容。其实最近浅墨实在是有些忙...
  • zhmxy555
  • zhmxy555
  • 2015-03-18 17:53:15
  • 78007

3D 专业词汇

3D API (3D应用程序接口)          Application Programming Interface(API)应用程序接口,是许多程序的大集合。3D API能让编程人员所设计的3...
  • gamedev3d
  • gamedev3d
  • 2014-09-23 17:17:27
  • 371

halcon开发全套资料

b82fbe0790c69ec<em>3d</em>5bb7591.pdf D:\\com\\Halcon...halcon机器视觉<em>软件</em>-7b70e3afdd3383c4bb4cd211.pdf...基于Halcon的SMT_PCB元件缺陷<em>检测</em>.pdf D:\\com\\...
  • 2018年04月11日 00:00
收藏助手
不良信息举报
您举报文章:Qt 3D的研究(九):尝试另外一种边缘检测方法
举报原因:
原因补充:

(最多只允许输入30个字)