两者都是只对单通道使用,对多通道的话 就需要分离通道处理再合并通道
两种方法,第一个要运算次数太多了,第二个只需要查表
伽马矫正函数,这里用第二种方法,且写法有点高级
int gammaCorrection(cv::Mat srcMat, cv::Mat& dstMat, float gamma) {
//建立查询表
unsigned char lut[256];
for (int i = 0; i < 256; i++)
{
//saturate_cast,防止像素值溢出,如果值<0,则返回0,如果大于255,则返回255
lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0f), gamma) * 255.0f);
}
srcMat.copyTo(dstMat);
MatIterator_<uchar> it, end;
for (it = dstMat.begin<uchar>(), end = dstMat.end<uchar>(); it != end; it++) {
*it = lut[(*it)];
}
return 0;
}
就是建立了查找表,然后计算查找表,再遍历像素直接赋值查找表,就不用计算了。
int readType = 0;
Mat srcMat = imread("kjy.jpg");
resize(srcMat, srcMat,Size(srcMat.rows*0.5, srcMat.rows * 0.5));
cv::Mat dstMat;
float gamma = GAMMA_FACTOR;
if (srcMat.type() == CV_8UC1){
gammaCorrection(srcMat, dstMat, gamma);
}
else {
Mat channel[3];
Mat out[3];
float hist[3][256];
//通道分离
split(srcMat, channel);
for (int i = 0; i < 3; i++) {
gammaCorrection(channel[i], out[i], gamma);
}
merge(out, 3, dstMat);
}
imshow("src", srcMat);
imshow("dst", dstMat);
waitKey(0);
destroyAllWindows();
这就是grammar矫正的代码
直方图均衡化(只对单通道有效果)多通道的话先分离通道再合并一样的
equalizeHist(srcMat, equalizeHistMat);
计算直方图函数
int calcIntenHist(const cv::Mat src, float* dstHist)
{
//输入必为单通道图
if (src.type() != CV_8UC1) {
return -1;
}
memset(dstHist, 0, sizeof(float) * 256);
int height = src.rows;
int width = src.cols;
//指针遍历
for (int k = 0; k < height; k++)
{
// 获取第k行的首地址
const uchar* inData = src.ptr<uchar>(k);
//处理每个像素
for (int i = 0; i < width; i++)
{
int gray = inData[i];
dstHist[gray]++;
}
}
//直方图归一化
float norm = height * width;
for (int n = 0; n < 256; n++) {
dstHist[n] = dstHist[n] / norm;
}
return 0;
}
还进行了归一化
直方图画画函数
int drawIntenHist(cv::Mat& histMat, float* srcHist, int bin_width, int bin_heght)
{
histMat.create(bin_heght, 256 * bin_width, CV_8UC3);
histMat = Scalar(255, 255, 255);
float maxVal = *std::max_element(srcHist, srcHist + 256);
for (int i = 0; i < 256; i++) {
Rect binRect;
binRect.x = i * bin_width;
float height_i = (float)bin_heght * srcHist[i] / maxVal;
binRect.height = (int)height_i;
binRect.y = bin_heght - binRect.height;
binRect.width = bin_width;
rectangle(histMat, binRect, CV_RGB(255, 0, 0), -1);
}
return 0;
}
float height_i = (float)bin_heght * srcHist[i] / maxVal;是防止不够高度大小 要进行的高度归一
直方图均衡化的完整代码:
float srcHist[256];
float dstHist[256];
Mat dstHistMat;
Mat srcHistMat;
Mat histMat[3];
Mat equalizeHistMat;
cv::Mat dstMat1;
int bin_width = 2;
int bin_heigth = 100;
if (srcMat.type() == CV_8UC1) {
equalizeHist(srcMat, equalizeHistMat);
imshow("src", srcMat);
imshow("equalizeHistMat", equalizeHistMat);
waitKey(0);
destroyAllWindows();
calcIntenHist(dstMat1, dstHist);
drawIntenHist(dstHistMat, dstHist, 3, 100);
imshow("dstMat hist", dstHistMat);
calcIntenHist(srcMat, srcHist);
drawIntenHist(srcHistMat, srcHist, 3, 100);
imshow("srcMat hist", srcHistMat);
waitKey(0);
destroyAllWindows();
}
else
{
Mat channel[3];
Mat out[3];
float hist[3][256];
split(srcMat, channel);
for (int i = 0; i < 3; i++) {
equalizeHist(channel[i], out[i]);
calcIntenHist(out[i], hist[i]);
drawIntenHist(histMat[i], hist[i], bin_width, bin_heigth);
//按照channel编号命名窗口
stringstream ss;
ss << i;
string histWindow = "Hist of chanel " + ss.str();
string matWindow = "Image of chanel " + ss.str();
imshow(histWindow, histMat[i]);
imshow(matWindow, out[i]);
}
merge(out, 3, dstMat1);
cv::Mat grayMat;
cv::Mat graydstMat;
cvtColor(srcMat, grayMat, CV_BGR2GRAY);
cvtColor(dstMat1, graydstMat, CV_BGR2GRAY);
//计算并绘制直方图
calcIntenHist(graydstMat, dstHist);
drawIntenHist(dstHistMat, dstHist, 3, 100);
imshow("dstMat", dstMat1);
imshow("dstMat hist", dstHistMat);
calcIntenHist(grayMat, srcHist);
drawIntenHist(srcHistMat, srcHist, 3, 100);
imshow("srcMat hist", srcHistMat);
imshow("srcMat", srcMat);
waitKey(0);
destroyAllWindows();
}
return 0;
}