美文网首页
Android基于Shader的图像处理(5)-Canny边缘检

Android基于Shader的图像处理(5)-Canny边缘检

作者: andev009 | 来源:发表于2018-09-22 16:41 被阅读68次

    完整代码位置:AndroidShaderDemo

    下面两篇文章对Canny边界探测算法描述的很好,可以查看了解下原理。这里重点讲的是在Android里通过Shader实现。
    Canny边界探测算法
    边缘检测之Canny

    android-gpuimage里没有实现Canny边缘检测,在网上查了很多,大都是OpenCV,C++等版本实现,没有看到在Android里通过Shader实现,这里研究了下ios版的gpuimage,写了个Android版的,为了清楚表示各个步骤,代码没有封装,最后效果和OpenCV的比有一定差距,有哪位提出改进更好。
    主要实现在CannyRender.java

    Canny边缘检测主要有以下几个步骤:
    1、使用高斯滤波器,以平滑图像,滤除噪声,生成灰度图。
    2、使用Sobel滤波器,计算每个像素点的梯度强度和方向。
    3、用非极大值(Non-Maximum Suppression)抑制,以消除边缘检测带来的杂散响应。
    4、应用双阈值(Double-Threshold)检测来确定真实的和潜在的边缘。
    5、通过抑制孤立的弱边缘最终完成边缘检测。

    在CannyRender的onDrawFrame方法里,分别用gaussianProgram,sobelProgram,nonmaximumSuppressionProgram,weakPixelInclusionProgram这4个Program完成以上工作。因为需要4次渲染,前三次分别渲染到3个帧缓存,最后一次渲染到屏幕。onDrawFrame方法如下:

    @Override
        public void onDrawFrame(GL10 gl) {
            glClear(GL_COLOR_BUFFER_BIT);
    
            //render to framebuffer0,gaussian and gray
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[0]);
            GLES20.glClearColor(0, 0, 0, 0);
    
            gaussianProgram.useProgram();
            gaussianProgram.setUniforms(textureIDs[0], 1.0f / width, 1.0f / height);
    
            vertexArray.setVertexAttribPointer(
                    0,
                    gaussianProgram.getPositionAttributeLocation(),
                    POSITION_COMPONENT_COUNT,
                    STRIDE);
    
            vertexArray.setVertexAttribPointer(
                    POSITION_COMPONENT_COUNT,
                    gaussianProgram.getTextureCoordinatesAttributeLocation(),
                    TEXTURE_COORDINATES_COMPONENT_COUNT,
                    STRIDE);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    
            //render to framebuffer1, sobel
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[1]);
            GLES20.glClearColor(0, 0, 0, 0);
    
            sobelProgram.useProgram();
            sobelProgram.setUniforms(mFrameBufferTextures[0], 1.0f / width, 1.0f / height);
    
            vertexArray.setVertexAttribPointer(
                    0,
                    sobelProgram.getPositionAttributeLocation(),
                    POSITION_COMPONENT_COUNT,
                    STRIDE);
    
            vertexArray.setVertexAttribPointer(
                    POSITION_COMPONENT_COUNT,
                    sobelProgram.getTextureCoordinatesAttributeLocation(),
                    TEXTURE_COORDINATES_COMPONENT_COUNT,
                    STRIDE);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    
            //render to framebuffer2, NonmaximumSuppression
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[2]);
            GLES20.glClearColor(0, 0, 0, 0);
    
            nonmaximumSuppressionProgram.useProgram();
            nonmaximumSuppressionProgram.setUniforms(mFrameBufferTextures[1], 1.0f / width, 1.0f / height);
    
            vertexArray.setVertexAttribPointer(
                    0,
                    nonmaximumSuppressionProgram.getPositionAttributeLocation(),
                    POSITION_COMPONENT_COUNT,
                    STRIDE);
    
            vertexArray.setVertexAttribPointer(
                    POSITION_COMPONENT_COUNT,
                    nonmaximumSuppressionProgram.getTextureCoordinatesAttributeLocation(),
                    TEXTURE_COORDINATES_COMPONENT_COUNT,
                    STRIDE);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    
            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    
            //render to screen,weakPixelInclusion
            weakPixelInclusionProgram.useProgram();
            weakPixelInclusionProgram.setUniforms(mFrameBufferTextures[2], 1.0f / width, 1.0f / height);
    
            flipVertexArray.setVertexAttribPointer(
                    0,
                    weakPixelInclusionProgram.getPositionAttributeLocation(),
                    POSITION_COMPONENT_COUNT,
                    STRIDE);
    
            flipVertexArray.setVertexAttribPointer(
                    POSITION_COMPONENT_COUNT,
                    weakPixelInclusionProgram.getTextureCoordinatesAttributeLocation(),
                    TEXTURE_COORDINATES_COMPONENT_COUNT,
                    STRIDE);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
        }
    

    最终渲染结果如下,图片压缩后效果不好:


    canny.png

    相关文章

      网友评论

          本文标题:Android基于Shader的图像处理(5)-Canny边缘检

          本文链接:https://www.haomeiwen.com/subject/xfdxoftx.html