【拜小白opencv】25-综合示例——8种阈值化操作【OTSU阈值化、自适应阈值化、二进制阈值化、反二进制阈值化、截断阈值化、阈值化为0、反阈值化为0,双阈值化】

来源:互联网 发布:it cost 编辑:程序博客网 时间:2024/06/14 12:18

常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。

本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。

博主机器配置为:VS2013+opencv2.4.13+Win-64bit。

若本文能给读者带来一点点启示与帮助,我就很开心了。

===========================分割线========================


结合前几节的内容,写了个综合示例,包含8种阈值化方法

  1. 二进制阈值化
  2. 反二进制阈值化
  3. 截断阈值化
  4. 阈值化为0
  5. 反阈值化为0
  6. OTSU阈值化
  7. 自适应阈值化
  8. 双阈值化
其中阈值量可通过滑动条来调节,下面来看看程序是如何实现的。
=====================分割线========================

代码演示

/*综合示例,8种阈值化操作:1.二进制阈值化2.反二进制阈值化3.截断阈值化4.阈值化为05.反阈值化为06.OTSU阈值化7.自适应阈值化8.双阈值化*/#include <opencv2/core/core.hpp>                #include <opencv2/highgui/highgui.hpp>                #include <opencv2/imgproc/imgproc.hpp>               #include <iostream>              using namespace std;using namespace cv;//------------------------【宏定义部分】------------------------#define WINDOW_NAME "【几种阈值化操作】"//-----------------------【全局变量声明部分】------------------------Mat g_srcImage, g_grayImage, g_dstImage;//源图像、灰度图、结果输出图Mat g_dstTempImage1, g_dstTempImage2;//双阈值化部分图像const int g_maxVal = 255; //预设最大值  int g_nThresholdValue = 90;//初始阈值量int g_nTresholdType = 0;//阈值类型,并设初值为0int g_nLowThreshold = 60;//双阈值操作中的较小阈值量int g_nHighThreshold = 120;//双阈值操作中较大阈值量//-----------------------【全局函数声明部分】------------------------static void ShowHelpText();//显示界面帮助文字void on_Threshold(int, void*);//滑动条回调函数int OTSU(Mat grayImage);    //OTSU法函数实现,返回一个阈值量Mat otsuThresh();//otsu阈值Mat adapThresh();//自适应阈值Mat doubleThresh();//双阈值//---------------【主函数】-------------------int main(){ShowHelpText();//------------【1】读取源图像并检查图像是否读取成功------------  g_srcImage = imread("D:\\OutPutResult\\ImageTest\\tower.jpg");if (!g_srcImage.data){cout << "读取图片错误,请重新输入正确路径!\n";system("pause");return -1;}imshow("【源图像】", g_srcImage);//--------------【2】灰度转换--------------cvtColor(g_srcImage, g_grayImage, COLOR_RGB2GRAY);//--------------【3】创建滑动条来控制阈值---------------namedWindow(WINDOW_NAME, WINDOW_AUTOSIZE);createTrackbar("阈值类型:", WINDOW_NAME, &g_nTresholdType, 7, on_Threshold);createTrackbar("阈值量:", WINDOW_NAME, &g_nThresholdValue, g_maxVal, on_Threshold);createTrackbar("小阈值量:", WINDOW_NAME, &g_nLowThreshold, g_maxVal, on_Threshold);createTrackbar("大阈值量:", WINDOW_NAME, &g_nHighThreshold, g_maxVal, on_Threshold);//--------------【4】结果在回调函数中显示---------------on_Threshold(0, 0);//-----------【5】轮询等待用户按键,如果ESC键按下则程序退出---------------while (1){char c = waitKey(10);             if (c == 27)    //按左上角ESC键退出。 27为ESC的ASCII码              break;  }return 0;}//-------------------【滑动条的回调函数】---------------------void on_Threshold(int, void*){switch (g_nTresholdType){case 0:cout << "\n当前为【二进制阈值化】操作" << endl;threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, 0);imshow(WINDOW_NAME, g_dstImage); break;case 1:cout << "\n当前为【反二进制阈值化】操作" << endl;threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, 1);imshow(WINDOW_NAME, g_dstImage); break;case 2:cout << "\n当前为【截断阈值化】操作" << endl;threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, 2);imshow(WINDOW_NAME, g_dstImage); break;case 3:cout << "\n当前为【阈值化为0】操作" << endl;threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, 3);imshow(WINDOW_NAME, g_dstImage); break;case 4:cout << "\n当前为【反阈值化为0】操作" << endl;threshold(g_grayImage, g_dstImage, g_nThresholdValue, 255, 4);imshow(WINDOW_NAME, g_dstImage); break;case 5:cout << "\n当前为【OTSU阈值化】操作,阈值量不可调" << endl;g_dstImage = otsuThresh();imshow(WINDOW_NAME, g_dstImage); break;case 6:cout << "\n当前为【自适应阈值化】操作,阈值量不可调" << endl;g_dstImage = adapThresh();imshow(WINDOW_NAME, g_dstImage); break;case 7:cout << "\n当前为【双阈值化】操作,请分别调节大、小阈值量" << endl;g_dstImage = doubleThresh();imshow(WINDOW_NAME, g_dstImage); break;}}//---------------【OTSU法函数实现】----------------------  //功能:仅仅返回一个阈值量,还未实现阈值化//-------------------------------------------------------int OTSU(Mat grayImage){int nRows = grayImage.rows;//行数  int nCols = grayImage.cols;//列数   int threshold = 0;  //初始化阈值  //------------【1】初始化统计参数------------  int nSumPix[256];   //用于灰度级中每个像素在整幅图像中的个数  float nProDis[256]; //用于记录每个灰度级占图像中的概率分布  for (int i = 0; i < 256; i++){nSumPix[i] = 0;nProDis[i] = 0;}//------------【2】统计灰度级中每个像素在整幅图像中的个数------------  for (int i = 0; i < nRows; i++){for (int j = 0; j < nCols; j++){nSumPix[(int)grayImage.at<uchar>(i, j)]++;}}//------------【3】计算每个灰度级占图像中的概率分布------------  for (int i = 0; i < 256; i++){nProDis[i] = (float)nSumPix[i] / (nCols*nRows);}//------------【4】遍历灰度级[0,255],计算出最大类间方差的阈值------------  float wb, wf; //比重. wb-背景部分; wf-前景部分  float u0_temp, u1_temp, u0, u1; //平均值  float delta_temp;   //存放临时方差  double delta_max = 0.0; //初始化最大类间方差  for (int i = 0; i < 256; i++){wb = wf = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;//初始化相关参数  for (int j = 0; j < 256; j++){//背景部分  if (j <= i){//当前i为分割阈值,第一类总的概率  wb += nProDis[j];   //比重  u0_temp += j*nProDis[j];}//前景部分  else{//当前i为分割阈值,第一类总的概率  wf += nProDis[i];   //比重  u1_temp += j*nProDis[j];}}//------------分别计算各类的平均值------------  u0 = u0_temp / wb;u1 = u1_temp / wf;//-----------计算最大类间方差------------  delta_temp = (float)(wb*wf*pow((u0 - u1), 2));//形如pow(x,y);其作用是计算x的y次方。  //------------依次找到最大类间方差下的阈值------------  if (delta_temp > delta_max){delta_max = delta_temp;threshold = i;}}//计算结束  return threshold;   //返回OTUS计算出的阈值  }//---------------【OTSU阈值化函数实现】----------------------  Mat otsuThresh(){int otsuThreshold = OTSU(g_grayImage);//调用OTSU()阈值化所得到阈值cout << "--------且调用OTSU()阈值化所得阈值量为:" << otsuThreshold << endl;g_dstImage = Mat::zeros(g_grayImage.rows, g_grayImage.cols, CV_8UC1);//创建输出结果图像  //------------【利用得到的阈值实现二值化操作】------------  for (int i = 0; i < g_grayImage.rows; i++){for (int j = 0; j < g_grayImage.cols; j++){//阈值判断。 若该点值大于阈值,则设为255,否则设为0。  if (g_grayImage.at<uchar>(i, j) > otsuThreshold)g_dstImage.at<uchar>(i, j) = 255;elseg_dstImage.at<uchar>(i, j) = 0;}}return g_dstImage;}//---------------【自适应阈值化函数实现】----------------------  Mat adapThresh(){//------------【初始化相关变量】---------------    int blockSize = 3;  //邻域块大小。取值3、5、7....等  int constValue = 10;int adaptiveMethod = 0;//自适应阈值算法int thresholdType = 1;//阈值类型/*自适应阈值算法0:ADAPTIVE_THRESH_MEAN_C1:ADAPTIVE_THRESH_GAUSSIAN_C--------------------------------------阈值类型0:THRESH_BINARY1:THRESH_BINARY_INV*///---------------【图像自适应阈值操作】-------------------------  adaptiveThreshold(g_grayImage, g_dstImage, g_maxVal, adaptiveMethod, thresholdType, blockSize, constValue);return g_dstImage;}//---------------【双边阈值化函数实现】----------------------  Mat doubleThresh(){//小阈值对源灰度图像进行二进制阈值化操作  threshold(g_grayImage, g_dstTempImage1, g_nLowThreshold, g_maxVal, THRESH_BINARY);//大阈值对源灰度图像进行反二进制阈值化操作  threshold(g_grayImage, g_dstTempImage2, g_nHighThreshold, g_maxVal, THRESH_BINARY_INV);//矩阵"与运算"得到二值化结果  bitwise_and(g_dstTempImage1, g_dstTempImage2, g_dstImage); //对像素加和  return g_dstImage;}//---------------【显示界面帮助文字】----------------------  void ShowHelpText() {cout << "\t按键操作说明:" << endl << endl;cout << "\t\t键盘按键【Esc】-退出程序" << endl;cout << "\t\t阈值类型0- 二进制阈值化" << endl;cout << "\t\t阈值类型1- 反二进制阈值化" << endl;cout << "\t\t阈值类型2- 截断阈值化" << endl;cout << "\t\t阈值类型3- 阈值化为0" << endl;cout << "\t\t阈值类型4- 反阈值化为0" << endl;cout << "\t\t阈值类型5- OTSU阈值化" << endl;cout << "\t\t阈值类型6- 自适应阈值化" << endl;cout << "\t\t阈值类型7- 双阈值化" << endl;cout << "-------------------------------------------------" << endl << endl;}


========================分割线======================

显示结果



















======================分割线======================

程序说明

其中阈值类型0--4,通过右上侧的阈值量来调节。
阈值类型5和6,为计算所得阈值量,不能调节。
阈值类型7,通过下面的,大、小阈值量来调节。

=====================END=====================

原创粉丝点击