Otsu Thresholding

今天复习Otsu算法,它利用阈值奖图片转成黑白色。Otsu算法是二值算法,目的是求出一个Threshhold,来最小化Within-Class方差,这等价最大化between-class方差。下面用java来实现算法。
package com.lili.ots<pre name="code" class="java">package com.lili.otsu;
public class OtsuThresholder
{
	private int histData[];
	private int maxLevelValue;
	private int threshold;

	public OtsuThresholder()
	{
		histData = new int[256];
	}

	public int[] getHistData()
	{
		return histData;
	}

	public int getMaxLevelValue()
	{
		return maxLevelValue;
	}

	public int getThreshold()
	{
		return threshold;
	}

	public int doThreshold(byte[] srcData, byte[] monoData)
	{
		int ptr;

		// Clear histogram data
		// Set all values to zero
		ptr = 0;
		while (ptr < histData.length) histData[ptr++] = 0;

		// Calculate histogram and find the level with the max value
		// Note: the max level value isn't required by the Otsu method
		ptr = 0;
		maxLevelValue = 0;
		while (ptr < srcData.length)
		{
			int h = 0xFF & srcData[ptr];  
			histData[h] ++;
			if (histData[h] > maxLevelValue) maxLevelValue = histData[h];
			ptr ++;
		}

		// Total number of pixels
		int total = srcData.length;                //48*57 image, total=48*57

		float sum = 0;
		for (int t=0 ; t<256 ; t++) sum += t * histData[t];

		float sumB = 0;
		int wB = 0;
		int wF = 0;

		float varMax = 0;
		threshold = 0;

		for (int t=0 ; t<256 ; t++)
		{
			wB += histData[t];					// Weight Background 
			if (wB == 0) continue;   // 'cause divide           the number of pixle of background

			wF = total - wB;						// Weight Foreground
			if (wF == 0) break;                

			sumB += (float) (t * histData[t]);

			float mB = sumB / wB;				// Mean Background
			float mF = (sum - sumB) / wF;		// Mean Foreground

			// Calculate Between Class Variance
			float varBetween = (float)wB * (float)wF * (mB - mF) * (mB - mF);	

			// Check if new maximum found
			if (varBetween > varMax) {
				varMax = varBetween;
				threshold = t;
			}
		}

		// Apply threshold to create binary image
		if (monoData != null)
		{
			ptr = 0;
			while (ptr < srcData.length)            // 48*57
			{
				monoData[ptr] = ((0xFF & srcData[ptr]) >= threshold) ? (byte) 255 : 0;
				ptr ++;
			}
		}

		return threshold;
	}
}

package com.lili.otsu;


import java.io.*;



import java.util.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;

import com.lili.otsu.GreyFrame;
import com.lili.otsu.OtsuThresholder;

public class OtsuDemo
{
	public OtsuDemo(String filename)
	{
		// Load Source image
		BufferedImage srcImage = null;

		try
		{
			File imgFile = new File(filename);
			srcImage = javax.imageio.ImageIO.read(imgFile);
		}
		catch (IOException ioE)
		{
			System.err.println(ioE);
			System.exit(1);
		}

		int width = srcImage.getWidth();
		int height = srcImage.getHeight();

		// Get raw image data
		Raster raster = srcImage.getData();
		DataBuffer buffer = raster.getDataBuffer();

		int type = buffer.getDataType();
		if (type != DataBuffer.TYPE_BYTE)
		{
			System.err.println("Wrong image data type");
			System.exit(1);
		}
		if (buffer.getNumBanks() != 1)
		{
			System.err.println("Wrong image data format");
			System.exit(1);
		}

		DataBufferByte byteBuffer = (DataBufferByte) buffer;
		byte[] srcData = byteBuffer.getData(0);

		// Sanity check image
		if (width * height  != srcData.length) {
			System.err.println("Unexpected image data size. Should be greyscale image");
			System.exit(1);
		}

		// Output Image info
		System.out.printf("Loaded image: '%s', width: %d, height: %d, num bytes: %d\n", filename, width, height, srcData.length);

		byte[] dstData = new byte[srcData.length];

		// Create Otsu Thresholder
		OtsuThresholder thresholder = new OtsuThresholder();
		int threshold = thresholder.doThreshold(srcData, dstData);
		

		System.out.printf("Threshold: %d\n", threshold);

		// Create GUI
		GreyFrame srcFrame = new GreyFrame(width, height, srcData);
		GreyFrame dstFrame = new GreyFrame(width, height, dstData);
		GreyFrame histFrame = createHistogramFrame(thresholder);

		JPanel infoPanel = new JPanel();
		infoPanel.add(histFrame);

		JPanel panel = new JPanel(new BorderLayout(5, 5));
		panel.setBorder(new javax.swing.border.EmptyBorder(5, 5, 5, 5));
		panel.add(infoPanel, BorderLayout.NORTH);
		panel.add(srcFrame, BorderLayout.WEST);
		panel.add(dstFrame, BorderLayout.EAST);
		panel.add(new JLabel("QingrouShui", JLabel.CENTER), BorderLayout.SOUTH);

		JFrame frame = new JFrame("QingrouShui");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(panel);
		frame.pack();
		frame.setVisible(true);

		// Save Images
		try
		{
			int dotPos = filename.lastIndexOf(".");
			String basename = filename.substring(0,dotPos);

			javax.imageio.ImageIO.write(dstFrame.getBufferImage(), "PNG", new File(basename+"_BW.png"));
			javax.imageio.ImageIO.write(histFrame.getBufferImage(), "PNG", new File(basename+"_hist.png"));
		}
		catch (IOException ioE)
		{
			System.err.println("Could not write image " + filename);
		}
	}

	private GreyFrame createHistogramFrame(OtsuThresholder thresholder)
	{
		int numPixels = 256 * 100;
		byte[] histPlotData = new byte[numPixels];

		int[] histData = thresholder.getHistData();
		int max = thresholder.getMaxLevelValue();
		int threshold = thresholder.getThreshold();
		
		
		for (int l=0 ; l<256 ; l++)
		{
			int ptr = (numPixels - 256) + l;
			int val = (100 * histData[l]) / max;

			if (l == threshold)
			{
				for (int i=0 ; i<100 ; i++, ptr-=256) histPlotData[ptr] = (byte) 128;
			}
			else
			{
				for (int i=0 ; i<100 ; i++, ptr-=256) histPlotData[ptr] = (val < i) ? (byte) 255 : 0;
			}
		}

		return new GreyFrame(256, 100, histPlotData);
	}

	public static void main(String args[])
	{
		new OtsuDemo("lili_icmv12.png");
		System.out.println("QingrouShui");
//		if (args.length<1) {
//			System.err.println("Provide image filename");
//			System.exit(1);
//		}
		

		
	}
}

 
<pre name="code" class="java">package com.lili.otsu;
import java.awt.*;

import javax.swing.*;
import java.awt.image.*;
import java.awt.color.*;

public class GreyFrame extends JComponent
{
	private int width;
	private int height;
	private Dimension size;
	private BufferedImage image;
	private String title;


	public GreyFrame(int width, int height, byte[] data)
	{
		this(width, height, data, null);
	}

	public GreyFrame(int width, int height, byte[] data, String title)
	{
		this.width = width;
		this.height = height;
		this.title = title;
		size = new Dimension(width, height);

		DataBufferByte dataBuffer = new DataBufferByte(data, data.length, 0);

		PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, 1, width, new int[] {0});
		ColorSpace colourSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
		ComponentColorModel colourModel = new ComponentColorModel(colourSpace, new int[] {8}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);

		WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);

		image = new BufferedImage(colourModel, raster, false, null);
	}

	public Graphics2D getBufferImageGraphics()
	{
		return image.createGraphics();
	}

	public BufferedImage getBufferImage()
	{
		return image;
	}

	public Dimension getSize()
	{
		return size;
	}

	public Dimension getPreferredSize()
	{
		return size;
	}

	public void paint(Graphics g)
	{
		super.paint(g);
		if (image != null) g.drawImage(image, 0, 0, this);

		if (title != null) {
			g.setColor(Color.RED);
			g.drawString(title, 5, height - 5);
		}
	}
}

<img src="https://img-blog.csdn.net/20150401123028357" alt="" /><img src="https://img-blog.csdn.net/20150401123001341" alt="" />
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值