上计算机视觉课老师布置的作业实现论文:Color Transfer between Images
基本思路是:
1.给定srcImg和targetImg
2.将RGB空间转为Lab空间
3.根据论文中公式:
计算每一个像素点
4.将resultImg转回到RGB空间显示
效果图:
见代码:
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/core/core.hpp> 3 #include <opencv2/imgproc/imgproc.hpp> 4 #include <math.h> 5 using namespace std; 6 using namespace cv; 7 8 class ColorTransfer 9 { 10 public: 11 Mat resultImg; 12 13 ColorTransfer(Mat src, Mat target) 14 { 15 src.convertTo(srcImg_32F, CV_32FC3,1.0f/255.f);//这里切记要类型转换下 16 target.convertTo(targetImg_32F, CV_32FC3, 1.0f/255.0f); 17 resultImg = srcImg_32F; //将结果先初始化为源图像 18 19 srcImg_Lab = RGBToLab(srcImg_32F); 20 targetImg_Lab = RGBToLab(targetImg_32F); 21 srcMeans = computeMeans(srcImg_Lab); 22 targetMeans = computeMeans(targetImg_Lab); 23 srcVariances = computeVariances(srcImg_Lab, srcMeans); 24 targetVariances = computeVariances(targetImg_Lab, targetMeans); 25 computeResult(); 26 } 27 28 private: 29 //读入的RGB图像 30 Mat srcImg_32F; 31 Mat targetImg_32F; 32 //转换后的Lab空间图像 33 Mat srcImg_Lab; 34 Mat targetImg_Lab; 35 //计算得到的均值和方差 36 Vector<double> srcMeans; 37 Vector<double> targetMeans; 38 Vector<double> srcVariances; 39 Vector<double> targetVariances; 40 41 //RGB转换到Lab空间 42 Mat RGBToLab(Mat m) 43 { 44 Mat_<Vec3f> I = m; 45 for(int i=0;i<I.rows;++i) 46 { 47 for(int j=0;j<I.cols;++j) 48 { 49 double L = 0.3811*I(i,j)[0] + 0.5783*I(i,j)[1] + 0.0402*I(i,j)[2]; 50 double M = 0.1967*I(i,j)[0] + 0.7244*I(i,j)[1] + 0.0782*I(i,j)[2]; 51 double S = 0.0241*I(i,j)[0] + 0.1288*I(i,j)[1] + 0.8444*I(i,j)[2]; 52 if(L == 0) L = 1; 53 if(M == 0) M = 1; 54 if(S == 0) S = 1; 55 L = log(L); 56 M = log(M); 57 S = log(S); 58 59 I(i,j)[0] = (L+M+S) / sqrt(3.0); 60 I(i,j)[1] = (L+M-2*S) / sqrt(6.0); 61 I(i,j)[2] = (L-M) / sqrt(2.0); 62 } 63 } 64 65 return I; 66 } 67 68 //Lab转换到RGB空间 69 Mat LabToRGB(Mat m) 70 { 71 Mat_<Vec3f> I = m; 72 for(int i=0;i<I.rows;++i) 73 for(int j=0;j<I.cols;++j) 74 { 75 double L = I(i,j)[0]/sqrt(3.0) + I(i,j)[1]/sqrt(6.0) + I(i,j)[2]/sqrt(2.0); 76 double M = I(i,j)[0]/sqrt(3.0) + I(i,j)[1]/sqrt(6.0) - I(i,j)[2]/sqrt(2.0); 77 double S = I(i,j)[0]/sqrt(3.0) - 2*I(i,j)[1]/sqrt(6.0); 78 79 L = exp(L); 80 M = exp(M); 81 S = exp(S); 82 83 I(i,j)[0] = 4.4679*L - 3.5873*M + 0.1193*S; 84 I(i,j)[1] = -1.2186*L + 2.3809*M - 0.1624*S; 85 I(i,j)[2] = 0.0497*L - 0.2439*M + 1.2045*S; 86 } 87 88 return I; 89 } 90 91 Vector<double> computeMeans(Mat m) 92 { 93 double sum[3] = { 0 }; 94 int pixes = m.cols * m.rows; 95 Vector<double> means; 96 means.resize(3); 97 Mat_<Vec3f> I = m; 98 99 for(int i=0;i<I.rows;++i) 100 for(int j=0;j<I.cols;++j) 101 { 102 for(int k = 0;k < 3;k++) 103 { 104 sum[k] += I(i,j)[k]; 105 } 106 } 107 108 for(int i = 0;i < 3;i++) 109 { 110 means[i] = sum[i] / pixes; 111 } 112 113 return means; 114 } 115 116 Vector<double> computeVariances(Mat m, Vector<double> means) 117 { 118 double sum[3] = { 0 }; 119 int pixes = m.cols * m.rows; 120 Mat_<Vec3f> I = m; 121 Vector<double> variances; 122 variances.resize(3); 123 124 for(int i=0;i<I.rows;++i) 125 for(int j=0;j<I.cols;++j) 126 { 127 for(int chanel = 0;chanel < 3;chanel++) 128 { 129 sum[chanel] += abs(I(i,j)[chanel] - means[chanel]); 130 } 131 } 132 133 for(int i = 0;i < 3;i++) 134 { 135 variances[i] = sqrt(sum[i] / pixes); 136 } 137 138 return variances; 139 } 140 141 void computeResult() 142 { 143 Mat_<Vec3f> I = resultImg; 144 double dataTemp[3] = { 0 }; 145 146 for(int chanel =0;chanel < 3;chanel++) 147 { 148 dataTemp[chanel] = targetVariances[chanel] / srcVariances[chanel]; 149 } 150 151 for(int i=0;i<I.rows;++i) 152 for(int j=0;j<I.cols;++j) 153 { 154 for(int chanel = 0;chanel < 3;chanel++) 155 { 156 I(i,j)[chanel] = dataTemp[chanel] * (I(i,j)[chanel]-srcMeans[chanel]) + targetMeans[chanel]; 157 } 158 } 159 resultImg = LabToRGB(resultImg); 160 } 161 }; 162 163 int main() 164 { 165 Mat src = imread("11.jpg"); 166 namedWindow("src"); 167 imshow("src", src); 168 Mat target = imread("12.jpg"); 169 namedWindow("target"); 170 imshow("target", target); 171 ColorTransfer clt(src,target); 172 namedWindow("result"); 173 imshow("result", clt.resultImg); 174 Mat saveImg; 175 clt.resultImg.convertTo(saveImg,CV_8U, 255.0, 1/255.0);//imwrite函数只支持8bit和16bit,前面将图像转为了float,保存前要转换 176 imwrite("result.jpg",saveImg); 177 178 waitKey(0); 179 return 0; 180 }