看到颜色迁移,觉得还蛮有意思的,遂简单看了一下,代码实现好像有错误,但是不知道错误出在哪里。
算法参考:
https://blog.csdn.net/sin_geek/article/details/22443537
https://blog.csdn.net/sin_geek/article/details/22325229
代码实现:希望有高手指出我的错误
理论效果:
// Reinhard.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <opencv2\opencv.hpp>
using namespace cv;
using namespace std;
bool TranRein(uchar* lpDIBBits, int lmageWidth, int lmageHeight, uchar* lpDIBBits2, int lmageWidth2, int lmageHeight2, uchar* lpDIBBits3);
void AverageVariance(double* lpLab, int Width, int Height, double& al, double& aa, double& ab, double& vl, double& va, double& vb);
void RgbToLab(uchar R, uchar G, uchar B, double& l, double& a, double& b);
void LabToRgb(double l, double a, double b, uchar& R, uchar& G, uchar& B);
void mat2Sample(Mat& src, uchar* sample, int nWidth, int nHeight);
void sample2Mat(Mat&src, int nWidth, int nHeight, uchar* sample);
int main()
{
Mat src = imread("3.jpg");
int ImageHeight = src.rows;
int ImageWidth = src.cols;
uchar* lpDIBBits = new uchar[3 * ImageHeight * ImageWidth];
mat2Sample(src, lpDIBBits, ImageWidth, ImageHeight);
imshow("src", src);
Mat dst = imread("1.jpg");
int ImageHeight2 = dst.rows;
int ImageWidth2 = dst.cols;
uchar* lpDIBBits2 = new uchar[3 * ImageHeight2 * ImageWidth2];
mat2Sample(dst, lpDIBBits2, ImageWidth2, ImageHeight2);
imshow("dst", dst);
uchar* lpDIBBits3 = new uchar[3 * ImageHeight2 * ImageWidth2];
TranRein(lpDIBBits, ImageWidth, ImageHeight, lpDIBBits2, ImageWidth2, ImageHeight2, lpDIBBits3);
Mat result(ImageHeight2, ImageWidth2, CV_8UC3);
sample2Mat(result, ImageWidth2, ImageHeight2, lpDIBBits3);
imshow("result", result);
waitKey(0);
}
bool TranRein(uchar* lpDIBBits, int lmageWidth, int lmageHeight, uchar* lpDIBBits2, int lmageWidth2, int lmageHeight2, uchar* lpDIBBits3)
{
//控制循环
int i;
int j;
int nindex;
//a为均值,v为方差,分别为源图像和目标图像的lab通道的均值和方差
double al, aa, ab, vl, va, vb, al2, aa2, ab2, vl2, va2, vb2;
//lab空间的矩阵 1目标图像,2源图像,3结果图像
double* lpImageLab = new double[lmageWidth*lmageHeight * 3];
double* lpImageLab2 = new double[lmageWidth2*lmageHeight2 * 3];
double* lpImageLab3 = new double[lmageWidth*lmageHeight * 3];
//目标图像转换为lab,并求lab的均值及标准差
for (j = 0; j < lmageHeight; j++)
{
for (i = 0; i < lmageWidth; i++)
{
nindex = ((lmageHeight - j - 1)*lmageWidth + i);
RgbToLab(lpDIBBits[nindex * 3 + 2], lpDIBBits[nindex * 3 + 1], lpDIBBits[nindex * 3 + 0],
lpImageLab[nindex * 3 + 0], lpImageLab[nindex * 3 + 1], lpImageLab[nindex * 3 + 2]);
}
}
AverageVariance(lpImageLab, lmageWidth, lmageHeight, al, aa, ab, vl, va, vb);
//源图像转换为lab,并求lab的均值及标准差
for (j = 0; j < lmageHeight2; j++)
{
for (i = 0; i < lmageWidth2; i++)
{
nindex = ((lmageHeight2 - j - 1)*lmageWidth2 + i);
RgbToLab(lpDIBBits2[nindex * 3 + 2], lpDIBBits2[nindex * 3 + 1], lpDIBBits2[nindex * 3 + 0],
lpImageLab2[nindex * 3 + 0], lpImageLab2[nindex * 3 + 1], lpImageLab2[nindex * 3 + 2]);
}
}
AverageVariance(lpImageLab2, lmageWidth2, lmageHeight2, al2, aa2, ab2, vl2, va2, vb2);
//求结果图像的lab
for (i = 0; i < lmageWidth*lmageHeight; i++)
{
lpImageLab3[i * 3 + 0] = (lpImageLab[i * 3 + 0] - al) * vl2 / vl + al2;
lpImageLab3[i * 3 + 1] = (lpImageLab[i * 3 + 1] - aa) * va2 / va + aa2;
lpImageLab3[i * 3 + 2] = (lpImageLab[i * 3 + 2] - ab) * vb2 / vb + ab2;
}
//将结果图像的lab转换为RGB
for (j = 0; j < lmageHeight; j++)
{
for (i = 0; i < lmageWidth; i++)
{
nindex = ((lmageHeight - j - 1)*lmageWidth + i);
LabToRgb(lpImageLab3[nindex * 3 + 0], lpImageLab3[nindex * 3 + 1], lpImageLab3[nindex * 3 + 2],
lpDIBBits3[nindex * 3 + 2], lpDIBBits3[nindex * 3 + 1], lpDIBBits3[nindex * 3 + 0]);
}
}
return true;
}
void AverageVariance(double* lpLab, int Width, int Height, double& al, double& aa, double& ab, double& vl, double& va, double& vb)
{
double suml = 0;
double suma = 0;
double sumb = 0;
double lsuml = 0;
double lsuma = 0;
double lsumb = 0;
//分行求平均,避免和过大而溢出
for (int j = 0; j < Height; j++)
{
for (int i = 0; i < Width; i++)
{
lsuml += lpLab[(j*Width + i) * 3];
lsuma += lpLab[(j*Width + i) * 3 + 1];
lsumb += lpLab[(j*Width + i) * 3 + 2];
}
suml += lsuml / Width;
suma += lsuma / Width;
sumb += lsumb / Width;
lsuml = lsuma = lsumb = 0;
}
al = suml / Height;
aa = suma / Height;
ab = sumb / Height;
suml = suma = sumb = 0;
for (int i = 0; i < Width*Height; i++)
{
suml += pow(lpLab[i * 3] - al, 2);
suma += pow(lpLab[i * 3 + 1] - aa, 2);
sumb += pow(lpLab[i * 3 + 2] - ab, 2);
}
vl = sqrt(suml);
va = sqrt(suma);
vb = sqrt(sumb);
}
void RgbToLab(uchar R, uchar G, uchar B, double& l, double& a, double& b)
{
double L = 0.3811*R + 0.5783*G + 0.0402*B;
double M = 0.1967*R + 0.7244*G + 0.0782*B;
double S = 0.0241*R + 0.1288*G + 0.8444*B;
//若RGB值均为0,则LMS为0,防止数学错误log0
if (L != 0) L = log(L) / log(10);
if (M != 0) M = log(M) / log(10);
if (S != 0) S = log(S) / log(10);
l = (L + M + S) / sqrt(3);
a = (L + M - 2 * S) / sqrt(6);
b = (L - M) / sqrt(2);
}
void LabToRgb(double l, double a, double b, uchar& R, uchar& G, uchar& B)
{
l /= sqrt(3);
a /= sqrt(6);
b /= sqrt(2);
double L = l + a + b;
double M = l + a - b;
double S = l - 2 * a;
L = pow(10, L);
M = pow(10, M);
S = pow(10, S);
double dR = 4.4679*L - 3.5873*M + 0.1193*S;
double dG = -1.2186*L + 2.3809*M - 0.1624*S;
double dB = 0.0497*L - 0.2439*M + 1.2045*S;
//防止溢出,若求得RGB值大于255则置为255,若小于0则置为0
if (dR > 255) R = 255;
else if (dR < 0) R = 0;
else R = uchar(dR);
if (dG > 255) G = 255;
else if (dG < 0) G = 0;
else G = uchar(dG);
if (dB > 255) B = 255;
else if (dB < 0) B = 0;
else B = uchar(dB);
}
void mat2Sample(Mat& src, uchar* sample, int nWidth, int nHeight)
{
//uchar* temp;
for (int i = 0; i < nHeight; ++i)
{
//temp = src.ptr<uchar>(i);
for (int j = 0; j < nWidth; ++j)
{
/*sample[i*nWidth + j * 3] = temp[j * 3];
sample[i*nWidth + j * 3 + 1] = temp[j * 3 + 1];
sample[i*nWidth + j * 3 + 2] = temp[j * 3 + 2];*/
sample[i*nWidth + j * 3] = src.at<Vec3b>(i, j)[0];
sample[i*nWidth + j * 3 + 1] = src.at<Vec3b>(i, j)[1];
sample[i*nWidth + j * 3 + 2] = src.at<Vec3b>(i, j)[2];
}
}
}
void sample2Mat(Mat&src, int nWidth, int nHeight, uchar* sample)
{
//uchar* temp;
for (int i = 0; i < nHeight; ++i)
{
//temp = src.ptr<uchar>(i);
for (int j = 0; j < nWidth; ++j)
{
src.at<Vec3b>(i, j)[0] = sample[i*nWidth + j * 3];
src.at<Vec3b>(i, j)[1] = sample[i*nWidth + j * 3 + 1];
src.at<Vec3b>(i, j)[2] = sample[i*nWidth + j * 3 + 2];
/*temp[j * 3] = sample[i*nWidth + j * 3];
temp[j * 3 + 1] = sample[i*nWidth + j * 3 + 1];
temp[j * 3 + 2] = sample[i*nWidth + j * 3 + 2];*/
}
}
}