在直方图的基础之上,考虑均值方差匹配(本质上根据直方图完成一次线性映射,y=kx+b;),来达到颜色匹配的效果。(颜色匹配在PS软件上也有类似功能)
匹配分为两个阶段:第一阶段,在HSV空间下对S、V通道进行匹配,H通道不变。会有些许色片。(对于HSV空间的理解,此处不足解释,自己查阅资料看)
第二阶段,将HSV空间下做好的匹配图转换到RGB空间下,在对R、G、B三通道分别进行匹配。这样就完成了。
过程中(指导老师提供了思想),遇到问题冷静思考解决,一步步去测试(直方图、均值、方差、映射系数、映射矩阵。。。)
自己碰到的麻烦;变量名的误写,最终的映射代码逻辑写反了(这个逻辑读者一定要注意)。
以下只给出HSV空间下的匹配代码(RGB空间用到的匹配思想是一样的,读者自行学习编写):
clear all;
close all;
clc;
%注意点乘和乘的区别
src=imread('E:\毕设图片\颜色匹配\source.jpg');
tar=imread('E:\毕设图片\颜色匹配\target.jpg');
src=mat2gray(src);
tar=mat2gray(tar);%归一化
[m,n,dim]=size(src);
[m,n,dim]=size(tar);
%%读取待匹配图像,将其的RGB转换成HSV
src_R=src(:,:,1);
src_G=src(:,:,2);
src_B=src(:,:,3);
%RGB—>HSV
src_H=zeros(m,n); %色相角
src_S=zeros(m,n); %饱和度
src_V=zeros(m,n); %明度
for i=1:m
for j=1:n
r=src_R(i,j);
g=src_G(i,j);
b=src_B(i,j);
MAX=max([r,g,b]);
MIN=min([r,g,b]);
if MAX==MIN
src_H(i,j)=0;
elseif MAX==r && g>=b
src_H(i,j)=60*(g-b)/(MAX-MIN);
elseif MAX==r && g<b
src_H(i,j)=60*(g-b)/(MAX-MIN)+360;
elseif MAX==g
src_H(i,j)=60*(b-r)/(MAX-MIN)+120;
elseif MAX==b
src_H(i,j)=60*(r-g)/(MAX-MIN)+240;
end
if MAX==0
src_S(i,j)=0;
else
src_S(i,j)=1-MIN/MAX;
end
src_V(i,j)=MAX;
end
end
src_S=round(src_S.*255);%扩大255倍,利于统计概率
src_V=round(src_V.*255);%扩大255倍,利于统计概率
%%读取参考图像,将其的RGB转换成HSV
tar_R=tar(:,:,1);
tar_G=tar(:,:,2);
tar_B=tar(:,:,3);
%RGB—>HSV
tar_H=zeros(m,n); %色相角
tar_S=zeros(m,n); %饱和度
tar_V=zeros(m,n); %明度
for i=1:m
for j=1:n
r=tar_R(i,j);
g=tar_G(i,j);
b=tar_B(i,j);
MAX=max([r,g,b]);
MIN=min([r,g,b]);
if MAX==MIN
tar_H(i,j)=0;
elseif MAX==r && g>=b
tar_H(i,j)=60*(g-b)/(MAX-MIN);
elseif MAX==r && g<b
tar_H(i,j)=60*(g-b)/(MAX-MIN)+360;
elseif MAX==g
tar_H(i,j)=60*(b-r)/(MAX-MIN)+120;
elseif MAX==b
tar_H(i,j)=60*(r-g)/(MAX-MIN)+240;
end
if MAX==0
tar_S(i,j)=0;
else
tar_S(i,j)=1-MIN/MAX;
end
tar_V(i,j)=MAX;
end
end
tar_S=round(tar_S.*255);%扩大255倍,利于统计概率
tar_V=round(tar_V.*255);%扩大255倍,利于统计概率
%在HSV空间下进行均值方差匹配s、v层
[m_src,n_src]=size(src_S);
[m_tar,n_tar]=size(tar_S);%两幅图像都是3000*4500
srcHisto=zeros(1,256);%待匹配的直方图
tarHisto=zeros(1,256);
srcAccHisto=zeros(1,256);%待匹配的累积直方图
tarAccHisto=zeros(1,256);
for k=0:255 %k表示像素可以取到的S值
count=0;
for i=1:m_src
for j=1:n_src
if(src_S(i,j)==k)
count=count+1;
end
end
end
srcHisto(k+1)=count/(m_src*n_src);
end
srcHisto
for k=0:255 %k表示像素可以取到的灰度值
count=0;
for i=1:m_tar
for j=1:n_tar
if(tar_S(i,j)==k)
count=count+1;
end
end
end
tarHisto(k+1)=count/(m_tar*n_tar);
end
tarHisto
srcVal=0;
tarVal=0;
for i=1:256
srcVal=srcVal+srcHisto(i);
tarVal=tarVal+tarHisto(i);
srcAccHisto(i)=srcVal;
tarAccHisto(i)=tarVal;
end
%计算两个图像的各自的均值和方差
srcMean=0;
tarMean=0;
srcStd=0;
tarStd=0;
for j=1:256
tarMean=tarMean+tarHisto(j)*(j-1);
srcMean=srcMean+srcHisto(j)*(j-1);
end
tarMean
srcMean
for j=1:256
tarStd=tarStd+(j-1-tarMean)*(j-1-tarMean)*tarHisto(j);%下标为对应的灰度级是j-1;
srcStd=srcStd+(j-1-srcMean)*(j-1-srcMean)*srcHisto(j);
end
tarStd
srcStd
%计算映射的矩阵HistoMap(1,256),通过选择系数来构建y=kx+b
HistoMap=zeros(1,256);
s=0;sstep=0.03;minstd=9999;lev=0;
for k=0:300
s=s+sstep;
%移动坐标
for j=1:256
HistoMap(j)=(j-1-srcMean)*s+tarMean;
if(HistoMap(j)<0)
HistoMap(j)=0;
end
if(HistoMap(j)>255)
HistoMap(j)=255;
end
end
%计算中间图的方差,找出与tarStd相差最小的方差以及其对应的系数k
srcMidStd=0;
for j=1:256
srcMidStd=srcMidStd+(HistoMap(j)-tarMean)*(HistoMap(j)-tarMean)*srcHisto(j);
end
diffstd=srcMidStd-tarStd;
if(diffstd<minstd)
minstd=fabs(diffstd);
lev=k;
end
end
%求出最终中间图的直方图HistoMap
s=sstep*lev;
for j=1:256
HistoMap(j)=(j-1-srcMean)*s+tarMean;
if(HistoMap(j)<0)
HistoMap(j)=0;
end
if(HistoMap(j)>255)
HistoMap(j)=255;
end
end
%m_HistoMap=round((HistoMap*255));
src_Smatch=src_S;
for i=0:255
src_Smatch(find(src_S==i))=HistoMap(i+1);
end
src_Smatch=double(src_Smatch);
src_Smatch=src_Smatch./255;%HSV空间下S通道的取值在0~1之间,所以要除去乘上的倍数
[m_src,n_src]=size(src_V);
[m_tar,n_tar]=size(tar_V);%两幅图像都是3000*4500
srcHisto=zeros(1,256);%待匹配的直方图
tarHisto=zeros(1,256);
srcAccHisto=zeros(1,256);%待匹配的累积直方图
tarAccHisto=zeros(1,256);
for k=0:255 %k表示像素可以取到的灰度值
count=0;
for i=1:m_src
for j=1:n_src
if(src_V(i,j)==k)
count=count+1;
end
end
end
srcHisto(k+1)=count/(m_src*n_src);
end
srcHisto
for k=0:255 %k表示像素可以取到的灰度值
count=0;
for i=1:m_tar
for j=1:n_tar
if(tar_V(i,j)==k)
count=count+1;
end
end
end
tarHisto(k+1)=count/(m_tar*n_tar);
end
tarHisto
srcVal=0;
tarVal=0;
for i=1:256
srcVal=srcVal+srcHisto(i);
tarVal=tarVal+tarHisto(i);
srcAccHisto(i)=srcVal;
tarAccHisto(i)=tarVal;
end
%计算两个图像的各自的均值和方差
srcMean=0;
tarMean=0;
srcStd=0;
tarStd=0;
for j=1:256
tarMean=tarMean+tarHisto(j)*(j-1);
srcMean=srcMean+srcHisto(j)*(j-1);
end
tarMean
srcMean
for j=1:256
tarStd=tarStd+(j-1-tarMean)*(j-1-tarMean)*tarHisto(j);%下标为对应的灰度级是j-1;
srcStd=srcStd+(j-1-srcMean)*(j-1-srcMean)*srcHisto(j);
end
tarStd
srcStd
%计算映射的矩阵HistoMap(1,256),通过选择系数来构建y=kx+b
HistoMap=zeros(1,256);
s=0;sstep=0.03;minstd=9999;lev=0;
for k=0:300
s=s+sstep;
%移动坐标
for j=1:256
HistoMap(j)=(j-1-srcMean)*s+tarMean;
if(HistoMap(j)<0)
HistoMap(j)=0;
end
if(HistoMap(j)>255)
HistoMap(j)=255;
end
end
%计算中间图的方差,找出与tarStd相差最小的方差以及其对应的系数k
srcMidStd=0;
for j=1:256
srcMidStd=srcMidStd+(HistoMap(j)-tarMean)*(HistoMap(j)-tarMean)*srcHisto(j);
end
diffstd=srcMidStd-tarStd;
if(diffstd<minstd)
minstd=fabs(diffstd);
lev=k;
end
end
%求出最终中间图的直方图HistoMap
s=sstep*lev;
for j=1:256
HistoMap(j)=(j-1-srcMean)*s+tarMean;
if(HistoMap(j)<0)
HistoMap(j)=0;
end
if(HistoMap(j)>255)
HistoMap(j)=255;
end
end
%m_HistoMap=round((HistoMap*255));
src_Vmatch=src_V;
for i=0:255
src_Vmatch(find(src_V==i))=HistoMap(i+1);
end
src_Vmatch=double(src_Vmatch);
src_Vmatch=src_Vmatch./255;%HSV空间下V通道的取值在0~1之间,所以要除去乘上的倍数
%匹配后转换成RGB空间下的图片
H=src_H;
S=src_Smatch;
V=src_Vmatch;
R=src_R;
G=src_G;
B=src_B;
%%图像HSV2RGB
for i=1:m
for j=1:n
h=floor(H(i,j)/60);
f=H(i,j)/60-h;
v=V(i,j);
s=S(i,j);
p=v*(1-s);
q=v*(1-f*s);
t=v*(1-(1-f)*s);
if h==0
R(i,j)=v;G(i,j)=t;B(i,j)=p;
elseif h==1
R(i,j)=q;G(i,j)=v;B(i,j)=p;
elseif h==2
R(i,j)=p;G(i,j)=v;B(i,j)=t;
elseif h==3
R(i,j)=p;G(i,j)=q;B(i,j)=v;
elseif h==4
R(i,j)=t;G(i,j)=p;B(i,j)=v;
elseif h==5
R(i,j)=v;G(i,j)=p;B(i,j)=q;
end
end
end
%%如果正反变换都没错的话,那么图像是不变的
img(:,:,1)=R;
img(:,:,2)=G;
img(:,:,3)=B;
figure;
imshow(img)
imwrite(img,'C:\Users\chenlong\Desktop\HSV空间\match.jpg');