使用OpenGL ES在C/C++中实现Sobel滤波器
Sobel filter in C/C++ using OpenGL ES
如果没有必要,我宁愿不重新创建轮子,而且这一定是以前做过的。有没有使用OpenGL ES实现Sobel过滤器?
如果Objective-C是可接受的,您可以查看我的GPUImage框架及其GPUImageSobelEdgeDetectionFilter。这适用于使用OpenGL ES 2.0片段着色器的Sobel边缘检测。你可以在这个答案的"草图"示例中看到它的输出。
如果您不想深入研究Objective-C代码,这里的关键工作由两组着色器执行。在第一次扫描中,我将图像降低到其亮度,并将该值存储在红色、绿色和蓝色通道中。我使用以下顶点着色器来完成此操作:
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
和片段着色器:
precision highp float;
varying vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
void main()
{
float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W);
gl_FragColor = vec4(vec3(luminance), 1.0);
}
之后,我使用以下顶点着色器实际执行Sobel边缘检测(在这种情况下,较轻的像素是边缘):
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
uniform highp float imageWidthFactor;
uniform highp float imageHeightFactor;
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
void main()
{
gl_Position = position;
vec2 widthStep = vec2(imageWidthFactor, 0.0);
vec2 heightStep = vec2(0.0, imageHeightFactor);
vec2 widthHeightStep = vec2(imageWidthFactor, imageHeightFactor);
vec2 widthNegativeHeightStep = vec2(imageWidthFactor, -imageHeightFactor);
textureCoordinate = inputTextureCoordinate.xy;
leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;
rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;
topTextureCoordinate = inputTextureCoordinate.xy + heightStep;
topLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;
topRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;
bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep;
bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;
bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;
}
以及这个片段着色器:
precision highp float;
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
uniform sampler2D inputImageTexture;
void main()
{
float i00 = texture2D(inputImageTexture, textureCoordinate).r;
float im1m1 = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
float ip1p1 = texture2D(inputImageTexture, topRightTextureCoordinate).r;
float im1p1 = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
float ip1m1 = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
float im10 = texture2D(inputImageTexture, leftTextureCoordinate).r;
float ip10 = texture2D(inputImageTexture, rightTextureCoordinate).r;
float i0m1 = texture2D(inputImageTexture, bottomTextureCoordinate).r;
float i0p1 = texture2D(inputImageTexture, topTextureCoordinate).r;
float h = -im1p1 - 2.0 * i0p1 - ip1p1 + im1m1 + 2.0 * i0m1 + ip1m1;
float v = -im1m1 - 2.0 * im10 - im1p1 + ip1m1 + 2.0 * ip10 + ip1p1;
float mag = length(vec2(h, v));
gl_FragColor = vec4(vec3(mag), 1.0);
}
CCD_ 1和CCD_ 2仅仅是以像素为单位的输入图像大小的倒数。
您可能会注意到,这种两次通过的方法比上面链接的答案中的方法更复杂。这是因为当在移动GPU上运行时,最初的实现并不是最高效的(至少是iOS设备中的PowerVR)。通过删除所有依赖的纹理读取并预先计算亮度,这样我只需要从最终着色器中的红色通道进行采样,这种调整后的边缘检测方法在我的基准测试中比一次性完成所有这些的原始方法快20倍。
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- 使用OpenGL ES在C/C++中实现Sobel滤波器