<span style="font-size:14px;word-wrap: normal; word-break: normal; "><strong><span style="word-wrap: normal; word-break: normal; font-family: 宋体; ">OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法。</span></strong></span>
1. OTSU算法原理简介
对于一幅图像,设当前景与背景的分割阈值为t时,前景点占图像比例为w0,均值为u0,背景点占图像比例为w1,均值为u1。则整个图像的均值为u = w0*u0+w1*u1。建立目标函数g(t)=w0*(u0-u)^2+w1*(u1-u)^2,g(t)就是当分割阈值为t时的类间方差表达式。OTSU算法使得g(t)取得全局最大值,当g(t)为最大时所对应的t称为最佳阈值。OTSU算法又称为最大类间方差法。
2.OTSU算法例程
下面是OSTU算法的C语言代码及其测试,代码基于opencv。
[cpp]
view plain
copy
- #include
- #include
-
- int
otsu(IplImage *image) - {
-
assert(NULL != image); -
-
int width = image->width; -
int height = image->height; -
int x=0,y=0; -
int pixelCount[256]; -
float pixelPro[256]; -
int i, j, pixelSum = width * height, threshold = 0; -
-
uchar* data = (uchar*)image->imageData; -
-
//初始化 -
for(i = 0; i < 256; i++) -
{ -
pixelCount[i] = 0; -
pixelPro[i] = 0; -
} -
-
//统计灰度级中每个像素在整幅图像中的个数 -
for(i = y; i < height; i++) -
{ -
for(j = x;j -
{ -
pixelCount[data[i * image->widthStep + j]]++; -
} -
} -
-
-
//计算每个像素在整幅图像中的比例 -
for(i = 0; i < 256; i++) -
{ -
pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum); -
} -
-
//经典ostu算法,得到前景和背景的分割 -
//遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值 -
float w0, w1, u0tmp, u1tmp, u0, u1, u,deltaTmp, deltaMax = 0; -
for(i = 0; i < 256; i++) -
{ -
w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0; -
-
for(j = 0; j < 256; j++) -
{ -
if(j <= i) //背景部分 -
{ -
//以i为阈值分类,第一类总的概率 -
w0 += pixelPro[j]; -
u0tmp += j * pixelPro[j]; -
} -
else //前景部分 -
{ -
//以i为阈值分类,第二类总的概率 -
w1 += pixelPro[j]; -
u1tmp += j * pixelPro[j]; -
} -
} -
-
u0 = u0tmp / w0; //第一类的平均灰度 -
u1 = u1tmp / w1; //第二类的平均灰度 -
u = u0tmp + u1tmp; //整幅图像的平均灰度 -
//计算类间方差 -
deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u); -
//找出最大类间方差以及对应的阈值 -
if(deltaTmp > deltaMax) -
{ -
deltaMax = deltaTmp; -
threshold = i; -
} -
} -
//返回最佳阈值; -
return threshold; - }
-
- int
main(int argc, char* argv[]) - {
-
IplImage* srcImage = cvLoadImage("D:\\technology\\CV\\Database\\image\\rice.png",0); -
assert(NULL != srcImage); -
-
cvNamedWindow("src"); -
cvShowImage("src",srcImage); -
-
IplImage* biImage = cvCreateImage(cvGetSize(srcImage),8,1); -
-
//计算最佳阈值 -
int threshold = otsu(srcImage); -
//对图像二值化 -
cvThreshold(srcImage,biImage,threshold,255,CV_THRESH_BINARY); -
-
cvNamedWindow("binary"); -
cvShowImage("binary",biImage); -
-
cvWaitKey(0); -
-
cvReleaseImage(&srcImage); -
cvReleaseImage(&biImage); -
cvDestroyWindow("src"); -
cvDestroyWindow("binary"); -
-
return 0; - }
下面是上述代码的运行结果图片。其中左边为原图像,右边为使用OTSU算法进行二值化后的图像。