【图像处理】图像分割-全局固定值阈值分割,局部阈值分割、大津Otsu自适应阈值分割

1 全局固定阈值分割
threshold(image, global, th, 255, CV_THRESH_BINARY_INV); 
一副图像包括目标、背景和噪声,设定某一阈值T将图像分成两部分:大于T的像素群和小于T的像素群。

捕获

在实际处理时候,为了显示需要一般用255表示背景,用0表示对象物。

由于实际得到的图像目标和背景之间不一定单纯地分布在两个灰度范围内,此时就需要两个或以上的阈值来提取目标。

捕获

图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。难点在于如何选择一个合适的阈值实现较好的分割。

 cv::threshold(image, global, th, 255, CV_THRESH_BINARY_INV);

  1. int main(int argc, char** argv)  
  2. {  
  3.     Mat image = imread("E:/VS2013/face/xuelian/png/1.png", CV_LOAD_IMAGE_GRAYSCALE);  
  4.     if (image.empty())  
  5.     {  
  6.         cout << "read image failure" << endl;  
  7.         return -1;  
  8.     }  
  9.   
  10.   
  11.     // 全局二值化  
  12.     int th = 100;//阈值  
  13.     Mat global;  
  14.     threshold(image, global, th, 255, CV_THRESH_BINARY_INV);  
  15.   
  16.   
  17.     // 局部二值化  
  18.   
  19.     int blockSize = 7;  
  20.     int constValue = 11;  
  21.     Mat local;  
  22.     adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);  
  23.   
  24.   
  25.     imshow("globalThreshold", global);  
  26.     imshow("localThreshold", local);  
  27.     waitKey(0);  
  28.   
  29.   
  30.     return 0;  
  31. }  


2 局部自适应阈值

adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);

   局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值。这样做的好处在于每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的。亮度较高的图像区域的二值化阈值通常会较高,而亮度较低的图像区域的二值化阈值则会相适应地变小。不同亮度、对比度、纹理的局部图像区域将会拥有相对应的局部二值化阈值。常用的局部自适应阈值有:1)局部邻域块的均值;2)局部邻域块的高斯加权和。

int main(int argc, char** argv)
{
	Mat image = imread("E:/VS2013/face/xuelian/png/1.png", CV_LOAD_IMAGE_GRAYSCALE);
	if (image.empty())
	{
		cout << "read image failure" << endl;
		return -1;
	}


	// 全局二值化
	int th = 100;//阈值
	Mat global;
	threshold(image, global, th, 255, CV_THRESH_BINARY_INV);


	// 局部二值化

	int blockSize = 7;
	int constValue = 11;
	Mat local;
	adaptiveThreshold(image, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);


	imshow("globalThreshold", global);
	imshow("localThreshold", local);
	waitKey(0);


	return 0;
}

adaptiveThreshold(
const CvArr* src,    // 输入图像. 
CvArr* dst,    //  输出图像.
double max_value,   // max_value:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值.
int adaptive_method=CV_ADAPTIVE_THRESH_MEAN_C,    // adaptive_method:自适应阈值算法使用:                                                                                                                    //CV_ADAPTIVE_THRESH_MEAN_C 或 CV_ADAPTIVE_THRESH_GAUSSIAN_C 
int threshold_type=CV_THRESH_BINARY, // threshold_type:取阈值类型:必须是CV_THRESH_BINARY或者                                                                                                         CV_THRESH_BINARY_INV
int block_size=3,//    block_size:用来计算阈值的象素邻域大小: 3, 5, 7, ...
double param=5 )//   param:与方法有关的参数。对方法 CV_ADAPTIVE_THRESH_MEAN_C 和                                                                                                   CV_ADAPTIVE_THRESH_GAUSSIAN_C,

 它是一个从均值或加权均值提取的常数(见讨论), 尽管它可以是负数。

对于max_value中的两个方式中的T是为每一个象素点单独计算的阈值,即每个像素点的阈值都是不同的,就是将该像素点周围B*B区域内的像素加权平均然后减去一个常数param,从而得到该点的阈值。b由block_size指定,常数由param1指定
对方法 CV_ADAPTIVE_THRESH_MEAN_C,先求出块中的均值,再减掉param。
对方法 CV_ADAPTIVE_THRESH_GAUSSIAN_C ,那么区域中(x,y)周围的像素根据高斯函数按照他们离中心点的距离进行加权计算, 再减掉param。



3.最大方差阈值

最大方差阈值的基本思想是:把直方图在某一阈值处分割成两组,当被分成的的两组之间方差最大时,决定阈值。

设图像的灰度值为0~m-1级,灰度值i的像素数为ni,此时我们得到像素总数:

捕获

然后用T将其分成两组C0={0~T-1},C1={T~m-1},各组的概率如下

捕获

平均值为:

捕获

其中:捕获是整体图像的灰度平均值,捕获是阈值为T时的灰度平均值,

所以全部采样的灰度平均值为:捕获

两组间的方差用下式求出:

捕获

从1~m-1之间改变T,求上式为最大时的T,Tmax即为我们需要的阈值。所以上式称为阈值选择函数。

 然后,基于上面的阈值对图像进行二值化处理,即可得到结果。

最大类间方差法(大津法,OTSU)

3自适应阈值算法(大津阈值法)

threshold(g_grayImage, g_ndstImage, 133, 255, THRESH_BINARY|THRESH_OTSU);
threshold(g_grayImage, g_ndstImage, 1, 255, THRESH_BINARY|THRESH_OTSU);

threshold(g_grayImage, g_ndstImage, 133, 255, THRESH_OTSU);

最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小。

对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均
灰度记为μ,类间方差记为g。假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:
      ω0=N0/ M×N                                                         (1)
      ω1=N1/ M×N                                                         (2)
      N0+N1=M×N                                                           (3)
      ω0+ω1=1                                                            (4)
      μ=ω0*μ0+ω1*μ1                                                   (5)
      g=ω0(μ0-μ)^2+ω1(μ1-μ)^2                                        (6)

将式(5)代入式(6),得到等价公式:
            g=ω0ω1(μ0-μ1)^2                                                  (7)

采用遍历的方法得到使类间方差最大的阈值T,即为所求。

由于,当图像在254或255灰度值上没有像素点时,求平均灰度时会出现0/0的情况,为避免抛出异常,可在当出现前景像素数为零时,跳出循环。

        

采用遍历的方法得到使类间方差最大的阈值,即为所求。

在大津法中,我们定义组内方差为

通过选择使得上述组内方差最小化时的阈值 t,就可以使得图像中的前景和背景尽可能的被区别开(假设我们将最终图像里被分开的两部分称为前景和背景)。w0w1分别是一个像素可能属于前景或背景的概率,而 σ 表示两个类别的方差。如果一个图像的直方图有L个等级(一般L=256),那么在给定阈值 t的情况下,w0w1分别定义为

大津展之证明最小化组内方差(intra-class variance)与最大化组间方差(inter-class variance)是等价的,于是有

又因为(其中 μ 表示均值或期望)

可以推出

这个证明仅仅涉及一些算术上的推导,我简单演示如下


otsu算法选择使类间方差最大的灰度值为阈值,具有很好的效果
算法具体描述见otsu论文,或冈萨雷斯著名的数字图像处理那本书
这里给出程序流程:
1、计算直方图并归一化histogram
2、计算图像灰度均值avgValue.
3、计算直方图的零阶w[i]和一级矩u[i]
4、计算并找到最大的类间方差(between-class variance)
variance[i]=(avgValue*w[i]-u[i])*(avgValue*w[i]-u[i])/(w[i]*(1-w[i]))
对应此最大方差的灰度值即为要找的阈值
5、用找到的阈值二值化图像

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;

//-----------------------------------【宏定义部分】-------------------------------------------- 
//  描述:定义一些辅助宏 
//----------------------------------------------------------------------------------------------
#define WINDOW_NAME "【Shi-Tomasi角点检测】"        //为窗口标题定义的宏 



//-----------------------------------【全局变量声明部分】--------------------------------------
//          描述:全局变量声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_grayImage,g_ndstImage;
int main(  )
{
	//【0】改变console字体颜色
	system("color 2F"); 
	//【1】载入源图像并将其转换为灰度图
	g_srcImage = imread("S (3).jpg");
	imshow("【原始图】", g_srcImage);
	cvtColor( g_srcImage, g_grayImage, CV_BGR2GRAY );
	imshow("【灰度图】", g_grayImage);
	//【方法1】全局固定阈值分割
	//threshold(g_grayImage, g_ndstImage, 133, 1, 1);	//更新效果图
	//imshow("threshold", g_ndstImage*255);

	//【方法2】局固自适应阈值分割
	//int blockSize = 13;  
	//int constValue =9;  
	//Mat local;  
	//adaptiveThreshold(g_grayImage, local, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY_INV, blockSize, constValue);    
	//imshow("localThreshold", local);
	//【方法3】大津法、Otus法阈值分割
	//threshold(g_grayImage, g_ndstImage, 133, 255, THRESH_OTSU);
	threshold(g_grayImage, g_ndstImage, 100, 255, THRESH_BINARY|THRESH_OTSU);	
	imshow("THRESH_OTSU", g_ndstImage);

	waitKey();
	return 0;
}

 PS说明    CV_THRESH_MASK        =7 //不工作问题

一. 关键函数介绍

下面就介绍OpenCV中对图像进行二值化的关键函数——cvThreshold()

函数功能:采用Canny方法对图像进行边缘检测

函数原型:

void cvThreshold(

  const CvArrsrc,

  CvArrdst,

  double threshold,

  double max_value,

  int threshold_type

);

函数说明:

第一个参数表示输入图像,必须为单通道灰度图。

第二个参数表示输出的边缘图像,为单通道黑白图。

第三个参数表示阈值

第四个参数表示最大值。

第五个参数表示运算方法。

OpenCVimgproc\types_c.h中可以找到运算方法的定义。

/* Threshold types */

enum

{

    CV_THRESH_BINARY      =0,  /* value = value > threshold ? max_value : 0       */

    CV_THRESH_BINARY_INV  =1,  /* value = value > threshold ? 0 : max_value       */

    CV_THRESH_TRUNC       =2,  /* value = value > threshold ? threshold : value   */

    CV_THRESH_TOZERO      =3,  /* value = value > threshold ? value : 0           */

    CV_THRESH_TOZERO_INV  =4,  /* value = value > threshold ? 0 : value           */

    CV_THRESH_MASK        =7,

    CV_THRESH_OTSU        =8  /* use Otsu algorithm to choose the optimal threshold value; combine the flag with one of the above CV_THRESH_* values */

};

注释已经写的很清楚了,因此不再用中文来表达了。

 




  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值