ReinHard颜色迁移

看到颜色迁移,觉得还蛮有意思的,遂简单看了一下,代码实现好像有错误,但是不知道错误出在哪里。

算法参考:

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];*/
		}
	}

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值