图像处理之最大熵阈值处理(C++)
前言
熵代表信息量,图像的信息量越大,熵就越大,最大熵算法的目的就是找一个最佳的阈值使得背景和前景两个部分的熵之和最大。应用场景:直方图多峰、自适应寻找阈值。
一、最大熵阈值原理
基本概念:
1.各个灰度级的概率(频率)p(i),h(i)是指灰度为i的像素的个数,M*N是整个图片的像素数之和。
2.累加概率P0(q)、P1(q)
3.背景和前景对应的熵分别为H0(q)、H1(q)
注意:S1(q)=S0(255)-S0(q);
4.图像的总熵值H(q)=H0(q)+H1(q).
二、代码实现
#include <iostream>
#include <opencv.hpp>
using namespace std;
const double g_EPSINON = 0.000001;
/*
* @param cv::Mat src 输入图像(CV_8U)
* @param cv::Mat dst 输出图像
* @param int thresh OTSU最大类间方差的灰度值
* @brief 计算OTSU的灰度值并返回
*/
int MaxEntropyThreshold(const cv::Mat& src, cv::Mat& dst, int& thresh)
{
int h = src.rows;
int w = src.cols;
const int grayscale = 256;
// 利用查表法计算各个灰度级的概率p(i)
double grayTable[grayscale] = { 0 };
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
grayTable[src.at<uchar>(i, j)]++;
for (int i = 0; i < grayscale; i++)
grayTable[i] /= (h * w);
// 建立各个灰度值对应的熵值表∑p(i)*log(p(i)),即S(q)
double EntropyTable[grayscale] = { 0 };
double entropySum = 0.;
for (int i = 0; i < grayscale; i++)
{
if (grayTable[i] > g_EPSINON) {
entropySum += (grayTable[i] * log(grayTable[i]));
}
EntropyTable[i] = entropySum;
}
// 计算各个灰度级的累加概率和,即P0(q)
double p_sum = 0;
double cumProba[grayscale];
for (int q = 0; q < grayscale; q++)
{
p_sum += grayTable[q]; // 灰度级为k的累加概率p1
cumProba[q] = p_sum;
}
// 计算图像的总熵值
double allEntropyTable[grayscale] = { 0 };
double h0 = 0;
double h1 = 0;
for (int q = 0; q < grayscale; q++)
{
double temp = cumProba[q];
if (temp > g_EPSINON) {
h0 = -EntropyTable[q] / temp + log(temp);
h1 = -(EntropyTable[255] - EntropyTable[q]) / (1 - temp) + log(1 - temp);
allEntropyTable[q] = h0 + h1;
}
else
{
allEntropyTable[q] = 0.;
}
}
// 查找对应图像总熵最大的灰度值k
double max = allEntropyTable[0];
thresh = 0;
for (int i = 1; i < grayscale; i++)
{
if (max < allEntropyTable[i])
{
max = allEntropyTable[i];
thresh = i;
}
}
// 进行图像二值化
dst = src.clone();
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++) {
if (src.at<uchar>(i, j) > thresh)
dst.at<uchar>(i, j) = 255;
else
dst.at<uchar>(i, j) = 0;
}
return thresh;
}
int main()
{
//读取图片
string filepath = "F://work_study//algorithm_demo//baby.jpg";
cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
if (src.empty())
{
std::cout << "imread error" << std::endl;
return -1;
}
cv::Mat dst(src.size(), src.type());
//最大熵阈值处理
int thresh = 0;
MaxEntropyThreshold(src, dst, thresh);
std::cout << thresh << endl;
//显示图片
cv::imwrite("dst.bmp", dst);
cv::waitKey(0);
return 0;
}
三、结果展示
总结
本文介绍了最大熵阈值的原理和以及相对应的具体的C++代码实现,对数学公式进行优化,欢迎大家阅读。
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。