????????图像分割算法的综述参考论文《图像分割方法综述_黄鹏》,知网上很方便查到下载,而且时间而言比较新。
????????基于阈值的方法,最普遍的一个是二值化,将阈值以下和以上的分为两部分。应用比较广泛的有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通道的。
????????可以看效果以及其余内容:?https://www.bilibili.com/read/cv12814828
|