现在的位置: 首页 > 综合 > 正文

使用大津法二值化灰度图像

2014年08月25日 ⁄ 综合 ⁄ 共 1854字 ⁄ 字号 评论关闭
       二值化是图像分割的一种方法,即将256个亮度等级的灰度图像通过适当的阈值选取,使得所有小于该阈值的像素置为一个值,所有大于该阈值的像素置为另一个值,最终得到一张非黑即白的二值图像。可见阈值的选择非常重要,不同的阈值,运算后得到的结果图像是完全不同的。对于多张图像,如何选取每一张图像合适的阈值呢?采用主观判定显然不太现实,合理的选择应该是采用一种自适应的阈值计算方法。自适应阈值计算,我主要看了大津法(维基百科),即最大类间方差法,由日本学者大津展之于1979年提出,简称Otsu,算法基本思想是:设使用某一个阈值将灰度图像根据灰度大小,分成前景部分和背景部分,在这两部分“类间差异最大”(也即“类内差异最小”)的时候,得到的阈值即是最优的二值化阈值。算法原理维基百科讲的很详细,这里不再赘述,只是配的程序实在不敢恭维,或许也就计算机能明白。
       大津法c++实现:

#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>

using namespace cv;

// 大津法求阈值
uchar OtsuThreshold(Mat &imgGray)
{  	
	int width  = imgGray.cols;
	int height = imgGray.rows;
	int histData[256] = { 0 };

	// 直方图统计
	uchar *pImg = imgGray.data;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			histData[pImg[j]]++;
		}
		pImg += imgGray.step;
	}

	// 计算像素总数及灰度总和
	int totalCount = width * height;
	double graySum = 0.0;
	for (int i = 0; i < 256; i++)
	{
		graySum += i * histData[i];
	}

	uchar threshold = 0;
	int backCount = 0, foreCount = 0;
	double backGraySum = 0.0, varMax = -999.9;
	for (int i = 0; i < 256; i++)
	{
		// 背景像素数
		backCount += histData[i];
		if (backCount == 0)
		{
			continue;
		}

		// 前景像素数
		foreCount = totalCount - backCount;
		if (foreCount == 0)
		{
			break;
		}

		// 背景像素灰度总和
		backGraySum += double(i * histData[i]);
		// 背景/前景均值
		double backMean = backGraySum / backCount;
		double foreMean = (graySum - backGraySum) / foreCount;

		// 计算类间差异
		double varBetween = backCount * foreCount * (backMean - foreMean) * (backMean - foreMean);
		// 最大值位置,即阈值
		if (varBetween > varMax)
		{
			varMax = varBetween;
			threshold = i;
		}
	}

	return threshold;
}

int main(int argc, _TCHAR* argv[])
{
	Mat img = imread("image\\snow.jpg");
	imshow("src", img);

	// 计算阈值
	Mat imgGray;
	cvtColor(img, imgGray, CV_BGR2GRAY);
	uchar threshold = OtsuThreshold(imgGray);

	// 二值化
	int width  = imgGray.cols;
	int height = imgGray.rows;
	uchar *pImg = imgGray.data;
	for (int i = 0; i < height; i++)
	{  
		for (int j = 0; j < width; j++)
		{
			pImg[j] = (pImg[j] > threshold) ? 255 : 0;
		}
		pImg += imgGray.step;
	}
	imshow("result", imgGray);

	waitKey();
	return 0;
}

运行结果:

工程下载链接:http://download.csdn.net/detail/u013085897/6774265

程序基于vs2005 + opencv210实现,下载工程后,如果与自己使用的opencv版本不一致,则需要对工程进行简单配置才能正确运行。

抱歉!评论已关闭.