我有160x120二进制图像,例如:



我想检测那些白色斑点的角。它们以前是通过数学形态封闭的,因此不应有任何内角。在这种特定情况下,我想要16个角,例如:非常不稳定)。我的想法是在GPU上进行这样的计算,因为我的源图像来自它。我在网上寻找有关如何编写此类着色器的想法(我使用的是OpenGL ES 2.0),但没有发现任何具体的想法。知道如何启动这样的算法吗?

评论

FAST慢吗? :)

是的,有趣吗?实际上,它比诸如SURF或SIFT之类的先前算法要快,但是它精度较低,从一个图像到另一个图像相当不稳定,并且仍然不够快,无法在CPU上完成
在每个帧上准确检测这些错误有多重要?矩形移动速度有多快?是否可以检测大多数帧的拐角并将其插值到算法遗漏的帧上?

@just很好,我现在的方式(通过使用OpenCV的cvFindContours()和cvApproxPoly()函数)随着时间的推移不是很稳定,所以我用低通滤波器对结果进行滤波,引入了滞后。您认为插值可以得到更稳定的结果吗?

#1 楼

您正在处理什么尺寸的图像?以什么帧速率?在什么硬件上?根据我的经验,FAST很漂亮,很容易实现。 image。

“ Harris”角检测器也可能非常快,因为它由非常简单的操作组成(例如,每个像素没有sqrt()!)-不如gFTT稳定,但可能

(就GPU的实现而言,谷歌搜索gpu corner似乎提供了很多链接,但我不知道它们的适用性-我倾向于在FPGA中实现。)

评论


$ \ begingroup $
我的图像在iPhone上的分辨率为160x120,以30fps的速度拍摄,但是该应用程序还有很多工作要做:-)我已经看到一个应用程序在这样的设备上实现FAST的速度非常快,只是一个演示而已,仅此而已...这就是为什么我希望使用基于GPU的解决方案。
$ \ endgroup $
–StéphanePéchard
2011年10月12日上午9:50

#2 楼

我只是碰巧使用Harris角检测在OpenGL ES 2.0上实现了类似的功能,虽然还没有完全完成,但我想我会分享到目前为止的基于着色器的实现。我已经将此操作作为基于iOS的开源框架的一部分,因此,如果您对某些特定步骤的工作方式感到好奇,可以查看代码。

为此,我使用请执行以下步骤:


使用RGB值与矢量(0.2125,0.7154,0.0721)的点积将图像降低到其亮度值。

通过从当前像素左右,上下左右像素减去红色通道值来计算X和Y导数。然后,我将x导数平方存储在红色通道中,将Y导数平方存储在绿色通道中,将X和Y导数的乘积存储在蓝色通道中。片段着色器如下所示:

precision highp float;

varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;

varying vec2 topTextureCoordinate; 
varying vec2 bottomTextureCoordinate;

uniform sampler2D inputImageTexture;

void main()
{
 float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
 float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
 float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
 float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;

 float verticalDerivative = abs(-topIntensity + bottomIntensity);
 float horizontalDerivative = abs(-leftIntensity + rightIntensity);

 gl_FragColor = vec4(horizontalDerivative * horizontalDerivative, verticalDerivative * verticalDerivative, verticalDerivative * horizontalDerivative, 1.0);
}


其中变化只是每个方向上的偏移纹理坐标。我在顶点着色器中对其进行了预先计算,以消除依赖的纹理读取,而这些读取在这些移动GPU上异常缓慢。

对此衍生图像应用高斯模糊。我使用了水平和垂直分离的模糊处理,并利用硬件纹理过滤的优势进行了一次9次模糊处理,每遍仅读取了五个纹理。我在此Stack Overflow答案中描述了此着色器。

使用模糊的输入导数值运行实际的Harris角点检测计算。在这种情况下,我实际上是使用Alison Noble在其博士学位中描述的计算方法。论文“图像表面的描述”。处理此问题的着色器如下所示:

varying highp vec2 textureCoordinate;

uniform sampler2D inputImageTexture;

const mediump float harrisConstant = 0.04;

void main()
{
 mediump vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;

 mediump float derivativeSum = derivativeElements.x + derivativeElements.y;

 // This is the Noble variant on the Harris detector, from 
 // Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45.     
 mediump float harrisIntensity = (derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z)) / (derivativeSum);

 // Original Harris detector
 //     highp float harrisIntensity = derivativeElements.x * derivativeElements.y - (derivativeElements.z * derivativeElements.z) - harrisConstant * derivativeSum * derivativeSum;

 gl_FragColor = vec4(vec3(harrisIntensity * 10.0), 1.0);
}



执行局部非最大抑制并应用阈值以突出显示通过的像素。我使用以下片段着色器对中心像素附近的八个像素进行采样,并确定该像素是否在该分组中最大:

uniform sampler2D inputImageTexture;

varying highp vec2 textureCoordinate;
varying highp vec2 leftTextureCoordinate;
varying highp vec2 rightTextureCoordinate;

varying highp vec2 topTextureCoordinate;
varying highp vec2 topLeftTextureCoordinate;
varying highp vec2 topRightTextureCoordinate;

varying highp vec2 bottomTextureCoordinate;
varying highp vec2 bottomLeftTextureCoordinate;
varying highp vec2 bottomRightTextureCoordinate;

void main()
{
    lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;
    lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
    lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
    lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
    lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;
    lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;
    lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;
    lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;
    lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;

    // Use a tiebreaker for pixels to the left and immediately above this one
    lowp float multiplier = 1.0 - step(centerColor.r, topColor);
    multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);
    multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);
    multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);

    lowp float maxValue = max(centerColor.r, bottomColor);
    maxValue = max(maxValue, bottomRightColor);
    maxValue = max(maxValue, rightColor);
    maxValue = max(maxValue, topRightColor);

    gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);
}



此过程从您的对象生成一个如下所示的拐角图:



为该滤镜设置了适当的阈值,尽管它确实倾向于将拐角放置在实际图像中一个像素左右,但它可以识别出图像中的所有16个拐角。对象的边缘。

在iPhone 4上,此角点检测可以以20 FPS的速度运行于来自相机的640x480帧视频,iPhone 4S可以轻松处理60 + FPS。对于这样的任务,这应该比CPU约束处理快很多,尽管现在读取点的过程是CPU约束的,并且比它应该的要慢一些。

如果您希望看到此功能,可以获取我的框架的代码并运行其随附的FilterShowcase示例。哈里斯拐角检测示例在设备摄像头的实时视频上运行,尽管正如我提到的,拐角点的读取当前发生在CPU上,这确实减慢了速度。我也正在为此使用基于GPU的过程。

评论


$ \ begingroup $
非常好!我在github上遵循您的框架,恭喜!
$ \ endgroup $
–StéphanePéchard
2012年5月2日,11:45

$ \ begingroup $
在某个地方有一个示例如何将角坐标实际返回给CPU?是否有某种智能GPU方式,或者是否需要回读,然后通过返回的位图在CPU上循环以查找标记的像素?
$ \ endgroup $
– Quasimondo
2014年1月8日在16:56

$ \ begingroup $
@Quasimondo-我一直在使用直方图金字塔进行点提取:tevs.eu/files/vmv06.pdf,以避免在角点检测中像素上CPU约束的迭代。最近有点分心,所以还没有完成,但是我想尽快。
$ \ endgroup $
–布拉德·拉森(Brad Larson)
2014年1月8日在17:01



$ \ begingroup $
@BradLarson,您好,我知道这是一个非常老的话题,感谢您的回答。我刚刚在GPUImage框架中检查了KGPUImageHarrisCornerDetection.m。要从图像中提取角位置,您已使用glReadPixels将图像读入缓冲区,然后在缓冲区上循环以将colotByte> 0的点存储在数组中。有什么方法可以在GPU中完成所有操作,而不必在缓冲区和循环中读取图像?
$ \ endgroup $
– Sahil Bajaj
17/12/26在10:16

$ \ begingroup $
@SahilBajaj-我见过(但尚未实现)的一种技术是使用直方图金字塔从像这样的稀疏图像中快速提取点。这将大大加快速度。
$ \ endgroup $
–布拉德·拉森(Brad Larson)
17-12-27 at 2:32

#3 楼

众所周知,像Shi-Tomasi和Moravec这样的“稳健”转角检测器速度很慢。
在这里检查它们-http://en.wikipedia.org/wiki/Corner_detection
FAST可能是唯一足够好的轻巧型角检测器。您可以通过进行非最大抑制来改善FAST-选择具有最佳“拐角”得分的FAST输出(有几种直观的计算方法,包括Shi-Tomasi和Moravec作为拐角得分)
您还可以选择几个FAST检测器-从FAST-5到FAST-12和FAST_ER(最后一个可能对于移动设备来说太大了)
另一种方法是获取生成的FAST-从作者网站获取FAST代码生成器并将其训练在可能的图像。
http://www.edwardrosten.com/work/fast.html

#4 楼

不是真正的GPU专用,但是Steve Smith的SUSAN算法非常适合角点检测。

该算法非常简单,如C中的源代码所示。