图像增强的一种重要方法是对比度增强,常见的有以下几种方法:
直方图均衡,局部自适应对比度增强(ACE adaptiveContrastEnhancement),自适应直方图均衡(CLAHE),自动对比度。
1. 直方图均衡
cv::equalizeHist(src, dst);
2. 自适应直方图均衡(CLAHE)参考
cv::Mat clahe_img = srcGray.clone();
cv::Mat clahe_dst;
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(8.); // (int)(4.*(8*8)/256)
clahe->setTilesGridSize(Size(32, 32)); // 将图像分为8*8块
clahe->apply(clahe_img, clahe_dst);
3. 局部自适应对比度增强(ACE)参考
void adaptContrastEnhancement()
{
cv::Mat srcMat = cv::imread("1.JPG");
cv::Mat srcGray;
cv::cvtColor(aConMat, srcGray, cv::COLOR_BGR2GRAY);
const int WINSIZE = 15;
const int MAXCG = 10;
Mat localMeansMatrix(srcGray.rows, srcGray.cols, CV_32FC1);
Mat localVarianceMatrix(srcGray.rows, srcGray.cols, CV_32FC1);
if (!getVarianceMean(srcGray, localMeansMatrix, localVarianceMatrix, WINSIZE)) //对Y通道进行增强;
{
cerr << "计算图像均值与标准差过程中发生错误";
return ;
}
Mat temp = srcGray.clone();
Scalar mean;
Scalar dev;
meanStdDev(temp, mean, dev);
float meansGlobal = mean.val[0];
Mat dstMat(srcGray.rows, srcGray.cols, CV_8UC1);
for (int i = 0; i < srcGray.rows; i++) //遍历,对每个点进行自适应调节
{
for (int j = 0; j < srcGray.cols; j++)
{
if (localVarianceMatrix.at<float>(i, j) >= 0.01)
{
float cg = 0.3*meansGlobal / localVarianceMatrix.at<float>(i, j);
float cgs = cg > MAXCG ? MAXCG : cg;
cgs = cgs < 1 ? 1 : cgs;
int e = localMeansMatrix.at<float>(i, j) + cgs * (temp.at<uchar>(i, j) - localMeansMatrix.at<float>(i, j));
if (e > 255) { e = 255; }
else if (e < 0) { e = 0; }
dstMat.at<uchar>(i, j) = e;
}
else
{
dstMat.at<uchar>(i, j) = temp.at<uchar>(i, j);
}
}
}
}
bool getVarianceMean(Mat &scr, Mat &meansDst, Mat &varianceDst, int winSize)
{
if (!scr.data) //判断图像是否被正确读取;
{
cerr << "获取方差与均值的函数读入图片有误";
return false;
}
if (winSize % 2 == 0)
{
cerr << "计算局部均值与标准差的窗口大小应该为单数";
return false;
}
Mat copyBorder_yChannels; //扩充图像边界;
int copyBorderSize = (winSize - 1) / 2;
copyMakeBorder(scr, copyBorder_yChannels, copyBorderSize, copyBorderSize, copyBorderSize, copyBorderSize, BORDER_REFLECT);
for (int i = (winSize - 1) / 2; i < copyBorder_yChannels.rows - (winSize - 1) / 2; i++)
{
for (int j = (winSize - 1) / 2; j < copyBorder_yChannels.cols - (winSize - 1) / 2; j++)
{
Mat temp = copyBorder_yChannels(Rect(j - (winSize - 1) / 2, i - (winSize - 1) / 2, winSize, winSize)); //截取扩展后的图像中的一个方块;
Scalar mean;
Scalar dev;
meanStdDev(temp, mean, dev);
varianceDst.at<float>(i - (winSize - 1) / 2, j - (winSize - 1) / 2) = dev.val[0]; ///一一对应赋值;
meansDst.at<float>(i - (winSize - 1) / 2, j - (winSize - 1) / 2) = mean.val[0];
}
}
return true;
}
4. 自动对比度参考
Mat autocontrost(Mat matface)
{
//进行自动对比度校正
double HistBlue[256] = { 0 };
int bluemap[256] = { 0 };
double dlowcut = 0.1;
double dhighcut = 0.1;
for (int i = 0; i < matface.rows; i++)
{
for (int j = 0; j < matface.cols; j++)
{
int iblue = matface.at<uchar>(i, j);
HistBlue[iblue]++;
}
}
int PixelAmount = matface.rows*matface.cols;
int isum = 0;
// blue
int iminblue = 0; int imaxblue = 0;
for (int y = 0; y < 256; y++)//这两个操作我基本能够了解了
{
isum = isum + HistBlue[y];
if (isum >= PixelAmount * dlowcut*0.01)
{
iminblue = y;
break;
}
}
isum = 0;
for (int y = 255; y >= 0; y--)
{
isum = isum + HistBlue[y];
if (isum >= PixelAmount * dhighcut*0.01)
{
imaxblue = y;
break;
}
}
// 自动色阶
//自动对比度
int imin = 255; int imax = 0;
if (imin > iminblue)
imin = iminblue;
iminblue = imin;
if (imax < imaxblue)
imax = imaxblue;
imaxblue = imax;
/
//blue
for (int y = 0; y < 256; y++)
{
if (y <= iminblue)
{
bluemap[y] = 0;
}
else
{
if (y > imaxblue)
{
bluemap[y] = 255;
}
else
{
// BlueMap(Y) = (Y - MinBlue) / (MaxBlue - MinBlue) * 255 '线性隐射
float ftmp = (float)(y - iminblue) / (imaxblue - iminblue);
bluemap[y] = (int)(ftmp * 255);
}
}
}
//查表
for (int i = 0; i < matface.rows; i++)
{
for (int j = 0; j < matface.cols; j++)
{
matface.at<uchar>(i, j) = bluemap[matface.at<uchar>(i, j)];
}
}
return matface;
}