OpenCV最大间方差分割
OpenCV中其实有对OTUS算法的实现,threhold()函数最后一个参数可以指定使用OTUS算法。
1、最大间方差(OTUS)算法的描述
和均值迭代算法相似,OTUS算法也是利用图像的直方图进行的。OTUS算法的思想是选取一个阈值$T, T \in [0,m-1]$,$m$为图像的灰度级将直方图两部分,$T$值使得分成的两组间方差最大。
2、算法的步骤
待处理图像灰度值范围为$[0, m-1]$, 记灰度值为$i$的像素个数为$n_{i}$.
- 统计待处理图像中像素灰度总和$N$: $$N=\sum_{i=0}^{m-1}n_{i}$$
- 计算每个灰度值$i, i \in [0,m-1]$所占的概率:$$p_{i}=\frac{n_{i}}{N}$$灰度均值$\mu$:$$\mu=\sum_{i=0}^{m-1}i*p_{i}$$
- 取灰度值$T = 0 ,`1,… m-1$,利用$T$将所有灰度分成两组$C_{0}={0 … T-1}$和$C_{1}={T … m-1}$,两组的均值和概率表示为:
第一类所占的概率:$$w_{0} = \sum_{i=0}^{T-1}p_{i}$$ 第一类的均值:$$\mu_{0} = \sum_{i=0}^{T-1}\frac{i*p_{i}}{w_{0}}$$ 第二类所占的概率:$$w_{1} = \sum_{i=T}^{m-1}p_{i} = 1-w_{0}$$ 第二类的均值:$$\mu_{1} = \sum_{i=T}^{m-1}\frac{i*p_{i}}{w_{1}}$$ - 计算两组间的方差:$$\delta^{2} = w_{0}(\mu_{0}-\mu)^{2} + w_{1}(\mu_{1}-\mu)^{2}$$
- 重复过程2 - 4,找到组间方差最大的灰度值$i$,使用$i$对图像进行阈值分割即可。
3、OpenCV下的实现
Mat OstuSeg(Mat src)
{
int tbHist[256] = {0}; //直方图数组
double average = 0.0; //平均像素值
double cov = 0.0; //方差
double maxcov = 0.0; //方差最大值
int index = 0; //分割像素值
Mat dst;
int nCol = src.cols * src.channels(); //每行的像素个数
for (int i = 0; i < src.rows; i++)
{
uchar* pData = src.ptr<uchar>(i);
for (int j = 0; j < nCol; ++j)
{
tbHist[pData[j]] += 1;
}
}
int sum = 0;
for (int i=0; i<256; ++i)
sum += tbHist[i];
double w0=0.0, w1=0.0, u0=0.0, u1=0.0;
int count0 = 0;
for (int i = 0; i < 255; ++i)
{
u0 = 0;
count0 = 0;
for (int j=0; j<=i; ++j)
{
u0 += j * tbHist[j];
count0 += tbHist[j];
}
u0 = u0/count0;
w0 = (float)count0/sum;
u1 = 0;
for (int j=i+1; j<256; ++j)
u1 += j*tbHist[j];
u1 = u1/(sum - count0);
w1 = 1 - w0;
cov = w0*w1*(u1-u0)*(u1-u0);
if (cov > maxcov)
{
maxcov = cov;
index = i;
}
}
cv::threshold(src, dst, index, 255, 0); //进行阈值分割
return dst.clone();
}
4、拓展
和上一篇所述一样,如果我们需要分割的物体并不是规则的矩形,那么任然可以采用在直方图中将我们已知的无效像素去掉。
- 原文作者:Binean
- 原文链接:https://bzhou830.github.io/post/20151129OpenCV%E6%9C%80%E5%A4%A7%E9%97%B4%E6%96%B9%E5%B7%AE%E5%88%86%E5%89%B2/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。