1.原理
opencv API
//HE
Mat enhance(const Mat& src)
{
Mat dst(src.size(),src.type());
if (src.channels() == 3)
{
vector<Mat>mv;
split(src, mv);
equalizeHist(mv[0], mv[0]);
equalizeHist(mv[1], mv[1]);
equalizeHist(mv[2], mv[2]);
merge(mv, dst);
}
else {
equalizeHist(src, dst);
}
return dst;
}
下边是直方图均衡化效果:
2.自动亮度对比度实现
下图帮助理解:
代码实现,增加了两个参数,用以调节亮度最低值和直方图的范围
在此备注C++默认参数函数设置,以防出现调试时重复定义的bug
先声明后定义时,默认参数赋值在函数声名时发生,具体如下
//.h
void BrightnessAndContrastAuto(const Mat &src, Mat &dst, float clipHistPercent = 0, int histSize = 255, int lowhist = 0);
//.cpp
void ImgEnhance::BrightnessAndContrastAuto(const Mat &src, Mat &dst, float clipHistPercent, int histSize, int lowhist)
算法具体实现如下: 其实主要是求解对比度和亮度两个参数,然后按照公式计算出结果灰度
// clipHistPercent 剪枝(剪去总像素的多少百分比)
// histSize 最后将所有的灰度值归到多大的范围
// lowhist 最小的灰度值
void BrightnessAndContrastAuto(const cv::Mat& src, cv::Mat& dst, float clipHistPercent = 0, int histSize = 255, int lowhist = 0)
{
CV_Assert(clipHistPercent >= 0);
CV_Assert((src.type() == CV_8UC1) || (src.type() == CV_8UC3) || (src.type() == CV_8UC4));
float alpha, beita;
double minGray = 0, maxGray = 0;
//to calculate grayscale histogram
Mat gray;
if (src.type() == CV_8UC1) gray = src.clone();
else if (src.type() == CV_8UC3) cvtColor(src, gray, COLOR_BGR2GRAY);
else if (src.type() == CV_8UC4) cvtColor(src, gray, COLOR_BGRA2GRAY);
if (clipHistPercent == 0)
{
//keep full available range
minMaxLoc(gray, &minGray, &maxGray);
}
else
{
Mat hist;
float range[] = { 0,256 };
const float* histRange = { range };
bool uniform = true;
bool accumulate = false;
calcHist(&gray, 1, 0, Mat(), hist, 1, &histSize, &histRange, uniform, accumulate);
//calculate cumulate distribution from the histogram
vector<float>accumulator(histSize);
accumulator[0] = hist.at<float>(0);
for (int i = 1; i < histSize; i++)
{
accumulator[i] = accumulator[i - 1] + hist.at<float>(i);
}
//locate points that cuts at required value
float max = accumulator.back();
int clipHistPercent2;
clipHistPercent2 = clipHistPercent * (max / 100.0); //make percent as absolute
clipHistPercent2 /= 2.0; // left and right wings
// locate left cut
minGray = 0;
while (accumulator[minGray] < clipHistPercent2)
minGray++;
// locate right cut
maxGray = histSize - 1;
while (accumulator[maxGray] >= (max - clipHistPercent2))
maxGray--;
}
// current range
float inputRange = maxGray - minGray;
alpha = (histSize - 1) / inputRange; // alpha expands current range to histsize range
beita = -minGray * alpha + lowhist; // beta shifts current range so that minGray will go to 0
// Apply brightness and contrast normalization
// convertTo operates with saurate_cast
src.convertTo(dst, -1, alpha, beita);
// restore alpha channel from source
if (dst.type() == CV_8UC4)
{
int from_to[] = { 3, 3 };
cv::mixChannels(&src, 4, &dst, 1, from_to, 1);
}
}
参考
1.https://blog.csdn.net/qq_20095389/article/details/83658878
2.https://blog.csdn.net/panda1234lee/article/details/52852765