【图像算法】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)
图像算法:图像阈值分割
SkySeraph Dec 21st 2010 HQU
Email:zgzhaobo@gmail.com QQ:452728574
Latest Modified Date:Dec.21st 2010 HQU
一、工具:VC+OpenCV
二、语言:C++
三、原理(略)
四、程序
主程序(核心部分)
- 代码
- 1 /*===============================图像分割=====================================*/
- 2 /*---------------------------------------------------------------------------*/
- 3 /*手动设置阀值*/
- 4 IplImage* binaryImg = cvCreateImage(cvSize(w, h),IPL_DEPTH_8U, 1);
- 5 cvThreshold(smoothImgGauss,binaryImg,71,255,CV_THRESH_BINARY);
- 6 cvNamedWindow("cvThreshold", CV_WINDOW_AUTOSIZE );
- 7 cvShowImage( "cvThreshold", binaryImg );
- 8 //cvReleaseImage(&binaryImg);
- 9 /*---------------------------------------------------------------------------*/
- 10 /*自适应阀值 //计算像域邻域的平均灰度,来决定二值化的值*/
- 11 IplImage* adThresImg = cvCreateImage(cvSize(w, h),IPL_DEPTH_8U, 1);
- 12 double max_value=255;
- 13 int adpative_method=CV_ADAPTIVE_THRESH_GAUSSIAN_C;//CV_ADAPTIVE_THRESH_MEAN_C
- 14 int threshold_type=CV_THRESH_BINARY;
- 15 int block_size=3;//阈值的象素邻域大小
- 16 int offset=5;//窗口尺寸
- 17 cvAdaptiveThreshold(smoothImgGauss,adThresImg,max_value,adpative_method,threshold_type,block_size,offset);
- 18 cvNamedWindow("cvAdaptiveThreshold", CV_WINDOW_AUTOSIZE );
- 19 cvShowImage( "cvAdaptiveThreshold", adThresImg );
- 20 cvReleaseImage(&adThresImg);
- 21 /*---------------------------------------------------------------------------*/
- 22 /*最大熵阀值分割法*/
- 23 IplImage* imgMaxEntropy = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
- 24 MaxEntropy(smoothImgGauss,imgMaxEntropy);
- 25 cvNamedWindow("MaxEntroyThreshold", CV_WINDOW_AUTOSIZE );
- 26 cvShowImage( "MaxEntroyThreshold", imgMaxEntropy );//显示图像
- 27 cvReleaseImage(&imgMaxEntropy );
- 28 /*---------------------------------------------------------------------------*/
- 29 /*基本全局阀值法*/
- 30 IplImage* imgBasicGlobalThreshold = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
- 31 cvCopyImage(srcImgGrey,imgBasicGlobalThreshold);
- 32 int pg[256],i,thre;
- 33 for (i=0;i<256;i++) pg[i]=0;
- 34 for (i=0;i<imgBasicGlobalThreshold->imageSize;i++) // 直方图统计
- 35 pg[(BYTE)imgBasicGlobalThreshold->imageData[i]]++;
- 36 thre = BasicGlobalThreshold(pg,0,256); // 确定阈值
- 37 cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<thre<<endl;//输出显示阀值
- 38 cvThreshold(imgBasicGlobalThreshold,imgBasicGlobalThreshold,thre,255,CV_THRESH_BINARY); // 二值化
- 39 cvNamedWindow("BasicGlobalThreshold", CV_WINDOW_AUTOSIZE );
- 40 cvShowImage( "BasicGlobalThreshold", imgBasicGlobalThreshold);//显示图像
- 41 cvReleaseImage(&imgBasicGlobalThreshold);
- 42 /*---------------------------------------------------------------------------*/
- 43 /*OTSU*/
- 44 IplImage* imgOtsu = cvCreateImage(cvGetSize(imgGrey),IPL_DEPTH_8U,1);
- 45 cvCopyImage(srcImgGrey,imgOtsu);
- 46 int thre2;
- 47 thre2 = otsu2(imgOtsu);
- 48 cout<<"The Threshold of this Image in Otsu is:"<<thre2<<endl;//输出显示阀值
- 49 cvThreshold(imgOtsu,imgOtsu,thre2,255,CV_THRESH_BINARY); // 二值化
- 50 cvNamedWindow("imgOtsu", CV_WINDOW_AUTOSIZE );
- 51 cvShowImage( "imgOtsu", imgOtsu);//显示图像
- 52 cvReleaseImage(&imgOtsu);
- 53 /*---------------------------------------------------------------------------*/
- 54 /*上下阀值法:利用正态分布求可信区间*/
- 55 IplImage* imgTopDown = cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U, 1 );
- 56 cvCopyImage(srcImgGrey,imgTopDown);
- 57 CvScalar mean ,std_dev;//平均值、 标准差
- 58 double u_threshold,d_threshold;
- 59 cvAvgSdv(imgTopDown,&mean,&std_dev,NULL);
- 60 u_threshold = mean.val[0] +2.5* std_dev.val[0];//上阀值
- 61 d_threshold = mean.val[0] -2.5* std_dev.val[0];//下阀值
- 62 //u_threshold = mean + 2.5 * std_dev; //错误
- 63 //d_threshold = mean - 2.5 * std_dev;
- 64 cout<<"The TopThreshold of this Image in TopDown is:"<<d_threshold<<endl;//输出显示阀值
- 65 cout<<"The DownThreshold of this Image in TopDown is:"<<u_threshold<<endl;
- 66 cvThreshold(imgTopDown,imgTopDown,d_threshold,u_threshold,CV_THRESH_BINARY_INV);//上下阀值
- 67 cvNamedWindow("imgTopDown", CV_WINDOW_AUTOSIZE );
- 68 cvShowImage( "imgTopDown", imgTopDown);//显示图像
- 69 cvReleaseImage(&imgTopDown);
- 70 /*---------------------------------------------------------------------------*/
- 71 /*迭代法*/
- 72 IplImage* imgIteration = cvCreateImage( cvGetSize(imgGrey), IPL_DEPTH_8U, 1 );
- 73 cvCopyImage(srcImgGrey,imgIteration);
- 74 int thre3,nDiffRec;
- 75 thre3 =DetectThreshold(imgIteration, 100, nDiffRec);
- 76 cout<<"The Threshold of this Image in imgIteration is:"<<thre3<<endl;//输出显示阀值
- 77 cvThreshold(imgIteration,imgIteration,thre3,255,CV_THRESH_BINARY_INV);//上下阀值
- 78 cvNamedWindow("imgIteration", CV_WINDOW_AUTOSIZE );
- 79 cvShowImage( "imgIteration", imgIteration);
- 80 cvReleaseImage(&imgIteration);
模块程序
迭代法
- 代码
- /*======================================================================*/
- /* 迭代法*/
- /*======================================================================*/
- // nMaxIter:最大迭代次数;nDiffRec:使用给定阀值确定的亮区与暗区平均灰度差异值
- int DetectThreshold(IplImage*img, int nMaxIter, int& iDiffRec) //阀值分割:迭代法
- {
- //图像信息
- int height = img->height;
- int width = img->width;
- int step = img->widthStep/sizeof(uchar);
- uchar *data = (uchar*)img->imageData;
- iDiffRec =;
- int F[]={ }; //直方图数组
- int iTotalGray=;//灰度值和
- int iTotalPixel =;//像素数和
- byte bt;//某点的像素值
- uchar iThrehold,iNewThrehold;//阀值、新阀值
- uchar iMaxGrayValue=,iMinGrayValue=;//原图像中的最大灰度值和最小灰度值
- uchar iMeanGrayValue1,iMeanGrayValue2;
- //获取(i,j)的值,存于直方图数组F
- for(int i=;i<width;i++)
- {
- for(int j=;j<height;j++)
- {
- bt = data[i*step+j];
- if(bt<iMinGrayValue)
- iMinGrayValue = bt;
- if(bt>iMaxGrayValue)
- iMaxGrayValue = bt;
- F[bt]++;
- }
- }
- iThrehold =;//
- iNewThrehold = (iMinGrayValue+iMaxGrayValue)/;//初始阀值
- iDiffRec = iMaxGrayValue - iMinGrayValue;
- for(int a=;(abs(iThrehold-iNewThrehold)>0.5)&&a<nMaxIter;a++)//迭代中止条件
- {
- iThrehold = iNewThrehold;
- //小于当前阀值部分的平均灰度值
- for(int i=iMinGrayValue;i<iThrehold;i++)
- {
- iTotalGray += F[i]*i;//F[]存储图像信息
- iTotalPixel += F[i];
- }
- iMeanGrayValue1 = (uchar)(iTotalGray/iTotalPixel);
- //大于当前阀值部分的平均灰度值
- iTotalPixel =;
- iTotalGray =;
- for(int j=iThrehold+;j<iMaxGrayValue;j++)
- {
- iTotalGray += F[j]*j;//F[]存储图像信息
- iTotalPixel += F[j];
- }
- iMeanGrayValue2 = (uchar)(iTotalGray/iTotalPixel);
- iNewThrehold = (iMeanGrayValue2+iMeanGrayValue1)/; //新阀值
- iDiffRec = abs(iMeanGrayValue2 - iMeanGrayValue1);
- }
- //cout<<"The Threshold of this Image in imgIteration is:"<<iThrehold<<endl;
- return iThrehold;
- }
Otsu代码一
- 代码
- /*======================================================================*/
- /* OTSU global thresholding routine */
- /* takes a 2D unsigned char array pointer, number of rows, and */
- /* number of cols in the array. returns the value of the threshold */
- /*parameter:
- *image --- buffer for image
- rows, cols --- size of image
- x0, y0, dx, dy --- region of vector used for computing threshold
- vvv --- debug option, is 0, no debug information outputed
- */
- /*
- OTSU 算法可以说是自适应计算单阈值(用来转换灰度图像为二值图像)的简单高效方法。
- 下面的代码最早由 Ryan Dibble提供,此后经过多人Joerg.Schulenburg, R.Z.Liu 等修改,补正。
- 算法对输入的灰度图像的直方图进行分析,将直方图分成两个部分,使得两部分之间的距离最大。
- 划分点就是求得的阈值。
- */
- /*======================================================================*/
- int otsu (unsigned char*image, int rows, int cols, int x0, int y0, int dx, int dy, int vvv)
- {
- unsigned char*np; // 图像指针
- int thresholdValue=; // 阈值
- int ihist[]; // 图像直方图,256个点
- int i, j, k; // various counters
- int n, n1, n2, gmin, gmax;
- double m1, m2, sum, csum, fmax, sb;
- // 对直方图置零
- memset(ihist, , sizeof(ihist));
- gmin=; gmax=;
- // 生成直方图
- for (i = y0 +; i < y0 + dy -; i++)
- {
- np = (unsigned char*)image[i*cols+x0+];
- for (j = x0 +; j < x0 + dx -; j++)
- {
- ihist[*np]++;
- if(*np > gmax) gmax=*np;
- if(*np < gmin) gmin=*np;
- np++; /* next pixel */
- }
- }
- // set up everything
- sum = csum =0.0;
- n =;
- for (k =; k <=; k++)
- {
- sum += (double) k * (double) ihist[k]; /* x*f(x) 质量矩*/
- n += ihist[k]; /* f(x) 质量 */
- }
- if (!n)
- {
- // if n has no value, there is problems...
- fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
- return ();
- }
- // do the otsu global thresholding method
- fmax =-1.0;
- n1 =;
- for (k =; k <; k++)
- {
- n1 += ihist[k];
- if (!n1)
- {
- continue;
- }
- n2 = n - n1;
- if (n2 ==)
- {
- break;
- }
- csum += (double) k *ihist[k];
- m1 = csum / n1;
- m2 = (sum - csum) / n2;
- sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2);
- /* bbg: note: can be optimized. */
- if (sb > fmax)
- {
- fmax = sb;
- thresholdValue = k;
- }
- }
- // at this point we have our thresholding value
- // debug code to display thresholding values
- if ( vvv & )
- fprintf(stderr,"# OTSU: thresholdValue = %d gmin=%d gmax=%d\n",
- thresholdValue, gmin, gmax);
- return(thresholdValue);
- }
Otsu代码二
- 代码
- /*======================================================================*/
- /* OTSU global thresholding routine */
- /*======================================================================*/
- int otsu2 (IplImage *image)
- {
- int w = image->width;
- int h = image->height;
- unsigned char*np; // 图像指针
- unsigned char pixel;
- int thresholdValue=; // 阈值
- int ihist[]; // 图像直方图,256个点
- int i, j, k; // various counters
- int n, n1, n2, gmin, gmax;
- double m1, m2, sum, csum, fmax, sb;
- // 对直方图置零...
- memset(ihist, , sizeof(ihist));
- gmin=; gmax=;
- // 生成直方图
- for (i =; i < h; i++)
- {
- np = (unsigned char*)(image->imageData + image->widthStep*i);
- for (j =; j < w; j++)
- {
- pixel = np[j];
- ihist[ pixel]++;
- if(pixel > gmax) gmax= pixel;
- if(pixel < gmin) gmin= pixel;
- }
- }
- // set up everything
- sum = csum =0.0;
- n =;
- for (k =; k <=; k++)
- {
- sum += k * ihist[k]; /* x*f(x) 质量矩*/
- n += ihist[k]; /* f(x) 质量 */
- }
- if (!n)
- {
- // if n has no value, there is problems...
- //fprintf (stderr, "NOT NORMAL thresholdValue = 160\n");
- thresholdValue =;
- goto L;
- }
- // do the otsu global thresholding method
- fmax =-1.0;
- n1 =;
- for (k =; k <; k++)
- {
- n1 += ihist[k];
- if (!n1) { continue; }
- n2 = n - n1;
- if (n2 ==) { break; }
- csum += k *ihist[k];
- m1 = csum / n1;
- m2 = (sum - csum) / n2;
- sb = n1 * n2 *(m1 - m2) * (m1 - m2);
- /* bbg: note: can be optimized. */
- if (sb > fmax)
- {
- fmax = sb;
- thresholdValue = k;
- }
- }
- L:
- for (i =; i < h; i++)
- {
- np = (unsigned char*)(image->imageData + image->widthStep*i);
- for (j =; j < w; j++)
- {
- if(np[j] >= thresholdValue)
- np[j] =;
- else np[j] =;
- }
- }
- //cout<<"The Threshold of this Image in Otsu is:"<<thresholdValue<<endl;
- return(thresholdValue);
- }
最大熵阀值
- 代码
- /*============================================================================
- = 代码内容:最大熵阈值分割
- = 修改日期:2009-3-3
- = 作者:crond123
- = 博客:http://blog.csdn.net/crond123/
- = E_Mail:crond123@163.com
- ===============================================================================*/
- // 计算当前位置的能量熵
- double caculateCurrentEntropy(CvHistogram * Histogram1,int cur_threshold,entropy_state state)
- {
- int start,end;
- int total =;
- double cur_entropy =0.0;
- if(state == back)
- {
- start =;
- end = cur_threshold;
- }
- else
- {
- start = cur_threshold;
- end =;
- }
- for(int i=start;i<end;i++)
- {
- total += (int)cvQueryHistValue_1D(Histogram1,i);//查询直方块的值 P304
- }
- for(int j=start;j<end;j++)
- {
- if((int)cvQueryHistValue_1D(Histogram1,j)==)
- continue;
- double percentage = cvQueryHistValue_1D(Histogram1,j)/total;
- /*熵的定义公式*/
- cur_entropy +=-percentage*logf(percentage);
- /*根据泰勒展式去掉高次项得到的熵的近似计算公式
- cur_entropy += percentage*percentage;*/
- }
- return cur_entropy;
- // return (1-cur_entropy);
- }
- //寻找最大熵阈值并分割
- void MaxEntropy(IplImage *src,IplImage *dst)
- {
- assert(src != NULL);
- assert(src->depth ==&& dst->depth ==);
- assert(src->nChannels ==);
- CvHistogram * hist = cvCreateHist(,&HistogramBins,CV_HIST_ARRAY,HistogramRange);//创建一个指定尺寸的直方图
- //参数含义:直方图包含的维数、直方图维数尺寸的数组、直方图的表示格式、方块范围数组、归一化标志
- cvCalcHist(&src,hist);//计算直方图
- double maxentropy =-1.0;
- int max_index =-;
- // 循环测试每个分割点,寻找到最大的阈值分割点
- for(int i=;i<HistogramBins;i++)
- {
- double cur_entropy = caculateCurrentEntropy(hist,i,object)+caculateCurrentEntropy(hist,i,back);
- if(cur_entropy>maxentropy)
- {
- maxentropy = cur_entropy;
- max_index = i;
- }
- }
- cout<<"The Threshold of this Image in MaxEntropy is:"<<max_index<<endl;
- cvThreshold(src, dst, (double)max_index,, CV_THRESH_BINARY);
- cvReleaseHist(&hist);
- }
基本全局阀值法
- 代码
- /*============================================================================
- = 代码内容:基本全局阈值法
- ==============================================================================*/
- int BasicGlobalThreshold(int*pg,int start,int end)
- { // 基本全局阈值法
- int i,t,t1,t2,k1,k2;
- double u,u1,u2;
- t=;
- u=;
- for (i=start;i<end;i++)
- {
- t+=pg[i];
- u+=i*pg[i];
- }
- k2=(int) (u/t); // 计算此范围灰度的平均值
- do
- {
- k1=k2;
- t1=;
- u1=;
- for (i=start;i<=k1;i++)
- { // 计算低灰度组的累加和
- t1+=pg[i];
- u1+=i*pg[i];
- }
- t2=t-t1;
- u2=u-u1;
- if (t1)
- u1=u1/t1; // 计算低灰度组的平均值
- else
- u1=;
- if (t2)
- u2=u2/t2; // 计算高灰度组的平均值
- else
- u2=;
- k2=(int) ((u1+u2)/); // 得到新的阈值估计值
- }
- while(k1!=k2); // 数据未稳定,继续
- //cout<<"The Threshold of this Image in BasicGlobalThreshold is:"<<k1<<endl;
- return(k1); // 返回阈值
- }
五 效果(略)
Author: SKySeraph
Email/GTalk: zgzhaobo@gmail.com QQ:452728574
From: http://www.cnblogs.com/skyseraph/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,请尊重作者的劳动成果。
【图像算法】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)的更多相关文章
- 七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)
http://blog.csdn.net/xw20084898/article/details/17564957 一.工具:VC+OpenCV 二.语言:C++ 三.原理 otsu法(最大类间方差法, ...
- 【转】七种常见阈值分割代码(Otsu、最大熵、迭代法、自适应阀值、手动、迭代法、基本全局阈值法)
http://blog.csdn.net/xw20084898/article/details/17564957 一.工具:VC+OpenCV 二.语言:C++ 三.原理 otsu法(最大类间方差法, ...
- 灰度图像的自动阈值分割(Otsu 法)(转载)
灰度图像的自动阈值分割(Otsu 法) 机器视觉领域许多算法都要求先对图像进行二值化.这种二值化操作阈值的选取非常重要.阈值选取的不合适,可能得到的结果就毫无用处.今天就来讲讲一种自动计算阈值的方法. ...
- 七种常见经典排序算法总结(C++实现)
排序算法是非常常见也非常基础的算法,以至于大部分情况下它们都被集成到了语言的辅助库中.排序算法虽然已经可以很方便的使用,但是理解排序算法可以帮助我们找到解题的方向. 1. 冒泡排序 (Bubble S ...
- Java枚举的七种常见用法
用法一:常量 在JDK1.5之前,我们定义常量都是:publicstaticfianl.....现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. Java代码 ...
- 七种常见经典排序算法总结(C++)
最近想复习下C++,很久没怎么用了,毕业时的一些经典排序算法也忘差不多了,所以刚好一起再学习一遍. 除了冒泡.插入.选择这几个复杂度O(n^2)的基本排序算法,希尔.归并.快速.堆排序,多多少少还有些 ...
- 灰度图像的自动阈值分割(Otsu 法)
关于otsu分割方法,这个文章讲的是最好的,清晰易懂,一看就是作者认真思考过的. 因为在看这个算法的时候我就想,如果一个很大的图像上,大部分像素值都在0 - 50范围内,但是有很小一块像素值在240的 ...
- 七种常见的核酸序列蛋白编码能力预测工具 | ncRNAs | lncRNA
注:这些工具的应用都是受限的,有些本来就是只能用于预测动物,在使用之前务必用ground truth数据来测试一些.我想预测某一个植物的转录本,所以可以拿已经注释得比较好的拟南芥来测试一下.(测试的结 ...
- 第十四节,OpenCV学习(三)图像的阈值分割
图像的阈值处理 图像的阈值分割:图像的二值化(Binarization) 阈值分割法的特点是:适用于目标与背景灰度有较强对比的情况,重要的是背景或物体的灰度比较单一,而且总可以得到封闭且连通区域的边界 ...
随机推荐
- 反向Ajax,第2部分:WebSocket
转自:http://kb.cnblogs.com/page/112616/ 前言 时至今日,用户期待的是可通过web访问快速.动态的应用.这一文章系列展示了如何使用反向Ajax(Reverse Aja ...
- win8.1 cygwin编译java轻量虚拟机avian
1.背景 昨天在网上看到别人用aauto写本地小程序写的很爽,我觉得如果java的jre能小一点,凭借java庞大的第三方类库写小工具也还算不错的.本人就经常用eclipse+一些commons包写些 ...
- 用Chrome devTools 调试Android手机app中的web页面。
(1) 手机要满足Android系统为4.4或更高版本,低版本不支持这种方式.(2) 确保App已经开启了webview的debug调试模式,由Android工程师协助.(2) 用usb数据线连接好手 ...
- angular 嵌套实现树结构 ng-repeat ng-include
效果图 ang.html <!doctype html><html lang="en"><head> <meta charset=& ...
- BZOJ1565 植物大战僵尸
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1565 这题看上去并不会做,结果又是最大权闭合子图的裸题. 于是就去看了一发论文,明白建图的 ...
- 4-Highcharts 3D图之3D普通饼图
<!DOCTYPE> <html lang='en'> <head> <title>4-Highcharts 3D图之3D普通饼图</title& ...
- frequentism-and-bayesianism-chs-iii
frequentism-and-bayesianism-chs-iii 频率主义 vs 贝叶斯主义 III:置信(Confidence)与可信(Credibility),频率主义与科学,不能混为一 ...
- Hadoop伪分布模式配置
本作品由Man_华创作,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.基于http://www.cnblogs.com/manhua/上的作品创作. 请先按照上一篇文章H ...
- Sqli-labs less 35
Less-35 35关和33关是大致的一样的,唯一的区别在于sql语句的不同. $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; ...
- zoj Fibonacci Numbers ( java , 简单 ,大数)
题目 //f(1) = 1, f(2) = 1, f(n > 2) = f(n - 1) + f(n - 2) import java.io.*; import java.util.*; imp ...