阈值分割法_迭代法阈值分割 - CSDN
精华内容
参与话题
  • 阈值分割法——最佳阈值的选择问题

    万次阅读 多人点赞 2019-10-08 21:30:01
    阈值分割法可以说是图像分割中的经典方法,它利用图像中要提取的目标与背景在灰度上的差异,通过设置阈值来把像素级分成若干类,从而实现目标与背景的分离。 一般流程:通过判断图像中每一个像素点的特征属性是否...

        阈值分割法可以说是图像分割中的经典方法,它利用图像中要提取的目标与背景在灰度上的差异,通过设置阈值来把像素级分成若干类,从而实现目标与背景的分离。

        一般流程:通过判断图像中每一个像素点的特征属性是否满足阈值的要求,来确定图像中的该像素点是属于目标区域还是背景区域,从而将一幅灰度图像转换成二值图像。

    用数学表达式来表示,则可设原始图像f(x,y),T为阈值,分割图像时则满足下式:

                                                                         

        阈值分割法计算简单,而且总能用封闭且连通的边界定义不交叠的区域,对目标与背景有较强对比的图像可以得到较好的分割效果。但是,关键问题来了,如何获得一个最优阈值呢?????

    以下是几种最优阈值的选择方法:

    (1)人工经验选择法:

        也就是我们自己根据需要处理的图像的先验知识,对图像中的目标与背景进行分析。通过对像素的判断,图像的分析,选择出阈值值所在的区间,并通过实验进行对比,最后选择出比较好的阈值。这种方法虽然能用,但是效率较低且不能实现自动的阈值选取。对于样本图片较少时,可以选用。

    (2)利用直方图

        利用直方图进行分析,并根据直方图的波峰和波谷之间的关系,选择出一个较好的阈值。这样方法,准确性较高,但是只对于存在一个目标和一个背景的,且两者对比明显的图像,且直方图是双峰的那种最有价值。

    (3)最大类间方差法(OTSU)

        OTSU是一种使用最大类间方差的自动确定阈值的方法。是一种基于全局的二值化算法,它是根据图像的灰度特性,将图像分为前景和背景两个部分。当取最佳阈值时,两部分之间的差别应该是最大的,在OTSU算法中所采用的衡量差别的标准就是较为常见的最大类间方差。前景和背景之间的类间方差如果越大,就说明构成图像的两个部分之间的差别越大,当部分目标被错分为背景或部分背景被错分为目标,都会导致两部分差别变小,当所取阈值的分割使类间方差最大时就意味着错分概率最小。

     

        记T为前景与背景的分割阈值,前景点数占图像比例为w0,平均灰度为u0;背景点数占图像比例为w1,平均灰度为u1,图像的总平均灰度为u,前景和背景图象的方差g,则有:

                                                  

     

    联立上式得:

                                                                 

    或:

                                                                           

     

            当方差g最大时,可以认为此时前景和背景差异最大,此时的灰度T是最佳阈值。类间方差法对噪声以及目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。当目标与背景的大小比例悬殊时(例如受光照不均、反光或背景复杂等因素影响),类间方差准则函数可能呈现双峰或多峰,此时效果不好。

    (4)自适应阈值法:

        上面的最大类间方差阈值分割法在分割过程中对图像上的每个像素都使用了相等的阈值。但在实际情况中,当照明不均匀、有突发噪声或者背景变化较大时,整幅图像分割时将没有合适的单一阈值,如果仍采用单一的阈值去处理每一个像素,可能会将目标和背景区域错误划分。而自适应阈值分割的思想,将图像中每个像素设置可能不一样的阈值。

    基本原理:

        一种较为简单的自适应阈值选取方法是对每个像素确定以其自身为中心的一个领域窗口,寻找窗口内像素的最大值与最小值,并取二者的平均值作为阈值,或者将窗口内所有像素的平均值作为阈值,亦或者将窗口内的所有像素的高斯卷积作为阈值。

     

    。你发大时,可以认为此时前景和背景差异最大,此时的灰度T是最佳阈值。类间方差法对噪声以及目标大小十分敏感,它仅对类间方差为单峰的图像产生较好的分割效果。当目标与背景的大小比例悬殊时(例如受光照不均、反光或背景复杂等因素影响),类间方差准则函数可能呈现双峰或多峰,此时效果)自适应阈值法

    展开全文
  • 图像处理——常用阈值分割方法及源码

    万次阅读 多人点赞 2018-07-18 20:37:18
    3、 最大熵阈值分割法 4、 迭代阈值分割  5、测验   1、Otsu阈值分割  Otsu(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个...

    目录

     

    1、Otsu阈值分割

    2、自适应阈值分割

    3、 最大熵阈值分割法

    4、 迭代阈值分割

     5、测验

     

    1、Otsu阈值分割

            Otsu(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。 所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。

    参考链接:https://www.cnblogs.com/moon1992/p/5092726.html

    opencv调用格式为:threshold(sourceImage, dstImage, 0, 255, CV_THRESH_OTSU);

    sourceImage:输入图像;

    dstImage:输出图像;

    otsu算法的源码如下:

    Mat OtsuAlgThreshold(Mat &image)
    {
    	if (image.channels() != 1)
    	{
    		cout << "Please input Gray-image!" << endl;
    	}
    	int T = 0; //Otsu算法阈值  
    	double varValue = 0; //类间方差中间值保存
    	double w0 = 0; //前景像素点数所占比例  
    	double w1 = 0; //背景像素点数所占比例  
    	double u0 = 0; //前景平均灰度  
    	double u1 = 0; //背景平均灰度  
    	double Histogram[256] = { 0 }; //灰度直方图,下标是灰度值,保存内容是灰度值对应的像素点总数  
    	uchar *data = image.data;
    
    	double totalNum = image.rows*image.cols; //像素总数
    
    	for (int i = 0; i < image.rows; i++)
    	{
    		for (int j = 0; j < image.cols; j++)
    		{
    			if (image.at<uchar>(i, j) != 0) Histogram[data[i*image.step + j]]++;
    		}
    	}
    	int minpos, maxpos;
    	for (int i = 0; i < 255; i++)
    	{
    		if (Histogram[i] != 0)
    		{
    			minpos = i;
    			break;
    		}
    	}
    	for (int i = 255; i > 0; i--)
    	{
    		if (Histogram[i] != 0)
    		{
    			maxpos = i;
    			break;
    		}
    	}
    
    	for (int i = minpos; i <= maxpos; i++)
    	{
    		//每次遍历之前初始化各变量  
    		w1 = 0;       u1 = 0;       w0 = 0;       u0 = 0;
    		//***********背景各分量值计算**************************  
    		for (int j = 0; j <= i; j++) //背景部分各值计算  
    		{
    			w1 += Histogram[j];   //背景部分像素点总数  
    			u1 += j*Histogram[j]; //背景部分像素总灰度和  
    		}
    		if (w1 == 0) //背景部分像素点数为0时退出  
    		{
    			break;
    		}
    		u1 = u1 / w1; //背景像素平均灰度  
    		w1 = w1 / totalNum; // 背景部分像素点数所占比例
    		//***********背景各分量值计算**************************  
    
    	    //***********前景各分量值计算**************************  
    		for (int k = i + 1; k < 255; k++)
    		{
    			w0 += Histogram[k];  //前景部分像素点总数  
    			u0 += k*Histogram[k]; //前景部分像素总灰度和  
    		}
    		if (w0 == 0) //前景部分像素点数为0时退出  
    		{
    			break;
    		}
    		u0 = u0 / w0; //前景像素平均灰度  
    		w0 = w0 / totalNum; // 前景部分像素点数所占比例  
    		//***********前景各分量值计算**************************  
    
    		//***********类间方差计算******************************  
    		double varValueI = w0*w1*(u1 - u0)*(u1 - u0); //当前类间方差计算  
    		if (varValue < varValueI)
    		{
    			varValue = varValueI;
    			T = i;
    		}
    	}
    	Mat dst;
    	threshold(image, dst, T, 255, CV_THRESH_OTSU);
    	return dst;
    }

    2、自适应阈值分割

    这一部分讲解的是opencv自带的adaptiveThreshold()函数,其算法流程:

             二值化算法是用输入像素的值I与一个值C来比较,根据比较结果确定输出值。

            自适应二值化的每一个像素的比较值C都不同,比较值C由这个像素为中心的一个块范围计算在减去差值delta得到。

            其中,C的常用计算方法有两种:

             a、平均值减去差值delta(使用盒过滤boxfilter,性能会非常不错)

             b、高斯分布加权和减去差值delta (使用高斯滤波GaussionBlur)

    adaptiveThreshold()源码如下:

    void myadaptive(InputArray _src, OutputArray _dst, double maxValue,
    	int method, int type, int blockSize, double delta)
    {
    	Mat src = _src.getMat();
    
    	CV_Assert(src.type() == CV_8UC1);
    	CV_Assert(blockSize % 2 == 1 && blockSize > 1);
    	Size size = src.size();
    
    	_dst.create(size, src.type());
    	Mat dst = _dst.getMat();
    
    	if (maxValue < 0)
    	{
    		dst = Scalar(0);
    		return;
    	}
    
    	Mat mean;
    	if (src.data != dst.data)
    		mean = dst;
    	if (method == ADAPTIVE_THRESH_GAUSSIAN_C)
    	{
    		GaussianBlur(src, mean, Size(blockSize, blockSize), 0, 0, BORDER_REPLICATE);
    	}
    	else if (method == ADAPTIVE_THRESH_MEAN_C)
    	{
    		boxFilter(src, mean, src.type(), Size(blockSize, blockSize),
    			Point(-1, -1), true, BORDER_REPLICATE);
    	}
    	else
    	{
    		CV_Error(CV_StsBadFlag, "Unknown/unsupported adaptive threshold method");
    	}
    
    	int i, j;
    	uchar imaxval = saturate_cast<uchar>(maxValue);
    	int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
    	uchar tab[768];
    
    	if (type == CV_THRESH_BINARY)
    		for (i = 0; i < 768; i++)
    			tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
    	else if (type == CV_THRESH_BINARY_INV)
    		for (i = 0; i < 768; i++)
    			tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
    	else
    	{
    		CV_Error(CV_StsBadFlag, "Unknown/unsupported threshold type");
    	}
    
    	if (src.isContinuous() && mean.isContinuous() && dst.isContinuous())
    	{
    		size.width *= size.height;
    		size.height = 1;
    	}
    
    	for (i = 0; i < size.height; i++)
    	{
    		const uchar* sdata = src.data + src.step*i;
    		const uchar* mdata = mean.data + mean.step*i;
    		uchar* ddata = dst.data + dst.step*i;
    
    		for (j = 0; j < size.width; j++)
    			// 将[-255, 255] 映射到[0, 510]然后查表
    			ddata[j] = tab[sdata[j] - mdata[j] + 255];
    	}
    }

    3、 最大熵阈值分割法

    参考链接:https://blog.csdn.net/qq_27668313/article/details/77949596

    https://blog.csdn.net/robin__chou/article/details/53931442

    https://blog.csdn.net/xw20084898/article/details/22760169

    最大熵阈值分割函数源码如下:

    Mat EntropySeg(Mat src)
    {
    	int tbHist[256] = { 0 };
    	int index = 0;
    	double Property = 0.0;
    	double maxEntropy = -1.0;
    	double frontEntropy = 0.0;
    	double backEntropy = 0.0;
    	int TotalPixel = 0;
    	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++)
    		{
    			++TotalPixel;
    			tbHist[pData[j]] += 1;
    		}
    	}
    
    	for (int i = 0; i < 256; i++)
    	{
    		double backTotal = 0;
    		for (int j = 0; j < i; j++)
    		{
    			backTotal += tbHist[j];
    		}
    
    		for (int j = 0; j < i; j++)
    		{
    			if (tbHist[j] != 0)
    			{
    				Property = tbHist[j] / backTotal;
    				backEntropy += -Property*logf((float)Property);
    			}
    		}
    
    		for (int k = i; k < 256; k++)
    		{
    			if (tbHist[k] != 0)
    			{
    				Property = tbHist[k] / (TotalPixel - backTotal);
    				frontEntropy += -Property * logf((float)Property);
    			}
    		}
    
    		if (frontEntropy + backEntropy > maxEntropy) 
    		{
    			maxEntropy = frontEntropy + backEntropy;
    			index = i;
    		}
    
    		frontEntropy = 0.0;
    		backEntropy = 0.0;
    	}
    
    	Mat dst;
    	threshold(src, dst, index, 255, 0);
    	return dst;
    }

    4、 迭代阈值分割

    通过迭代方法选择阈值, 计算方法如下:

    (1)选择灰度图的平均值作为初始阈值T0 ;

    (2)计算小于等于T0的平均值T1, 和大于T0的平均值T2;

    (3)新的阈值为T = (T1 + T2)/ 2;

    (4)比较T和T0,若相等,则返回T,即为迭代阈值; 否则 T0 = T,重复(1)-(3)

    迭代阈值分割的源码如下:

    Mat IterationThreshold(Mat src)
    {
    	int width = src.cols;
    	int height = src.rows;
    	int hisData[256] = { 0 };
    	for (int j = 0; j < height; j++)
    	{
    		uchar* data = src.ptr<uchar>(j);
    		for (int i = 0; i < width; i++)
    			hisData[data[i]]++;
    	}
    
    	int T0 = 0;
    	for (int i = 0; i < 256; i++)
    	{
    		T0 += i*hisData[i];
    	}
    	T0 /= width*height;
    
    	int T1 = 0, T2 = 0;
    	int num1 = 0, num2 = 0;
    	int T = 0;
    	while (1)
    	{
    		for (int i = 0; i < T0 + 1; i++)
    		{
    			T1 += i*hisData[i];
    			num1 += hisData[i];
    		}
    		if (num1 == 0)
    			continue;
    		for (int i = T0 + 1; i < 256; i++)
    		{
    			T2 += i*hisData[i];
    			num2 += hisData[i];
    		}
    		if (num2 == 0)
    			continue;
    
    		T = (T1 / num1 + T2 / num2) / 2;
    
    		if (T == T0)
    			break;
    		else
    			T0 = T;
    	}
    
    	Mat dst;
    	threshold(src, dst, T, 255, 0);
    	return dst;
    }

     5、测验

    void main()
    {
    	Mat src = imread("1.jpg");
    	cvtColor(src, src, COLOR_RGB2GRAY);
    
    	Mat bw1, bw2, bw3, bw4;
    	myadaptive(src, bw1, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 10);
    	bw2 = EntropySeg(src);
    	bw3 = OtsuAlgThreshold(src);
    	bw4 = IterationThreshold(src);
    
    	imshow("source", src);
    	imshow("自适应阈值分割", bw1);
    	imshow("最大熵阈值分割", bw2);
    	imshow("Otsu阈值分割", bw3);
    	imshow("迭代阈值分割", bw4);
    	waitKey(0);
    }

    测验结果:

     

     

     

    展开全文
  • 阈值分割法

    2020-07-17 17:55:41
    图像灰度化后,可以进行人工选取阈值分割和自动阈值分割.
  •  otsu(最大类间方差,有时也称之为大津算法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度...

    一、工具:VC+OpenCV

    二、语言:C++

    三、原理

         

          otsu法(最大类间方差法,有时也称之为大津算法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别 来划分。 所以 可以在二值化的时候 采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。


    设t为设定的阈值。

    wo: 分开后 前景像素点数占图像的比例

    uo: 分开后 前景像素点的平均灰度

    w1:分开后 被景像素点数占图像的比例

    u1: 分开后 被景像素点的平均灰度

    u=w0*u0 + w1*u1 :图像总平均灰度


    从L个灰度级遍历t,使得t为某个值的时候,前景和背景的方差最大, 则 这个 t 值便是我们要求得的阈值。

    其中,方差的计算公式如下:

    g=wo * (uo - u) * (uo - u) + w1 * (u1 - u) * (u1 - u)

    [ 此公式计算量较大,可以采用: g = wo * w1 * (uo - u1) * (uo - u1) ]

    由于otsu算法是对图像的灰度级进行聚类,so 在执行otsu算法之前,需要计算该图像的灰度直方图。


    迭代法原理:迭代选择法是首先猜测一个初始阈值,然后再通过对图像的多趟计算对阈值进行改进的过程。重复地对图像进行阈值操作,将图像分割为对象类和背景类,然后来利用每一个类中的灰阶级别对阈值进行改进。

    图像阈值分割---迭代算法

       1 .处理流程:

           1.为全局阈值选择一个初始估计值T(图像的平均灰度)。
           2.用T分割图像。产生两组像素:G1有灰度值大于T的像素组成,G2有小于等于T像素组成。
           3.计算G1和G2像素的平均灰度值m1和m2;
           4.计算一个新的阈值:T = (m1 + m2) / 2;
           5.重复步骤2和4,直到连续迭代中的T值间的差小于一个预定义参数为止。

           适合图像直方图有明显波谷



    四、程序

    主程序(核心部分) 

    阈值分割
    1 /*===============================图像分割=====================================*/
    2 /*---------------------------------------------------------------------------*/
    3 /*手动设置阀值*/
    4 IplImage* binaryImg = cvCreateImage(cvSize(w, h),IPL_DEPTH_8U, 1);
    5 cvThreshold(smoothImgGauss,binaryImg,71,255,CV_THRESH_BINARY); 
    6 cvNamedWindow("cvThreshold", CV_WINDOW_AUTOSIZE );
    7 cvShowImage( "cvThreshold", binaryImg );
    8 //cvReleaseImage(&binaryImg); 
    9  /*---------------------------------------------------------------------------*/
    10 /*自适应阀值 //计算像域邻域的平均灰度,来决定二值化的值*/
    11 IplImage* adThresImg = cvCreateImage(cvSize(w, h),IPL_DEPTH_8U, 1);
    12 double max_value=255;
    13 int adpative_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;//CV_ADAPTIVE_THRESH_MEAN_C
    14  int threshold_type=CV_THRESH_BINARY;
    15 int block_size=3;//阈值的象素邻域大小
    16  int offset=5;//窗口尺寸
    17   cvAdaptiveThreshold(smoothImgGauss,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
    18 cvNamedWindow("cvAdaptiveThreshold", CV_WINDOW_AUTOSIZE );
    19 cvShowImage( "cvAdaptiveThreshold", adThresImg );
    20 cvReleaseImage(&adThresImg);
    21 /*---------------------------------------------------------------------------*/
    22 /*最大熵阀值分割法*/ 
    23 IplImage* imgMaxEntropy = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
    24 MaxEntropy(smoothImgGauss,imgMaxEntropy);
    25 cvNamedWindow("MaxEntroyThreshold", CV_WINDOW_AUTOSIZE );
    26 cvShowImage( "MaxEntroyThreshold", imgMaxEntropy );//显示图像
    27   cvReleaseImage(&imgMaxEntropy ); 
    28 /*---------------------------------------------------------------------------*/
    29 /*基本全局阀值法*/
    30 IplImage* imgBasicGlobalThreshold = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
    31 cvCopyImage(srcImgGrey,imgBasicGlobalThreshold);
    32 int pg[256],i,thre; 
    33 for (i=0;i<256;i++) pg[i]=0;
    34 for (i=0;i<imgBasicGlobalThreshold->imageSize;i++) // 直方图统计
    35   pg[(BYTE)imgBasicGlobalThreshold->imageData[i]]++; 
    36 thre = BasicGlobalThreshold(pg,0,256); // 确定阈值
    37   cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<thre<<endl;//输出显示阀值
    38   cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre,255,CV_THRESH_BINARY); // 二值化 
    39   cvNamedWindow("BasicGlobalThreshold", CV_WINDOW_AUTOSIZE );
    40 cvShowImage( "BasicGlobalThreshold", imgBasicGlobalThreshold);//显示图像
    41   cvReleaseImage(&imgBasicGlobalThreshold);
    42 /*---------------------------------------------------------------------------*/
    43 /*OTSU*/
    44 IplImage* imgOtsu = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
    45 cvCopyImage(srcImgGrey,imgOtsu);
    46 int thre2;
    47 thre2 = otsu2(imgOtsu);
    48 cout<<"The Threshold of this Image in Otsu is:"<<thre2<<endl;//输出显示阀值
    49 cvThreshold(imgOtsu,imgOtsu,thre2,255,CV_THRESH_BINARY); // 二值化 
    50 cvNamedWindow("imgOtsu", CV_WINDOW_AUTOSIZE );
    51 cvShowImage( "imgOtsu", imgOtsu);//显示图像 
    52 cvReleaseImage(&imgOtsu);
    53 /*---------------------------------------------------------------------------*/
    54 /*上下阀值法:利用正态分布求可信区间*/
    55 IplImage* imgTopDown = cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U, 1 );
    56 cvCopyImage(srcImgGrey,imgTopDown);
    57 CvScalar mean ,std_dev;//平均值、 标准差
    58 double u_threshold,d_threshold;
    59 cvAvgSdv(imgTopDown,&mean,&std_dev,NULL); 
    60 u_threshold = mean.val[0] +2.5* std_dev.val[0];//上阀值
    61 d_threshold = mean.val[0] -2.5* std_dev.val[0];//下阀值
    62 //u_threshold = mean + 2.5 * std_dev; //错误
    63 //d_threshold = mean - 2.5 * std_dev;
    64 cout<<"The TopThreshold of this Image in TopDown is:"<<d_threshold<<endl;//输出显示阀值
    65 cout<<"The DownThreshold of this Image in TopDown is:"<<u_threshold<<endl;
    66 cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV);//上下阀值
    67 cvNamedWindow("imgTopDown", CV_WINDOW_AUTOSIZE );
    68 cvShowImage( "imgTopDown", imgTopDown);//显示图像 
    69 cvReleaseImage(&imgTopDown);
    70 /*---------------------------------------------------------------------------*/
    71 /*迭代法*/
    72 IplImage* imgIteration = cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U, 1 );
    73 cvCopyImage(srcImgGrey,imgIteration);
    74 int thre3,nDiffRec;
    75 thre3 =DetectThreshold(imgIteration, 100, nDiffRec);
    76 cout<<"The Threshold of this Image in imgIteration is:"<<thre3<<endl;//输出显示阀值
    77 cvThreshold(imgIteration,imgIteration,thre3,255,CV_THRESH_BINARY_INV);//上下阀值
    78 cvNamedWindow("imgIteration", CV_WINDOW_AUTOSIZE );
    79 cvShowImage( "imgIteration", imgIteration);
    80 cvReleaseImage(&imgIteration);
    迭代
    1 /*======================================================================*/
    2 /* 迭代法*/
    3 /*======================================================================*/
    4 // nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值
    5 int DetectThreshold(IplImage*img, int nMaxIter, int& iDiffRec) //阀值分割:迭代法
    6 {
    7 //图像信息
    8 int height = img->height;
    9 int width = img->width;
    10 int step = img->widthStep/sizeof(uchar);
    11 uchar *data = (uchar*)img->imageData;
    12 
    13 iDiffRec =0;
    14 int F[256]={ 0 }; //直方图数组
    15 int iTotalGray=0;//灰度值和
    16 int iTotalPixel =0;//像素数和
    17 byte bt;//某点的像素值
    18 
    19 uchar iThrehold,iNewThrehold;//阀值、新阀值
    20 uchar iMaxGrayValue=0,iMinGrayValue=255;//原图像中的最大灰度值和最小灰度值
    21 uchar iMeanGrayValue1,iMeanGrayValue2;
    22 
    23 //获取(i,j)的值,存于直方图数组F
    24 for(int i=0;i<width;i++)
    25 {
    26 for(int j=0;j<height;j++)
    27 {
    28 bt = data[i*step+j];
    29 if(bt<iMinGrayValue)
    30 iMinGrayValue = bt;
    31 if(bt>iMaxGrayValue)
    32 iMaxGrayValue = bt;
    33 F[bt]++;
    34 }
    35 }
    36 
    37 iThrehold =0;//
    38 iNewThrehold = (iMinGrayValue+iMaxGrayValue)/2;//初始阀值
    39 iDiffRec = iMaxGrayValue - iMinGrayValue;
    40 
    41 for(int a=0;(abs(iThrehold-iNewThrehold)>0.5)&&a<nMaxIter;a++)//迭代中止条件
    42 {
    43 iThrehold = iNewThrehold;
    44 //小于当前阀值部分的平均灰度值
    45 for(int i=iMinGrayValue;i<iThrehold;i++)
    46 {
    47 iTotalGray += F[i]*i;//F[]存储图像信息
    48 iTotalPixel += F[i];
    49 }
    50 iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
    51 //大于当前阀值部分的平均灰度值
    52 iTotalPixel =0;
    53 iTotalGray =0;
    54 for(int j=iThrehold+1;j<iMaxGrayValue;j++)
    55 {
    56 iTotalGray += F[j]*j;//F[]存储图像信息
    57 iTotalPixel += F[j]; 
    58 }
    59 iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);
    60 
    61 iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/2; //新阀值
    62 iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
    63 }
    64 
    65 //cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
    66 return iThrehold;
    67 }
    68
    Otsu代码一
    1 /*======================================================================*/
    2 /* OTSU global thresholding routine */
    3 /* takes a 2D unsigned char array pointer, number of rows, and */
    4 /* number of cols in the array. returns the value of the threshold */
    5 /*parameter: 
    6 *image --- buffer for image
    7 rows, cols --- size of image
    8 x0, y0, dx, dy --- region of vector used for computing threshold
    9 vvv --- debug option, is 0, no debug information outputed
    10 */
    11 /*
    12 OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。
    13 下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。
    14 算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。
    15 划分点就是求得的阈值。
    16 */
    17 /*======================================================================*/
    18 int otsu (unsigned char*image, int rows, int cols, int x0, int y0, int dx, int dy, int vvv)
    19 {
    20 
    21 unsigned char*np; // 图像指针
    22 int thresholdValue=1; // 阈值
    23 int ihist[256]; // 图像直方图,256个点
    24 
    25 int i, j, k; // various counters
    26 int n, n1, n2, gmin, gmax;
    27 double m1, m2, sum, csum, fmax, sb;
    28 
    29 // 对直方图置零
    30 memset(ihist, 0, sizeof(ihist));
    31 
    32 gmin=255; gmax=0;
    33 // 生成直方图
    34 for (i = y0 +1; i < y0 + dy -1; i++) 
    35 {
    36 np = (unsigned char*)image[i*cols+x0+1];
    37 for (j = x0 +1; j < x0 + dx -1; j++)
    38 {
    39 ihist[*np]++;
    40 if(*np > gmax) gmax=*np;
    41 if(*np < gmin) gmin=*np;
    42 np++; /* next pixel */
    43 }
    44 }
    45 
    46 // set up everything
    47 sum = csum =0.0;
    48 n =0;
    49 
    50 for (k =0; k <=255; k++) 
    51 {
    52 sum += (double) k * (double) ihist[k]; /* x*f(x) 质量矩*/
    53 n += ihist[k]; /* f(x) 质量 */
    54 }
    55 
    56 if (!n) 
    57 {
    58 // if n has no value, there is problems...
    59 fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
    60 return (160);
    61 }
    62 
    63 // do the otsu global thresholding method
    64 fmax =-1.0;
    65 n1 =0;
    66 for (k =0; k <255; k++)
    67 {
    68 n1 += ihist[k];
    69 if (!n1) 
    70 { 
    71 continue; 
    72 }
    73 n2 = n - n1;
    74 if (n2 ==0)
    75 { 
    76 break; 
    77 }
    78 csum += (double) k *ihist[k];
    79 m1 = csum / n1;
    80 m2 = (sum - csum) / n2;
    81 sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
    82 /* bbg: note: can be optimized. */
    83 if (sb > fmax) 
    84 {
    85 fmax = sb;
    86 thresholdValue = k;
    87 }
    88 }
    89 
    90 // at this point we have our thresholding value
    91 
    92 // debug code to display thresholding values
    93 if ( vvv &1 )
    94 fprintf(stderr,"# OTSU: thresholdValue = %d gmin=%d gmax=%d\n",
    95 thresholdValue, gmin, gmax);
    96 
    97 return(thresholdValue);
    98 } 
    Otsu代码二
    1 /*======================================================================*/
    2 /* OTSU global thresholding routine */
    3 /*======================================================================*/
    4 int otsu2 (IplImage *image)
    5 {
    6 int w = image->width;
    7 int h = image->height;
    8 
    9 unsigned char*np; // 图像指针
    10 unsigned char pixel;
    11 int thresholdValue=1; // 阈值
    12 int ihist[256]; // 图像直方图,256个点
    13 
    14 int i, j, k; // various counters
    15 int n, n1, n2, gmin, gmax;
    16 double m1, m2, sum, csum, fmax, sb;
    17 
    18 // 对直方图置零...
    19 memset(ihist, 0, sizeof(ihist));
    20 
    21 gmin=255; gmax=0;
    22 // 生成直方图
    23 for (i =0; i < h; i++) 
    24 {
    25 np = (unsigned char*)(image->imageData + image->widthStep*i);
    26 for (j =0; j < w; j++) 
    27 {
    28 pixel = np[j];
    29 ihist[ pixel]++;
    30 if(pixel > gmax) gmax= pixel;
    31 if(pixel < gmin) gmin= pixel;
    32 }
    33 }
    34 
    35 // set up everything
    36 sum = csum =0.0;
    37 n =0;
    38 
    39 for (k =0; k <=255; k++) 
    40 {
    41 sum += k * ihist[k]; /* x*f(x) 质量矩*/
    42 n += ihist[k]; /* f(x) 质量 */
    43 }
    44 
    45 if (!n) 
    46 {
    47 // if n has no value, there is problems...
    48 //fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
    49 thresholdValue =160;
    50 goto L;
    51 }
    52 
    53 // do the otsu global thresholding method
    54 fmax =-1.0;
    55 n1 =0;
    56 for (k =0; k <255; k++) 
    57 {
    58 n1 += ihist[k];
    59 if (!n1) { continue; }
    60 n2 = n - n1;
    61 if (n2 ==0) { break; }
    62 csum += k *ihist[k];
    63 m1 = csum / n1;
    64 m2 = (sum - csum) / n2;
    65 sb = n1 * n2 *(m1 - m2) * (m1 - m2);
    66 /* bbg: note: can be optimized. */
    67 if (sb > fmax)
    68 {
    69 fmax = sb;
    70 thresholdValue = k;
    71 }
    72 }
    73 
    74 L:
    75 for (i =0; i < h; i++) 
    76 {
    77 np = (unsigned char*)(image->imageData + image->widthStep*i);
    78 for (j =0; j < w; j++) 
    79 {
    80 if(np[j] >= thresholdValue)
    81 np[j] =255;
    82 else np[j] =0;
    83 }
    84 }
    85 
    86 //cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
    87 return(thresholdValue);
    88 }
    最大熵阀值
    1 /*============================================================================
    2 = 代码内容:最大熵阈值分割 
    3 = 修改日期:2009-3-3 
    4 = 作者:crond123 
    5 = 博客:http://blog.csdn.net/crond123/
    6 = E_Mail:crond123@163.com 
    7 ===============================================================================*/
    8 // 计算当前位置的能量熵
    9 double caculateCurrentEntropy(CvHistogram * Histogram1,int cur_threshold,entropy_state state)
    10 {
    11 int start,end;
    12 int total =0;
    13 double cur_entropy =0.0;
    14 if(state == back) 
    15 {
    16 start =0;
    17 end = cur_threshold; 
    18 }
    19 else 
    20 {
    21 start = cur_threshold;
    22 end =256; 
    23 } 
    24 for(int i=start;i<end;i++) 
    25 {
    26 total += (int)cvQueryHistValue_1D(Histogram1,i);//查询直方块的值 P304
    27 }
    28 for(int j=start;j<end;j++)
    29 {
    30 if((int)cvQueryHistValue_1D(Histogram1,j)==0)
    31 continue;
    32 double percentage = cvQueryHistValue_1D(Histogram1,j)/total;
    33 /*熵的定义公式*/
    34 cur_entropy +=-percentage*logf(percentage);
    35 /*根据泰勒展式去掉高次项得到的熵的近似计算公式
    36 cur_entropy += percentage*percentage;*/ 
    37 }
    38 return cur_entropy;
    39 // return (1-cur_entropy);
    40 }
    41 
    42 //寻找最大熵阈值并分割
    43 void MaxEntropy(IplImage *src,IplImage *dst)
    44 {
    45 assert(src != NULL);
    46 assert(src->depth ==8&& dst->depth ==8);
    47 assert(src->nChannels ==1);
    48 CvHistogram * hist = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);//创建一个指定尺寸的直方图
    49 //参数含义:直方图包含的维数、直方图维数尺寸的数组、直方图的表示格式、方块范围数组、归一化标志
    50 cvCalcHist(&src,hist);//计算直方图
    51 double maxentropy =-1.0;
    52 int max_index =-1;
    53 // 循环测试每个分割点,寻找到最大的阈值分割点
    54 for(int i=0;i<HistogramBins;i++) 
    55 {
    56 double cur_entropy = caculateCurrentEntropy(hist,i,object)+caculateCurrentEntropy(hist,i,back);
    57 if(cur_entropy>maxentropy)
    58 {
    59 maxentropy = cur_entropy;
    60 max_index = i;
    61 }
    62 }
    63 cout<<"The Threshold of this Image in MaxEntropy is:"<<max_index<<endl;
    64 cvThreshold(src, dst, (double)max_index,255, CV_THRESH_BINARY);
    65 cvReleaseHist(&hist);
    66 }
    基本全局阀值法
    1 /*============================================================================
    2 = 代码内容:基本全局阈值法 
    3 ==============================================================================*/
    4 int BasicGlobalThreshold(int*pg,int start,int end)
    5 { // 基本全局阈值法
    6 int i,t,t1,t2,k1,k2;
    7 double u,u1,u2; 
    8 t=0; 
    9 u=0;
    10 for (i=start;i<end;i++) 
    11 {
    12 t+=pg[i]; 
    13 u+=i*pg[i];
    14 }
    15 k2=(int) (u/t); // 计算此范围灰度的平均值 
    16 do 
    17 {
    18 k1=k2;
    19 t1=0; 
    20 u1=0;
    21 for (i=start;i<=k1;i++) 
    22 { // 计算低灰度组的累加和
    23 t1+=pg[i]; 
    24 u1+=i*pg[i];
    25 }
    26 t2=t-t1;
    27 u2=u-u1;
    28 if (t1) 
    29 u1=u1/t1; // 计算低灰度组的平均值
    30 else 
    31 u1=0;
    32 if (t2) 
    33 u2=u2/t2; // 计算高灰度组的平均值
    34 else 
    35 u2=0;
    36 k2=(int) ((u1+u2)/2); // 得到新的阈值估计值
    37 }
    38 while(k1!=k2); // 数据未稳定,继续
    39 //cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
    40 return(k1); // 返回阈值
    41 }
    
    


    展开全文
  • 阈值分割与区域分割

    万次阅读 2017-01-02 13:22:51
    阈值分割我们曾在3.5节学习过灰度阈值变换的相关知识, 利用灰度阈值变换分割图像就称为阈值分割, 它是一种基本的图像分割方法。 阙值分割的基本思想是确定一个阈值, 然后把每个像素点的灰度值和阈值相比较,根据...

    本文主要包括以下内容

    • 阈值分割技术
    • 基于区域的图像分割技术
    • 本章的典型案例
      • 基于LoG和Canny算子的精确边缘检测
      • 基于Hough变换的直线检测
      • 图像的四叉树分解

    阈值分割

    我们曾在3.5节学习过灰度阈值变换的相关知识, 利用灰度阈值变换分割图像就称为阈值分割, 它是一种基本的图像分割方法。
    阙值分割的基本思想是确定一个阈值, 然后把每个像素点的灰度值和阈值相比较,根据比较的结果把该像素划分为两类:前景或者背景,阈值分割可以分成以下3步:

    • 确定阈值.
    • 将阈值和像素比较,.
    • 把像素归类

    其中第1步阈值最重要。阈值的选择将直接影响分割的准确性以及由此产生的图像描述,分析的正确性。

    阈值分割方法

    阈值分割常用的方法一般有以下几种。

    实验法
    实验法是通过人眼的观察, 对已知某些特征的图像, 只要试验不同的阈值, 然后看是否满足已知特征即可。这种方法的不足在于适用范围窄,
    使用前必须了解图像的某些特征, 譬如平均灰度等,而且分割后图像质量的好坏受主观局限性很大。

    根据直方图谷底确定阈值
    如果图像的前景物体内部和背景区域的灰度值分布都比较均匀, 那么这个图像的灰度直方图将具有明显双峰, 此时可以选择两峰之间的谷底作为阈值。
    其表达式为:

    注意:由于直方图是各灰度的像素统计,其峰值和谷底特性不一定代表目标和背景.因此,如果没有图像其他方面的知识,只靠直方图进行图像分割不一定准确 .

    迭代选择阈值法
    迭代式阈值选择方法的基本思想是:开始选择一个阈值作为初始估计值,然后按照某种规则不断地更新这一估计值,直到满足给定的条件为止。这个过程的关键在于选择怎么样的 迭代规则。一个好的迭代规则必须既能够快速收敛,又能够在每一个迭代过程中产生优于上次迭代的结果。下面是一种迭代选择阈值算法:
    (1)选择一个T的初始估计值。
    (2)利用阈值T把图像分为两个区域R1, 和R2
    (3)对区域R1和R2中的所有像素计算平均灰度值μ1和μ2
    (4)计算新的阈值:

    T=12(u1+u2)

    (5)重复步骤2-4, 直到逐次迭代所得的T值小于事先定义的参数T。

    最小均方误差法
    最小均方误差法也是常用的阈值分割法之一。这种方法通常以图像中的灰度为模式特征,假设各模式的灰度是独立分布的随机变量,并假设图像中待分割的模式服从一定的概率分布。一般来说,采用的是正态分布,即高斯概率分布。
    首先假设一幅图像仅包含两个主要的灰度区域前景和背景。令z表示灰度值,p(z)表示灰度值概率密度函数的估计值。假设概率密度函数一个对应于背景的灰度值,另一个对应于图像中前景即对象的灰度值。则描述图像中整体灰度变换的混合密度函数是:

    p(z)=P1p1(z)+P2p2(z)

    其中P1是前景中具有值z的像素出现的概率,P2是背景中具有值z的像素出现的概率,两者的关系为:
    P1+P2=1


    最大类间方差法
    在对图像进行阈值分割时,选定的分割阈值应使前景区域的平均灰度、背景区域的平均灰度与整幅图像的平均灰度之间差别最大,这种差异用区域的方差来表示。由此,Otsu在1978年提出了最大方差法。该算法在判决分析最小二乘法原理的基础上推导得出,计算过程简单是一种稳定、常用的算法。

    让T在[O,L-1]范围内依次取值, 使类间方差最大的T值便是最佳区域分割阈值。
    该方法不需要人为设定其他参数,是一种自动选择阈值的方法,而且能得到较好的结果。它不仅适用于包含两个区域的单阈值选择,也同样适用于多区域的多阈值选择。

    Matlab实现

    最大类间方差法
    Matlab中和阙值变换相关的两个主要函数是im2bw和graythresh。实际上,利用graythresh函数即可实现最大类间方差法。

    迭代选择阈值法

    function [Ibw, thres] = autothreshold(I)
    % 迭代法自动阈值分割
    %
    % 输入:I - 要进行自动阈值分割的灰度图像
    % 输出:Ibw - 分割后的二值图像
    %      thres - 自动分割采用的阈值
    
    thres = 0.5 * (double(min(I(:))) + double(max(I(:)))); %初始阈值
    done = false; %结束标志
    while ~done
        g = I >= thres;
        Tnext = 0.5 * (mean(I(g)) + mean(I(~g)));
        done = abs(thres - Tnext) < 0.5;
        thres = Tnext;
    end;
    
    Ibw = im2bw(I, thres/255); % 二值化

    区域分割

    前面所讲的图像分割方法都是基于像素的灰度来进行阈值分割, 本节将讨论以区域为基础的图像分割技术。传统的区域分割方法有区域生长和区域分裂与合井, 其中最基础的是区域生长法。

    区域生长及其实现

    区域生长是根据事先定义的准则将像素或者子区域聚合成更大区域的过程。其基本思想是从一组生长点开始(生长点可以是单个像素,也可以为某个小区域),将与该生长点性质相似的相邻像素或者区域与生长点合并,形成新的生长点,重复此过程直到不能生长为止。生长点和相邻区域的相似性判据可以是灰度值、纹理、颜色等多种图像信息。

    区域生长算法
    区域生长一般有3个步骤。
    (1)选择合适的生长点。
    (2)确定相似性准则即生长准则。
    (3)确定生长停止条件。
    一般来说, 在无像素或者区域满足加入生长区域的条件时, 区域生长就会停止。

    上述方法比较的是单个像素与其邻域的灰度特征以实现区域生长,也有一种混合型区域生长把图像分割成若干小区域,比较相邻小区域的相似性,如果相似则合并。在实际中,区 域生长时经常还要考虑到生长的”历史”,还要根据区域的尺寸、形状等图像的全局性质来决定区域的合并。

    matlab实现

    function J = regionGrow(I)
    % 区域生长,需要以交互方式设定初始种子点,具体方法为鼠标单击图像中一点后,按下回车键
    %
    % 输入:I - 原图像
    % 输出:J - 输出图像
    
    if isinteger(I)
        I=im2double(I);
    end
    figure,imshow(I),title('原始图像')
    [M,N]=size(I);
    [y,x]=getpts;             %获得区域生长起始点
    x1=round(x);            %横坐标取整
    y1=round(y);            %纵坐标取整
    seed=I(x1,y1);           %将生长起始点灰度值存入seed中
    J=zeros(M,N);          %作一个全零与原图像等大的图像矩阵J,作为输出图像矩阵
    J(x1,y1)=1;             %将J中与所取点相对应位置的点设置为白
    sum=seed;              %储存符合区域生长条件的点的灰度值的和
    suit=1;                 %储存符合区域生长条件的点的个数
    count=1;               %记录每次判断一点周围八点符合条件的新点的数目
    threshold=0.15;         %阈值,注意需要和double类型存储的图像相符合
    while count>0
        s=0;                   %记录判断一点周围八点时,符合条件的新点的灰度值之和
         count=0;
         for i=1:M
           for j=1:N
             if J(i,j)==1
              if (i-1)>0 & (i+1)<(M+1) & (j-1)>0 & (j+1)<(N+1)  %判断此点是否为图像边界上的点
               for u= -1:1                               %判断点周围八点是否符合阈值条件
                for v= -1:1
                  if  J(i+u,j+v)==0 & abs(I(i+u,j+v)-seed)<=threshold& 1/(1+1/15*abs(I(i+u,j+v)-seed))>0.8
                               J(i+u,j+v)=1;
                        %判断是否尚未标记,并且为符合阈值条件的点
                        %符合以上两条件即将其在J中与之位置对应的点设置为白
                     count=count+1;
                     s=s+I(i+u,j+v);                      %此点的灰度之加入s中
                  end
                end
               end
              end
             end
           end
         end
        suit=suit+count;                                   %将n加入符合点数计数器中
        sum=sum+s;                                     %将s加入符合点的灰度值总合中
        seed=sum/suit;                                    %计算新的灰度平均值
    end


    选择不同的生长点,结果不同。

    区域分裂与合并

    区域生长是从一组生长点开始的,另一种方法是在开始时将图像分割为一系列任意不相交的区域, 然后将它们合并或者拆分以满足限制条件, 这就是区域分裂与合并。 通过分裂, 可以将不同特征的区域分离开, 而通过合并, 可以将相同特征的区域合并起来。

    区域分裂与合并算法


    图像先分裂为如图9.22Ca)所示;第二次分裂时,如图(b)所示,由于左下角区域满足P(Ri)=TRUE,则不进行分裂操作;第三次分裂时,如图(c)所示,仅仅右边的突出部分 P(Ri)=FALSE, 需要进行分裂操作,其余不变,完成后,分裂停止;最后,对两个相邻区域 实行合并,一直得到最后的结果,如图(d)所示。
    区域分裂与合并对分割复杂的场景图像比较有效,如果引入应用领域知识,则可以更好地提高分割效果。

    区域分裂的Matlab实现
    在Matlab中, 和区域分裂相关的3个主要函数分别是qtdecomp、qtgetblk和qtsetblk。

    (1) qtdecomp函数
    Matlab的IPT函数qtdecomp可以进行四叉树分解。该函数首先将图像划分成相等大4的4块,然后对每一个块进行一致性检查。如果该块不符合一致性标准, 则将该块继续分为4块; 否则不对其进行进一步的分割。这个过程将会一直重复直至每一个块都符合一致性标
    准, 分解的结果可能会包含许多大小不同的块。
    qtdecomp函数的常用调用形式为:
    S = qtdecomp(I,threshold,[mindim,maxdim])

    threshold是分割成的子块中允许的阈值,默认值为0.如杲子块中最大元素和最小元 素的差值小于该阈值就认为满足一致性条件.对于double型矩阵,threshold将直接作为阈值;而对于uinit8和uintl6类型的矩阵,threshold将被乘以255和65535以作为实际阈值.对于图像而言,threshold的取值范围是0到1.

    [mindim maxdim]是尺度阈值.mindim参数可以屏蔽函数对尺度上小于mindim的子块的处理,而不论这个子块是否满足一致性条件;如果参数形式为[mindim maxdim], 则表示不产生小于mindim尺度的子块,也不保留大于maxdim尺度的子块,此时 maxdim/mindim必须是2的整数次幂

    注意: qtdecomp函数主要适用于边长是2的整数次幂的正方形图像, 如128x128,512x512, 此时分解可一直进行至子块大小为1x1。对于长宽不是2的整数次幂的图像, 分解可能无法进行到底. 例如, 对于96x96
    的图像, 将首先分解为48x48, 然后是24x24, 12*12, 6*6, 最后是3x3, 无法再继续分解. 此时必须指定mindim参数为3或是2的整数次幕与3的乘积.

    (2) qtgetblk函数
    在得到稀疏矩阵S后, 利用IPT函数qtgetblk可进一步获得四叉树分解后所有指定大小的子块像素及位置信息。常用调用形式为:
    [vals,r,c]=qtgetblk(I,S,dim)
    稀疏矩阵S是经过qtdecomp函数处理的输出结果.
    dim是指定子块的大小

    vals是dim*dim*k的三维矩阵,包含I中所有符合条件的子块数据。其中k为符合 条件的dim*dim的大小的子块的个数,vals(:.:,i)表示符合条件的第i个子块的内容.
    r和c均为列向量,分别表示图像I中符合条件子块左上角的纵坐标(行索引)和横坐标(列索引).

    (3) qtsetblk函数
    在将图像划分为子块后, 还需要使用函数qtsetblk将四叉树分解所得到的子块中符合条件的部分全部替换为指定的子块。函数语法为:
    J = qtsetblk(I,S,dim,vals)
    S是I经过qtdecomp函数处理的结果.
    dim是指定的子块大小.
    vals是dim*dim*k的三维矩阵,包含了用来替换原有子块的新子块信息.其中K应为图像I中大小为dim*dim的子块的总数,vals(:,:,i)表示要替换的第i个子块.

    I1 = imread('rice.png');
    
    S = qtdecomp(I1,0.2);
    S2 = full(S);
    
    figure;
    subplot(1,2,1),imshow(I1);
    subplot(1,2,2),imshow(S2);
    
    ct = zeros(6,1);
    for ii = 1:6
        [vals{ii},r,c]=qtgetblk(I1,S2,2^(ii-1));
        ct(ii) = size(vals(ii),3);
    end

    小结
    图像分割问题是一个十分困难的问题。因为分割后的图像是系统目标的一个函数, 所以根本不存在理想的或正确的分割。
    物体及其组成部件的二维表现形式受到光照条件、透视畸变、观察点变化、遮挡等的影响。此外, 物体及其组成部件与背景之间在视觉上可能无法区分。因此, 人们无法预测能够从图像中抽取出哪些与物体识别相关的初始信息。
    唯一可以肯定的是,这一过程将在本质上具有不可靠性。某些有用的信息能够被抽取出,且同时也会出现许多错误。因此,在任何应用领域中都不存在最优解。分割结果的好坏或者正确与否, 目前还没有一个统一的评价判断标准, 大都从分割的视觉效果和实际的应用场景来判断。

    展开全文
  • 阈值分割方法总结

    千次阅读 2019-02-25 16:50:40
    阈值是界限的意思,阈值分割就是以一个合适的像素值作为界限将图像处理成高对比度、容易识别的图像的一种方法。 threshold() double cv::threshold( cv::InputArray src, // 输入图像 cv::OutputArray dst, // ...
  • 阈值分割法简述

    千次阅读 2007-07-24 06:56:00
    阈值分割法 阈值分割法分为全局阈值法和局部阈值分割法。所谓局部阈值分割法是将原始图像划分成较小的图像,并对每个子图像选取相应的阈值。在阈值分割后,相邻子图像之间的边界处可能产生灰度级的不连续性,因此...
  • 图像处理基本算法 动态阈值分割

    万次阅读 多人点赞 2012-02-11 16:18:32
    在图像处理时,受外界光线的干扰一般比较大,假如在阈值分割时采用固 定阈值,那么在环境改变时分割效果受影响极大,那么为了避免此影响就 必须采用动态阈值,自动求出合适的阈值进行分割。 本文的介绍几...
  • 大津和局部阈值分割

    万次阅读 2016-11-29 13:57:48
    opencv中大津和局部阈值分割
  • 图像的阈值分割(迭代选择阈值)

    万次阅读 多人点赞 2015-07-27 14:46:36
    迭代法阈值选择算法是对双峰的改进,他首先选择一个近似的阈值T,将图像分割成两个部分,R1和R2,计算出区域R1和R2的均值u1和u2,再选择新的 阈值T=(u1+u2)/2; 重复上面的过程,知道u1和u2不在变化为止, 详细...
  • 1996年,Prewitt提出了直方图双峰,即如果灰度级直方图呈明显的双峰状,则选取两峰之间的谷底所对应的灰度级作为阈值。 注意:应用灰度直方图双峰分割图像,也需要一定的图像先验知识,因为同一个直方...
  • 图像分割阈值法-双峰

    千次阅读 2018-08-15 22:12:22
    1996年,Prewitt提出了直方图双峰,即如果灰度级直方图呈明显的双峰状,则选取两峰之间的谷底所对应的灰度级作为阈值。 注意:应用灰度直方图双峰分割图像,也需要一定的图像先验知识,...
  • 阈值分割(一)双峰
  • Matlab实现图像阈值分割

    万次阅读 多人点赞 2019-08-03 11:32:54
    使用matlab实现阈值分割,实现两种方法,一是人工选择阈值进行分割,而是自动选择阈值进行分割。操作步骤 1、 打开Matlab内容自带的coins.png图像。 2、 观察它的直方图。 3、 人工选定一个阈值,并进行分割。 4...
  •  阈值分割是最经典的分割技术,也是最简单实用的。许多情况下,图像中目标区域与背景区域或者说不同区域之间其灰度值存在差异,此时可以将灰度的均一性作为依据进行分割。阈值分割即通过一个或几个阈值将图像分割成...
  • MATLAB——阈值分割(一)

    万次阅读 多人点赞 2018-11-01 23:44:51
    阈值分割是一种简单有效的图像分割方法,适用于分割物体与背景有较强对比的图像,所有灰度大于或等于阈值的像素被判定为属于物体,灰度值为255表示前景,否则这些像素点将被排除在物体区域以外,灰度值为0表示背景。...
  • 在matlab的image processing工具箱中,大津(Ostu)阈值分割方法有现成的函数实现 graythreshold  GRAYTHRESH Global image threshold using Otsu's method.  LEVEL = GRAYTHRESH(I) computes a global ...
  • 图像分割——迭代式阈值分割

    千次阅读 2018-08-04 09:48:00
    (3)用T分割图像为G1、G2两组,G1由灰度值大于T的所有像素组成,G2由灰度值小于等于T的所有像素组成。 (4)对G1和G2的像素分别计算平均灰度值m1,m2。 (5)计算出新的阈值:T1=(m1+m2)/2 (6)重复步骤3到...
  • 图像分割阈值获取方法总结

    万次阅读 2017-07-16 16:58:30
    阈值分割原理: 一副图像包括目标、背景和噪声,设定某一阈值T将图像分成两部分:大于T的像素群和小于T的像素群。 在实际处理时候,为了显示需要一般用255表示背景,用0表示对象物。 由于实际得到的图像目标...
  • 基于阈值的图像分割

    万次阅读 2018-05-23 14:46:00
    1. 直方图双峰(mode ) Prewitt 等人于六十年代中期提出的直方图双峰(也称 mode ) 是典型的全局单阈值分割方法。该方法的基本思想是:假设图像中有明显的目标和背景,则其灰度直方图呈双峰分布,当...
1 2 3 4 5 ... 20
收藏数 15,991
精华内容 6,396
关键字:

阈值分割法