论文地址:IPOL Journal · Local Color Correction
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
/* LCC 算法公式实现*/
Mat Color_correction(const Mat& src)
{
int rows = src.rows;
int cols = src.cols;
//int** I;
//I = new int* [rows]; // 在堆区开辟所有行的数组
//for (int i = 0; i < rows; i++)
//{
// I[i] = new int [cols]; // 在堆区开辟,所有列放到每一行中
//}
Mat I(src.size(), CV_8UC1);
Mat mast(rows, cols, CV_8UC1);
for (int i = 0; i < rows; i++)
{
uchar* data = mast.ptr<uchar>(i); // 获取mast每行的地址
for (int j = 0; j < cols; j++)
{
//I[i][j] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i, j)[2]) / 3.0; // 将原图中每个像素点的 b+g+r的平均值存入I中
I.at<uchar>(i,j) = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i, j)[2]) / 3.0;
//*data = 255 - I[i][j];
*data = 255 - I.at<uchar>(i, j);
data++;
}
}
GaussianBlur(mast, mast, Size(41, 41), BORDER_DEFAULT); // 高斯滤波
Mat dst(rows, cols, CV_8UC3);
for (int i = 0; i < rows; i++)
{
uchar* data = mast.ptr<uchar>(i);
for (int j = 0; j < cols; j++)
{
for (int k = 0; k < 3; k++)
{
float exp = pow(2, (128 - data[j]) / 128.0);
int value = int(255 * pow(src.at<Vec3b>(i, j)[k] / 255.0, exp));
dst.at<Vec3b>(i, j)[k] = value;
}
}
}
return dst;
}
// 单纯的增加像素值
Mat add_piexl(Mat src, int num)
{
int rows = src.rows;
int cols = src.cols;
Mat dst(rows,cols,CV_8UC3);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
dst.at<Vec3b>(i,j)[0] = src.at<Vec3b>(i, j)[0];
dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1];
dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2] + num;
}
}
return dst;
}
Mat contrastimagecorrection(Mat src)
{
int rows = src.rows;
int cols = src.cols;
Mat yuvimg;
cvtColor(src, yuvimg, COLOR_BGR2YUV_I420);
vector <Mat> mv;
split(yuvimg, mv);
Mat oldy = mv[0].clone();
//for (int i = 0; i < rows; i++)
//{
// for (int j = 0; j < cols; j++)
// {
// mv[0].at<uchar>(i, j) = 255 - mv[0].at<uchar>(i, j);
// }
//}
Mat temp;
bilateralFilter(mv[0], temp, 9, 50, 50); // 双边滤波
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
float exp = pow(2, (128 - (255 - temp.at<uchar>(i, j))) / 128.0);
int value = int(255 * pow(oldy.at<uchar>(i, j) / 255.0, exp));
temp.at<uchar>(i, j) = value;
}
}
Mat dst(rows, cols, CV_8UC3);
//mv[0] = temp;
//merge(mv, dst);
//cvtColor(dst, dst, COLOR_YUV2BGRA_I420);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (oldy.at<uchar>(i, j) == 0)
{
for (int k = 0; k < 3; k++) dst.at<Vec3b>(i, j)[k] = 0;
}
else
{
dst.at<Vec3b>(i, j)[0] = (temp.at<uchar>(i, j) * (src.at<Vec3b>(i, j)[0] + oldy.at<uchar>(i, j)) / oldy.at<uchar>(i, j) + src.at<Vec3b>(i, j)[0] - oldy.at<uchar>(i, j)) >> 1;
dst.at<Vec3b>(i, j)[1] = (temp.at<uchar>(i, j) * (src.at<Vec3b>(i, j)[1] + oldy.at<uchar>(i, j)) / oldy.at<uchar>(i, j) + src.at<Vec3b>(i, j)[1] - oldy.at<uchar>(i, j)) >> 1;
dst.at<Vec3b>(i, j)[2] = (temp.at<uchar>(i, j) * (src.at<Vec3b>(i, j)[2] + oldy.at<uchar>(i, j)) / oldy.at<uchar>(i, j) + src.at<Vec3b>(i, j)[2] - oldy.at<uchar>(i, j)) >> 1;
}
}
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
for (int k = 0; k < 3; k++)
{
if (dst.at<Vec3b>(i, j)[k] < 0)
{
dst.at<Vec3b>(i, j)[k] = 0;
}
else if (dst.at<Vec3b>(i, j)[k] > 255)
{
dst.at<Vec3b>(i, j)[k] = 255;
}
}
}
}
return dst;
}
int main()
{
Mat src = imread("E:/work/images/2010_005754.jpg"); // 2010_005754 2009_002774
// LCC 论文地址为:http://www.ipol.im/pub/art/2011/gl_lcc/
// 方式1
Mat dst = Color_correction(src);
// 方式2
Mat dst1 = add_piexl(src, 100);
// 方式3
Rect rect(0, 0, (src.cols - 1) / 2 * 2, (src.rows - 1) / 2 * 2);
Mat newsrc = src(rect);
Mat dst2 = contrastimagecorrection(newsrc);
imshow("origin", src);
imshow("result", dst);
imshow("result1", dst1);
imshow("result2", dst2);
char key = waitKey();
if (key == 'q')
{
return 0;
}
return 0;
}
输入输出结果: