1.寻找波峰
原理后面再补,先上代码:
cv::Mat findpeakmax(cv::Mat srcImage, std::vector<int>& resultVec)//求波峰
{
cv::Mat value;//返回投影向量
cv::Mat VerMat;
cv::Mat resMat = srcImage.clone();
//阈值化操作
int thresh = 130;
int threshType = 0;
//预设最大值
const int maxVal = 255;
//固定阈值化操作
cv::threshold(srcImage, srcImage, thresh, maxVal, threshType);
srcImage.convertTo(srcImage, CV_32FC1);
//计算垂直投影
cv::reduce(srcImage, VerMat, 0, CV_REDUCE_SUM);
//遍历求差分符号
float *iptr = ((float*)VerMat.data) + 1;
std::vector<int> tempVec(VerMat.cols - 1, 0);
for (int i = 1; i < VerMat.cols - 1; ++i, ++iptr)
{
if (*(iptr + 1) - *iptr > 0)
{
tempVec[i] = 1;
}
else if (*(iptr + 1) - *iptr < 0)
{
tempVec[i] = -1;
}
else
{
tempVec[i] = 0;
}
}
//对符号函数进行遍历
for (int i = tempVec.size() - 1; i >= 0; i--)
{
if (tempVec[i] == 0 && tempVec.size() - 1)
{
tempVec[i] = 1;
}
else if (tempVec[i] == 0)
{
if (tempVec[i + 1] >= 0)
{
tempVec[i] = 1;
}
else
{
tempVec[i] = -1;
}
}
}
//波峰判断输出
for (std::vector<int>::size_type i = 0; i != tempVec.size() - 1; i++)
{
if (tempVec[i + 1] - tempVec[i] == -2)//+2为波谷
{
resultVec.push_back(i + 1);
}
}
//输出波峰位置
for (int i = 0; i < resultVec.size(); i++)
{
for (int ii = 0; ii < resMat.rows; ++ii)
{
resMat.at<unsigned char>(ii, resultVec[i]) = 255;
}
}
value = VerMat;
return value;
}
2.寻找最佳阈值:
原理后面再补,先上代码:
#pragma region 寻找最佳阈值函数-Get_IterationThres
int Get_IterationThres(cv::Mat Img)
{
/************************绘制直方图****************************/
const int channels[1] = { 0 };
//直方图的每一个维度的 柱条的数目(就是将灰度级分组)
int histSize[] = { 256 }; //如果这里写成int histSize = 256; 那么下面调用计算直方图的函数的时候,该变量需要写 &histSize
//定义一个变量用来存储 单个维度 的数值的取值范围
float midRanges[] = { 0, 256 };
//确定每个维度的取值范围,就是横坐标的总数
const float *ranges[] = { midRanges };
//输出的结果存储的 空间 ,用MatND类型来存储结果
cv::MatND dstHist;
double* HistGram = new double[256];
calcHist(&Img, 1, channels, cv::Mat(), dstHist, 1, histSize, ranges, true, false);
for (int i = 0; i < 256; i++)
{
HistGram[i] = dstHist.at<float>(i);
}
int X, Iter = 0;
int MeanValueOne, MeanValueTwo, SumOne, SumTwo, SumIntegralOne, SumIntegralTwo;
int MinValue, MaxValue;
int NewThreshold;
for (MinValue = 0; MinValue < 256 && HistGram[MinValue] == 0; MinValue++);
{
for (MaxValue = 255; MaxValue > MinValue && HistGram[MinValue] == 0; MaxValue--);
{
if (MaxValue == MinValue)
return MaxValue; // 图像中只有一个颜色
if (MinValue + 1 == MaxValue)
return MinValue; // 图像中只有二个颜色
}
}
int IterationThres = MinValue;
NewThreshold = (MaxValue + MinValue) >> 1;//NewThreshold为灰度最大最小值的平均值
while (IterationThres != NewThreshold)//当前后两次迭代获得阈值相同时,结束迭代
{
SumOne = 0;
SumIntegralOne = 0;
SumTwo = 0;
SumIntegralTwo = 0;
IterationThres = NewThreshold;
for (X = MinValue; X <= IterationThres; X++)//根据阈值将图像分割成目标和背景两部分,求出两部分的平均灰度值
{
SumIntegralOne += HistGram[X] * X;
SumOne += HistGram[X];
}
MeanValueOne = SumIntegralOne / SumOne;
for (X = IterationThres + 1; X <= MaxValue; X++)
{
SumIntegralTwo += HistGram[X] * X;
SumTwo += HistGram[X];
}
if (SumTwo == 0)
{
NewThreshold = MeanValueOne;
}
else
{
MeanValueTwo = SumIntegralTwo / SumTwo;
NewThreshold = (MeanValueOne + MeanValueTwo) >> 1;//求出新的阈值
}
Iter++;
if (Iter >= 1000)
return -1;
}
return IterationThres;
}