图像分割算法的综述参考论文《图像分割方法综述_黄鹏》,知网上很方便查到下载,而且时间而言比较新。
基于阈值的方法,最普遍的一个是二值化,将阈值以下和以上的分为两部分。应用比较广泛的有Otsu方法,可以计算出满足规则的最优阈值,规则一般采取类间方差的计算。当然还有其他的阈值选取规则方法。
基于类间方差的方法自动获取最优阈值,再以此最优阈值进行分割。通过遍历每一个阈值,获得最优的类间方差值所对应的阈值作为最优解。因为是在同一项目中,只实现给定阈值计算类间方差的方法,最优阈值在初始化中遍历获取。
规则说明
灰度级获取规则:采取0-255划分为256个等级,不进行低维度的划分。
类间方差获取规则:
-
//类间方差计算规则
-
//w0 分开后前景像素点数占图像的比例
-
//u0 分开后前景像素点的平均灰度
-
//w1 分开后背景像素点数占图像的比例
-
//u1 分开后背景像素点的平均灰度
-
//方差值 返回w0*w1*(u0-u1)*(u0-u1)
-
//至于原理许多博客中均有提到
实现
由于从一个项目分出来的,带m_的是类的成员
灰度级函数
-
void ImgDivision::getGrayLevel()
-
{
-
for(int y = 0; y<m_Img->height(); y++)
-
{
-
QRgb * line = (QRgb *)m_Img->scanLine(y);
-
for(int x = 0; x<m_Img->width(); x++)
-
{
-
int average = (qRed(line[x]) + qGreen(line[x]) + qBlue(line[x]))/3;
-
m_GrayLevel[average] = m_GrayLevel[average] + 1;
-
}
-
}
-
}
获取类间方差函数
返回该阈值下的方差值,因此后续在ImgDivision初始化时计算最优阈值,存在m_BestThreshold中。
-
double ImgDivision::getInterclassVariance(int first_threshold){
-
//w0 分开后前景像素点数占图像的比例
-
double frontNums = 0.0;
-
double frontGraySum = 0;
-
for (int i = 0; i < first_threshold; i++) {
-
frontNums = frontNums + m_GrayLevel[i];
-
frontGraySum = frontGraySum + m_GrayLevel[i] * i;
-
}
-
double w0 = frontNums / (m_Img->width() * m_Img->height());
-
//u0 分开后前景像素点的平均灰度
-
double u0 = frontGraySum / frontNums;
-
//w1 分开后背景像素点数占图像的比例
-
double backNums = 0.0;
-
double backGraySum = 0;
-
for (int i = first_threshold; i < 256; i++) {
-
backNums = backNums + m_GrayLevel[i];
-
backGraySum = backGraySum + m_GrayLevel[i] * i;
-
}
-
double w1 = backNums / (m_Img->width() * m_Img->height());
-
// u1 分开后背景像素点的平均灰度
-
double u1 = backGraySum / backNums;
-
return w0*w1*(u0-u1)*(u0-u1);
-
}
初始化中部分内容
-
//获取灰度级
-
getGrayLevel();
-
//计算类间方差 得到最优阈值
-
double g = 0;
-
for (int i = 0; i<256; i++) {
-
if(g < getInterclassVariance(i)){
-
g = getInterclassVariance(i);
-
m_BestThreshold = i;
-
}
-
}
普通二值化函数
-
QImage* ImgDivision::byThreshold(int threshold)
-
{
-
QImage *newImg = new QImage(m_Img->width(), m_Img->height(), QImage::Format_ARGB32);
-
for(int y = 0; y<m_Img->height(); y++)
-
{
-
QRgb * line = (QRgb *)m_Img->scanLine(y);
-
for(int x = 0; x<m_Img->width(); x++)
-
{
-
int average = (qRed(line[x]) + qGreen(line[x]) + qBlue(line[x]))/3;
-
if(average < threshold){
-
newImg->setPixel(x,y, qRgb(255, 255, 255));
-
}else {
-
newImg->setPixel(x,y, qRgb(0, 0, 0));
-
}
-
}
-
}
-
return newImg;
-
}
Otsu方法则只需要在调用普通二值化函数时,传入最优的阈值即可。
主要内容是计算类间方差的实现。值得说明为了整体的方便,二值化并非是01,而是以0,255黑白两种像素进行区分,且都为RGB通道的。
可以看效果以及其余内容: /read/cv12814828