大津法(otsu),中间像素统计法,kittler全局阈值图像二值化

图像的二值化有很多方法,这里介绍的三种是全局阈值的二值化方法。

这里给个原图:

1.大津法

大津算法的源代码非本人所写,见下面参考文献,这个算法实现的很好。大津算法的所用的时间是2.0ms。阈值为117.处理结果如下:

2.中间像素统计法

这个算法的具体名称我也不清楚,,姑且这么叫吧。取像素数中值的灰度作为阈值,以此阈值进行二值化。

这个算法所用的时间1.3ms。阈值为130.处理结果如下:

3.kittler算法

是一种快速的全局阈值法。它的中心思想是,计算整幅图像的梯度灰度的平均值,以此平均值做为阈值。百科上说它比大津法速度快很多倍,而且效果也差不多,但是实际情况却并不理想,难道是我程序写的有问题?

这个算法运行时间有3.5ms,所确定的阈值是122. 处理结果如下:

源代码如下:

// 20130624_Binaryzation.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "highgui.h"#include<windows.h>//为了测试程序运行时间所定义的变量LARGE_INTEGER freq, start, end;char info[256];double dTime = 0;void midValueBinary( IplImage *imge){int *histogram = new int [256 ];int height = imge->height;int width = imge->width;int widthStep = imge->widthStep;char *pData = imge->imageData;int t_nTotalPiexl = imge -> height * imge -> width;int count = 0;for ( int i = 0; i < 256; ++i )histogram[i] = 0;//统计直方图中的相应的灰度的数量for ( int i = 0; i < height; ++i )for( int j = 0; j < width; ++j ){int pos = i * ( widthStep) + j;++histogram[ ( uchar ) pData[ pos ] ];}int threshold = 0; //阈值大小for ( ; threshold < 256; ++threshold ){if ( count > t_nTotalPiexl / 2 ) //比总像素数一半大的灰度即为阈值break;count += histogram[threshold];}printf( " threshold的大小: %d ", threshold );for ( int i = 0; i < height ; ++i )for( int j = 0; j <width; ++j ){int curPos = i *widthStep + j;pData[curPos] = (uchar)pData[curPos] > threshold ? 255 : 0;}delete histogram;}void Kittler( IplImage *imge ){int sumGrads = 0;int sumGrayGrads = 0;char *pData = imge->imageData;int height = imge ->height;int width = imge->width;int widthStep = imge->widthStep; for ( int i = 1; i < height – 1; i++ )for( int j = 1; j < width – 1; j++ ){int curPos = i * widthStep + j;int leftPos = curPos – 1;int rightPos = curPos + 1;int upPos = curPos -widthStep;int downPos =curPos + widthStep;//求水平或垂直方向的最大梯度int Grads=MAX(abs(pData[leftPos]-pData[rightPos]),abs(pData[upPos] -pData[downPos]));sumGrads += Grads;//梯度与当前点灰度的积sumGrayGrads += Grads*((uchar)pData[curPos]);} int threshold = sumGrayGrads / sumGrads;printf("%d\n",threshold);for ( int i = 0; i < height; ++i )for( int j = 0; j <width; ++j ){int curPos = i *widthStep + j;pData[curPos] = (uchar)pData[curPos] >threshold ? 255 : 0;}}void myOtsu(const IplImage *frame) //大津法求阈值{#define GrayScale 256//frame灰度级int width = frame->width;int height = frame->height;int pixelCount[GrayScale]={0};float pixelPro[GrayScale]={0};int i, j, pixelSum = width * height, threshold = 0;uchar* pData = (uchar*)frame->imageData;//统计每个灰度级中像素的个数for(i = 0; i < height; i++){for(j = 0;j < width;j++){pixelCount[(int)pData[i * width + j]]++;}}//计算每个灰度级的像素数目占整幅图像的比例for(i = 0; i < GrayScale; i++){pixelPro[i] = (float)pixelCount[i] / pixelSum;}//遍历灰度级[0,255],寻找合适的thresholdfloat w0, w1, u0tmp, u1tmp, u0, u1, deltaTmp, deltaMax = 0;for(i = 0; i < GrayScale; i++){w0 = w1 = u0tmp = u1tmp = u0 = u1 = deltaTmp = 0;for(j = 0; j < GrayScale; j++){if(j <= i) //背景部分{w0 += pixelPro[j];u0tmp += j * pixelPro[j];}else //前景部分{w1 += pixelPro[j];u1tmp += j * pixelPro[j];}}u0 = u0tmp / w0;u1 = u1tmp / w1;deltaTmp = (float)(w0 *w1* pow((u0 – u1), 2)) ;if(deltaTmp > deltaMax){deltaMax = deltaTmp;threshold = i;}}//return threshold;printf("阈值为:%d \n ", threshold);for ( int i = 0; i < height ; ++i )for( int j = 0; j <width; ++j ){int curPos = i *frame ->widthStep + j;pData[curPos] = (uchar)pData[curPos] >threshold ? 255 : 0;}}int main(int argc, char* argv[]){IplImage *imge = cvLoadImage("lena.bmp", -1);//测量程序运行时间开始QueryPerformanceFrequency(&freq);QueryPerformanceCounter(&start);//要运行的函数//midValueBinary(imge);//Kittler(imge);myOtsu(imge);//测量程序运行时间结束QueryPerformanceCounter(&end);dTime = (double)(end.QuadPart – start.QuadPart);dTime = 1000*dTime / freq.QuadPart;printf( " time: %.2f ms.\n", dTime);cvShowImage("lena.bmp", imge);// wait for a keycvWaitKey(0);// release the imagecvReleaseImage(&imge);return 0;}参考文献:

%E5%A4%A7%E6%B4%A5%E7%AE%97%E6%B3%95

没有朋友的人生是孤独的,不完整的,可是,因为生活的忙碌,

大津法(otsu),中间像素统计法,kittler全局阈值图像二值化

相关文章:

你感兴趣的文章:

标签云: