您的位置:首页 > 其它

图像二值化----otsu(最大类间方差法)

2017-04-07 10:35 211 查看
/*****转自:http://blog.csdn.net/abcjennifer/article/details/6671288******/最大类间方差法是由日本学者大津于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,即为所求。
Otsu算法步骤如下:设图象包含L个灰度级(0,1…,L-1),灰度值为i的的象素点数为Ni ,图象总的象素点数为N=N0+N1+...+N(L-1)。灰度值为i的点的概为:P(i) = N(i)/N.门限t将整幅图象分为暗区c1和亮区c2两类,则类间方差σ是t的函数:σ=a1*a2(u1-u2)^2 (2)式中,aj 为类cj的面积与图象总面积之比,a1 = sum(P(i)) i->t, a2 = 1-a1; uj为类cj的均值,u1 = sum(i*P(i))/a1 0->t, u2 = sum(i*P(i))/a2, t+1->L-1 该法选择最佳门限t^ 使类间方差最大,即:令Δu=u1-u2,σb = max{a1(t)*a2(t)Δu^2}/****************************************以下部分内容为原创;OTSU代码**********************************************/

#include <stdio.h>
#include <string>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
#include
#include
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
// OTSU大均法函数实现
int OTSU(cv::Mat srcImage)
{
int nCols = srcImage.cols;
int nRows = srcImage.rows;
int threshold = 0;
// 初始化统计参数
int nSumPix[256];
float nProDis[256];
for (int i = 0; i < 256; i++)
{
nSumPix[i] = 0;
nProDis[i] = 0;
}
// 统计灰度级中每个像素在整幅图像中的个数
for (int i = 0; i < nCols; i++)
{
for (int j = 0; j < nRows; j++)
{
nSumPix[(int)srcImage.at(i, j)]++;
}
}
// 计算每个灰度级占图像中的概率分布
for (int i = 0; i < 256; i++)
{
nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
}
// 遍历灰度级[0,255],计算出最大类间方差下的阈值
float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
double delta_max = 0.0;
for (int i = 0; i < 256; i++)
{
// 初始化相关参数
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
for (int j = 0; j < 256; j++)
{
//背景部分
if (j <= i)
{
// 当前i为分割阈值,第一类总的概率
w0 += nProDis[j];
u0_temp += j * nProDis[j];
}
//前景部分
else
{
// 当前i为分割阈值,第一类总的概率
w1 += nProDis[j];
u1_temp += j * nProDis[j];
}
}
// 分别计算各类的平均灰度
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));
// 依次找到最大类间方差下的阈值
if (delta_temp > delta_max)
{
delta_max = delta_temp;
threshold = i;
}
}
return threshold;
}
int main()
{
// 图像读取及判断
cv::Mat srcImage = cv::imread("..\\images\\people.jpg");
if (!srcImage.data)
return 1;
// 灰度转换
cv::Mat srcGray;
cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
cv::imshow("srcGray", srcGray);
// 调用OTSU二值化算法得到阈值
int  ostuThreshold = OTSU(srcGray);
std::cout << ostuThreshold << std::endl;
// 定义输出结果图像
cv::Mat otsuResultImage =
cv::Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1);
// 利用得到的阈值实现二值化操作
for (int i = 0; i < srcGray.rows; i++)
{
for (int j = 0; j < srcGray.cols; j++)
{
// 满足大于阈值ostuThreshold置255
if (srcGray.at(i, j) > ostuThreshold)
otsuResultImage.at(i, j) = 255;
else
otsuResultImage.at(i, j) = 0;
}
}
cv::imshow("otsuResultImage", otsuResultImage);
cv::waitKey(0);
return 0;
}

// OTSU大均法函数实现
int OTSU(cv::Mat srcImage)
{
int nCols = srcImage.cols;
int nRows = srcImage.rows;
int threshold = 0;
// 初始化统计参数
int nSumPix[256];
float nProDis[256];
for (int i = 0; i < 256; i++)
{
nSumPix[i] = 0;
nProDis[i] = 0;
}
// 统计灰度级中每个像素在整幅图像中的个数
for (int i = 0; i < nCols; i++)
{
for (int j = 0; j < nRows; j++)
{
nSumPix[(int)srcImage.at<uchar>(i, j)]++;
}
}
// 计算每个灰度级占图像中的概率分布
for (int i = 0; i < 256; i++)
{
nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
}
// 遍历灰度级[0,255],计算出最大类间方差下的阈值
float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
double delta_max = 0.0;
for (int i = 0; i < 256; i++)
{
// 初始化相关参数
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
for (int j = 0; j < 256; j++)
{
//背景部分
if (j <= i)
{
// 当前i为分割阈值,第一类总的概率
w0 += nProDis[j];
u0_temp += j * nProDis[j];
}
//前景部分
else
{
// 当前i为分割阈值,第一类总的概率
w1 += nProDis[j];
u1_temp += j * nProDis[j];
}
}
// 分别计算各类的平均灰度
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));
// 依次找到最大类间方差下的阈值
if (delta_temp > delta_max)
{
delta_max = delta_temp;
threshold = i;
}
}
return threshold;
}
int main()
{
// 图像读取及判断
cv::Mat srcImage = cv::imread("..\\images\\people.jpg");
if (!srcImage.data)
return 1;
// 灰度转换
cv::Mat srcGray;
cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);
cv::imshow("srcGray", srcGray);
// 调用OTSU二值化算法得到阈值
int ostuThreshold = OTSU(srcGray);
std::cout << ostuThreshold << std::endl;
// 定义输出结果图像
cv::Mat otsuResultImage =
cv::Mat::zeros(srcGray.rows, srcGray.cols, CV_8UC1);
// 利用得到的阈值实现二值化操作
for (int i = 0; i < srcGray.rows; i++)
{
for (int j = 0; j < srcGray.cols; j++)
{
// 满足大于阈值ostuThreshold置255
if (srcGray.at<uchar>(i, j) > ostuThreshold)
otsuResultImage.at<uchar>(i, j) = 255;
else
otsuResultImage.at<uchar>(i, j) = 0;
}
}
cv::imshow("otsuResultImage", otsuResultImage);
cv::waitKey(0);
return 0;
}

/****************************************以下内容为MATLAB实现的OTSU代码**********************************************/



[plain] view
plain copy

I=imread('D:\Images\pic_loc\1870405130305041503.jpg');  

a=rgb2gray(I);  

level = graythresh(a);  

a=im2bw(a,level);  

imshow(a,[]); 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: