#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<iostream>
#include<time.h>
using namespace std;
using namespace cv;
int IterationThreshold(Mat gray);
int EntropySeg(Mat src);
int pValueThreshold(Mat Frame, int maxValue, double ratio, int valueTop);
int main()
{
clock_t start, finish;
double totaltime;
start = clock();
Mat src = imread("C:/Users/dxscd/Desktop/图片1.jpg",1);
const int width = src.cols;
const int height = src.rows;
Mat gray,OutImage1, OutImage2, OutImage3,OutImage4,OutImage5;
gray.create(height, width, CV_8UC1);
cvtColor(src, gray, CV_BGR2GRAY);
int graythreshold,T1;
int thres = IterationThreshold(gray);
T1 = EntropySeg(gray);
Mat OutImage6 = gray.clone();
//用哪个方法就注释掉其他方法,可计算耗时
//threshold(gray, OutImage1, thres, 255, CV_THRESH_BINARY);//迭代阈值分割
graythreshold = threshold(gray,OutImage2,0,255,CV_THRESH_BINARY | CV_THRESH_OTSU); //大律法
//adaptiveThreshold(gray,OutImage3,255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,151,0);//自适应阈值
//threshold(gray,OutImage4, 50, 255, CV_THRESH_BINARY);//固定阈值分割
//threshold(gray, OutImage5, T1, 255, CV_THRESH_BINARY);//最大熵阈值分割
//int res = pValueThreshold(OutImage6, 218, 0.26346,255);//P参数法
finish = clock();
totaltime = (double)(finish - start) / CLOCKS_PER_SEC;
cout << "此程序锁耗时间为:" << totaltime << "秒" << endl;
/*namedWindow("迭代阈值",0);
imshow("迭代阈值", OutImage1);*/
/*namedWindow("OTSU",0);
imshow("OTSU", OutImage2);*/
/*namedWindow("自适应阈值",0);
imshow("自适应阈值", OutImage3);*/
/*namedWindow("固定阈值",0);
imshow("固定阈值", OutImage4);*/
/*namedWindow("最大熵阈值",0);
imshow("最大熵阈值", OutImage5);*/
/*namedWindow("P参数法",0);
imshow("P参数法", OutImage6);*/
imwrite("C:/Users/dxscd/Desktop/迭代阈值.jpg", OutImage2);
//imwrite("C:/Users/dxscd/Desktop/OTSU.jpg", OutImage2);
//imwrite("C:/Users/dxscd/Desktop/自适应阈值.jpg", OutImage3);
//imwrite("C:/Users/dxscd/Desktop/固定阈值.jpg", OutImage4);
//imwrite("C:/Users/dxscd/Desktop/最大熵阈值.jpg", OutImage5);
/*imwrite("C:/Users/dxscd/Desktop/P参数法.jpg", OutImage6);*/
waitKey(0);
return 0;
}
//迭代阈值分割******************************************************************************************************
int IterationThreshold(Mat gray)//迭代阈值分割
{
int width = gray.cols;
int height = gray.rows;
//直方图统计
int histData[256] = {0};
for(int j = 0; j < height; j ++)
{
uchar*data = (uchar*)(gray.ptr<uchar>(0) + j * gray.step);
for (int i = 0; i < width; i ++)
{
histData[data[i]]++;
}
}
//求图像的平均灰度值作为初始阈值
int T0 = 0;
for (int i = 0; i < 256; i ++)
{
T0 += i * histData[i];
}
T0 /= width * height;
//迭代
int T1 = 0, T2 = 0;
int num1 = 0, num2 = 0;
int T = 0;
while (1)
{
for ( int i = 0; i < T0+1; i ++)
{
T1 += i * histData[i];
num1 += histData[i];
}
if (num1 == 0)
continue;
for ( int i = T0 + 1; i < 256; i ++)
{
T2 += i * histData[i];
num2 += histData[i];
}
if (num2 == 0)
continue;
T = (T1 / num1 + T2 / num2) / 2;
if ( T == T0 )
break;
else
T0 = T;
}
return T;
}
//最大熵阈值分割*************************************************************************
int EntropySeg(Mat src)
{
int tbHist[256] = { 0 };
int index = 0;
double Property = 0.0;
double maxEntropy = -1.0;
double frontEntropy = 0.0;
double backEntropy = 0.0;
int TotalPixel = 0;
int nCol = src.cols*src.channels();
for (int i = 0; i < src.rows; i++)
{
uchar* pData = src.ptr<uchar>(i);
for (int j = 0; j < nCol; j++)
{
++TotalPixel;
tbHist[pData[j]] += 1;
}
}
for (int i = 0; i < 256; i++)
{
double backTotal = 0;
for (int j = 0; j < i; j++)
{
backTotal += tbHist[j];
}
for (int j = 0; j < i; j++)
{
if (tbHist[j] != 0)
{
Property = tbHist[j] / backTotal;
backEntropy += -Property*logf((float)Property);
}
}
for (int k = i; k < 256; k++)
{
if (tbHist[k] != 0)
{
Property = tbHist[k] / (TotalPixel - backTotal);
frontEntropy += -Property * logf((float)Property);
}
}
if (frontEntropy + backEntropy > maxEntropy)
{
maxEntropy = frontEntropy + backEntropy;
index = i;
}
frontEntropy = 0.0;
backEntropy = 0.0;
}
//Mat dst;
//threshold(src, dst, index, 255, 0);
return index;
}
//P参数法****************************************************************
int pValueThreshold(Mat Frame, int maxValue, double ratio, int valueTop)
{
//直方图均衡化
equalizeHist(Frame, Frame);
//计算直方图
Mat hist; //将要获得的直方图
int imgNum = 1; //图像数量
int histDim = 1; //直方图维度
int histSize = 256; //每个维度的bin个数
float range[] = { 0,256 }; //每个维度的统计范围
const float* histRange = { range };
bool accumulate = false;
calcHist(&Frame, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);
//hist中的第一行,是直方图的值.
float* p = hist.ptr<float>(0);
//循环计算阈值
int countPix = Frame.cols * Frame.rows;
int thresholdPix = 0;
double ratioReal;
int thresholdValue = maxValue;
for (; thresholdValue >= 0; thresholdValue--)
{
thresholdPix += p[thresholdValue];
ratioReal = (double)thresholdPix / countPix;
if (ratioReal>ratio)
{
break;
}
}
//可能图像不符合要求
if (thresholdValue < 0)
{ return -1;
}
//使用阈值将图像二值化
int curValue = 0;
for (int i = 0; i < Frame.rows; ++i)
{
for (int j = 0; j < Frame.cols; ++j)
{
curValue = Frame.at<uchar>(i, j);
if (curValue >= thresholdValue && curValue <= maxValue)
{
Frame.at<uchar>(i, j) = 0;
}
else
{
Frame.at<uchar>(i, j) = valueTop;
}
}
}
return 0;
}