opencv中图像的均值化都是基于灰度图的,直方图均衡化是通过拉伸像素强度分布范围来增强图像对比度的一种方法,能提高图片的对比度。
1.自带函数均值化
函数原型:
equalizeHist( InputArray src, OutputArray dst );
注:src为单通道8位的图片,dst为与src相同大小和类型的目标图像
代码示例:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int artc, char** argv) {
if(argc < 2)
{
cerr << "usage: input the image ." << endl;
return -1;
}
Mat src = imread(argv[1]);
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
//1、灰度
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input1", src);
Mat gray, dst;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("input", gray);
equalizeHist(gray, dst);
imshow("eq", dst);
//2、色彩空间转换
Mat ycrcb;
cvtColor(src, ycrcb, COLOR_BGR2YCrCb);
vector<Mat>channels;
split(ycrcb, channels);
equalizeHist(channels[0], channels[0]);
Mat result;
merge(channels, ycrcb);
cvtColor(ycrcb, result, COLOR_YCrCb2BGR);
imshow("equalizeHist", result);
waitKey(0);
return 0;
}
代码思路:
(1)灰度图
1、读入图片
2、显示源图
3、显示色彩空间转换后的灰度图
4、显示直方图均衡化后的图片
(2)色彩空间转换
1、读入图片
2、色彩空间转换Ycrcb
3、图像通道分离
4、图像直方图均衡化
5、通道合并
6、色彩空间转换BGR
7、显示图像直方图均衡化后的图像
输出结果:
2.自定义均值化
函数原型:
Ptr<CLAHE> createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8))
注:clipLimit为对比度限制阈;tileGridSize用于直方图均衡化的网格大小,输入图像将被分割成大小相等的矩形块,在tileGridSize定义行和列中的块数。
代码示例
#include <opencv2/opencv.hpp>
#include <iostream>
/*
* 将一幅RGB图像转换YCrCb图像,并得到三个分离的通道。
*/
static void TransferRGB2YCrCb(cv::Mat &input, std::vector<cv::Mat> &chls)
{
//YCrCb色彩空间:Y为颜色的亮度(luma)成分、而CB和CR则为蓝色和红色的浓度偏移量成分。
//只有Y成分的图基本等同于彩色图像的灰度图。
cv::cvtColor(input, input, cv::COLOR_BGR2YCrCb);
cv::split(input, chls);
}
/*
* 将Y、Cr、Cb三个分离的通道合并为YCrCb图像,再转换为RGB图像。
*/
static void MergeYCrCb2RGB(cv::Mat &output, std::vector<cv::Mat> &chls)
{
cv::merge(chls, output);
cv::cvtColor(output, output, cv::COLOR_YCrCb2BGR);
}
/*
*CLAHE.
*@ClipLimit:直方图的柱子高度大于计算后的ClipLimit的部分被裁剪掉,然后将其平均分配给整张直方图,从而提升*整个图像。
*但是本人觉得这里解释的不对,更像是累计概率分布函数的斜率上限阈值,高于ClipLimit的部分被裁剪掉,
*然后将其平均分配给整张直方图,从而提升整个图像。
*@TilesGridSize:// 将图像分为TilesGridSize*TilesGridSize大小的方块.。(滑动窗口大小为TilesGridSize*TilesGridSize)
*/
cv::Mat clahe_deal(cv::Mat &src, double ClipLimit = 40.0, int TilesGridSize = 8)
{
cv::Mat ycrcb = src.clone();
std::vector<cv::Mat> channels;
TransferRGB2YCrCb(ycrcb, channels);
cv::Mat clahe_img;
//opencv源码中原型: createCLAHE(double clipLimit = 40.0, Size tileGridSize = Size(8, 8));
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(ClipLimit);
clahe->setTilesGridSize(Size(TilesGridSize, TilesGridSize));
clahe->apply(channels[0], clahe_img);
channels[0].release();
clahe_img.copyTo(channels[0]);
MergeYCrCb2RGB(ycrcb, channels);
return ycrcb;
}
int main()
{
cv::Mat src = cv::imread("CLAHE.png", IMREAD_UNCHANGED);
imshow("原图",src);
double ClipLimit = 4.0;
int TilesGridSize = 8;
cv::Mat claheRes = clahe_deal(src, ClipLimit, TilesGridSize);
imshow("结果图1", claheRes);
ClipLimit = 8.0, TilesGridSize = 8;
cv::Mat claheRes_2 = clahe_deal(src, ClipLimit, TilesGridSize);
imshow("结果图2", claheRes_2);
ClipLimit = 16, TilesGridSize = 8;
cv::Mat claheRes_3 = clahe_deal(src, ClipLimit, TilesGridSize);
imshow("结果图3", claheRes_3);
cv::waitKey(0);
return 0;
}
输出结果: