对含小目标的灰度图二值化方法
在实际经历中,对原始图像经过一定操作之后得到了包含目标的灰度图像,其中,目标在图像中属于比较亮的区域,背景则是相对较暗的区域,现在需要将目标提取出来。
最先想到的方法是将灰度图像二值化,并且希望目标区域二值图中为1(255)的集合,背景则是0的集合。一般想法可能直接是阈值分割,对于单帧或者图像序列亮度及目标亮度变化不大的情况一般适用,但是对于复杂情况可能不太适用。因为在不同的环境中,阈值可能不一样了,之前能够很好分割的阈值在其他图像中将目标判断成了背景也是很可能发生的。
在最近的工作中,发现了一种工程上的方法,能够比较好的做到自适应阈值,其中或许包含某些参数,但是参数调整范围很小(比如1-3),减少了阈值调整的难度,且适应范围及分割鲁棒性得到很大的提高。
接下来我们先来看看这个方法的思路(利益相关,无法展示测试图片及代码,仅描述方法):
- 设定分割阈值mean = 0;
- 在图像M中,f(x, y)表示(x, y)处的灰度值,求取图像中f(x, y) > mean 的平均灰度值,即f(x, y) <= mean 的像素点不参与计算;
- 更新mean为2中求取的全局平均灰度值;
- 回到2,算法迭代n次,n为可调参数(实际上n不用太大,n = 3应该就是足够了)。
算法的思路是,在目标很小的时候,平均灰度偏向于背景灰度(因为背景远大于目标),但是由于目标是相对与背景的亮的区域,平均亮度会大于大部分背景的亮度,迭代之后实际上是减少了背景区域的面积,迭代若干次之后,目标区域和有效的背景区域面积可能会差不多,此时得到的分割阈值即几乎将所有的背景区域都分割出去了,从而达到了分割效果。
伪代码:
for (int i = 0; i < frame.cols; i++)
{
for (int j = 0; j < frame.rows; j++)
{
gray[frame.at<uchar>(j, i)]++;
}
}
mean = 0;
sum = 0;
count = 0;
for (int i = 0; i < loop_scale; i++)
{
for (j = 255; j > 0; j++)
{
if (j > mean)
{
sum += gray[j] * j;
count += gray[j];
}
}
mean = sum / count;
sum = 0;
count = 0;
}
另外一些问题:
对于大目标的效果如何呢?(目标慢慢靠近,怎么判断?切换算法,或该算法效果如何?)
待更新...如果记得的话...