着重介绍了阈值二值化及ostu二值化的实现,算法本身很简单,主要是将算法并行化,有点费事,同时也注意到了对于时序性较强的算法,cuda移植后性能并不会得到大幅度提升,提升往往在10倍左右,值得深思。
阈值二值化
阈值二值化,这里是指阈值是人为设定的,简单的二值化,鲁棒性低,但计算量小。
1 |
|
这个算法非常简单,设置与图像像素数一样的thread,thread读取每个像素值,直接进行判断,这里使用分支语句的影响很小,貌似可以被编译器优化,不必太担心效率。 而且通过适当的参数设置(见代码中的注释部分),可以得到与opencv中threshold函数一样的效果。
OSTU二值化
OSTU又称为自适应阈值二值化,它的主要思想是迭代,从灰度级0到255,每次按照当前的灰度值将图像分为出背景和前景,如果当前两个部分(背景和前景)的类间方差最大,则说明此时的阈值是最优的。
求直方图:
1 |
|
这里需要注意的是,由于我们面向视频处理,像atomicAdd这类的操作,之前需要将整个数组清空,因为上一帧的处理结果还在内存中,并没有删除。并且还需要同步一下线程,确保整个hist都已被清空。
计算类间方差
1 |
|
最后面计算类间方差的公式是化简后得到公式,参考。上述程序会得到一个大小为256的类间方差数组,里面的值对应每个灰度级作为二值化阈值时对应的类间方差。
寻找最优阈值
1 |
|
这一步是借用并行求和的思想,来并行求最大值,由于我们最终是要得到类间方差最大时的阈值,也就是类间方差最大那个值的索引,所以我们又定义了一个varId
变量来保存每一次树型对比时获得的最大类间方差对应的索引,则对比完后,varId[0]
保存的就是最大类间方对应的索引。最后我们再使用之前的阈值二值化进行二值化即可。
整体流程及thread、block设置
1 |
|