首页  >  文章  >  Java  >  java 图像的二值化与大津阈值法

java 图像的二值化与大津阈值法

黄舟
黄舟原创
2016-12-30 11:53:542756浏览

这篇主要关注于图像的二值化,即在灰度化的基础上,进行阈值分割。二值化的方法很多,事实上,在图像进行处理的时候,能够完美的分割出目标区域,那么已经成功了一大半,可见二值化的重要性。本文主要介绍三种二值化方法。

1.固定阈值法,设定好阈值,大于该阈值的像素点设为255,否则为0,这是最简单的,效果也是最不稳定的。

<span style="font-size:14px;"><span style="font-size:10px;">public void SimBinary(){
		toGray();//灰度化
		int Threshold = 128;
		for (int y = 0; y < h; y++) {
                   for (int x = 0; x < w; x++) {
            	      if(data[x + y * w] < Threshold){
            		 data[x + y * w] = 0;

            	      }else{
            		data[x + y * w] = 255;
            	      }
                  }
	       }
					
	}</span></span>

运行效果如下:

724.jpg

725.jpg

2.循环法 (参考:图像处理之常见二值化方法汇总)

1. 一个初始化阈值T,可以自己设置或者根据随机方法生成。

2. 根据阈值图每个像素数据P(n,m)分为对象像素数据G1与背景像素数据G2。(n为

行,m为列)

3. G1的平均值是m1, G2的平均值是m2

4. 一个新的阈值T’ = (m1 + m2)/2

5. 回到第二步,用新的阈值继续分像素数据为对象与北京像素数据,继续2~4步,

直到计算出来的新阈值等于上一次阈值。

代码如下:

<span style="font-size:14px;">	public void IterBinary(){
		toGray();
		
		int Threshold = 128;
		int preThreshold = 256;
		
		while (Math.abs(Threshold-preThreshold) > 4){
			int s1 = 0;
			int s2 = 0;
			int f1 = 0;
			int f2 = 0;
			
			for (int y = 0; y < h; y++) {
	                  for (int x = 0; x < w; x++) {
	            	    if(data[x + y * w] < Threshold){
	            		s1 += data[x + y * w];
	            		f1++;
	            	      }else{
	            		s2 += data[x + y * w];
	            		f2++;
	            	      }
	                 }
		       }
			
			preThreshold = Threshold;
			Threshold = (int)((s1/f1+s2/f2)/2);
		 }
		
		for (int y = 0; y < h; y++) {
                   for (int x = 0; x < w; x++) {
            	     if(data[x + y * w] < Threshold){
            		data[x + y * w] = 0;

            	     }else{
            		data[x + y * w] = 255;
            	     }
                  }
	       }
					
	}</span>

效果如下:

726.jpg

3.大津阈值法(参考:自适应阈值算法(大津阈值法))

最大类间方差法是由日本学者大津于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,即为所求。

代码如下:

<span style="font-size:14px;">public void Otsu(){
		toGray();
		int num = h*w;
		int[] hist = hist();
		int sum = math.sum(hist);
		double[] res = new double[256];
		double m1=0,m2=0,w1=0,w2=0;
		
		for(int k=0;k<256;k++){
			for(int i=0;i<k;i++){
				m1 +=hist[i];
			}
			w1 = m1/num;
			w2 = 1-w1;
			m2 = (sum-m1)/(255-k);
			m1 = m1/(k+1);
			res[k] = w1*w2*Math.abs(m1 - m2)*Math.abs(m1 - m2);
		}
		
		int Threshold = math.maxIndex(res); //获得最大值的下标
		
		for (int y = 0; y < h; y++) {
                  for (int x = 0; x < w; x++) {
            	    if(data[x + y * w] < Threshold){
            		data[x + y * w] = 0;

            	    }else{
            		data[x + y * w] = 255;
            	    }
                }
		}
	}</span>

运行效果如下:

727.jpg

 以上就是java 图像的二值化与大津阈值法的内容,更多相关内容请关注PHP中文网(www.php.cn)!


声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn