图像处理------基于Otsu阈值二值化

一:基本原理

该方法是图像二值化处理常见方法之一,在Matlab与OpenCV中均有实现。

Otsu Threshing方法是一种基于寻找合适阈值实现二值化的方法,其最重

要的部分是寻找图像二值化阈值,然后根据阈值将图像分为前景(白色)

或者背景(黑色)。假设有6x6的灰度图像,其像素数据及其对应的直方

图如下图:


阈值寻找方法首先假设是为T=3,则背景像素的比重、均值、方差的计算

结果如下:


根据前景像素直方图,计算比重、均值、方差的过程如下:


上述整个计算步骤与结果是假设阈值T=3时候的结果,同样计算假设阈值为

T=0、T=1、T=2、T=4、T=5的类内方差,比较类内方差之间的值,最小类

内方差使用的阈值T即为图像二值化的阈值。上述是假设图像灰度值级别为

0~5六个值,实际中图像灰度值取值范围为0~255之间,所以要循环计算

使用每个灰度值作为阈值,得到类内方差,最终取最小类内方差对应的灰度

值作为阈值实现图像二值化即可。

二:代码实现

  1. package com.gloomyfish.filter.study;  
  2.   
  3. import java.awt.image.BufferedImage;  
  4.   
  5. public class OtsuBinaryFilter extends AbstractBufferedImageOp {  
  6.       
  7.     public OtsuBinaryFilter()  
  8.     {  
  9.         System.out.println("Otsu Threshold Binary Filter...");  
  10.     }  
  11.   
  12.     @Override  
  13.     public BufferedImage filter(BufferedImage src, BufferedImage dest) {  
  14.         int width = src.getWidth();  
  15.         int height = src.getHeight();  
  16.   
  17.         if ( dest == null )  
  18.             dest = createCompatibleDestImage( src, null );  
  19.         // 图像灰度化  
  20.         int[] inPixels = new int[width*height];  
  21.         int[] outPixels = new int[width*height];  
  22.         getRGB( src, 00, width, height, inPixels );  
  23.         int index = 0;  
  24.         for(int row=0; row<height; row++) {  
  25.             int ta = 0, tr = 0, tg = 0, tb = 0;  
  26.             for(int col=0; col<width; col++) {  
  27.                 index = row * width + col;  
  28.                 ta = (inPixels[index] >> 24) & 0xff;  
  29.                 tr = (inPixels[index] >> 16) & 0xff;  
  30.                 tg = (inPixels[index] >> 8) & 0xff;  
  31.                 tb = inPixels[index] & 0xff;  
  32.                 int gray= (int)(0.299 *tr + 0.587*tg + 0.114*tb);  
  33.                 inPixels[index]  = (ta << 24) | (gray << 16) | (gray << 8) | gray;  
  34.             }  
  35.         }  
  36.         // 获取直方图  
  37.         int[] histogram = new int[256];  
  38.         for(int row=0; row<height; row++) {  
  39.             int tr = 0;  
  40.             for(int col=0; col<width; col++) {  
  41.                 index = row * width + col;  
  42.                 tr = (inPixels[index] >> 16) & 0xff;  
  43.                 histogram[tr]++;  
  44.             }  
  45.         }  
  46.         // 图像二值化 - OTSU 阈值化方法  
  47.         double total = width * height;  
  48.         double[] variances = new double[256];  
  49.         for(int i=0; i<variances.length; i++)  
  50.         {  
  51.             double bw = 0;  
  52.             double bmeans = 0;  
  53.             double bvariance = 0;  
  54.             double count = 0;  
  55.             for(int t=0; t<i; t++)  
  56.             {  
  57.                 count += histogram[t];  
  58.                 bmeans += histogram[t] * t;  
  59.             }  
  60.             bw = count / total;  
  61.             bmeans = (count == 0) ? 0 :(bmeans / count);  
  62.             for(int t=0; t<i; t++)  
  63.             {  
  64.                 bvariance += (Math.pow((t-bmeans),2) * histogram[t]);  
  65.             }  
  66.             bvariance = (count == 0) ? 0 : (bvariance / count);  
  67.             double fw = 0;  
  68.             double fmeans = 0;  
  69.             double fvariance = 0;  
  70.             count = 0;  
  71.             for(int t=i; t<histogram.length; t++)  
  72.             {  
  73.                 count += histogram[t];  
  74.                 fmeans += histogram[t] * t;  
  75.             }  
  76.             fw = count / total;  
  77.             fmeans = (count == 0) ? 0 : (fmeans / count);  
  78.             for(int t=i; t<histogram.length; t++)  
  79.             {  
  80.                 fvariance += (Math.pow((t-fmeans),2) * histogram[t]);  
  81.             }  
  82.             fvariance = (count == 0) ? 0 : (fvariance / count);  
  83.             variances[i] = bw * bvariance + fw * fvariance;  
  84.         }  
  85.   
  86.         // find the minimum within class variance  
  87.         double min = variances[0];  
  88.         int threshold = 0;  
  89.         for(int m=1; m<variances.length; m++)  
  90.         {  
  91.             if(min > variances[m]){  
  92.                 threshold = m;  
  93.                 min = variances[m];  
  94.             }  
  95.         }  
  96.         // 二值化  
  97.         System.out.println("final threshold value : " + threshold);  
  98.         for(int row=0; row<height; row++) {  
  99.             for(int col=0; col<width; col++) {  
  100.                 index = row * width + col;  
  101.                 int gray = (inPixels[index] >> 8) & 0xff;  
  102.                 if(gray > threshold)  
  103.                 {  
  104.                     gray = 255;  
  105.                     outPixels[index]  = (0xff << 24) | (gray << 16) | (gray << 8) | gray;  
  106.                 }  
  107.                 else  
  108.                 {  
  109.                     gray = 0;  
  110.                     outPixels[index]  = (0xff << 24) | (gray << 16) | (gray << 8) | gray;  
  111.                 }  
  112.                   
  113.             }  
  114.         }  
  115.         setRGB(dest, 00, width, height, outPixels );  
  116.         return dest;  
  117.     }  
  118.   
  119. }  

运行效果图:

展开阅读全文
©️2020 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值