圖像二值化是圖像分析與處理中最多見最重要的處理手段,二值處理方法也很是多。越java
精準的方法計算量也越大。本文主要介紹四種常見的二值處理方法,一般狀況下能夠滿ide
足大多數圖像處理的須要。主要本文討論的方法僅針對RGB色彩空間。this
方法一:url
該方法很是簡單,對RGB彩色圖像灰度化之後,掃描圖像的每一個像素值,值小於127的spa
將像素值設爲0(黑色),值大於等於127的像素值設爲255(白色)。該方法的好處是計算.net
量少速度快。缺點更多首先閾值爲127沒有任何理由能夠解釋,其次徹底不考慮圖像的orm
像素分佈情況與像素值特徵。能夠說該方法是史最弱智的二值處理方法一點也不爲過。對象
方法二:blog
最多見的二值處理方法是計算像素的平均值K,掃描圖像的每一個像素值如像素值大於Kip
像素值設爲255(白色),值小於等於K像素值設爲0(黑色)。該方法相比方法一,閾值的
選取稍微有點智商,能夠解釋。可是使用平均值做爲二值化閾值一樣有個致命的缺點,
可能致使部分對象像素或者背景像素丟失。二值化結果不能真實反映源圖像信息。
方法三:
使用直方圖方法來尋找二值化閾值,直方圖是圖像的重要特質,直方圖方法選擇二值
化閾值主要是發現圖像的兩個最高的峯,而後在閾值取值在兩個峯之間的峯谷最低處。
該方法相對前面兩種方法而言稍微精準一點點。結果也更讓人能夠接受。
方法四:http://en.wikipedia.org/wiki/Thresholding_(image_processing)
使用近似一維Means方法尋找二值化閾值,該方法的大體步驟以下:
1. 一個初始化閾值T,能夠本身設置或者根據隨機方法生成。
2. 根據閾值圖每一個像素數據P(n,m)分爲對象像素數據G1與背景像素數據G2。(n爲
行,m爲列)
3. G1的平均值是m1, G2的平均值是m2
4. 一個新的閾值T’ = (m1 + m2)/2
5. 回到第二步,用新的閾值繼續分像素數據爲對象與北京像素數據,繼續2~4步,
直到計算出來的新閾值等於上一次閾值。
前面三種在之前的博文中都有涉及,最後一種二值化方法的代碼以下:
- package com.gloomyfish.filter.study;
-
- import java.awt.image.BufferedImage;
- import java.util.ArrayList;
- import java.util.List;
-
- public class ThresholdBinaryFilter extends GrayFilter {
-
- @Override
- public BufferedImage filter(BufferedImage src, BufferedImage dest) {
- int width = src.getWidth();
- int height = src.getHeight();
-
- if ( dest == null )
- dest = createCompatibleDestImage( src, null );
-
- int[] inPixels = new int[width*height];
- int[] outPixels = new int[width*height];
- src = super.filter(src, null);
- getRGB( src, 0, 0, width, height, inPixels );
- int index = 0;
- int means = getThreshold(inPixels, height, width);
- for(int row=0; row<height; row++) {
- int ta = 0, tr = 0, tg = 0, tb = 0;
- for(int col=0; col<width; col++) {
- index = row * width + col;
- ta = (inPixels[index] >> 24) & 0xff;
- tr = (inPixels[index] >> 16) & 0xff;
- tg = (inPixels[index] >> 8) & 0xff;
- tb = inPixels[index] & 0xff;
- if(tr > means) {
- tr = tg = tb = 255;
- } else {
- tr = tg = tb = 0;
- }
- outPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
- }
- }
- setRGB( dest, 0, 0, width, height, outPixels );
- return dest;
- }
-
- private int getThreshold(int[] inPixels, int height, int width) {
-
- int inithreshold = 127;
- int finalthreshold = 0;
- int temp[] = new int[inPixels.length];
- for(int index=0; index<inPixels.length; index++) {
- temp[index] = (inPixels[index] >> 16) & 0xff;
- }
- List<Integer> sub1 = new ArrayList<Integer>();
- List<Integer> sub2 = new ArrayList<Integer>();
- int means1 = 0, means2 = 0;
- while(finalthreshold != inithreshold) {
- finalthreshold = inithreshold;
- for(int i=0; i<temp.length; i++) {
- if(temp[i] <= inithreshold) {
- sub1.add(temp[i]);
- } else {
- sub2.add(temp[i]);
- }
- }
- means1 = getMeans(sub1);
- means2 = getMeans(sub2);
- sub1.clear();
- sub2.clear();
- inithreshold = (means1 + means2) / 2;
- }
- long start = System.currentTimeMillis();
- System.out.println("Final threshold = " + finalthreshold);
- long endTime = System.currentTimeMillis() - start;
- System.out.println("Time consumes : " + endTime);
- return finalthreshold;
- }
-
- private static int getMeans(List<Integer> data) {
- int result = 0;
- int size = data.size();
- for(Integer i : data) {
- result += i;
- }
- return (result/size);
- }
-
- }
效果以下:
